]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
openmp: Initial part of OpenMP 5.0 non-rectangular loop support
authorJakub Jelinek <jakub@redhat.com>
Tue, 16 Jun 2020 14:31:13 +0000 (16:31 +0200)
committerKwok Cheung Yeung <kcy@codesourcery.com>
Tue, 9 Feb 2021 18:09:02 +0000 (10:09 -0800)
OpenMP 5.0 adds support for non-rectangular loop collapses, e.g.
triangular and more complex.

This patch deals just with the diagnostics so that they aren't rejected
immediately as before.  As the spec generally requires as before that the
iteration variable initializer and bound in the comparison as invariant
vs. the outermost loop, and just add some exceptional forms that can violate
that, we need to avoid folding the expressions until we can detect them and
in order to avoid folding it later on, I chose to use a TREE_VEC in those
expressions to hold the var_outer * expr1 + expr2 triplet, the patch adds
pretty-printing of that, gimplification etc. and just sorry_at during
omp expansion for now.

The next step will be to implement the different cases of that one by one.

2020-06-16  Jakub Jelinek  <jakub@redhat.com>

gcc/
* tree.h (OMP_FOR_NON_RECTANGULAR): Define.
* gimplify.c (gimplify_omp_for): Diagnose schedule, ordered
or dist_schedule clause on non-rectangular loops.  Handle
gimplification of non-rectangular lb/b expressions.  When changing
iteration variable, adjust also non-rectangular lb/b expressions
referencing that.
* omp-general.h (struct omp_for_data_loop): Add m1, m2 and outer
members.
(struct omp_for_data): Add non_rect member.
* omp-general.c (omp_extract_for_data): Handle non-rectangular
loops.  Fill in non_rect, m1, m2 and outer.
* omp-low.c (lower_omp_for): Handle non-rectangular lb/b expressions.
* omp-expand.c (expand_omp_for): Emit sorry_at for unsupported
non-rectangular loop cases and assert for cases that can't be
non-rectangular.
* tree-pretty-print.c (dump_mem_ref): Formatting fix.
(dump_omp_loop_non_rect_expr): New function.
(dump_generic_node): Handle non-rectangular OpenMP loops.
* tree-pretty-print.h (dump_omp_loop_non_rect_expr): Declare.
* gimple-pretty-print.c (dump_gimple_omp_for): Handle non-rectangular
OpenMP loops.
gcc/c-family/
* c-common.h (c_omp_check_loop_iv_exprs): Add an int argument.
* c-omp.c (struct c_omp_check_loop_iv_data): Add maybe_nonrect and
idx members.
(c_omp_is_loop_iterator): New function.
(c_omp_check_loop_iv_r): Use it.  Add support for silent scanning
if outer loop iterator is present.  Perform duplicate checking through
hash_set in the function rather than expecting caller to do that.
Pass NULL instead of d->ppset to walk_tree_1.
(c_omp_check_nonrect_loop_iv): New function.
(c_omp_check_loop_iv): Use it.  Fill in new members, allow
non-rectangular loop forms, diagnose multiple associated loops with
the same iterator.  Pass NULL instead of &pset to walk_tree_1.
(c_omp_check_loop_iv_exprs): Likewise.
gcc/c/
* c-parser.c (c_parser_expr_no_commas): Save, clear and restore
c_in_omp_for.
(c_parser_omp_for_loop): Set c_in_omp_for around some calls to avoid
premature c_fully_fold.  Defer explicit c_fully_fold calls to after
c_finish_omp_for.
* c-tree.h (c_in_omp_for): Declare.
* c-typeck.c (c_in_omp_for): Define.
(build_modify_expr): Avoid c_fully_fold if c_in_omp_for.
(digest_init): Likewise.
(build_binary_op): Likewise.
gcc/cp/
* semantics.c (handle_omp_for_class_iterator): Adjust
c_omp_check_loop_iv_exprs caller.
(finish_omp_for): Likewise.  Don't call fold_build_cleanup_point_expr
before calling c_finish_omp_for and c_omp_check_loop_iv, move it
after those calls.
* pt.c (tsubst_omp_for_iterator): Handle non-rectangular loops.
gcc/testsuite/
* c-c++-common/gomp/loop-6.c: New test.
* gcc.dg/gomp/loop-1.c: Don't expect diagnostics on valid
non-rectangular loops.
* gcc.dg/gomp/loop-2.c: New test.
* g++.dg/gomp/loop-1.C: Don't expect diagnostics on valid
non-rectangular loops.
* g++.dg/gomp/loop-2.C: Likewise.
* g++.dg/gomp/loop-5.C: New test.
* g++.dg/gomp/loop-6.C: New test.

(cherry picked from commit 1160ec9a141faf1c4c0496c7412c8febeb623962)

28 files changed:
gcc/ChangeLog.omp
gcc/c-family/ChangeLog.omp
gcc/c-family/c-common.h
gcc/c-family/c-omp.c
gcc/c/ChangeLog.omp
gcc/c/c-parser.c
gcc/c/c-tree.h
gcc/c/c-typeck.c
gcc/cp/ChangeLog.omp
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/gimple-pretty-print.c
gcc/gimplify.c
gcc/omp-expand.c
gcc/omp-general.c
gcc/omp-general.h
gcc/omp-low.c
gcc/testsuite/ChangeLog.omp
gcc/testsuite/c-c++-common/gomp/loop-6.c [new file with mode: 0644]
gcc/testsuite/g++.dg/gomp/loop-1.C
gcc/testsuite/g++.dg/gomp/loop-2.C
gcc/testsuite/g++.dg/gomp/loop-5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/gomp/loop-6.C [new file with mode: 0644]
gcc/testsuite/gcc.dg/gomp/loop-1.c
gcc/testsuite/gcc.dg/gomp/loop-2.c [new file with mode: 0644]
gcc/tree-pretty-print.c
gcc/tree-pretty-print.h
gcc/tree.h

index 4e2340462bd46f02c0bc61505bad59dc1971ee1e..1cdcc1ebc1d70d0c38b1866be54cd7417f332a0a 100644 (file)
@@ -1,3 +1,30 @@
+2021-02-09  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+       Backport from mainline
+       2020-06-16  Jakub Jelinek  <jakub@redhat.com>
+
+       * tree.h (OMP_FOR_NON_RECTANGULAR): Define.
+       * gimplify.c (gimplify_omp_for): Diagnose schedule, ordered
+       or dist_schedule clause on non-rectangular loops.  Handle
+       gimplification of non-rectangular lb/b expressions.  When changing
+       iteration variable, adjust also non-rectangular lb/b expressions
+       referencing that.
+       * omp-general.h (struct omp_for_data_loop): Add m1, m2 and outer
+       members.
+       (struct omp_for_data): Add non_rect member.
+       * omp-general.c (omp_extract_for_data): Handle non-rectangular
+       loops.  Fill in non_rect, m1, m2 and outer.
+       * omp-low.c (lower_omp_for): Handle non-rectangular lb/b expressions.
+       * omp-expand.c (expand_omp_for): Emit sorry_at for unsupported
+       non-rectangular loop cases and assert for cases that can't be
+       non-rectangular.
+       * tree-pretty-print.c (dump_mem_ref): Formatting fix.
+       (dump_omp_loop_non_rect_expr): New function.
+       (dump_generic_node): Handle non-rectangular OpenMP loops.
+       * tree-pretty-print.h (dump_omp_loop_non_rect_expr): Declare.
+       * gimple-pretty-print.c (dump_gimple_omp_for): Handle non-rectangular
+       OpenMP loops.
+
 2021-01-22  Kwok Cheung Yeung  <kcy@codesourcery.com>
 
        Backport from mainline
index d0d7d3f08b6d692ef793daa9e0d8794180507da0..9c641515185b93903709bbc478ec38b7cb0b4e44 100644 (file)
@@ -1,3 +1,22 @@
+2021-02-09  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+       Backport from mainline
+       2020-06-16  Jakub Jelinek  <jakub@redhat.com>
+
+       * c-common.h (c_omp_check_loop_iv_exprs): Add an int argument.
+       * c-omp.c (struct c_omp_check_loop_iv_data): Add maybe_nonrect and
+       idx members.
+       (c_omp_is_loop_iterator): New function.
+       (c_omp_check_loop_iv_r): Use it.  Add support for silent scanning
+       if outer loop iterator is present.  Perform duplicate checking through
+       hash_set in the function rather than expecting caller to do that.
+       Pass NULL instead of d->ppset to walk_tree_1.
+       (c_omp_check_nonrect_loop_iv): New function.
+       (c_omp_check_loop_iv): Use it.  Fill in new members, allow
+       non-rectangular loop forms, diagnose multiple associated loops with
+       the same iterator.  Pass NULL instead of &pset to walk_tree_1.
+       (c_omp_check_loop_iv_exprs): Likewise.
+
 2021-01-22  Kwok Cheung Yeung  <kcy@codesourcery.com>
 
        Backport from mainline
index c0fcf0a442d3536e12e93c78e30f4b277b3d0e7d..d3128b8c57599bf36c69c288cfc17a88cce744ce 100644 (file)
@@ -1205,7 +1205,7 @@ extern void c_finish_omp_taskyield (location_t);
 extern tree c_finish_omp_for (location_t, enum tree_code, tree, tree, tree,
                              tree, tree, tree, tree, bool);
 extern bool c_omp_check_loop_iv (tree, tree, walk_tree_lh);
