@@ -508,6 +508,7 @@ c_genericize_control_stmt (tree *stmt_p, int *walk_subtrees, void *data,
case OMP_DISTRIBUTE:
case OMP_LOOP:
case OMP_TASKLOOP:
+ case OMP_LOOP_TRANS:
case OACC_LOOP:
genericize_omp_for_stmt (stmt_p, walk_subtrees, data, func, lh);
break;
@@ -3359,14 +3359,14 @@ const struct c_omp_directive c_omp_directives[] = {
C_OMP_DIR_STANDALONE, false },
{ "taskyield", nullptr, nullptr, PRAGMA_OMP_TASKYIELD,
C_OMP_DIR_STANDALONE, false },
- /* { "tile", nullptr, nullptr, PRAGMA_OMP_TILE,
- C_OMP_DIR_CONSTRUCT, false }, */
+ { "tile", nullptr, nullptr, PRAGMA_OMP_TILE,
+ C_OMP_DIR_CONSTRUCT, false },
{ "teams", nullptr, nullptr, PRAGMA_OMP_TEAMS,
C_OMP_DIR_CONSTRUCT, true },
{ "threadprivate", nullptr, nullptr, PRAGMA_OMP_THREADPRIVATE,
- C_OMP_DIR_DECLARATIVE, false }
- /* { "unroll", nullptr, nullptr, PRAGMA_OMP_UNROLL,
- C_OMP_DIR_CONSTRUCT, false }, */
+ C_OMP_DIR_DECLARATIVE, false },
+ { "unroll", nullptr, nullptr, PRAGMA_OMP_UNROLL,
+ C_OMP_DIR_CONSTRUCT, false },
};
/* Find (non-combined/composite) OpenMP directive (if any) which starts
@@ -1550,6 +1550,8 @@ static const struct omp_pragma_def omp_pragmas_simd[] = {
{ "target", PRAGMA_OMP_TARGET },
{ "taskloop", PRAGMA_OMP_TASKLOOP },
{ "teams", PRAGMA_OMP_TEAMS },
+ { "tile", PRAGMA_OMP_TILE },
+ { "unroll", PRAGMA_OMP_UNROLL },
};
void
@@ -81,8 +81,10 @@ enum pragma_kind {
PRAGMA_OMP_TASKYIELD,
PRAGMA_OMP_THREADPRIVATE,
PRAGMA_OMP_TEAMS,
+ PRAGMA_OMP_TILE,
+ PRAGMA_OMP_UNROLL,
/* PRAGMA_OMP__LAST_ should be equal to the last PRAGMA_OMP_* code. */
- PRAGMA_OMP__LAST_ = PRAGMA_OMP_TEAMS,
+ PRAGMA_OMP__LAST_ = PRAGMA_OMP_UNROLL,
PRAGMA_GCC_PCH_PREPROCESS,
PRAGMA_IVDEP,
@@ -119,6 +121,7 @@ enum pragma_omp_clause {
PRAGMA_OMP_CLAUSE_FIRSTPRIVATE,
PRAGMA_OMP_CLAUSE_FOR,
PRAGMA_OMP_CLAUSE_FROM,
+ PRAGMA_OMP_CLAUSE_FULL,
PRAGMA_OMP_CLAUSE_GRAINSIZE,
PRAGMA_OMP_CLAUSE_HAS_DEVICE_ADDR,
PRAGMA_OMP_CLAUSE_HINT,
@@ -141,6 +144,7 @@ enum pragma_omp_clause {
PRAGMA_OMP_CLAUSE_ORDER,
PRAGMA_OMP_CLAUSE_ORDERED,
PRAGMA_OMP_CLAUSE_PARALLEL,
+ PRAGMA_OMP_CLAUSE_PARTIAL,
PRAGMA_OMP_CLAUSE_PRIORITY,
PRAGMA_OMP_CLAUSE_PRIVATE,
PRAGMA_OMP_CLAUSE_PROC_BIND,
@@ -155,6 +159,7 @@ enum pragma_omp_clause {
PRAGMA_OMP_CLAUSE_TASKGROUP,
PRAGMA_OMP_CLAUSE_THREAD_LIMIT,
PRAGMA_OMP_CLAUSE_THREADS,
+ PRAGMA_OMP_CLAUSE_TILE,
PRAGMA_OMP_CLAUSE_TO,
PRAGMA_OMP_CLAUSE_UNIFORM,
PRAGMA_OMP_CLAUSE_UNTIED,
@@ -1554,6 +1554,7 @@ static tree objc_foreach_break_label, objc_foreach_continue_label;
*/
struct omp_for_parse_data {
enum tree_code code;
+ tree clauses;
tree declv, condv, incrv, initv;
tree pre_body;
tree bindings;
@@ -1662,7 +1663,10 @@ static void c_parser_omp_threadprivate (c_parser *);
static void c_parser_omp_barrier (c_parser *);
static void c_parser_omp_depobj (c_parser *);
static void c_parser_omp_flush (c_parser *);
+static bool c_parser_see_omp_loop_nest (c_parser *, enum tree_code, bool);
static tree c_parser_omp_loop_nest (c_parser *, bool *);
+static int c_parser_omp_nested_loop_transform_clauses (c_parser *, tree &, int,
+ int, const char *);
static tree c_parser_omp_for_loop (location_t, c_parser *, enum tree_code,
tree, tree *, bool *);
static void c_parser_omp_taskwait (c_parser *);
@@ -5720,6 +5724,37 @@ c_parser_nth_token_starts_std_attributes (c_parser *parser, unsigned int n)
return token->type == CPP_CLOSE_SQUARE;
}
+/* Skip standard attribute tokens starting at Nth token (with 1 as the
+ next token), return index of the first token after the standard
+ attribute tokens, or N on failure. */
+
+static size_t
+c_parser_skip_std_attribute_spec_seq (c_parser *parser, size_t n)
+{
+ size_t orig_n = n;
+ while (true)
+ {
+ if (c_parser_peek_nth_token_raw (parser, n)->type == CPP_OPEN_SQUARE
+ && (c_parser_peek_nth_token_raw (parser, n + 1)->type
+ == CPP_OPEN_SQUARE))
+ {
+ unsigned int m = n + 2;
+ if (!c_parser_check_balanced_raw_token_sequence (parser, &m))
+ return orig_n;
+ c_token *token = c_parser_peek_nth_token_raw (parser, m);
+ if (token->type != CPP_CLOSE_SQUARE)
+ return orig_n;
+ token = c_parser_peek_nth_token_raw (parser, m + 1);
+ if (token->type != CPP_CLOSE_SQUARE)
+ return orig_n;
+ n = m + 2;
+ }
+ else
+ break;
+ }
+ return n;
+}
+
static tree
c_parser_std_attribute_specifier_sequence (c_parser *parser)
{
@@ -6305,7 +6340,20 @@ check_omp_intervening_code (c_parser *parser)
"%<reduction%> %<inscan%> clause");
omp_for_parse_state->perfect_nesting_fail = true;
}
- /* TODO: Also reject loops with TILE directive. */
+ else
+ {
+ tree c = omp_find_clause (omp_for_parse_state->clauses,
+ OMP_CLAUSE_TILE);
+ if (c &&
+ ((int) tree_to_uhwi (OMP_CLAUSE_TRANSFORM_LEVEL (c))
+ <= omp_for_parse_state->depth))
+ {
+ error_at (omp_for_parse_state->for_loc,
+ "inner loops must be perfectly nested "
+ "with %<tile%> directive");
+ omp_for_parse_state->perfect_nesting_fail = true;
+ }
+ }
if (omp_for_parse_state->perfect_nesting_fail)
omp_for_parse_state->fail = true;
}
@@ -6412,7 +6460,9 @@ c_parser_compound_statement_nostart (c_parser *parser)
if (in_omp_loop_block && !last_label)
{
if (want_nested_loop
- && c_parser_next_token_is_keyword (parser, RID_FOR))
+ && c_parser_see_omp_loop_nest (parser,
+ omp_for_parse_state->code,
+ false))
{
/* Found the next nested loop. If there were intervening
code statements collected before now, wrap them in an
@@ -13953,6 +14003,8 @@ c_parser_omp_clause_name (c_parser *parser)
result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE;
else if (!strcmp ("from", p))
result = PRAGMA_OMP_CLAUSE_FROM;
+ else if (!strcmp ("full", p))
+ result = PRAGMA_OMP_CLAUSE_FULL;
break;
case 'g':
if (!strcmp ("gang", p))
@@ -14027,6 +14079,8 @@ c_parser_omp_clause_name (c_parser *parser)
case 'p':
if (!strcmp ("parallel", p))
result = PRAGMA_OMP_CLAUSE_PARALLEL;
+ else if (!strcmp ("partial", p))
+ result = PRAGMA_OMP_CLAUSE_PARTIAL;
else if (!strcmp ("present", p))
result = PRAGMA_OACC_CLAUSE_PRESENT;
/* As of OpenACC 2.5, these are now aliases of the non-present_or
@@ -14121,12 +14175,15 @@ c_parser_omp_clause_name (c_parser *parser)
/* Validate that a clause of the given type does not already exist. */
-static void
+static bool
check_no_duplicate_clause (tree clauses, enum omp_clause_code code,
const char *name)
{
- if (tree c = omp_find_clause (clauses, code))
+ tree c = omp_find_clause (clauses, code);
+ if (c)
error_at (OMP_CLAUSE_LOCATION (c), "too many %qs clauses", name);
+
+ return c == NULL_TREE;
}
/* OpenACC 2.0
@@ -17993,6 +18050,67 @@ c_parser_omp_clause_uniform (c_parser *parser, tree list)
return list;
}
+/* OpenMP 5.1
+ full */
+
+static tree
+c_parser_omp_clause_unroll_full (c_parser *parser, tree list)
+{
+ if (!check_no_duplicate_clause (list, OMP_CLAUSE_UNROLL_FULL, "full"))
+ return list;
+
+ location_t loc = c_parser_peek_token (parser)->location;
+ tree c = build_omp_clause (loc, OMP_CLAUSE_UNROLL_FULL);
+ OMP_CLAUSE_TRANSFORM_LEVEL (c) = build_int_cst (unsigned_type_node, 0);
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+}
+
+/* OpenMP 5.1
+ partial ( constant-expression ) */
+
+static tree
+c_parser_omp_clause_unroll_partial (c_parser *parser, tree list)
+{
+ if (!check_no_duplicate_clause (list, OMP_CLAUSE_UNROLL_PARTIAL, "partial"))
+ return list;
+
+ tree c, num = error_mark_node;
+ HOST_WIDE_INT n;
+ location_t loc;
+
+ loc = c_parser_peek_token (parser)->location;
+ c = build_omp_clause (loc, OMP_CLAUSE_UNROLL_PARTIAL);
+ OMP_CLAUSE_UNROLL_PARTIAL_EXPR (c) = NULL_TREE;
+ OMP_CLAUSE_TRANSFORM_LEVEL (c) = build_int_cst (unsigned_type_node, 0);
+ OMP_CLAUSE_CHAIN (c) = list;
+
+ if (!c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ return c;
+
+ matching_parens parens;
+ parens.consume_open (parser);
+ num = c_parser_expr_no_commas (parser, NULL).value;
+ parens.skip_until_found_close (parser);
+
+ if (num == error_mark_node)
+ return list;
+
+ mark_exp_read (num);
+ num = c_fully_fold (num, false, NULL);
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (num)) || !tree_fits_shwi_p (num)
+ || (n = tree_to_shwi (num)) <= 0 || (int)n != n)
+ {
+ error_at (loc,
+ "partial argument needs positive constant integer expression");
+ return list;
+ }
+
+ OMP_CLAUSE_UNROLL_PARTIAL_EXPR (c) = num;
+
+ return c;
+}
+
/* OpenMP 5.0:
detach ( event-handle ) */
@@ -18589,6 +18707,14 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask,
clauses);
c_name = "enter";
break;
+ case PRAGMA_OMP_CLAUSE_FULL:
+ c_name = "full";
+ clauses = c_parser_omp_clause_unroll_full (parser, clauses);
+ break;
+ case PRAGMA_OMP_CLAUSE_PARTIAL:
+ c_name = "partial";
+ clauses = c_parser_omp_clause_unroll_partial (parser, clauses);
+ break;
default:
c_parser_error (parser, "expected an OpenMP clause");
goto saw_error;
@@ -20848,6 +20974,44 @@ c_parser_omp_scan_loop_body (c_parser *parser, bool open_brace_parsed)
}
+/* Check that the next token starts a loop nest. Return true if yes,
+ otherwise diagnose an error if ERROR_P is true, and return false. */
+static bool
+c_parser_see_omp_loop_nest (c_parser *parser, enum tree_code code,
+ bool error_p)
+{
+ if (code == OACC_LOOP)
+ {
+ if (c_parser_next_token_is_keyword (parser, RID_FOR))
+ return true;
+ if (error_p)
+ c_parser_error (parser, "for statement expected");
+ }
+ else
+ {
+ if (c_parser_next_token_is_keyword (parser, RID_FOR)
+ || c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_UNROLL
+ || c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_TILE)
+ return true;
+
+ /* For consistency with C++, treat standard attributes followed
+ by RID_FOR as a loop nest, but diagnose unknown attributes as
+ an error in c_parser_omp_loop_nest. */
+ size_t n = c_parser_skip_std_attribute_spec_seq (parser, 1);
+ c_token *token = c_parser_peek_nth_token_raw (parser, n);
+ /* TOKEN is a raw token that hasn't been converted to a keyword yet,
+ we have to do the lookup explicitly. */
+ if (token->type == CPP_NAME
+ && C_IS_RESERVED_WORD (token->value)
+ && C_RID_CODE (token->value) == RID_FOR)
+ return true;
+ if (error_p)
+ c_parser_error (parser, "loop nest expected");
+ }
+
+ return false;
+}
+
/* This function parses a single level of a loop nest, invoking itself
recursively if necessary.
@@ -20883,6 +21047,51 @@ c_parser_omp_loop_nest (c_parser *parser, bool *if_p)
gcc_assert (omp_for_parse_state);
int depth = omp_for_parse_state->depth;
+ /* Reject non-empty standard attributes with an error. C++ allows OpenMP
+ directives to be specified with attribute syntax, but C does not. */
+ if (c_parser_nth_token_starts_std_attributes (parser, 1))
+ {
+ tree std_attrs = c_parser_std_attribute_specifier_sequence (parser);
+ if (std_attrs)
+ error_at (c_parser_peek_token (parser)->location,
+ "attributes are not allowed on %<for%> in loop nest");
+ }
+
+ /* Handle loop transformations first. Note that when we get here
+ omp_for_parse_state->depth has already been incremented to indicate
+ the depth of the *next* loop, not the level of the loop body the
+ transformation directive appears in. */
+ if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_UNROLL
+ || c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_TILE)
+ {
+ int count = omp_for_parse_state->count;
+ int more = c_parser_omp_nested_loop_transform_clauses (
+ parser, omp_for_parse_state->clauses,
+ depth, count - depth, "loop collapse");
+ if (depth + more > count)
+ {
+ count = depth + more;
+ omp_for_parse_state->count = count;
+ omp_for_parse_state->declv
+ = grow_tree_vec (omp_for_parse_state->declv, count);
+ omp_for_parse_state->initv
+ = grow_tree_vec (omp_for_parse_state->initv, count);
+ omp_for_parse_state->condv
+ = grow_tree_vec (omp_for_parse_state->condv, count);
+ omp_for_parse_state->incrv
+ = grow_tree_vec (omp_for_parse_state->incrv, count);
+ }
+ if (c_parser_see_omp_loop_nest (parser, omp_for_parse_state->code,
+ true))
+ return c_parser_omp_loop_nest (parser, if_p);
+ else
+ {
+ /* FIXME: Better error recovery here? */
+ omp_for_parse_state->fail = true;
+ return NULL_TREE;
+ }
+ }
+
/* We have already matched the FOR token but not consumed it yet. */
loc = c_parser_peek_token (parser)->location;
gcc_assert (c_parser_next_token_is_keyword (parser, RID_FOR));
@@ -21017,7 +21226,9 @@ c_parser_omp_loop_nest (c_parser *parser, bool *if_p)
parse_next:
moreloops = depth < omp_for_parse_state->count - 1;
omp_for_parse_state->want_nested_loop = moreloops;
- if (moreloops && c_parser_next_token_is_keyword (parser, RID_FOR))
+ if (moreloops
+ && c_parser_see_omp_loop_nest (parser, omp_for_parse_state->code,
+ false))
{
omp_for_parse_state->depth++;
body = c_parser_omp_loop_nest (parser, if_p);
@@ -21129,7 +21340,7 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
tree ret = NULL_TREE;
tree ordered_cl = NULL_TREE;
int i, collapse = 1, ordered = 0, count;
- bool tiling = false;
+ bool oacc_tiling = false;
bool inscan = false;
struct omp_for_parse_data data;
struct omp_for_parse_data *save_data = parser->omp_for_parse_state;
@@ -21139,7 +21350,7 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (cl));
else if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_OACC_TILE)
{
- tiling = true;
+ oacc_tiling = true;
collapse = list_length (OMP_CLAUSE_OACC_TILE_LIST (cl));
}
else if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_ORDERED
@@ -21162,15 +21373,29 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
ordered = collapse;
}
- gcc_assert (tiling || (collapse >= 1 && ordered >= 0));
- count = ordered ? ordered : collapse;
+ c_parser_omp_nested_loop_transform_clauses (parser, clauses, 0, collapse,
+ "loop collapse");
- if (!c_parser_next_token_is_keyword (parser, RID_FOR))
+ /* Find the depth of the loop nest affected by "omp tile"
+ directives. There can be several such directives, but the tiling
+ depth of the outer ones may not be larger than the depth of the
+ innermost directive. */
+ int omp_tile_depth = 0;
+ for (tree c = clauses; c; c = TREE_CHAIN (c))
{
- c_parser_error (parser, "for statement expected");
- return NULL;
+ if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_TILE)
+ continue;
+
+ omp_tile_depth = list_length (OMP_CLAUSE_TILE_SIZES (c));
}
+ gcc_assert (oacc_tiling || (collapse >= 1 && ordered >= 0));
+ count = ordered ? ordered : collapse;
+ count = MAX (count, omp_tile_depth);
+
+ if (!c_parser_see_omp_loop_nest (parser, code, true))
+ return NULL;
+
/* Initialize parse state for recursive descent. */
data.declv = make_tree_vec (count);
data.initv = make_tree_vec (count);
@@ -21189,9 +21414,11 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
data.inscan = inscan;
data.saw_intervening_code = false;
data.code = code;
+ data.clauses = clauses;
parser->omp_for_parse_state = &data;
body = c_parser_omp_loop_nest (parser, if_p);
+ count = data.count;
/* Add saved bindings for iteration variables that were declared in
the nested for loop to the scope surrounding the entire loop. */
@@ -24641,6 +24868,263 @@ c_parser_omp_taskloop (location_t loc, c_parser *parser,
return ret;
}
+#define OMP_UNROLL_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARTIAL) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FULL) )
+
+/* OpenMP 5.1: Parse sizes list for "omp tile sizes"
+ sizes ( size-expr-list ) */
+static tree
+c_parser_omp_tile_sizes (c_parser *parser, location_t loc)
+{
+ tree sizes = NULL_TREE;
+
+ c_token *tok = c_parser_peek_token (parser);
+ if (tok->type != CPP_NAME
+ || strcmp ("sizes", IDENTIFIER_POINTER (tok->value)))
+ {
+ c_parser_error (parser, "expected %<sizes%>");
+ return error_mark_node;
+ }
+ c_parser_consume_token (parser);
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return error_mark_node;
+
+ do
+ {
+ if (sizes && !c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+ return error_mark_node;
+
+ location_t expr_loc = c_parser_peek_token (parser)->location;
+ c_expr cexpr = c_parser_expr_no_commas (parser, NULL);
+ cexpr = convert_lvalue_to_rvalue (expr_loc, cexpr, false, true);
+ tree expr = cexpr.value;
+
+ if (expr == error_mark_node)
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ return error_mark_node;
+ }
+
+ expr = c_fully_fold (expr, false, NULL);
+
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (expr)) || !tree_fits_shwi_p (expr)
+ || tree_to_shwi (expr) <= 0)
+ {
+ c_parser_error (parser, "%<tile sizes%> argument needs positive"
+ " integral constant");
+ expr = integer_zero_node;
+ }
+
+ sizes = tree_cons (NULL_TREE, expr, sizes);
+ }
+ while (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN));
+ c_parser_consume_token (parser);
+
+ gcc_assert (sizes);
+ tree c = build_omp_clause (loc, OMP_CLAUSE_TILE);
+ OMP_CLAUSE_TRANSFORM_LEVEL (c) = build_int_cst (unsigned_type_node, 0);
+ OMP_CLAUSE_TILE_SIZES (c) = sizes;
+
+ return c;
+}
+
+/* Parse a single OpenMP loop transformation directive and return the
+ clause that is used internally to represent the directive. */
+
+static tree
+c_parser_omp_loop_transform_clause (c_parser *parser)
+{
+ c_token *tok = c_parser_peek_token (parser);
+ if (tok->type != CPP_PRAGMA)
+ return NULL_TREE;
+
+ tree c;
+ switch (tok->pragma_kind)
+ {
+ case PRAGMA_OMP_UNROLL:
+ c_parser_consume_pragma (parser);
+ c = c_parser_omp_all_clauses (parser, OMP_UNROLL_CLAUSE_MASK,
+ "#pragma omp unroll", false, true);
+ if (!c && c_parser_next_token_is (parser, CPP_PRAGMA_EOL))
+ {
+ c = build_omp_clause (tok->location, OMP_CLAUSE_UNROLL_NONE);
+ OMP_CLAUSE_TRANSFORM_LEVEL (c)
+ = build_int_cst (unsigned_type_node, 0);
+ }
+ else if (!c)
+ c = error_mark_node;
+ c_parser_skip_to_pragma_eol (parser);
+ break;
+
+ case PRAGMA_OMP_TILE:
+ c_parser_consume_pragma (parser);
+ c = c_parser_omp_tile_sizes (parser, tok->location);
+ c_parser_skip_to_pragma_eol (parser);
+ break;
+
+ default:
+ c = NULL_TREE;
+ break;
+ }
+
+ gcc_assert (!c || !TREE_CHAIN (c));
+ return c;
+}
+
+/* Parse zero or more OpenMP loop transformation directives that
+ follow another directive that requires a canonical loop nest,
+ append all to CLAUSES and record the LEVEL at which the clauses
+ appear in the loop nest in each clause.
+
+ REQUIRED_DEPTH is the nesting depth of the loop nest required by
+ the preceding directive. OUTER_DESCR is a description of the
+ language construct that requires the loop nest depth (e.g. "loop
+ collpase", "outer transformation") that is used for error
+ messages. */
+
+static int
+c_parser_omp_nested_loop_transform_clauses (c_parser *parser, tree &clauses,
+ int level, int required_depth,
+ const char *outer_descr)
+{
+ tree c = NULL_TREE;
+ tree last_c = tree_last (clauses);
+
+ /* The depth of the loop nest, counting from LEVEL, after the
+ transformations. That is, the nesting depth left by the outermost
+ transformation which is the first to be parsed, but the last to be
+ executed. */
+ int transformed_depth = 0;
+
+ /* The minimum nesting depth required by the last parsed transformation. */
+ int last_depth = required_depth;
+ while ((c = c_parser_omp_loop_transform_clause (parser)))
+ {
+ /* The nesting depth left after the current transformation. */
+ int depth = 1;
+ if (TREE_CODE (c) == ERROR_MARK)
+ goto error;
+
+ gcc_assert (!TREE_CHAIN (c));
+ switch (OMP_CLAUSE_CODE (c))
+ {
+ case OMP_CLAUSE_UNROLL_FULL:
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%<full%> clause is invalid here; "
+ "turns loop into non-loop");
+ goto error;
+ case OMP_CLAUSE_UNROLL_NONE:
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%<#pragma omp unroll%> without "
+ "%<partial%> clause is invalid here; "
+ "turns loop into non-loop");
+ goto error;
+ case OMP_CLAUSE_UNROLL_PARTIAL:
+ depth = 1;
+ break;
+ case OMP_CLAUSE_TILE:
+ depth = list_length (OMP_CLAUSE_TILE_SIZES (c));
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ if (depth < last_depth)
+ {
+ bool is_outermost_clause = !transformed_depth;
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "nesting depth left after this transformation too low "
+ "for %s",
+ is_outermost_clause ? outer_descr
+ : "outer transformation");
+ goto error;
+ }
+
+ last_depth = depth;
+
+ if (!transformed_depth)
+ transformed_depth = last_depth;
+
+ OMP_CLAUSE_TRANSFORM_LEVEL (c) = build_int_cst (unsigned_type_node, level);
+ if (!clauses)
+ clauses = c;
+ else if (last_c)
+ TREE_CHAIN (last_c) = c;
+
+ last_c = c;
+ }
+
+ return transformed_depth;
+
+error:
+ while (c_parser_omp_loop_transform_clause (parser))
+ ;
+ clauses = NULL_TREE;
+ return -1;
+}
+
+/* OpenMP 5.1:
+ tile sizes ( size-expr-list ) */
+
+static tree
+c_parser_omp_tile (location_t loc, c_parser *parser, bool *if_p)
+{
+ tree block;
+ tree ret = error_mark_node;
+
+ tree clauses = c_parser_omp_tile_sizes (parser, loc);
+ c_parser_skip_to_pragma_eol (parser);
+
+ if (!clauses || clauses == error_mark_node)
+ return error_mark_node;
+
+ int required_depth = list_length (OMP_CLAUSE_TILE_SIZES (clauses));
+ c_parser_omp_nested_loop_transform_clauses (parser, clauses, 0,
+ required_depth,
+ "outer transformation");
+
+ block = c_begin_compound_stmt (true);
+ ret = c_parser_omp_for_loop (loc, parser, OMP_LOOP_TRANS, clauses,
+ NULL, if_p);
+ block = c_end_compound_stmt (loc, block, true);
+ add_stmt (block);
+
+ return ret;
+ }
+
+static tree
+c_parser_omp_unroll (location_t loc, c_parser *parser, bool *if_p)
+{
+ tree block, ret;
+ static const char *p_name = "#pragma omp unroll";
+ omp_clause_mask mask = OMP_UNROLL_CLAUSE_MASK;
+
+ tree clauses = c_parser_omp_all_clauses (parser, mask, p_name, false);
+ int required_depth = 1;
+ c_parser_omp_nested_loop_transform_clauses (parser, clauses, 0,
+ required_depth,
+ "outer transformation");
+
+ if (!clauses)
+ {
+ tree c = build_omp_clause (loc, OMP_CLAUSE_UNROLL_NONE);
+ OMP_CLAUSE_TRANSFORM_LEVEL (c) = build_int_cst (unsigned_type_node, 0);
+ OMP_CLAUSE_CHAIN (c) = clauses;
+ clauses = c;
+ }
+
+ block = c_begin_compound_stmt (true);
+ ret = c_parser_omp_for_loop (loc, parser, OMP_LOOP_TRANS, clauses,
+ NULL, if_p);
+ block = c_end_compound_stmt (loc, block, true);
+ add_stmt (block);
+
+ return ret;
+}
+
/* OpenMP 5.1
#pragma omp nothing new-line */
@@ -25032,6 +25516,7 @@ c_parser_omp_construct (c_parser *parser, bool *if_p)
p_kind = c_parser_peek_token (parser)->pragma_kind;
c_parser_consume_pragma (parser);
+ gcc_assert (parser->in_pragma);
switch (p_kind)
{
case PRAGMA_OACC_ATOMIC:
@@ -25122,6 +25607,12 @@ c_parser_omp_construct (c_parser *parser, bool *if_p)
case PRAGMA_OMP_ASSUME:
c_parser_omp_assume (parser, if_p);
return;
+ case PRAGMA_OMP_TILE:
+ stmt = c_parser_omp_tile (loc, parser, if_p);
+ break;
+ case PRAGMA_OMP_UNROLL:
+ stmt = c_parser_omp_unroll (loc, parser, if_p);
+ break;
default:
gcc_unreachable ();
}
@@ -15920,6 +15920,14 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
pc = &OMP_CLAUSE_CHAIN (c);
continue;
+ case OMP_CLAUSE_UNROLL_FULL:
+ pc = &OMP_CLAUSE_CHAIN (c);
+ continue;
+
+ case OMP_CLAUSE_UNROLL_PARTIAL:
+ pc = &OMP_CLAUSE_CHAIN (c);
+ continue;
+
case OMP_CLAUSE_INBRANCH:
case OMP_CLAUSE_NOTINBRANCH:
if (branch_seen)
@@ -647,6 +647,7 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
case OMP_DISTRIBUTE:
case OMP_LOOP:
case OMP_TASKLOOP:
+ case OMP_LOOP_TRANS:
ret = cp_gimplify_omp_for (expr_p, pre_p);
break;
@@ -1188,6 +1189,7 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_)
case OMP_DISTRIBUTE:
case OMP_LOOP:
case OMP_TASKLOOP:
+ case OMP_LOOP_TRANS:
case OACC_LOOP:
cp_walk_tree (&OMP_FOR_BODY (stmt), cp_fold_r, data, NULL);
cp_walk_tree (&OMP_FOR_CLAUSES (stmt), cp_fold_r, data, NULL);
@@ -1964,6 +1966,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
case OMP_FOR:
case OMP_SIMD:
case OMP_LOOP:
+ case OMP_LOOP_TRANS:
case OACC_LOOP:
case STATEMENT_LIST:
/* These cases are handled by shared code. */
@@ -2972,7 +2972,11 @@ static bool cp_parser_skip_up_to_closing_square_bracket
static bool cp_parser_skip_to_closing_square_bracket
(cp_parser *);
static size_t cp_parser_skip_balanced_tokens (cp_parser *, size_t);
+static bool cp_parser_see_omp_loop_nest (cp_parser *, enum tree_code, bool);
static tree cp_parser_omp_loop_nest (cp_parser *, bool *);
+static int cp_parser_omp_nested_loop_transform_clauses (cp_parser *, tree &,
+ int, int,
+ const char *);
// -------------------------------------------------------------------------- //
// Unevaluated Operand Guard
@@ -13119,7 +13123,20 @@ check_omp_intervening_code (cp_parser *parser)
"%<reduction%> %<inscan%> clause");
omp_for_parse_state->perfect_nesting_fail = true;
}
- /* TODO: Also reject loops with TILE directive. */
+ else
+ {
+ tree c = omp_find_clause (omp_for_parse_state->clauses,
+ OMP_CLAUSE_TILE);
+ if (c &&
+ ((int) tree_to_uhwi (OMP_CLAUSE_TRANSFORM_LEVEL (c))
+ <= omp_for_parse_state->depth))
+ {
+ error_at (omp_for_parse_state->for_loc,
+ "inner loops must be perfectly nested "
+ "with %<tile%> directive");
+ omp_for_parse_state->perfect_nesting_fail = true;
+ }
+ }
if (omp_for_parse_state->perfect_nesting_fail)
omp_for_parse_state->fail = true;
}
@@ -13171,7 +13188,9 @@ cp_parser_statement_seq_opt (cp_parser* parser, tree in_statement_expr)
{
bool want_nested_loop = omp_for_parse_state->want_nested_loop;
if (want_nested_loop
- && token->type == CPP_KEYWORD && token->keyword == RID_FOR)
+ && cp_parser_see_omp_loop_nest (parser,
+ omp_for_parse_state->code,
+ false))
{
/* Found the nested loop. */
omp_for_parse_state->depth++;
@@ -37494,6 +37513,8 @@ cp_parser_omp_clause_name (cp_parser *parser)
result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE;
else if (!strcmp ("from", p))
result = PRAGMA_OMP_CLAUSE_FROM;
+ else if (!strcmp ("full", p))
+ result = PRAGMA_OMP_CLAUSE_FULL;
break;
case 'g':
if (!strcmp ("gang", p))
@@ -37568,6 +37589,8 @@ cp_parser_omp_clause_name (cp_parser *parser)
case 'p':
if (!strcmp ("parallel", p))
result = PRAGMA_OMP_CLAUSE_PARALLEL;
+ if (!strcmp ("partial", p))
+ result = PRAGMA_OMP_CLAUSE_PARTIAL;
else if (!strcmp ("present", p))
result = PRAGMA_OACC_CLAUSE_PRESENT;
else if (!strcmp ("present_or_copy", p)
@@ -37658,12 +37681,15 @@ cp_parser_omp_clause_name (cp_parser *parser)
/* Validate that a clause of the given type does not already exist. */
-static void
+static bool
check_no_duplicate_clause (tree clauses, enum omp_clause_code code,
const char *name, location_t location)
{
- if (omp_find_clause (clauses, code))
+ bool found = omp_find_clause (clauses, code);
+ if (found)
error_at (location, "too many %qs clauses", name);
+
+ return !found;
}
/* OpenMP 2.5:
@@ -39782,6 +39808,58 @@ cp_parser_omp_clause_thread_limit (cp_parser *parser, tree list,
return c;
}
+/* OpenMP 5.1
+ full */
+
+static tree
+cp_parser_omp_clause_unroll_full (tree list, location_t loc)
+{
+ if (!check_no_duplicate_clause (list, OMP_CLAUSE_UNROLL_FULL, "full", loc))
+ return list;
+
+ tree c = build_omp_clause (loc, OMP_CLAUSE_UNROLL_FULL);
+ OMP_CLAUSE_TRANSFORM_LEVEL (c) = build_int_cst (unsigned_type_node, 0);
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+}
+
+/* OpenMP 5.1
+ partial ( constant-expression ) */
+
+static tree
+cp_parser_omp_clause_unroll_partial (cp_parser *parser, tree list,
+ location_t loc)
+{
+ if (!check_no_duplicate_clause (list, OMP_CLAUSE_UNROLL_PARTIAL, "partial",
+ loc))
+ return list;
+
+ tree c, num = error_mark_node;
+ c = build_omp_clause (loc, OMP_CLAUSE_UNROLL_PARTIAL);
+ OMP_CLAUSE_UNROLL_PARTIAL_EXPR (c) = NULL_TREE;
+ OMP_CLAUSE_TRANSFORM_LEVEL (c) = build_int_cst (unsigned_type_node, 0);
+ OMP_CLAUSE_CHAIN (c) = list;
+
+ if (!cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+ return c;
+
+ matching_parens parens;
+ parens.consume_open (parser);
+ num = cp_parser_constant_expression (parser);
+ cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+
+ if (num == error_mark_node)
+ return list;
+
+ mark_exp_read (num);
+ num = fold_non_dependent_expr (num);
+
+ OMP_CLAUSE_UNROLL_PARTIAL_EXPR (c) = num;
+ return c;
+}
+
/* OpenMP 4.0:
aligned ( variable-list )
aligned ( variable-list : constant-expression ) */
@@ -41473,15 +41551,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);
@@ -41822,6 +41897,16 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask,
clauses);
c_name = "enter";
break;
+ case PRAGMA_OMP_CLAUSE_PARTIAL:
+ clauses = cp_parser_omp_clause_unroll_partial (parser, clauses,
+ token->location);
+ c_name = "partial";
+ break;
+ case PRAGMA_OMP_CLAUSE_FULL:
+ clauses = cp_parser_omp_clause_unroll_full (clauses,
+ token->location);
+ c_name = "full";
+ break;
default:
cp_parser_error (parser, "expected an OpenMP clause");
goto saw_error;
@@ -43999,6 +44084,44 @@ cp_parser_omp_scan_loop_body (cp_parser *parser)
}
+/* Check that the next token starts a loop nest. Return true if yes,
+ otherwise diagnose an error if ERROR_P is true and return false. */
+static bool
+cp_parser_see_omp_loop_nest (cp_parser *parser, enum tree_code code,
+ bool error_p)
+{
+ if (code == OACC_LOOP)
+ {
+ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR))
+ return true;
+ if (error_p)
+ cp_parser_error (parser, "for statement expected");
+ }
+ else
+ {
+ if (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))
+ return true;
+ /* The OpenMP spec isn't very clear on this. Here we consider that
+ any attribute specifier sequence followed by a FOR loop is a loop
+ nest, but cp_parser_omp_loop_nest rejects invalid attributes
+ with an error. If we rejected such things here, too, then the
+ associated FOR statement would be considered intervening code
+ instead, and we would get a different error about a loop in
+ intervening code. */
+ size_t n = cp_parser_skip_std_attribute_spec_seq (parser, 1);
+ if (cp_lexer_nth_token_is_keyword (parser->lexer, n, RID_FOR))
+ return true;
+ if (error_p)
+ cp_parser_error (parser, "loop nest expected");
+ }
+ return false;
+}
+
+
/* This function parses a single level of a loop nest, invoking itself
recursively if necessary.
@@ -44051,8 +44174,69 @@ cp_parser_omp_loop_nest (cp_parser *parser, bool *if_p)
gcc_assert (omp_for_parse_state);
int depth = omp_for_parse_state->depth;
- /* We have already matched the FOR token but not consumed it yet. */
- gcc_assert (cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR));
+ /* Handle loop transformations first. Note that when we get here
+ omp_for_parse_state->depth has already been incremented to indicate
+ 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. Give an error if there are other random attributes present. */
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+ tree std_attrs = cp_parser_std_attribute_spec_seq (parser);
+ std_attrs = cp_parser_handle_statement_omp_attributes (parser, std_attrs);
+ if (std_attrs)
+ error_at (token->location,
+ "attributes other than OpenMP directives "
+ "are not allowed on %<for%> in loop nest");
+
+ if ((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))
+ {
+ int count = omp_for_parse_state->count;
+ int more = cp_parser_omp_nested_loop_transform_clauses (
+ parser, omp_for_parse_state->clauses,
+ depth, count - depth, "loop collapse");
+ if (depth + more > count)
+ {
+ count = depth + more;
+ omp_for_parse_state->count = count;
+ omp_for_parse_state->declv
+ = grow_tree_vec (omp_for_parse_state->declv, count);
+ omp_for_parse_state->initv
+ = grow_tree_vec (omp_for_parse_state->initv, count);
+ omp_for_parse_state->condv
+ = grow_tree_vec (omp_for_parse_state->condv, count);
+ omp_for_parse_state->incrv
+ = grow_tree_vec (omp_for_parse_state->incrv, count);
+ if (omp_for_parse_state->orig_declv)
+ omp_for_parse_state->orig_declv
+ = grow_tree_vec (omp_for_parse_state->orig_declv, count);
+ }
+ }
+
+ /* 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)
+ {
+ 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;
+ }
loc = cp_lexer_consume_token (parser->lexer)->location;
/* Forbid break/continue in the loop initializer, condition, and
@@ -44307,7 +44491,9 @@ 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))
+ if (moreloops
+ && 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));
@@ -44582,6 +44768,10 @@ fixup_blocks_walker (tree *tp, int *walk_subtrees, void *dp)
return NULL;
}
+static int cp_parser_omp_nested_loop_transform_clauses (cp_parser *, tree &,
+ int, int,
+ const char *);
+
/* Parse the restricted form of the for statement allowed by OpenMP. */
static tree
@@ -44592,7 +44782,7 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses,
tree cl, ordered_cl = NULL_TREE;
int collapse = 1, ordered = 0;
unsigned int count;
- bool tiling = false;
+ bool oacc_tiling = false;
bool inscan = false;
struct omp_for_parse_data data;
struct omp_for_parse_data *save_data = parser->omp_for_parse_state;
@@ -44604,7 +44794,7 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses,
collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (cl));
else if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_OACC_TILE)
{
- tiling = true;
+ oacc_tiling = true;
collapse = list_length (OMP_CLAUSE_OACC_TILE_LIST (cl));
}
else if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_ORDERED
@@ -44627,14 +44817,28 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses,
ordered = collapse;
}
- gcc_assert (tiling || (collapse >= 1 && ordered >= 0));
+ gcc_assert (oacc_tiling || (collapse >= 1 && ordered >= 0));
count = ordered ? ordered : collapse;
- if (!cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR))
+ cp_parser_omp_nested_loop_transform_clauses (parser, clauses, 0, count,
+ "loop collapse");
+
+ /* Find the depth of the loop nest affected by "omp tile"
+ directives. There can be several such directives, but the tiling
+ depth of the outer ones may not be larger than the depth of the
+ innermost directive. */
+ unsigned int omp_tile_depth = 0;
+ for (tree c = clauses; c; c = TREE_CHAIN (c))
{
- cp_parser_error (parser, "for statement expected");
- return NULL;
+ if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_TILE)
+ continue;
+
+ omp_tile_depth = list_length (OMP_CLAUSE_TILE_SIZES (c));
}
+ count = MAX (count, omp_tile_depth);
+
+ if (!cp_parser_see_omp_loop_nest (parser, code, true))
+ return NULL;
/* Initialize parse state for recursive descent. */
data.declv = make_tree_vec (count);
@@ -44687,6 +44891,7 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses,
We also need to flatten the init blocks, as some code for later
processing of combined directives gets confused otherwise. */
+ count = data.count;
gcc_assert (vec_safe_length (data.init_blockv) == count);
gcc_assert (vec_safe_length (data.body_blockv) == count);
gcc_assert (vec_safe_length (data.init_placeholderv) == count);
@@ -46479,6 +46684,272 @@ cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok,
return true;
}
+
+/* OpenMP 5.1: Parse sizes list for "omp tile sizes"
+ sizes ( size-expr-list ) */
+static tree
+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)))
+ {
+ cp_parser_error (parser, "expected %<sizes%>");
+ return error_mark_node;
+ }
+ cp_lexer_consume_token (lexer);
+
+ if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
+ return error_mark_node;
+
+ do
+ {
+ if (sizes && !cp_parser_require (parser, CPP_COMMA, RT_COMMA))
+ return error_mark_node;
+
+ tree expr = cp_parser_constant_expression (parser);
+ if (expr == error_mark_node)
+ {
+ cp_parser_skip_to_closing_parenthesis (parser,
+ /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/
+ true);
+ return error_mark_node;
+ }
+
+ sizes = tree_cons (NULL_TREE, expr, sizes);
+ }
+ while (cp_lexer_next_token_is_not (lexer, CPP_CLOSE_PAREN));
+ cp_lexer_consume_token (lexer);
+
+ gcc_assert (sizes);
+ tree c = build_omp_clause (loc, OMP_CLAUSE_TILE);
+ OMP_CLAUSE_TRANSFORM_LEVEL (c) = build_int_cst (unsigned_type_node, 0);
+ OMP_CLAUSE_TILE_SIZES (c) = sizes;
+ OMP_CLAUSE_TRANSFORM_LEVEL (c)
+ = build_int_cst (unsigned_type_node, 0);
+
+ return c;
+}
+
+/* OpenMP 5.1:
+ tile sizes ( size-expr-list ) */
+
+static tree
+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);
+
+ if (!clauses || clauses == error_mark_node)
+ return error_mark_node;
+
+ int required_depth = list_length (OMP_CLAUSE_TILE_SIZES (clauses));
+ cp_parser_omp_nested_loop_transform_clauses (parser, clauses, 0,
+ required_depth,
+ "outer transformation");
+
+ block = begin_omp_structured_block ();
+ clauses = finish_omp_clauses (clauses, C_ORT_OMP);
+
+ ret = cp_parser_omp_for_loop (parser, OMP_LOOP_TRANS, clauses, NULL, if_p);
+ block = finish_omp_structured_block (block);
+ add_stmt (block);
+
+ return ret;
+}
+
+#define OMP_UNROLL_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARTIAL) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FULL) )
+
+/* Parse a single OpenMP loop transformation directive and return the
+ clause that is used internally to represent the directive. */
+
+static tree
+cp_parser_omp_loop_transform_clause (cp_parser *parser)
+{
+ cp_lexer *lexer = parser->lexer;
+ cp_token *tok = cp_lexer_peek_token (lexer);
+ if (tok->type != CPP_PRAGMA)
+ return NULL_TREE;
+
+ tree c;
+ switch (cp_parser_pragma_kind (tok))
+ {
+ case PRAGMA_OMP_UNROLL:
+ cp_lexer_consume_token (lexer);
+ lexer->in_pragma = true;
+ c = cp_parser_omp_all_clauses (parser, OMP_UNROLL_CLAUSE_MASK,
+ "#pragma omp unroll", tok,
+ false, true);
+ if (!c && cp_lexer_next_token_is (lexer, CPP_PRAGMA_EOL))
+ {
+ c = build_omp_clause (tok->location, OMP_CLAUSE_UNROLL_NONE);
+ OMP_CLAUSE_TRANSFORM_LEVEL (c)
+ = build_int_cst (unsigned_type_node, 0);
+ }
+ else if (!c)
+ c = error_mark_node;
+ cp_parser_skip_to_pragma_eol (parser, tok);
+ break;
+
+ case PRAGMA_OMP_TILE:
+ cp_lexer_consume_token (lexer);
+ lexer->in_pragma = true;
+ c = cp_parser_omp_tile_sizes (parser, tok->location);
+ cp_parser_require_pragma_eol (parser, tok);
+ break;
+
+ default:
+ c = NULL_TREE;
+ break;
+ }
+
+ gcc_assert (!c || !TREE_CHAIN (c));
+ return c;
+}
+
+/* Parse zero or more OpenMP loop transformation directives that
+ follow another directive that requires a canonical loop nest,
+ append all to CLAUSES, and require the level at which the clause
+ appears in the loop nest in each clause. Return the nesting depth
+ of the transformed loop nest.
+
+ REQUIRED_DEPTH is the nesting depth of the loop nest required by
+ the preceding directive. OUTER_DESCR is a description of the
+ language construct that requires the loop nest depth (e.g. "loop
+ collpase", "outer transformation") that is used for error
+ messages. */
+
+static int
+cp_parser_omp_nested_loop_transform_clauses (cp_parser *parser, tree &clauses,
+ int level, int required_depth,
+ const char *outer_descr)
+{
+ tree c = NULL_TREE;
+ tree last_c = tree_last (clauses);
+
+ /* The depth of the loop nest after the transformations. That is,
+ the nesting depth left by the outermost transformation which is
+ the first to be parsed, but the last to be executed. */
+ int transformed_depth = 0;
+
+ /* The minimum nesting depth required by the last parsed transformation. */
+ int last_depth = required_depth;
+
+ while ((c = cp_parser_omp_loop_transform_clause (parser)))
+ {
+ /* The nesting depth left after the current transformation. */
+ int depth = 1;
+ if (TREE_CODE (c) == ERROR_MARK)
+ goto error;
+
+ gcc_assert (!TREE_CHAIN (c));
+ switch (OMP_CLAUSE_CODE (c))
+ {
+ case OMP_CLAUSE_UNROLL_FULL:
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%<full%> clause is invalid here; "
+ "turns loop into non-loop");
+ goto error;
+ case OMP_CLAUSE_UNROLL_NONE:
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%<#pragma omp unroll%> without "
+ "%<partial%> clause is invalid here; "
+ "turns loop into non-loop");
+ goto error;
+ case OMP_CLAUSE_UNROLL_PARTIAL:
+ depth = 1;
+ break;
+ case OMP_CLAUSE_TILE:
+ depth = list_length (OMP_CLAUSE_TILE_SIZES (c));
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ OMP_CLAUSE_TRANSFORM_LEVEL (c)
+ = build_int_cst (unsigned_type_node, level);
+
+ if (depth < last_depth)
+ {
+ bool is_outermost_clause = !transformed_depth;
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "nesting depth left after this transformation too low "
+ "for %s",
+ is_outermost_clause ? outer_descr
+ : "outer transformation");
+ goto error;
+ }
+
+ last_depth = depth;
+
+ if (!transformed_depth)
+ transformed_depth = last_depth;
+
+ c = finish_omp_clauses (c, C_ORT_OMP);
+
+ if (!clauses)
+ clauses = c;
+ else if (last_c)
+ TREE_CHAIN (last_c) = c;
+
+ last_c = c;
+ }
+
+ return transformed_depth;
+
+error:
+ while (cp_parser_omp_loop_transform_clause (parser))
+ ;
+ clauses = NULL_TREE;
+ return -1;
+}
+
+static tree
+cp_parser_omp_unroll (cp_parser *parser, cp_token *tok, bool *if_p)
+{
+ tree block, ret;
+ 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)
+ {
+ tree c = build_omp_clause (tok->location, OMP_CLAUSE_UNROLL_NONE);
+ OMP_CLAUSE_TRANSFORM_LEVEL (c) = build_int_cst (unsigned_type_node, 0);
+ OMP_CLAUSE_CHAIN (c) = clauses;
+ clauses = c;
+ }
+
+ int required_depth = 1;
+ cp_parser_omp_nested_loop_transform_clauses (parser, clauses, 0,
+ required_depth,
+ "outer transformation");
+
+ block = begin_omp_structured_block ();
+ ret = cp_parser_omp_for_loop (parser, OMP_LOOP_TRANS, clauses, NULL, if_p);
+ block = finish_omp_structured_block (block);
+ add_stmt (block);
+
+ return ret;
+}
+
/* OpenACC 2.0:
# pragma acc cache (variable-list) new-line
*/
@@ -49675,6 +50146,12 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok, bool *if_p)
case PRAGMA_OMP_ASSUME:
cp_parser_omp_assume (parser, pragma_tok, if_p);
return;
+ case PRAGMA_OMP_TILE:
+ stmt = cp_parser_omp_tile (parser, pragma_tok, if_p);
+ break;
+ case PRAGMA_OMP_UNROLL:
+ stmt = cp_parser_omp_unroll (parser, pragma_tok, if_p);
+ break;
default:
gcc_unreachable ();
}
@@ -50321,6 +50798,14 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p)
cp_parser_omp_construct (parser, pragma_tok, if_p);
pop_omp_privatization_clauses (stmt);
return true;
+ case PRAGMA_OMP_TILE:
+ case PRAGMA_OMP_UNROLL:
+ if (context != pragma_stmt && context != pragma_compound)
+ goto bad_stmt;
+ stmt = push_omp_privatization_clauses (false);
+ cp_parser_omp_construct (parser, pragma_tok, if_p);
+ pop_omp_privatization_clauses (stmt);
+ return true;
case PRAGMA_OMP_REQUIRES:
if (context != pragma_external)
@@ -18142,6 +18142,16 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort,
OMP_CLAUSE_OPERAND (nc, 0)
= tsubst_expr (OMP_CLAUSE_OPERAND (oc, 0), args, complain, in_decl);
break;
+ case OMP_CLAUSE_UNROLL_PARTIAL:
+ OMP_CLAUSE_UNROLL_PARTIAL_EXPR (nc)
+ = tsubst_expr (OMP_CLAUSE_UNROLL_PARTIAL_EXPR (oc), args, complain,
+ in_decl);
+ break;
+ case OMP_CLAUSE_TILE:
+ OMP_CLAUSE_TILE_SIZES (nc)
+ = tsubst_expr (OMP_CLAUSE_TILE_SIZES (oc), args, complain,
+ in_decl);
+ break;
case OMP_CLAUSE_REDUCTION:
case OMP_CLAUSE_IN_REDUCTION:
case OMP_CLAUSE_TASK_REDUCTION:
@@ -18222,6 +18232,8 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort,
case OMP_CLAUSE_IF_PRESENT:
case OMP_CLAUSE_FINALIZE:
case OMP_CLAUSE_NOHOST:
+ case OMP_CLAUSE_UNROLL_FULL:
+ case OMP_CLAUSE_UNROLL_NONE:
break;
default:
gcc_unreachable ();
@@ -19494,6 +19506,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
case OMP_SIMD:
case OMP_DISTRIBUTE:
case OMP_TASKLOOP:
+ case OMP_LOOP_TRANS:
case OACC_LOOP:
{
tree clauses, body, pre_body;
@@ -6887,6 +6887,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
bool mergeable_seen = false;
bool implicit_moved = false;
bool target_in_reduction_seen = false;
+ bool unroll_full_seen = false;
bitmap_obstack_initialize (NULL);
bitmap_initialize (&generic_head, &bitmap_default_obstack);
@@ -8876,6 +8877,46 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
}
break;
+ case OMP_CLAUSE_TILE:
+ for (tree list = OMP_CLAUSE_TILE_SIZES (c); !remove && list;
+ list = TREE_CHAIN (list))
+ {
+ t = TREE_VALUE (list);
+
+ if (t == error_mark_node)
+ remove = true;
+ else if (!type_dependent_expression_p (t)
+ && !INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%<tile sizes%> argument needs integral type");
+ remove = true;
+ }
+ else
+ {
+ t = mark_rvalue_use (t);
+ if (!processing_template_decl)
+ {
+ t = maybe_constant_value (t);
+ int n;
+ if (!tree_fits_shwi_p (t)
+ || !INTEGRAL_TYPE_P (TREE_TYPE (t))
+ || (n = tree_to_shwi (t)) <= 0 || (int)n != n)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%<tile sizes%> argument needs positive "
+ "integral constant");
+ remove = true;
+ }
+ t = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+ }
+ }
+
+ /* Update list item. */
+ TREE_VALUE (list) = t;
+ }
+ break;
+
case OMP_CLAUSE_ORDERED:
ordered_seen = true;
break;
@@ -8930,6 +8971,60 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
}
break;
+ case OMP_CLAUSE_UNROLL_FULL:
+ if (unroll_full_seen)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%<full%> appears more than once");
+ remove = true;
+ }
+ unroll_full_seen = true;
+ break;
+
+ case OMP_CLAUSE_UNROLL_PARTIAL:
+ {
+ tree t = OMP_CLAUSE_UNROLL_PARTIAL_EXPR (c);
+
+ if (!t)
+ break;
+
+ if (t == error_mark_node)
+ remove = true;
+ else if (!type_dependent_expression_p (t)
+ && !INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "partial argument needs integral type");
+ remove = true;
+ }
+ else
+ {
+ t = mark_rvalue_use (t);
+ if (!processing_template_decl)
+ {
+ t = maybe_constant_value (t);
+
+ int n;
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
+ || !tree_fits_shwi_p (t)
+ || (n = tree_to_shwi (t)) <= 0 || (int)n != n)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "partial argument needs positive constant "
+ "integer expression");
+ remove = true;
+ }
+ t = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+ }
+ }
+
+ OMP_CLAUSE_UNROLL_PARTIAL_EXPR (c) = t;
+ }
+ break;
+
+ case OMP_CLAUSE_UNROLL_NONE:
+ break;
+
default:
gcc_unreachable ();
}
@@ -1,17 +1,20 @@
/* { dg-do compile { target { c || c++11 } } } */
/* Check that a nested FOR loop with standard c/c++ attributes on it
- is treated as intervening code, since it doesn't match the grammar
- for canonical loop nest form. */
+ (not the C++ attribute syntax for OpenMP directives)
+ gives an error. */
extern void do_something (void);
+
+/* This one should be OK, an empty attribute list is ignored in both C
+ and C++. */
void imperfect1 (int x, int y)
{
#pragma omp for collapse (2)
- for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */
+ for (int i = 0; i < x; i++)
{
- [[]] for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */
+ [[]] for (int j = 0; j < y; j++)
do_something ();
}
}
@@ -19,16 +22,15 @@ void imperfect1 (int x, int y)
void perfect1 (int x, int y)
{
#pragma omp for ordered (2)
- for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */
- /* { dg-error "inner loops must be perfectly nested" "" { target *-*-*} .-1 } */
+ for (int i = 0; i < x; i++)
{
- [[]] for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */
+ [[]] for (int j = 0; j < y; j++)
do_something ();
}
}
/* Similar, but put the attributes on a block wrapping the nested loop
- instead. */
+ instead. This is not allowed by the grammar. */
void imperfect2 (int x, int y)
{
new file mode 100644
@@ -0,0 +1,11 @@
+void test ()
+{
+#pragma omp tile sizes (2,4,6)
+ for (unsigned i = 0; i < 10; i++) /* { dg-error "inner loops must be perfectly nested" } */
+ for (unsigned j = 0; j < 10; j++)
+ {
+ float intervening_decl = 0;
+#pragma omp unroll partial(2)
+ for (unsigned k = 0; k < 10; k++);
+ }
+}
new file mode 100644
@@ -0,0 +1,160 @@
+extern void dummy (int);
+
+void
+test ()
+{
+ #pragma omp tile sizes(1)
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp tile sizes(0) /* { dg-error {'tile sizes' argument needs positive integral constant} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp tile sizes(-1) /* { dg-error {'tile sizes' argument needs positive integral constant} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp tile sizes() /* { dg-error {expected expression before} "" { target c} } */
+ /* { dg-error {expected primary-expression before} "" { target c++ } .-1 } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp tile sizes(,) /* { dg-error {expected expression before} "" { target c } } */
+ /* { dg-error {expected primary-expression before} "" { target c++ } .-1 } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp tile sizes(1,2 /* { dg-error {expected '\,' before end of line} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp tile sizes /* { dg-error {expected '\(' before end of line} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp tile sizes(1) sizes(1) /* { dg-error {expected end of line before 'sizes'} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp tile sizes(1)
+ #pragma omp tile sizes(1)
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp tile sizes(1, 2)
+ #pragma omp 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);
+
+ #pragma omp tile sizes(1, 2)
+ #pragma omp tile sizes(1, 2)
+ for (int i = 0; i < 100; ++i)
+ for (int j = 0; j < 100; ++j)
+ dummy (i);
+
+ #pragma omp tile sizes(5, 6)
+ #pragma omp 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);
+
+ #pragma omp tile sizes(1)
+ #pragma omp unroll partia /* { dg-error {expected an OpenMP clause before 'partia'} } */
+ #pragma omp tile sizes(1)
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp tile sizes(1)
+ #pragma omp 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);
+
+ #pragma omp tile sizes(1)
+ #pragma omp unroll full /* { dg-error {'full' clause is invalid here; turns loop into non-loop} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp tile sizes(1)
+ #pragma omp unroll partial
+ #pragma omp tile sizes(1)
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp tile sizes(8,8)
+ #pragma omp unroll partial /* { dg-error {nesting depth left after this transformation too low for outer transformation} } */
+ #pragma omp tile sizes(1)
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp tile sizes(8,8)
+ #pragma omp unroll partial /* { dg-error {nesting depth left after this transformation too low for outer transformation} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp tile sizes(1, 2)
+ for (int i = 0; i < 100; ++i)
+ for (int j = 0; j < 100; ++j)
+ dummy (i);
+
+ #pragma omp 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);
+
+ #pragma omp 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);
+
+ #pragma omp 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);
+
+ #pragma omp tile sizes(1)
+ for (int i = 0; i < 100; ++i)
+ {
+ dummy (i);
+ for (int j = 0; j < 100; ++j)
+ dummy (i);
+ }
+
+ #pragma omp tile sizes(1)
+ for (int i = 0; i < 100; ++i)
+ {
+ for (int j = 0; j < 100; ++j)
+ dummy (j);
+ dummy (i);
+ }
+
+ #pragma omp 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);
+ }
+
+ #pragma omp 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;
+ #pragma omp 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 } */
+ /* { dg-error {'s' cannot appear in a constant-expression} "" { target c++98_only } .-2 } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp tile sizes(42.0) /* { dg-error {'tile sizes' argument needs positive integral constant} "" { target c } } */
+ /* { dg-error {'tile sizes' argument needs integral type} "" { target c++ } .-1 } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+}
new file mode 100644
@@ -0,0 +1,179 @@
+extern void dummy (int);
+
+void
+test ()
+{
+ #pragma omp parallel for
+ #pragma omp tile sizes(1)
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp parallel for
+ #pragma omp tile sizes(0) /* { dg-error {'tile sizes' argument needs positive integral constant} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp parallel for
+ #pragma omp tile sizes(-1) /* { dg-error {'tile sizes' argument needs positive integral constant} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp parallel for
+ #pragma omp tile sizes() /* { dg-error {expected expression before} "" { target c} } */
+ /* { dg-error {expected primary-expression before} "" { target c++ } .-1 } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp parallel for
+ #pragma omp tile sizes(,) /* { dg-error {expected expression before} "" { target c } } */
+ /* { dg-error {expected primary-expression before} "" { target c++ } .-1 } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp parallel for
+ #pragma omp tile sizes(1,2 /* { dg-error {expected '\,' before end of line} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp parallel for
+ #pragma omp tile sizes /* { dg-error {expected '\(' before end of line} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp parallel for
+ #pragma omp tile sizes(1) sizes(1) /* { dg-error {expected end of line before 'sizes'} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp parallel for
+ #pragma omp tile sizes(1)
+ #pragma omp tile sizes(1)
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp parallel for
+ #pragma omp tile sizes(1, 2)
+ #pragma omp 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);
+
+ #pragma omp parallel for
+ #pragma omp tile sizes(1, 2)
+ #pragma omp tile sizes(1, 2)
+ for (int i = 0; i < 100; ++i)
+ for (int j = 0; j < 100; ++j)
+ dummy (i);
+
+ #pragma omp parallel for
+ #pragma omp tile sizes(5, 6)
+ #pragma omp 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);
+
+ #pragma omp parallel for
+ #pragma omp tile sizes(1)
+ #pragma omp unroll partia /* { dg-error {expected an OpenMP clause before 'partia'} } */
+ #pragma omp tile sizes(1)
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp parallel for
+ #pragma omp tile sizes(1)
+ #pragma omp 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);
+
+ #pragma omp parallel for
+ #pragma omp tile sizes(1)
+ #pragma omp unroll full /* { dg-error {'full' clause is invalid here; turns loop into non-loop} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp parallel for
+ #pragma omp tile sizes(1)
+ #pragma omp unroll partial
+ #pragma omp tile sizes(1)
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp parallel for
+ #pragma omp tile sizes(8,8)
+ #pragma omp unroll partial /* { dg-error {nesting depth left after this transformation too low for outer transformation} } */
+ #pragma omp tile sizes(1)
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp parallel for
+ #pragma omp tile sizes(8,8)
+ #pragma omp unroll partial /* { dg-error {nesting depth left after this transformation too low for outer transformation} } */
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+ #pragma omp parallel for
+ #pragma omp tile sizes(1, 2)
+ for (int i = 0; i < 100; ++i)
+ for (int j = 0; j < 100; ++j)
+ dummy (i);
+
+ #pragma omp parallel for
+ #pragma omp 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);
+
+ #pragma omp parallel for
+ #pragma omp 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);
+
+ #pragma omp parallel for
+ #pragma omp 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);
+
+ #pragma omp parallel for
+ #pragma omp tile sizes(1)
+ for (int i = 0; i < 100; ++i)
+ {
+ dummy (i);
+ for (int j = 0; j < 100; ++j)
+ dummy (i);
+ }
+
+ #pragma omp parallel for
+ #pragma omp tile sizes(1)
+ for (int i = 0; i < 100; ++i)
+ {
+ for (int j = 0; j < 100; ++j)
+ dummy (j);
+ dummy (i);
+ }
+
+ #pragma omp parallel for
+ #pragma omp 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);
+ }
+
+ #pragma omp parallel for
+ #pragma omp 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);
+ }
+
+ #pragma omp parallel for
+ #pragma omp tile sizes(1)
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+}
new file mode 100644
@@ -0,0 +1,109 @@
+extern void dummy (int);
+
+void
+test ()
+{
+ #pragma omp for
+ #pragma omp 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);
+
+ #pragma omp for
+ #pragma omp 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);
+
+
+#pragma omp for collapse(1)
+ #pragma omp tile sizes(1)
+ for (int i = 0; i < 100; ++i)
+ for (int j = 0; j < 100; ++j)
+ dummy (i);
+
+#pragma omp for collapse(2)
+ #pragma omp 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);
+
+#pragma omp for collapse(2)
+ #pragma omp tile sizes(1, 2)
+ for (int i = 0; i < 100; ++i)
+ for (int j = 0; j < 100; ++j)
+ dummy (i);
+
+#pragma omp for collapse(3)
+ #pragma omp 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);
+
+#pragma omp for collapse(1)
+#pragma omp tile sizes(1)
+#pragma omp tile sizes(1)
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+#pragma omp for collapse(2)
+#pragma omp tile sizes(1, 2)
+#pragma omp 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);
+
+#pragma omp for collapse(2)
+#pragma omp tile sizes(1, 2)
+#pragma omp tile sizes(1, 2)
+ for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} } */
+ dummy (i);
+
+#pragma omp for collapse(2)
+#pragma omp tile sizes(5, 6)
+#pragma omp tile sizes(1, 2, 3)
+ for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} } */
+ dummy (i);
+
+#pragma omp for collapse(1)
+#pragma omp tile sizes(1)
+#pragma omp tile sizes(1)
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+
+#pragma omp for collapse(2)
+#pragma omp tile sizes(1, 2)
+#pragma omp 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);
+
+#pragma omp for collapse(2)
+#pragma omp tile sizes(1, 2)
+#pragma omp tile sizes(1, 2)
+ for (int i = 0; i < 100; ++i)
+ for (int j = 0; j < 100; ++j)
+ dummy (i);
+
+#pragma omp for collapse(2)
+#pragma omp tile sizes(5, 6)
+#pragma omp 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);
+
+#pragma omp for collapse(3)
+#pragma omp tile sizes(1, 2) /* { dg-error {nesting depth left after this transformation too low for loop collapse} } */
+#pragma omp 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);
+
+#pragma omp for collapse(3)
+#pragma omp tile sizes(5, 6) /* { dg-error {nesting depth left after this transformation too low for loop collapse} } */
+#pragma omp 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);
+}
new file mode 100644
@@ -0,0 +1,322 @@
+/* { dg-do run } */
+/* { dg-options "-O0 -fopenmp-simd" } */
+
+#include <stdio.h>
+
+#define ASSERT_EQ(var, val) if (var != val) { fprintf (stderr, "%s:%d: Unexpected value %d, expected %d\n", __FILE__, __LINE__, var, val); \
+ __builtin_abort (); }
+
+int
+test1 ()
+{
+ int iter = 0;
+ int i;
+#pragma omp tile sizes(3)
+ for (i = 0; i < 10; i=i+2)
+ {
+ ASSERT_EQ (i, iter)
+ iter = iter + 2;
+ }
+
+ ASSERT_EQ (i, 10)
+ return iter;
+}
+
+int
+test2 ()
+{
+ int iter = 0;
+ int i;
+#pragma omp tile sizes(3)
+ for (i = 0; i < 10; i=i+2)
+ {
+ ASSERT_EQ (i, iter)
+ iter = iter + 2;
+ }
+
+ ASSERT_EQ (i, 10)
+ return iter;
+}
+
+int
+test3 ()
+{
+ int iter = 0;
+ int i;
+#pragma omp tile sizes(8)
+ for (i = 0; i < 10; i=i+2)
+ {
+ ASSERT_EQ (i, iter)
+ iter = iter + 2;
+ }
+
+ ASSERT_EQ (i, 10)
+ return iter;
+}
+
+int
+test4 ()
+{
+ int iter = 10;
+ int i;
+#pragma omp tile sizes(8)
+ for (i = 10; i > 0; i=i-2)
+ {
+ ASSERT_EQ (i, iter)
+ iter = iter - 2;
+ }
+ ASSERT_EQ (i, 0)
+ return iter;
+}
+
+int
+test5 ()
+{
+ int iter = 10;
+ int i;
+#pragma omp tile sizes(71)
+ for (i = 10; i > 0; i=i-2)
+ {
+ ASSERT_EQ (i, iter)
+ iter = iter - 2;
+ }
+
+ ASSERT_EQ (i, 0)
+ return iter;
+}
+
+int
+test6 ()
+{
+ int iter = 10;
+ int i;
+#pragma omp tile sizes(1)
+ for (i = 10; i > 0; i=i-2)
+ {
+ ASSERT_EQ (i, iter)
+ iter = iter - 2;
+ }
+ ASSERT_EQ (i, 0)
+ return iter;
+}
+
+int
+test7 ()
+{
+ int iter = 5;
+ int i;
+#pragma omp tile sizes(2)
+ for (i = 5; i < -5; i=i-3)
+ {
+ fprintf (stderr, "%d\n", i);
+ __builtin_abort ();
+ iter = iter - 3;
+ }
+
+ ASSERT_EQ (i, 5)
+
+ /* No iteration expected */
+ return iter;
+}
+
+int
+test8 ()
+{
+ int iter = 5;
+ int i;
+#pragma omp tile sizes(2)
+ for (i = 5; i > -5; i=i-3)
+ {
+ ASSERT_EQ (i, iter)
+ /* Expect only first iteration of the last tile to execute */
+ if (iter != -4)
+ iter = iter - 3;
+ }
+
+ ASSERT_EQ (i, -7)
+ return iter;
+}
+
+
+int
+test9 ()
+{
+ int iter = 5;
+ int i;
+#pragma omp tile sizes(5)
+ for (i = 5; i >= -5; i=i-4)
+ {
+ ASSERT_EQ (i, iter)
+ /* Expect only first iteration of the last tile to execute */
+ if (iter != - 3)
+ iter = iter - 4;
+ }
+
+ ASSERT_EQ (i, -7)
+ return iter;
+}
+
+int
+test10 ()
+{
+ int iter = 5;
+ int i;
+#pragma omp tile sizes(5)
+ for (i = 5; i >= -5; i--)
+ {
+ ASSERT_EQ (i, iter)
+ iter--;
+ }
+
+ ASSERT_EQ (i, -6)
+ return iter;
+}
+
+int
+test11 ()
+{
+ int iter = 5;
+ int i;
+#pragma omp tile sizes(15)
+ for (i = 5; i != -5; i--)
+ {
+ ASSERT_EQ (i, iter)
+ iter--;
+ }
+ ASSERT_EQ (i, -5)
+ return iter;
+}
+
+int
+test12 ()
+{
+ int iter = 0;
+ unsigned i;
+#pragma omp tile sizes(3)
+ for (i = 0; i != 5; i++)
+ {
+ ASSERT_EQ (i, iter)
+ iter++;
+ }
+
+ ASSERT_EQ (i, 5)
+ return iter;
+}
+
+int
+test13 ()
+{
+ int iter = -5;
+ long long unsigned int i;
+#pragma omp tile sizes(15)
+ for (int i = -5; i < 5; i=i+3)
+ {
+ ASSERT_EQ (i, iter)
+ iter++;
+ }
+
+ ASSERT_EQ (i, 5)
+ return iter;
+}
+
+int
+test14 (unsigned init, int step)
+{
+ int iter = init;
+ long long unsigned int i;
+#pragma omp tile sizes(8)
+ for (i = init; i < 2*init; i=i+step)
+ iter++;
+
+ ASSERT_EQ (i, 2*init)
+ return iter;
+}
+
+int
+test15 (unsigned init, int step)
+{
+ int iter = init;
+ int i;
+#pragma omp tile sizes(8)
+ for (unsigned i = init; i > 2* init; i=i+step)
+ iter++;
+
+ return iter;
+}
+
+int
+main ()
+{
+ int last_iter;
+
+ last_iter = test1 ();
+ ASSERT_EQ (last_iter, 10);
+
+ last_iter = test2 ();
+ ASSERT_EQ (last_iter, 10);
+
+ last_iter = test3 ();
+ ASSERT_EQ (last_iter, 10);
+
+ last_iter = test4 ();
+ ASSERT_EQ (last_iter, 0);
+
+ last_iter = test5 ();
+ ASSERT_EQ (last_iter, 0);
+
+ last_iter = test6 ();
+ ASSERT_EQ (last_iter, 0);
+
+ last_iter = test7 ();
+ ASSERT_EQ (last_iter, 5);
+
+ last_iter = test8 ();
+ ASSERT_EQ (last_iter, -4);
+
+ last_iter = test9 ();
+ ASSERT_EQ (last_iter, -3);
+
+ last_iter = test10 ();
+ ASSERT_EQ (last_iter, -6);
+ return 0;
+
+ last_iter = test11 ();
+ ASSERT_EQ (last_iter, -4);
+ return 0;
+
+ last_iter = test12 ();
+ ASSERT_EQ (last_iter, 5);
+ return 0;
+
+ last_iter = test13 ();
+ ASSERT_EQ (last_iter, 4);
+ return 0;
+
+ last_iter = test14 (0, 1);
+ ASSERT_EQ (last_iter, 0);
+ return 0;
+
+ last_iter = test14 (0, -1);
+ ASSERT_EQ (last_iter, 0);
+ return 0;
+
+ last_iter = test14 (8, 2);
+ ASSERT_EQ (last_iter, 16);
+ return 0;
+
+ last_iter = test14 (5, 3);
+ ASSERT_EQ (last_iter, 9);
+ return 0;
+
+ last_iter = test15 (8, -1);
+ ASSERT_EQ (last_iter, 9);
+ return 0;
+
+ last_iter = test15 (8, -2);
+ ASSERT_EQ (last_iter, 10);
+ return 0;
+
+ last_iter = test15 (5, -3);
+ ASSERT_EQ (last_iter, 6);
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,150 @@
+/* { dg-do run } */
+/* { dg-options "-O0 -fopenmp-simd" } */
+
+#include <stdio.h>
+
+#define ASSERT_EQ(var, val) if (var != val) { fprintf (stderr, "%s:%d: Unexpected value %d\n", __FILE__, __LINE__, var); \
+ __builtin_abort (); }
+
+#define ASSERT_EQ_PTR(var, ptr) if (var != ptr) { fprintf (stderr, "%s:%d: Unexpected value %p\n", __FILE__, __LINE__, var); \
+ __builtin_abort (); }
+
+int
+test1 (int data[10])
+{
+ int iter = 0;
+ int *i;
+ #pragma omp tile sizes(5)
+ for (i = data; i < data + 10 ; i++)
+ {
+ ASSERT_EQ (*i, data[iter]);
+ ASSERT_EQ_PTR (i, data + iter);
+ iter++;
+ }
+
+ ASSERT_EQ_PTR (i, data + 10)
+ return iter;
+}
+
+int
+test2 (int data[10])
+{
+ int iter = 0;
+ int *i;
+ #pragma omp tile sizes(5)
+ for (i = data; i < data + 10 ; i=i+2)
+ {
+ ASSERT_EQ_PTR (i, data + 2 * iter);
+ ASSERT_EQ (*i, data[2 * iter]);
+ iter++;
+ }
+
+ ASSERT_EQ_PTR (i, data + 10)
+ return iter;
+}
+
+int
+test3 (int data[10])
+{
+ int iter = 0;
+ int *i;
+ #pragma omp tile sizes(5)
+ for (i = data; i <= data + 9 ; i=i+2)
+ {
+ ASSERT_EQ (*i, data[2 * iter]);
+ iter++;
+ }
+
+ ASSERT_EQ_PTR (i, data + 10)
+ return iter;
+}
+
+int
+test4 (int data[10])
+{
+ int iter = 0;
+ int *i;
+ #pragma omp tile sizes(5)
+ for (i = data; i != data + 10 ; i=i+1)
+ {
+ ASSERT_EQ (*i, data[iter]);
+ iter++;
+ }
+
+ ASSERT_EQ_PTR (i, data + 10)
+ return iter;
+}
+
+int
+test5 (int data[10])
+{
+ int iter = 0;
+ int *i;
+ #pragma omp tile sizes(3)
+ for (i = data + 9; i >= data ; i--)
+ {
+ ASSERT_EQ (*i, data[9 - iter]);
+ iter++;
+ }
+
+ ASSERT_EQ_PTR (i, data - 1)
+ return iter;
+}
+
+int
+test6 (int data[10])
+{
+ int iter = 0;
+ int *i;
+ #pragma omp tile sizes(3)
+ for (i = data + 9; i > data - 1 ; i--)
+ {
+ ASSERT_EQ (*i, data[9 - iter]);
+ iter++;
+ }
+
+ ASSERT_EQ_PTR (i, data - 1)
+ return iter;
+}
+
+int
+test7 (int data[10])
+{
+ int iter = 0;
+ #pragma omp tile sizes(1)
+ for (int *i = data + 9; i != data - 1 ; i--)
+ {
+ ASSERT_EQ (*i, data[9 - iter]);
+ iter++;
+ }
+
+ return iter;
+}
+
+int
+main ()
+{
+ int iter_count;
+ int data[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ iter_count = test1 (data);
+ ASSERT_EQ (iter_count, 10);
+
+ iter_count = test2 (data);
+ ASSERT_EQ (iter_count, 5);
+
+ iter_count = test3 (data);
+ ASSERT_EQ (iter_count, 5);
+
+ iter_count = test4 (data);
+ ASSERT_EQ (iter_count, 10);
+
+ iter_count = test5 (data);
+ ASSERT_EQ (iter_count, 10);
+
+ iter_count = test6 (data);
+ ASSERT_EQ (iter_count, 10);
+
+ iter_count = test7 (data);
+ ASSERT_EQ (iter_count, 10);
+}
new file mode 100644
@@ -0,0 +1,34 @@
+/* { dg-do run } */
+/* { dg-options "-O0 -fopenmp-simd" } */
+
+#include <stdio.h>
+
+int
+test1 ()
+{
+ int sum = 0;
+for (int k = 0; k < 10; k++)
+ {
+#pragma omp tile sizes(5,7)
+ for (int i = 0; i < 10; i++)
+ for (int j = 0; j < 10; j=j+2)
+ {
+ sum = sum + 1;
+ }
+ }
+
+ return sum;
+}
+
+int
+main ()
+{
+ int result = test1 ();
+
+ if (result != 500)
+ {
+ fprintf (stderr, "Wrong result: %d\n", result);
+ __builtin_abort ();
+ }
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,31 @@
+/* { dg-do run } */
+/* { dg-options "-O0 -fopenmp-simd" } */
+
+#include <stdio.h>
+#define ASSERT_EQ(var, val) if (var != val) { fprintf (stderr, "%s:%d: Unexpected value %d\n", __FILE__, __LINE__, var); \
+ __builtin_abort (); }
+
+#define ASSERT_EQ_PTR(var, ptr) if (var != ptr) { fprintf (stderr, "%s:%d: Unexpected value %p\n", __FILE__, __LINE__, var); \
+ __builtin_abort (); }
+
+int
+main ()
+{
+ int iter_count;
+ int data[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ int iter = 0;
+ int *i;
+ #pragma omp tile sizes(1)
+ for (i = data; i < data + 10; i=i+2)
+ {
+ ASSERT_EQ_PTR (i, data + 2 * iter);
+ ASSERT_EQ (*i, data[2 * iter]);
+ iter++;
+ }
+
+ unsigned long real_iter_count = ((unsigned long)i - (unsigned long)data) / (sizeof (int) * 2);
+ ASSERT_EQ (real_iter_count, 5);
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,40 @@
+/* { dg-do run } */
+/* { dg-options "-O0 -fopenmp-simd" } */
+
+#include <stdio.h>
+
+#define ASSERT_EQ(var, val) if (var != val) { fprintf (stderr, "%s:%d: Unexpected value %d, expected %d\n", __FILE__, __LINE__, var, val); \
+ __builtin_abort (); }
+
+int
+main ()
+{
+ int iter_j = 0, iter_k = 0;
+ unsigned i, j, k;
+#pragma omp tile sizes(3,5,8)
+ for (i = 0; i < 2; i=i+2)
+ for (j = 0; j < 3; j=j+1)
+ for (k = 0; k < 5; k=k+3)
+ {
+ /* fprintf (stderr, "i=%d j=%d k=%d\n", i, j, k);
+ * fprintf (stderr, "iter_j=%d iter_k=%d\n", iter_j, iter_k); */
+ ASSERT_EQ (i, 0);
+ if (k == 0)
+ {
+ ASSERT_EQ (j, iter_j);
+ iter_k = 0;
+ }
+
+ ASSERT_EQ (k, iter_k);
+
+ iter_k = iter_k + 3;
+ if (k == 3)
+ iter_j++;
+ }
+
+ ASSERT_EQ (i, 2);
+ ASSERT_EQ (j, 3);
+ ASSERT_EQ (k, 6);
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,133 @@
+extern void dummy (int);
+
+void
+test1 ()
+{
+#pragma omp unroll partial
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+}
+
+void
+test2 ()
+{
+#pragma omp unroll partial(10)
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+}
+
+void
+test3 ()
+{
+#pragma omp unroll full
+ for (int i = 0; i < 100; ++i)
+ dummy (i);
+}
+
+void
+test4 ()
+{
+#pragma omp unroll full
+ for (int i = 0; i > 100; ++i)
+ dummy (i);
+}
+
+void
+test5 ()
+{
+#pragma omp unroll full
+ for (int i = 1; i <= 100; ++i)
+ dummy (i);
+}
+
+void
+test6 ()
+{
+#pragma omp unroll full
+ for (int i = 200; i >= 100; i--)
+ dummy (i);
+}
+
+void
+test7 ()
+{
+#pragma omp unroll full
+ for (int i = -100; i > 100; ++i)
+ dummy (i);
+}
+
+void
+test8 ()
+{
+#pragma omp unroll full
+ for (int i = 100; i > -200; --i)
+ dummy (i);
+}
+
+void
+test9 ()
+{
+#pragma omp unroll full
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+}
+
+void
+test10 ()
+{
+#pragma omp unroll full
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+}
+
+void
+test12 ()
+{
+#pragma omp unroll full
+#pragma omp unroll partial
+#pragma omp unroll partial
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+}
+
+void
+test13 ()
+{
+ for (int i = 0; i < 100; ++i)
+#pragma omp unroll full
+#pragma omp unroll partial
+#pragma omp unroll partial
+ for (int j = -300; j != 100; ++j)
+ dummy (i);
+}
+
+void
+test14 ()
+{
+ #pragma omp for
+ for (int i = 0; i < 100; ++i)
+#pragma omp unroll full
+#pragma omp unroll partial
+#pragma omp unroll partial
+ for (int j = -300; j != 100; ++j)
+ dummy (i);
+}
+
+void
+test15 ()
+{
+ #pragma omp for
+ for (int i = 0; i < 100; ++i)
+ {
+
+ dummy (i);
+
+#pragma omp unroll full
+#pragma omp unroll partial
+#pragma omp unroll partial
+ for (int j = -300; j != 100; ++j)
+ dummy (j);
+
+ dummy (i);
+ }
+ }
new file mode 100644
@@ -0,0 +1,95 @@
+/* { dg-prune-output "error: invalid controlling predicate" } */
+/* { dg-additional-options "-std=c++11" { target c++} } */
+
+extern void dummy (int);
+
+void
+test ()
+{
+#pragma omp unroll partial
+#pragma omp unroll full /* { dg-error {'full' clause is invalid here; turns loop into non-loop} } */
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+
+#pragma omp for
+#pragma omp unroll full /* { dg-error {'full' clause is invalid here; turns loop into non-loop} } */
+#pragma omp unroll partial
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+
+#pragma omp for
+#pragma omp unroll full /* { dg-error {'full' clause is invalid here; turns loop into non-loop} } */
+#pragma omp unroll full
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+
+#pragma omp for
+#pragma omp unroll partial partial /* { dg-error {too many 'partial' clauses} } */
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+
+#pragma omp unroll full full /* { dg-error {too many 'full' clauses} } */
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+
+#pragma omp unroll partial
+#pragma omp 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);
+
+#pragma omp for
+#pragma omp 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;
+#pragma omp for
+#pragma omp unroll( /* { dg-error {expected an OpenMP clause before '\(' token} } */
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+
+#pragma omp for
+#pragma omp unroll foo /* { dg-error {expected an OpenMP clause before 'foo'} } */
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+
+#pragma omp unroll partial( /* { dg-error {expected expression before end of line} "" { target c } } */
+ /* { dg-error {expected primary-expression before end of line} "" { target c++ } .-1 } */
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+
+#pragma omp unroll partial() /* { dg-error {expected expression before '\)' token} "" { target c } } */
+ /* { dg-error {expected primary-expression before '\)' token} "" { target c++ } .-1 } */
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+
+#pragma omp 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);
+
+#pragma omp unroll parti /* { dg-error {expected an OpenMP clause before 'parti'} } */
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+
+#pragma omp for
+#pragma omp unroll partial(1)
+#pragma omp unroll parti /* { dg-error {expected an OpenMP clause before 'parti'} } */
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+
+#pragma omp for
+#pragma omp unroll partial(1)
+#pragma omp unroll parti /* { dg-error {expected an OpenMP clause before 'parti'} } */
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+
+int sum = 0;
+#pragma omp parallel for reduction(+ : sum) collapse(2)
+#pragma omp 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++;
+}
+
new file mode 100644
@@ -0,0 +1,18 @@
+/* { dg-additional-options "-fdump-tree-omp_transform_loops" }
+ * { dg-additional-options "-fdump-tree-original" } */
+
+extern void dummy (int);
+
+void
+test1 ()
+{
+ int i;
+#pragma omp 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" } } */
new file mode 100644
@@ -0,0 +1,19 @@
+/* { dg-additional-options "-fdump-tree-omp_transform_loops" }
+ * { dg-additional-options "-fdump-tree-original" } */
+
+extern void dummy (int);
+
+void
+test1 ()
+{
+ int i;
+#pragma omp unroll
+ for (int i = 0; i < 100; i++)
+ dummy (i);
+}
+
+/* Loop should not be unrolled, but the internal representation should be lowered
+ * { dg-final { scan-tree-dump "#pragma omp loop_transform" "original" } }
+ * { dg-final { scan-tree-dump-not "#pragma omp" "omp_transform_loops" } }
+ * { dg-final { scan-tree-dump-times "dummy" 1 "omp_transform_loops" } }
+ * { dg-final { scan-tree-dump-times {if \(i < .+?.+goto.+else goto.*?$} 1 "omp_transform_loops" } } */
new file mode 100644
@@ -0,0 +1,19 @@
+/* { dg-additional-options "-fdump-tree-omp_transform_loops -fopt-info-omp-optimized-missed" }
+ * { dg-additional-options "-fdump-tree-original" } */
+
+extern void dummy (int);
+
+void
+test1 ()
+{
+ int i;
+#pragma omp unroll partial /* { dg-optimized {'partial' clause without unrolling factor turned into 'partial\(5\)' clause} } */
+ for (int i = 0; i < 100; i++)
+ dummy (i);
+}
+
+/* Loop should be unrolled 5 times and the internal representation should be lowered
+ * { dg-final { scan-tree-dump "#pragma omp loop_transform" "original" } }
+ * { dg-final { scan-tree-dump-not "#pragma omp" "omp_transform_loops" } }
+ * { dg-final { scan-tree-dump-times "dummy" 5 "omp_transform_loops" } }
+ * { dg-final { scan-tree-dump-times {if \(i < .+?.+goto.+else goto.*?$} 1 "omp_transform_loops" } } */
new file mode 100644
@@ -0,0 +1,20 @@
+/* { dg-additional-options "--param=omp-unroll-default-factor=100" }
+ * { dg-additional-options "-fdump-tree-omp_transform_loops -fopt-info-omp-optimized-missed" }
+ * { dg-additional-options "-fdump-tree-original" } */
+
+extern void dummy (int);
+
+void
+test1 ()
+{
+ int i;
+#pragma omp unroll /* { dg-optimized {added 'partial\(100\)' clause to 'omp unroll' directive} } */
+ for (int i = 0; i < 100; i++)
+ dummy (i);
+}
+
+/* Loop should be unrolled 5 times and the internal representation should be lowered
+ * { dg-final { scan-tree-dump "#pragma omp loop_transform unroll_none" "original" } }
+ * { dg-final { scan-tree-dump-not "#pragma omp" "omp_transform_loops" } }
+ * { dg-final { scan-tree-dump-times "dummy" 100 "omp_transform_loops" } }
+ * { dg-final { scan-tree-dump-times {if \(i < .+?.+goto.+else goto.*?$} 1 "omp_transform_loops" } } */
new file mode 100644
@@ -0,0 +1,144 @@
+/* { dg-do run } */
+/* { dg-options "-O0 -fopenmp-simd" } */
+
+#include <stdio.h>
+
+#define ASSERT_EQ(var, val) if (var != val) { fprintf (stderr, "%s:%d: Unexpected value %d\n", __FILE__, __LINE__, var); \
+ __builtin_abort (); }
+
+#define ASSERT_EQ_PTR(var, ptr) if (var != ptr) { fprintf (stderr, "%s:%d: Unexpected value %p\n", __FILE__, __LINE__, var); \
+ __builtin_abort (); }
+
+int
+test1 (int data[10])
+{
+ int iter = 0;
+ int *i;
+ #pragma omp unroll partial(8)
+ for (i = data; i < data + 10 ; i++)
+ {
+ ASSERT_EQ (*i, data[iter]);
+ ASSERT_EQ_PTR (i, data + iter);
+ iter++;
+ }
+
+ return iter;
+}
+
+int
+test2 (int data[10])
+{
+ int iter = 0;
+ int *i;
+ #pragma omp unroll partial(8)
+ for (i = data; i < data + 10 ; i=i+2)
+ {
+ ASSERT_EQ_PTR (i, data + 2 * iter);
+ ASSERT_EQ (*i, data[2 * iter]);
+ iter++;
+ }
+
+ return iter;
+}
+
+int
+test3 (int data[10])
+{
+ int iter = 0;
+ int *i;
+ #pragma omp unroll partial(8)
+ for (i = data; i <= data + 9 ; i=i+2)
+ {
+ ASSERT_EQ (*i, data[2 * iter]);
+ iter++;
+ }
+
+ return iter;
+}
+
+int
+test4 (int data[10])
+{
+ int iter = 0;
+ int *i;
+ #pragma omp unroll partial(8)
+ for (i = data; i != data + 10 ; i=i+1)
+ {
+ ASSERT_EQ (*i, data[iter]);
+ iter++;
+ }
+
+ return iter;
+}
+
+int
+test5 (int data[10])
+{
+ int iter = 0;
+ int *i;
+ #pragma omp unroll partial(7)
+ for (i = data + 9; i >= data ; i--)
+ {
+ ASSERT_EQ (*i, data[9 - iter]);
+ iter++;
+ }
+
+ return iter;
+}
+
+int
+test6 (int data[10])
+{
+ int iter = 0;
+ int *i;
+ #pragma omp unroll partial(7)
+ for (i = data + 9; i > data - 1 ; i--)
+ {
+ ASSERT_EQ (*i, data[9 - iter]);
+ iter++;
+ }
+
+ return iter;
+}
+
+int
+test7 (int data[10])
+{
+ int iter = 0;
+ #pragma omp unroll partial(7)
+ for (int *i = data + 9; i != data - 1 ; i--)
+ {
+ ASSERT_EQ (*i, data[9 - iter]);
+ iter++;
+ }
+
+ return iter;
+}
+
+int
+main ()
+{
+ int iter_count;
+ int data[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ iter_count = test1 (data);
+ ASSERT_EQ (iter_count, 10);
+
+ iter_count = test2 (data);
+ ASSERT_EQ (iter_count, 5);
+
+ iter_count = test3 (data);
+ ASSERT_EQ (iter_count, 5);
+
+ iter_count = test4 (data);
+ ASSERT_EQ (iter_count, 10);
+
+ iter_count = test5 (data);
+ ASSERT_EQ (iter_count, 10);
+
+ iter_count = test6 (data);
+ ASSERT_EQ (iter_count, 10);
+
+ iter_count = test7 (data);
+ ASSERT_EQ (iter_count, 10);
+}
new file mode 100644
@@ -0,0 +1,76 @@
+extern void dummy(int);
+
+void
+test1 ()
+{
+#pragma omp unroll full /* { dg-warning "Cannot apply full unrolling to infinite loop" } */
+ for (int i = 101; i > 100; i++)
+ dummy (i);
+}
+
+
+void
+test2 ()
+{
+#pragma omp unroll full
+ for (int i = 101; i != 100; i++)
+ dummy (i);
+}
+
+void
+test3 ()
+{
+#pragma omp unroll full /* { dg-warning "Cannot apply full unrolling to infinite loop" } */
+ for (int i = 0; i <= 0; i--)
+ dummy (i);
+}
+
+void
+test4 ()
+{
+#pragma omp unroll full /* { dg-warning "Cannot apply full unrolling to infinite loop" } */
+ for (int i = 101; i > 100; i=i+2)
+ dummy (i);
+}
+
+void
+test5 ()
+{
+#pragma omp unroll full /* { dg-warning "Cannot apply full unrolling to infinite loop" } */
+ for (int i = -101; i < 100; i=i-10)
+ dummy (i);
+}
+
+void
+test6 ()
+{
+#pragma omp unroll full /* { dg-warning "Cannot apply full unrolling to infinite loop" } */
+ for (int i = -101; i < 100; i=i-300)
+ dummy (i);
+}
+
+void
+test7 ()
+{
+#pragma omp unroll full /* { dg-warning "Cannot apply full unrolling to infinite loop" } */
+ for (int i = 101; i > -100; i=i+300)
+ dummy (i);
+
+ /* Loop does not iterate, hence no warning. */
+#pragma omp unroll full
+ for (int i = 101; i > 101; i=i+300)
+ dummy (i);
+}
+
+void
+test8 ()
+{
+#pragma omp unroll full /* { dg-warning "Cannot apply full unrolling to infinite loop" } */
+ for (int i = -21; i < -20; i=i-40)
+ dummy (i);
+
+ /* Loop does not iterate, hence no warning. */
+#pragma omp unroll full
+ for (int i = -21; i > 20; i=i-40)
+ dummy (i);
+}
new file mode 100644
@@ -0,0 +1,15 @@
+/* { dg-additional-options "-std=c++11" { target c++} } */
+
+extern void dummy (int);
+
+void
+test ()
+{
+
+#pragma omp target parallel for collapse(2)
+ for (int i = -300; i != 100; ++i)
+ #pragma omp unroll partial
+ for (int j = 0; j != 100; ++j)
+ dummy (i);
+}
+
new file mode 100644
@@ -0,0 +1,29 @@
+/* { dg-additional-options "-std=c++11" { target c++} } */
+
+extern void dummy (int);
+
+void
+test ()
+{
+
+#pragma omp target parallel for collapse(2)
+ for (int i = -300; i != 100; ++i)
+#pragma omp tile sizes(2)
+ for (int j = 0; j != 100; ++j)
+ dummy (i);
+
+#pragma omp target parallel for collapse(2)
+ for (int i = -300; i != 100; ++i) /* { dg-error {not enough nested loops} } */
+#pragma omp tile sizes(2, 3)
+ for (int j = 0; j != 100; ++j)
+ dummy (i);
+
+#pragma omp target parallel for collapse(2)
+ for (int i = -300; i != 100; ++i)
+#pragma omp tile sizes(2, 3)
+ for (int j = 0; j != 100; ++j)
+ for (int k = 0; k != 100; ++k)
+ dummy (i);
+}
+
+
new file mode 100644
@@ -0,0 +1,37 @@
+extern void dummy (int);
+
+void
+test1 ()
+{
+#pragma omp target parallel for collapse(2)
+ for (int i = -300; i != 100; ++i)
+#pragma omp unroll partial(2)
+ for (int j = i * 2; j <= i * 4 + 1; ++j)
+ dummy (i);
+
+#pragma omp target parallel for collapse(3)
+ for (int i = -300; i != 100; ++i)
+ for (int j = i; j != i * 2; ++j)
+ #pragma omp unroll partial
+ for (int k = 2; k != 100; ++k)
+ dummy (i);
+
+#pragma omp unroll full
+ for (int i = -300; i != 100; ++i)
+ for (int j = i; j != i * 2; ++j)
+ for (int k = 2; k != 100; ++k)
+ dummy (i);
+
+ for (int i = -300; i != 100; ++i)
+#pragma omp unroll full
+ for (int j = i; j != i + 10; ++j)
+ for (int k = 2; k != 100; ++k)
+ dummy (i);
+
+ for (int i = -300; i != 100; ++i)
+#pragma omp unroll full
+ for (int j = i; j != i + 10; ++j)
+ for (int k = j; k != 100; ++k)
+ dummy (i);
+}
+
new file mode 100644
@@ -0,0 +1,22 @@
+extern void dummy (int);
+
+void
+test1 ()
+{
+#pragma omp target parallel for collapse(2) /* { dg-error {invalid OpenMP non-rectangular loop step; \'\(1 - 0\) \* 1\' is not a multiple of loop 2 step \'5\'} "" { target c } } */
+ for (int i = -300; i != 100; ++i) /* { dg-error {invalid OpenMP non-rectangular loop step; \'\(1 - 0\) \* 1\' is not a multiple of loop 2 step \'5\'} "" { target c++ } } */
+#pragma omp unroll partial
+ for (int j = 2; j != i; ++j)
+ dummy (i);
+}
+
+void
+test2 ()
+{
+ int i,j;
+#pragma omp target parallel for collapse(2)
+ for (i = -300; i != 100; ++i)
+ #pragma omp unroll partial
+ for (j = 2; j != i; ++j)
+ dummy (i);
+}
new file mode 100644
@@ -0,0 +1,84 @@
+/* { dg-options "-fno-openmp -fopenmp-simd" } */
+/* { dg-do run } */
+/* { dg-additional-options "-fdump-tree-original" } */
+/* { dg-additional-options "-fdump-tree-omp_transform_loops" } */
+
+#include <stdio.h>
+
+int compute_sum1 ()
+{
+ int sum = 0;
+ int i,j;
+
+#pragma omp simd reduction(+:sum)
+ for (i = 3; i < 10; ++i)
+ #pragma omp unroll full
+ for (j = -2; j < 7; ++j)
+ sum++;
+
+ if (j != 7)
+ __builtin_abort;
+
+ return sum;
+}
+
+int compute_sum2()
+{
+ int sum = 0;
+ int i,j;
+#pragma omp simd reduction(+:sum)
+#pragma omp unroll partial(5)
+ for (i = 3; i < 10; ++i)
+ for (j = -2; j < 7; ++j)
+ sum++;
+
+ if (j != 7)
+ __builtin_abort;
+
+ return sum;
+}
+
+int compute_sum3()
+{
+ int sum = 0;
+ int i,j;
+#pragma omp simd reduction(+:sum)
+#pragma omp unroll partial(1)
+ for (i = 3; i < 10; ++i)
+ for (j = -2; j < 7; ++j)
+ sum++;
+
+ if (j != 7)
+ __builtin_abort;
+
+ return sum;
+}
+
+int main ()
+{
+ int result = compute_sum1 ();
+ if (result != 7 * 9)
+ {
+ fprintf (stderr, "%d: Wrong result %d\n", __LINE__, result);
+ __builtin_abort ();
+ }
+
+ result = compute_sum1 ();
+ if (result != 7 * 9)
+ {
+ fprintf (stderr, "%d: Wrong result %d\n", __LINE__, result);
+ __builtin_abort ();
+ }
+
+ result = compute_sum3 ();
+ if (result != 7 * 9)
+ {
+ fprintf (stderr, "%d: Wrong result %d\n", __LINE__, result);
+ __builtin_abort ();
+ }
+
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump {omp loop_transform} "original" } } */
+/* { dg-final { scan-tree-dump-not {omp loop_transform} "omp_transform_loops" } } */
@@ -49,7 +49,7 @@ foo (int x)
for (int i = 0; i < 16; i++)
;
#pragma omp for
- [[omp::directive (master)]] // { dg-error "for statement expected before '\\\[' token" }
+ [[omp::directive (master)]] // { dg-error "loop nest expected before '\\\[' token" }
;
#pragma omp target teams
[[omp::directive (parallel)]] // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" }
@@ -24,7 +24,7 @@ void foo (int j, int k)
// Malformed parallel loops.
#pragma omp for
- i = 0; // { dg-error "for statement expected" }
+ i = 0; // { dg-error "loop nest expected" }
for ( ; i < 10; )
{
baz (i);
new file mode 100644
@@ -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);
+}
new file mode 100644
@@ -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);
+}
new file mode 100644
@@ -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);
+}
new file mode 100644
@@ -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);
+ }
+ }
new file mode 100644
@@ -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++;
+}
+
new file mode 100644
@@ -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" } } */
new file mode 100644
@@ -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);
+}
+
new file mode 100644
@@ -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);
+}
+
+
new file mode 100644
@@ -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);
+}
+
new file mode 100644
@@ -0,0 +1,27 @@
+// { dg-do compile }
+// { dg-additional-options "-std=c++11" }
+
+#include <vector>
+
+extern void dummy (int);
+
+template<class T, int U, unsigned V> void
+test1_template ()
+{
+ std::vector<int> v;
+
+ for (unsigned i = 0; i < 10; i++)
+ v.push_back (i);
+
+#pragma omp for
+ for (int i : v)
+ dummy (i);
+
+#pragma omp tile sizes (U, 10, V)
+ for (T i : v)
+ for (T j : v)
+ for (T k : v)
+ dummy (i);
+}
+
+void test () { test1_template <long, 5, 3> (); };
new file mode 100644
@@ -0,0 +1,27 @@
+// { dg-do compile }
+// { dg-additional-options "-std=c++11" }
+
+#include <vector>
+
+extern void dummy (int);
+
+template<class T, int U, unsigned V> void
+test1_template ()
+{
+ std::vector<int> v;
+
+ for (unsigned i = 0; i < 10; i++)
+ v.push_back (i);
+
+#pragma omp teams distribute parallel for num_teams(V)
+ for (int i : v)
+ dummy (i);
+
+#pragma omp tile sizes (V, U)
+ for (T i : v)
+ for (T j : v)
+ for (T k : v)
+ dummy (i);
+}
+
+void test () { test1_template <long, 5, 3> (); };
new file mode 100644
@@ -0,0 +1,27 @@
+// { dg-do compile }
+// { dg-additional-options "-std=c++11" }
+
+#include <vector>
+
+extern void dummy (int);
+
+template<class T, int U, unsigned V> void
+test1_template ()
+{
+ std::vector<int> v;
+
+ for (unsigned i = 0; i < 10; i++)
+ v.push_back (i);
+
+#pragma omp for
+ for (int i : v)
+ dummy (i);
+
+#pragma omp tile sizes (U, 10, V) // { dg-error {'tile sizes' argument needs positive integral constant} }
+ for (T i : v)
+ for (T j : v)
+ for (T k : v)
+ dummy (i);
+}
+
+void test () { test1_template <long, 5, 0> (); };
new file mode 100644
@@ -0,0 +1,42 @@
+// { dg-do compile }
+// { dg-additional-options "-std=c++11" }
+#include <vector>
+
+extern void dummy (int);
+
+void
+test1 ()
+{
+ std::vector<int> v;
+
+ for (unsigned i = 0; i < 1000; i++)
+ v.push_back (i);
+
+#pragma omp for
+ for (int i : v)
+ dummy (i);
+
+#pragma omp unroll partial(5)
+ for (int i : v)
+ dummy (i);
+}
+
+void
+test2 ()
+{
+ std::vector<std::vector<int>> v;
+
+ for (unsigned i = 0; i < 10; i++)
+ {
+ std::vector<int> u;
+ for (unsigned j = 0; j < 10; j++)
+ u.push_back (j);
+ v.push_back (u);
+ }
+
+#pragma omp for
+#pragma omp unroll partial(5)
+ for (auto u : v)
+ for (int i : u)
+ dummy (i);
+}
new file mode 100644
@@ -0,0 +1,47 @@
+// { dg-do link }
+// { dg-additional-options "-std=c++11" }
+#include <vector>
+
+extern void dummy (int);
+
+template<class T, int U1, int U2, int U3> void
+test_template ()
+{
+ std::vector<int> v;
+
+ for (unsigned i = 0; i < 1000; i++)
+ v.push_back (i);
+
+#pragma omp for
+ for (int i : v)
+ dummy (i);
+
+#pragma omp unroll partial(U1)
+ for (T i : v)
+ dummy (i);
+
+#pragma omp unroll partial(U2) // { dg-error {partial argument needs positive constant integer expression} }
+ for (T i : v)
+ dummy (i);
+
+#pragma omp unroll partial(U3) // { dg-error {partial argument needs positive constant integer expression} }
+ for (T i : v)
+ dummy (i);
+
+#pragma omp for
+#pragma omp unroll partial(U1)
+ for (T i : v)
+ dummy (i);
+
+#pragma omp for
+#pragma omp unroll partial(U2) // { dg-error {partial argument needs positive constant integer expression} }
+ for (T i : v)
+ dummy (i);
+
+#pragma omp for
+#pragma omp unroll partial(U3) // { dg-error {partial argument needs positive constant integer expression} }
+ for (T i : v)
+ dummy (i);
+}
+
+void test () { test_template <long, 5,-2, 0> (); };
new file mode 100644
@@ -0,0 +1,37 @@
+// { dg-do compile }
+// { dg-additional-options "-std=c++11" }
+// { dg-additional-options "-fdump-tree-omp_transform_loops -fopt-info-omp-optimized-missed" }
+// { dg-additional-options "-fdump-tree-original" }
+#include <vector>
+
+extern void dummy (int);
+
+constexpr unsigned fib (unsigned n)
+{
+ return n <= 2 ? 1 : fib (n-1) + fib (n-2);
+}
+
+void
+test1 ()
+{
+ std::vector<int> v;
+
+ for (unsigned i = 0; i < 1000; i++)
+ v.push_back (i);
+
+#pragma omp unroll partial(fib(10))
+ for (int i : v)
+ dummy (i);
+}
+
+
+// Loop should be unrolled fib(10) = 55 times
+// ! { dg-final { scan-tree-dump {#pragma omp loop_transform unroll_partial\(55\)} "original" } }
+// ! { dg-final { scan-tree-dump-not "#pragma omp" "omp_transform_loops" } }
+// ! { dg-final { scan-tree-dump-times "dummy" 55 "omp_transform_loops" } }
+
+// There should be one loop that fills the vector ...
+// ! { dg-final { scan-tree-dump-times {if \(i.*? <= .+?.+goto.+else goto.*?$} 1 "omp_transform_loops" } }
+
+// ... and one resulting from the lowering of the unrolled loop
+// ! { dg-final { scan-tree-dump-times {if \(D\.[0-9]+ < retval.+?.+goto.+else goto.*?$} 1 "omp_transform_loops" } }
@@ -8,7 +8,7 @@ void
bar ()
{
#pragma omp parallel master taskloop
- foo (); // { dg-error "for statement expected before" }
+ foo (); // { dg-error "loop nest expected before" }
}
void
@@ -26,7 +26,7 @@ void foo (int j, int k)
/* Malformed parallel loops. */
#pragma omp for
- i = 0; /* { dg-error "3:for statement expected" } */
+ i = 0; /* { dg-error "3:loop nest expected" } */
for ( ; i < 10; )
{
baz (i);
@@ -30,7 +30,7 @@ void foo (int j, int k)
/* Malformed parallel loops. */
#pragma omp for
- i = 0; /* { dg-error "for statement expected" } */
+ i = 0; /* { dg-error "loop nest expected" } */
for ( ; i < 10; )
{
baz (i);
new file mode 100644
@@ -0,0 +1,13 @@
+/* { dg-additional-options { -O0 -fdump-tree-original -Wall -Wno-unknown-pragmas } } */
+
+#define COMMON_DIRECTIVE
+#define COMMON_TOP_TRANSFORM omp unroll full
+#define COLLAPSE_1
+#define COLLAPSE_2
+#define COLLAPSE_3
+#define IMPLEMENTATION_FILE "../../libgomp.c-c++-common/loop-transforms/matrix-constant-iter.h"
+
+#include "../../libgomp.c-c++-common/loop-transforms/matrix-transform-variants-1.h"
+
+/* A consistency check to prevent broken macro usage. */
+/* { dg-final { scan-tree-dump-times "unroll_full" 13 "original" } } */
new file mode 100644
@@ -0,0 +1,69 @@
+// { dg-additional-options "-std=c++11" }
+// { dg-additional-options "-O0" }
+
+#include <vector>
+#include <stdio.h>
+
+constexpr unsigned fib (unsigned n)
+{
+ return n <= 2 ? 1 : fib (n-1) + fib (n-2);
+}
+
+int
+test1 ()
+{
+ std::vector<int> v;
+
+ for (unsigned i = 0; i <= 9; i++)
+ v.push_back (1);
+
+ int sum = 0;
+ for (int k = 0; k < 10; k++)
+ #pragma omp tile sizes(fib(4))
+ for (int i : v) {
+ for (int j = 8; j != -2; --j)
+ sum = sum + i;
+ }
+
+ return sum;
+}
+
+int
+test2 ()
+{
+ std::vector<int> v;
+
+ for (unsigned i = 0; i <= 10; i++)
+ v.push_back (i);
+
+ int sum = 0;
+ for (int k = 0; k < 10; k++)
+#pragma omp parallel for collapse(2) reduction(+:sum)
+#pragma omp tile sizes(fib(4), 1)
+ for (int i : v)
+ for (int j = 8; j > -2; --j)
+ sum = sum + i;
+
+ return sum;
+}
+
+int
+main ()
+{
+ int result = test1 ();
+
+ if (result != 1000)
+ {
+ fprintf (stderr, "%d: Wrong result: %d\n", __LINE__, result);
+ __builtin_abort ();
+ }
+
+ result = test2 ();
+ if (result != 5500)
+ {
+ fprintf (stderr, "%d: Wrong result: %d\n", __LINE__, result);
+ __builtin_abort ();
+ }
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,28 @@
+// { dg-additional-options "-std=c++11" }
+// { dg-additional-options "-O0" }
+
+#include <vector>
+
+int
+main ()
+{
+ std::vector<int> v;
+ std::vector<int> w;
+
+ for (unsigned i = 0; i <= 9; i++)
+ v.push_back (i);
+
+ int iter = 0;
+#pragma omp for
+#pragma omp tile sizes(5)
+ for (int i : v)
+ {
+ w.push_back (iter);
+ iter++;
+ }
+
+ for (int i = 0; i < w.size (); i++)
+ if (w[i] != i)
+ __builtin_abort ();
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,73 @@
+// { dg-additional-options "-std=c++11" }
+// { dg-additional-options "-O0" }
+
+#include <vector>
+#include <stdio.h>
+
+constexpr unsigned fib (unsigned n)
+{
+ return n <= 2 ? 1 : fib (n-1) + fib (n-2);
+}
+
+int
+test1 ()
+{
+ std::vector<int> v;
+
+ for (unsigned i = 0; i <= 9; i++)
+ v.push_back (1);
+
+ int sum = 0;
+ for (int k = 0; k < 10; k++)
+#pragma omp unroll partial(fib(3))
+ for (int i : v) {
+ for (int j = 8; j != -2; --j)
+ sum = sum + i;
+ }
+
+ return sum;
+}
+
+int
+test2 ()
+{
+ std::vector<int> v;
+
+ for (unsigned i = 0; i <= 10; i++)
+ v.push_back (i);
+
+ int sum = 0;
+#pragma omp parallel for reduction(+:sum)
+ for (int k = 0; k < 10; k++)
+#pragma omp unroll
+#pragma omp unroll partial(fib(4))
+ for (int i : v)
+ {
+ #pragma omp unroll full
+ for (int j = 8; j != -2; --j)
+ sum = sum + i;
+ }
+
+ return sum;
+}
+
+int
+main ()
+{
+ int result = test1 ();
+
+ if (result != 1000)
+ {
+ fprintf (stderr, "Wrong result: %d\n", result);
+ __builtin_abort ();
+ }
+
+ result = test2 ();
+ if (result != 5500)
+ {
+ fprintf (stderr, "Wrong result: %d\n", result);
+ __builtin_abort ();
+ }
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,34 @@
+// { dg-do run }
+// { dg-additional-options "-std=c++11" }
+#include <vector>
+#include <iostream>
+
+int
+main ()
+{
+ std::vector<std::vector<int>> v;
+ std::vector<int> w;
+
+ for (unsigned i = 0; i < 10; i++)
+ {
+ std::vector<int> u;
+ for (unsigned j = 0; j < 10; j++)
+ u.push_back (j);
+ v.push_back (u);
+ }
+
+#pragma omp for
+#pragma omp unroll partial(7)
+ for (auto u : v)
+ for (int x : u)
+ w.push_back (x);
+
+ std::size_t l = w.size ();
+ for (std::size_t i = 0; i < l; i++)
+ {
+ if (w[i] != i % 10)
+ __builtin_abort ();
+ }
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,84 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+template <int dim0, int dim1>
+int sum ()
+{
+ int sum = 0;
+#pragma omp unroll full
+#pragma omp tile sizes(dim0, dim1)
+ for (unsigned i = 0; i < 4; i++)
+ for (unsigned j = 0; j < 5; j++)
+ sum++;
+
+ return sum;
+}
+
+int main ()
+{
+ if (sum <1,1> () != 20)
+ __builtin_abort ();
+ if (sum <1,2> () != 20)
+ __builtin_abort ();
+ if (sum <1,3> () != 20)
+ __builtin_abort ();
+ if (sum <1,4> () != 20)
+ __builtin_abort ();
+ if (sum <1,5> () != 20)
+ __builtin_abort ();
+
+ if (sum <2,1> () != 20)
+ __builtin_abort ();
+ if (sum <2,2> () != 20)
+ __builtin_abort ();
+ if (sum <2,3> () != 20)
+ __builtin_abort ();
+ if (sum <2,4> () != 20)
+ __builtin_abort ();
+ if (sum <2,5> () != 20)
+ __builtin_abort ();
+
+ if (sum <3,1> () != 20)
+ __builtin_abort ();
+ if (sum <3,2> () != 20)
+ __builtin_abort ();
+ if (sum <3,3> () != 20)
+ __builtin_abort ();
+ if (sum <3,4> () != 20)
+ __builtin_abort ();
+ if (sum <3,5> () != 20)
+ __builtin_abort ();
+
+ if (sum <4,1> () != 20)
+ __builtin_abort ();
+ if (sum <4,2> () != 20)
+ __builtin_abort ();
+ if (sum <4,3> () != 20)
+ __builtin_abort ();
+ if (sum <4,4> () != 20)
+ __builtin_abort ();
+ if (sum <4,5> () != 20)
+ __builtin_abort ();
+
+ if (sum <5,1> () != 20)
+ __builtin_abort ();
+ if (sum <5,2> () != 20)
+ __builtin_abort ();
+ if (sum <5,3> () != 20)
+ __builtin_abort ();
+ if (sum <5,4> () != 20)
+ __builtin_abort ();
+ if (sum <5,5> () != 20)
+ __builtin_abort ();
+
+ if (sum <6,1> () != 20)
+ __builtin_abort ();
+ if (sum <6,2> () != 20)
+ __builtin_abort ();
+ if (sum <6,3> () != 20)
+ __builtin_abort ();
+ if (sum <6,4> () != 20)
+ __builtin_abort ();
+ if (sum <6,5> () != 20)
+ __builtin_abort ();
+}
new file mode 100644
@@ -0,0 +1,79 @@
+/* { dg-do run } */
+
+/* Like imperfect1.c, but also includes loop transforms. */
+
+static int f1count[3], f2count[3];
+
+#ifndef __cplusplus
+extern void abort (void);
+#else
+extern "C" void abort (void);
+#endif
+
+int f1 (int depth, int iter)
+{
+ f1count[depth]++;
+ return iter;
+}
+
+int f2 (int depth, int iter)
+{
+ f2count[depth]++;
+ return iter;
+}
+
+void s1 (int a1, int a2, int a3)
+{
+ int i, j, k;
+
+#pragma omp for collapse(2)
+ for (i = 0; i < a1; i++)
+ {
+ f1 (0, i);
+ for (j = 0; j < a2; j++)
+ {
+ f1 (1, j);
+#pragma omp unroll partial
+ for (k = 0; k < a3; k++)
+ {
+ f1 (2, k);
+ f2 (2, k);
+ }
+ f2 (1, j);
+ }
+ f2 (0, i);
+ }
+}
+
+int
+main (void)
+{
+ f1count[0] = 0;
+ f1count[1] = 0;
+ f1count[2] = 0;
+ f2count[0] = 0;
+ f2count[1] = 0;
+ f2count[2] = 0;
+
+ s1 (3, 4, 5);
+
+ /* All intervening code at the same depth must be executed the same
+ number of times. */
+ if (f1count[0] != f2count[0]) abort ();
+ if (f1count[1] != f2count[1]) abort ();
+ if (f1count[2] != f2count[2]) abort ();
+
+ /* Intervening code must be executed at least as many times as the loop
+ that encloses it. */
+ if (f1count[0] < 3) abort ();
+ if (f1count[1] < 3 * 4) abort ();
+
+ /* Intervening code must not be executed more times than the number
+ of logical iterations. */
+ if (f1count[0] > 3 * 4 * 5) abort ();
+ if (f1count[1] > 3 * 4 * 5) abort ();
+
+ /* Check that the innermost loop body is executed exactly the number
+ of logical iterations expected. */
+ if (f1count[2] != 3 * 4 * 5) abort ();
+}
new file mode 100644
@@ -0,0 +1,79 @@
+/* { dg-do run } */
+
+/* Like imperfect1.c, but also includes loop transforms. */
+
+static int f1count[3], f2count[3];
+
+#ifndef __cplusplus
+extern void abort (void);
+#else
+extern "C" void abort (void);
+#endif
+
+int f1 (int depth, int iter)
+{
+ f1count[depth]++;
+ return iter;
+}
+
+int f2 (int depth, int iter)
+{
+ f2count[depth]++;
+ return iter;
+}
+
+void s1 (int a1, int a2, int a3)
+{
+ int i, j, k;
+
+#pragma omp for collapse(2)
+ for (i = 0; i < a1; i++)
+ {
+ f1 (0, i);
+ for (j = 0; j < a2; j++)
+ {
+ f1 (1, j);
+#pragma omp tile sizes(5)
+ for (k = 0; k < a3; k++)
+ {
+ f1 (2, k);
+ f2 (2, k);
+ }
+ f2 (1, j);
+ }
+ f2 (0, i);
+ }
+}
+
+int
+main (void)
+{
+ f1count[0] = 0;
+ f1count[1] = 0;
+ f1count[2] = 0;
+ f2count[0] = 0;
+ f2count[1] = 0;
+ f2count[2] = 0;
+
+ s1 (3, 4, 5);
+
+ /* All intervening code at the same depth must be executed the same
+ number of times. */
+ if (f1count[0] != f2count[0]) abort ();
+ if (f1count[1] != f2count[1]) abort ();
+ if (f1count[2] != f2count[2]) abort ();
+
+ /* Intervening code must be executed at least as many times as the loop
+ that encloses it. */
+ if (f1count[0] < 3) abort ();
+ if (f1count[1] < 3 * 4) abort ();
+
+ /* Intervening code must not be executed more times than the number
+ of logical iterations. */
+ if (f1count[0] > 3 * 4 * 5) abort ();
+ if (f1count[1] > 3 * 4 * 5) abort ();
+
+ /* Check that the innermost loop body is executed exactly the number
+ of logical iterations expected. */
+ if (f1count[2] != 3 * 4 * 5) abort ();
+}
new file mode 100644
@@ -0,0 +1,70 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+
+#ifndef FUN_NAME_SUFFIX
+#define FUN_NAME_SUFFIX
+#endif
+
+#ifdef MULT
+#undef MULT
+#endif
+#define MULT CAT(mult, FUN_NAME_SUFFIX)
+
+#ifdef MAIN
+#undef MAIN
+#endif
+#define MAIN CAT(main, FUN_NAME_SUFFIX)
+
+void MULT (float *matrix1, float *matrix2, float *result,
+ unsigned dim0, unsigned dim1)
+{
+ unsigned i;
+
+ memset (result, 0, sizeof (float) * dim0 * dim1);
+ DIRECTIVE
+ TRANSFORMATION1
+ for (i = 0; i < dim0; i++)
+ TRANSFORMATION2
+ for (unsigned j = 0; j < dim1; j++)
+ TRANSFORMATION3
+ for (unsigned k = 0; k < dim1; k++)
+ result[i * dim1 + j] += matrix1[i * dim1 + k] * matrix2[k * dim0 + j];
+}
+
+int MAIN ()
+{
+ unsigned dim0 = 20;
+ unsigned dim1 = 20;
+
+ float *result = (float *)malloc (sizeof (float) * dim0 * dim1);
+ float *matrix1 = (float *)malloc (sizeof (float) * dim0 * dim1);
+ float *matrix2 = (float *)malloc (sizeof (float) * dim0 * dim1);
+
+ for (unsigned i = 0; i < dim0; i++)
+ for (unsigned j = 0; j < dim1; j++)
+ matrix1[i * dim1 + j] = j;
+
+ for (unsigned i = 0; i < dim0; i++)
+ for (unsigned j = 0; j < dim1; j++)
+ if (i == j)
+ matrix2[i * dim1 + j] = 1;
+ else
+ matrix2[i * dim1 + j] = 0;
+
+ MULT (matrix1, matrix2, result, dim0, dim1);
+
+ for (unsigned i = 0; i < dim0; i++)
+ for (unsigned j = 0; j < dim1; j++) {
+ if (matrix1[i * dim1 + j] != result[i * dim1 + j]) {
+ print_matrix (matrix1, dim0, dim1);
+ print_matrix (matrix2, dim0, dim1);
+ print_matrix (result, dim0, dim1);
+ fprintf(stderr, "%s: ERROR at %d, %d\n", __FUNCTION__, i, j);
+ abort();
+ }
+ }
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,71 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+
+#ifndef FUN_NAME_SUFFIX
+#define FUN_NAME_SUFFIX
+#endif
+
+#ifdef MULT
+#undef MULT
+#endif
+#define MULT CAT(mult, FUN_NAME_SUFFIX)
+
+#ifdef MAIN
+#undef MAIN
+#endif
+#define MAIN CAT(main, FUN_NAME_SUFFIX)
+
+void MULT (float *matrix1, float *matrix2, float *result)
+{
+ const unsigned dim0 = 20;
+ const unsigned dim1 = 20;
+
+ memset (result, 0, sizeof (float) * dim0 * dim1);
+ DIRECTIVE
+ TRANSFORMATION1
+ for (unsigned i = 0; i < dim0; i++)
+ TRANSFORMATION2
+ for (unsigned j = 0; j < dim1; j++)
+ TRANSFORMATION3
+ for (unsigned k = 0; k < dim1; k++)
+ result[i * dim1 + j] += matrix1[i * dim1 + k] * matrix2[k * dim0 + j];
+}
+
+int MAIN ()
+{
+ const unsigned dim0 = 20;
+ const unsigned dim1 = 20;
+
+ float *result = (float *)malloc (sizeof (float) * dim0 * dim1);
+ float *matrix1 = (float *)malloc (sizeof (float) * dim0 * dim1);
+ float *matrix2 = (float *)malloc (sizeof (float) * dim0 * dim1);
+
+ for (unsigned i = 0; i < dim0; i++)
+ for (unsigned j = 0; j < dim1; j++)
+ matrix1[i * dim1 + j] = j;
+
+ for (unsigned i = 0; i < dim0; i++)
+ for (unsigned j = 0; j < dim1; j++)
+ if (i == j)
+ matrix2[i * dim1 + j] = 1;
+ else
+ matrix2[i * dim1 + j] = 0;
+
+ MULT (matrix1, matrix2, result);
+
+ for (unsigned i = 0; i < dim0; i++)
+ for (unsigned j = 0; j < dim1; j++) {
+ if (matrix1[i * dim1 + j] != result[i * dim1 + j]) {
+ __builtin_printf("%s: error at %d, %d\n", __FUNCTION__, i, j);
+ print_matrix (matrix1, dim0, dim1);
+ print_matrix (matrix2, dim0, dim1);
+ print_matrix (result, dim0, dim1);
+ __builtin_printf("\n");
+ __builtin_abort();
+ }
+ }
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,19 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#define CAT(x,y) XCAT(x,y)
+#define XCAT(x,y) x ## y
+#define DO_PRAGMA(x) XDO_PRAGMA(x)
+#define XDO_PRAGMA(x) _Pragma (#x)
+
+
+void print_matrix (float *matrix, unsigned dim0, unsigned dim1)
+{
+ for (unsigned i = 0; i < dim0; i++)
+ {
+ for (unsigned j = 0; j < dim1; j++)
+ fprintf (stderr, "%f ", matrix[i * dim1 + j]);
+ fprintf (stderr, "\n");
+ }
+ fprintf (stderr, "\n");
+}
new file mode 100644
@@ -0,0 +1,11 @@
+/* { dg-additional-options { -fdump-tree-original -Wall -Wno-unknown-pragmas } } */
+
+#define COMMON_DIRECTIVE
+#define COLLAPSE_1 collapse(1)
+#define COLLAPSE_2 collapse(2)
+#define COLLAPSE_3 collapse(3)
+
+#include "matrix-transform-variants-1.h"
+
+/* A consistency check to prevent broken macro usage. */
+/* { dg-final { scan-tree-dump-times "unroll_partial" 12 "original" } } */
new file mode 100644
@@ -0,0 +1,13 @@
+/* { dg-additional-options { -O2 -fdump-tree-original -Wall -Wno-unknown-pragmas } } */
+
+#define COMMON_DIRECTIVE
+#define COMMON_TOP_TRANSFORM omp unroll full
+#define COLLAPSE_1
+#define COLLAPSE_2
+#define COLLAPSE_3
+#define IMPLEMENTATION_FILE "matrix-constant-iter.h"
+
+#include "matrix-transform-variants-1.h"
+
+/* A consistency check to prevent broken macro usage. */
+/* { dg-final { scan-tree-dump-times "unroll_full" 13 "original" } } */
new file mode 100644
@@ -0,0 +1,8 @@
+/* { dg-additional-options { -Wall -Wno-unknown-pragmas } } */
+
+#define COMMON_DIRECTIVE "omp teams distribute parallel for"
+#define COLLAPSE_1 "collapse(1)"
+#define COLLAPSE_2 "collapse(2)"
+#define COLLAPSE_3 "collapse(3)"
+
+#include "matrix-transform-variants-1.h"
new file mode 100644
@@ -0,0 +1,13 @@
+/* { dg-additional-options { -fdump-tree-original -Wall -Wno-unknown-pragmas } } */
+
+#define COMMON_DIRECTIVE omp for
+#define COLLAPSE_1 collapse(1)
+#define COLLAPSE_2 collapse(2)
+#define COLLAPSE_3 collapse(3)
+
+#include "matrix-transform-variants-1.h"
+
+
+/* A consistency check to prevent broken macro usage. */
+/* { dg-final { scan-tree-dump-times "omp for" 13 "original" } } */
+/* { dg-final { scan-tree-dump-times "collapse" 12 "original" } } */
new file mode 100644
@@ -0,0 +1,13 @@
+/* { dg-additional-options { -fdump-tree-original -Wall -Wno-unknown-pragmas } } */
+
+#define COMMON_DIRECTIVE omp parallel for
+#define COLLAPSE_1 collapse(1)
+#define COLLAPSE_2 collapse(2)
+#define COLLAPSE_3
+
+#include "matrix-transform-variants-1.h"
+
+
+/* A consistency check to prevent broken macro usage. */
+/* { dg-final { scan-tree-dump-times "omp parallel" 13 "original" } } */
+/* { dg-final { scan-tree-dump-times "collapse" 9 "original" } } */
new file mode 100644
@@ -0,0 +1,8 @@
+/* { dg-additional-options { -Wall -Wno-unknown-pragmas } } */
+
+#define COMMON_DIRECTIVE omp parallel masked taskloop
+#define COLLAPSE_1 collapse(1)
+#define COLLAPSE_2 collapse(2)
+#define COLLAPSE_3
+
+#include "matrix-transform-variants-1.h"
new file mode 100644
@@ -0,0 +1,8 @@
+/* { dg-additional-options { -Wall -Wno-unknown-pragmas } } */
+
+#define COMMON_DIRECTIVE omp parallel masked taskloop simd
+#define COLLAPSE_1 collapse(1)
+#define COLLAPSE_2 collapse(2)
+#define COLLAPSE_3
+
+#include "matrix-transform-variants-1.h"
new file mode 100644
@@ -0,0 +1,15 @@
+/* This test appears to have too much parallelism to run without a GPU. */
+/* { dg-do run { target { offload_device } } } */
+/* { dg-additional-options { -fdump-tree-original -Wall -Wno-unknown-pragmas } } */
+
+#define COMMON_DIRECTIVE omp target parallel for map(tofrom:result[0:dim0*dim1]) map(to:matrix1[0:dim0*dim1], matrix2[0:dim0*dim1])
+#define COLLAPSE_1 collapse(1)
+#define COLLAPSE_2 collapse(2)
+#define COLLAPSE_3
+
+#include "matrix-transform-variants-1.h"
+
+/* A consistency check to prevent broken macro usage. */
+/* { dg-final { scan-tree-dump-times "omp target" 13 "original" } } */
+/* { dg-final { scan-tree-dump-times "collapse" 9 "original" } } */
+/* { dg-final { scan-tree-dump-times "unroll_partial" 12 "original" } } */
new file mode 100644
@@ -0,0 +1,10 @@
+/* This test appears to have too much parallelism to run without a GPU. */
+/* { dg-do run { target { offload_device } } } */
+/* { dg-additional-options { -Wall -Wno-unknown-pragmas } } */
+
+#define COMMON_DIRECTIVE omp target teams distribute parallel for map(tofrom:result[:dim0*dim1]) map(to:matrix1[0:dim0*dim1], matrix2[0:dim0*dim1])
+#define COLLAPSE_1 collapse(1)
+#define COLLAPSE_2 collapse(2)
+#define COLLAPSE_3
+
+#include "matrix-transform-variants-1.h"
new file mode 100644
@@ -0,0 +1,8 @@
+/* { dg-additional-options { -Wall -Wno-unknown-pragmas } } */
+
+#define COMMON_DIRECTIVE omp taskloop
+#define COLLAPSE_1 collapse(1)
+#define COLLAPSE_2 collapse(2)
+#define COLLAPSE_3 collapse(3)
+
+#include "matrix-transform-variants-1.h"
new file mode 100644
@@ -0,0 +1,8 @@
+/* { dg-additional-options { -Wall -Wno-unknown-pragmas } } */
+
+#define COMMON_DIRECTIVE omp teams distribute parallel for
+#define COLLAPSE_1 collapse(1)
+#define COLLAPSE_2 collapse(2)
+#define COLLAPSE_3
+
+#include "matrix-transform-variants-1.h"
new file mode 100644
@@ -0,0 +1,8 @@
+/* { dg-additional-options { -Wall -Wno-unknown-pragmas } } */
+
+#define COMMON_DIRECTIVE omp simd
+#define COLLAPSE_1 collapse(1)
+#define COLLAPSE_2 collapse(2)
+#define COLLAPSE_3 collapse(3)
+
+#include "matrix-transform-variants-1.h"
new file mode 100644
@@ -0,0 +1,191 @@
+#include "matrix-helper.h"
+
+#ifndef COMMON_TOP_TRANSFORM
+#define COMMON_TOP_TRANSFORM
+#endif
+
+#ifndef IMPLEMENTATION_FILE
+#define IMPLEMENTATION_FILE "matrix-1.h"
+#endif
+
+#define FUN_NAME_SUFFIX 1
+#define DIRECTIVE DO_PRAGMA(COMMON_DIRECTIVE)
+#define TRANSFORMATION1 DO_PRAGMA(COMMON_TOP_TRANSFORM) _Pragma("omp unroll partial(2)") _Pragma("omp tile sizes(10)")
+#define TRANSFORMATION2
+#define TRANSFORMATION3
+#include IMPLEMENTATION_FILE
+
+#undef DIRECTIVE
+#undef TRANSFORMATION1
+#undef TRANSFORMATION2
+#undef TRANSFORMATION3
+#undef FUN_NAME_SUFFIX
+
+#define FUN_NAME_SUFFIX 2
+#define DIRECTIVE DO_PRAGMA(COMMON_DIRECTIVE COLLAPSE_3)
+#define TRANSFORMATION1 DO_PRAGMA(COMMON_TOP_TRANSFORM) _Pragma("omp tile sizes(8,16,4)")
+#define TRANSFORMATION2
+#define TRANSFORMATION3
+#include IMPLEMENTATION_FILE
+
+#undef DIRECTIVE
+#undef TRANSFORMATION1
+#undef TRANSFORMATION2
+#undef TRANSFORMATION3
+#undef FUN_NAME_SUFFIX
+
+#define FUN_NAME_SUFFIX 3
+#define DIRECTIVE DO_PRAGMA(COMMON_DIRECTIVE COLLAPSE_2)
+#define TRANSFORMATION1 DO_PRAGMA(COMMON_TOP_TRANSFORM) _Pragma("omp tile sizes(8, 8)")
+#define TRANSFORMATION2
+#define TRANSFORMATION3
+#include IMPLEMENTATION_FILE
+
+#undef DIRECTIVE
+#undef TRANSFORMATION1
+#undef TRANSFORMATION2
+#undef TRANSFORMATION3
+#undef FUN_NAME_SUFFIX
+
+#define FUN_NAME_SUFFIX 4
+#define DIRECTIVE DO_PRAGMA(COMMON_DIRECTIVE COLLAPSE_1)
+#define TRANSFORMATION1 DO_PRAGMA(COMMON_TOP_TRANSFORM) _Pragma("omp tile sizes(8, 8)")
+#define TRANSFORMATION2
+#define TRANSFORMATION3
+#include IMPLEMENTATION_FILE
+
+#undef DIRECTIVE
+#undef TRANSFORMATION1
+#undef TRANSFORMATION2
+#undef TRANSFORMATION3
+#undef FUN_NAME_SUFFIX
+
+#define FUN_NAME_SUFFIX 5
+#define DIRECTIVE DO_PRAGMA(COMMON_DIRECTIVE COLLAPSE_1)
+#define TRANSFORMATION1 DO_PRAGMA(COMMON_TOP_TRANSFORM) _Pragma("omp tile sizes(8, 8, 8)")
+#define TRANSFORMATION2
+#define TRANSFORMATION3
+#include IMPLEMENTATION_FILE
+
+#undef DIRECTIVE
+#undef TRANSFORMATION1
+#undef TRANSFORMATION2
+#undef TRANSFORMATION3
+#undef FUN_NAME_SUFFIX
+
+#define FUN_NAME_SUFFIX 6
+#define DIRECTIVE DO_PRAGMA(COMMON_DIRECTIVE COLLAPSE_1)
+#define TRANSFORMATION1 DO_PRAGMA(COMMON_TOP_TRANSFORM) _Pragma("omp tile sizes(10)") _Pragma("omp unroll partial(2)")
+#define TRANSFORMATION2
+#define TRANSFORMATION3
+#include IMPLEMENTATION_FILE
+
+#undef DIRECTIVE
+#undef TRANSFORMATION1
+#undef TRANSFORMATION2
+#undef TRANSFORMATION3
+#undef FUN_NAME_SUFFIX
+
+#define FUN_NAME_SUFFIX 7
+#define DIRECTIVE DO_PRAGMA(COMMON_DIRECTIVE COLLAPSE_2)
+#define TRANSFORMATION1 DO_PRAGMA(COMMON_TOP_TRANSFORM) _Pragma("omp tile sizes(7, 11)")
+#define TRANSFORMATION2 _Pragma("omp unroll partial(7)")
+#define TRANSFORMATION3
+#include IMPLEMENTATION_FILE
+
+#undef DIRECTIVE
+#undef TRANSFORMATION1
+#undef TRANSFORMATION2
+#undef TRANSFORMATION3
+#undef FUN_NAME_SUFFIX
+
+#define FUN_NAME_SUFFIX 8
+#define DIRECTIVE DO_PRAGMA(COMMON_DIRECTIVE COLLAPSE_2)
+#define TRANSFORMATION1 DO_PRAGMA(COMMON_TOP_TRANSFORM) _Pragma("omp tile sizes(7, 11)")
+#define TRANSFORMATION2 _Pragma("omp tile sizes(7)") _Pragma("omp unroll partial(7)")
+#define TRANSFORMATION3
+#include IMPLEMENTATION_FILE
+
+#undef DIRECTIVE
+#undef TRANSFORMATION1
+#undef TRANSFORMATION2
+#undef TRANSFORMATION3
+#undef FUN_NAME_SUFFIX
+
+#define FUN_NAME_SUFFIX 9
+#define DIRECTIVE DO_PRAGMA(COMMON_DIRECTIVE COLLAPSE_2)
+#define TRANSFORMATION1 DO_PRAGMA(COMMON_TOP_TRANSFORM) _Pragma("omp tile sizes(7, 11)")
+#define TRANSFORMATION2 _Pragma("omp tile sizes(7)") _Pragma("omp unroll partial(3)") _Pragma("omp tile sizes(7)")
+#define TRANSFORMATION3
+#include IMPLEMENTATION_FILE
+
+#undef DIRECTIVE
+#undef TRANSFORMATION1
+#undef TRANSFORMATION2
+#undef TRANSFORMATION3
+#undef FUN_NAME_SUFFIX
+
+#define FUN_NAME_SUFFIX 10
+#define DIRECTIVE DO_PRAGMA(COMMON_DIRECTIVE COLLAPSE_1)
+#define TRANSFORMATION1 DO_PRAGMA(COMMON_TOP_TRANSFORM) _Pragma("omp unroll partial(5)") _Pragma("omp tile sizes(7)") _Pragma("omp unroll partial(3)") _Pragma("omp tile sizes(7)")
+#define TRANSFORMATION2
+#define TRANSFORMATION3
+#include IMPLEMENTATION_FILE
+
+#undef DIRECTIVE
+#undef TRANSFORMATION1
+#undef TRANSFORMATION2
+#undef TRANSFORMATION3
+#undef FUN_NAME_SUFFIX
+
+#define FUN_NAME_SUFFIX 11
+#define DIRECTIVE DO_PRAGMA(COMMON_DIRECTIVE COLLAPSE_2)
+#define TRANSFORMATION1 DO_PRAGMA(COMMON_TOP_TRANSFORM)
+#define TRANSFORMATION2 _Pragma("omp unroll partial(5)") _Pragma("omp tile sizes(7)") _Pragma("omp unroll partial(3)") _Pragma("omp tile sizes(7)")
+#define TRANSFORMATION3
+#include IMPLEMENTATION_FILE
+
+#undef DIRECTIVE
+#undef TRANSFORMATION1
+#undef TRANSFORMATION2
+#undef TRANSFORMATION3
+#undef FUN_NAME_SUFFIX
+
+#define FUN_NAME_SUFFIX 12
+#define DIRECTIVE DO_PRAGMA(COMMON_DIRECTIVE COLLAPSE_3)
+#define TRANSFORMATION1 DO_PRAGMA(COMMON_TOP_TRANSFORM)
+#define TRANSFORMATION2
+#define TRANSFORMATION3 _Pragma("omp unroll partial(5)") _Pragma("omp tile sizes(7)") _Pragma("omp unroll partial(3)") _Pragma("omp tile sizes(7)")
+#include IMPLEMENTATION_FILE
+
+#undef DIRECTIVE
+#undef TRANSFORMATION1
+#undef TRANSFORMATION2
+#undef TRANSFORMATION3
+#undef FUN_NAME_SUFFIX
+
+#define FUN_NAME_SUFFIX 13
+#define DIRECTIVE DO_PRAGMA(COMMON_DIRECTIVE COLLAPSE_3)
+#define TRANSFORMATION1 DO_PRAGMA(COMMON_TOP_TRANSFORM)
+#define TRANSFORMATION2 _Pragma("omp tile sizes(7,8)")
+#define TRANSFORMATION3 _Pragma("omp unroll partial(3)") _Pragma("omp tile sizes(7)")
+#include IMPLEMENTATION_FILE
+
+int main ()
+{
+ main1 ();
+ main2 ();
+ main3 ();
+ main4 ();
+ main5 ();
+ main6 ();
+ main7 ();
+ main8 ();
+ main9 ();
+ main10 ();
+ main11 ();
+ main12 ();
+ main13 ();
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,78 @@
+/* { dg-additional-options { -Wall -Wno-unknown-pragmas } } */
+
+#include <stdio.h>
+
+int compute_sum1 ()
+{
+ int sum = 0;
+ int i,j;
+#pragma omp parallel for reduction(+:sum) lastprivate(j)
+#pragma omp unroll partial
+ for (i = 3; i < 10; ++i)
+ for (j = -2; j < 7; ++j)
+ sum++;
+
+ if (j != 7)
+ __builtin_abort ();
+
+ return sum;
+}
+
+int compute_sum2()
+{
+ int sum = 0;
+ int i,j;
+#pragma omp parallel for reduction(+:sum) lastprivate(j)
+#pragma omp unroll partial(5)
+ for (i = 3; i < 10; ++i)
+ for (j = -2; j < 7; ++j)
+ sum++;
+
+ if (j != 7)
+ __builtin_abort ();
+
+ return sum;
+}
+
+int compute_sum3()
+{
+ int sum = 0;
+ int i,j;
+#pragma omp parallel for reduction(+:sum)
+#pragma omp unroll partial(1)
+ for (i = 3; i < 10; ++i)
+ for (j = -2; j < 7; ++j)
+ sum++;
+
+ if (j != 7)
+ __builtin_abort ();
+
+ return sum;
+}
+
+int main ()
+{
+ int result;
+ result = compute_sum1 ();
+ if (result != 7 * 9)
+ {
+ fprintf (stderr, "%d: Wrong result %d\n", __LINE__, result);
+ __builtin_abort ();
+ }
+
+ result = compute_sum2 ();
+ if (result != 7 * 9)
+ {
+ fprintf (stderr, "%d: Wrong result %d\n", __LINE__, result);
+ __builtin_abort ();
+ }
+
+ result = compute_sum3 ();
+ if (result != 7 * 9)
+ {
+ fprintf (stderr, "%d: Wrong result %d\n", __LINE__, result);
+ __builtin_abort ();
+ }
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,131 @@
+/* { dg-additional-options { -Wall -Wno-unknown-pragmas } } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+void test1 ()
+{
+ int sum = 0;
+ for (int i = -3; i != 1; ++i)
+ for (int j = -2; j < i * -1; ++j)
+ sum++;
+
+ if (sum != 14)
+ {
+ fprintf (stderr, "%s: Wrong sum: %d\n", __FUNCTION__, sum);
+ abort ();
+ }
+}
+
+void test2 ()
+{
+ int sum = 0;
+ #pragma omp unroll partial
+ for (int i = -3; i != 1; ++i)
+ for (int j = -2; j < i * -1; ++j)
+ sum++;
+
+ if (sum != 14)
+ {
+ fprintf (stderr, "%s: Wrong sum: %d\n", __FUNCTION__, sum);
+ abort ();
+ }
+}
+
+void test3 ()
+{
+ int sum = 0;
+ #pragma omp unroll partial
+ for (int i = -3; i != 1; ++i)
+ #pragma omp unroll partial
+ for (int j = -2; j < i * -1; ++j)
+ sum++;
+
+ if (sum != 14)
+ {
+ fprintf (stderr, "%s: Wrong sum: %d\n", __FUNCTION__, sum);
+ abort ();
+ }
+}
+
+void test4 ()
+{
+ int sum = 0;
+#pragma omp for
+#pragma omp unroll partial(5)
+ for (int i = -3; i != 1; ++i)
+#pragma omp unroll partial(2)
+ for (int j = -2; j < i * -1; ++j)
+ sum++;
+
+ if (sum != 14)
+ {
+ fprintf (stderr, "%s: Wrong sum: %d\n", __FUNCTION__, sum);
+ abort ();
+ }
+}
+
+void test5 ()
+{
+ int sum = 0;
+#pragma omp parallel for reduction(+:sum)
+#pragma omp unroll partial(2)
+ for (int i = -3; i != 1; ++i)
+#pragma omp unroll partial(2)
+ for (int j = -2; j < i * -1; ++j)
+ sum++;
+
+ if (sum != 14)
+ {
+ fprintf (stderr, "%s: Wrong sum: %d\n", __FUNCTION__, sum);
+ abort ();
+ }
+}
+
+void test6 ()
+{
+ int sum = 0;
+#pragma omp target parallel for reduction(+:sum)
+#pragma omp unroll partial(7)
+ for (int i = -3; i != 1; ++i)
+#pragma omp unroll partial(2)
+ for (int j = -2; j < i * -1; ++j)
+ sum++;
+
+ if (sum != 14)
+ {
+ fprintf (stderr, "%s: Wrong sum: %d\n", __FUNCTION__, sum);
+ abort ();
+ }
+}
+
+void test7 ()
+{
+ int sum = 0;
+#pragma omp target teams distribute parallel for reduction(+:sum)
+#pragma omp unroll partial(7)
+ for (int i = -3; i != 1; ++i)
+#pragma omp unroll partial(2)
+ for (int j = -2; j < i * -1; ++j)
+ sum++;
+
+ if (sum != 14)
+ {
+ fprintf (stderr, "%s: Wrong sum: %d\n", __FUNCTION__, sum);
+ abort ();
+ }
+}
+
+int
+main ()
+{
+ test1 ();
+ test2 ();
+ test3 ();
+ test4 ();
+ test5 ();
+ test6 ();
+ test7 ();
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,82 @@
+/* { dg-do run } */
+
+/* Like imperfect-transform.c, but enables offloading. */
+
+static int f1count[3], f2count[3];
+#pragma omp declare target enter (f1count, f2count)
+
+#ifndef __cplusplus
+extern void abort (void);
+#else
+extern "C" void abort (void);
+#endif
+
+int f1 (int depth, int iter)
+{
+ #pragma omp atomic
+ f1count[depth]++;
+ return iter;
+}
+
+int f2 (int depth, int iter)
+{
+ #pragma omp atomic
+ f2count[depth]++;
+ return iter;
+}
+
+void s1 (int a1, int a2, int a3)
+{
+ int i, j, k;
+
+#pragma omp target parallel for collapse(2) map(always, tofrom:f1count, f2count)
+ for (i = 0; i < a1; i++)
+ {
+ f1 (0, i);
+ for (j = 0; j < a2; j++)
+ {
+ f1 (1, j);
+#pragma omp unroll partial
+ for (k = 0; k < a3; k++)
+ {
+ f1 (2, k);
+ f2 (2, k);
+ }
+ f2 (1, j);
+ }
+ f2 (0, i);
+ }
+}
+
+int
+main (void)
+{
+ f1count[0] = 0;
+ f1count[1] = 0;
+ f1count[2] = 0;
+ f2count[0] = 0;
+ f2count[1] = 0;
+ f2count[2] = 0;
+
+ s1 (3, 4, 5);
+
+ /* All intervening code at the same depth must be executed the same
+ number of times. */
+ if (f1count[0] != f2count[0]) abort ();
+ if (f1count[1] != f2count[1]) abort ();
+ if (f1count[2] != f2count[2]) abort ();
+
+ /* Intervening code must be executed at least as many times as the loop
+ that encloses it. */
+ if (f1count[0] < 3) abort ();
+ if (f1count[1] < 3 * 4) abort ();
+
+ /* Intervening code must not be executed more times than the number
+ of logical iterations. */
+ if (f1count[0] > 3 * 4 * 5) abort ();
+ if (f1count[1] > 3 * 4 * 5) abort ();
+
+ /* Check that the innermost loop body is executed exactly the number
+ of logical iterations expected. */
+ if (f1count[2] != 3 * 4 * 5) abort ();
+}
new file mode 100644
@@ -0,0 +1,82 @@
+/* { dg-do run } */
+
+/* Like imperfect-transform.c, but enables offloading. */
+
+static int f1count[3], f2count[3];
+#pragma omp declare target enter (f1count, f2count)
+
+#ifndef __cplusplus
+extern void abort (void);
+#else
+extern "C" void abort (void);
+#endif
+
+int f1 (int depth, int iter)
+{
+ #pragma omp atomic
+ f1count[depth]++;
+ return iter;
+}
+
+int f2 (int depth, int iter)
+{
+ #pragma omp atomic
+ f2count[depth]++;
+ return iter;
+}
+
+void s1 (int a1, int a2, int a3)
+{
+ int i, j, k;
+
+#pragma omp target parallel for collapse(2) map(always, tofrom:f1count, f2count)
+ for (i = 0; i < a1; i++)
+ {
+ f1 (0, i);
+ for (j = 0; j < a2; j++)
+ {
+ f1 (1, j);
+#pragma omp tile sizes(5)
+ for (k = 0; k < a3; k++)
+ {
+ f1 (2, k);
+ f2 (2, k);
+ }
+ f2 (1, j);
+ }
+ f2 (0, i);
+ }
+}
+
+int
+main (void)
+{
+ f1count[0] = 0;
+ f1count[1] = 0;
+ f1count[2] = 0;
+ f2count[0] = 0;
+ f2count[1] = 0;
+ f2count[2] = 0;
+
+ s1 (3, 4, 5);
+
+ /* All intervening code at the same depth must be executed the same
+ number of times. */
+ if (f1count[0] != f2count[0]) abort ();
+ if (f1count[1] != f2count[1]) abort ();
+ if (f1count[2] != f2count[2]) abort ();
+
+ /* Intervening code must be executed at least as many times as the loop
+ that encloses it. */
+ if (f1count[0] < 3) abort ();
+ if (f1count[1] < 3 * 4) abort ();
+
+ /* Intervening code must not be executed more times than the number
+ of logical iterations. */
+ if (f1count[0] > 3 * 4 * 5) abort ();
+ if (f1count[1] > 3 * 4 * 5) abort ();
+
+ /* Check that the innermost loop body is executed exactly the number
+ of logical iterations expected. */
+ if (f1count[2] != 3 * 4 * 5) abort ();
+}