diff options
Diffstat (limited to 'gcc/c/c-parser.c')
-rw-r--r-- | gcc/c/c-parser.c | 2526 |
1 files changed, 2254 insertions, 272 deletions
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index b612e29c852..8d609936107 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see #include "timevar.h" #include "c-family/c-pragma.h" #include "c-tree.h" +#include "c-lang.h" #include "flags.h" #include "ggc.h" #include "c-family/c-common.h" @@ -162,9 +163,12 @@ typedef struct GTY (()) c_token { tokens of look-ahead; more are not needed for C. */ typedef struct GTY(()) c_parser { /* The look-ahead tokens. */ - c_token tokens[2]; - /* How many look-ahead tokens are available (0, 1 or 2). */ - short tokens_avail; + c_token * GTY((skip)) tokens; + /* Buffer for look-ahead tokens. */ + c_token tokens_buf[2]; + /* How many look-ahead tokens are available (0, 1 or 2, or + more if parsing from pre-lexed tokens). */ + unsigned int tokens_avail; /* True if a syntax error is being recovered from; false otherwise. c_parser_error sets this flag. It should clear this flag when enough tokens have been consumed to recover from the error. */ @@ -736,7 +740,9 @@ c_parser_consume_token (c_parser *parser) gcc_assert (parser->tokens[0].type != CPP_EOF); gcc_assert (!parser->in_pragma || parser->tokens[0].type != CPP_PRAGMA_EOL); gcc_assert (parser->error || parser->tokens[0].type != CPP_PRAGMA); - if (parser->tokens_avail == 2) + if (parser->tokens != &parser->tokens_buf[0]) + parser->tokens++; + else if (parser->tokens_avail == 2) parser->tokens[0] = parser->tokens[1]; parser->tokens_avail--; } @@ -750,7 +756,9 @@ c_parser_consume_pragma (c_parser *parser) gcc_assert (!parser->in_pragma); gcc_assert (parser->tokens_avail >= 1); gcc_assert (parser->tokens[0].type == CPP_PRAGMA); - if (parser->tokens_avail == 2) + if (parser->tokens != &parser->tokens_buf[0]) + parser->tokens++; + else if (parser->tokens_avail == 2) parser->tokens[0] = parser->tokens[1]; parser->tokens_avail--; parser->in_pragma = true; @@ -1112,7 +1120,7 @@ enum c_parser_prec { static void c_parser_external_declaration (c_parser *); static void c_parser_asm_definition (c_parser *); static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool, - bool, bool, tree *); + bool, bool, tree *, vec<c_token>); static void c_parser_static_assert_declaration_no_semi (c_parser *); static void c_parser_static_assert_declaration (c_parser *); static void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool, @@ -1155,11 +1163,12 @@ static tree c_parser_asm_statement (c_parser *); static tree c_parser_asm_operands (c_parser *); static tree c_parser_asm_goto_operands (c_parser *); static tree c_parser_asm_clobbers (c_parser *); -static struct c_expr c_parser_expr_no_commas (c_parser *, struct c_expr *); +static struct c_expr c_parser_expr_no_commas (c_parser *, struct c_expr *, + tree = NULL_TREE); static struct c_expr c_parser_conditional_expression (c_parser *, - struct c_expr *); + struct c_expr *, tree); static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *, - enum c_parser_prec); + tree); static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *); static struct c_expr c_parser_unary_expression (c_parser *); static struct c_expr c_parser_sizeof_expression (c_parser *); @@ -1185,9 +1194,15 @@ static void c_parser_omp_barrier (c_parser *); static void c_parser_omp_flush (c_parser *); static void c_parser_omp_taskwait (c_parser *); static void c_parser_omp_taskyield (c_parser *); +static void c_parser_omp_cancel (c_parser *); +static void c_parser_omp_cancellation_point (c_parser *); -enum pragma_context { pragma_external, pragma_stmt, pragma_compound }; +enum pragma_context { pragma_external, pragma_struct, pragma_param, + pragma_stmt, pragma_compound }; static bool c_parser_pragma (c_parser *, enum pragma_context); +static bool c_parser_omp_target (c_parser *, enum pragma_context); +static void c_parser_omp_end_declare_target (c_parser *); +static void c_parser_omp_declare (c_parser *, enum pragma_context); /* These Objective-C parser functions are only ever called when compiling Objective-C. */ @@ -1360,11 +1375,14 @@ c_parser_external_declaration (c_parser *parser) an @interface or @protocol with prefix attributes). We can only tell which after parsing the declaration specifiers, if any, and the first declarator. */ - c_parser_declaration_or_fndef (parser, true, true, true, false, true, NULL); + c_parser_declaration_or_fndef (parser, true, true, true, false, true, + NULL, vNULL); break; } } +static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token>); + /* Parse a declaration or function definition (C90 6.5, 6.7.1, C99 6.7, 6.9.1). If FNDEF_OK is true, a function definition is accepted; otherwise (old-style parameter declarations) only other @@ -1440,7 +1458,8 @@ static void c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool static_assert_ok, bool empty_ok, bool nested, bool start_attr_ok, - tree *objc_foreach_object_declaration) + tree *objc_foreach_object_declaration, + vec<c_token> omp_declare_simd_clauses) { struct c_declspecs *specs; tree prefix_attrs; @@ -1610,6 +1629,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, C_DTR_NORMAL, &dummy); if (declarator == NULL) { + if (omp_declare_simd_clauses.exists ()) + c_finish_omp_declare_simd (parser, NULL_TREE, NULL_TREE, + omp_declare_simd_clauses); c_parser_skip_to_end_of_block_or_statement (parser); return; } @@ -1646,6 +1668,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, chainon (postfix_attrs, all_prefix_attrs)); if (!d) d = error_mark_node; + if (omp_declare_simd_clauses.exists ()) + c_finish_omp_declare_simd (parser, d, NULL_TREE, + omp_declare_simd_clauses); start_init (d, asm_name, global_bindings_p ()); init_loc = c_parser_peek_token (parser)->location; init = c_parser_initializer (parser); @@ -1662,6 +1687,28 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, tree d = start_decl (declarator, specs, false, chainon (postfix_attrs, all_prefix_attrs)); + if (omp_declare_simd_clauses.exists ()) + { + tree parms = NULL_TREE; + if (d && TREE_CODE (d) == FUNCTION_DECL) + { + struct c_declarator *ce = declarator; + while (ce != NULL) + if (ce->kind == cdk_function) + { + parms = ce->u.arg_info->parms; + break; + } + else + ce = ce->declarator; + } + if (parms) + temp_store_parm_decls (d, parms); + c_finish_omp_declare_simd (parser, d, parms, + omp_declare_simd_clauses); + if (parms) + temp_pop_parm_decls (); + } if (d) finish_decl (d, UNKNOWN_LOCATION, NULL_TREE, NULL_TREE, asm_name); @@ -1751,8 +1798,11 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, while (c_parser_next_token_is_not (parser, CPP_EOF) && c_parser_next_token_is_not (parser, CPP_OPEN_BRACE)) c_parser_declaration_or_fndef (parser, false, false, false, - true, false, NULL); + true, false, NULL, vNULL); store_parm_decls (); + if (omp_declare_simd_clauses.exists ()) + c_finish_omp_declare_simd (parser, current_function_decl, NULL_TREE, + omp_declare_simd_clauses); DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus = c_parser_peek_token (parser)->location; fnbody = c_parser_compound_statement (parser); @@ -2481,7 +2531,7 @@ c_parser_struct_or_union_specifier (c_parser *parser) /* Accept #pragmas at struct scope. */ if (c_parser_next_token_is (parser, CPP_PRAGMA)) { - c_parser_pragma (parser, pragma_external); + c_parser_pragma (parser, pragma_struct); continue; } /* Parse some comma-separated declarations, but not the @@ -3329,7 +3379,7 @@ c_parser_parameter_declaration (c_parser *parser, tree attrs) /* Accept #pragmas between parameter declarations. */ while (c_parser_next_token_is (parser, CPP_PRAGMA)) - c_parser_pragma (parser, pragma_external); + c_parser_pragma (parser, pragma_param); if (!c_parser_next_token_starts_declspecs (parser)) { @@ -4074,7 +4124,11 @@ c_parser_initval (c_parser *parser, struct c_expr *after, openmp-directive: barrier-directive - flush-directive */ + flush-directive + taskwait-directive + taskyield-directive + cancel-directive + cancellation-point-directive */ static tree c_parser_compound_statement (c_parser *parser) @@ -4179,7 +4233,8 @@ c_parser_compound_statement_nostart (c_parser *parser) { last_label = false; mark_valid_location_for_stdc_pragma (false); - c_parser_declaration_or_fndef (parser, true, true, true, true, true, NULL); + c_parser_declaration_or_fndef (parser, true, true, true, true, + true, NULL, vNULL); if (last_stmt) pedwarn_c90 (loc, (pedantic && !flag_isoc99) @@ -4207,7 +4262,7 @@ c_parser_compound_statement_nostart (c_parser *parser) last_label = false; mark_valid_location_for_stdc_pragma (false); c_parser_declaration_or_fndef (parser, true, true, true, true, - true, NULL); + true, NULL, vNULL); /* Following the old parser, __extension__ does not disable this diagnostic. */ restore_extension_diagnostics (ext); @@ -4345,7 +4400,8 @@ c_parser_label (c_parser *parser) c_parser_declaration_or_fndef (parser, /*fndef_ok*/ false, /*static_assert_ok*/ true, /*empty_ok*/ true, /*nested*/ true, - /*start_attr_ok*/ true, NULL); + /*start_attr_ok*/ true, NULL, + vNULL); } } } @@ -4408,9 +4464,12 @@ c_parser_label (c_parser *parser) openmp-construct: parallel-construct for-construct + simd-construct + for-simd-construct sections-construct single-construct parallel-for-construct + parallel-for-simd-construct parallel-sections-construct master-construct critical-construct @@ -4423,6 +4482,12 @@ c_parser_label (c_parser *parser) for-construct: for-directive iteration-statement + simd-construct: + simd-directive iteration-statements + + for-simd-construct: + for-simd-directive iteration-statements + sections-construct: sections-directive section-scope @@ -4432,6 +4497,9 @@ c_parser_label (c_parser *parser) parallel-for-construct: parallel-for-directive iteration-statement + parallel-for-simd-construct: + parallel-for-simd-directive iteration-statement + parallel-sections-construct: parallel-sections-directive section-scope @@ -4979,7 +5047,7 @@ c_parser_for_statement (c_parser *parser) else if (c_parser_next_tokens_start_declaration (parser)) { c_parser_declaration_or_fndef (parser, true, true, true, true, true, - &object_expression); + &object_expression, vNULL); parser->objc_could_be_foreach_context = false; if (c_parser_next_token_is_keyword (parser, RID_IN)) @@ -5008,7 +5076,7 @@ c_parser_for_statement (c_parser *parser) ext = disable_extension_diagnostics (); c_parser_consume_token (parser); c_parser_declaration_or_fndef (parser, true, true, true, true, - true, &object_expression); + true, &object_expression, vNULL); parser->objc_could_be_foreach_context = false; restore_extension_diagnostics (ext); @@ -5396,13 +5464,14 @@ c_parser_asm_goto_operands (c_parser *parser) error. */ static struct c_expr -c_parser_expr_no_commas (c_parser *parser, struct c_expr *after) +c_parser_expr_no_commas (c_parser *parser, struct c_expr *after, + tree omp_atomic_lhs) { struct c_expr lhs, rhs, ret; enum tree_code code; location_t op_location, exp_location; gcc_assert (!after || c_dialect_objc ()); - lhs = c_parser_conditional_expression (parser, after); + lhs = c_parser_conditional_expression (parser, after, omp_atomic_lhs); op_location = c_parser_peek_token (parser)->location; switch (c_parser_peek_token (parser)->type) { @@ -5476,14 +5545,15 @@ c_parser_expr_no_commas (c_parser *parser, struct c_expr *after) */ static struct c_expr -c_parser_conditional_expression (c_parser *parser, struct c_expr *after) +c_parser_conditional_expression (c_parser *parser, struct c_expr *after, + tree omp_atomic_lhs) { struct c_expr cond, exp1, exp2, ret; location_t cond_loc, colon_loc, middle_loc; gcc_assert (!after || c_dialect_objc ()); - cond = c_parser_binary_expression (parser, after, PREC_NONE); + cond = c_parser_binary_expression (parser, after, omp_atomic_lhs); if (c_parser_next_token_is_not (parser, CPP_QUERY)) return cond; @@ -5535,7 +5605,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after) } { location_t exp2_loc = c_parser_peek_token (parser)->location; - exp2 = c_parser_conditional_expression (parser, NULL); + exp2 = c_parser_conditional_expression (parser, NULL, NULL_TREE); exp2 = default_function_array_read_conversion (exp2_loc, exp2); } c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node; @@ -5568,8 +5638,13 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after) /* Parse a binary expression; that is, a logical-OR-expression (C90 6.3.5-6.3.14, C99 6.5.5-6.5.14). If AFTER is not NULL then it is an Objective-C message expression which is the primary-expression - starting the expression as an initializer. PREC is the starting - precedence, usually PREC_NONE. + starting the expression as an initializer. + + OMP_ATOMIC_LHS is NULL, unless parsing OpenMP #pragma omp atomic, + when it should be the unfolded lhs. In a valid OpenMP source, + one of the operands of the toplevel binary expression must be equal + to it. In that case, just return a build2 created binary operation + rather than result of parser_build_binary_op. multiplicative-expression: cast-expression @@ -5622,7 +5697,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after) static struct c_expr c_parser_binary_expression (c_parser *parser, struct c_expr *after, - enum c_parser_prec prec) + tree omp_atomic_lhs) { /* A binary expression is parsed using operator-precedence parsing, with the operands being cast expressions. All the binary @@ -5680,16 +5755,30 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after, stack[sp].expr \ = default_function_array_read_conversion (stack[sp].loc, \ stack[sp].expr); \ - stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc, \ - stack[sp].op, \ - stack[sp - 1].expr, \ - stack[sp].expr); \ + if (__builtin_expect (omp_atomic_lhs != NULL_TREE, 0) && sp == 1 \ + && c_parser_peek_token (parser)->type == CPP_SEMICOLON \ + && ((1 << stack[sp].prec) \ + & (1 << (PREC_BITOR | PREC_BITXOR | PREC_BITAND | PREC_SHIFT \ + | PREC_ADD | PREC_MULT))) \ + && stack[sp].op != TRUNC_MOD_EXPR \ + && stack[0].expr.value != error_mark_node \ + && stack[1].expr.value != error_mark_node \ + && (c_tree_equal (stack[0].expr.value, omp_atomic_lhs) \ + || c_tree_equal (stack[1].expr.value, omp_atomic_lhs))) \ + stack[0].expr.value \ + = build2 (stack[1].op, TREE_TYPE (stack[0].expr.value), \ + stack[0].expr.value, stack[1].expr.value); \ + else \ + stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc, \ + stack[sp].op, \ + stack[sp - 1].expr, \ + stack[sp].expr); \ sp--; \ } while (0) gcc_assert (!after || c_dialect_objc ()); stack[0].loc = c_parser_peek_token (parser)->location; stack[0].expr = c_parser_cast_expression (parser, after); - stack[0].prec = prec; + stack[0].prec = PREC_NONE; sp = 0; while (true) { @@ -5778,11 +5867,7 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after, } binary_loc = c_parser_peek_token (parser)->location; while (oprec <= stack[sp].prec) - { - if (sp == 0) - goto out; - POP; - } + POP; c_parser_consume_token (parser); switch (ocode) { @@ -7955,7 +8040,7 @@ c_parser_objc_methodprotolist (c_parser *parser) } else c_parser_declaration_or_fndef (parser, false, false, true, - false, true, NULL); + false, true, NULL, vNULL); break; } } @@ -8936,10 +9021,39 @@ c_parser_pragma (c_parser *parser, enum pragma_context context) c_parser_omp_taskyield (parser); return false; + case PRAGMA_OMP_CANCEL: + if (context != pragma_compound) + { + if (context == pragma_stmt) + c_parser_error (parser, "%<#pragma omp cancel%> may only be " + "used in compound statements"); + goto bad_stmt; + } + c_parser_omp_cancel (parser); + return false; + + case PRAGMA_OMP_CANCELLATION_POINT: + if (context != pragma_compound) + { + if (context == pragma_stmt) + c_parser_error (parser, "%<#pragma omp cancellation point%> may " + "only be used in compound statements"); + goto bad_stmt; + } + c_parser_omp_cancellation_point (parser); + return false; + case PRAGMA_OMP_THREADPRIVATE: c_parser_omp_threadprivate (parser); return false; + case PRAGMA_OMP_TARGET: + return c_parser_omp_target (parser, context); + + case PRAGMA_OMP_END_DECLARE_TARGET: + c_parser_omp_end_declare_target (parser); + return false; + case PRAGMA_OMP_SECTION: error_at (c_parser_peek_token (parser)->location, "%<#pragma omp section%> may only be used in " @@ -8947,6 +9061,10 @@ c_parser_pragma (c_parser *parser, enum pragma_context context) c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); return false; + case PRAGMA_OMP_DECLARE_REDUCTION: + c_parser_omp_declare (parser, context); + return false; + case PRAGMA_GCC_PCH_PREPROCESS: c_parser_error (parser, "%<#pragma GCC pch_preprocess%> must be first"); c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); @@ -8955,7 +9073,7 @@ c_parser_pragma (c_parser *parser, enum pragma_context context) default: if (id < PRAGMA_FIRST_EXTERNAL) { - if (context == pragma_external) + if (context != pragma_stmt && context != pragma_compound) { bad_stmt: c_parser_error (parser, "expected declaration specifiers"); @@ -9020,7 +9138,7 @@ c_parser_pragma_pch_preprocess (c_parser *parser) c_common_pch_pragma (parse_in, TREE_STRING_POINTER (name)); } -/* OpenMP 2.5 parsing routines. */ +/* OpenMP 2.5 / 3.0 / 3.1 / 4.0 parsing routines. */ /* Returns name of the next clause. If the clause is not recognized PRAGMA_OMP_CLAUSE_NONE is returned and @@ -9036,12 +9154,18 @@ c_parser_omp_clause_name (c_parser *parser) result = PRAGMA_OMP_CLAUSE_IF; else if (c_parser_next_token_is_keyword (parser, RID_DEFAULT)) result = PRAGMA_OMP_CLAUSE_DEFAULT; + else if (c_parser_next_token_is_keyword (parser, RID_FOR)) + result = PRAGMA_OMP_CLAUSE_FOR; else if (c_parser_next_token_is (parser, CPP_NAME)) { const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); switch (p[0]) { + case 'a': + if (!strcmp ("aligned", p)) + result = PRAGMA_OMP_CLAUSE_ALIGNED; + break; case 'c': if (!strcmp ("collapse", p)) result = PRAGMA_OMP_CLAUSE_COLLAPSE; @@ -9050,23 +9174,45 @@ c_parser_omp_clause_name (c_parser *parser) else if (!strcmp ("copyprivate", p)) result = PRAGMA_OMP_CLAUSE_COPYPRIVATE; break; + case 'd': + if (!strcmp ("depend", p)) + result = PRAGMA_OMP_CLAUSE_DEPEND; + else if (!strcmp ("device", p)) + result = PRAGMA_OMP_CLAUSE_DEVICE; + else if (!strcmp ("dist_schedule", p)) + result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE; + break; case 'f': if (!strcmp ("final", p)) result = PRAGMA_OMP_CLAUSE_FINAL; else if (!strcmp ("firstprivate", p)) result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE; + else if (!strcmp ("from", p)) + result = PRAGMA_OMP_CLAUSE_FROM; + break; + case 'i': + if (!strcmp ("inbranch", p)) + result = PRAGMA_OMP_CLAUSE_INBRANCH; break; case 'l': if (!strcmp ("lastprivate", p)) result = PRAGMA_OMP_CLAUSE_LASTPRIVATE; + else if (!strcmp ("linear", p)) + result = PRAGMA_OMP_CLAUSE_LINEAR; break; case 'm': - if (!strcmp ("mergeable", p)) + if (!strcmp ("map", p)) + result = PRAGMA_OMP_CLAUSE_MAP; + else if (!strcmp ("mergeable", p)) result = PRAGMA_OMP_CLAUSE_MERGEABLE; break; case 'n': - if (!strcmp ("nowait", p)) + if (!strcmp ("notinbranch", p)) + result = PRAGMA_OMP_CLAUSE_NOTINBRANCH; + else if (!strcmp ("nowait", p)) result = PRAGMA_OMP_CLAUSE_NOWAIT; + else if (!strcmp ("num_teams", p)) + result = PRAGMA_OMP_CLAUSE_NUM_TEAMS; else if (!strcmp ("num_threads", p)) result = PRAGMA_OMP_CLAUSE_NUM_THREADS; break; @@ -9075,21 +9221,41 @@ c_parser_omp_clause_name (c_parser *parser) result = PRAGMA_OMP_CLAUSE_ORDERED; break; case 'p': - if (!strcmp ("private", p)) + if (!strcmp ("parallel", p)) + result = PRAGMA_OMP_CLAUSE_PARALLEL; + else if (!strcmp ("private", p)) result = PRAGMA_OMP_CLAUSE_PRIVATE; + else if (!strcmp ("proc_bind", p)) + result = PRAGMA_OMP_CLAUSE_PROC_BIND; break; case 'r': if (!strcmp ("reduction", p)) result = PRAGMA_OMP_CLAUSE_REDUCTION; break; case 's': - if (!strcmp ("schedule", p)) + if (!strcmp ("safelen", p)) + result = PRAGMA_OMP_CLAUSE_SAFELEN; + else if (!strcmp ("schedule", p)) result = PRAGMA_OMP_CLAUSE_SCHEDULE; + else if (!strcmp ("sections", p)) + result = PRAGMA_OMP_CLAUSE_SECTIONS; else if (!strcmp ("shared", p)) result = PRAGMA_OMP_CLAUSE_SHARED; + else if (!strcmp ("simdlen", p)) + result = PRAGMA_OMP_CLAUSE_SIMDLEN; + break; + case 't': + if (!strcmp ("taskgroup", p)) + result = PRAGMA_OMP_CLAUSE_TASKGROUP; + else if (!strcmp ("thread_limit", p)) + result = PRAGMA_OMP_CLAUSE_THREAD_LIMIT; + else if (!strcmp ("to", p)) + result = PRAGMA_OMP_CLAUSE_TO; break; case 'u': - if (!strcmp ("untied", p)) + if (!strcmp ("uniform", p)) + result = PRAGMA_OMP_CLAUSE_UNIFORM; + else if (!strcmp ("untied", p)) result = PRAGMA_OMP_CLAUSE_UNTIED; break; } @@ -9133,8 +9299,7 @@ check_no_duplicate_clause (tree clauses, enum omp_clause_code code, static tree c_parser_omp_variable_list (c_parser *parser, location_t clause_loc, - enum omp_clause_code kind, - tree list) + enum omp_clause_code kind, tree list) { if (c_parser_next_token_is_not (parser, CPP_NAME) || c_parser_peek_token (parser)->id_kind != C_ID_ID) @@ -9146,22 +9311,70 @@ c_parser_omp_variable_list (c_parser *parser, tree t = lookup_name (c_parser_peek_token (parser)->value); if (t == NULL_TREE) - undeclared_variable (c_parser_peek_token (parser)->location, - c_parser_peek_token (parser)->value); - else if (t == error_mark_node) + { + undeclared_variable (c_parser_peek_token (parser)->location, + c_parser_peek_token (parser)->value); + t = error_mark_node; + } + + c_parser_consume_token (parser); + + if (t == error_mark_node) ; else if (kind != 0) { - tree u = build_omp_clause (clause_loc, kind); - OMP_CLAUSE_DECL (u) = t; - OMP_CLAUSE_CHAIN (u) = list; - list = u; + switch (kind) + { + case OMP_CLAUSE_MAP: + case OMP_CLAUSE_FROM: + case OMP_CLAUSE_TO: + case OMP_CLAUSE_DEPEND: + while (c_parser_next_token_is (parser, CPP_OPEN_SQUARE)) + { + tree low_bound = NULL_TREE, length = NULL_TREE; + + c_parser_consume_token (parser); + if (!c_parser_next_token_is (parser, CPP_COLON)) + low_bound = c_parser_expression (parser).value; + if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) + length = integer_one_node; + else + { + /* Look for `:'. */ + if (!c_parser_require (parser, CPP_COLON, + "expected %<:%>")) + { + t = error_mark_node; + break; + } + if (!c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) + length = c_parser_expression (parser).value; + } + /* Look for the closing `]'. */ + if (!c_parser_require (parser, CPP_CLOSE_SQUARE, + "expected %<]%>")) + { + t = error_mark_node; + break; + } + t = tree_cons (low_bound, length, t); + } + break; + default: + break; + } + + if (t != error_mark_node) + { + tree u = build_omp_clause (clause_loc, kind); + OMP_CLAUSE_DECL (u) = t; + OMP_CLAUSE_CHAIN (u) = list; + list = u; + } } else list = tree_cons (t, NULL_TREE, list); - c_parser_consume_token (parser); - if (c_parser_next_token_is_not (parser, CPP_COMMA)) break; @@ -9209,6 +9422,8 @@ c_parser_omp_clause_collapse (c_parser *parser, tree list) } 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)) || !host_integerp (num, 0) || (n = tree_low_cst (num, 0)) <= 0 @@ -9474,11 +9689,17 @@ c_parser_omp_clause_private (c_parser *parser, tree list) reduction-operator: One of: + * - & ^ | && || - + OpenMP 3.1: reduction-operator: - One of: + * - & ^ | && || max min */ + One of: + * - & ^ | && || max min + + OpenMP 4.0: + + reduction-operator: + One of: + * - & ^ | && || + identifier */ static tree c_parser_omp_clause_reduction (c_parser *parser, tree list) @@ -9486,7 +9707,8 @@ c_parser_omp_clause_reduction (c_parser *parser, tree list) location_t clause_loc = c_parser_peek_token (parser)->location; if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { - enum tree_code code; + enum tree_code code = ERROR_MARK; + tree reduc_id = NULL_TREE; switch (c_parser_peek_token (parser)->type) { @@ -9528,8 +9750,9 @@ c_parser_omp_clause_reduction (c_parser *parser, tree list) code = MAX_EXPR; break; } + reduc_id = c_parser_peek_token (parser)->value; + break; } - /* FALLTHRU */ default: c_parser_error (parser, "expected %<+%>, %<*%>, %<-%>, %<&%>, " @@ -9538,6 +9761,7 @@ c_parser_omp_clause_reduction (c_parser *parser, tree list) return list; } c_parser_consume_token (parser); + reduc_id = c_omp_reduction_id (code, reduc_id); if (c_parser_require (parser, CPP_COLON, "expected %<:%>")) { tree nl, c; @@ -9545,7 +9769,17 @@ c_parser_omp_clause_reduction (c_parser *parser, tree list) nl = c_parser_omp_variable_list (parser, clause_loc, OMP_CLAUSE_REDUCTION, list); for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) - OMP_CLAUSE_REDUCTION_CODE (c) = code; + { + tree type = TREE_TYPE (OMP_CLAUSE_DECL (c)); + OMP_CLAUSE_REDUCTION_CODE (c) = code; + if (code == ERROR_MARK + || !(INTEGRAL_TYPE_P (type) + || TREE_CODE (type) == REAL_TYPE + || TREE_CODE (type) == COMPLEX_TYPE)) + OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) + = c_omp_reduction_lookup (reduc_id, + TYPE_MAIN_VARIANT (type)); + } list = nl; } @@ -9675,13 +9909,544 @@ c_parser_omp_clause_untied (c_parser *parser ATTRIBUTE_UNUSED, tree list) return c; } +/* OpenMP 4.0: + inbranch + notinbranch */ + +static tree +c_parser_omp_clause_branch (c_parser *parser ATTRIBUTE_UNUSED, + enum omp_clause_code code, tree list) +{ + check_no_duplicate_clause (list, code, omp_clause_code_name[code]); + + tree c = build_omp_clause (c_parser_peek_token (parser)->location, code); + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 4.0: + parallel + for + sections + taskgroup */ + +static tree +c_parser_omp_clause_cancelkind (c_parser *parser ATTRIBUTE_UNUSED, + enum omp_clause_code code, tree list) +{ + tree c = build_omp_clause (c_parser_peek_token (parser)->location, code); + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 4.0: + num_teams ( expression ) */ + +static tree +c_parser_omp_clause_num_teams (c_parser *parser, tree list) +{ + location_t num_teams_loc = c_parser_peek_token (parser)->location; + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + location_t expr_loc = c_parser_peek_token (parser)->location; + tree c, t = c_parser_expression (parser).value; + mark_exp_read (t); + t = c_fully_fold (t, false, NULL); + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + c_parser_error (parser, "expected integer expression"); + return list; + } + + /* Attempt to statically determine when the number isn't positive. */ + c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, + build_int_cst (TREE_TYPE (t), 0)); + if (CAN_HAVE_LOCATION_P (c)) + SET_EXPR_LOCATION (c, expr_loc); + if (c == boolean_true_node) + { + warning_at (expr_loc, 0, "%<num_teams%> value must be positive"); + t = integer_one_node; + } + + check_no_duplicate_clause (list, OMP_CLAUSE_NUM_TEAMS, "num_teams"); + + c = build_omp_clause (num_teams_loc, OMP_CLAUSE_NUM_TEAMS); + OMP_CLAUSE_NUM_TEAMS_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + +/* OpenMP 4.0: + thread_limit ( expression ) */ + +static tree +c_parser_omp_clause_thread_limit (c_parser *parser, tree list) +{ + location_t num_teams_loc = c_parser_peek_token (parser)->location; + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + location_t expr_loc = c_parser_peek_token (parser)->location; + tree c, t = c_parser_expression (parser).value; + mark_exp_read (t); + t = c_fully_fold (t, false, NULL); + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + c_parser_error (parser, "expected integer expression"); + return list; + } + + /* Attempt to statically determine when the number isn't positive. */ + c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, + build_int_cst (TREE_TYPE (t), 0)); + if (CAN_HAVE_LOCATION_P (c)) + SET_EXPR_LOCATION (c, expr_loc); + if (c == boolean_true_node) + { + warning_at (expr_loc, 0, "%<thread_limit%> value must be positive"); + t = integer_one_node; + } + + check_no_duplicate_clause (list, OMP_CLAUSE_THREAD_LIMIT, + "thread_limit"); + + c = build_omp_clause (num_teams_loc, OMP_CLAUSE_THREAD_LIMIT); + OMP_CLAUSE_THREAD_LIMIT_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + +/* OpenMP 4.0: + aligned ( variable-list ) + aligned ( variable-list : constant-expression ) */ + +static tree +c_parser_omp_clause_aligned (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + tree nl, c; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + + nl = c_parser_omp_variable_list (parser, clause_loc, + OMP_CLAUSE_ALIGNED, list); + + if (c_parser_next_token_is (parser, CPP_COLON)) + { + c_parser_consume_token (parser); + tree alignment = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (alignment); + alignment = c_fully_fold (alignment, false, NULL); + if (!INTEGRAL_TYPE_P (TREE_TYPE (alignment)) + && TREE_CODE (alignment) != INTEGER_CST + && tree_int_cst_sgn (alignment) != 1) + { + error_at (clause_loc, "%<aligned%> clause alignment expression must " + "be positive constant integer expression"); + alignment = NULL_TREE; + } + + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_ALIGNED_ALIGNMENT (c) = alignment; + } + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return nl; +} + +/* OpenMP 4.0: + linear ( variable-list ) + linear ( variable-list : expression ) */ + +static tree +c_parser_omp_clause_linear (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + tree nl, c, step; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + + nl = c_parser_omp_variable_list (parser, clause_loc, + OMP_CLAUSE_LINEAR, list); + + if (c_parser_next_token_is (parser, CPP_COLON)) + { + c_parser_consume_token (parser); + step = c_parser_expression (parser).value; + mark_exp_read (step); + step = c_fully_fold (step, false, NULL); + if (!INTEGRAL_TYPE_P (TREE_TYPE (step))) + { + error_at (clause_loc, "%<linear%> clause step expression must " + "be integral"); + step = integer_one_node; + } + + } + else + step = integer_one_node; + + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + { + OMP_CLAUSE_LINEAR_STEP (c) = step; + } + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return nl; +} + +/* OpenMP 4.0: + safelen ( constant-expression ) */ + +static tree +c_parser_omp_clause_safelen (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + tree c, t; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + + t = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (t); + t = c_fully_fold (t, false, NULL); + if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) + && TREE_CODE (t) != INTEGER_CST + && tree_int_cst_sgn (t) != 1) + { + error_at (clause_loc, "%<safelen%> clause expression must " + "be positive constant integer expression"); + t = NULL_TREE; + } + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + if (t == NULL_TREE || t == error_mark_node) + return list; + + check_no_duplicate_clause (list, OMP_CLAUSE_SAFELEN, "safelen"); + + c = build_omp_clause (clause_loc, OMP_CLAUSE_SAFELEN); + OMP_CLAUSE_SAFELEN_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 4.0: + simdlen ( constant-expression ) */ + +static tree +c_parser_omp_clause_simdlen (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + tree c, t; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + + t = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (t); + t = c_fully_fold (t, false, NULL); + if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) + && TREE_CODE (t) != INTEGER_CST + && tree_int_cst_sgn (t) != 1) + { + error_at (clause_loc, "%<simdlen%> clause expression must " + "be positive constant integer expression"); + t = NULL_TREE; + } + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + if (t == NULL_TREE || t == error_mark_node) + return list; + + check_no_duplicate_clause (list, OMP_CLAUSE_SIMDLEN, "simdlen"); + + c = build_omp_clause (clause_loc, OMP_CLAUSE_SIMDLEN); + OMP_CLAUSE_SIMDLEN_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 4.0: + depend ( depend-kind: variable-list ) + + depend-kind: + in | out | inout */ + +static tree +c_parser_omp_clause_depend (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_INOUT; + tree nl, c; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp ("in", p) == 0) + kind = OMP_CLAUSE_DEPEND_IN; + else if (strcmp ("inout", p) == 0) + kind = OMP_CLAUSE_DEPEND_INOUT; + else if (strcmp ("out", p) == 0) + kind = OMP_CLAUSE_DEPEND_OUT; + else + goto invalid_kind; + } + else + goto invalid_kind; + + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + goto resync_fail; + + nl = c_parser_omp_variable_list (parser, clause_loc, + OMP_CLAUSE_DEPEND, list); + + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_DEPEND_KIND (c) = kind; + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return nl; + + invalid_kind: + c_parser_error (parser, "invalid depend kind"); + resync_fail: + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return list; +} + +/* OpenMP 4.0: + map ( map-kind: variable-list ) + map ( variable-list ) + + map-kind: + alloc | to | from | tofrom */ + +static tree +c_parser_omp_clause_map (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + enum omp_clause_map_kind kind = OMP_CLAUSE_MAP_TOFROM; + tree nl, c; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_COLON) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp ("alloc", p) == 0) + kind = OMP_CLAUSE_MAP_ALLOC; + else if (strcmp ("to", p) == 0) + kind = OMP_CLAUSE_MAP_TO; + else if (strcmp ("from", p) == 0) + kind = OMP_CLAUSE_MAP_FROM; + else if (strcmp ("tofrom", p) == 0) + kind = OMP_CLAUSE_MAP_TOFROM; + else + { + c_parser_error (parser, "invalid map kind"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return list; + } + c_parser_consume_token (parser); + c_parser_consume_token (parser); + } + + nl = c_parser_omp_variable_list (parser, clause_loc, OMP_CLAUSE_MAP, list); + + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_MAP_KIND (c) = kind; + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return nl; +} + +/* OpenMP 4.0: + device ( expression ) */ + +static tree +c_parser_omp_clause_device (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + tree c, t = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (t); + t = c_fully_fold (t, false, NULL); + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + c_parser_error (parser, "expected integer expression"); + return list; + } + + check_no_duplicate_clause (list, OMP_CLAUSE_DEVICE, "device"); + + c = build_omp_clause (clause_loc, OMP_CLAUSE_DEVICE); + OMP_CLAUSE_DEVICE_ID (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + +/* OpenMP 4.0: + dist_schedule ( static ) + dist_schedule ( static , expression ) */ + +static tree +c_parser_omp_clause_dist_schedule (c_parser *parser, tree list) +{ + tree c, t = NULL_TREE; + location_t loc = c_parser_peek_token (parser)->location; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + + if (!c_parser_next_token_is_keyword (parser, RID_STATIC)) + { + c_parser_error (parser, "invalid dist_schedule kind"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return list; + } + + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_COMMA)) + { + c_parser_consume_token (parser); + + t = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (t); + t = c_fully_fold (t, false, NULL); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + } + else + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<,%> or %<)%>"); + + check_no_duplicate_clause (list, OMP_CLAUSE_SCHEDULE, "schedule"); + if (t == error_mark_node) + return list; + + c = build_omp_clause (loc, OMP_CLAUSE_DIST_SCHEDULE); + OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 4.0: + proc_bind ( proc-bind-kind ) + + proc-bind-kind: + master | close | spread */ + +static tree +c_parser_omp_clause_proc_bind (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + enum omp_clause_proc_bind_kind kind; + tree c; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp ("master", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_MASTER; + else if (strcmp ("close", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_CLOSE; + else if (strcmp ("spread", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_SPREAD; + else + goto invalid_kind; + } + else + goto invalid_kind; + + c_parser_consume_token (parser); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + c = build_omp_clause (clause_loc, OMP_CLAUSE_PROC_BIND); + OMP_CLAUSE_PROC_BIND_KIND (c) = kind; + OMP_CLAUSE_CHAIN (c) = list; + return c; + + invalid_kind: + c_parser_error (parser, "invalid proc_bind kind"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return list; +} + +/* OpenMP 4.0: + to ( variable-list ) */ + +static tree +c_parser_omp_clause_to (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO, list); +} + +/* OpenMP 4.0: + from ( variable-list ) */ + +static tree +c_parser_omp_clause_from (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FROM, list); +} + +/* OpenMP 4.0: + uniform ( variable-list ) */ + +static tree +c_parser_omp_clause_uniform (c_parser *parser, tree list) +{ + /* The clauses location. */ + location_t loc = c_parser_peek_token (parser)->location; + + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + list = c_parser_omp_variable_list (parser, loc, OMP_CLAUSE_UNIFORM, + list); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + } + return list; +} + /* Parse all OpenMP clauses. The set clauses allowed by the directive is a bitmask in MASK. Return the list of clauses found; the result of clause default goes in *pdefault. */ static tree -c_parser_omp_all_clauses (c_parser *parser, unsigned int mask, - const char *where) +c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, + const char *where, bool finish_p = true) { tree clauses = NULL; bool first = true; @@ -9696,7 +10461,6 @@ c_parser_omp_all_clauses (c_parser *parser, unsigned int mask, if (!first && c_parser_next_token_is (parser, CPP_COMMA)) c_parser_consume_token (parser); - first = false; here = c_parser_peek_token (parser)->location; c_kind = c_parser_omp_clause_name (parser); @@ -9770,11 +10534,116 @@ c_parser_omp_all_clauses (c_parser *parser, unsigned int mask, clauses = c_parser_omp_clause_untied (parser, clauses); c_name = "untied"; break; + case PRAGMA_OMP_CLAUSE_INBRANCH: + clauses = c_parser_omp_clause_branch (parser, OMP_CLAUSE_INBRANCH, + clauses); + c_name = "inbranch"; + break; + case PRAGMA_OMP_CLAUSE_NOTINBRANCH: + clauses = c_parser_omp_clause_branch (parser, OMP_CLAUSE_NOTINBRANCH, + clauses); + c_name = "notinbranch"; + break; + case PRAGMA_OMP_CLAUSE_PARALLEL: + clauses + = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_PARALLEL, + clauses); + c_name = "parallel"; + if (!first) + { + clause_not_first: + error_at (here, "%qs must be the first clause of %qs", + c_name, where); + clauses = prev; + } + break; + case PRAGMA_OMP_CLAUSE_FOR: + clauses + = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_FOR, + clauses); + c_name = "for"; + if (!first) + goto clause_not_first; + break; + case PRAGMA_OMP_CLAUSE_SECTIONS: + clauses + = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_SECTIONS, + clauses); + c_name = "sections"; + if (!first) + goto clause_not_first; + break; + case PRAGMA_OMP_CLAUSE_TASKGROUP: + clauses + = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_TASKGROUP, + clauses); + c_name = "taskgroup"; + if (!first) + goto clause_not_first; + break; + case PRAGMA_OMP_CLAUSE_TO: + clauses = c_parser_omp_clause_to (parser, clauses); + c_name = "to"; + break; + case PRAGMA_OMP_CLAUSE_FROM: + clauses = c_parser_omp_clause_from (parser, clauses); + c_name = "from"; + break; + case PRAGMA_OMP_CLAUSE_UNIFORM: + clauses = c_parser_omp_clause_uniform (parser, clauses); + c_name = "uniform"; + break; + case PRAGMA_OMP_CLAUSE_NUM_TEAMS: + clauses = c_parser_omp_clause_num_teams (parser, clauses); + c_name = "num_teams"; + break; + case PRAGMA_OMP_CLAUSE_THREAD_LIMIT: + clauses = c_parser_omp_clause_thread_limit (parser, clauses); + c_name = "thread_limit"; + break; + case PRAGMA_OMP_CLAUSE_ALIGNED: + clauses = c_parser_omp_clause_aligned (parser, clauses); + c_name = "aligned"; + break; + case PRAGMA_OMP_CLAUSE_LINEAR: + clauses = c_parser_omp_clause_linear (parser, clauses); + c_name = "linear"; + break; + case PRAGMA_OMP_CLAUSE_DEPEND: + clauses = c_parser_omp_clause_depend (parser, clauses); + c_name = "depend"; + break; + case PRAGMA_OMP_CLAUSE_MAP: + clauses = c_parser_omp_clause_map (parser, clauses); + c_name = "map"; + break; + case PRAGMA_OMP_CLAUSE_DEVICE: + clauses = c_parser_omp_clause_device (parser, clauses); + c_name = "device"; + break; + case PRAGMA_OMP_CLAUSE_DIST_SCHEDULE: + clauses = c_parser_omp_clause_dist_schedule (parser, clauses); + c_name = "dist_schedule"; + break; + case PRAGMA_OMP_CLAUSE_PROC_BIND: + clauses = c_parser_omp_clause_proc_bind (parser, clauses); + c_name = "proc_bind"; + break; + case PRAGMA_OMP_CLAUSE_SAFELEN: + clauses = c_parser_omp_clause_safelen (parser, clauses); + c_name = "safelen"; + break; + case PRAGMA_OMP_CLAUSE_SIMDLEN: + clauses = c_parser_omp_clause_simdlen (parser, clauses); + c_name = "simdlen"; + break; default: c_parser_error (parser, "expected %<#pragma omp%> clause"); goto saw_error; } + first = false; + if (((mask >> c_kind) & 1) == 0 && !parser->error) { /* Remove the invalid clause(s) from the list to avoid @@ -9787,7 +10656,10 @@ c_parser_omp_all_clauses (c_parser *parser, unsigned int mask, saw_error: c_parser_skip_to_pragma_eol (parser); - return c_finish_omp_clauses (clauses); + if (finish_p) + return c_finish_omp_clauses (clauses); + + return clauses; } /* OpenMP 2.5: @@ -9843,10 +10715,18 @@ c_parser_omp_structured_block (c_parser *parser) update-stmt: expression-stmt | x = x binop expr capture-stmt: - v = x binop= expr | v = x++ | v = ++x | v = x-- | v = --x + v = expression-stmt capture-block: { v = x; update-stmt; } | { update-stmt; v = x; } + OpenMP 4.0: + update-stmt: + expression-stmt | x = x binop expr | x = expr binop x + capture-stmt: + v = update-stmt + capture-block: + { v = x; update-stmt; } | { update-stmt; v = x; } | { v = x; x = expr; } + where x and v are lvalue expressions with scalar type. LOC is the location of the #pragma token. */ @@ -9856,10 +10736,13 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) { tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE; tree lhs1 = NULL_TREE, rhs1 = NULL_TREE; - tree stmt, orig_lhs; + tree stmt, orig_lhs, unfolded_lhs = NULL_TREE, unfolded_lhs1 = NULL_TREE; enum tree_code code = OMP_ATOMIC, opcode = NOP_EXPR; - struct c_expr rhs_expr; + struct c_expr expr; + location_t eloc; bool structured_block = false; + bool swapped = false; + bool seq_cst = false; if (c_parser_next_token_is (parser, CPP_NAME)) { @@ -9878,6 +10761,15 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) if (p) c_parser_consume_token (parser); } + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (!strcmp (p, "seq_cst")) + { + seq_cst = true; + c_parser_consume_token (parser); + } + } c_parser_skip_to_pragma_eol (parser); switch (code) @@ -9931,7 +10823,11 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) /* For structured_block case we don't know yet whether old or new x should be captured. */ restart: - lhs = c_parser_unary_expression (parser).value; + eloc = c_parser_peek_token (parser)->location; + expr = c_parser_unary_expression (parser); + lhs = expr.value; + expr = default_function_array_conversion (eloc, expr); + unfolded_lhs = expr.value; lhs = c_fully_fold (lhs, false, NULL); orig_lhs = lhs; switch (TREE_CODE (lhs)) @@ -9958,6 +10854,7 @@ restart: /* FALLTHROUGH */ case PREINCREMENT_EXPR: lhs = TREE_OPERAND (lhs, 0); + unfolded_lhs = NULL_TREE; opcode = PLUS_EXPR; rhs = integer_one_node; break; @@ -9968,6 +10865,7 @@ restart: /* FALLTHROUGH */ case PREDECREMENT_EXPR: lhs = TREE_OPERAND (lhs, 0); + unfolded_lhs = NULL_TREE; opcode = MINUS_EXPR; rhs = integer_one_node; break; @@ -9993,6 +10891,7 @@ restart: /* This is pre or post increment. */ rhs = TREE_OPERAND (lhs, 1); lhs = TREE_OPERAND (lhs, 0); + unfolded_lhs = NULL_TREE; opcode = NOP_EXPR; if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block @@ -10007,6 +10906,7 @@ restart: /* This is pre or post decrement. */ rhs = TREE_OPERAND (lhs, 1); lhs = TREE_OPERAND (lhs, 0); + unfolded_lhs = NULL_TREE; opcode = NOP_EXPR; if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block @@ -10047,87 +10947,67 @@ restart: opcode = BIT_XOR_EXPR; break; case CPP_EQ: - if (structured_block || code == OMP_ATOMIC) + c_parser_consume_token (parser); + eloc = c_parser_peek_token (parser)->location; + expr = c_parser_expr_no_commas (parser, NULL, unfolded_lhs); + rhs1 = expr.value; + switch (TREE_CODE (rhs1)) { - location_t aloc = c_parser_peek_token (parser)->location; - location_t rhs_loc; - enum c_parser_prec oprec = PREC_NONE; - - c_parser_consume_token (parser); - rhs1 = c_parser_unary_expression (parser).value; - rhs1 = c_fully_fold (rhs1, false, NULL); - if (rhs1 == error_mark_node) - goto saw_error; - switch (c_parser_peek_token (parser)->type) + case MULT_EXPR: + case TRUNC_DIV_EXPR: + case PLUS_EXPR: + case MINUS_EXPR: + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case BIT_AND_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + if (c_tree_equal (TREE_OPERAND (rhs1, 0), unfolded_lhs)) { - case CPP_SEMICOLON: - if (code == OMP_ATOMIC_CAPTURE_NEW) - { - code = OMP_ATOMIC_CAPTURE_OLD; - v = lhs; - lhs = NULL_TREE; - lhs1 = rhs1; - rhs1 = NULL_TREE; - c_parser_consume_token (parser); - goto restart; - } - c_parser_error (parser, - "invalid form of %<#pragma omp atomic%>"); - goto saw_error; - case CPP_MULT: - opcode = MULT_EXPR; - oprec = PREC_MULT; - break; - case CPP_DIV: - opcode = TRUNC_DIV_EXPR; - oprec = PREC_MULT; - break; - case CPP_PLUS: - opcode = PLUS_EXPR; - oprec = PREC_ADD; - break; - case CPP_MINUS: - opcode = MINUS_EXPR; - oprec = PREC_ADD; - break; - case CPP_LSHIFT: - opcode = LSHIFT_EXPR; - oprec = PREC_SHIFT; - break; - case CPP_RSHIFT: - opcode = RSHIFT_EXPR; - oprec = PREC_SHIFT; - break; - case CPP_AND: - opcode = BIT_AND_EXPR; - oprec = PREC_BITAND; - break; - case CPP_OR: - opcode = BIT_IOR_EXPR; - oprec = PREC_BITOR; - break; - case CPP_XOR: - opcode = BIT_XOR_EXPR; - oprec = PREC_BITXOR; - break; - default: - c_parser_error (parser, - "invalid operator for %<#pragma omp atomic%>"); - goto saw_error; + opcode = TREE_CODE (rhs1); + rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL); + rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 0), false, NULL); + goto stmt_done; } - loc = aloc; - c_parser_consume_token (parser); - rhs_loc = c_parser_peek_token (parser)->location; - if (commutative_tree_code (opcode)) - oprec = (enum c_parser_prec) (oprec - 1); - rhs_expr = c_parser_binary_expression (parser, NULL, oprec); - rhs_expr = default_function_array_read_conversion (rhs_loc, - rhs_expr); - rhs = rhs_expr.value; - rhs = c_fully_fold (rhs, false, NULL); - goto stmt_done; - } - /* FALLTHROUGH */ + if (c_tree_equal (TREE_OPERAND (rhs1, 1), unfolded_lhs)) + { + opcode = TREE_CODE (rhs1); + rhs = c_fully_fold (TREE_OPERAND (rhs1, 0), false, NULL); + rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL); + swapped = !commutative_tree_code (opcode); + goto stmt_done; + } + break; + case ERROR_MARK: + goto saw_error; + default: + break; + } + if (c_parser_peek_token (parser)->type == CPP_SEMICOLON) + { + if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW) + { + code = OMP_ATOMIC_CAPTURE_OLD; + v = lhs; + lhs = NULL_TREE; + expr = default_function_array_read_conversion (eloc, expr); + unfolded_lhs1 = expr.value; + lhs1 = c_fully_fold (unfolded_lhs1, false, NULL); + rhs1 = NULL_TREE; + c_parser_consume_token (parser); + goto restart; + } + if (structured_block) + { + opcode = NOP_EXPR; + expr = default_function_array_read_conversion (eloc, expr); + rhs = c_fully_fold (expr.value, false, NULL); + rhs1 = NULL_TREE; + goto stmt_done; + } + } + c_parser_error (parser, "invalid form of %<#pragma omp atomic%>"); + goto saw_error; default: c_parser_error (parser, "invalid operator for %<#pragma omp atomic%>"); @@ -10138,12 +11018,10 @@ restart: c_finish_omp_atomic. */ loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); - { - location_t rhs_loc = c_parser_peek_token (parser)->location; - rhs_expr = c_parser_expression (parser); - rhs_expr = default_function_array_read_conversion (rhs_loc, rhs_expr); - } - rhs = rhs_expr.value; + eloc = c_parser_peek_token (parser)->location; + expr = c_parser_expression (parser); + expr = default_function_array_read_conversion (eloc, expr); + rhs = expr.value; rhs = c_fully_fold (rhs, false, NULL); break; } @@ -10158,7 +11036,11 @@ stmt_done: goto saw_error; if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) goto saw_error; - lhs1 = c_parser_unary_expression (parser).value; + eloc = c_parser_peek_token (parser)->location; + expr = c_parser_unary_expression (parser); + lhs1 = expr.value; + expr = default_function_array_read_conversion (eloc, expr); + unfolded_lhs1 = expr.value; lhs1 = c_fully_fold (lhs1, false, NULL); if (lhs1 == error_mark_node) goto saw_error; @@ -10169,7 +11051,16 @@ stmt_done: c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>"); } done: - stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1); + if (unfolded_lhs && unfolded_lhs1 + && !c_tree_equal (unfolded_lhs, unfolded_lhs1)) + { + error ("%<#pragma omp atomic capture%> uses two different " + "expressions for memory"); + stmt = error_mark_node; + } + else + stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1, + swapped, seq_cst); if (stmt != error_mark_node) add_stmt (stmt); @@ -10249,8 +11140,8 @@ c_parser_omp_flush (c_parser *parser) LOC is the location of the OMP in "#pragma omp". */ static tree -c_parser_omp_for_loop (location_t loc, - c_parser *parser, tree clauses, tree *par_clauses) +c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, + tree clauses, tree *cclauses) { tree decl, cond, incr, save_break, save_cont, body, init, stmt, cl; tree declv, condv, incrv, initv, ret = NULL; @@ -10290,7 +11181,8 @@ c_parser_omp_for_loop (location_t loc, { if (i > 0) vec_safe_push (for_block, c_begin_compound_stmt (true)); - c_parser_declaration_or_fndef (parser, true, true, true, true, true, NULL); + c_parser_declaration_or_fndef (parser, true, true, true, true, true, + NULL, vNULL); decl = check_for_loop_decls (for_loc, flag_isoc99); if (decl == NULL) goto error_init; @@ -10337,8 +11229,8 @@ c_parser_omp_for_loop (location_t loc, if (c_parser_next_token_is_not (parser, CPP_SEMICOLON)) { location_t cond_loc = c_parser_peek_token (parser)->location; - struct c_expr cond_expr = c_parser_binary_expression (parser, NULL, - PREC_NONE); + struct c_expr cond_expr + = c_parser_binary_expression (parser, NULL, NULL_TREE); cond = cond_expr.value; cond = c_objc_common_truthvalue_conversion (cond_loc, cond); @@ -10477,13 +11369,15 @@ c_parser_omp_for_loop (location_t loc, an error from the initialization parsing. */ if (!fail) { - stmt = c_finish_omp_for (loc, declv, initv, condv, incrv, body, NULL); + stmt = c_finish_omp_for (loc, code, declv, initv, condv, + incrv, body, NULL); if (stmt) { - if (par_clauses != NULL) + if (cclauses != NULL + && cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] != NULL) { tree *c; - for (c = par_clauses; *c ; ) + for (c = &cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; *c ; ) if (OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_FIRSTPRIVATE && OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_LASTPRIVATE) c = &OMP_CLAUSE_CHAIN (*c); @@ -10532,33 +11426,128 @@ pop_scopes: return ret; } +/* Helper function for OpenMP parsing, split clauses and call + finish_omp_clauses on each of the set of clauses afterwards. */ + +static void +omp_split_clauses (location_t loc, enum tree_code code, + omp_clause_mask mask, tree clauses, tree *cclauses) +{ + int i; + c_omp_split_clauses (loc, code, mask, clauses, cclauses); + for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++) + if (cclauses[i]) + cclauses[i] = c_finish_omp_clauses (cclauses[i]); +} + +/* OpenMP 4.0: + #pragma omp simd simd-clause[optseq] new-line + for-loop + + LOC is the location of the #pragma token. +*/ + +#define OMP_SIMD_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SAFELEN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE)) + +static tree +c_parser_omp_simd (location_t loc, c_parser *parser, + char *p_name, omp_clause_mask mask, tree *cclauses) +{ + tree block, clauses, ret; + + strcat (p_name, " simd"); + mask |= OMP_SIMD_CLAUSE_MASK; + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED); + + clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); + if (cclauses) + { + omp_split_clauses (loc, OMP_SIMD, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_SIMD]; + } + + block = c_begin_compound_stmt (true); + ret = c_parser_omp_for_loop (loc, parser, OMP_SIMD, clauses, cclauses); + block = c_end_compound_stmt (loc, block, true); + add_stmt (block); + + return ret; +} + /* OpenMP 2.5: #pragma omp for for-clause[optseq] new-line for-loop + OpenMP 4.0: + #pragma omp for simd for-simd-clause[optseq] new-line + for-loop + LOC is the location of the #pragma token. */ -#define OMP_FOR_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ - | (1u << PRAGMA_OMP_CLAUSE_ORDERED) \ - | (1u << PRAGMA_OMP_CLAUSE_SCHEDULE) \ - | (1u << PRAGMA_OMP_CLAUSE_COLLAPSE) \ - | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) +#define OMP_FOR_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) static tree -c_parser_omp_for (location_t loc, c_parser *parser) +c_parser_omp_for (location_t loc, c_parser *parser, + char *p_name, omp_clause_mask mask, tree *cclauses) { tree block, clauses, ret; - clauses = c_parser_omp_all_clauses (parser, OMP_FOR_CLAUSE_MASK, - "#pragma omp for"); + strcat (p_name, " for"); + mask |= OMP_FOR_CLAUSE_MASK; + if (cclauses) + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + if (strcmp (p, "simd") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + + c_parser_consume_token (parser); + block = c_begin_compound_stmt (true); + ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses); + block = c_end_compound_stmt (loc, block, true); + if (ret == NULL_TREE) + return ret; + ret = make_node (OMP_FOR); + TREE_TYPE (ret) = void_type_node; + OMP_FOR_BODY (ret) = block; + OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; + SET_EXPR_LOCATION (ret, loc); + add_stmt (ret); + return ret; + } + } + + clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); + if (cclauses) + { + omp_split_clauses (loc, OMP_FOR, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; + } block = c_begin_compound_stmt (true); - ret = c_parser_omp_for_loop (loc, parser, clauses, NULL); + ret = c_parser_omp_for_loop (loc, parser, OMP_FOR, clauses, cclauses); block = c_end_compound_stmt (loc, block, true); add_stmt (block); @@ -10623,21 +11612,7 @@ c_parser_omp_sections_scope (location_t sections_loc, c_parser *parser) if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_SECTION) { - substmt = push_stmt_list (); - - while (1) - { - c_parser_statement (parser); - - if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION) - break; - if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) - break; - if (c_parser_next_token_is (parser, CPP_EOF)) - break; - } - - substmt = pop_stmt_list (substmt); + substmt = c_parser_omp_structured_block (parser); substmt = build1 (OMP_SECTION, void_type_node, substmt); SET_EXPR_LOCATION (substmt, loc); add_stmt (substmt); @@ -10688,20 +11663,30 @@ c_parser_omp_sections_scope (location_t sections_loc, c_parser *parser) LOC is the location of the #pragma token. */ -#define OMP_SECTIONS_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ - | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) +#define OMP_SECTIONS_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) static tree -c_parser_omp_sections (location_t loc, c_parser *parser) +c_parser_omp_sections (location_t loc, c_parser *parser, + char *p_name, omp_clause_mask mask, tree *cclauses) { tree block, clauses, ret; - clauses = c_parser_omp_all_clauses (parser, OMP_SECTIONS_CLAUSE_MASK, - "#pragma omp sections"); + strcat (p_name, " sections"); + mask |= OMP_SECTIONS_CLAUSE_MASK; + if (cclauses) + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); + + clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); + if (cclauses) + { + omp_split_clauses (loc, OMP_SECTIONS, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_SECTIONS]; + } block = c_begin_compound_stmt (true); ret = c_parser_omp_sections_scope (loc, parser); @@ -10721,76 +11706,72 @@ c_parser_omp_sections (location_t loc, c_parser *parser) LOC is the location of the #pragma token. */ -#define OMP_PARALLEL_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_IF) \ - | (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \ - | (1u << PRAGMA_OMP_CLAUSE_SHARED) \ - | (1u << PRAGMA_OMP_CLAUSE_COPYIN) \ - | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ - | (1u << PRAGMA_OMP_CLAUSE_NUM_THREADS)) +#define OMP_PARALLEL_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PROC_BIND)) static tree -c_parser_omp_parallel (location_t loc, c_parser *parser) +c_parser_omp_parallel (location_t loc, c_parser *parser, + char *p_name, omp_clause_mask mask, tree *cclauses) { - enum pragma_kind p_kind = PRAGMA_OMP_PARALLEL; - const char *p_name = "#pragma omp parallel"; - tree stmt, clauses, par_clause, ws_clause, block; - unsigned int mask = OMP_PARALLEL_CLAUSE_MASK; + tree stmt, clauses, block; + + strcat (p_name, " parallel"); + mask |= OMP_PARALLEL_CLAUSE_MASK; if (c_parser_next_token_is_keyword (parser, RID_FOR)) { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + c_parser_consume_token (parser); - p_kind = PRAGMA_OMP_PARALLEL_FOR; - p_name = "#pragma omp parallel for"; - mask |= OMP_FOR_CLAUSE_MASK; - mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT); + block = c_begin_omp_parallel (); + c_parser_omp_for (loc, parser, p_name, mask, cclauses); + stmt + = c_finish_omp_parallel (loc, cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], + block); + OMP_PARALLEL_COMBINED (stmt) = 1; + return stmt; + } + else if (cclauses) + { + error_at (loc, "expected %<for%> after %qs", p_name); + c_parser_skip_to_pragma_eol (parser); + return NULL_TREE; } else if (c_parser_next_token_is (parser, CPP_NAME)) { const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); if (strcmp (p, "sections") == 0) { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + c_parser_consume_token (parser); - p_kind = PRAGMA_OMP_PARALLEL_SECTIONS; - p_name = "#pragma omp parallel sections"; - mask |= OMP_SECTIONS_CLAUSE_MASK; - mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT); + block = c_begin_omp_parallel (); + c_parser_omp_sections (loc, parser, p_name, mask, cclauses); + stmt = c_finish_omp_parallel (loc, + cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], + block); + OMP_PARALLEL_COMBINED (stmt) = 1; + return stmt; } } - clauses = c_parser_omp_all_clauses (parser, mask, p_name); - - switch (p_kind) - { - case PRAGMA_OMP_PARALLEL: - block = c_begin_omp_parallel (); - c_parser_statement (parser); - stmt = c_finish_omp_parallel (loc, clauses, block); - break; - - case PRAGMA_OMP_PARALLEL_FOR: - block = c_begin_omp_parallel (); - c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause); - c_parser_omp_for_loop (loc, parser, ws_clause, &par_clause); - stmt = c_finish_omp_parallel (loc, par_clause, block); - OMP_PARALLEL_COMBINED (stmt) = 1; - break; + clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); - case PRAGMA_OMP_PARALLEL_SECTIONS: - block = c_begin_omp_parallel (); - c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause); - stmt = c_parser_omp_sections_scope (loc, parser); - if (stmt) - OMP_SECTIONS_CLAUSES (stmt) = ws_clause; - stmt = c_finish_omp_parallel (loc, par_clause, block); - OMP_PARALLEL_COMBINED (stmt) = 1; - break; - - default: - gcc_unreachable (); - } + block = c_begin_omp_parallel (); + c_parser_statement (parser); + stmt = c_finish_omp_parallel (loc, clauses, block); return stmt; } @@ -10802,11 +11783,11 @@ c_parser_omp_parallel (location_t loc, c_parser *parser) LOC is the location of the #pragma. */ -#define OMP_SINGLE_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) +#define OMP_SINGLE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) static tree c_parser_omp_single (location_t loc, c_parser *parser) @@ -10829,15 +11810,16 @@ c_parser_omp_single (location_t loc, c_parser *parser) LOC is the location of the #pragma. */ -#define OMP_TASK_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_IF) \ - | (1u << PRAGMA_OMP_CLAUSE_UNTIED) \ - | (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \ - | (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_SHARED) \ - | (1u << PRAGMA_OMP_CLAUSE_FINAL) \ - | (1u << PRAGMA_OMP_CLAUSE_MERGEABLE)) +#define OMP_TASK_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNTIED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FINAL) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)) static tree c_parser_omp_task (location_t loc, c_parser *parser) @@ -10880,6 +11862,983 @@ c_parser_omp_taskyield (c_parser *parser) c_finish_omp_taskyield (loc); } +/* OpenMP 4.0: + # pragma omp taskgroup new-line +*/ + +static tree +c_parser_omp_taskgroup (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_skip_to_pragma_eol (parser); + return c_finish_omp_taskgroup (loc, c_parser_omp_structured_block (parser)); +} + +/* OpenMP 4.0: + # pragma omp cancel cancel-clause[optseq] new-line + + LOC is the location of the #pragma. +*/ + +#define OMP_CANCEL_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARALLEL) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FOR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)) + +static void +c_parser_omp_cancel (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + + c_parser_consume_pragma (parser); + tree clauses = c_parser_omp_all_clauses (parser, OMP_CANCEL_CLAUSE_MASK, + "#pragma omp cancel"); + + c_finish_omp_cancel (loc, clauses); +} + +/* OpenMP 4.0: + # pragma omp cancellation point cancelpt-clause[optseq] new-line + + LOC is the location of the #pragma. +*/ + +#define OMP_CANCELLATION_POINT_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARALLEL) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FOR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP)) + +static void +c_parser_omp_cancellation_point (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + tree clauses; + bool point_seen = false; + + c_parser_consume_pragma (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "point") == 0) + { + c_parser_consume_token (parser); + point_seen = true; + } + } + if (!point_seen) + { + c_parser_error (parser, "expected %<point%>"); + c_parser_skip_to_pragma_eol (parser); + return; + } + + clauses + = c_parser_omp_all_clauses (parser, OMP_CANCELLATION_POINT_CLAUSE_MASK, + "#pragma omp cancellation point"); + + c_finish_omp_cancellation_point (loc, clauses); +} + +/* OpenMP 4.0: + #pragma omp distribute distribute-clause[optseq] new-line + for-loop */ + +#define OMP_DISTRIBUTE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)\ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE)) + +static tree +c_parser_omp_distribute (location_t loc, c_parser *parser, + char *p_name, omp_clause_mask mask, tree *cclauses) +{ + tree clauses, block, ret; + + strcat (p_name, " distribute"); + mask |= OMP_DISTRIBUTE_CLAUSE_MASK; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + bool simd = false; + bool parallel = false; + + if (strcmp (p, "simd") == 0) + simd = true; + else + parallel = strcmp (p, "parallel") == 0; + if (parallel || simd) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + c_parser_consume_token (parser); + block = c_begin_compound_stmt (true); + if (simd) + ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses); + else + ret = c_parser_omp_parallel (loc, parser, p_name, mask, cclauses); + block = c_end_compound_stmt (loc, block, true); + if (ret == NULL) + return ret; + ret = make_node (OMP_DISTRIBUTE); + TREE_TYPE (ret) = void_type_node; + OMP_FOR_BODY (ret) = block; + OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE]; + SET_EXPR_LOCATION (ret, loc); + add_stmt (ret); + return ret; + } + } + + clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); + if (cclauses) + { + omp_split_clauses (loc, OMP_DISTRIBUTE, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE]; + } + + block = c_begin_compound_stmt (true); + ret = c_parser_omp_for_loop (loc, parser, OMP_DISTRIBUTE, clauses, NULL); + block = c_end_compound_stmt (loc, block, true); + add_stmt (block); + + return ret; +} + +/* OpenMP 4.0: + # pragma omp teams teams-clause[optseq] new-line + structured-block */ + +#define OMP_TEAMS_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT)) + +static tree +c_parser_omp_teams (location_t loc, c_parser *parser, + char *p_name, omp_clause_mask mask, tree *cclauses) +{ + tree clauses, block, ret; + + strcat (p_name, " teams"); + mask |= OMP_TEAMS_CLAUSE_MASK; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "distribute") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + + c_parser_consume_token (parser); + block = c_begin_compound_stmt (true); + ret = c_parser_omp_distribute (loc, parser, p_name, mask, cclauses); + block = c_end_compound_stmt (loc, block, true); + if (ret == NULL) + return ret; + clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; + ret = make_node (OMP_TEAMS); + TREE_TYPE (ret) = void_type_node; + OMP_TEAMS_CLAUSES (ret) = clauses; + OMP_TEAMS_BODY (ret) = block; + return add_stmt (ret); + } + } + + clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); + if (cclauses) + { + omp_split_clauses (loc, OMP_TEAMS, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; + } + + tree stmt = make_node (OMP_TEAMS); + TREE_TYPE (stmt) = void_type_node; + OMP_TEAMS_CLAUSES (stmt) = clauses; + OMP_TEAMS_BODY (stmt) = c_parser_omp_structured_block (parser); + + return add_stmt (stmt); +} + +/* OpenMP 4.0: + # pragma omp target data target-data-clause[optseq] new-line + structured-block */ + +#define OMP_TARGET_DATA_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)) + +static tree +c_parser_omp_target_data (location_t loc, c_parser *parser) +{ + tree stmt = make_node (OMP_TARGET_DATA); + TREE_TYPE (stmt) = void_type_node; + + OMP_TARGET_DATA_CLAUSES (stmt) + = c_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK, + "#pragma omp target data"); + keep_next_level (); + tree block = c_begin_compound_stmt (true); + add_stmt (c_parser_omp_structured_block (parser)); + OMP_TARGET_DATA_BODY (stmt) = c_end_compound_stmt (loc, block, true); + + SET_EXPR_LOCATION (stmt, loc); + return add_stmt (stmt); +} + +/* OpenMP 4.0: + # pragma omp target update target-update-clause[optseq] new-line */ + +#define OMP_TARGET_UPDATE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FROM) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TO) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)) + +static bool +c_parser_omp_target_update (location_t loc, c_parser *parser, + enum pragma_context context) +{ + if (context == pragma_stmt) + { + error_at (loc, + "%<#pragma omp target update%> may only be " + "used in compound statements"); + c_parser_skip_to_pragma_eol (parser); + return false; + } + + tree clauses + = c_parser_omp_all_clauses (parser, OMP_TARGET_UPDATE_CLAUSE_MASK, + "#pragma omp target update"); + if (find_omp_clause (clauses, OMP_CLAUSE_TO) == NULL_TREE + && find_omp_clause (clauses, OMP_CLAUSE_FROM) == NULL_TREE) + { + error_at (loc, + "%<#pragma omp target update must contain at least one " + "%<from%> or %<to%> clauses"); + return false; + } + + tree stmt = make_node (OMP_TARGET_UPDATE); + TREE_TYPE (stmt) = void_type_node; + OMP_TARGET_UPDATE_CLAUSES (stmt) = clauses; + SET_EXPR_LOCATION (stmt, loc); + add_stmt (stmt); + return false; +} + +/* OpenMP 4.0: + # pragma omp target target-clause[optseq] new-line + structured-block */ + +#define OMP_TARGET_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)) + +static bool +c_parser_omp_target (c_parser *parser, enum pragma_context context) +{ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_pragma (parser); + + if (context != pragma_stmt && context != pragma_compound) + { + c_parser_error (parser, "expected declaration specifiers"); + c_parser_skip_to_pragma_eol (parser); + return false; + } + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + if (strcmp (p, "data") == 0) + { + c_parser_consume_token (parser); + c_parser_omp_target_data (loc, parser); + return true; + } + else if (strcmp (p, "update") == 0) + { + c_parser_consume_token (parser); + return c_parser_omp_target_update (loc, parser, context); + } + else if (strcmp (p, "teams") == 0) + { + tree cclauses[C_OMP_CLAUSE_SPLIT_COUNT]; + char p_name[sizeof ("#pragma omp target teams distribute " + "parallel for simd")]; + + c_parser_consume_token (parser); + strcpy (p_name, "#pragma omp target"); + keep_next_level (); + tree block = c_begin_compound_stmt (true); + tree ret = c_parser_omp_teams (loc, parser, p_name, + OMP_TARGET_CLAUSE_MASK, cclauses); + block = c_end_compound_stmt (loc, block, true); + if (ret == NULL) + return ret; + tree stmt = make_node (OMP_TARGET); + TREE_TYPE (stmt) = void_type_node; + OMP_TARGET_CLAUSES (stmt) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET]; + OMP_TARGET_BODY (stmt) = block; + add_stmt (stmt); + return true; + } + } + + tree stmt = make_node (OMP_TARGET); + TREE_TYPE (stmt) = void_type_node; + + OMP_TARGET_CLAUSES (stmt) + = c_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK, + "#pragma omp target"); + keep_next_level (); + tree block = c_begin_compound_stmt (true); + add_stmt (c_parser_omp_structured_block (parser)); + OMP_TARGET_BODY (stmt) = c_end_compound_stmt (loc, block, true); + + SET_EXPR_LOCATION (stmt, loc); + add_stmt (stmt); + return true; +} + +/* OpenMP 4.0: + # pragma omp declare simd declare-simd-clauses[optseq] new-line */ + +#define OMP_DECLARE_SIMD_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMDLEN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNIFORM) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_INBRANCH) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOTINBRANCH)) + +static void +c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context) +{ + vec<c_token> clauses = vNULL; + while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + { + c_token *token = c_parser_peek_token (parser); + if (token->type == CPP_EOF) + { + c_parser_skip_to_pragma_eol (parser); + clauses.release (); + return; + } + clauses.safe_push (*token); + c_parser_consume_token (parser); + } + clauses.safe_push (*c_parser_peek_token (parser)); + c_parser_skip_to_pragma_eol (parser); + + while (c_parser_next_token_is (parser, CPP_PRAGMA)) + { + if (c_parser_peek_token (parser)->pragma_kind + != PRAGMA_OMP_DECLARE_REDUCTION + || c_parser_peek_2nd_token (parser)->type != CPP_NAME + || strcmp (IDENTIFIER_POINTER + (c_parser_peek_2nd_token (parser)->value), + "simd") != 0) + { + c_parser_error (parser, + "%<#pragma omp declare simd%> must be followed by " + "function declaration or definition or another " + "%<#pragma omp declare simd%>"); + clauses.release (); + return; + } + c_parser_consume_pragma (parser); + while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + { + c_token *token = c_parser_peek_token (parser); + if (token->type == CPP_EOF) + { + c_parser_skip_to_pragma_eol (parser); + clauses.release (); + return; + } + clauses.safe_push (*token); + c_parser_consume_token (parser); + } + clauses.safe_push (*c_parser_peek_token (parser)); + c_parser_skip_to_pragma_eol (parser); + } + + /* Make sure nothing tries to read past the end of the tokens. */ + c_token eof_token; + memset (&eof_token, 0, sizeof (eof_token)); + eof_token.type = CPP_EOF; + clauses.safe_push (eof_token); + clauses.safe_push (eof_token); + + switch (context) + { + case pragma_external: + if (c_parser_next_token_is (parser, CPP_KEYWORD) + && c_parser_peek_token (parser)->keyword == RID_EXTENSION) + { + int ext = disable_extension_diagnostics (); + do + c_parser_consume_token (parser); + while (c_parser_next_token_is (parser, CPP_KEYWORD) + && c_parser_peek_token (parser)->keyword == RID_EXTENSION); + c_parser_declaration_or_fndef (parser, true, true, true, false, true, + NULL, clauses); + restore_extension_diagnostics (ext); + } + else + c_parser_declaration_or_fndef (parser, true, true, true, false, true, + NULL, clauses); + break; + case pragma_struct: + case pragma_param: + c_parser_error (parser, "%<#pragma omp declare simd%> must be followed by " + "function declaration or definition"); + break; + case pragma_compound: + case pragma_stmt: + if (c_parser_next_token_is (parser, CPP_KEYWORD) + && c_parser_peek_token (parser)->keyword == RID_EXTENSION) + { + int ext = disable_extension_diagnostics (); + do + c_parser_consume_token (parser); + while (c_parser_next_token_is (parser, CPP_KEYWORD) + && c_parser_peek_token (parser)->keyword == RID_EXTENSION); + if (c_parser_next_tokens_start_declaration (parser)) + { + c_parser_declaration_or_fndef (parser, true, true, true, true, + true, NULL, clauses); + restore_extension_diagnostics (ext); + break; + } + restore_extension_diagnostics (ext); + } + else if (c_parser_next_tokens_start_declaration (parser)) + { + c_parser_declaration_or_fndef (parser, true, true, true, true, true, + NULL, clauses); + break; + } + c_parser_error (parser, "%<#pragma omp declare simd%> must be followed by " + "function declaration or definition"); + break; + default: + gcc_unreachable (); + } + clauses.release (); +} + +/* Finalize #pragma omp declare simd clauses after FNDECL has been parsed, + and put that into "omp declare simd" attribute. */ + +static void +c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms, + vec<c_token> clauses) +{ + /* Normally first token is CPP_NAME "simd". CPP_EOF there indicates + error has been reported and CPP_PRAGMA that c_finish_omp_declare_simd + has already processed the tokens. */ + if (clauses[0].type == CPP_EOF) + return; + if (fndecl == NULL_TREE || TREE_CODE (fndecl) != FUNCTION_DECL) + { + error ("%<#pragma omp declare simd%> not immediately followed by " + "a function declaration or definition"); + clauses[0].type = CPP_EOF; + return; + } + if (clauses[0].type != CPP_NAME) + { + error_at (DECL_SOURCE_LOCATION (fndecl), + "%<#pragma omp declare simd%> not immediately followed by " + "a single function declaration or definition"); + clauses[0].type = CPP_EOF; + return; + } + + if (parms == NULL_TREE) + parms = DECL_ARGUMENTS (fndecl); + + unsigned int tokens_avail = parser->tokens_avail; + gcc_assert (parser->tokens == &parser->tokens_buf[0]); + parser->tokens = clauses.address (); + parser->tokens_avail = clauses.length (); + + /* c_parser_omp_declare_simd pushed 2 extra CPP_EOF tokens at the end. */ + while (parser->tokens_avail > 3) + { + c_token *token = c_parser_peek_token (parser); + gcc_assert (token->type == CPP_NAME + && strcmp (IDENTIFIER_POINTER (token->value), "simd") == 0); + c_parser_consume_token (parser); + parser->in_pragma = true; + + tree c = c_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK, + "#pragma omp declare simd"); + c = c_omp_declare_simd_clauses_to_numbers (parms, c); + if (c != NULL_TREE) + c = tree_cons (NULL_TREE, c, NULL_TREE); + c = build_tree_list (get_identifier ("omp declare simd"), c); + TREE_CHAIN (c) = DECL_ATTRIBUTES (fndecl); + DECL_ATTRIBUTES (fndecl) = c; + } + + parser->tokens = &parser->tokens_buf[0]; + parser->tokens_avail = tokens_avail; + clauses[0].type = CPP_PRAGMA; +} + + +/* OpenMP 4.0: + # pragma omp declare target new-line + declarations and definitions + # pragma omp end declare target new-line */ + +static void +c_parser_omp_declare_target (c_parser *parser) +{ + c_parser_skip_to_pragma_eol (parser); + current_omp_declare_target_attribute++; +} + +static void +c_parser_omp_end_declare_target (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_pragma (parser); + if (c_parser_next_token_is (parser, CPP_NAME) + && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), + "declare") == 0) + { + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_NAME) + && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), + "target") == 0) + c_parser_consume_token (parser); + else + { + c_parser_error (parser, "expected %<target%>"); + c_parser_skip_to_pragma_eol (parser); + return; + } + } + else + { + c_parser_error (parser, "expected %<declare%>"); + c_parser_skip_to_pragma_eol (parser); + return; + } + c_parser_skip_to_pragma_eol (parser); + if (!current_omp_declare_target_attribute) + error_at (loc, "%<#pragma omp end declare target%> without corresponding " + "%<#pragma omp declare target%>"); + else + current_omp_declare_target_attribute--; +} + + +/* OpenMP 4.0 + #pragma omp declare reduction (reduction-id : typename-list : expression) \ + initializer-clause[opt] new-line + + initializer-clause: + initializer (omp_priv = initializer) + initializer (function-name (argument-list)) */ + +static void +c_parser_omp_declare_reduction (c_parser *parser, enum pragma_context context) +{ + unsigned int tokens_avail = 0, i; + vec<tree> types = vNULL; + vec<c_token> clauses = vNULL; + enum tree_code reduc_code = ERROR_MARK; + tree reduc_id = NULL_TREE; + tree type; + location_t rloc = c_parser_peek_token (parser)->location; + + if (context == pragma_struct || context == pragma_param) + { + error ("%<#pragma omp declare reduction%> not at file or block scope"); + goto fail; + } + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + goto fail; + + switch (c_parser_peek_token (parser)->type) + { + case CPP_PLUS: + reduc_code = PLUS_EXPR; + break; + case CPP_MULT: + reduc_code = MULT_EXPR; + break; + case CPP_MINUS: + reduc_code = MINUS_EXPR; + break; + case CPP_AND: + reduc_code = BIT_AND_EXPR; + break; + case CPP_XOR: + reduc_code = BIT_XOR_EXPR; + break; + case CPP_OR: + reduc_code = BIT_IOR_EXPR; + break; + case CPP_AND_AND: + reduc_code = TRUTH_ANDIF_EXPR; + break; + case CPP_OR_OR: + reduc_code = TRUTH_ORIF_EXPR; + break; + case CPP_NAME: + const char *p; + p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "min") == 0) + { + reduc_code = MIN_EXPR; + break; + } + if (strcmp (p, "max") == 0) + { + reduc_code = MAX_EXPR; + break; + } + reduc_id = c_parser_peek_token (parser)->value; + break; + default: + c_parser_error (parser, + "expected %<+%>, %<*%>, %<-%>, %<&%>, " + "%<^%>, %<|%>, %<&&%>, %<||%>, %<min%> or identifier"); + goto fail; + } + + tree orig_reduc_id, reduc_decl; + orig_reduc_id = reduc_id; + reduc_id = c_omp_reduction_id (reduc_code, reduc_id); + reduc_decl = c_omp_reduction_decl (reduc_id); + c_parser_consume_token (parser); + + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + goto fail; + + while (true) + { + location_t loc = c_parser_peek_token (parser)->location; + struct c_type_name *ctype = c_parser_type_name (parser); + if (ctype != NULL) + { + type = groktypename (ctype, NULL, NULL); + if (type == error_mark_node) + ; + else if ((INTEGRAL_TYPE_P (type) + || TREE_CODE (type) == REAL_TYPE + || TREE_CODE (type) == COMPLEX_TYPE) + && orig_reduc_id == NULL_TREE) + error_at (loc, "predeclared arithmetic type in " + "%<#pragma omp declare reduction%>"); + else if (TREE_CODE (type) == FUNCTION_TYPE + || TREE_CODE (type) == ARRAY_TYPE) + error_at (loc, "function or array type in " + "%<#pragma omp declare reduction%>"); + else if (TYPE_QUALS_NO_ADDR_SPACE (type)) + error_at (loc, "const, volatile or restrict qualified type in " + "%<#pragma omp declare reduction%>"); + else + { + tree t; + for (t = DECL_INITIAL (reduc_decl); t; t = TREE_CHAIN (t)) + if (comptypes (TREE_PURPOSE (t), type)) + { + error_at (loc, "redeclaration of %qs " + "%<#pragma omp declare reduction%> for " + "type %qT", + IDENTIFIER_POINTER (reduc_id) + + sizeof ("omp declare reduction ") - 1, + type); + location_t ploc + = DECL_SOURCE_LOCATION (TREE_VEC_ELT (TREE_VALUE (t), + 0)); + error_at (ploc, "previous %<#pragma omp declare " + "reduction%>"); + break; + } + if (t == NULL_TREE) + types.safe_push (type); + } + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + else + break; + } + + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>") + || types.is_empty ()) + { + fail: + clauses.release (); + types.release (); + while (true) + { + c_token *token = c_parser_peek_token (parser); + if (token->type == CPP_EOF || token->type == CPP_PRAGMA_EOL) + break; + c_parser_consume_token (parser); + } + c_parser_skip_to_pragma_eol (parser); + return; + } + + if (types.length () > 1) + { + while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + { + c_token *token = c_parser_peek_token (parser); + if (token->type == CPP_EOF) + goto fail; + clauses.safe_push (*token); + c_parser_consume_token (parser); + } + clauses.safe_push (*c_parser_peek_token (parser)); + c_parser_skip_to_pragma_eol (parser); + + /* Make sure nothing tries to read past the end of the tokens. */ + c_token eof_token; + memset (&eof_token, 0, sizeof (eof_token)); + eof_token.type = CPP_EOF; + clauses.safe_push (eof_token); + clauses.safe_push (eof_token); + } + + int errs = errorcount; + FOR_EACH_VEC_ELT (types, i, type) + { + tokens_avail = parser->tokens_avail; + gcc_assert (parser->tokens == &parser->tokens_buf[0]); + if (!clauses.is_empty ()) + { + parser->tokens = clauses.address (); + parser->tokens_avail = clauses.length (); + parser->in_pragma = true; + } + + bool nested = current_function_decl != NULL_TREE; + if (nested) + c_push_function_context (); + tree fndecl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL, + reduc_id, default_function_type); + current_function_decl = fndecl; + allocate_struct_function (fndecl, true); + push_scope (); + tree stmt = push_stmt_list (); + /* Intentionally BUILTINS_LOCATION, so that -Wshadow doesn't + warn about these. */ + tree omp_out = build_decl (BUILTINS_LOCATION, VAR_DECL, + get_identifier ("omp_out"), type); + DECL_ARTIFICIAL (omp_out) = 1; + DECL_CONTEXT (omp_out) = fndecl; + pushdecl (omp_out); + tree omp_in = build_decl (BUILTINS_LOCATION, VAR_DECL, + get_identifier ("omp_in"), type); + DECL_ARTIFICIAL (omp_in) = 1; + DECL_CONTEXT (omp_in) = fndecl; + pushdecl (omp_in); + struct c_expr combiner = c_parser_expression (parser); + struct c_expr initializer; + tree omp_priv = NULL_TREE, omp_orig = NULL_TREE; + bool bad = false; + initializer.value = error_mark_node; + if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + bad = true; + else if (c_parser_next_token_is (parser, CPP_NAME) + && strcmp (IDENTIFIER_POINTER + (c_parser_peek_token (parser)->value), + "initializer") == 0) + { + c_parser_consume_token (parser); + pop_scope (); + push_scope (); + omp_priv = build_decl (BUILTINS_LOCATION, VAR_DECL, + get_identifier ("omp_priv"), type); + DECL_ARTIFICIAL (omp_priv) = 1; + DECL_INITIAL (omp_priv) = error_mark_node; + DECL_CONTEXT (omp_priv) = fndecl; + pushdecl (omp_priv); + omp_orig = build_decl (BUILTINS_LOCATION, VAR_DECL, + get_identifier ("omp_orig"), type); + DECL_ARTIFICIAL (omp_orig) = 1; + DECL_CONTEXT (omp_orig) = fndecl; + pushdecl (omp_orig); + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + bad = true; + else if (!c_parser_next_token_is (parser, CPP_NAME)) + { + c_parser_error (parser, "expected %<omp_priv%> or " + "function-name"); + bad = true; + } + else if (strcmp (IDENTIFIER_POINTER + (c_parser_peek_token (parser)->value), + "omp_priv") != 0) + { + if (c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN + || c_parser_peek_token (parser)->id_kind != C_ID_ID) + { + c_parser_error (parser, "expected function-name %<(%>"); + bad = true; + } + else + initializer = c_parser_postfix_expression (parser); + if (initializer.value + && TREE_CODE (initializer.value) == CALL_EXPR) + { + int j; + tree c = initializer.value; + for (j = 0; j < call_expr_nargs (c); j++) + if (TREE_CODE (CALL_EXPR_ARG (c, j)) == ADDR_EXPR + && TREE_OPERAND (CALL_EXPR_ARG (c, j), 0) == omp_priv) + break; + if (j == call_expr_nargs (c)) + error ("one of the initializer call arguments should be " + "%<&omp_priv%>"); + } + } + else + { + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) + bad = true; + else + { + tree st = push_stmt_list (); + start_init (omp_priv, NULL_TREE, 0); + location_t loc = c_parser_peek_token (parser)->location; + struct c_expr init = c_parser_initializer (parser); + finish_init (); + finish_decl (omp_priv, loc, init.value, + init.original_type, NULL_TREE); + pop_stmt_list (st); + } + } + if (!bad + && !c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + bad = true; + } + + if (!bad) + { + c_parser_skip_to_pragma_eol (parser); + + tree t = tree_cons (type, make_tree_vec (omp_priv ? 6 : 3), + DECL_INITIAL (reduc_decl)); + DECL_INITIAL (reduc_decl) = t; + DECL_SOURCE_LOCATION (omp_out) = rloc; + TREE_VEC_ELT (TREE_VALUE (t), 0) = omp_out; + TREE_VEC_ELT (TREE_VALUE (t), 1) = omp_in; + TREE_VEC_ELT (TREE_VALUE (t), 2) = combiner.value; + walk_tree (&combiner.value, c_check_omp_declare_reduction_r, + &TREE_VEC_ELT (TREE_VALUE (t), 0), NULL); + if (omp_priv) + { + DECL_SOURCE_LOCATION (omp_priv) = rloc; + TREE_VEC_ELT (TREE_VALUE (t), 3) = omp_priv; + TREE_VEC_ELT (TREE_VALUE (t), 4) = omp_orig; + TREE_VEC_ELT (TREE_VALUE (t), 5) = initializer.value; + walk_tree (&initializer.value, c_check_omp_declare_reduction_r, + &TREE_VEC_ELT (TREE_VALUE (t), 3), NULL); + walk_tree (&DECL_INITIAL (omp_priv), + c_check_omp_declare_reduction_r, + &TREE_VEC_ELT (TREE_VALUE (t), 3), NULL); + } + } + + pop_stmt_list (stmt); + pop_scope (); + if (cfun->language != NULL) + { + ggc_free (cfun->language); + cfun->language = NULL; + } + set_cfun (NULL); + current_function_decl = NULL_TREE; + if (nested) + c_pop_function_context (); + + if (!clauses.is_empty ()) + { + parser->tokens = &parser->tokens_buf[0]; + parser->tokens_avail = tokens_avail; + } + if (bad) + goto fail; + if (errs != errorcount) + break; + } + + clauses.release (); + types.release (); +} + + +/* OpenMP 4.0 + #pragma omp declare simd declare-simd-clauses[optseq] new-line + #pragma omp declare reduction (reduction-id : typename-list : expression) \ + initializer-clause[opt] new-line + #pragma omp declare target new-line */ + +static void +c_parser_omp_declare (c_parser *parser, enum pragma_context context) +{ + c_parser_consume_pragma (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "simd") == 0) + { + /* c_parser_consume_token (parser); done in + c_parser_omp_declare_simd. */ + c_parser_omp_declare_simd (parser, context); + return; + } + if (strcmp (p, "reduction") == 0) + { + c_parser_consume_token (parser); + c_parser_omp_declare_reduction (parser, context); + return; + } + if (strcmp (p, "target") == 0) + { + c_parser_consume_token (parser); + c_parser_omp_declare_target (parser); + return; + } + } + + c_parser_error (parser, "expected %<simd%> or %<reduction%> " + "or %<target%>"); + c_parser_skip_to_pragma_eol (parser); +} + /* Main entry point to parsing most OpenMP pragmas. */ static void @@ -10888,6 +12847,8 @@ c_parser_omp_construct (c_parser *parser) enum pragma_kind p_kind; location_t loc; tree stmt; + char p_name[sizeof "#pragma omp teams distribute parallel for simd"]; + omp_clause_mask mask (0); loc = c_parser_peek_token (parser)->location; p_kind = c_parser_peek_token (parser)->pragma_kind; @@ -10901,8 +12862,13 @@ c_parser_omp_construct (c_parser *parser) case PRAGMA_OMP_CRITICAL: stmt = c_parser_omp_critical (loc, parser); break; + case PRAGMA_OMP_DISTRIBUTE: + strcpy (p_name, "#pragma omp"); + stmt = c_parser_omp_distribute (loc, parser, p_name, mask, NULL); + break; case PRAGMA_OMP_FOR: - stmt = c_parser_omp_for (loc, parser); + strcpy (p_name, "#pragma omp"); + stmt = c_parser_omp_for (loc, parser, p_name, mask, NULL); break; case PRAGMA_OMP_MASTER: stmt = c_parser_omp_master (loc, parser); @@ -10911,10 +12877,16 @@ c_parser_omp_construct (c_parser *parser) stmt = c_parser_omp_ordered (loc, parser); break; case PRAGMA_OMP_PARALLEL: - stmt = c_parser_omp_parallel (loc, parser); + strcpy (p_name, "#pragma omp"); + stmt = c_parser_omp_parallel (loc, parser, p_name, mask, NULL); break; case PRAGMA_OMP_SECTIONS: - stmt = c_parser_omp_sections (loc, parser); + strcpy (p_name, "#pragma omp"); + stmt = c_parser_omp_sections (loc, parser, p_name, mask, NULL); + break; + case PRAGMA_OMP_SIMD: + strcpy (p_name, "#pragma omp"); + stmt = c_parser_omp_simd (loc, parser, p_name, mask, NULL); break; case PRAGMA_OMP_SINGLE: stmt = c_parser_omp_single (loc, parser); @@ -10922,6 +12894,13 @@ c_parser_omp_construct (c_parser *parser) case PRAGMA_OMP_TASK: stmt = c_parser_omp_task (loc, parser); break; + case PRAGMA_OMP_TASKGROUP: + stmt = c_parser_omp_taskgroup (parser); + break; + case PRAGMA_OMP_TEAMS: + strcpy (p_name, "#pragma omp"); + stmt = c_parser_omp_teams (loc, parser, p_name, mask, NULL); + break; default: gcc_unreachable (); } @@ -11148,7 +13127,7 @@ c_parser_transaction_expression (c_parser *parser, enum rid keyword) */ static tree -c_parser_transaction_cancel(c_parser *parser) +c_parser_transaction_cancel (c_parser *parser) { location_t loc = c_parser_peek_token (parser)->location; tree attrs; @@ -11208,6 +13187,7 @@ c_parse_file (void) c_parser tparser; memset (&tparser, 0, sizeof tparser); + tparser.tokens = &tparser.tokens_buf[0]; the_parser = &tparser; if (c_parser_peek_token (&tparser)->pragma_kind == PRAGMA_GCC_PCH_PREPROCESS) @@ -11215,6 +13195,8 @@ c_parse_file (void) the_parser = ggc_alloc_c_parser (); *the_parser = tparser; + if (tparser.tokens == &tparser.tokens_buf[0]) + the_parser->tokens = &the_parser->tokens_buf[0]; /* Initialize EH, if we've been told to do so. */ if (flag_exceptions) |