@@ -506,6 +506,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;
@@ -3212,9 +3212,9 @@ const struct c_omp_directive c_omp_directives[] = {
{ "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
@@ -1593,6 +1593,7 @@ static const struct omp_pragma_def omp_pragmas_simd[] = {
{ "target", PRAGMA_OMP_TARGET },
{ "taskloop", PRAGMA_OMP_TASKLOOP },
{ "teams", PRAGMA_OMP_TEAMS },
+ { "unroll", PRAGMA_OMP_UNROLL },
};
void
@@ -81,8 +81,9 @@ enum pragma_kind {
PRAGMA_OMP_TASKYIELD,
PRAGMA_OMP_THREADPRIVATE,
PRAGMA_OMP_TEAMS,
+ 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,
@@ -118,6 +119,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,
@@ -140,6 +142,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,
@@ -13471,6 +13471,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))
@@ -13545,6 +13547,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
@@ -13639,12 +13643,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
@@ -17448,6 +17455,65 @@ 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_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_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 ) */
@@ -18042,6 +18108,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 %<#pragma omp%> clause");
goto saw_error;
@@ -20169,6 +20243,8 @@ c_parser_omp_scan_loop_body (c_parser *parser, bool open_brace_parsed)
"expected %<}%>");
}
+static bool c_parser_nested_omp_unroll_clauses (c_parser *, tree &);
+
/* Parse the restricted form of loop statements allowed by OpenACC and OpenMP.
The real trick here is to determine the loop control variable early
so that we can push a new decl if necessary to make it private.
@@ -20227,6 +20303,13 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
condv = make_tree_vec (count);
incrv = make_tree_vec (count);
+ if (c_parser_nested_omp_unroll_clauses (parser, clauses)
+ && count > 1)
+ {
+ error_at (loc, "collapse cannot be larger than 1 on an unrolled loop");
+ return NULL;
+ }
+
if (!c_parser_next_token_is_keyword (parser, RID_FOR))
{
c_parser_error (parser, "for statement expected");
@@ -23858,6 +23941,76 @@ 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) )
+
+/* Parse zero or more '#pragma omp unroll' that follow
+ another directive that requires a canonical loop nest. */
+
+static bool
+c_parser_nested_omp_unroll_clauses (c_parser *parser, tree &clauses)
+{
+ static const char *p_name = "#pragma omp unroll";
+ c_token *tok;
+ bool found_unroll = false;
+ while (c_parser_next_token_is (parser, CPP_PRAGMA)
+ && (tok = c_parser_peek_token (parser),
+ tok->pragma_kind == PRAGMA_OMP_UNROLL))
+ {
+ c_parser_consume_pragma (parser);
+ tree c = c_parser_omp_all_clauses (parser, OMP_UNROLL_CLAUSE_MASK,
+ p_name, true);
+ if (c)
+ {
+ gcc_assert (!TREE_CHAIN (c));
+ found_unroll = true;
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_UNROLL_FULL)
+ {
+ error_at (tok->location, "%<full%> clause is invalid here; "
+ "turns loop into non-loop");
+ continue;
+ }
+ }
+ else
+ {
+ error_at (tok->location, "%<#pragma omp unroll%> without "
+ "%<partial%> clause is invalid here; "
+ "turns loop into non-loop");
+ continue;
+ }
+
+ clauses = chainon (clauses, c);
+ }
+
+ return found_unroll;
+}
+
+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);
+ c_parser_nested_omp_unroll_clauses (parser, clauses);
+
+ if (!clauses)
+ {
+ tree c = build_omp_clause (loc, OMP_CLAUSE_UNROLL_NONE);
+ 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 */
@@ -24249,6 +24402,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:
@@ -24342,6 +24496,9 @@ 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_UNROLL:
+ stmt = c_parser_omp_unroll (loc, parser, if_p);
+ break;
default:
gcc_unreachable ();
}
@@ -15916,6 +15916,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)
@@ -638,6 +638,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;
@@ -1097,6 +1098,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);
@@ -1855,6 +1857,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. */
@@ -37204,6 +37204,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))
@@ -37278,6 +37280,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)
@@ -37368,12 +37372,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:
@@ -39459,6 +39466,56 @@ 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_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_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 ) */
@@ -41441,6 +41498,15 @@ 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 %<#pragma omp%> clause");
goto saw_error;
@@ -43565,6 +43631,8 @@ cp_parser_omp_scan_loop_body (cp_parser *parser)
braces.require_close (parser);
}
+static bool cp_parser_nested_omp_unroll_clauses (cp_parser *, tree &);
+
/* Parse the restricted form of the for statement allowed by OpenMP. */
static tree
@@ -43622,6 +43690,15 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses,
loc_first = cp_lexer_peek_token (parser->lexer)->location;
+ if (cp_parser_nested_omp_unroll_clauses (parser, clauses)
+ && count > 1)
+ {
+ error_at (loc_first,
+ "collapse cannot be larger than 1 on an unrolled loop");
+ return NULL;
+ }
+
+
for (i = 0; i < count; i++)
{
int bracecount = 0;
@@ -45657,6 +45734,79 @@ cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok,
return true;
}
+#define OMP_UNROLL_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARTIAL) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FULL) )
+
+/* Parse zero or more '#pragma omp unroll' that follow
+ another directive that requires a canonical loop nest. */
+
+static bool
+cp_parser_nested_omp_unroll_clauses (cp_parser *parser, tree &clauses)
+{
+ static const char *p_name = "#pragma omp unroll";
+ cp_token *tok;
+ bool unroll_found = false;
+ while (cp_lexer_next_token_is (parser->lexer, CPP_PRAGMA)
+ && (tok = cp_lexer_peek_token (parser->lexer),
+ cp_parser_pragma_kind (tok) == PRAGMA_OMP_UNROLL))
+ {
+ cp_lexer_consume_token (parser->lexer);
+ gcc_assert (tok->type == CPP_PRAGMA);
+ parser->lexer->in_pragma = true;
+ tree c = cp_parser_omp_all_clauses (parser, OMP_UNROLL_CLAUSE_MASK,
+ p_name, tok);
+ if (c)
+ {
+ gcc_assert (!TREE_CHAIN (c));
+ unroll_found = true;
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_UNROLL_FULL)
+ {
+ error_at (tok->location, "%<full%> clause is invalid here; "
+ "turns loop into non-loop");
+ continue;
+ }
+
+ c = finish_omp_clauses (c, C_ORT_OMP);
+ }
+ else
+ {
+ error_at (tok->location, "%<#pragma omp unroll%> without "
+ "%<partial%> clause is invalid here; "
+ "turns loop into non-loop");
+ continue;
+ }
+ clauses = chainon (clauses, c);
+ }
+ return unroll_found;
+}
+
+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;
+
+ tree clauses = cp_parser_omp_all_clauses (parser, mask, p_name, tok, false);
+
+ if (!clauses)
+ {
+ tree c = build_omp_clause (tok->location, OMP_CLAUSE_UNROLL_NONE);
+ OMP_CLAUSE_CHAIN (c) = clauses;
+ clauses = c;
+ }
+
+ cp_parser_nested_omp_unroll_clauses (parser, clauses);
+
+ 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
*/
@@ -48750,6 +48900,9 @@ 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_UNROLL:
+ stmt = cp_parser_omp_unroll (parser, pragma_tok, if_p);
+ break;
default:
gcc_unreachable ();
}
@@ -49376,6 +49529,13 @@ 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_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)
@@ -18086,6 +18086,7 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort,
case OMP_CLAUSE_ASYNC:
case OMP_CLAUSE_WAIT:
case OMP_CLAUSE_DETACH:
+ case OMP_CLAUSE_UNROLL_PARTIAL:
OMP_CLAUSE_OPERAND (nc, 0)
= tsubst_expr (OMP_CLAUSE_OPERAND (oc, 0), args, complain, in_decl);
break;
@@ -18169,6 +18170,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 ();
@@ -19437,6 +19440,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;
@@ -6779,6 +6779,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);
@@ -8822,6 +8823,61 @@ 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 ();
}
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,99 @@
+/* { 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 /* { 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 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 '#pragma omp' clause before '\(' token} } */
+ /* { dg-error {'#pragma omp unroll' without 'partial' clause is invalid here; turns loop into non-loop} "" { target *-*-* } .-1 } */
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+
+#pragma omp for
+#pragma omp unroll foo /* { dg-error {expected '#pragma omp' clause before 'foo'} } */
+ /* { dg-error {'#pragma omp unroll' without 'partial' clause is invalid here; turns loop into non-loop} "" { target *-*-* } .-1 } */
+ 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 c } .-2 } */
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+
+#pragma omp unroll parti /* { dg-error {expected '#pragma omp' 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 '#pragma omp' clause before 'parti'} } */
+ /* { dg-error {'#pragma omp unroll' without 'partial' clause is invalid here; turns loop into non-loop} "" { target *-*-* } .-1 } */
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+
+#pragma omp for
+#pragma omp unroll partial(1)
+#pragma omp unroll parti /* { dg-error {expected '#pragma omp' clause before 'parti'} } */
+ /* { dg-error {'#pragma omp unroll' without 'partial' clause is invalid here; turns loop into non-loop} "" { target *-*-* } .-1 } */
+ for (int i = -300; i != 100; ++i)
+ dummy (i);
+
+int sum = 0;
+#pragma omp parallel for reduction(+ : sum) collapse(2) /* { dg-error {collapse cannot be larger than 1 on an unrolled loop} "" { target c } } */
+#pragma omp unroll partial(1) /* { dg-error {collapse cannot be larger than 1 on an unrolled loop} "" { target c++ } } */
+ 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,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" } } */
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" } }
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,76 @@
+#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;
+}