gcc/cp/ChangeLog
* parser.cc (cp_parser_omp_all_clauses): Allow comma before first
clause.
(cp_parser_see_omp_loop_nest): Accept C++ standard attributes
before RID_FOR.
(cp_parser_omp_loop_nest): Process C++ standard attributes like
pragmas. Improve error handling for bad pragmas/attributes.
Use cp_parser_see_omp_loop_nest instead of duplicating what it
does.
(cp_parser_omp_tile_sizes): Permit comma before the clause.
(cp_parser_omp_tile): Assert that this isn't called for inner
directive.
(cp_parser_omp_unroll): Likewise.
gcc/testsuite/ChangeLog
* g++.dg/gomp/loop-transforms/attrs-tile-1.C: New file.
* g++.dg/gomp/loop-transforms/attrs-tile-2.C: New file.
* g++.dg/gomp/loop-transforms/attrs-tile-3.C: New file.
* g++.dg/gomp/loop-transforms/attrs-unroll-1.C: New file.
* g++.dg/gomp/loop-transforms/attrs-unroll-2.C: New file.
* g++.dg/gomp/loop-transforms/attrs-unroll-3.C: New file.
* g++.dg/gomp/loop-transforms/attrs-unroll-inner-1.C: New file.
* g++.dg/gomp/loop-transforms/attrs-unroll-inner-2.C: New file.
* g++.dg/gomp/loop-transforms/attrs-unroll-inner-3.C: New file.
---
gcc/cp/ChangeLog.omp | 15 ++
gcc/cp/parser.cc | 69 ++++---
gcc/testsuite/ChangeLog.omp | 12 ++
.../gomp/loop-transforms/attrs-tile-1.C | 164 +++++++++++++++++
.../gomp/loop-transforms/attrs-tile-2.C | 174 ++++++++++++++++++
.../gomp/loop-transforms/attrs-tile-3.C | 111 +++++++++++
.../gomp/loop-transforms/attrs-unroll-1.C | 135 ++++++++++++++
.../gomp/loop-transforms/attrs-unroll-2.C | 81 ++++++++
.../gomp/loop-transforms/attrs-unroll-3.C | 20 ++
.../loop-transforms/attrs-unroll-inner-1.C | 15 ++
.../loop-transforms/attrs-unroll-inner-2.C | 29 +++
.../loop-transforms/attrs-unroll-inner-3.C | 71 +++++++
12 files changed, 872 insertions(+), 24 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-tile-1.C
create mode 100644 gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-tile-2.C
create mode 100644 gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-tile-3.C
create mode 100644 gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-1.C
create mode 100644 gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-2.C
create mode 100644 gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-3.C
create mode 100644
gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-inner-1.C
create mode 100644
gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-inner-2.C
create mode 100644
gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-inner-3.C
diff --git a/gcc/cp/ChangeLog.omp b/gcc/cp/ChangeLog.omp
index 1b2d71422d8..fe5ef67a7ad 100644
--- a/gcc/cp/ChangeLog.omp
+++ b/gcc/cp/ChangeLog.omp
@@ -1,3 +1,18 @@
+2023-08-18 Sandra Loosemore <[email protected]>
+
+ * parser.cc (cp_parser_omp_all_clauses): Allow comma before first
+ clause.
+ (cp_parser_see_omp_loop_nest): Accept C++ standard attributes
+ before RID_FOR.
+ (cp_parser_omp_loop_nest): Process C++ standard attributes like
+ pragmas. Improve error handling for bad pragmas/attributes.
+ Use cp_parser_see_omp_loop_nest instead of duplicating what it
+ does.
+ (cp_parser_omp_tile_sizes): Permit comma before the clause.
+ (cp_parser_omp_tile): Assert that this isn't called for inner
+ directive.
+ (cp_parser_omp_unroll): Likewise.
+
2023-08-18 Sandra Loosemore <[email protected]>
* parser.cc (cp_parser_omp_declare_mapper): Allow commas between
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 0ce2a7be608..4871f4511a9 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -42240,15 +42240,12 @@ cp_parser_omp_all_clauses (cp_parser *parser,
omp_clause_mask mask,
if (nested && cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
break;
- if (!first || nested != 2)
- {
- if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
- cp_lexer_consume_token (parser->lexer);
- else if (nested == 2)
- error_at (cp_lexer_peek_token (parser->lexer)->location,
- "clauses in %<simd%> trait should be separated "
- "by %<,%>");
- }
+ if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+ cp_lexer_consume_token (parser->lexer);
+ else if (!first && nested == 2)
+ error_at (cp_lexer_peek_token (parser->lexer)->location,
+ "clauses in %<simd%> trait should be separated "
+ "by %<,%>");
token = cp_lexer_peek_token (parser->lexer);
c_kind = cp_parser_omp_clause_name (parser);
@@ -44803,6 +44800,11 @@ cp_parser_see_omp_loop_nest (cp_parser *parser, enum
tree_code code,
|| (cp_parser_pragma_kind (cp_lexer_peek_token (parser->lexer))
== PRAGMA_OMP_TILE))
return true;
+ if (cp_lexer_nth_token_is_keyword
+ (parser->lexer,
+ cp_parser_skip_std_attribute_spec_seq (parser, 1),
+ RID_FOR))
+ return true;
if (error_p)
cp_parser_error (parser, "loop nest expected");
}
@@ -44868,6 +44870,11 @@ cp_parser_omp_loop_nest (cp_parser *parser, bool *if_p)
the depth of the *next* loop, not the level of the loop body the
transformation directive appears in. */
+ /* Arrange for C++ standard attribute syntax to be parsed as regular
+ pragmas. */
+ tree std_attrs = cp_parser_std_attribute_spec_seq (parser);
+ std_attrs = cp_parser_handle_statement_omp_attributes (parser, std_attrs);
+
if ((cp_parser_pragma_kind (cp_lexer_peek_token (parser->lexer))
== PRAGMA_OMP_UNROLL)
|| (cp_parser_pragma_kind (cp_lexer_peek_token (parser->lexer))
@@ -44893,19 +44900,29 @@ cp_parser_omp_loop_nest (cp_parser *parser, bool
*if_p)
omp_for_parse_state->orig_declv
= grow_tree_vec (omp_for_parse_state->orig_declv, count);
}
- if (cp_parser_see_omp_loop_nest (parser, omp_for_parse_state->code,
- true))
- return cp_parser_omp_loop_nest (parser, if_p);
- else
+ }
+
+ /* Diagnose errors if we don't have a "for" loop following the
+ optional loop transforms. Otherwise, consume the token. */
+ if (!cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR))
+ {
+ omp_for_parse_state->fail = true;
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+ /* Don't call cp_parser_error here since it overrides the
+ provided message with a more confusing one if there was
+ a bad pragma or attribute directive. */
+ error_at (token->location, "loop nest expected");
+ /* See if we can recover by skipping over bad pragma(s). */
+ while (token->type == CPP_PRAGMA)
{
- /* FIXME: Better error recovery here? */
- omp_for_parse_state->fail = true;
- return NULL_TREE;
+ cp_parser_skip_to_pragma_eol (parser, token);
+ if (cp_parser_see_omp_loop_nest (parser, omp_for_parse_state->code,
+ false))
+ return cp_parser_omp_loop_nest (parser, if_p);
+ token = cp_lexer_peek_token (parser->lexer);
}
+ return NULL_TREE;
}
-
- /* We have already matched the FOR token but not consumed it yet. */
- gcc_assert (cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR));
loc = cp_lexer_consume_token (parser->lexer)->location;
/* Forbid break/continue in the loop initializer, condition, and
@@ -45161,11 +45178,8 @@ cp_parser_omp_loop_nest (cp_parser *parser, bool *if_p)
moreloops = depth < omp_for_parse_state->count - 1;
omp_for_parse_state->want_nested_loop = moreloops;
if (moreloops
- && (cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR)
- || (cp_parser_pragma_kind (cp_lexer_peek_token (parser->lexer))
- == PRAGMA_OMP_UNROLL)
- || (cp_parser_pragma_kind (cp_lexer_peek_token (parser->lexer))
- == PRAGMA_OMP_TILE)))
+ && cp_parser_see_omp_loop_nest (parser, omp_for_parse_state->code,
+ false))
{
omp_for_parse_state->depth++;
add_stmt (cp_parser_omp_loop_nest (parser, if_p));
@@ -47323,6 +47337,9 @@ cp_parser_omp_tile_sizes (cp_parser *parser, location_t
loc)
tree sizes = NULL_TREE;
cp_lexer *lexer = parser->lexer;
+ if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+ cp_lexer_consume_token (parser->lexer);
+
cp_token *tok = cp_lexer_peek_token (lexer);
if (tok->type != CPP_NAME
|| strcmp ("sizes", IDENTIFIER_POINTER (tok->u.value)))
@@ -47375,6 +47392,8 @@ cp_parser_omp_tile (cp_parser *parser, cp_token *tok,
bool *if_p)
tree block;
tree ret = error_mark_node;
+ gcc_assert (!parser->omp_for_parse_state);
+
tree clauses = cp_parser_omp_tile_sizes (parser, tok->location);
cp_parser_require_pragma_eol (parser, tok);
@@ -47553,6 +47572,8 @@ cp_parser_omp_unroll (cp_parser *parser, cp_token *tok,
bool *if_p)
static const char *p_name = "#pragma omp unroll";
omp_clause_mask mask = OMP_UNROLL_CLAUSE_MASK;
+ gcc_assert (!parser->omp_for_parse_state);
+
tree clauses = cp_parser_omp_all_clauses (parser, mask, p_name, tok, true);
if (!clauses)
diff --git a/gcc/testsuite/ChangeLog.omp b/gcc/testsuite/ChangeLog.omp
index a7d11777988..3008a8e52eb 100644
--- a/gcc/testsuite/ChangeLog.omp
+++ b/gcc/testsuite/ChangeLog.omp
@@ -1,3 +1,15 @@
+2023-08-18 Sandra Loosemore <[email protected]>
+
+ * g++.dg/gomp/loop-transforms/attrs-tile-1.C: New file.
+ * g++.dg/gomp/loop-transforms/attrs-tile-2.C: New file.
+ * g++.dg/gomp/loop-transforms/attrs-tile-3.C: New file.
+ * g++.dg/gomp/loop-transforms/attrs-unroll-1.C: New file.
+ * g++.dg/gomp/loop-transforms/attrs-unroll-2.C: New file.
+ * g++.dg/gomp/loop-transforms/attrs-unroll-3.C: New file.
+ * g++.dg/gomp/loop-transforms/attrs-unroll-inner-1.C: New file.
+ * g++.dg/gomp/loop-transforms/attrs-unroll-inner-2.C: New file.
+ * g++.dg/gomp/loop-transforms/attrs-unroll-inner-3.C: New file.
+
2023-08-18 Sandra Loosemore <[email protected]>
* g++.dg/gomp/attrs-declare-mapper-3.C: New file.
diff --git a/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-tile-1.C
b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-tile-1.C
new file mode 100644
index 00000000000..0906ff3bbe8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-tile-1.C
@@ -0,0 +1,164 @@
+// { dg-do compile { target c++11 } }
+
+extern void dummy (int);
+
+void
+test ()
+{
+ [[omp::directive (tile sizes(1))]]
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::directive (tile sizes(0))]] /* { dg-error {'tile sizes' argument
needs positive integral constant} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::directive (tile sizes(-1))]] /* { dg-error {'tile sizes' argument
needs positive integral constant} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::directive (tile sizes())]] /* { dg-error {expected
primary-expression before} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::directive (tile sizes)]] /* { dg-error {expected '\(' before end of
line} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::directive (tile sizes(1) sizes(1))]] /* { dg-error {expected end of
line before 'sizes'} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::directive (tile, sizes(1), sizes(1))]] /* { dg-error {expected end
of line before ','} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::sequence
+ (directive (tile sizes(1)),
+ directive (tile sizes(1)))]]
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::sequence
+ (directive (tile sizes(1, 2)),
+ directive (tile sizes(1)))]] /* { dg-error {nesting depth left after
this transformation too low for outer transformation} } */
+ for (int i = 0; i < 100; ++i)
+ for (int j = 0; j < 100; ++j)
+ dummy (i);
+
+ [[omp::sequence
+ (directive (tile sizes(1, 2)),
+ directive (tile sizes(1, 2)))]]
+ for (int i = 0; i < 100; ++i)
+ for (int j = 0; j < 100; ++j)
+ dummy (i);
+
+ [[omp::sequence
+ (directive (tile sizes(5, 6)),
+ directive (tile sizes(1, 2, 3)))]]
+ for (int i = 0; i < 100; ++i)
+ for (int j = 0; j < 100; ++j)
+ for (int k = 0; k < 100; ++k)
+ dummy (i);
+
+ [[omp::sequence
+ (directive (tile sizes(1)),
+ directive (unroll partia), /* { dg-error {expected an OpenMP clause
before 'partia'} } */
+ directive (tile sizes(1)))]]
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::sequence
+ (directive (tile sizes(1)),
+ directive (unroll))]] /* { dg-error {'#pragma omp unroll' without
'partial' clause is invalid here; turns loop into non-loop} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::sequence
+ (directive (tile sizes(1)),
+ directive (unroll full))]] /* { dg-error {'full' clause is invalid
here; turns loop into non-loop} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::sequence
+ (directive (tile sizes(1)),
+ directive (unroll partial),
+ directive (tile sizes(1)))]]
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::sequence
+ (directive (tile sizes(8,8)),
+ directive (unroll partial), /* { dg-error {nesting depth left after
this transformation too low for outer transformation} } */
+ directive (tile sizes(1)))]]
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::sequence
+ (directive (tile sizes(8,8)),
+ directive (unroll partial))]] /* { dg-error {nesting depth left after
this transformation too low for outer transformation} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::directive (tile sizes(1, 2))]]
+ for (int i = 0; i < 100; ++i)
+ for (int j = 0; j < 100; ++j)
+ dummy (i);
+
+ [[omp::directive (tile sizes(1, 2))]] /* { dg-error {'tile' loop
transformation may not appear on non-rectangular for} } */
+ for (int i = 0; i < 100; ++i)
+ for (int j = i; j < 100; ++j)
+ dummy (i);
+
+ [[omp::directive (tile sizes(1, 2))]] /* { dg-error {'tile' loop
transformation may not appear on non-rectangular for} } */
+ for (int i = 0; i < 100; ++i)
+ for (int j = 2; j < i; ++j)
+ dummy (i);
+
+ [[omp::directive (tile sizes(1, 2, 3))]]
+ for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} } */
+ for (int j = 0; j < 100; ++j)
+ dummy (i);
+
+ [[omp::directive (tile sizes(1))]]
+ for (int i = 0; i < 100; ++i)
+ {
+ dummy (i);
+ for (int j = 0; j < 100; ++j)
+ dummy (i);
+ }
+
+ [[omp::directive (tile sizes(1))]]
+ for (int i = 0; i < 100; ++i)
+ {
+ for (int j = 0; j < 100; ++j)
+ dummy (j);
+ dummy (i);
+ }
+
+ [[omp::directive (tile sizes(1, 2))]]
+ for (int i = 0; i < 100; ++i) /* { dg-error {inner loops must be perfectly
nested} } */
+ {
+ dummy (i);
+ for (int j = 0; j < 100; ++j)
+ dummy (j);
+ }
+
+ [[omp::directive (tile sizes(1, 2))]]
+ for (int i = 0; i < 100; ++i) /* { dg-error {inner loops must be perfectly
nested} } */
+ {
+ for (int j = 0; j < 100; ++j)
+ dummy (j);
+ dummy (i);
+ }
+
+ int s;
+ [[omp::directive (tile sizes(s))]] /* { dg-error {'tile sizes' argument
needs positive integral constant} "" { target { ! c++98_only } } } */
+ /* { dg-error {the value of 's' is not usable in a constant expression} ""
{ target { c++ && { ! c++98_only } } } .-1 } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::directive (tile sizes(42.0))]] /* { dg-error {'tile sizes' argument
needs integral type} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+}
diff --git a/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-tile-2.C
b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-tile-2.C
new file mode 100644
index 00000000000..ab02924defa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-tile-2.C
@@ -0,0 +1,174 @@
+// { dg-do compile { target c++11 } }
+
+extern void dummy (int);
+
+void
+test ()
+{
+ [[omp::sequence (directive (parallel for),
+ directive (tile sizes(1)))]]
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::sequence (directive (parallel for),
+ directive (tile sizes(0)))]] /* { dg-error {'tile sizes' argument needs
positive integral constant} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::sequence (directive (parallel for),
+ directive (tile sizes(-1)))]] /* { dg-error {'tile sizes' argument needs
positive integral constant} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::sequence (directive (parallel for),
+ directive (tile sizes()))]] /* { dg-error {expected primary-expression
before} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::sequence (directive (parallel for),
+ directive (tile sizes(,)))]] /* { dg-error {expected primary-expression
before} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::sequence (directive (parallel for),
+ directive (tile sizes))]] /* { dg-error {expected '\(' before end of
line} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::sequence (directive (parallel for),
+ directive (tile sizes(1) sizes(1)))]] /* { dg-error {expected end of
line before 'sizes'} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::sequence (directive (parallel for),
+ directive (tile sizes(1)),
+ directive (tile sizes(1)))]]
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::sequence (directive (parallel for),
+ directive (tile sizes(1, 2)),
+ directive (tile sizes(1)))]] /* { dg-error {nesting depth left after
this transformation too low for outer transformation} } */
+ for (int i = 0; i < 100; ++i)
+ for (int j = 0; j < 100; ++j)
+ dummy (i);
+
+ [[omp::sequence (directive (parallel for),
+ directive (tile sizes(1, 2)),
+ directive (tile sizes(1, 2)))]]
+ for (int i = 0; i < 100; ++i)
+ for (int j = 0; j < 100; ++j)
+ dummy (i);
+
+ [[omp::sequence (directive (parallel for),
+ directive (tile sizes(5, 6)),
+ directive (tile sizes(1, 2, 3)))]]
+ for (int i = 0; i < 100; ++i)
+ for (int j = 0; j < 100; ++j)
+ for (int k = 0; k < 100; ++k)
+ dummy (i);
+
+ [[omp::sequence (directive (parallel for),
+ directive (tile sizes(1)),
+ directive (unroll partia), /* { dg-error {expected an OpenMP clause
before 'partia'} } */
+ directive (tile sizes(1)))]]
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::sequence (directive (parallel for),
+ directive (tile sizes(1)),
+ directive (unroll))]] /* { dg-error {'#pragma omp unroll' without
'partial' clause is invalid here; turns loop into non-loop} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::sequence (directive (parallel for),
+ directive (tile sizes(1)),
+ directive (unroll full))]] /* { dg-error {'full' clause is invalid here;
turns loop into non-loop} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::sequence (directive (parallel for),
+ directive (tile sizes(1)),
+ directive (unroll partial),
+ directive (tile sizes(1)))]]
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::sequence (directive (parallel for),
+ directive (tile sizes(8,8)),
+ directive (unroll partial), /* { dg-error {nesting depth left after this
transformation too low for outer transformation} } */
+ directive (tile sizes(1)))]]
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::sequence (directive (parallel for),
+ directive (tile sizes(8,8)),
+ directive (unroll partial))]] /* { dg-error {nesting depth left after
this transformation too low for outer transformation} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::sequence (directive (parallel for),
+ directive (tile sizes(1, 2)))]]
+ for (int i = 0; i < 100; ++i)
+ for (int j = 0; j < 100; ++j)
+ dummy (i);
+
+ [[omp::sequence (directive (parallel for),
+ directive (tile sizes(1, 2)))]] /* { dg-error {'tile' loop
transformation may not appear on non-rectangular for} } */
+ for (int i = 0; i < 100; ++i)
+ for (int j = i; j < 100; ++j)
+ dummy (i);
+
+ [[omp::sequence (directive (parallel for),
+ directive (tile sizes(1, 2)))]] /* { dg-error {'tile' loop
transformation may not appear on non-rectangular for} } */
+ for (int i = 0; i < 100; ++i)
+ for (int j = 2; j < i; ++j)
+ dummy (i);
+
+ [[omp::sequence (directive (parallel for),
+ directive (tile sizes(1, 2, 3)))]]
+ for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} } */
+ for (int j = 0; j < 100; ++j)
+ dummy (i);
+
+ [[omp::sequence (directive (parallel for),
+ directive (tile sizes(1)))]]
+ for (int i = 0; i < 100; ++i)
+ {
+ dummy (i);
+ for (int j = 0; j < 100; ++j)
+ dummy (i);
+ }
+
+ [[omp::sequence (directive (parallel for),
+ directive (tile sizes(1)))]]
+ for (int i = 0; i < 100; ++i)
+ {
+ for (int j = 0; j < 100; ++j)
+ dummy (j);
+ dummy (i);
+ }
+
+ [[omp::sequence (directive (parallel for),
+ directive (tile sizes(1, 2)))]]
+ for (int i = 0; i < 100; ++i) /* { dg-error {inner loops must be perfectly
nested} } */
+ {
+ dummy (i);
+ for (int j = 0; j < 100; ++j)
+ dummy (j);
+ }
+
+ [[omp::sequence (directive (parallel for),
+ directive (tile sizes(1, 2)))]]
+ for (int i = 0; i < 100; ++i) /* { dg-error {inner loops must be perfectly
nested} } */
+ {
+ for (int j = 0; j < 100; ++j)
+ dummy (j);
+ dummy (i);
+ }
+
+ [[omp::sequence (directive (parallel for),
+ directive (tile sizes(1)))]]
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+}
diff --git a/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-tile-3.C
b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-tile-3.C
new file mode 100644
index 00000000000..95a0115b014
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-tile-3.C
@@ -0,0 +1,111 @@
+// { dg-do compile { target c++11 } }
+
+extern void dummy (int);
+
+void
+test ()
+{
+ [[omp::sequence (directive (for),
+ directive (tile sizes(1, 2)))]] /* { dg-error {'tile' loop
transformation may not appear on non-rectangular for} } */
+ for (int i = 0; i < 100; ++i)
+ for (int j = i; j < 100; ++j)
+ dummy (i);
+
+ [[omp::sequence (directive (for),
+ directive (tile sizes(1, 2)))]] /* { dg-error {'tile' loop
transformation may not appear on non-rectangular for} } */
+ for (int i = 0; i < 100; ++i)
+ for (int j = 0; j < i; ++j)
+ dummy (i);
+
+
+ [[omp::sequence (directive (for collapse(1)),
+ directive (tile sizes(1)))]]
+ for (int i = 0; i < 100; ++i)
+ for (int j = 0; j < 100; ++j)
+ dummy (i);
+
+ [[omp::sequence (directive (for collapse(2)),
+ directive (tile sizes(1)))]] /* { dg-error {nesting depth left after
this transformation too low for loop collapse} } */
+ for (int i = 0; i < 100; ++i)
+ for (int j = 0; j < 100; ++j)
+ dummy (i);
+
+ [[omp::sequence (directive (for collapse(2)),
+ directive (tile sizes(1, 2)))]]
+ for (int i = 0; i < 100; ++i)
+ for (int j = 0; j < 100; ++j)
+ dummy (i);
+
+ [[omp::sequence (directive (for collapse(3)),
+ directive (tile sizes(1, 2)))]] /* { dg-error {nesting depth left after
this transformation too low for loop collapse} } */
+ for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} } */
+ for (int j = 0; j < 100; ++j)
+ dummy (i);
+
+ [[omp::sequence (directive (for collapse(1)),
+ directive (tile sizes(1)),
+ directive (tile sizes(1)))]]
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::sequence (directive (for collapse(2)),
+ directive (tile sizes(1, 2)),
+ directive (tile sizes(1)))]] /* { dg-error {nesting depth left after
this transformation too low for outer transformation} } */
+ for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} } */
+ dummy (i);
+
+ [[omp::sequence (directive (for collapse(2)),
+ directive (tile sizes(1, 2)),
+ directive (tile sizes(1, 2)))]]
+ for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} } */
+ dummy (i);
+
+ [[omp::sequence (directive (for collapse(2)),
+ directive (tile sizes(5, 6)),
+ directive (tile sizes(1, 2, 3)))]]
+ for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} } */
+ dummy (i);
+
+ [[omp::sequence (directive (for collapse(1)),
+ directive (tile sizes(1)),
+ directive (tile sizes(1)))]]
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ [[omp::sequence (directive (for collapse(2)),
+ directive (tile sizes(1, 2)),
+ directive (tile sizes(1)))]] /* { dg-error {nesting depth left after
this transformation too low for outer transformation} } */
+ for (int i = 0; i < 100; ++i)
+ for (int j = 0; j < 100; ++j)
+ dummy (i);
+
+ [[omp::sequence (directive (for collapse(2)),
+ directive (tile sizes(1, 2)),
+ directive (tile sizes(1, 2)))]]
+ for (int i = 0; i < 100; ++i)
+ for (int j = 0; j < 100; ++j)
+ dummy (i);
+
+ [[omp::sequence (directive (for collapse(2)),
+ directive (tile sizes(5, 6)),
+ directive (tile sizes(1, 2, 3)))]]
+ for (int i = 0; i < 100; ++i)
+ for (int j = 0; j < 100; ++j)
+ for (int k = 0; k < 100; ++k)
+ dummy (i);
+
+ [[omp::sequence (directive (for collapse(3)),
+ directive (tile sizes(1, 2)), /* { dg-error {nesting depth left after
this transformation too low for loop collapse} } */
+ directive (tile sizes(1, 2)))]]
+ for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} } */
+ for (int j = 0; j < 100; ++j)
+ dummy (i);
+
+ [[omp::sequence (directive (for collapse(3)),
+ directive (tile sizes(5, 6)), /* { dg-error {nesting depth left after
this transformation too low for loop collapse} } */
+ directive (tile sizes(1, 2, 3)))]]
+ for (int i = 0; i < 100; ++i)
+ for (int j = 0; j < 100; ++j)
+ for (int k = 0; k < 100; ++k)
+ dummy (i);
+}
diff --git a/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-1.C
b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-1.C
new file mode 100644
index 00000000000..5b93b9fa59e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-1.C
@@ -0,0 +1,135 @@
+// { dg-do compile { target c++11 } }
+
+extern void dummy (int);
+
+void
+test1 ()
+{
+[[omp::directive (unroll partial)]]
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+}
+
+void
+test2 ()
+{
+[[omp::directive (unroll partial(10))]]
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+}
+
+void
+test3 ()
+{
+[[omp::directive (unroll full)]]
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+}
+
+void
+test4 ()
+{
+[[omp::directive (unroll full)]]
+ for (int i = 0; i > 100; ++i)
+ dummy (i);
+}
+
+void
+test5 ()
+{
+[[omp::directive (unroll full)]]
+ for (int i = 1; i <= 100; ++i)
+ dummy (i);
+}
+
+void
+test6 ()
+{
+[[omp::directive (unroll full)]]
+ for (int i = 200; i >= 100; i--)
+ dummy (i);
+}
+
+void
+test7 ()
+{
+[[omp::directive (unroll full)]]
+ for (int i = -100; i > 100; ++i)
+ dummy (i);
+}
+
+void
+test8 ()
+{
+[[omp::directive (unroll full)]]
+ for (int i = 100; i > -200; --i)
+ dummy (i);
+}
+
+void
+test9 ()
+{
+[[omp::directive (unroll full)]]
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+}
+
+void
+test10 ()
+{
+[[omp::directive (unroll full)]]
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+}
+
+void
+test12 ()
+{
+[[omp::sequence (directive (unroll full),
+ directive (unroll partial),
+ directive (unroll partial))]]
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+}
+
+void
+test13 ()
+{
+ for (int i = 0; i < 100; ++i)
+[[omp::sequence (directive (unroll full),
+ directive (unroll partial),
+ directive (unroll partial))]]
+ for (int j = -300; j != 100; ++j)
+ dummy (i);
+}
+
+void
+test14 ()
+{
+ [[omp::directive (for)]]
+ for (int i = 0; i < 100; ++i)
+ [[omp::sequence (directive (unroll full),
+ directive (unroll partial),
+ directive (unroll partial))]]
+ for (int j = -300; j != 100; ++j)
+ dummy (i);
+}
+
+void
+test15 ()
+{
+ [[omp::directive (for)]]
+ for (int i = 0; i < 100; ++i)
+ {
+
+ dummy (i);
+
+ [[omp::sequence (directive (unroll full),
+ directive (unroll partial),
+ directive (unroll partial))]]
+ for (int j = -300; j != 100; ++j)
+ dummy (j);
+
+ dummy (i);
+ }
+ }
diff --git a/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-2.C
b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-2.C
new file mode 100644
index 00000000000..1a45eadec64
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-2.C
@@ -0,0 +1,81 @@
+/* { dg-prune-output "error: invalid controlling predicate" } */
+// { dg-do compile { target c++11 } }
+
+extern void dummy (int);
+
+void
+test ()
+{
+[[omp::sequence (directive (unroll partial),
+ directive (unroll full))]] /* { dg-error {'full' clause is invalid here;
turns loop into non-loop} } */
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+
+[[omp::sequence (directive (for),
+ directive (unroll full), /* { dg-error {'full' clause is invalid here; turns
loop into non-loop} } */
+ directive (unroll partial))]]
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+
+[[omp::sequence (directive (for),
+ directive (unroll full), /* { dg-error {'full' clause is invalid here; turns
loop into non-loop} } */
+ directive (unroll full))]]
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+
+[[omp::sequence (directive (for),
+ directive (unroll partial partial))]] /* { dg-error {too many 'partial'
clauses} } */
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+
+[[omp::directive (unroll full full)]] /* { dg-error {too many 'full' clauses}
} */
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+
+[[omp::sequence (directive (unroll partial),
+ directive (unroll))]] /* { dg-error {'#pragma omp unroll' without 'partial'
clause is invalid here; turns loop into non-loop} } */
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+
+[[omp::sequence (directive (for),
+ directive (unroll))]] /* { dg-error {'#pragma omp unroll' without 'partial'
clause is invalid here; turns loop into non-loop} } */
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+
+ int i;
+
+[[omp::sequence (directive (for),
+ directive (unroll foo))]] /* { dg-error {expected an OpenMP clause before
'foo'} } */
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+
+[[omp::directive (unroll partial(i))]]
+ /* { dg-error {the value of 'i' is not usable in a constant expression} "" {
target c++ } .-1 } */
+ /* { dg-error {partial argument needs positive constant integer expression}
"" { target *-*-* } .-2 } */
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+
+[[omp::directive (unroll parti)]] /* { dg-error {expected an OpenMP clause
before 'parti'} } */
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+
+[[omp::sequence (directive (for),
+ directive (unroll partial(1)),
+ directive (unroll parti))]] /* { dg-error {expected an OpenMP clause before
'parti'} } */
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+
+[[omp::sequence (directive (for),
+ directive (unroll partial(1)),
+ directive (unroll parti))]] /* { dg-error {expected an OpenMP clause before
'parti'} } */
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+
+int sum = 0;
+[[omp::sequence (directive (parallel for reduction(+ : sum) collapse(2)),
+ directive (unroll partial(1)))]] /* { dg-error {nesting depth left after
this transformation too low for loop collapse} } */
+ for (int i = 3; i < 10; ++i)
+ for (int j = -2; j < 7; ++j)
+ sum++;
+}
+
diff --git a/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-3.C
b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-3.C
new file mode 100644
index 00000000000..20c11c0f314
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-3.C
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++11 } }
+
+/* { dg-additional-options "-fdump-tree-omp_transform_loops" }
+ * { dg-additional-options "-fdump-tree-original" } */
+
+extern void dummy (int);
+
+void
+test1 ()
+{
+ int i;
+ [[omp::directive (unroll full)]]
+ for (int i = 0; i < 10; i++)
+ dummy (i);
+}
+
+ /* Loop should be removed with 10 copies of the body remaining
+ * { dg-final { scan-tree-dump-times "dummy" 10 "omp_transform_loops" } }
+ * { dg-final { scan-tree-dump "#pragma omp loop_transform" "original" } }
+ * { dg-final { scan-tree-dump-not "#pragma omp" "omp_transform_loops" } } */
diff --git a/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-inner-1.C
b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-inner-1.C
new file mode 100644
index 00000000000..234753ad017
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-inner-1.C
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++11 } }
+
+extern void dummy (int);
+
+void
+test ()
+{
+
+ [[omp::directive (target parallel for collapse(2))]]
+ for (int i = -300; i != 100; ++i)
+ [[omp::directive (unroll, partial)]]
+ for (int j = 0; j != 100; ++j)
+ dummy (i);
+}
+
diff --git a/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-inner-2.C
b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-inner-2.C
new file mode 100644
index 00000000000..26cc665007d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-inner-2.C
@@ -0,0 +1,29 @@
+// { dg-do compile { target c++11 } }
+
+extern void dummy (int);
+
+void
+test ()
+{
+
+#pragma omp target parallel for collapse(2)
+ for (int i = -300; i != 100; ++i)
+ [[omp::directive (tile sizes (2))]]
+ for (int j = 0; j != 100; ++j)
+ dummy (i);
+
+ [[omp::directive (target parallel for collapse(2))]]
+ for (int i = -300; i != 100; ++i) /* { dg-error {not enough nested loops} }
*/
+ [[omp::directive (tile sizes(2, 3))]]
+ for (int j = 0; j != 100; ++j)
+ dummy (i);
+
+ [[omp::directive (target parallel for, collapse(2))]]
+ for (int i = -300; i != 100; ++i)
+ [[omp::directive (tile, sizes(2, 3))]]
+ for (int j = 0; j != 100; ++j)
+ for (int k = 0; k != 100; ++k)
+ dummy (i);
+}
+
+
diff --git a/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-inner-3.C
b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-inner-3.C
new file mode 100644
index 00000000000..46970b84a24
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-inner-3.C
@@ -0,0 +1,71 @@
+// { dg-do compile { target c++11 } }
+
+// Test that omp::sequence is handled properly in a loop nest, but that
+// invalid attribute specifiers are rejected.
+
+extern void dummy (int);
+
+void
+test1 ()
+{
+ [[omp::directive (target parallel for collapse(2))]]
+ for (int i = -300; i != 100; ++i)
+ [[omp::sequence (directive (unroll, partial))]] // OK
+ for (int j = 0; j != 100; ++j)
+ dummy (i);
+}
+
+void
+test2 ()
+{
+ [[omp::directive (target parallel for collapse(2))]]
+ for (int i = -300; i != 100; ++i)
+ [[omp::directive (masked)]] // { dg-error "loop nest expected" }
+ for (int j = 0; j != 100; ++j)
+ dummy (i);
+}
+
+void
+test3 ()
+{
+ [[omp::directive (target parallel for collapse(2))]]
+ for (int i = -300; i != 100; ++i)
+ [[omp::directive (unroll, partial)]] // { dg-error "attributes on the
same statement" }
+ [[omp::directive (masked)]]
+ for (int j = 0; j != 100; ++j)
+ dummy (i);
+}
+
+void
+test4 ()
+{
+ [[omp::directive (target parallel for collapse(2))]]
+ for (int i = -300; i != 100; ++i)
+ [[omp::sequence (directive (unroll, partial),
+ directive (masked))]] // { dg-error "loop nest expected" }
+ for (int j = 0; j != 100; ++j)
+ dummy (i);
+}
+
+void
+test5 ()
+{
+ [[omp::directive (target parallel for collapse(2))]]
+ for (int i = -300; i != 100; ++i)
+ [[omp::sequence (directive (masked), // { dg-error "loop nest expected" }
+ directive (unroll, partial))]]
+ for (int j = 0; j != 100; ++j)
+ dummy (i);
+}
+
+void
+test6 ()
+{
+ [[omp::directive (target parallel for collapse(2))]]
+ for (int i = -300; i != 100; ++i)
+ [[omp::directive (unroll, partial), // { dg-error "attributes on the same
statement" }
+ omp::directive (masked)]]
+ for (int j = 0; j != 100; ++j)
+ dummy (i);
+}
+
--
2.31.1