-extern bool c_omp_check_loop_iv_exprs (location_t, tree, tree, tree, tree,
+extern bool c_omp_check_loop_iv_exprs (location_t, tree, int, tree, tree, tree,
                                       walk_tree_lh);
 extern tree c_finish_oacc_wait (location_t, tree, tree);
 extern tree c_oacc_split_loop_clauses (tree, tree *, bool);
index 55f3b666ef6a069521bb4959f92d2880973eccac..2a42c58dbe88f0b93f1d2c4188b47346c7066b16 100644 (file)
@@ -35,6 +35,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "attribs.h"
 #include "gimplify.h"
 #include "tree-iterator.h"
+#include "langhooks.h"
+
 
 /* Complete a #pragma oacc wait construct.  LOC is the location of
    the #pragma.  */
@@ -1196,13 +1198,37 @@ struct c_omp_check_loop_iv_data
 {
   tree declv;
   bool fail;
+  bool maybe_nonrect;
   location_t stmt_loc;
   location_t expr_loc;
   int kind;
+  int idx;
   walk_tree_lh lh;
   hash_set<tree> *ppset;
 };
 
+/* Return -1 if DECL is not a loop iterator in loop nest D, otherwise
+   return the index of the loop in which it is an iterator.
+   Return TREE_VEC_LENGTH (d->declv) if it is a C++ range for iterator.  */
+
+static int
+c_omp_is_loop_iterator (tree decl, struct c_omp_check_loop_iv_data *d)
+{
+  for (int i = 0; i < TREE_VEC_LENGTH (d->declv); i++)
+    if (decl == TREE_VEC_ELT (d->declv, i)
+       || (TREE_CODE (TREE_VEC_ELT (d->declv, i)) == TREE_LIST
+           && decl == TREE_PURPOSE (TREE_VEC_ELT (d->declv, i))))
+      return i;
+    else if (TREE_CODE (TREE_VEC_ELT (d->declv, i)) == TREE_LIST
+            && TREE_CHAIN (TREE_VEC_ELT (d->declv, i))
+            && (TREE_CODE (TREE_CHAIN (TREE_VEC_ELT (d->declv, i)))
+                == TREE_VEC)
+            && decl == TREE_VEC_ELT (TREE_CHAIN (TREE_VEC_ELT (d->declv,
+                                                 i)), 2))
+      return TREE_VEC_LENGTH (d->declv);
+  return -1;
+}
+
 /* Helper function called via walk_tree, to diagnose uses
    of associated loop IVs inside of lb, b and incr expressions
    of OpenMP loops.  */
@@ -1214,51 +1240,234 @@ c_omp_check_loop_iv_r (tree *tp, int *walk_subtrees, void *data)
     = (struct c_omp_check_loop_iv_data *) data;
   if (DECL_P (*tp))
     {
-      int i;
-      for (i = 0; i < TREE_VEC_LENGTH (d->declv); i++)
-       if (*tp == TREE_VEC_ELT (d->declv, i)
-           || (TREE_CODE (TREE_VEC_ELT (d->declv, i)) == TREE_LIST
-               && *tp == TREE_PURPOSE (TREE_VEC_ELT (d->declv, i)))
-           || (TREE_CODE (TREE_VEC_ELT (d->declv, i)) == TREE_LIST
-               && TREE_CHAIN (TREE_VEC_ELT (d->declv, i))
-               && (TREE_CODE (TREE_CHAIN (TREE_VEC_ELT (d->declv, i)))
-                   == TREE_VEC)
-               && *tp == TREE_VEC_ELT (TREE_CHAIN (TREE_VEC_ELT (d->declv,
-                                                                 i)), 2)))
-         {
-           location_t loc = d->expr_loc;
-           if (loc == UNKNOWN_LOCATION)
-             loc = d->stmt_loc;
-           switch (d->kind)
-             {
-             case 0:
-               error_at (loc, "initializer expression refers to "
-                              "iteration variable %qD", *tp);
-               break;
-             case 1:
-               error_at (loc, "condition expression refers to "
-                              "iteration variable %qD", *tp);
-               break;
-             case 2:
-               error_at (loc, "increment expression refers to "
-                              "iteration variable %qD", *tp);
-               break;
-             }
-           d->fail = true;
-         }
+      int idx = c_omp_is_loop_iterator (*tp, d);
+      if (idx == -1)
+       return NULL_TREE;
+
+      if ((d->kind & 4) && idx < d->idx)
+       {
+         d->maybe_nonrect = true;
+         return NULL_TREE;
+       }
+
+      if (d->ppset->add (*tp))
+       return NULL_TREE;
+
+      location_t loc = d->expr_loc;
+      if (loc == UNKNOWN_LOCATION)
+       loc = d->stmt_loc;
+
+      switch (d->kind & 3)
+       {
+       case 0:
+         error_at (loc, "initializer expression refers to "
+                        "iteration variable %qD", *tp);
+         break;
+       case 1:
+         error_at (loc, "condition expression refers to "
+                        "iteration variable %qD", *tp);
+         break;
+       case 2:
+         error_at (loc, "increment expression refers to "
+                        "iteration variable %qD", *tp);
+         break;
+       }
+      d->fail = true;
     }
+  else if (d->ppset->add (*tp))
+    *walk_subtrees = 0;
   /* Don't walk dtors added by C++ wrap_cleanups_r.  */
   else if (TREE_CODE (*tp) == TRY_CATCH_EXPR
           && TRY_CATCH_IS_CLEANUP (*tp))
     {
       *walk_subtrees = 0;
       return walk_tree_1 (&TREE_OPERAND (*tp, 0), c_omp_check_loop_iv_r, data,
-                         d->ppset, d->lh);
+                         NULL, d->lh);
     }
 
   return NULL_TREE;
 }
 
+/* Check the allowed expressions for non-rectangular loop nest lb and b
+   expressions.  Return the outer var decl referenced in the expression.  */
+
+static tree
+c_omp_check_nonrect_loop_iv (tree *tp, struct c_omp_check_loop_iv_data *d,
+                            walk_tree_lh lh)
+{
+  d->maybe_nonrect = false;
+  if (d->fail)
+    return NULL_TREE;
+
+  hash_set<tree> pset;
+  hash_set<tree> *ppset = d->ppset;
+  d->ppset = &pset;
+
+  tree t = *tp;
+  if (TREE_CODE (t) == TREE_VEC
+      && TREE_VEC_LENGTH (t) == 3
+      && DECL_P (TREE_VEC_ELT (t, 0))
+      && c_omp_is_loop_iterator (TREE_VEC_ELT (t, 0), d) >= 0)
+    {
+      d->kind &= 3;
+      walk_tree_1 (&TREE_VEC_ELT (t, 1), c_omp_check_loop_iv_r, d, NULL, lh);
+      walk_tree_1 (&TREE_VEC_ELT (t, 1), c_omp_check_loop_iv_r, d, NULL, lh);
+      d->ppset = ppset;
+      return d->fail ? NULL_TREE : TREE_VEC_ELT (t, 0);
+    }
+
+  while (CONVERT_EXPR_P (t))
+    t = TREE_OPERAND (t, 0);
+
+  tree a1 = t, a2 = integer_zero_node;
+  bool neg_a1 = false, neg_a2 = false;
+  switch (TREE_CODE (t))
+    {
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+      a1 = TREE_OPERAND (t, 0);
+      a2 = TREE_OPERAND (t, 1);
+      while (CONVERT_EXPR_P (a1))
+       a1 = TREE_OPERAND (a1, 0);
+      while (CONVERT_EXPR_P (a2))
+       a2 = TREE_OPERAND (a2, 0);
+      if (DECL_P (a1) && c_omp_is_loop_iterator (a1, d) >= 0)
+       {
+         a2 = TREE_OPERAND (t, 1);
+         if (TREE_CODE (t) == MINUS_EXPR)
+           neg_a2 = true;
+         t = a1;
+         break;
+       }
+      if (DECL_P (a2) && c_omp_is_loop_iterator (a2, d) >= 0)
+       {
+         a1 = TREE_OPERAND (t, 0);
+         if (TREE_CODE (t) == MINUS_EXPR)
+           neg_a1 = true;
+         t = a2;
+         a2 = a1;
+         break;
+       }
+      if (TREE_CODE (a1) == MULT_EXPR && TREE_CODE (a2) == MULT_EXPR)
+       {
+         tree o1 = TREE_OPERAND (a1, 0);
+         tree o2 = TREE_OPERAND (a1, 1);
+         while (CONVERT_EXPR_P (o1))
+           o1 = TREE_OPERAND (o1, 0);
+         while (CONVERT_EXPR_P (o2))
+           o2 = TREE_OPERAND (o2, 0);
+         if ((DECL_P (o1) && c_omp_is_loop_iterator (o1, d) >= 0)
+             || (DECL_P (o2) && c_omp_is_loop_iterator (o2, d) >= 0))
+           {
+             a2 = TREE_OPERAND (t, 1);
+             if (TREE_CODE (t) == MINUS_EXPR)
+               neg_a2 = true;
+             t = a1;
+             break;
+           }
+       }
+      if (TREE_CODE (a2) == MULT_EXPR)
+       {
+         a1 = TREE_OPERAND (t, 0);
+         if (TREE_CODE (t) == MINUS_EXPR)
+           neg_a1 = true;
+         t = a2;
+         a2 = a1;
+         break;
+       }
+      if (TREE_CODE (a1) == MULT_EXPR)
+       {
+         a2 = TREE_OPERAND (t, 1);
+         if (TREE_CODE (t) == MINUS_EXPR)
+           neg_a2 = true;
+         t = a1;
+         break;
+       }
+      a2 = integer_zero_node;
+      break;
+    default:
+      break;
+    }
+
+  a1 = integer_one_node;
+  if (TREE_CODE (t) == MULT_EXPR)
+    {
+      tree o1 = TREE_OPERAND (t, 0);
+      tree o2 = TREE_OPERAND (t, 1);
+      while (CONVERT_EXPR_P (o1))
+       o1 = TREE_OPERAND (o1, 0);
+      while (CONVERT_EXPR_P (o2))
+       o2 = TREE_OPERAND (o2, 0);
+      if (DECL_P (o1) && c_omp_is_loop_iterator (o1, d) >= 0)
+       {
+         a1 = TREE_OPERAND (t, 1);
+         t = o1;
+       }
+      else if (DECL_P (o2) && c_omp_is_loop_iterator (o2, d) >= 0)
+       {
+         a1 = TREE_OPERAND (t, 0);
+         t = o2;
+       }
+    }
+
+  d->kind &= 3;
+  tree ret = NULL_TREE;
+  if (DECL_P (t) && c_omp_is_loop_iterator (t, d) >= 0)
+    {
+      location_t loc = d->expr_loc;
+      if (loc == UNKNOWN_LOCATION)
+       loc = d->stmt_loc;
+      if (!lang_hooks.types_compatible_p (TREE_TYPE (*tp), TREE_TYPE (t)))
+       {
+         if (d->kind == 0)
+           error_at (loc, "outer iteration variable %qD used in initializer"
+                          " expression has type other than %qT",
+                     t, TREE_TYPE (*tp));
+         else
+           error_at (loc, "outer iteration variable %qD used in condition"
+                          " expression has type other than %qT",
+                     t, TREE_TYPE (*tp));
+         d->fail = true;
+       }
+      else if (!INTEGRAL_TYPE_P (TREE_TYPE (a1)))
+       {
+         error_at (loc, "outer iteration variable %qD multiplier expression"
+                        " %qE is not integral", t, a1);
+         d->fail = true;
+       }
+      else if (!INTEGRAL_TYPE_P (TREE_TYPE (a2)))
+       {
+         error_at (loc, "outer iteration variable %qD addend expression"
+                        " %qE is not integral", t, a2);
+         d->fail = true;
+       }
+      else
+       {
+         walk_tree_1 (&a1, c_omp_check_loop_iv_r, d, NULL, lh);
+         walk_tree_1 (&a2, c_omp_check_loop_iv_r, d, NULL, lh);
+        }
+      if (!d->fail)
+       {
+         a1 = fold_convert (TREE_TYPE (*tp), a1);
+         a2 = fold_convert (TREE_TYPE (*tp), a2);
+         if (neg_a1)
+           a1 = fold_build1 (NEGATE_EXPR, TREE_TYPE (a1), a1);
+         if (neg_a2)
+           a2 = fold_build1 (NEGATE_EXPR, TREE_TYPE (a2), a2);
+         ret = t;
+         *tp = make_tree_vec (3);
+         TREE_VEC_ELT (*tp, 0) = t;
+         TREE_VEC_ELT (*tp, 1) = a1;
+         TREE_VEC_ELT (*tp, 2) = a2;
+       }
+    }
+  else
+    walk_tree_1 (&t, c_omp_check_loop_iv_r, d, NULL, lh);
+
+  d->ppset = ppset;
+  return ret;
+}
+
 /* Diagnose invalid references to loop iterators in lb, b and incr
    expressions.  */
 
@@ -1271,6 +1480,7 @@ c_omp_check_loop_iv (tree stmt, tree declv, walk_tree_lh lh)
 
   data.declv = declv;
   data.fail = false;
+  data.maybe_nonrect = false;
   data.stmt_loc = EXPR_LOCATION (stmt);
   data.lh = lh;
   data.ppset = &pset;
