diff options
author | mrs <mrs@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-10-20 23:47:35 +0000 |
---|---|---|
committer | mrs <mrs@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-10-20 23:47:35 +0000 |
commit | 6b40961666f073231ed8a76e6e33deeda063cde7 (patch) | |
tree | 8247eb4232e8be98b7f61bd68bab2fd1a9f06ca3 /gcc/c | |
parent | e6b1b76450af5f98696ecedd4bd9a0ed18cdb2a6 (diff) | |
parent | fc1ce0cf396bf638746d546a557158d87f13849b (diff) | |
download | gcc-6b40961666f073231ed8a76e6e33deeda063cde7.tar.gz |
Merge in trunk.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/wide-int@203881 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/c')
-rw-r--r-- | gcc/c/ChangeLog | 142 | ||||
-rw-r--r-- | gcc/c/Make-lang.in | 62 | ||||
-rw-r--r-- | gcc/c/c-decl.c | 176 | ||||
-rw-r--r-- | gcc/c/c-lang.h | 3 | ||||
-rw-r--r-- | gcc/c/c-parser.c | 2565 | ||||
-rw-r--r-- | gcc/c/c-tree.h | 9 | ||||
-rw-r--r-- | gcc/c/c-typeck.c | 1016 |
7 files changed, 3608 insertions, 365 deletions
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 81b2018e8c0..0e2409aa182 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,145 @@ +2013-10-17 Andrew MacLeod <amacleod@redhat.com> + + * c-parser.c: Include omp-low.h. + * c-typeck.c: Likewise. + +2013-10-17 Marek Polacek <polacek@redhat.com> + + PR c/58267 + * c-parser.c (c_parser_declspecs): Add alignspec_ok parameter. + Document syntax of the array-declarator. + (c_parser_declspecs) <RID_ALIGNAS>: Bail out if alignment specs + are not permitted. + (c_parser_declaration_or_fndef): Adjust c_parser_declspecs call. + (c_parser_struct_declaration): Likewise. + (c_parser_declarator): Likewise. + (c_parser_direct_declarator_inner): Likewise. + (c_parser_parameter_declaration): Likewise. + (c_parser_type_name): Likewise. + +2013-10-11 Jakub Jelinek <jakub@redhat.com> + + * c-lang.h (current_omp_declare_target_attribute): New extern + decl. + * c-parser.c: Include c-lang.h. + (struct c_parser): Change tokens to c_token *. + Add tokens_buf field. Change tokens_avail type to unsigned int. + (c_parser_consume_token): If parser->tokens isn't + &parser->tokens_buf[0], increment parser->tokens. + (c_parser_consume_pragma): Likewise. + (enum pragma_context): Add pragma_struct and pragma_param. + (c_parser_external_declaration): Adjust + c_parser_declaration_or_fndef caller. + (c_parser_declaration_or_fndef): Add omp_declare_simd_clauses + argument, if it is non-vNULL vector, call c_finish_omp_declare_simd. + Adjust recursive call. + (c_parser_struct_or_union_specifier): Use pragma_struct instead + of pragma_external. + (c_parser_parameter_declaration): Use pragma_param instead of + pragma_external. + (c_parser_compound_statement_nostart, c_parser_label, + c_parser_for_statement): Adjust + c_parser_declaration_or_fndef callers. + (c_parser_expr_no_commas): Add omp_atomic_lhs argument, pass + it through to c_parser_conditional_expression. + (c_parser_conditional_expression): Add omp_atomic_lhs argument, + pass it through to c_parser_binary_expression. Adjust recursive + call. + (c_parser_binary_expression): Remove prec argument, add + omp_atomic_lhs argument instead. Always start from PREC_NONE, if + omp_atomic_lhs is non-NULL and one of the arguments of toplevel + binop matches it, use build2 instead of parser_build_binary_op. + (c_parser_pragma): Handle PRAGMA_OMP_CANCEL, + PRAGMA_OMP_CANCELLATION_POINT, PRAGMA_OMP_TARGET, + PRAGMA_OMP_END_DECLARE_TARGET, PRAGMA_OMP_DECLARE_REDUCTION. + Handle pragma_struct and pragma_param the same as pragma_external. + (c_parser_omp_clause_name): Parse new OpenMP 4.0 clause names. + (c_parser_omp_variable_list): Parse array sections for + OMP_CLAUSE_{DEPEND,MAP,TO,FROM} clauses. + (c_parser_omp_clause_collapse): Fully fold collapse expression. + (c_parser_omp_clause_reduction): Handle user defined reductions. + (c_parser_omp_clause_branch, c_parser_omp_clause_cancelkind, + c_parser_omp_clause_num_teams, c_parser_omp_clause_thread_limit, + c_parser_omp_clause_aligned, c_parser_omp_clause_linear, + c_parser_omp_clause_safelen, c_parser_omp_clause_simdlen, + c_parser_omp_clause_depend, c_parser_omp_clause_map, + c_parser_omp_clause_device, c_parser_omp_clause_dist_schedule, + c_parser_omp_clause_proc_bind, c_parser_omp_clause_to, + c_parser_omp_clause_from, c_parser_omp_clause_uniform): New functions. + (c_parser_omp_all_clauses): Add finish_p argument. Don't call + c_finish_omp_clauses if it is false. Handle new OpenMP 4.0 clauses. + (c_parser_omp_atomic): Parse seq_cst clause, pass true if it is + present to c_finish_omp_atomic. Handle OpenMP 4.0 atomic forms. + (c_parser_omp_for_loop): Add CODE argument, pass it through + to c_finish_omp_for. Change last argument to cclauses, + and adjust uses to grab parallel clauses from the array of all + the split clauses. Adjust c_parser_binary_expression, + c_parser_declaration_or_fndef and c_finish_omp_for callers. + (omp_split_clauses): New function. + (c_parser_omp_simd): New function. + (c_parser_omp_for): Add p_name, mask and cclauses arguments. + Allow the function to be called also when parsing combined constructs, + and call c_parser_omp_simd when parsing for simd. + (c_parser_omp_sections_scope): If section-sequence doesn't start with + #pragma omp section, require exactly one structured-block instead of + sequence of statements. + (c_parser_omp_sections): Add p_name, mask and cclauses arguments. + Allow the function to be called also when parsing combined constructs. + (c_parser_omp_parallel): Add p_name, mask and cclauses arguments. + Allow the function to be called also when parsing combined + constructs. + (c_parser_omp_taskgroup, c_parser_omp_cancel, + c_parser_omp_cancellation_point, c_parser_omp_distribute, + c_parser_omp_teams, c_parser_omp_target_data, + c_parser_omp_target_update, c_parser_omp_target, + c_parser_omp_declare_simd, c_finish_omp_declare_simd, + c_parser_omp_declare_target, c_parser_omp_end_declare_target, + c_parser_omp_declare_reduction, c_parser_omp_declare): New functions. + (c_parser_omp_construct): Add p_name and mask vars. Handle + PRAGMA_OMP_DISTRIBUTE, PRAGMA_OMP_SIMD, PRAGMA_OMP_TASKGROUP, + PRAGMA_OMP_TEAMS. Adjust c_parser_omp_for, c_parser_omp_parallel + and c_parser_omp_sections callers. + (c_parse_file): Initialize tparser.tokens and the_parser->tokens here. + (OMP_FOR_CLAUSE_MASK, OMP_SECTIONS_CLAUSE_MASK, + OMP_SINGLE_CLAUSE_MASK): Use OMP_CLAUSE_MASK_1 instead of 1. + (OMP_PARALLEL_CLAUSE_MASK): Likewise. Add OMP_CLAUSE_PROC_BIND. + (OMP_TASK_CLAUSE_MASK): Use OMP_CLAUSE_MASK_1 instead of 1. Add + OMP_CLAUSE_DEPEND. + (OMP_SIMD_CLAUSE_MASK, OMP_CANCEL_CLAUSE_MASK, + OMP_CANCELLATION_POINT_CLAUSE_MASK, OMP_DISTRIBUTE_CLAUSE_MASK, + OMP_TEAMS_CLAUSE_MASK, OMP_TARGET_DATA_CLAUSE_MASK, + OMP_TARGET_UPDATE_CLAUSE_MASK, OMP_TARGET_CLAUSE_MASK, + OMP_DECLARE_SIMD_CLAUSE_MASK): Define. + * c-typeck.c: Include tree-inline.h. + (c_finish_omp_cancel, c_finish_omp_cancellation_point, + handle_omp_array_sections_1, handle_omp_array_sections, + c_clone_omp_udr, c_find_omp_placeholder_r): New functions. + (c_finish_omp_clauses): Handle new OpenMP 4.0 clauses and + user defined reductions. + (c_tree_equal): New function. + * c-tree.h (temp_store_parm_decls, temp_pop_parm_decls, + c_finish_omp_cancel, c_finish_omp_cancellation_point, c_tree_equal, + c_omp_reduction_id, c_omp_reduction_decl, c_omp_reduction_lookup, + c_check_omp_declare_reduction_r): New prototypes. + * c-decl.c (current_omp_declare_target_attribute): New variable. + (c_decl_attributes): New function. + (start_decl, start_function): Use it instead of decl_attributes. + (temp_store_parm_decls, temp_pop_parm_decls, c_omp_reduction_id, + c_omp_reduction_decl, c_omp_reduction_lookup, + c_check_omp_declare_reduction_r): New functions. + +2013-09-25 Tom Tromey <tromey@redhat.com> + + * Make-lang.in (c/gccspec.o): Remove. + (CFLAGS-c/gccspec.o): New variable. + (cc1-checksum.o, C_TREE_H, c/c-aux-info.o, c/c-convert.o) + (c/c-decl.o, c/c-errors.o, c/c-lang.o, c/c-objc-common.o) + (c/c-parser.o, c/c-typeck.o, c/c-array-notation.o): Remove. + +2013-09-25 Tom Tromey <tromey@redhat.com> + + * Make-lang.in (c/gccspec.o): Don't use subshell. + 2013-09-18 Marek Polacek <polacek@redhat.com> PR sanitize/58443 diff --git a/gcc/c/Make-lang.in b/gcc/c/Make-lang.in index 8a4eb85cbbe..e68000a8246 100644 --- a/gcc/c/Make-lang.in +++ b/gcc/c/Make-lang.in @@ -44,12 +44,7 @@ c: cc1$(exeext) # The C front end driver. This is different from the drivers for other # front ends, because there is no C language specific driver (i.e. nothing # is to cc1 as e.g. g++ is to cc1plus, or gfortran is to f951). -c/gccspec.o: c/gccspec.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(GCC_H) \ - $(OPTS_H) - (SHLIB='$(SHLIB)'; \ - $(COMPILER) $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) \ - $(DRIVER_DEFINES) \ - -c $(srcdir)/c/gccspec.c $(OUTPUT_OPTION)) +CFLAGS-c/gccspec.o += $(DRIVER_DEFINES) # The C compiler itself. @@ -72,8 +67,6 @@ cc1-checksum.c : build/genchecksum$(build_exeext) checksum-options \ checksum-options > cc1-checksum.c.tmp && \ $(srcdir)/../move-if-change cc1-checksum.c.tmp cc1-checksum.c -cc1-checksum.o : cc1-checksum.c $(CONFIG_H) $(SYSTEM_H) - cc1$(exeext): $(C_OBJS) cc1-checksum.o $(BACKEND) $(LIBDEPS) +$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ $(C_OBJS) \ cc1-checksum.o $(BACKEND) $(LIBS) $(BACKENDLIBS) @@ -144,56 +137,3 @@ c.stageprofile: stageprofile-start -mv c/*$(objext) stageprofile/c c.stagefeedback: stagefeedback-start -mv c/*$(objext) stagefeedback/c - -# -# .o: .h dependencies. -# C language specific files. -C_TREE_H = c/c-tree.h $(C_COMMON_H) $(DIAGNOSTIC_H) -c/c-aux-info.o : c/c-aux-info.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(C_TREE_H) $(TREE_H) $(FLAGS_H) - -c/c-convert.o : c/c-convert.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TREE_H) $(C_TREE_H) $(FLAGS_H) $(C_COMMON_H) convert.h \ - langhooks.h $(TARGET_H) - -c/c-decl.o : c/c-decl.c c/c-lang.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TREE_H) $(C_TREE_H) $(GGC_H) $(TARGET_H) $(FLAGS_H) $(FUNCTION_H) \ - output.h debug.h toplev.h intl.h $(TM_P_H) $(TREE_INLINE_H) \ - $(TIMEVAR_H) $(OPTS_H) $(C_PRAGMA_H) gt-c-c-decl.h $(CGRAPH_H) \ - $(HASH_TABLE_H) $(LANGHOOKS_DEF_H) \ - dumpfile.h $(C_COMMON_H) $(CPPLIB_H) $(DIAGNOSTIC_CORE_H) \ - $(INPUT_H) langhooks.h pointer-set.h tree-iterator.h \ - $(PLUGIN_H) c-family/c-ada-spec.h c-family/c-objc.h - -c/c-errors.o: c/c-errors.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(C_TREE_H) $(FLAGS_H) $(DIAGNOSTIC_H) $(TM_P_H) - -c/c-lang.o : c/c-lang.c c/c-objc-common.h \ - $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(C_TREE_H) $(DIAGNOSTIC_CORE_H) \ - langhooks.h $(LANGHOOKS_DEF_H) $(C_COMMON_H) gtype-c.h \ - $(C_PRAGMA_H) $(TREE_INLINE_H) - -c/c-objc-common.o : c/c-objc-common.c c/c-objc-common.h \ - $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TREE_H) $(C_TREE_H) $(FLAGS_H) $(DIAGNOSTIC_H) \ - langhooks.h $(GGC_H) $(C_PRETTY_PRINT_H) intl.h \ - $(TREE_PRETTY_PRINT_H) - -c/c-parser.o : c/c-parser.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(TREE_H) $(C_TREE_H) $(C_COMMON_H) $(C_PRAGMA_H) $(CPPLIB_H) \ - $(GGC_H) $(TIMEVAR_H) $(INPUT_H) $(FLAGS_H) \ - gt-c-c-parser.h langhooks.h \ - $(VEC_H) $(TARGET_H) $(CGRAPH_H) $(PLUGIN_H) \ - c-family/c-objc.h - -c/c-typeck.o : c/c-typeck.c c/c-lang.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TREE_H) $(C_TREE_H) $(TARGET_H) $(FLAGS_H) intl.h \ - langhooks.h tree-iterator.h $(BITMAP_H) $(GIMPLE_H) \ - c-family/c-objc.h c-family/c-common.h wide-int.h - -c/c-array-notation.o: c/c-array-notation.c c/c-lang.h $(CONFIG_H) \ - $(SYSTEM_H) coretypes.h $(TREE_H) $(C_TREE_H) $(TARGET_H) \ - intl.h output.h $(EXPR_H) langhooks.h tree-iterator.h $(BITMAP_H) \ - $(GIMPLE_H) c-family/c-objc.h - diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 5c90f09e85e..c99db13ff84 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -147,6 +147,9 @@ static bool undef_nested_function; enum machine_mode c_default_pointer_mode = VOIDmode; +/* If non-zero, implicit "omp declare target" attribute is added into the + attribute lists. */ +int current_omp_declare_target_attribute; /* Each c_binding structure describes one binding of an identifier to a decl. All the decls in a scope - irrespective of namespace - are @@ -3971,6 +3974,35 @@ groktypename (struct c_type_name *type_name, tree *expr, return type; } +/* Wrapper for decl_attributes that adds some implicit attributes + to VAR_DECLs or FUNCTION_DECLs. */ + +static tree +c_decl_attributes (tree *node, tree attributes, int flags) +{ + /* Add implicit "omp declare target" attribute if requested. */ + if (current_omp_declare_target_attribute + && ((TREE_CODE (*node) == VAR_DECL && TREE_STATIC (*node)) + || TREE_CODE (*node) == FUNCTION_DECL)) + { + if (TREE_CODE (*node) == VAR_DECL + && ((DECL_CONTEXT (*node) + && TREE_CODE (DECL_CONTEXT (*node)) == FUNCTION_DECL) + || (current_function_decl && !DECL_EXTERNAL (*node)))) + error ("%q+D in block scope inside of declare target directive", + *node); + else if (TREE_CODE (*node) == VAR_DECL + && !COMPLETE_TYPE_P (TREE_TYPE (*node))) + error ("%q+D in declare target directive does not have mappable type", + *node); + else + attributes = tree_cons (get_identifier ("omp declare target"), + NULL_TREE, attributes); + } + return decl_attributes (node, attributes, flags); +} + + /* Decode a declarator in an ordinary declaration or data definition. This is called as soon as the type information and variable name have been parsed, before parsing the initializer if any. @@ -4105,7 +4137,7 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs, DECL_COMMON (decl) = 1; /* Set attributes here so if duplicate decl, will have proper attributes. */ - decl_attributes (&decl, attributes, 0); + c_decl_attributes (&decl, attributes, 0); /* Handle gnu_inline attribute. */ if (declspecs->inline_p @@ -7728,7 +7760,7 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, loc = DECL_SOURCE_LOCATION (decl1); - decl_attributes (&decl1, attributes, 0); + c_decl_attributes (&decl1, attributes, 0); if (DECL_DECLARED_INLINE_P (decl1) && DECL_UNINLINABLE (decl1) @@ -8325,6 +8357,44 @@ store_parm_decls (void) if (arg_info->pending_sizes) add_stmt (arg_info->pending_sizes); } + +/* Store PARM_DECLs in PARMS into scope temporarily. Used for + c_finish_omp_declare_simd for function prototypes. No diagnostics + should be done. */ + +void +temp_store_parm_decls (tree fndecl, tree parms) +{ + push_scope (); + for (tree p = parms; p; p = DECL_CHAIN (p)) + { + DECL_CONTEXT (p) = fndecl; + if (DECL_NAME (p)) + bind (DECL_NAME (p), p, current_scope, + /*invisible=*/false, /*nested=*/false, + UNKNOWN_LOCATION); + } +} + +/* Undo what temp_store_parm_decls did. */ + +void +temp_pop_parm_decls (void) +{ + /* Clear all bindings in this temporary scope, so that + pop_scope doesn't create a BLOCK. */ + struct c_binding *b = current_scope->bindings; + current_scope->bindings = NULL; + for (; b; b = free_binding_and_advance (b)) + { + gcc_assert (TREE_CODE (b->decl) == PARM_DECL); + gcc_assert (I_SYMBOL_BINDING (b->id) == b); + I_SYMBOL_BINDING (b->id) = b->shadowed; + if (b->shadowed && b->shadowed->u.type) + TREE_TYPE (b->shadowed->decl) = b->shadowed->u.type; + } + pop_scope (); +} /* Finish up a function declaration and compile that function @@ -10159,4 +10229,106 @@ c_register_addr_space (const char *word, addr_space_t as) ridpointers [rid] = id; } +/* Return identifier to look up for omp declare reduction. */ + +tree +c_omp_reduction_id (enum tree_code reduction_code, tree reduction_id) +{ + const char *p = NULL; + switch (reduction_code) + { + case PLUS_EXPR: p = "+"; break; + case MULT_EXPR: p = "*"; break; + case MINUS_EXPR: p = "-"; break; + case BIT_AND_EXPR: p = "&"; break; + case BIT_XOR_EXPR: p = "^"; break; + case BIT_IOR_EXPR: p = "|"; break; + case TRUTH_ANDIF_EXPR: p = "&&"; break; + case TRUTH_ORIF_EXPR: p = "||"; break; + case MIN_EXPR: p = "min"; break; + case MAX_EXPR: p = "max"; break; + default: + break; + } + + if (p == NULL) + { + if (TREE_CODE (reduction_id) != IDENTIFIER_NODE) + return error_mark_node; + p = IDENTIFIER_POINTER (reduction_id); + } + + const char prefix[] = "omp declare reduction "; + size_t lenp = sizeof (prefix); + size_t len = strlen (p); + char *name = XALLOCAVEC (char, lenp + len); + memcpy (name, prefix, lenp - 1); + memcpy (name + lenp - 1, p, len + 1); + return get_identifier (name); +} + +/* Lookup REDUCTION_ID in the current scope, or create an artificial + VAR_DECL, bind it into the current scope and return it. */ + +tree +c_omp_reduction_decl (tree reduction_id) +{ + struct c_binding *b = I_SYMBOL_BINDING (reduction_id); + if (b != NULL && B_IN_CURRENT_SCOPE (b)) + return b->decl; + + tree decl = build_decl (BUILTINS_LOCATION, VAR_DECL, + reduction_id, integer_type_node); + DECL_ARTIFICIAL (decl) = 1; + DECL_EXTERNAL (decl) = 1; + TREE_STATIC (decl) = 1; + TREE_PUBLIC (decl) = 0; + bind (reduction_id, decl, current_scope, true, false, BUILTINS_LOCATION); + return decl; +} + +/* Lookup REDUCTION_ID in the first scope where it has entry for TYPE. */ + +tree +c_omp_reduction_lookup (tree reduction_id, tree type) +{ + struct c_binding *b = I_SYMBOL_BINDING (reduction_id); + while (b) + { + tree t; + for (t = DECL_INITIAL (b->decl); t; t = TREE_CHAIN (t)) + if (comptypes (TREE_PURPOSE (t), type)) + return TREE_VALUE (t); + b = b->shadowed; + } + return error_mark_node; +} + +/* Helper function called via walk_tree, to diagnose invalid + #pragma omp declare reduction combiners or initializers. */ + +tree +c_check_omp_declare_reduction_r (tree *tp, int *, void *data) +{ + tree *vars = (tree *) data; + if (SSA_VAR_P (*tp) + && !DECL_ARTIFICIAL (*tp) + && *tp != vars[0] + && *tp != vars[1]) + { + location_t loc = DECL_SOURCE_LOCATION (vars[0]); + if (strcmp (IDENTIFIER_POINTER (DECL_NAME (vars[0])), "omp_out") == 0) + error_at (loc, "%<#pragma omp declare reduction%> combiner refers to " + "variable %qD which is not %<omp_out%> nor %<omp_in%>", + *tp); + else + error_at (loc, "%<#pragma omp declare reduction%> initializer refers " + "to variable %qD which is not %<omp_priv%> nor " + "%<omp_orig%>", + *tp); + return *tp; + } + return NULL_TREE; +} + #include "gt-c-c-decl.h" diff --git a/gcc/c/c-lang.h b/gcc/c/c-lang.h index 5ff7cd5422e..cbd5d1fa643 100644 --- a/gcc/c/c-lang.h +++ b/gcc/c/c-lang.h @@ -55,5 +55,8 @@ struct GTY(()) language_function { int warn_about_return_type; }; +/* If non-zero, implicit "omp declare target" attribute is added into the + attribute lists. */ +extern GTY(()) int current_omp_declare_target_attribute; #endif /* ! GCC_C_LANG_H */ diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index db0f730f787..f8b737b02fb 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" @@ -54,6 +55,7 @@ along with GCC; see the file COPYING3. If not see #include "target.h" #include "cgraph.h" #include "plugin.h" +#include "omp-low.h" /* Initialization routine for this file. */ @@ -162,9 +164,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 +741,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 +757,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,11 +1121,11 @@ 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, - bool, enum c_lookahead_kind); + bool, bool, enum c_lookahead_kind); static struct c_typespec c_parser_enum_specifier (c_parser *); static struct c_typespec c_parser_struct_or_union_specifier (c_parser *); static tree c_parser_struct_declaration (c_parser *); @@ -1155,11 +1164,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 +1195,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 +1376,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 +1459,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; @@ -1475,7 +1495,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, fndef_ok = !nested; } - c_parser_declspecs (parser, specs, true, true, start_attr_ok, cla_nonabstract_decl); + c_parser_declspecs (parser, specs, true, true, start_attr_ok, + true, cla_nonabstract_decl); if (parser->error) { c_parser_skip_to_end_of_block_or_statement (parser); @@ -1610,6 +1631,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 +1670,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 +1689,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 +1800,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); @@ -1892,8 +1944,9 @@ c_parser_static_assert_declaration_no_semi (c_parser *parser) /* Parse some declaration specifiers (possibly none) (C90 6.5, C99 6.7), adding them to SPECS (which may already include some). Storage class specifiers are accepted iff SCSPEC_OK; type - specifiers are accepted iff TYPESPEC_OK; attributes are accepted at - the start iff START_ATTR_OK. + specifiers are accepted iff TYPESPEC_OK; alignment specifiers are + accepted iff ALIGNSPEC_OK; attributes are accepted at the start + iff START_ATTR_OK. declaration-specifiers: storage-class-specifier declaration-specifiers[opt] @@ -1989,7 +2042,7 @@ c_parser_static_assert_declaration_no_semi (c_parser *parser) static void c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, bool scspec_ok, bool typespec_ok, bool start_attr_ok, - enum c_lookahead_kind la) + bool alignspec_ok, enum c_lookahead_kind la) { bool attrs_ok = start_attr_ok; bool seen_type = specs->typespec_kind != ctsk_none; @@ -2185,6 +2238,8 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, declspecs_add_attrs (loc, specs, attrs); break; case RID_ALIGNAS: + if (!alignspec_ok) + goto out; align = c_parser_alignas_specifier (parser); declspecs_add_alignas (loc, specs, align); break; @@ -2481,7 +2536,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 @@ -2590,7 +2645,8 @@ c_parser_struct_declaration (c_parser *parser) } specs = build_null_declspecs (); decl_loc = c_parser_peek_token (parser)->location; - c_parser_declspecs (parser, specs, false, true, true, cla_nonabstract_decl); + c_parser_declspecs (parser, specs, false, true, true, + true, cla_nonabstract_decl); if (parser->error) return NULL_TREE; if (!specs->declspecs_seen_p) @@ -2838,6 +2894,12 @@ c_parser_alignas_specifier (c_parser * parser) type-qualifier-list type-qualifier type-qualifier-list attributes + array-declarator: + [ type-qualifier-list[opt] assignment-expression[opt] ] + [ static type-qualifier-list[opt] assignment-expression ] + [ type-qualifier-list static assignment-expression ] + [ type-qualifier-list[opt] * ] + parameter-type-list: parameter-list parameter-list , ... @@ -2896,7 +2958,8 @@ c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind, struct c_declspecs *quals_attrs = build_null_declspecs (); struct c_declarator *inner; c_parser_consume_token (parser); - c_parser_declspecs (parser, quals_attrs, false, false, true, cla_prefer_id); + c_parser_declspecs (parser, quals_attrs, false, false, true, + true, cla_prefer_id); inner = c_parser_declarator (parser, type_seen_p, kind, seen_id); if (inner == NULL) return NULL; @@ -3048,12 +3111,14 @@ c_parser_direct_declarator_inner (c_parser *parser, bool id_present, bool star_seen; tree dimen; c_parser_consume_token (parser); - c_parser_declspecs (parser, quals_attrs, false, false, true, cla_prefer_id); + c_parser_declspecs (parser, quals_attrs, false, false, true, + false, cla_prefer_id); static_seen = c_parser_next_token_is_keyword (parser, RID_STATIC); if (static_seen) c_parser_consume_token (parser); if (static_seen && !quals_attrs->declspecs_seen_p) - c_parser_declspecs (parser, quals_attrs, false, false, true, cla_prefer_id); + c_parser_declspecs (parser, quals_attrs, false, false, true, + false, cla_prefer_id); if (!quals_attrs->declspecs_seen_p) quals_attrs = NULL; /* If "static" is present, there must be an array dimension. @@ -3329,7 +3394,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)) { @@ -3356,7 +3421,8 @@ c_parser_parameter_declaration (c_parser *parser, tree attrs) declspecs_add_attrs (input_location, specs, attrs); attrs = NULL_TREE; } - c_parser_declspecs (parser, specs, true, true, true, cla_nonabstract_decl); + c_parser_declspecs (parser, specs, true, true, true, true, + cla_nonabstract_decl); finish_declspecs (specs); pending_xref_error (); prefix_attrs = specs->attrs; @@ -3665,7 +3731,8 @@ c_parser_type_name (c_parser *parser) struct c_declarator *declarator; struct c_type_name *ret; bool dummy = false; - c_parser_declspecs (parser, specs, false, true, true, cla_prefer_type); + c_parser_declspecs (parser, specs, false, true, true, false, + cla_prefer_type); if (!specs->declspecs_seen_p) { c_parser_error (parser, "expected specifier-qualifier-list"); @@ -4074,7 +4141,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 +4250,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 +4279,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 +4417,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 +4481,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 +4499,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 +4514,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 +5064,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 +5093,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 +5481,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 +5562,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 +5622,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 +5655,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 +5714,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 +5772,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 +5884,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 +8057,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 +9038,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 +9078,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 +9090,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 +9155,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 +9171,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 +9191,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 +9238,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 +9316,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 +9328,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 +9439,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)) || !tree_fits_shwi_p (num) || (n = tree_to_shwi (num)) <= 0 @@ -9474,11 +9706,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 +9724,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 +9767,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 +9778,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 +9786,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 +9926,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 +10478,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 +10551,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 +10673,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 +10732,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 +10753,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 +10778,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 +10840,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 +10871,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 +10882,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 +10908,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 +10923,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 +10964,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 +11035,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 +11053,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 +11068,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 +11157,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 +11198,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 +11246,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 +11386,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 +11443,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 +11629,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 +11680,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 +11723,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 +11800,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 +11827,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 +11879,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 +12864,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 +12879,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 +12894,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 +12911,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 +13144,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 +13204,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 +13212,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) diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index d1a871daa68..2565ccb4f15 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -526,6 +526,8 @@ extern tree start_struct (location_t, enum tree_code, tree, struct c_struct_parse_info **); extern void store_parm_decls (void); extern void store_parm_decls_from (struct c_arg_info *); +extern void temp_store_parm_decls (tree, tree); +extern void temp_pop_parm_decls (void); extern tree xref_tag (enum tree_code, tree); extern struct c_typespec parser_xref_tag (location_t, enum tree_code, tree); extern struct c_parm *build_c_parm (struct c_declspecs *, tree, @@ -637,9 +639,12 @@ extern tree c_begin_omp_parallel (void); extern tree c_finish_omp_parallel (location_t, tree, tree); extern tree c_begin_omp_task (void); extern tree c_finish_omp_task (location_t, tree, tree); +extern void c_finish_omp_cancel (location_t, tree); +extern void c_finish_omp_cancellation_point (location_t, tree); extern tree c_finish_omp_clauses (tree); extern tree c_build_va_arg (location_t, tree, tree); extern tree c_finish_transaction (location_t, tree, int); +extern bool c_tree_equal (tree, tree); /* Set to 0 at beginning of a function definition, set to 1 if a return statement that specifies a return value is seen. */ @@ -663,6 +668,10 @@ extern enum machine_mode c_default_pointer_mode; /* In c-decl.c */ extern void c_finish_incomplete_decl (tree); extern void c_write_global_declarations (void); +extern tree c_omp_reduction_id (enum tree_code, tree); +extern tree c_omp_reduction_decl (tree); +extern tree c_omp_reduction_lookup (tree, tree); +extern tree c_check_omp_declare_reduction_r (tree *, int *, void *); /* In c-errors.c */ extern void pedwarn_c90 (location_t, int opt, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4); diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 14d5979624d..90318ba8ae4 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -37,6 +37,8 @@ along with GCC; see the file COPYING3. If not see #include "tree-iterator.h" #include "bitmap.h" #include "gimple.h" +#include "tree-inline.h" +#include "omp-low.h" #include "c-family/c-objc.h" #include "c-family/c-common.h" #include "c-family/c-ubsan.h" @@ -10694,6 +10696,537 @@ c_finish_omp_task (location_t loc, tree clauses, tree block) return add_stmt (stmt); } +/* Generate GOMP_cancel call for #pragma omp cancel. */ + +void +c_finish_omp_cancel (location_t loc, tree clauses) +{ + tree fn = builtin_decl_explicit (BUILT_IN_GOMP_CANCEL); + int mask = 0; + if (find_omp_clause (clauses, OMP_CLAUSE_PARALLEL)) + mask = 1; + else if (find_omp_clause (clauses, OMP_CLAUSE_FOR)) + mask = 2; + else if (find_omp_clause (clauses, OMP_CLAUSE_SECTIONS)) + mask = 4; + else if (find_omp_clause (clauses, OMP_CLAUSE_TASKGROUP)) + mask = 8; + else + { + error_at (loc, "%<#pragma omp cancel must specify one of " + "%<parallel%>, %<for%>, %<sections%> or %<taskgroup%> " + "clauses"); + return; + } + tree ifc = find_omp_clause (clauses, OMP_CLAUSE_IF); + if (ifc != NULL_TREE) + { + tree type = TREE_TYPE (OMP_CLAUSE_IF_EXPR (ifc)); + ifc = fold_build2_loc (OMP_CLAUSE_LOCATION (ifc), NE_EXPR, + boolean_type_node, OMP_CLAUSE_IF_EXPR (ifc), + build_zero_cst (type)); + } + else + ifc = boolean_true_node; + tree stmt = build_call_expr_loc (loc, fn, 2, + build_int_cst (integer_type_node, mask), + ifc); + add_stmt (stmt); +} + +/* Generate GOMP_cancellation_point call for + #pragma omp cancellation point. */ + +void +c_finish_omp_cancellation_point (location_t loc, tree clauses) +{ + tree fn = builtin_decl_explicit (BUILT_IN_GOMP_CANCELLATION_POINT); + int mask = 0; + if (find_omp_clause (clauses, OMP_CLAUSE_PARALLEL)) + mask = 1; + else if (find_omp_clause (clauses, OMP_CLAUSE_FOR)) + mask = 2; + else if (find_omp_clause (clauses, OMP_CLAUSE_SECTIONS)) + mask = 4; + else if (find_omp_clause (clauses, OMP_CLAUSE_TASKGROUP)) + mask = 8; + else + { + error_at (loc, "%<#pragma omp cancellation point must specify one of " + "%<parallel%>, %<for%>, %<sections%> or %<taskgroup%> " + "clauses"); + return; + } + tree stmt = build_call_expr_loc (loc, fn, 1, + build_int_cst (integer_type_node, mask)); + add_stmt (stmt); +} + +/* Helper function for handle_omp_array_sections. Called recursively + to handle multiple array-section-subscripts. C is the clause, + T current expression (initially OMP_CLAUSE_DECL), which is either + a TREE_LIST for array-section-subscript (TREE_PURPOSE is low-bound + expression if specified, TREE_VALUE length expression if specified, + TREE_CHAIN is what it has been specified after, or some decl. + TYPES vector is populated with array section types, MAYBE_ZERO_LEN + set to true if any of the array-section-subscript could have length + of zero (explicit or implicit), FIRST_NON_ONE is the index of the + first array-section-subscript which is known not to have length + of one. Given say: + map(a[:b][2:1][:c][:2][:d][e:f][2:5]) + FIRST_NON_ONE will be 3, array-section-subscript [:b], [2:1] and [:c] + all are or may have length of 1, array-section-subscript [:2] is the + first one knonwn not to have length 1. For array-section-subscript + <= FIRST_NON_ONE we diagnose non-contiguous arrays if low bound isn't + 0 or length isn't the array domain max + 1, for > FIRST_NON_ONE we + can if MAYBE_ZERO_LEN is false. MAYBE_ZERO_LEN will be true in the above + case though, as some lengths could be zero. */ + +static tree +handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, + bool &maybe_zero_len, unsigned int &first_non_one) +{ + tree ret, low_bound, length, type; + if (TREE_CODE (t) != TREE_LIST) + { + if (t == error_mark_node || TREE_TYPE (t) == error_mark_node) + return error_mark_node; + if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + if (DECL_P (t)) + error_at (OMP_CLAUSE_LOCATION (c), + "%qD is not a variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + else + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + else if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + && TREE_CODE (t) == VAR_DECL && DECL_THREAD_LOCAL_P (t)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD is threadprivate variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + return t; + } + + ret = handle_omp_array_sections_1 (c, TREE_CHAIN (t), types, + maybe_zero_len, first_non_one); + if (ret == error_mark_node || ret == NULL_TREE) + return ret; + + type = TREE_TYPE (ret); + low_bound = TREE_PURPOSE (t); + length = TREE_VALUE (t); + + if (low_bound == error_mark_node || length == error_mark_node) + return error_mark_node; + + if (low_bound && !INTEGRAL_TYPE_P (TREE_TYPE (low_bound))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "low bound %qE of array section does not have integral type", + low_bound); + return error_mark_node; + } + if (length && !INTEGRAL_TYPE_P (TREE_TYPE (length))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "length %qE of array section does not have integral type", + length); + return error_mark_node; + } + if (low_bound + && TREE_CODE (low_bound) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (low_bound)) + > TYPE_PRECISION (sizetype)) + low_bound = fold_convert (sizetype, low_bound); + if (length + && TREE_CODE (length) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (length)) + > TYPE_PRECISION (sizetype)) + length = fold_convert (sizetype, length); + if (low_bound == NULL_TREE) + low_bound = integer_zero_node; + + if (length != NULL_TREE) + { + if (!integer_nonzerop (length)) + maybe_zero_len = true; + if (first_non_one == types.length () + && (TREE_CODE (length) != INTEGER_CST || integer_onep (length))) + first_non_one++; + } + if (TREE_CODE (type) == ARRAY_TYPE) + { + if (length == NULL_TREE + && (TYPE_DOMAIN (type) == NULL_TREE + || TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "for unknown bound array type length expression must " + "be specified"); + return error_mark_node; + } + if (TREE_CODE (low_bound) == INTEGER_CST + && tree_int_cst_sgn (low_bound) == -1) + { + error_at (OMP_CLAUSE_LOCATION (c), + "negative low bound in array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + if (length != NULL_TREE + && TREE_CODE (length) == INTEGER_CST + && tree_int_cst_sgn (length) == -1) + { + error_at (OMP_CLAUSE_LOCATION (c), + "negative length in array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + if (TYPE_DOMAIN (type) + && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) + && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) + == INTEGER_CST) + { + tree size = size_binop (PLUS_EXPR, + TYPE_MAX_VALUE (TYPE_DOMAIN (type)), + size_one_node); + if (TREE_CODE (low_bound) == INTEGER_CST) + { + if (tree_int_cst_lt (size, low_bound)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "low bound %qE above array section size " + "in %qs clause", low_bound, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + if (tree_int_cst_equal (size, low_bound)) + maybe_zero_len = true; + else if (length == NULL_TREE + && first_non_one == types.length () + && tree_int_cst_equal + (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), + low_bound)) + first_non_one++; + } + else if (length == NULL_TREE) + { + maybe_zero_len = true; + if (first_non_one == types.length ()) + first_non_one++; + } + if (length && TREE_CODE (length) == INTEGER_CST) + { + if (tree_int_cst_lt (size, length)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "length %qE above array section size " + "in %qs clause", length, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + if (TREE_CODE (low_bound) == INTEGER_CST) + { + tree lbpluslen + = size_binop (PLUS_EXPR, + fold_convert (sizetype, low_bound), + fold_convert (sizetype, length)); + if (TREE_CODE (lbpluslen) == INTEGER_CST + && tree_int_cst_lt (size, lbpluslen)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "high bound %qE above array section size " + "in %qs clause", lbpluslen, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + } + } + } + else if (length == NULL_TREE) + { + maybe_zero_len = true; + if (first_non_one == types.length ()) + first_non_one++; + } + + /* For [lb:] we will need to evaluate lb more than once. */ + if (length == NULL_TREE && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND) + { + tree lb = c_save_expr (low_bound); + if (lb != low_bound) + { + TREE_PURPOSE (t) = lb; + low_bound = lb; + } + } + } + else if (TREE_CODE (type) == POINTER_TYPE) + { + if (length == NULL_TREE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "for pointer type length expression must be specified"); + return error_mark_node; + } + /* If there is a pointer type anywhere but in the very first + array-section-subscript, the array section can't be contiguous. */ + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + && TREE_CODE (TREE_CHAIN (t)) == TREE_LIST) + { + error_at (OMP_CLAUSE_LOCATION (c), + "array section is not contiguous in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + } + else + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE does not have pointer or array type", ret); + return error_mark_node; + } + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND) + types.safe_push (TREE_TYPE (ret)); + /* We will need to evaluate lb more than once. */ + tree lb = c_save_expr (low_bound); + if (lb != low_bound) + { + TREE_PURPOSE (t) = lb; + low_bound = lb; + } + ret = build_array_ref (OMP_CLAUSE_LOCATION (c), ret, low_bound); + return ret; +} + +/* Handle array sections for clause C. */ + +static bool +handle_omp_array_sections (tree c) +{ + bool maybe_zero_len = false; + unsigned int first_non_one = 0; + vec<tree> types = vNULL; + tree first = handle_omp_array_sections_1 (c, OMP_CLAUSE_DECL (c), types, + maybe_zero_len, first_non_one); + if (first == error_mark_node) + { + types.release (); + return true; + } + if (first == NULL_TREE) + { + types.release (); + return false; + } + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND) + { + tree t = OMP_CLAUSE_DECL (c); + tree tem = NULL_TREE; + types.release (); + /* Need to evaluate side effects in the length expressions + if any. */ + while (TREE_CODE (t) == TREE_LIST) + { + if (TREE_VALUE (t) && TREE_SIDE_EFFECTS (TREE_VALUE (t))) + { + if (tem == NULL_TREE) + tem = TREE_VALUE (t); + else + tem = build2 (COMPOUND_EXPR, TREE_TYPE (tem), + TREE_VALUE (t), tem); + } + t = TREE_CHAIN (t); + } + if (tem) + first = build2 (COMPOUND_EXPR, TREE_TYPE (first), tem, first); + first = c_fully_fold (first, false, NULL); + OMP_CLAUSE_DECL (c) = first; + } + else + { + unsigned int num = types.length (), i; + tree t, side_effects = NULL_TREE, size = NULL_TREE; + tree condition = NULL_TREE; + + if (int_size_in_bytes (TREE_TYPE (first)) <= 0) + maybe_zero_len = true; + + for (i = num, t = OMP_CLAUSE_DECL (c); i > 0; + t = TREE_CHAIN (t)) + { + tree low_bound = TREE_PURPOSE (t); + tree length = TREE_VALUE (t); + + i--; + if (low_bound + && TREE_CODE (low_bound) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (low_bound)) + > TYPE_PRECISION (sizetype)) + low_bound = fold_convert (sizetype, low_bound); + if (length + && TREE_CODE (length) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (length)) + > TYPE_PRECISION (sizetype)) + length = fold_convert (sizetype, length); + if (low_bound == NULL_TREE) + low_bound = integer_zero_node; + if (!maybe_zero_len && i > first_non_one) + { + if (integer_nonzerop (low_bound)) + goto do_warn_noncontiguous; + if (length != NULL_TREE + && TREE_CODE (length) == INTEGER_CST + && TYPE_DOMAIN (types[i]) + && TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])) + && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (types[i]))) + == INTEGER_CST) + { + tree size; + size = size_binop (PLUS_EXPR, + TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])), + size_one_node); + if (!tree_int_cst_equal (length, size)) + { + do_warn_noncontiguous: + error_at (OMP_CLAUSE_LOCATION (c), + "array section is not contiguous in %qs " + "clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + types.release (); + return true; + } + } + if (length != NULL_TREE + && TREE_SIDE_EFFECTS (length)) + { + if (side_effects == NULL_TREE) + side_effects = length; + else + side_effects = build2 (COMPOUND_EXPR, + TREE_TYPE (side_effects), + length, side_effects); + } + } + else + { + tree l; + + if (i > first_non_one && length && integer_nonzerop (length)) + continue; + if (length) + l = fold_convert (sizetype, length); + else + { + l = size_binop (PLUS_EXPR, + TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])), + size_one_node); + l = size_binop (MINUS_EXPR, l, + fold_convert (sizetype, low_bound)); + } + if (i > first_non_one) + { + l = fold_build2 (NE_EXPR, boolean_type_node, l, + size_zero_node); + if (condition == NULL_TREE) + condition = l; + else + condition = fold_build2 (BIT_AND_EXPR, boolean_type_node, + l, condition); + } + else if (size == NULL_TREE) + { + size = size_in_bytes (TREE_TYPE (types[i])); + size = size_binop (MULT_EXPR, size, l); + if (condition) + size = fold_build3 (COND_EXPR, sizetype, condition, + size, size_zero_node); + } + else + size = size_binop (MULT_EXPR, size, l); + } + } + types.release (); + if (side_effects) + size = build2 (COMPOUND_EXPR, sizetype, side_effects, size); + first = c_fully_fold (first, false, NULL); + OMP_CLAUSE_DECL (c) = first; + if (size) + size = c_fully_fold (size, false, NULL); + OMP_CLAUSE_SIZE (c) = size; + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) + return false; + tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); + OMP_CLAUSE_MAP_KIND (c2) = OMP_CLAUSE_MAP_POINTER; + if (!c_mark_addressable (t)) + return false; + OMP_CLAUSE_DECL (c2) = t; + t = build_fold_addr_expr (first); + t = fold_convert_loc (OMP_CLAUSE_LOCATION (c), ptrdiff_type_node, t); + tree ptr = OMP_CLAUSE_DECL (c2); + if (!POINTER_TYPE_P (TREE_TYPE (ptr))) + ptr = build_fold_addr_expr (ptr); + t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR, + ptrdiff_type_node, t, + fold_convert_loc (OMP_CLAUSE_LOCATION (c), + ptrdiff_type_node, ptr)); + t = c_fully_fold (t, false, NULL); + OMP_CLAUSE_SIZE (c2) = t; + OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c); + OMP_CLAUSE_CHAIN (c) = c2; + } + return false; +} + +/* Helper function of finish_omp_clauses. Clone STMT as if we were making + an inline call. But, remap + the OMP_DECL1 VAR_DECL (omp_out resp. omp_orig) to PLACEHOLDER + and OMP_DECL2 VAR_DECL (omp_in resp. omp_priv) to DECL. */ + +static tree +c_clone_omp_udr (tree stmt, tree omp_decl1, tree omp_decl2, + tree decl, tree placeholder) +{ + copy_body_data id; + struct pointer_map_t *decl_map = pointer_map_create (); + + *pointer_map_insert (decl_map, omp_decl1) = placeholder; + *pointer_map_insert (decl_map, omp_decl2) = decl; + memset (&id, 0, sizeof (id)); + id.src_fn = DECL_CONTEXT (omp_decl1); + id.dst_fn = current_function_decl; + id.src_cfun = DECL_STRUCT_FUNCTION (id.src_fn); + id.decl_map = decl_map; + + id.copy_decl = copy_decl_no_change; + id.transform_call_graph_edges = CB_CGE_DUPLICATE; + id.transform_new_cfg = true; + id.transform_return_to_modify = false; + id.transform_lang_insert_block = NULL; + id.eh_lp_nr = 0; + walk_tree (&stmt, copy_tree_body_r, &id, NULL); + pointer_map_destroy (decl_map); + return stmt; +} + +/* Helper function of c_finish_omp_clauses, called via walk_tree. + Find OMP_CLAUSE_PLACEHOLDER (passed in DATA) in *TP. */ + +static tree +c_find_omp_placeholder_r (tree *tp, int *, void *data) +{ + if (*tp == (tree) data) + return *tp; + return NULL_TREE; +} + /* For all elements of CLAUSES, validate them vs OpenMP constraints. Remove any elements from the list that are invalid. */ @@ -10701,13 +11234,17 @@ tree c_finish_omp_clauses (tree clauses) { bitmap_head generic_head, firstprivate_head, lastprivate_head; + bitmap_head aligned_head; tree c, t, *pc = &clauses; - const char *name; + bool branch_seen = false; + bool copyprivate_seen = false; + tree *nowait_clause = NULL; bitmap_obstack_initialize (NULL); bitmap_initialize (&generic_head, &bitmap_default_obstack); bitmap_initialize (&firstprivate_head, &bitmap_default_obstack); bitmap_initialize (&lastprivate_head, &bitmap_default_obstack); + bitmap_initialize (&aligned_head, &bitmap_default_obstack); for (pc = &clauses, c = clauses; c ; c = *pc) { @@ -10718,28 +11255,19 @@ c_finish_omp_clauses (tree clauses) switch (OMP_CLAUSE_CODE (c)) { case OMP_CLAUSE_SHARED: - name = "shared"; need_implicitly_determined = true; goto check_dup_generic; case OMP_CLAUSE_PRIVATE: - name = "private"; need_complete = true; need_implicitly_determined = true; goto check_dup_generic; case OMP_CLAUSE_REDUCTION: - name = "reduction"; need_implicitly_determined = true; t = OMP_CLAUSE_DECL (c); - if (AGGREGATE_TYPE_P (TREE_TYPE (t)) - || POINTER_TYPE_P (TREE_TYPE (t))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE has invalid type for %<reduction%>", t); - remove = true; - } - else if (FLOAT_TYPE_P (TREE_TYPE (t))) + if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) == NULL_TREE + && FLOAT_TYPE_P (TREE_TYPE (t))) { enum tree_code r_code = OMP_CLAUSE_REDUCTION_CODE (c); const char *r_name = NULL; @@ -10778,14 +11306,88 @@ c_finish_omp_clauses (tree clauses) remove = true; } } + else if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) == error_mark_node) + { + error_at (OMP_CLAUSE_LOCATION (c), + "user defined reduction not found for %qD", t); + remove = true; + } + else if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)) + { + tree list = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c); + tree type = TYPE_MAIN_VARIANT (TREE_TYPE (t)); + tree placeholder = build_decl (OMP_CLAUSE_LOCATION (c), + VAR_DECL, NULL_TREE, type); + OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = placeholder; + DECL_ARTIFICIAL (placeholder) = 1; + DECL_IGNORED_P (placeholder) = 1; + if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 0))) + c_mark_addressable (placeholder); + if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 1))) + c_mark_addressable (OMP_CLAUSE_DECL (c)); + OMP_CLAUSE_REDUCTION_MERGE (c) + = c_clone_omp_udr (TREE_VEC_ELT (list, 2), + TREE_VEC_ELT (list, 0), + TREE_VEC_ELT (list, 1), + OMP_CLAUSE_DECL (c), placeholder); + OMP_CLAUSE_REDUCTION_MERGE (c) + = build3_loc (OMP_CLAUSE_LOCATION (c), BIND_EXPR, + void_type_node, NULL_TREE, + OMP_CLAUSE_REDUCTION_MERGE (c), NULL_TREE); + TREE_SIDE_EFFECTS (OMP_CLAUSE_REDUCTION_MERGE (c)) = 1; + if (TREE_VEC_LENGTH (list) == 6) + { + if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 3))) + c_mark_addressable (OMP_CLAUSE_DECL (c)); + if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 4))) + c_mark_addressable (placeholder); + tree init = TREE_VEC_ELT (list, 5); + if (init == error_mark_node) + init = DECL_INITIAL (TREE_VEC_ELT (list, 3)); + OMP_CLAUSE_REDUCTION_INIT (c) + = c_clone_omp_udr (init, TREE_VEC_ELT (list, 4), + TREE_VEC_ELT (list, 3), + OMP_CLAUSE_DECL (c), placeholder); + if (TREE_VEC_ELT (list, 5) == error_mark_node) + OMP_CLAUSE_REDUCTION_INIT (c) + = build2 (INIT_EXPR, TREE_TYPE (t), t, + OMP_CLAUSE_REDUCTION_INIT (c)); + if (walk_tree (&OMP_CLAUSE_REDUCTION_INIT (c), + c_find_omp_placeholder_r, + placeholder, NULL)) + OMP_CLAUSE_REDUCTION_OMP_ORIG_REF (c) = 1; + } + else + { + tree init; + if (AGGREGATE_TYPE_P (TREE_TYPE (t))) + init = build_constructor (TREE_TYPE (t), NULL); + else + init = fold_convert (TREE_TYPE (t), integer_zero_node); + OMP_CLAUSE_REDUCTION_INIT (c) + = build2 (INIT_EXPR, TREE_TYPE (t), t, init); + } + OMP_CLAUSE_REDUCTION_INIT (c) + = build3_loc (OMP_CLAUSE_LOCATION (c), BIND_EXPR, + void_type_node, NULL_TREE, + OMP_CLAUSE_REDUCTION_INIT (c), NULL_TREE); + TREE_SIDE_EFFECTS (OMP_CLAUSE_REDUCTION_INIT (c)) = 1; + } goto check_dup_generic; case OMP_CLAUSE_COPYPRIVATE: - name = "copyprivate"; + copyprivate_seen = true; + if (nowait_clause) + { + error_at (OMP_CLAUSE_LOCATION (*nowait_clause), + "%<nowait%> clause must not be used together " + "with %<copyprivate%>"); + *nowait_clause = OMP_CLAUSE_CHAIN (*nowait_clause); + nowait_clause = NULL; + } goto check_dup_generic; case OMP_CLAUSE_COPYIN: - name = "copyin"; t = OMP_CLAUSE_DECL (c); if (TREE_CODE (t) != VAR_DECL || !DECL_THREAD_LOCAL_P (t)) { @@ -10795,12 +11397,37 @@ c_finish_omp_clauses (tree clauses) } goto check_dup_generic; + case OMP_CLAUSE_LINEAR: + t = OMP_CLAUSE_DECL (c); + if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) + && TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "linear clause applied to non-integral non-pointer " + "variable with type %qT", TREE_TYPE (t)); + remove = true; + break; + } + if (TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c))) == POINTER_TYPE) + { + tree s = OMP_CLAUSE_LINEAR_STEP (c); + s = pointer_int_sum (OMP_CLAUSE_LOCATION (c), PLUS_EXPR, + OMP_CLAUSE_DECL (c), s); + s = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR, + sizetype, s, OMP_CLAUSE_DECL (c)); + if (s == error_mark_node) + s = size_one_node; + OMP_CLAUSE_LINEAR_STEP (c) = s; + } + goto check_dup_generic; + check_dup_generic: t = OMP_CLAUSE_DECL (c); if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) { error_at (OMP_CLAUSE_LOCATION (c), - "%qE is not a variable in clause %qs", t, name); + "%qE is not a variable in clause %qs", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; } else if (bitmap_bit_p (&generic_head, DECL_UID (t)) @@ -10816,7 +11443,6 @@ c_finish_omp_clauses (tree clauses) break; case OMP_CLAUSE_FIRSTPRIVATE: - name = "firstprivate"; t = OMP_CLAUSE_DECL (c); need_complete = true; need_implicitly_determined = true; @@ -10838,7 +11464,6 @@ c_finish_omp_clauses (tree clauses) break; case OMP_CLAUSE_LASTPRIVATE: - name = "lastprivate"; t = OMP_CLAUSE_DECL (c); need_complete = true; need_implicitly_determined = true; @@ -10859,16 +11484,167 @@ c_finish_omp_clauses (tree clauses) bitmap_set_bit (&lastprivate_head, DECL_UID (t)); break; + case OMP_CLAUSE_ALIGNED: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in %<aligned%> clause", t); + remove = true; + } + else if (bitmap_bit_p (&aligned_head, DECL_UID (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE appears more than once in %<aligned%> clauses", + t); + remove = true; + } + else + bitmap_set_bit (&aligned_head, DECL_UID (t)); + break; + + case OMP_CLAUSE_DEPEND: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) == TREE_LIST) + { + if (handle_omp_array_sections (c)) + remove = true; + break; + } + if (t == error_mark_node) + remove = true; + else if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in %<depend%> clause", t); + remove = true; + } + else if (!c_mark_addressable (t)) + remove = true; + break; + + case OMP_CLAUSE_MAP: + case OMP_CLAUSE_TO: + case OMP_CLAUSE_FROM: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) == TREE_LIST) + { + if (handle_omp_array_sections (c)) + remove = true; + else + { + t = OMP_CLAUSE_DECL (c); + if (!COMPLETE_TYPE_P (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "array section does not have mappable type " + "in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + } + break; + } + if (t == error_mark_node) + remove = true; + else if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (TREE_CODE (t) == VAR_DECL && DECL_THREAD_LOCAL_P (t)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD is threadprivate variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (!c_mark_addressable (t)) + remove = true; + else if (!COMPLETE_TYPE_P (TREE_TYPE (t)) + && !(OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD does not have a mappable type in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (bitmap_bit_p (&generic_head, DECL_UID (t))) + { + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) + error ("%qD appears more than once in motion clauses", t); + else + error ("%qD appears more than once in map clauses", t); + remove = true; + } + else + bitmap_set_bit (&generic_head, DECL_UID (t)); + break; + + case OMP_CLAUSE_UNIFORM: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) != PARM_DECL) + { + if (DECL_P (t)) + error_at (OMP_CLAUSE_LOCATION (c), + "%qD is not an argument in %<uniform%> clause", t); + else + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not an argument in %<uniform%> clause", t); + remove = true; + } + break; + + case OMP_CLAUSE_NOWAIT: + if (copyprivate_seen) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%<nowait%> clause must not be used together " + "with %<copyprivate%>"); + remove = true; + break; + } + nowait_clause = pc; + pc = &OMP_CLAUSE_CHAIN (c); + continue; + case OMP_CLAUSE_IF: case OMP_CLAUSE_NUM_THREADS: + case OMP_CLAUSE_NUM_TEAMS: + case OMP_CLAUSE_THREAD_LIMIT: case OMP_CLAUSE_SCHEDULE: - case OMP_CLAUSE_NOWAIT: case OMP_CLAUSE_ORDERED: case OMP_CLAUSE_DEFAULT: case OMP_CLAUSE_UNTIED: case OMP_CLAUSE_COLLAPSE: case OMP_CLAUSE_FINAL: case OMP_CLAUSE_MERGEABLE: + case OMP_CLAUSE_SAFELEN: + case OMP_CLAUSE_SIMDLEN: + case OMP_CLAUSE_DEVICE: + case OMP_CLAUSE_DIST_SCHEDULE: + case OMP_CLAUSE_PARALLEL: + case OMP_CLAUSE_FOR: + case OMP_CLAUSE_SECTIONS: + case OMP_CLAUSE_TASKGROUP: + case OMP_CLAUSE_PROC_BIND: + pc = &OMP_CLAUSE_CHAIN (c); + continue; + + case OMP_CLAUSE_INBRANCH: + case OMP_CLAUSE_NOTINBRANCH: + if (branch_seen) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%<inbranch%> clause is incompatible with " + "%<notinbranch%>"); + remove = true; + break; + } + branch_seen = true; pc = &OMP_CLAUSE_CHAIN (c); continue; @@ -10914,7 +11690,8 @@ c_finish_omp_clauses (tree clauses) { error_at (OMP_CLAUSE_LOCATION (c), "%qE is predetermined %qs for %qs", - t, share_name, name); + t, share_name, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; } } @@ -11018,3 +11795,204 @@ c_build_va_arg (location_t loc, tree expr, tree type) "C++ requires promoted type, not enum type, in %<va_arg%>"); return build_va_arg (loc, expr, type); } + +/* Return truthvalue of whether T1 is the same tree structure as T2. + Return 1 if they are the same. Return 0 if they are different. */ + +bool +c_tree_equal (tree t1, tree t2) +{ + enum tree_code code1, code2; + + if (t1 == t2) + return true; + if (!t1 || !t2) + return false; + + for (code1 = TREE_CODE (t1); + CONVERT_EXPR_CODE_P (code1) + || code1 == NON_LVALUE_EXPR; + code1 = TREE_CODE (t1)) + t1 = TREE_OPERAND (t1, 0); + for (code2 = TREE_CODE (t2); + CONVERT_EXPR_CODE_P (code2) + || code2 == NON_LVALUE_EXPR; + code2 = TREE_CODE (t2)) + t2 = TREE_OPERAND (t2, 0); + + /* They might have become equal now. */ + if (t1 == t2) + return true; + + if (code1 != code2) + return false; + + switch (code1) + { + case INTEGER_CST: + return wi::eq_p (t1, t2); + + case REAL_CST: + return REAL_VALUES_EQUAL (TREE_REAL_CST (t1), TREE_REAL_CST (t2)); + + case STRING_CST: + return TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2) + && !memcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2), + TREE_STRING_LENGTH (t1)); + + case FIXED_CST: + return FIXED_VALUES_IDENTICAL (TREE_FIXED_CST (t1), + TREE_FIXED_CST (t2)); + + case COMPLEX_CST: + return c_tree_equal (TREE_REALPART (t1), TREE_REALPART (t2)) + && c_tree_equal (TREE_IMAGPART (t1), TREE_IMAGPART (t2)); + + case VECTOR_CST: + return operand_equal_p (t1, t2, OEP_ONLY_CONST); + + case CONSTRUCTOR: + /* We need to do this when determining whether or not two + non-type pointer to member function template arguments + are the same. */ + if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2)) + || CONSTRUCTOR_NELTS (t1) != CONSTRUCTOR_NELTS (t2)) + return false; + { + tree field, value; + unsigned int i; + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t1), i, field, value) + { + constructor_elt *elt2 = CONSTRUCTOR_ELT (t2, i); + if (!c_tree_equal (field, elt2->index) + || !c_tree_equal (value, elt2->value)) + return false; + } + } + return true; + + case TREE_LIST: + if (!c_tree_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2))) + return false; + if (!c_tree_equal (TREE_VALUE (t1), TREE_VALUE (t2))) + return false; + return c_tree_equal (TREE_CHAIN (t1), TREE_CHAIN (t2)); + + case SAVE_EXPR: + return c_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)); + + case CALL_EXPR: + { + tree arg1, arg2; + call_expr_arg_iterator iter1, iter2; + if (!c_tree_equal (CALL_EXPR_FN (t1), CALL_EXPR_FN (t2))) + return false; + for (arg1 = first_call_expr_arg (t1, &iter1), + arg2 = first_call_expr_arg (t2, &iter2); + arg1 && arg2; + arg1 = next_call_expr_arg (&iter1), + arg2 = next_call_expr_arg (&iter2)) + if (!c_tree_equal (arg1, arg2)) + return false; + if (arg1 || arg2) + return false; + return true; + } + + case TARGET_EXPR: + { + tree o1 = TREE_OPERAND (t1, 0); + tree o2 = TREE_OPERAND (t2, 0); + + /* Special case: if either target is an unallocated VAR_DECL, + it means that it's going to be unified with whatever the + TARGET_EXPR is really supposed to initialize, so treat it + as being equivalent to anything. */ + if (TREE_CODE (o1) == VAR_DECL && DECL_NAME (o1) == NULL_TREE + && !DECL_RTL_SET_P (o1)) + /*Nop*/; + else if (TREE_CODE (o2) == VAR_DECL && DECL_NAME (o2) == NULL_TREE + && !DECL_RTL_SET_P (o2)) + /*Nop*/; + else if (!c_tree_equal (o1, o2)) + return false; + + return c_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1)); + } + + case COMPONENT_REF: + if (TREE_OPERAND (t1, 1) != TREE_OPERAND (t2, 1)) + return false; + return c_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)); + + case PARM_DECL: + case VAR_DECL: + case CONST_DECL: + case FIELD_DECL: + case FUNCTION_DECL: + case IDENTIFIER_NODE: + case SSA_NAME: + return false; + + case TREE_VEC: + { + unsigned ix; + if (TREE_VEC_LENGTH (t1) != TREE_VEC_LENGTH (t2)) + return false; + for (ix = TREE_VEC_LENGTH (t1); ix--;) + if (!c_tree_equal (TREE_VEC_ELT (t1, ix), + TREE_VEC_ELT (t2, ix))) + return false; + return true; + } + + default: + break; + } + + switch (TREE_CODE_CLASS (code1)) + { + case tcc_unary: + case tcc_binary: + case tcc_comparison: + case tcc_expression: + case tcc_vl_exp: + case tcc_reference: + case tcc_statement: + { + int i, n = TREE_OPERAND_LENGTH (t1); + + switch (code1) + { + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + n = 1; + break; + case ARRAY_REF: + n = 2; + break; + default: + break; + } + + if (TREE_CODE_CLASS (code1) == tcc_vl_exp + && n != TREE_OPERAND_LENGTH (t2)) + return false; + + for (i = 0; i < n; ++i) + if (!c_tree_equal (TREE_OPERAND (t1, i), TREE_OPERAND (t2, i))) + return false; + + return true; + } + + case tcc_type: + return comptypes (t1, t2); + default: + gcc_unreachable (); + } + /* We can get here with --disable-checking. */ + return false; +} |