diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index e12a528..2c2410e 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -237,8 +237,8 @@ static void cp_parser_initial_pragma static tree cp_literal_operator_id (const char *); -static void cp_parser_cilk_simd - (cp_parser *, cp_token *); +static tree cp_parser_cilk_simd + (cp_parser *, cp_token *, tree); static bool cp_parser_omp_declare_reduction_exprs (tree, cp_parser *); static tree cp_parser_cilk_simd_vectorlength @@ -9380,6 +9380,18 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, statement = cp_parser_iteration_statement (parser, false); break; + case RID_CILK_FOR: + if (!flag_enable_cilkplus) + { + error_at (cp_lexer_peek_token (parser->lexer)->location, + "-fcilkplus must be enabled to use %<_Cilk_for%>"); + cp_lexer_consume_token (parser->lexer); + statement = error_mark_node; + } + else + statement = cp_parser_cilk_simd (parser, NULL, integer_zero_node); + break; + case RID_BREAK: case RID_CONTINUE: case RID_RETURN: @@ -28865,7 +28877,7 @@ cp_parser_omp_for_cond (cp_parser *parser, tree decl, enum tree_code code) case LE_EXPR: break; case NE_EXPR: - if (code == CILK_SIMD) + if (code == CILK_SIMD || code == CILK_FOR) break; /* Fall through: OpenMP disallows NE_EXPR. */ default: @@ -29190,11 +29202,18 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, bool add_private_clause = false; location_t loc; - if (!cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR)) + if (code == CILK_SIMD + && !cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR)) { cp_parser_error (parser, "for statement expected"); return NULL; } + if (code == CILK_FOR + && !cp_lexer_next_token_is_keyword (parser->lexer, RID_CILK_FOR)) + { + cp_parser_error (parser, "_Cilk_for statement expected"); + return NULL; + } loc = cp_lexer_consume_token (parser->lexer)->location; if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) @@ -29203,13 +29222,26 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, init = decl = real_decl = NULL; this_pre_body = push_stmt_list (); + if (code == CILK_FOR + && cp_lexer_next_token_is_keyword (parser->lexer, RID_STATIC)) + { + error_at (cp_lexer_peek_token (parser->lexer)->location, + "induction variable cannot be static"); + cp_lexer_consume_token (parser->lexer); + } add_private_clause |= cp_parser_omp_for_loop_init (parser, - /*parsing_openmp=*/code != CILK_SIMD, + /*parsing_openmp=*/ + (code != CILK_SIMD && code != CILK_FOR), this_pre_body, for_block, init, decl, real_decl); - cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); + if (!cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON) + && code == CILK_FOR) + { + cp_parser_skip_to_end_of_statement (parser); + cp_parser_consume_semicolon_at_end_of_statement (parser); + } if (this_pre_body) { this_pre_body = pop_stmt_list (this_pre_body); @@ -29367,17 +29399,30 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, /* Note that we saved the original contents of this flag when we entered the structured block, and so we don't need to re-save it here. */ - if (code == CILK_SIMD) + if (code == CILK_SIMD || code == CILK_FOR) parser->in_statement = IN_CILK_SIMD_FOR; else parser->in_statement = IN_OMP_FOR; + tree top_body = NULL_TREE, top_level_body = NULL_TREE; + if (code == CILK_FOR) + { + top_level_body = push_stmt_list (); + top_body = begin_omp_parallel (); + } + /* Note that the grammar doesn't call for a structured block here, though the loop as a whole is a structured block. */ body = push_stmt_list (); cp_parser_statement (parser, NULL_TREE, false, NULL); body = pop_stmt_list (body); + if (code == CILK_FOR) + { + body = add_stmt (body); + body = finish_omp_parallel (NULL_TREE, top_body); + body = pop_stmt_list (top_level_body); + } if (declv == NULL_TREE) ret = NULL_TREE; else @@ -31312,6 +31357,38 @@ cp_parser_initial_pragma (cp_token *first_token) cp_lexer_get_preprocessor_token (NULL, first_token); } +/* Parses the grainsize pragma for the _Cilk_for statement. + Syntax: + #pragma cilk grainsize = . */ + +static void +cp_parser_cilk_grainsize (cp_parser *parser, cp_token *pragma_tok) +{ + if (cp_parser_require (parser, CPP_EQ, RT_EQ)) + { + tree exp = cp_parser_binary_expression (parser, false, false, + PREC_NOT_OPERATOR, NULL); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + if (!exp || exp == error_mark_node) + { + error_at (pragma_tok->location, "invalid grainsize for _Cilk_for"); + return; + } + cp_token *n_tok = cp_lexer_peek_token (parser->lexer); + + /* Make sure the next token is _Cilk_for, it is invalid otherwise. */ + if (n_tok && n_tok->type == CPP_KEYWORD + && n_tok->keyword == RID_CILK_FOR) + cp_parser_cilk_simd (parser, NULL, exp); + else + warning_at (cp_lexer_peek_token (parser->lexer)->location, 0, + "%<#pragma cilk grainsize%> is not followed by " + "%<_Cilk_for%>"); + return; + } + cp_parser_skip_to_pragma_eol (parser, pragma_tok); +} + /* Normal parsing of a pragma token. Here we can (and must) use the regular lexer. */ @@ -31491,9 +31568,30 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context) "%<#pragma simd%> must be inside a function"); break; } - cp_parser_cilk_simd (parser, pragma_tok); + cp_parser_cilk_simd (parser, pragma_tok, NULL_TREE); return true; + case PRAGMA_CILK_GRAINSIZE: + if (context == pragma_external) + { + error_at (pragma_tok->location, + "%<#pragma cilk grainsize%> must be inside a function"); + break; + } + + /* Ignore the pragma if Cilk Plus is not enabled. */ + if (flag_enable_cilkplus) + { + cp_parser_cilk_grainsize (parser, pragma_tok); + return true; + } + else + { + error_at (pragma_tok->location, "-fcilkplus must be enabled to use " + "%<#pragma cilk grainsize%>"); + break; + } + default: gcc_assert (id >= PRAGMA_FIRST_EXTERNAL); c_invoke_pragma_handler (id); @@ -31811,31 +31909,64 @@ cp_parser_cilk_simd_all_clauses (cp_parser *parser, cp_token *pragma_token) return c_finish_cilk_clauses (clauses); } -/* Main entry-point for parsing Cilk Plus <#pragma simd> for loops. */ +/* Main entry-point for parsing Cilk Plus <#pragma simd> for and _Cilk_for + loops. This function returns NULL_TREE whenever it is parsing the + #pragma simd's for because the caller does not check the return value. + _Cilk_for's caller checks this value and thus return error_mark_node + when errors happen and a valid value when things go as expected. */ -static void -cp_parser_cilk_simd (cp_parser *parser, cp_token *pragma_token) +static tree +cp_parser_cilk_simd (cp_parser *parser, cp_token *pragma_token, tree grain) { - tree clauses = cp_parser_cilk_simd_all_clauses (parser, pragma_token); + bool is_cilk_for = !pragma_token ? true: false; + tree clauses = NULL_TREE; + + if (!is_cilk_for) + clauses = cp_parser_cilk_simd_all_clauses (parser, pragma_token); if (clauses == error_mark_node) - return; - - if (cp_lexer_next_token_is_not_keyword (parser->lexer, RID_FOR)) + return NULL_TREE; + + if (!is_cilk_for + && cp_lexer_next_token_is_not_keyword (parser->lexer, RID_FOR)) { error_at (cp_lexer_peek_token (parser->lexer)->location, "for statement expected"); - return; + return NULL_TREE; + } + if (is_cilk_for + && cp_lexer_next_token_is_not_keyword (parser->lexer, RID_CILK_FOR)) + { + error_at (cp_lexer_peek_token (parser->lexer)->location, + "_Cilk_for statement expected"); + return error_mark_node; } tree sb = begin_omp_structured_block (); int save = cp_parser_begin_omp_structured_block (parser); - tree ret = cp_parser_omp_for_loop (parser, CILK_SIMD, clauses, NULL); + enum tree_code code = is_cilk_for ? CILK_FOR : CILK_SIMD; + tree ret = cp_parser_omp_for_loop (parser, code, clauses, NULL); if (ret) cpp_validate_cilk_plus_loop (OMP_FOR_BODY (ret)); + + /* For _Cilk_for statements, the grain value is stored in the same + location as clauses for OMP for inside a schedule clause. */ + if (is_cilk_for && ret) + { + tree l = build_omp_clause (EXPR_LOCATION (grain), + OMP_CLAUSE_SCHEDULE); + OMP_CLAUSE_SCHEDULE_KIND (l) = OMP_CLAUSE_SCHEDULE_RUNTIME; + OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (l) = grain; + OMP_CLAUSE_CHAIN (l) = NULL_TREE; + OMP_FOR_CLAUSES (ret) = l; + } + cp_parser_end_omp_structured_block (parser, save); - add_stmt (finish_omp_structured_block (sb)); - return; + tree stmt = finish_omp_structured_block (sb); + add_stmt (stmt); + if (is_cilk_for) + return stmt; + return NULL_TREE; } /* Create an identifier for a generic parameter type (a synthesized diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 930ca29..2bb85a0 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -13586,6 +13586,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, case OMP_FOR: case OMP_SIMD: case CILK_SIMD: + case CILK_FOR: case OMP_DISTRIBUTE: { tree clauses, body, pre_body; diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 3a8daca..bb64a06 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -6036,7 +6036,8 @@ finish_omp_task (tree clauses, tree body) static bool handle_omp_for_class_iterator (int i, location_t locus, tree declv, tree initv, tree condv, tree incrv, tree *body, - tree *pre_body, tree clauses) + tree *pre_body, tree clauses, + bool is_cilk_for) { tree diff, iter_init, iter_incr = NULL, last; tree incr_var = NULL, orig_pre_body, orig_body, c; @@ -6056,6 +6057,7 @@ handle_omp_for_class_iterator (int i, location_t locus, tree declv, tree initv, case GE_EXPR: case LT_EXPR: case LE_EXPR: + case NE_EXPR: if (TREE_OPERAND (cond, 1) == iter) cond = build2 (swap_tree_comparison (TREE_CODE (cond)), TREE_TYPE (cond), iter, TREE_OPERAND (cond, 0)); @@ -6199,6 +6201,11 @@ handle_omp_for_class_iterator (int i, location_t locus, tree declv, tree initv, break; decl = create_temporary_var (TREE_TYPE (diff)); + /* In _Cilk_for we must know the induction variable name since it is + read by expand_cilk_for_body in omp-low.c to set the induction + variable in the child function correctly. */ + if (is_cilk_for) + DECL_NAME (decl) = make_anon_name (); pushdecl (decl); add_decl_expr (decl); last = create_temporary_var (TREE_TYPE (diff)); @@ -6414,8 +6421,24 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv, tree initv, "iteration variable %qE", decl); return NULL; } - if (handle_omp_for_class_iterator (i, locus, declv, initv, condv, - incrv, &body, &pre_body, clauses)) + + /* In _Cilk_for, all the iterator mapping code should be + inserted in the OMP_PARALLEL_BODY. */ + if (code == CILK_FOR) + { + tree the_body = OMP_PARALLEL_BODY (body); + if (TREE_CODE (the_body) == BIND_EXPR) + the_body = BIND_EXPR_BODY (the_body); + if (handle_omp_for_class_iterator (i, locus, declv, initv, + condv, incrv, &the_body, + &pre_body, clauses, true)) + return NULL; + else + BIND_EXPR_BODY (OMP_PARALLEL_BODY (body)) = the_body; + } + else if (handle_omp_for_class_iterator (i, locus, declv, initv, + condv, incrv, &body, + &pre_body, clauses, false)) return NULL; continue; } diff --git a/gcc/testsuite/g++.dg/cilk-plus/CK/cilk-for-tplt.cc b/gcc/testsuite/g++.dg/cilk-plus/CK/cilk-for-tplt.cc new file mode 100644 index 0000000..8221371 --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/CK/cilk-for-tplt.cc @@ -0,0 +1,25 @@ +/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-options "-fcilkplus" } */ +/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */ + +#define SIZE 100 +#define CHECK_VALUE 5 + +template +int func (T start, T end) +{ + int Array[SIZE]; + _Cilk_for (T ii = 0; ii < end; ii++) + Array[ii] = CHECK_VALUE; + + for (T ii = 0; ii < end; ii++) + if (Array[ii] != CHECK_VALUE) + __builtin_abort (); + + return 0; +} + +int main (void) +{ + return func (0, 100) + func (0, 100); +} diff --git a/gcc/testsuite/g++.dg/cilk-plus/CK/stl_iter.cc b/gcc/testsuite/g++.dg/cilk-plus/CK/stl_iter.cc new file mode 100644 index 0000000..2ac8c72 --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/CK/stl_iter.cc @@ -0,0 +1,52 @@ +/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-options "-fcilkplus" } */ +/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */ + +#include +#include +#include +#include + +using namespace std; + + +int main(void) +{ +vector array; +vector array_serial; + +#if 1 +for (int ii = -1; ii < 10; ii++) +{ + array.push_back(ii); + array_serial.push_back (ii); +} +#endif +_Cilk_for (vector::iterator iter = array.begin(); iter != array.end(); + iter++) +{ + if (*iter == 6) + *iter = 13; +} +for (vector::iterator iter = array_serial.begin(); + iter != array_serial.end(); iter++) +{ + if (*iter == 6) + *iter = 13; +} +sort (array.begin(), array.end()); +sort (array_serial.begin(), array_serial.end()); + +vector ::iterator iter = array.begin (); +vector ::iterator iter_serial = array_serial.begin (); + +while (iter != array.end () && iter_serial != array_serial.end ()) +{ + if (*iter != *iter_serial) + __builtin_abort (); + iter++; + iter_serial++; +} + +return 0; +} diff --git a/gcc/testsuite/g++.dg/cilk-plus/CK/stl_rev_iter.cc b/gcc/testsuite/g++.dg/cilk-plus/CK/stl_rev_iter.cc new file mode 100644 index 0000000..1cf3301 --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/CK/stl_rev_iter.cc @@ -0,0 +1,72 @@ +/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-options "-fcilkplus" } */ +/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */ + + +#include +#include +#include +#include + +using namespace std; + + +int main(void) +{ +vector array,array_serial; + +#if 1 +for (int ii = -1; ii < 10; ii++) +{ + array.push_back(ii); + array_serial.push_back(ii); +} +#endif +_Cilk_for (vector::reverse_iterator iter4 = array.rbegin(); + iter4 != array.rend(); iter4++) +{ + if (*iter4 == 0x8) { + *iter4 = 9; + } +} + +_Cilk_for (vector::reverse_iterator iter4 = array_serial.rbegin(); + iter4 != array_serial.rend(); iter4++) +{ + if (*iter4 == 0x8) { + *iter4 = 9; + } +} +_Cilk_for (vector::reverse_iterator iter2 = array.rbegin(); + iter2 != array.rend(); + iter2 += 1) +{ + if ((*iter2 == 0x4) || (*iter2 == 0x7)) { + *iter2 = 0x3; + } +} +for (vector::reverse_iterator iter2 = array_serial.rbegin(); + iter2 != array_serial.rend(); + iter2 += 1) +{ + if ((*iter2 == 0x4) || (*iter2 == 0x7)) { + *iter2 = 0x3; + } +} +sort (array.begin(), array.end()); +sort (array_serial.begin(), array_serial.end()); + +vector ::iterator iter = array.begin (); +vector ::iterator iter_serial = array_serial.begin (); +while (iter != array.end () && iter_serial != array_serial.end ()) +{ + if (*iter != *iter_serial) + __builtin_abort (); + iter++; + iter_serial++; +} + +return 0; +} + + diff --git a/gcc/testsuite/g++.dg/cilk-plus/CK/stl_test.cc b/gcc/testsuite/g++.dg/cilk-plus/CK/stl_test.cc new file mode 100644 index 0000000..3e350a1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/CK/stl_test.cc @@ -0,0 +1,50 @@ +/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-options "-fcilkplus" } */ +/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */ + + +#include +#include +#include +#include +#include +#include + +using namespace std; + + +int main(int argc, char **argv) +{ + vector number_list, number_list_serial; + int new_number = 0; + int no_elements = 0; + + if (argc != 2) + { + no_elements = 10000; + } + + + number_list.clear(); + number_list_serial.clear(); + for (int ii = 0; ii < no_elements; ii++) + { + number_list.push_back(new_number); + number_list_serial.push_back(new_number); + } + + _Cilk_for (int jj = 0; jj < no_elements; jj++) + { + number_list[jj] = jj + no_elements; + } + for (int jj = 0; jj < no_elements; jj++) + { + number_list_serial[jj] = jj + no_elements; + } + + for (int jj = 0; jj < no_elements; jj++) + if (number_list_serial[jj] != number_list[jj]) + abort (); + + return 0; +}