@@ -1284,9 +1494,31 @@ c_omp_check_loop_iv (tree stmt, tree declv, walk_tree_lh lh)
       gcc_assert (TREE_OPERAND (cond, 0) == decl);
       tree incr = TREE_VEC_ELT (OMP_FOR_INCR (stmt), i);
       data.expr_loc = EXPR_LOCATION (TREE_OPERAND (init, 1));
-      data.kind = 0;
+      tree vec_outer1 = NULL_TREE, vec_outer2 = NULL_TREE;
+      int kind = 0;
+      if (i > 0
+         && (unsigned) c_omp_is_loop_iterator (decl, &data) < (unsigned) i)
+       {
+         location_t loc = data.expr_loc;
+         if (loc == UNKNOWN_LOCATION)
+           loc = data.stmt_loc;
+         error_at (loc, "the same loop iteration variables %qD used in "
+                        "multiple associated loops", decl);
+         data.fail = true;
+       }
+      /* Handle non-rectangular loop nests.  */
+      if (TREE_CODE (stmt) != OACC_LOOP
+         && (TREE_CODE (TREE_OPERAND (init, 1)) == TREE_VEC
+             || INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (init, 1))))
+         && i > 0)
+       kind = 4;
+      data.kind = kind;
+      data.idx = i;
       walk_tree_1 (&TREE_OPERAND (init, 1),
-                  c_omp_check_loop_iv_r, &data, &pset, lh);
+                  c_omp_check_loop_iv_r, &data, NULL, lh);
+      if (data.maybe_nonrect)
+       vec_outer1 = c_omp_check_nonrect_loop_iv (&TREE_OPERAND (init, 1),
+                                                 &data, lh);
       /* Don't warn for C++ random access iterators here, the
         expression then involves the subtraction and always refers
         to the original value.  The C++ FE needs to warn on those
@@ -1296,10 +1528,24 @@ c_omp_check_loop_iv (tree stmt, tree declv, walk_tree_lh lh)
              && decl == TREE_PURPOSE (TREE_VEC_ELT (declv, i))))
        {
          data.expr_loc = EXPR_LOCATION (cond);
-         data.kind = 1;
+         data.kind = kind | 1;
          walk_tree_1 (&TREE_OPERAND (cond, 1),
-                      c_omp_check_loop_iv_r, &data, &pset, lh);
+                      c_omp_check_loop_iv_r, &data, NULL, lh);
+         if (data.maybe_nonrect)
+           vec_outer2 = c_omp_check_nonrect_loop_iv (&TREE_OPERAND (cond, 1),
+                                                     &data, lh);
+       }
+      if (vec_outer1 && vec_outer2 && vec_outer1 != vec_outer2)
+       {
+         location_t loc = data.expr_loc;
+         if (loc == UNKNOWN_LOCATION)
+           loc = data.stmt_loc;
+         error_at (loc, "two different outer iteration variables %qD and %qD"
+                        " used in a single loop", vec_outer1, vec_outer2);
+         data.fail = true;
        }
+      if (vec_outer1 || vec_outer2)
+       OMP_FOR_NON_RECTANGULAR (stmt) = 1;
       if (TREE_CODE (incr) == MODIFY_EXPR)
        {
          gcc_assert (TREE_OPERAND (incr, 0) == decl);
@@ -1310,13 +1556,13 @@ c_omp_check_loop_iv (tree stmt, tree declv, walk_tree_lh lh)
            {
              data.expr_loc = EXPR_LOCATION (TREE_OPERAND (incr, 0));
              walk_tree_1 (&TREE_OPERAND (incr, 0),
-                          c_omp_check_loop_iv_r, &data, &pset, lh);
+                          c_omp_check_loop_iv_r, &data, NULL, lh);
            }
          else
            {
              data.expr_loc = EXPR_LOCATION (TREE_OPERAND (incr, 1));
              walk_tree_1 (&TREE_OPERAND (incr, 1),
-                          c_omp_check_loop_iv_r, &data, &pset, lh);
+                          c_omp_check_loop_iv_r, &data, NULL, lh);
            }
        }
     }
@@ -1326,7 +1572,7 @@ c_omp_check_loop_iv (tree stmt, tree declv, walk_tree_lh lh)
 /* Similar, but allows to check the init or cond expressions individually.  */
 
 bool
-c_omp_check_loop_iv_exprs (location_t stmt_loc, tree declv, tree decl,
+c_omp_check_loop_iv_exprs (location_t stmt_loc, tree declv, int i, tree decl,
                           tree init, tree cond, walk_tree_lh lh)
 {
   hash_set<tree> pset;
@@ -1334,15 +1580,24 @@ c_omp_check_loop_iv_exprs (location_t stmt_loc, tree declv, tree decl,
 
   data.declv = declv;
   data.fail = false;
+  data.maybe_nonrect = false;
   data.stmt_loc = stmt_loc;
   data.lh = lh;
   data.ppset = &pset;
+  data.idx = i;
+  if (i > 0
+      && (unsigned) c_omp_is_loop_iterator (decl, &data) < (unsigned) i)
+    {
+      error_at (stmt_loc, "the same loop iteration variables %qD used in "
+                         "multiple associated loops", decl);
+      data.fail = true;
+    }
   if (init)
     {
       data.expr_loc = EXPR_LOCATION (init);
       data.kind = 0;
       walk_tree_1 (&init,
-                  c_omp_check_loop_iv_r, &data, &pset, lh);
+                  c_omp_check_loop_iv_r, &data, NULL, lh);
     }
   if (cond)
     {
@@ -1351,10 +1606,10 @@ c_omp_check_loop_iv_exprs (location_t stmt_loc, tree declv, tree decl,
       data.kind = 1;
       if (TREE_OPERAND (cond, 0) == decl)
        walk_tree_1 (&TREE_OPERAND (cond, 1),
-                    c_omp_check_loop_iv_r, &data, &pset, lh);
+                    c_omp_check_loop_iv_r, &data, NULL, lh);
       else
        walk_tree_1 (&TREE_OPERAND (cond, 0),
-                    c_omp_check_loop_iv_r, &data, &pset, lh);
+                    c_omp_check_loop_iv_r, &data, NULL, lh);
     }
   return !data.fail;
 }
index e9ad3a1ea6f6c8c8d68f2e8cac3949c5d08145e0..78f5e0f071034e022177498ed1efe1d1fb3b8af4 100644 (file)
@@ -1,3 +1,19 @@
+2021-02-09  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+       Backport from mainline
+       2020-06-16  Jakub Jelinek  <jakub@redhat.com>
+
+       * c-parser.c (c_parser_expr_no_commas): Save, clear and restore
+       c_in_omp_for.
+       (c_parser_omp_for_loop): Set c_in_omp_for around some calls to avoid
+       premature c_fully_fold.  Defer explicit c_fully_fold calls to after
+       c_finish_omp_for.
+       * c-tree.h (c_in_omp_for): Declare.
+       * c-typeck.c (c_in_omp_for): Define.
+       (build_modify_expr): Avoid c_fully_fold if c_in_omp_for.
+       (digest_init): Likewise.
+       (build_binary_op): Likewise.
+
 2021-01-22  Kwok Cheung Yeung  <kcy@codesourcery.com>
 
        Backport from mainline
index cb491d2d0a447ec29d64050d432381987a6e3355..fae597128e902578fb55a322536b07e43eee7bb3 100644 (file)
@@ -7570,6 +7570,8 @@ c_parser_expr_no_commas (c_parser *parser, struct c_expr *after,
   struct c_expr lhs, rhs, ret;
   enum tree_code code;
   location_t op_location, exp_location;
+  bool save_in_omp_for = c_in_omp_for;
+  c_in_omp_for = false;
   gcc_assert (!after || c_dialect_objc ());
   lhs = c_parser_conditional_expression (parser, after, omp_atomic_lhs);
   op_location = c_parser_peek_token (parser)->location;
@@ -7609,6 +7611,7 @@ c_parser_expr_no_commas (c_parser *parser, struct c_expr *after,
       code = BIT_IOR_EXPR;
       break;
     default:
+      c_in_omp_for = save_in_omp_for;
       return lhs;
     }
   c_parser_consume_token (parser);
@@ -7628,6 +7631,7 @@ c_parser_expr_no_commas (c_parser *parser, struct c_expr *after,
       ret.original_code = ERROR_MARK;
     }
   ret.original_type = NULL;
+  c_in_omp_for = save_in_omp_for;
   return ret;
 }
 
@@ -18163,8 +18167,10 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
          if (i > 0)
            vec_safe_push (for_block, c_begin_compound_stmt (true));
          this_pre_body = push_stmt_list ();
+         c_in_omp_for = true;
          c_parser_declaration_or_fndef (parser, true, true, true, true, true,
                                         NULL, vNULL);
+         c_in_omp_for = false;
          if (this_pre_body)
            {
              this_pre_body = pop_stmt_list (this_pre_body);
@@ -18202,9 +18208,11 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
          init_exp = c_parser_expr_no_commas (parser, NULL);
          init_exp = default_function_array_read_conversion (init_loc,
                                                             init_exp);
+         c_in_omp_for = true;
          init = build_modify_expr (init_loc, decl, decl_exp.original_type,
                                    NOP_EXPR, init_loc, init_exp.value,
                                    init_exp.original_type);
+         c_in_omp_for = false;
          init = c_process_expr_stmt (init_loc, init);
 
          c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
@@ -18225,19 +18233,13 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
       if (c_parser_next_token_is_not (parser, CPP_SEMICOLON))
        {
          location_t cond_loc = c_parser_peek_token (parser)->location;
+         c_in_omp_for = true;
          struct c_expr cond_expr
            = c_parser_binary_expression (parser, NULL, NULL_TREE);
+          c_in_omp_for = false;
 
          cond = cond_expr.value;
          cond = c_objc_common_truthvalue_conversion (cond_loc, cond);
-         if (COMPARISON_CLASS_P (cond))
-           {
-             tree op0 = TREE_OPERAND (cond, 0), op1 = TREE_OPERAND (cond, 1);
-             op0 = c_fully_fold (op0, false, NULL);
-             op1 = c_fully_fold (op1, false, NULL);
-             TREE_OPERAND (cond, 0) = op0;
-             TREE_OPERAND (cond, 1) = op1;
-           }
          switch (cond_expr.original_code)
            {
            case GT_EXPR:
@@ -18371,8 +18373,10 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
      an error from the initialization parsing.  */
   if (!fail)
     {
+      c_in_omp_for = true;
       stmt = c_finish_omp_for (loc, code, declv, NULL, initv, condv,
                               incrv, body, pre_body, true);
+      c_in_omp_for = false;
 
       /* Check for iterators appearing in lb, b or incr expressions.  */
       if (stmt && !c_omp_check_loop_iv (stmt, declv, NULL))
@@ -18382,6 +18386,40 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
        {
          add_stmt (stmt);
 
+         for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (stmt)); i++)
+           {
+             tree init = TREE_VEC_ELT (OMP_FOR_INIT (stmt), i);
+             gcc_assert (TREE_CODE (init) == MODIFY_EXPR);
+             tree decl = TREE_OPERAND (init, 0);
+             tree cond = TREE_VEC_ELT (OMP_FOR_COND (stmt), i);
+             gcc_assert (COMPARISON_CLASS_P (cond));
+             gcc_assert (TREE_OPERAND (cond, 0) == decl);
+
+             tree op0 = TREE_OPERAND (init, 1);
+             if (!OMP_FOR_NON_RECTANGULAR (stmt)
+                 || TREE_CODE (op0) != TREE_VEC)
+               TREE_OPERAND (init, 1) = c_fully_fold (op0, false, NULL);
+             else
+               {
+                 TREE_VEC_ELT (op0, 1)
+                   = c_fully_fold (TREE_VEC_ELT (op0, 1), false, NULL);
+                 TREE_VEC_ELT (op0, 2)
+                   = c_fully_fold (TREE_VEC_ELT (op0, 2), false, NULL);
+               }
+
+             tree op1 = TREE_OPERAND (cond, 1);
+             if (!OMP_FOR_NON_RECTANGULAR (stmt)
+                 || TREE_CODE (op1) != TREE_VEC)
+               TREE_OPERAND (cond, 1) = c_fully_fold (op1, false, NULL);
+             else
+               {
+                 TREE_VEC_ELT (op1, 1)
+                   = c_fully_fold (TREE_VEC_ELT (op1, 1), false, NULL);
+                 TREE_VEC_ELT (op1, 2)
+                   = c_fully_fold (TREE_VEC_ELT (op1, 2), false, NULL);
+               }
+           }
+
          if (cclauses != NULL
              && cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] != NULL)
            {
index 830cd1fcc2cbde4f39e5f6823067c0bdbbba9327..7e51859b7e09ec6a2a8a96be713126981a0d1414 100644 (file)
@@ -668,6 +668,7 @@ extern alias_set_type c_get_alias_set (tree);
 extern int in_alignof;
 extern int in_sizeof;
 extern int in_typeof;
+extern bool c_in_omp_for;
 
 extern tree c_last_sizeof_arg;
 extern location_t c_last_sizeof_loc;
index 9c8e37fd1e9af241477248bfe4c5c06f873d10f1..6af1976632463a5c7607a7f00ae7a6d1f0f66de8 100644 (file)
@@ -71,6 +71,9 @@ int in_sizeof;
 /* The level of nesting inside "typeof".  */
 int in_typeof;
 
+/* True when parsing OpenMP loop expressions.  */
+bool c_in_omp_for;
+
 /* The argument of last parsed sizeof expression, only to be tested
    if expr.original_code == SIZEOF_EXPR.  */
 tree c_last_sizeof_arg;
@@ -6209,15 +6212,20 @@ build_modify_expr (location_t location, tree lhs, tree lhs_origtype,
   if (!(is_atomic_op && modifycode != NOP_EXPR))
     {
       tree rhs_semantic_type = NULL_TREE;
-      if (TREE_CODE (newrhs) == EXCESS_PRECISION_EXPR)
+      if (!c_in_omp_for)
        {
-         rhs_semantic_type = TREE_TYPE (newrhs);
-         newrhs = TREE_OPERAND (newrhs, 0);
+         if (TREE_CODE (newrhs) == EXCESS_PRECISION_EXPR)
+           {
+             rhs_semantic_type = TREE_TYPE (newrhs);
+             newrhs = TREE_OPERAND (newrhs, 0);
+           }
+         npc = null_pointer_constant_p (newrhs);
+         newrhs = c_fully_fold (newrhs, false, NULL);
+         if (rhs_semantic_type)
+           newrhs = build1 (EXCESS_PRECISION_EXPR, rhs_semantic_type, newrhs);
        }
-      npc = null_pointer_constant_p (newrhs);
-      newrhs = c_fully_fold (newrhs, false, NULL);
-      if (rhs_semantic_type)
-       newrhs = build1 (EXCESS_PRECISION_EXPR, rhs_semantic_type, newrhs);
+      else
+       npc = null_pointer_constant_p (newrhs);
       newrhs = convert_for_assignment (location, rhs_loc, lhstype, newrhs,
                                       rhs_origtype, ic_assign, npc,
                                       NULL_TREE, NULL_TREE, 0);
@@ -7745,12 +7753,15 @@ digest_init (location_t init_loc, tree type, tree init, tree origtype,
 
   STRIP_TYPE_NOPS (inside_init);
 
-  if (TREE_CODE (inside_init) == EXCESS_PRECISION_EXPR)
+  if (!c_in_omp_for)
     {
-      semantic_type = TREE_TYPE (inside_init);
-      inside_init = TREE_OPERAND (inside_init, 0);
+      if (TREE_CODE (inside_init) == EXCESS_PRECISION_EXPR)
+       {
+         semantic_type = TREE_TYPE (inside_init);
+         inside_init = TREE_OPERAND (inside_init, 0);
+       }
+      inside_init = c_fully_fold (inside_init, require_constant, &maybe_const);
     }
-  inside_init = c_fully_fold (inside_init, require_constant, &maybe_const);
 
   /* Initialization of an array of chars from a string constant
      optionally enclosed in braces.  */
@@ -12417,7 +12428,7 @@ build_binary_op (location_t location, enum tree_code code,
          converted = 1;
          resultcode = xresultcode;
 
-         if (c_inhibit_evaluation_warnings == 0)
+         if (c_inhibit_evaluation_warnings == 0 && !c_in_omp_for)
            {
              bool op0_maybe_const = true;
              bool op1_maybe_const = true;
index 559eb47f12a11be0d8dcdf3cf51fe28a8013000c..7e75e9e30506e8e827b9abc1979378439b9b306c 100644 (file)
@@ -1,3 +1,15 @@
+2021-02-09  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+       Backport from mainline
+       2020-06-16  Jakub Jelinek  <jakub@redhat.com>
+
+       * semantics.c (handle_omp_for_class_iterator): Adjust
+       c_omp_check_loop_iv_exprs caller.
+       (finish_omp_for): Likewise.  Don't call fold_build_cleanup_point_expr
+       before calling c_finish_omp_for and c_omp_check_loop_iv, move it
+       after those calls.
+       * pt.c (tsubst_omp_for_iterator): Handle non-rectangular loops.
+
 2021-01-22  Kwok Cheung Yeung  <kcy@codesourcery.com>
 
        Backport from mainline
index 781b055921b36e190656011a712316d226c38bdd..90cee31bb5a54e351daba9c6995f686ac6144e50 100644 (file)
@@ -17524,7 +17524,16 @@ tsubst_omp_for_iterator (tree t, int i, tree declv, tree &orig_declv,
       else
        decl = RECUR (decl);
     }
-  init = RECUR (init);
+  if (init && TREE_CODE (init) == TREE_VEC)
+    {
+      init = copy_node (init);
+      TREE_VEC_ELT (init, 0)
+       = tsubst_decl (TREE_VEC_ELT (init, 0), args, complain);
+      TREE_VEC_ELT (init, 1) = RECUR (TREE_VEC_ELT (init, 1));
+      TREE_VEC_ELT (init, 2) = RECUR (TREE_VEC_ELT (init, 2));
+    }
+  else
+    init = RECUR (init);
 
   if (orig_declv && OMP_FOR_ORIG_DECLS (t))
     {
@@ -17576,7 +17585,21 @@ tsubst_omp_for_iterator (tree t, int i, tree declv, tree &orig_declv,
 
       if (!range_for)
        {
-         cond = RECUR (TREE_VEC_ELT (OMP_FOR_COND (t), i));
+         cond = TREE_VEC_ELT (OMP_FOR_COND (t), i);
+         if (COMPARISON_CLASS_P (cond)
+             && TREE_CODE (TREE_OPERAND (cond, 1)) == TREE_VEC)
+           {
+             tree lhs = RECUR (TREE_OPERAND (cond, 0));
+             tree rhs = copy_node (TREE_OPERAND (cond, 1));
+             TREE_VEC_ELT (rhs, 0)
+               = tsubst_decl (TREE_VEC_ELT (rhs, 0), args, complain);
+             TREE_VEC_ELT (rhs, 1) = RECUR (TREE_VEC_ELT (rhs, 1));
+             TREE_VEC_ELT (rhs, 2) = RECUR (TREE_VEC_ELT (rhs, 2));
+             cond = build2 (TREE_CODE (cond), TREE_TYPE (cond),
+                            lhs, rhs);       
+           }
+         else
+           cond = RECUR (cond);
          incr = TREE_VEC_ELT (OMP_FOR_INCR (t), i);
          if (TREE_CODE (incr) == MODIFY_EXPR)
            {
index 9eda407bbf1764b2f9d0073f4b1ed89ae1722924..370d5831091a4b51eba6784d6a0b59898d09519e 100644 (file)
@@ -9019,7 +9019,7 @@ handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code,
                TREE_OPERAND (cond, 1), iter);
       return true;
     }
-  if (!c_omp_check_loop_iv_exprs (locus, orig_declv,
+  if (!c_omp_check_loop_iv_exprs (locus, orig_declv, i,
                                  TREE_VEC_ELT (declv, i), NULL_TREE,
                                  cond, cp_walk_subtrees))
     return true;
@@ -9405,8 +9405,8 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv,
       tree orig_init;
       FOR_EACH_VEC_ELT (*orig_inits, i, orig_init)
        if (orig_init
-           && !c_omp_check_loop_iv_exprs (locus, orig_declv
-                                                 ? orig_declv : declv,
+           && !c_omp_check_loop_iv_exprs (locus,
+                                          orig_declv ? orig_declv : declv, i,
                                           TREE_VEC_ELT (declv, i), orig_init,
                                           NULL_TREE, cp_walk_subtrees))
          fail = true;
@@ -9500,35 +9500,11 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv,
          return NULL;
        }
 
-      if (!processing_template_decl)
-       {
-         init = fold_build_cleanup_point_expr (TREE_TYPE (init), init);
-         init = cp_build_modify_expr (elocus, decl, NOP_EXPR, init,
-                                      tf_warning_or_error);
-       }
+      if (!processing_template_decl && TREE_CODE (init) != TREE_VEC)
+       init = cp_build_modify_expr (elocus, decl, NOP_EXPR, init,
+                                    tf_warning_or_error);
       else
        init = build2 (MODIFY_EXPR, void_type_node, decl, init);
-      if (cond
-         && TREE_SIDE_EFFECTS (cond)
-         && COMPARISON_CLASS_P (cond)
-         && !processing_template_decl)
-       {
-         tree t = TREE_OPERAND (cond, 0);
-         if (TREE_SIDE_EFFECTS (t)
-             && t != decl
-             && (TREE_CODE (t) != NOP_EXPR
-                 || TREE_OPERAND (t, 0) != decl))
-           TREE_OPERAND (cond, 0)
-             = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
-
-         t = TREE_OPERAND (cond, 1);
-         if (TREE_SIDE_EFFECTS (t)
-             && t != decl
-             && (TREE_CODE (t) != NOP_EXPR
-                 || TREE_OPERAND (t, 0) != decl))
-           TREE_OPERAND (cond, 1)
-             = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
-       }
       if (decl == error_mark_node || init == error_mark_node)
        return NULL;
 
@@ -9557,9 +9533,45 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv,
 
   for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INCR (omp_for)); i++)
     {
-      decl = TREE_OPERAND (TREE_VEC_ELT (OMP_FOR_INIT (omp_for), i), 0);
+      init = TREE_VEC_ELT (OMP_FOR_INIT (omp_for), i);
+      decl = TREE_OPERAND (init, 0);
+      cond = TREE_VEC_ELT (OMP_FOR_COND (omp_for), i);
       incr = TREE_VEC_ELT (OMP_FOR_INCR (omp_for), i);
 
+      if (!processing_template_decl)
+       {
+         if (TREE_CODE (TREE_OPERAND (init, 1)) == TREE_VEC)
+           {
+             tree t = TREE_VEC_ELT (TREE_OPERAND (init, 1), 1);
+             TREE_VEC_ELT (TREE_OPERAND (init, 1), 1)
+               = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+             t = TREE_VEC_ELT (TREE_OPERAND (init, 1), 2);
+             TREE_VEC_ELT (TREE_OPERAND (init, 1), 2)
+               = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+           }
+         else
+           {
+             tree t = TREE_OPERAND (init, 1);
+             TREE_OPERAND (init, 1)
+               = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+           }
+         if (TREE_CODE (TREE_OPERAND (cond, 1)) == TREE_VEC)
+           {
+             tree t = TREE_VEC_ELT (TREE_OPERAND (cond, 1), 1);
+             TREE_VEC_ELT (TREE_OPERAND (cond, 1), 1)
+               = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+             t = TREE_VEC_ELT (TREE_OPERAND (cond, 1), 2);
+             TREE_VEC_ELT (TREE_OPERAND (cond, 1), 2)
+               = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+           }
+         else
+           {
+             tree t = TREE_OPERAND (cond, 1);
+             TREE_OPERAND (cond, 1)
+               = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+           }
+       }
+
       if (TREE_CODE (incr) != MODIFY_EXPR)
        continue;
 
index 54a6d318dc555c7b8c1ed730e0aca17967ba9e67..2ff837b2f9a983f0a96ee321a74f8cefc0d940cf 100644 (file)
@@ -1512,8 +1512,11 @@ dump_gimple_omp_for (pretty_printer *buffer, const gomp_for *gs, int spc,
          dump_generic_node (buffer, gimple_omp_for_index (gs, i), spc,
                             flags, false);
          pp_string (buffer, " = ");
-         dump_generic_node (buffer, gimple_omp_for_initial (gs, i), spc,
-                            flags, false);
+         tree init = gimple_omp_for_initial (gs, i);
+         if (TREE_CODE (init) != TREE_VEC)
+           dump_generic_node (buffer, init, spc, flags, false);
+         else
+           dump_omp_loop_non_rect_expr (buffer, init, spc, flags);
          pp_string (buffer, "; ");
 
          dump_generic_node (buffer, gimple_omp_for_index (gs, i), spc,
@@ -1540,8 +1543,11 @@ dump_gimple_omp_for (pretty_printer *buffer, const gomp_for *gs, int spc,
              gcc_unreachable ();
            }
          pp_space (buffer);
-         dump_generic_node (buffer, gimple_omp_for_final (gs, i), spc,
-                            flags, false);
+         tree cond = gimple_omp_for_final (gs, i);
+         if (TREE_CODE (cond) != TREE_VEC)
+           dump_generic_node (buffer, cond, spc, flags, false);
+         else
+           dump_omp_loop_non_rect_expr (buffer, cond, spc, flags);
          pp_string (buffer, "; ");
 
          dump_generic_node (buffer, gimple_omp_for_index (gs, i), spc,
index ba19017709279ace66b3d26321e26455ad0536fe..89d81ba904aed77520f5110377dbdb077df2a181 100644 (file)
@@ -11749,7 +11749,26 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
   switch (TREE_CODE (for_stmt))
     {
     case OMP_FOR:
+      if (OMP_FOR_NON_RECTANGULAR (inner_for_stmt ? inner_for_stmt : for_stmt))
+       {
+         if (omp_find_clause (OMP_FOR_CLAUSES (for_stmt),
+                              OMP_CLAUSE_SCHEDULE))
+           error_at (EXPR_LOCATION (for_stmt),
+                     "%qs clause may not appear on non-rectangular %qs",
+                     "schedule", "for");
+         if (omp_find_clause (OMP_FOR_CLAUSES (for_stmt), OMP_CLAUSE_ORDERED))
+           error_at (EXPR_LOCATION (for_stmt),
+                     "%qs clause may not appear on non-rectangular %qs",
+                     "ordered", "for");
+       }
+      break;
     case OMP_DISTRIBUTE:
+      if (OMP_FOR_NON_RECTANGULAR (inner_for_stmt ? inner_for_stmt : for_stmt)
+         && omp_find_clause (OMP_FOR_CLAUSES (for_stmt),
+                             OMP_CLAUSE_DIST_SCHEDULE))
+       error_at (EXPR_LOCATION (for_stmt),
+                 "%qs clause may not appear on non-rectangular %qs",
+                 "dist_schedule", "distribute");
       break;
     case OACC_LOOP:
       ort = ORT_ACC;
@@ -12342,8 +12361,18 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
       else
        var = decl;
 
-      tret = gimplify_expr (&TREE_OPERAND (t, 1), &for_pre_body, NULL,
-                           is_gimple_val, fb_rvalue, false);
+      if (TREE_CODE (TREE_OPERAND (t, 1)) == TREE_VEC)
+       {
+         tree lb = TREE_OPERAND (t, 1);
+         tret = gimplify_expr (&TREE_VEC_ELT (lb, 1), &for_pre_body, NULL,
+                               is_gimple_val, fb_rvalue, false);
+         ret = MIN (ret, tret);
+         tret = gimplify_expr (&TREE_VEC_ELT (lb, 2), &for_pre_body, NULL,
+                               is_gimple_val, fb_rvalue, false);
+       }
+      else
+       tret = gimplify_expr (&TREE_OPERAND (t, 1), &for_pre_body, NULL,
+                             is_gimple_val, fb_rvalue, false);
       ret = MIN (ret, tret);
       if (ret == GS_ERROR)
        return ret;
@@ -12353,8 +12382,18 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
       gcc_assert (COMPARISON_CLASS_P (t));
       gcc_assert (TREE_OPERAND (t, 0) == decl);
 
-      tret = gimplify_expr (&TREE_OPERAND (t, 1), &for_pre_body, NULL,
-                           is_gimple_val, fb_rvalue, false);
+      if (TREE_CODE (TREE_OPERAND (t, 1)) == TREE_VEC)
+       {
+         tree ub = TREE_OPERAND (t, 1);
+         tret = gimplify_expr (&TREE_VEC_ELT (ub, 1), &for_pre_body, NULL,
+                               is_gimple_val, fb_rvalue, false);
+         ret = MIN (ret, tret);
+         tret = gimplify_expr (&TREE_VEC_ELT (ub, 2), &for_pre_body, NULL,
+                               is_gimple_val, fb_rvalue, false);
+       }
+      else
+       tret = gimplify_expr (&TREE_OPERAND (t, 1), &for_pre_body, NULL,
+                             is_gimple_val, fb_rvalue, false);
       ret = MIN (ret, tret);
 
       /* Handle OMP_FOR_INCR.  */
@@ -12496,6 +12535,20 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
                pop_gimplify_context (bind);
              }
        }
+      if (OMP_FOR_NON_RECTANGULAR (for_stmt) && var != decl)
+       for (int j = i + 1; j < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); j++)
+         {
+           t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), j);
+           gcc_assert (TREE_CODE (t) == MODIFY_EXPR);
+           if (TREE_CODE (TREE_OPERAND (t, 1)) == TREE_VEC
+               && TREE_VEC_ELT (TREE_OPERAND (t, 1), 0) == decl)
+             TREE_VEC_ELT (TREE_OPERAND (t, 1), 0) = var;
+           t = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), j);
+           gcc_assert (COMPARISON_CLASS_P (t));
+           if (TREE_CODE (TREE_OPERAND (t, 1)) == TREE_VEC
+               && TREE_VEC_ELT (TREE_OPERAND (t, 1), 0) == decl)
+             TREE_VEC_ELT (TREE_OPERAND (t, 1), 0) = var;
+         }
     }
 
   BITMAP_FREE (has_decl_expr);
@@ -12540,6 +12593,27 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
        t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i);
        TREE_OPERAND (t, 1) = copy_node (TREE_OPERAND (t, 1));
        TREE_OPERAND (TREE_OPERAND (t, 1), 0) = var;
+       if (OMP_FOR_NON_RECTANGULAR (for_stmt))
+         for (int j = i + 1;
+              j < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); j++)
+           {
+             t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), j);
+             gcc_assert (TREE_CODE (t) == MODIFY_EXPR);
+             if (TREE_CODE (TREE_OPERAND (t, 1)) == TREE_VEC
+                 && TREE_VEC_ELT (TREE_OPERAND (t, 1), 0) == decl)
+               {
+                 TREE_OPERAND (t, 1) = copy_node (TREE_OPERAND (t, 1));
+                 TREE_VEC_ELT (TREE_OPERAND (t, 1), 0) = var;
+               }
+             t = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), j);
+             gcc_assert (COMPARISON_CLASS_P (t));
+             if (TREE_CODE (TREE_OPERAND (t, 1)) == TREE_VEC
+                 && TREE_VEC_ELT (TREE_OPERAND (t, 1), 0) == decl)
+               {
+                 TREE_OPERAND (t, 1) = copy_node (TREE_OPERAND (t, 1));
+                 TREE_VEC_ELT (TREE_OPERAND (t, 1), 0) = var;
+               }
+         }
       }
 
   gimplify_adjust_omp_clauses (pre_p, for_body,
index db2ae54feab8a4dfd4ae86be384bd62a35c191aa..a44724f919535e3477ef8d9f2772bc383bae0d08 100644 (file)
@@ -6587,14 +6587,22 @@ expand_omp_for (struct omp_region *region, gimple *inner_stmt)
     expand_omp_for_generic (region, &fd, BUILT_IN_NONE, BUILT_IN_NONE,
                            NULL_TREE, inner_stmt);
   else if (gimple_omp_for_kind (fd.for_stmt) == GF_OMP_FOR_KIND_SIMD)
-    expand_omp_simd (region, &fd);
+    {
+      if (fd.non_rect)
+       sorry_at (gimple_location (fd.for_stmt),
+                 "non-rectangular %<simd%> not supported yet");
+      expand_omp_simd (region, &fd);
+    }
   else if (gimple_omp_for_kind (fd.for_stmt) == GF_OMP_FOR_KIND_OACC_LOOP)
     {
-      gcc_assert (!inner_stmt);
+      gcc_assert (!inner_stmt && !fd.non_rect);
       expand_oacc_for (region, &fd);
     }
   else if (gimple_omp_for_kind (fd.for_stmt) == GF_OMP_FOR_KIND_TASKLOOP)
     {
+      if (fd.non_rect)
+       sorry_at (gimple_location (fd.for_stmt),
+                 "non-rectangular %<taskloop%> not supported yet");
       if (gimple_omp_for_combined_into_p (fd.for_stmt))
        expand_omp_taskloop_for_inner (region, &fd, inner_stmt);
       else
@@ -6603,6 +6611,9 @@ expand_omp_for (struct omp_region *region, gimple *inner_stmt)
   else if (fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC
           && !fd.have_ordered)
     {
+      if (fd.non_rect)
+       sorry_at (gimple_location (fd.for_stmt),
+                 "non-rectangular OpenMP loops not supported yet");
       if (fd.chunk_size == NULL)
        expand_omp_for_static_nochunk (region, &fd, inner_stmt);
       else
@@ -6615,7 +6626,7 @@ expand_omp_for (struct omp_region *region, gimple *inner_stmt)
       tree sched_arg = NULL_TREE;
 
       gcc_assert (gimple_omp_for_kind (fd.for_stmt)
-                 == GF_OMP_FOR_KIND_FOR);
+                 == GF_OMP_FOR_KIND_FOR && !fd.non_rect);
       if (fd.chunk_size == NULL
          && fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC)
        fd.chunk_size = integer_zero_node;
index f479e27b9f305bceeab3a032997c12ea4200e924..18d722a7129385b432e9c338e1f2d337c32e6fd2 100644 (file)
@@ -201,6 +201,7 @@ omp_extract_for_data (gomp_for *for_stmt, struct omp_for_data *fd,
   fd->have_pointer_condtemp = false;
   fd->have_scantemp = false;
   fd->have_nonctrl_scantemp = false;
+  fd->non_rect = false;
   fd->lastprivate_conditional = 0;
   fd->tiling = NULL_TREE;
   fd->collapse = 1;
@@ -330,12 +331,45 @@ omp_extract_for_data (gomp_for *for_stmt, struct omp_for_data *fd,
                  || TREE_CODE (TREE_TYPE (loop->v)) == POINTER_TYPE);
       var = TREE_CODE (loop->v) == SSA_NAME ? SSA_NAME_VAR (loop->v) : loop->v;
       loop->n1 = gimple_omp_for_initial (for_stmt, i);
+      loop->m1 = NULL_TREE;
+      loop->m2 = NULL_TREE;
+      loop->outer = 0;
+      if (TREE_CODE (loop->n1) == TREE_VEC)
+       {
+         for (int j = i - 1; j >= 0; j--)
+           if (TREE_VEC_ELT (loop->n1, 0) == gimple_omp_for_index (for_stmt, j))
+             {
+               loop->outer = i - j;
+               break;
+             }
+         gcc_assert (loop->outer);
+         loop->m1 = TREE_VEC_ELT (loop->n1, 1);
+         loop->n1 = TREE_VEC_ELT (loop->n1, 2);
+         fd->non_rect = true;
+       }
 
       loop->cond_code = gimple_omp_for_cond (for_stmt, i);
       loop->n2 = gimple_omp_for_final (for_stmt, i);
       gcc_assert (loop->cond_code != NE_EXPR
                  || (gimple_omp_for_kind (for_stmt)
                      != GF_OMP_FOR_KIND_OACC_LOOP));
+      if (TREE_CODE (loop->n2) == TREE_VEC)
+       {
+         if (loop->outer)
+           gcc_assert (TREE_VEC_ELT (loop->n2, 0)
+                       == gimple_omp_for_index (for_stmt, i - loop->outer));
+         else
+           for (int j = i - 1; j >= 0; j--)
+             if (TREE_VEC_ELT (loop->n2, 0) == gimple_omp_for_index (for_stmt, j))
+               {
+                 loop->outer = i - j;
+                 break;
+               }
+         gcc_assert (loop->outer);
+         loop->m2 = TREE_VEC_ELT (loop->n2, 1);
+         loop->n2 = TREE_VEC_ELT (loop->n2, 2);
+         fd->non_rect = true;
+       }
 
       t = gimple_omp_for_incr (for_stmt, i);
       gcc_assert (TREE_OPERAND (t, 0) == var);
@@ -357,6 +391,10 @@ omp_extract_for_data (gomp_for *for_stmt, struct omp_for_data *fd,
              = build_nonstandard_integer_type
                  (TYPE_PRECISION (TREE_TYPE (loop->v)), 1);
        }
+      else if (loop->m1 || loop->m2)
+       /* Non-rectangular loops should use static schedule and no
+          ordered clause.  */
+       gcc_unreachable ();
       else if (iter_type != long_long_unsigned_type_node)
        {
          if (POINTER_TYPE_P (TREE_TYPE (loop->v)))
@@ -406,13 +444,18 @@ omp_extract_for_data (gomp_for *for_stmt, struct omp_for_data *fd,
 
       if (collapse_count && *collapse_count == NULL)
        {
-         t = fold_binary (loop->cond_code, boolean_type_node,
-                          fold_convert (TREE_TYPE (loop->v), loop->n1),
-                          fold_convert (TREE_TYPE (loop->v), loop->n2));
+         if (loop->m1 || loop->m2)
+           t = NULL_TREE;
+         else
+           t = fold_binary (loop->cond_code, boolean_type_node,
+                            fold_convert (TREE_TYPE (loop->v), loop->n1),
+                            fold_convert (TREE_TYPE (loop->v), loop->n2));
          if (t && integer_zerop (t))
            count = build_zero_cst (long_long_unsigned_type_node);
          else if ((i == 0 || count != NULL_TREE)
                   && TREE_CODE (TREE_TYPE (loop->v)) == INTEGER_TYPE
+                  && loop->m1 == NULL_TREE
+                  && loop->m2 == NULL_TREE
                   && TREE_CONSTANT (loop->n1)
                   && TREE_CONSTANT (loop->n2)
                   && TREE_CODE (loop->step) == INTEGER_CST)
@@ -486,6 +529,9 @@ omp_extract_for_data (gomp_for *for_stmt, struct omp_for_data *fd,
       fd->loop.n1 = build_int_cst (TREE_TYPE (fd->loop.v), 0);
       fd->loop.n2 = *collapse_count;
       fd->loop.step = build_int_cst (TREE_TYPE (fd->loop.v), 1);
+      fd->loop.m1 = NULL_TREE;
+      fd->loop.m2 = NULL_TREE;
+      fd->loop.outer = 0;
       fd->loop.cond_code = LT_EXPR;
     }
   else if (loops)
index 4b6f0e3e43f6b0db51d9578009163a825303a7af..499982ad2ac27ac3bea2598a225f0c121ab21247 100644 (file)
@@ -44,11 +44,16 @@ enum oacc_loop_flags {
 };
 
 /* A structure holding the elements of:
-   for (V = N1; V cond N2; V += STEP) [...] */
+   for (V = N1; V cond N2; V += STEP) [...]
+   or for non-rectangular loops:
+   for (V = M1 * W + N1; V cond M2 * W + N2; V += STEP;
+   where W is V of the OUTER-th loop (e.g. for OUTER 1 it is the
+   the index of the immediately surrounding loop).  */
 
 struct omp_for_data_loop
 {
-  tree v, n1, n2, step;
+  tree v, n1, n2, step, m1, m2;
+  int outer;
   enum tree_code cond_code;
 };
 
@@ -65,6 +70,7 @@ struct omp_for_data
   int ordered;
   bool have_nowait, have_ordered, simd_schedule, have_reductemp;
   bool have_pointer_condtemp, have_scantemp, have_nonctrl_scantemp;
+  bool non_rect;
   int lastprivate_conditional;
   unsigned char sched_modifiers;
   enum omp_clause_schedule_kind sched_kind;
index c3972383bcf6ca55dfb121785eadc5939debe4e3..c5279646ff39589d762ceda73066afba3b292950 100644 (file)
@@ -11230,13 +11230,31 @@ lower_omp_for (gimple_stmt_iterator *gsi_p, omp_context *ctx)
   for (i = 0; i < gimple_omp_for_collapse (stmt); i++)
     {
       rhs_p = gimple_omp_for_initial_ptr (stmt, i);
-      if (!is_gimple_min_invariant (*rhs_p))
+      if (TREE_CODE (*rhs_p) == TREE_VEC)
+       {
+         if (!is_gimple_min_invariant (TREE_VEC_ELT (*rhs_p, 1)))
+           TREE_VEC_ELT (*rhs_p, 1)
+             = get_formal_tmp_var (TREE_VEC_ELT (*rhs_p, 1), &cnt_list);
+         if (!is_gimple_min_invariant (TREE_VEC_ELT (*rhs_p, 2)))
+           TREE_VEC_ELT (*rhs_p, 1)
+             = get_formal_tmp_var (TREE_VEC_ELT (*rhs_p, 2), &cnt_list);
+       }
+      else if (!is_gimple_min_invariant (*rhs_p))
        *rhs_p = get_formal_tmp_var (*rhs_p, &cnt_list);
       else if (TREE_CODE (*rhs_p) == ADDR_EXPR)
        recompute_tree_invariant_for_addr_expr (*rhs_p);
 
       rhs_p = gimple_omp_for_final_ptr (stmt, i);
-      if (!is_gimple_min_invariant (*rhs_p))
+      if (TREE_CODE (*rhs_p) == TREE_VEC)
+       {
+         if (!is_gimple_min_invariant (TREE_VEC_ELT (*rhs_p, 1)))
+           TREE_VEC_ELT (*rhs_p, 1)
+             = get_formal_tmp_var (TREE_VEC_ELT (*rhs_p, 1), &cnt_list);
+         if (!is_gimple_min_invariant (TREE_VEC_ELT (*rhs_p, 2)))
+           TREE_VEC_ELT (*rhs_p, 1)
+             = get_formal_tmp_var (TREE_VEC_ELT (*rhs_p, 2), &cnt_list);
+       }
+      else if (!is_gimple_min_invariant (*rhs_p))
        *rhs_p = get_formal_tmp_var (*rhs_p, &cnt_list);
       else if (TREE_CODE (*rhs_p) == ADDR_EXPR)
        recompute_tree_invariant_for_addr_expr (*rhs_p);
index 87b0e1e4a7e935dd106f7ecf807ffe6f97cfff96..62c4c6033d776361742ba5b608c6c6103c7cf908 100644 (file)
@@ -1,3 +1,18 @@
+2021-02-09  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+       Backport from mainline
+       2020-06-16  Jakub Jelinek  <jakub@redhat.com>
+
+       * c-c++-common/gomp/loop-6.c: New test.
+       * gcc.dg/gomp/loop-1.c: Don't expect diagnostics on valid
+       non-rectangular loops.
+       * gcc.dg/gomp/loop-2.c: New test.
+       * g++.dg/gomp/loop-1.C: Don't expect diagnostics on valid
+       non-rectangular loops.
+       * g++.dg/gomp/loop-2.C: Likewise.
+       * g++.dg/gomp/loop-5.C: New test.
+       * g++.dg/gomp/loop-6.C: New test.
+
 2021-01-22  Kwok Cheung Yeung  <kcy@codesourcery.com>
 
        Backport from mainline
diff --git a/gcc/testsuite/c-c++-common/gomp/loop-6.c b/gcc/testsuite/c-c++-common/gomp/loop-6.c
new file mode 100644 (file)
index 0000000..0d4474d
--- /dev/null
@@ -0,0 +1,113 @@
+int bar (int);
+int baz (int *);
+
+void
+f1 (int x)
+{
+  int i = 0, j = 0, k = 0;
+  long long l = 0;
+  #pragma omp for collapse(2)
+  for (i = 0; i < 16; i = i + 2)
+    for (j = i * i; j < 16; j += 2)    /* { dg-error "initializer expression refers to iteration variable" } */
+      ;
+  #pragma omp for collapse(2)
+  for (i = 0; i < 16; i = i + 2)
+    for (j = i + 3; j < (i + 1) * 2; j += 2)   /* { dg-error "condition expression refers to iteration variable" } */
+      ;
+  #pragma omp for collapse(2)
+  for (i = 0; i < 16; i = i + 2)
+    for (j = (i + 1) * 2; j < i * 8; j += 2)   /* { dg-error "initializer expression refers to iteration variable" } */
+      ;
+  #pragma omp for collapse(3)
+  for (i = 0; i < 16; i = i + 2)
+    for (j = 0; j < 16; j++)
+      for (k = i + j; k < 32; k++)     /* { dg-error "initializer expression refers to iteration variable" } */
+       ;
+  #pragma omp for collapse(2)
+  for (l = 0; l < 16; l++)
+    for (j = 0; j < l; j++)            /* { dg-error "outer iteration variable 'l' used in condition expression has type other than 'int'" } */
+      ;
+  #pragma omp for collapse(2)          /* { dg-error "outer iteration variable 'l' used in initializer expression has type other than 'int'" "" { target c } } */
+  for (l = 0; l < 16; l++)             /* { dg-error "outer iteration variable 'l' used in initializer expression has type other than 'int'" "" { target c++ } } */
+    for (j = 7LL * l; j < 32; j++)
+      ;
+  #pragma omp for collapse(2)
+  for (i = 0; i < 16; i = i + 2)
+    for (j = i + 3; j < i * 2 + 2; j += 2)
+      ;
+  #pragma omp for collapse(2)
+  for (i = 0; i < 16; i = i + 2)
+    for (j = i * 2 + 2; j < i * 6 + 2; j += 2)
+      ;
+  #pragma omp for collapse(3)
+  for (i = 0; i < 16; i = i + 2)
+    for (j = 0; j < 16; j++)
+      for (k = 14 + 7 * i; k < 32 * j; k++)    /* { dg-error "two different outer iteration variables 'i' and 'j' used in a single loop" } */
+       ;
+  #pragma omp for schedule(static, 2) collapse(2)      /* { dg-error "'schedule' clause may not appear on non-rectangular 'for'" } */
+  for (i = 0; i < 16; i++)
+    for (j = 1; j < i; j++)
+      ;
+  #pragma omp for schedule(static) collapse(2)         /* { dg-error "'schedule' clause may not appear on non-rectangular 'for'" } */
+  for (i = 0; i < 16; i++)
+    for (j = 1; j < i; j++)
+      ;
+  #pragma omp for schedule(dynamic, 5) collapse(2)     /* { dg-error "'schedule' clause may not appear on non-rectangular 'for'" } */
+  for (i = 0; i < 16; i++)
+    for (j = 1; j < i; j++)
+      ;
+  #pragma omp for ordered collapse(2)                  /* { dg-error "'ordered' clause may not appear on non-rectangular 'for'" } */
+  for (i = 0; i < 16; i++)
+    for (j = 1; j < i; j++)
+      ;
+  #pragma omp for ordered collapse(2)                  /* { dg-error "'ordered' clause may not appear on non-rectangular 'for'" } */
+  for (i = 0; i < 16; i++)
+    for (j = 1; j < i; j++)
+      ;
+  #pragma omp for ordered (3) collapse (2)             /* { dg-error "'ordered' clause may not appear on non-rectangular 'for'" } */
+  for (i = 0; i < 64; i++)
+    for (j = 0; j < i; j++)
+      for (k = 0; k < 64; k++)
+        {
+          #pragma omp ordered depend (sink: i - 1, j - 2, k - 3)
+          #pragma omp ordered depend (source)
+        }
+  #pragma omp for ordered (3) collapse (2)             /* { dg-error "'ordered' clause may not appear on non-rectangular 'for'" } */
+  for (i = 0; i < 64; i++)
+    for (j = 0; j < 64; j++)
+      for (k = i; k < 64; k++)
+        {
+          #pragma omp ordered depend (sink: i - 1, j - 2, k - 3)
+          #pragma omp ordered depend (source)
+        }
+  #pragma omp for simd schedule(simd: static) collapse(2)      /* { dg-error "'schedule' clause may not appear on non-rectangular 'for'" } */
+  for (i = 0; i < 16; i++)
+    for (j = 1; j < i; j++)
+      ;
+}
+
+void
+f2 (void)
+{
+  int i = 0, j = 0;
+  #pragma omp distribute dist_schedule(static, 4) collapse(2)  /* { dg-error "'dist_schedule' clause may not appear on non-rectangular 'distribute'" } */
+  for (i = 0; i < 64; i++)
+    for (j = i; j < 64; j++)
+      ;
+  #pragma omp distribute collapse(2) dist_schedule(static)     /* { dg-error "'dist_schedule' clause may not appear on non-rectangular 'distribute'" } */
+  for (i = 0; i < 64; i++)
+    for (j = i; j < 64; j++)
+      ;
+  #pragma omp distribute parallel for simd schedule(simd: static) collapse(2)  /* { dg-error "'schedule' clause may not appear on non-rectangular 'for'" } */
+  for (i = 0; i < 16; i++)
+    for (j = 1; j < i; j++)
+      ;
+  #pragma omp distribute parallel for simd collapse(2) dist_schedule(static)   /* { dg-error "'dist_schedule' clause may not appear on non-rectangular 'distribute'" } */
+  for (i = 0; i < 64; i++)
+    for (j = i; j < 64; j++)
+      ;
+  #pragma omp distribute simd collapse(2) dist_schedule(static)        /* { dg-error "'dist_schedule' clause may not appear on non-rectangular 'distribute'" } */
+  for (i = 0; i < 64; i++)
+    for (j = i; j < 64; j++)
+      ;
+}
index b3db0f4736b9e752eb39757eee032c75524dfe74..abfd1e30424159ec4398bf2d92c420ccc7ae2461 100644 (file)
@@ -74,12 +74,12 @@ f1 (int x)
     for (j = 0; j < 16; j++)
       ;
   #pragma omp for collapse(2)
-  for (i = 0; i < 16; i = i + 2) /* { dg-error "initializer expression refers to iteration variable" } */
+  for (i = 0; i < 16; i = i + 2)
     for (j = i; j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < 16; i = i + 2)
-    for (j = i + 3; j < 16; j += 2) /* { dg-error "initializer expression refers to iteration variable" } */
+    for (j = i + 3; j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < 16; i++)
@@ -91,11 +91,11 @@ f1 (int x)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < 16; i++)
-    for (j = 0; j < i; j++) /* { dg-error "condition expression refers to iteration variable" } */
+    for (j = 0; j < i; j++)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < 16; i++)
-    for (j = 0; j < i + 4; j++) /* { dg-error "condition expression refers to iteration variable" } */
+    for (j = 0; j < i + 4; j++)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < j + 4; i++) /* { dg-error "condition expression refers to iteration variable" } */
@@ -207,12 +207,12 @@ f2 (int x)
     for (int j = 0; j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
-  for (int i = 0; i < 16; i = i + 2) /* { dg-error "initializer expression refers to iteration variable" } */
+  for (int i = 0; i < 16; i = i + 2)
     for (int j = i; j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i = i + 2)
-    for (int j = i + 3; j < 16; j += 2) /* { dg-error "initializer expression refers to iteration variable" } */
+    for (int j = i + 3; j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i++)
@@ -224,11 +224,11 @@ f2 (int x)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i++)
-    for (int j = 0; j < i; j++) /* { dg-error "condition expression refers to iteration variable" } */
+    for (int j = 0; j < i; j++)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i++)
-    for (int j = 0; j < i + 4; j++) /* { dg-error "condition expression refers to iteration variable" } */
+    for (int j = 0; j < i + 4; j++)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i++)
index 9deeaa5d8874a30d631399c1dd549f7736e156b6..327fb0e10fe3ed0d7e8c459ed45a7f584eb37b45 100644 (file)
@@ -75,12 +75,12 @@ f1 (int x)
     for (j = 0; j < 16; j++)
       ;
   #pragma omp for collapse(2)
-  for (i = 0; i < 16; i = i + 2) /* { dg-error "initializer expression refers to iteration variable" } */
+  for (i = 0; i < 16; i = i + 2)
     for (j = i; j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < 16; i = i + 2)
-    for (j = i + 3; j < 16; j += 2) /* { dg-error "initializer expression refers to iteration variable" } */
+    for (j = i + 3; j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < 16; i++)
@@ -92,11 +92,11 @@ f1 (int x)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < 16; i++)
-    for (j = 0; j < i; j++) /* { dg-error "condition expression refers to iteration variable" } */
+    for (j = 0; j < i; j++)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < 16; i++)
-    for (j = 0; j < i + 4; j++) /* { dg-error "condition expression refers to iteration variable" } */
+    for (j = 0; j < i + 4; j++)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < j + 4; i++) /* { dg-error "condition expression refers to iteration variable" } */
@@ -209,12 +209,12 @@ f2 (int x)
     for (int j = 0; j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
-  for (int i = 0; i < 16; i = i + 2) /* { dg-error "initializer expression refers to iteration variable" } */
+  for (int i = 0; i < 16; i = i + 2)
     for (int j = i; j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i = i + 2)
-    for (int j = i + 3; j < 16; j += 2) /* { dg-error "initializer expression refers to iteration variable" } */
+    for (int j = i + 3; j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i++)
@@ -226,11 +226,11 @@ f2 (int x)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i++)
-    for (int j = 0; j < i; j++) /* { dg-error "condition expression refers to iteration variable" } */
+    for (int j = 0; j < i; j++)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i++)
-    for (int j = 0; j < i + 4; j++) /* { dg-error "condition expression refers to iteration variable" } */
+    for (int j = 0; j < i + 4; j++)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i++)
diff --git a/gcc/testsuite/g++.dg/gomp/loop-5.C b/gcc/testsuite/g++.dg/gomp/loop-5.C
new file mode 100644 (file)
index 0000000..8601d03
--- /dev/null
@@ -0,0 +1,50 @@
+void
+foo ()
+{
+  int i = 0;
+  #pragma omp for collapse(2)
+  for (i = 0; i < 16; i++)     // { dg-error "the same loop iteration variables 'i' used in multiple associated loops" }
+    for (i = 1; i < 32; i++)
+      ;
+  #pragma omp taskloop collapse(2)
+  for (int j = 0; j < 16; j++) // { dg-error "the same loop iteration variables 'j' used in multiple associated loops" }
+    for (j = 0; j < 16; j++)
+      ;
+}
+
+template <int N>
+void
+bar ()
+{
+  int i = 0;
+  #pragma omp for collapse(2)
+  for (i = 0; i < 16; i++)     // { dg-error "the same loop iteration variables 'i' used in multiple associated loops" }
+    for (i = 1; i < 32; i++)
+      ;
+  #pragma omp taskloop collapse(2)
+  for (int j = 0; j < 16; j++) // { dg-error "the same loop iteration variables 'j' used in multiple associated loops" }
+    for (j = 0; j < 16; j++)
+      ;
+}
+
+template <typename T>
+void
+baz ()
+{
+  T i = 0;
+  #pragma omp for collapse(2)  // { dg-error "the same loop iteration variables 'i' used in multiple associated loops" }
+  for (i = 0; i < 16; i++)
+    for (i = 1; i < 32; i++)
+      ;
+  #pragma omp taskloop collapse(2)     // { dg-error "the same loop iteration variables 'j' used in multiple associated loops" }
+  for (T j = 0; j < 16; j++)
+    for (j = 0; j < 16; j++)
+      ;
+}
+
+void
+test ()
+{
+  bar <0> ();
+  baz <int> ();
+}
diff --git a/gcc/testsuite/g++.dg/gomp/loop-6.C b/gcc/testsuite/g++.dg/gomp/loop-6.C
new file mode 100644 (file)
index 0000000..902fef3
--- /dev/null
@@ -0,0 +1,69 @@
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+
+template <typename T>
+class I
+{
+public:
+  typedef ptrdiff_t difference_type;
+  I ();
+  ~I ();
+  I (T *);
+  I (const I &);
+  T &operator * ();
+  T *operator -> ();
+  T &operator [] (const difference_type &) const;
+  I &operator = (const I &);
+  I &operator ++ ();
+  I operator ++ (int);
+  I &operator -- ();
+  I operator -- (int);
+  I &operator += (const difference_type &);
+  I &operator -= (const difference_type &);
+  I operator + (const difference_type &) const;
+  I operator - (const difference_type &) const;
+  template <typename S> friend bool operator == (I<S> &, I<S> &);
+  template <typename S> friend bool operator == (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator < (I<S> &, I<S> &);
+  template <typename S> friend bool operator < (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator <= (I<S> &, I<S> &);
+  template <typename S> friend bool operator <= (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator > (I<S> &, I<S> &);
+  template <typename S> friend bool operator > (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator >= (I<S> &, I<S> &);
+  template <typename S> friend bool operator >= (const I<S> &, const I<S> &);
+  template <typename S> friend typename I<S>::difference_type operator - (I<S> &, I<S> &);
+  template <typename S> friend typename I<S>::difference_type operator - (const I<S> &, const I<S> &);
+  template <typename S> friend I<S> operator + (typename I<S>::difference_type , const I<S> &);
+private:
+  T *p;
+};
+
+template <typename T> bool operator == (I<T> &, I<T> &);
+template <typename T> bool operator == (const I<T> &, const I<T> &);
+template <typename T> bool operator != (I<T> &, I<T> &);
+template <typename T> bool operator != (const I<T> &, const I<T> &);
+template <typename T> bool operator < (I<T> &, I<T> &);
+template <typename T> bool operator < (const I<T> &, const I<T> &);
+template <typename T> bool operator <= (I<T> &, I<T> &);
+template <typename T> bool operator <= (const I<T> &, const I<T> &);
+template <typename T> bool operator > (I<T> &, I<T> &);
+template <typename T> bool operator > (const I<T> &, const I<T> &);
+template <typename T> bool operator >= (I<T> &, I<T> &);
+template <typename T> bool operator >= (const I<T> &, const I<T> &);
+template <typename T> typename I<T>::difference_type operator - (I<T> &, I<T> &);
+template <typename T> typename I<T>::difference_type operator - (const I<T> &, const I<T> &);
+template <typename T> I<T> operator + (typename I<T>::difference_type, const I<T> &);
+
+void
+f1 (I<int> &x, I<int> &y)
+{
+  I<int> i;
+  #pragma omp for collapse(2)
+  for (i = x; i < y; i++)      // { dg-error "the same loop iteration variables 'i' used in multiple associated loops" }
+    for (i = x; i < y; i++)
+      ;
+  #pragma omp for collapse(2)
+  for (I<int> j = x; j < y; j++)// { dg-error "the same loop iteration variables 'j' used in multiple associated loops" }
+    for (j = y; j > x; j--)
+      ;
+}
index 527d31929231c63990ca09f4d03543d8b48525e8..7ec634664f49e95c629a5d4782262ac3baf1fb3c 100644 (file)
@@ -73,13 +73,13 @@ f1 (int x)
   for (i = j; i < 16; i = i + 2)
     for (j = 0; j < 16; j++)
       ;
-  #pragma omp for collapse(2) /* { dg-error "initializer expression refers to iteration variable" } */
+  #pragma omp for collapse(2)
   for (i = 0; i < 16; i = i + 2)
     for (j = i; j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < 16; i = i + 2)
-    for (j = i + 3; j < 16; j += 2) /* { dg-error "initializer expression refers to iteration variable" } */
+    for (j = i + 3; j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < 16; i++)
@@ -91,11 +91,11 @@ f1 (int x)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < 16; i++)
-    for (j = 0; j < i; j++) /* { dg-error "condition expression refers to iteration variable" } */
+    for (j = 0; j < i; j++)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < 16; i++)
-    for (j = 0; j < i + 4; j++) /* { dg-error "condition expression refers to iteration variable" } */
+    for (j = 0; j < i + 4; j++)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < j + 4; i++) /* { dg-error "condition expression refers to iteration variable" } */
@@ -206,13 +206,13 @@ f2 (int x)
   for (int i = 0; i < 16; i = i + 2)
     for (int j = 0; j < 16; j += 2)
       ;
-  #pragma omp for collapse(2) /* { dg-error "initializer expression refers to iteration variable" } */
+  #pragma omp for collapse(2)
   for (int i = 0; i < 16; i = i + 2)
     for (int j = i; j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i = i + 2)
-    for (int j = i + 3; j < 16; j += 2) /* { dg-error "initializer expression refers to iteration variable" } */
+    for (int j = i + 3; j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i++)
@@ -224,11 +224,11 @@ f2 (int x)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i++)
-    for (int j = 0; j < i; j++) /* { dg-error "condition expression refers to iteration variable" } */
+    for (int j = 0; j < i; j++)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i++)
-    for (int j = 0; j < i + 4; j++) /* { dg-error "condition expression refers to iteration variable" } */
+    for (int j = 0; j < i + 4; j++)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i++)
diff --git a/gcc/testsuite/gcc.dg/gomp/loop-2.c b/gcc/testsuite/gcc.dg/gomp/loop-2.c
new file mode 100644 (file)
index 0000000..2917a4a
--- /dev/null
@@ -0,0 +1,13 @@
+void
+foo (void)
+{
+  int i = 0;
+  #pragma omp for collapse(2)  /* { dg-error "the same loop iteration variables 'i' used in multiple associated loops" } */
+  for (i = 0; i < 16; i++)
+    for (i = 1; i < 32; i++)
+      ;
+  #pragma omp taskloop collapse(2)     /* { dg-error "the same loop iteration variables 'j' used in multiple associated loops" } */
+  for (int j = 0; j < 16; j++)
+    for (j = 0; j < 16; j++)
+      ;
+}
index c8ccb43b072bba6e33f6de69ab1642089ca494f6..261cc9d76fca5215b65bef478ffa3f0aa2b8e431 100644 (file)
@@ -1625,7 +1625,36 @@ dump_mem_ref (pretty_printer *pp, tree node, int spc, dump_flags_t flags)
        }
       pp_right_bracket (pp);
     }
- }
+}
+
+/* Helper function for dump_generic_node.  Dump INIT or COND expression for
+   OpenMP loop non-rectangular iterators.  */
+
+void
+dump_omp_loop_non_rect_expr (pretty_printer *pp, tree node, int spc,
+                            dump_flags_t flags)
+{
+  gcc_assert (TREE_CODE (node) == TREE_VEC);
+  dump_generic_node (pp, TREE_VEC_ELT (node, 0), spc, flags, false);
+  pp_string (pp, " * ");
+  if (op_prio (TREE_VEC_ELT (node, 1)) <= op_code_prio (MULT_EXPR))
+    {
+      pp_left_paren (pp);
+      dump_generic_node (pp, TREE_VEC_ELT (node, 1), spc, flags, false);
+      pp_right_paren (pp);
+    }
+  else
+    dump_generic_node (pp, TREE_VEC_ELT (node, 1), spc, flags, false);
+  pp_string (pp, " + ");
+  if (op_prio (TREE_VEC_ELT (node, 1)) <= op_code_prio (PLUS_EXPR))
+    {
+      pp_left_paren (pp);
+      dump_generic_node (pp, TREE_VEC_ELT (node, 2), spc, flags, false);
+      pp_right_paren (pp);
+    }
+  else
+    dump_generic_node (pp, TREE_VEC_ELT (node, 2), spc, flags, false);
+}
 
 /* Dump the node NODE on the pretty_printer PP, SPC spaces of
    indent.  FLAGS specifies details to show in the dump (see TDF_* in
@@ -3460,13 +3489,34 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags,
                  spc += 2;
                  newline_and_indent (pp, spc);
                  pp_string (pp, "for (");
-                 dump_generic_node (pp,
-                                    TREE_VEC_ELT (OMP_FOR_INIT (node), i),
-                                    spc, flags, false);
+                 tree init = TREE_VEC_ELT (OMP_FOR_INIT (node), i);
+                 if (TREE_CODE (init) != MODIFY_EXPR
+                     || TREE_CODE (TREE_OPERAND (init, 1)) != TREE_VEC)
+                   dump_generic_node (pp, init, spc, flags, false);
+                 else
+                   {
+                     dump_generic_node (pp, TREE_OPERAND (init, 0),
+                                        spc, flags, false);
+                     pp_string (pp, " = ");
+                     dump_omp_loop_non_rect_expr (pp, TREE_OPERAND (init, 1),
+                                                  spc, flags);
+                   }
                  pp_string (pp, "; ");
-                 dump_generic_node (pp,
-                                    TREE_VEC_ELT (OMP_FOR_COND (node), i),
-                                    spc, flags, false);
+                 tree cond = TREE_VEC_ELT (OMP_FOR_COND (node), i);
+                 if (!COMPARISON_CLASS_P (cond)
+                     || TREE_CODE (TREE_OPERAND (cond, 1)) != TREE_VEC)
+                   dump_generic_node (pp, cond, spc, flags, false);
+                 else
+                   {
+                     dump_generic_node (pp, TREE_OPERAND (cond, 0),
+                                        spc, flags, false);
+                     const char *op = op_symbol (cond);
+                     pp_space (pp);
+                     pp_string (pp, op);
+                     pp_space (pp);
+                     dump_omp_loop_non_rect_expr (pp, TREE_OPERAND (cond, 1),
+                                                  spc, flags);
+                   }
                  pp_string (pp, "; ");
                  dump_generic_node (pp,
                                     TREE_VEC_ELT (OMP_FOR_INCR (node), i),
index 33a2d4031695e8f20bd50380dcde42bf3e4dbd8b..aca7679b49674ad61b0c0bf54593820a9226ef68 100644 (file)
@@ -42,6 +42,8 @@ extern char *print_generic_expr_to_str (tree);
 extern void dump_omp_clauses (pretty_printer *, tree, int, dump_flags_t);
 extern void dump_omp_atomic_memory_order (pretty_printer *,
                                          enum omp_memory_order);
+extern void dump_omp_loop_non_rect_expr (pretty_printer *, tree, int,
+                                        dump_flags_t);
 extern int dump_generic_node (pretty_printer *, tree, int, dump_flags_t, bool);
 extern void print_declaration (pretty_printer *, tree, int, dump_flags_t);
 extern int op_code_prio (enum tree_code);
index 61567c31db50c43e349e6071ecb3d1e7d71ed84e..8d9829c8b035eb62b3e302d2122e84d31f0cea9e 100644 (file)
@@ -1465,6 +1465,11 @@ class auto_suppress_location_wrappers
   != UNKNOWN_LOCATION)
 #define OMP_CLAUSE_LOCATION(NODE)  (OMP_CLAUSE_CHECK (NODE))->omp_clause.locus
 
+/* True on OMP_FOR and other OpenMP/OpenACC looping constructs if the loop nest
+   is non-rectangular.  */
+#define OMP_FOR_NON_RECTANGULAR(NODE) \
+  (OMP_LOOPING_CHECK (NODE)->base.private_flag)
+
 /* True on an OMP_SECTION statement that was the last lexical member.
    This status is meaningful in the implementation of lastprivate.  */
 #define OMP_SECTION_LAST(NODE) \