diff options
author | dnovillo <dnovillo@138bc75d-0d04-0410-961f-82ee72b054a4> | 2006-01-18 19:21:25 +0000 |
---|---|---|
committer | dnovillo <dnovillo@138bc75d-0d04-0410-961f-82ee72b054a4> | 2006-01-18 19:21:25 +0000 |
commit | 1e8e992020adfba209ef30b3c369e2ca6282d837 (patch) | |
tree | b7647b4100a528e9911385ca6d0d57a23899ae2c /gcc/c-parser.c | |
parent | 14efb9b7b52e816aa93ea4a451b5c10eb7634a8b (diff) | |
download | gcc-1e8e992020adfba209ef30b3c369e2ca6282d837.tar.gz |
2006-01-18 Richard Henderson <rth@redhat.com>
Jakub Jelinek <jakub@redhat.com>
Diego Novillo <dnovillo@redhat.com>
* libgomp: New directory.
* Makefile.def: Add target_module libgomp.
* Makefile.in: Regenerate.
* configure.in (target_libraries): Add target-libgomp.
* configure: Regenerate.
contrib/
2006-01-18 Richard Henderson <rth@redhat.com>
Diego Novillo <dnovillo@redhat.com>
* gcc_update (files_and_dependencies): Add libgomp files.
gcc/
2006-01-18 Richard Henderson <rth@redhat.com>
Aldy Hernandez <aldyh@redhat.com>
Jakub Jelinek <jakub@redhat.com>
Diego Novillo <dnovillo@redhat.com>
* omp-low.c: New file.
* c-omp.c: New file.
2006-01-18 Richard Henderson <rth@redhat.com>
Jakub Jelinek <jakub@redhat.com>
Diego Novillo <dnovillo@redhat.com>
* doc/invoke.texi: Document -fopenmp.
* tree-dump.h (debug_function): Declare.
* hooks.c (hook_bool_tree_bool_false): New function.
(hook_tree_tree_null): Remove.
(hook_tree_tree_tree_null): New.
* hooks.h: Update to match.
* tree-pretty-print.c (debug_tree_chain): New.
(print_generic_expr): Handle TDF_CHAIN.
(dump_generic_node): Handle BLOCK.
Do not abort with incomplete SWITCH_EXPRs.
Do not dump body of an OpenMP directive if TDF_SLIM is given.
<case OMP_PARALLEL, OMP_FOR, OMP_SECTIONS>: Don't
print space after directive name.
<OMP_FOR>: Handle printing OMP_FOR_PRE_BODY.
Handle OMP_MASTER and OMP_ORDERED.
Handle printing of OMP_BODY just in one place, goto
dump_omp_body in the rest of OMP_* nodes that have
OMP_BODY.
Don't handle clause nodes here. Update omp statements to
use dump_omp_clauses.
Handle OMP_SINGLE, OMP_SECTIONS, OMP_SECTION,
OMP_CLAUSE_ORDERED, OMP_CLAUSE_SCHEDULE, OMP_ATOMIC,
OMP_CRITICAL, OMP_CLAUSE_NOWAIT, GOMP_CLAUSE_IF,
GOMP_CLAUSE_NUM_THREADS, GOMP_FOR, GOMP_CLAUSE_SHARED,
GOMP_CLAUSE_FIRSTPRIVATE, GOMP_CLAUSE_LASTPRIVATE,
GOMP_CLAUSE_COPYIN and GOMP_CLAUSE_COPYPRIVATE.
Adjust output for GOMP_PARALLEL.
(dump_omp_clauses): New.
(print_declaration): Dump DECL_VALUE_EXPR.
(op_symbol_1): Split out of op_symbol.
(dumping_stmts): Remove. Update all users.
* cgraph.c (cgraph_analyze_queue): New.
(cgraph_add_new_function): New.
* cgraph.h (cgraph_analyze_queue): Declare.
(cgraph_add_new_function): Declare.
(cgraph_lower_function): Remove.
* tree.c (walk_tree): Walk OMP_CLAUSE_CHAIN of OMP_CLAUSE_*
nodes. Use switch for all nodes, handle most of IS_EXPR_CODE_CLASS
and TYPE_P nodes in its default clause.
(empty_body_p): New.
(tree_range_check_failed): New.
(build5_stat): New.
* tree.h (OMP_CLAUSE_REDUCTION_INIT,
OMP_CLAUSE_REDUCTION_MERGE,
OMP_CLAUSE_REDUCTION_PLACEHOLDER,
OMP_CLAUSE_PRIVATE_DEBUG,
OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE, OMP_FOR_PRE_BODY,
OMP_MASTER_BODY, OMP_ORDERED_BODY OMP_BODY,
OMP_CLAUSES, OMP_CLAUSE_DECL, OMP_CLAUSE_DEFAULT_KIND,
OMP_CLAUSE_CHAIN, OMP_CLAUSE_OUTER_DECL,
OMP_CLAUSE_INNER_DECL, OMP_CLAUSE_NUM_THREADS_EXPR,
OMP_CLAUSE_IF_EXPR, OMP_CLAUSE_SCHEDULE_CHUNK_EXPR,
OMP_CLAUSE_SCHEDULE_CHUNK_SIZE. OMP_PARALLEL_VAR_INIT,
OMP_PARALLEL_VAR_REDUC, OMP_FOR_VAR_INIT,
OMP_FOR_VAR_LAST, OMP_FOR_VAR_REDUC,
OMP_SECTIONS_VAR_INIT, OMP_SECTIONS_VAR_LAST,
OMP_SECTIONS_VAR_REDUC, OMP_CLAUSE_REDUCTION_CODE
OMP_SINGLE_CLAUSES, OMP_SINGLE_BODY,
OMP_CLAUSE_SCHEDULE_CHUNK_SIZE, OMP_SECTION_BODY,
OMP_CRITICAL_NAME, OMP_CRITICAL_BODY): New.
(TREE_RANGE_CHECK): New.
(empty_body_p): Declare.
(enum omp_clause_default_kind): New.
(build_string_literal): Declare.
(enum omp_clause_schedule_kind, OMP_CLAUSE_SCHEDULE_KIND): New.
(build5_stat, build5): Declare.
* tree-pass.h (TDF_CHAIN): Define.
* tree-pass.h (PROP_gimple_lomp): Define.
(pass_lower_omp): Declare.
* diagnostic.h (debug_tree_chain): Declare.
* builtins.c (get_builtin_sync_mode): Use 0 as last argument to
mode_for_size.
(expand_builtin): Handle sync BUILT_IN_*_16 builtins.
* builtins.c (build_string_literal): Make extern.
* gcc.c (include_spec_function): New.
(static_spec_functions): Add it.
(main): Move load of libgomp.spec ...
(LINK_COMMAND_SPEC): ... here.
(link_gomp_spec): New.
(static_specs): Include it.
(LINK_COMMAND_SPEC): Add link_gomp.
(GOMP_SELF_SPECS): New.
(driver_self_specs): Include it.
(switch_matches): Don't mark inline.
(main): Load libgomp.spec.
* tree-gimple.c (is_gimple_stmt): True for OMP_MASTER,
OMP_ORDERED, OMP_CRITICAL, OMP_SECTIONS, OMP_SECTION,
and OMP_SINGLE, OMP_FOR and OMP_PARALLEL.
* tree-gimple.h (enum omp_parallel): Declare.
(determine_parallel_type): Declare.
(omp_firstprivatize_variable): Declare.
(omp_reduction_init): Declare.
(diagnose_omp_structured_block_errors): Declare.
(struct walk_stmt_info): Add want_return_expr.
(struct walk_stmt_info): Add want_bind_expr, want_locations.
(find_omp_clause): Declare.
(insert_field_into_struct): Declare.
(struct walk_stmt_info): Move from tree-nested.c
(walk_stmts): Declare.
* c-cppbuiltin.c (c_cpp_builtins): If -fopenmp, #define _OPENMP
to 200505.
* cgraphunit.c (cgraph_lower_function): Make static.
(cgraph_finalize_pending_functions): New.
(cgraph_finalize_function): Call it.
(cgraph_finalize_compilation_unit): Likewise.
* builtin-types.def (BT_I16, BT_FN_I16_VPTR_I16,
BT_FN_BOOL_VPTR_I16_I16, BT_FN_I16_VPTR_I16_I16): Add.
(BT_FN_UINT_UINT): New.
(DEF_FUNCTION_TYPE_6, DEF_FUNCTION_TYPE_7,
DEF_FUNCTION_TYPE_VAR_4): Document.
(BT_PTR_LONG, BT_PTR_PTR, BT_FN_BOOL, BT_FN_INT,
BT_FN_VOID_PTRPTR, BT_PTR_FN_VOID_PTR,
BT_FN_BOOL_LONGPTR_LONGPTR, BT_FN_VOID_OMPFN_PTR_UINT,
BT_FN_VOID_OMPFN_PTR_UINT_UINT,
BT_FN_BOOL_LONG_LONG_LONG_LONGPTR_LONGPTR,
BT_FN_BOOL_LONG_LONG_LONG_LONG_LONGPTR_LONGPTR,
BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG,
BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG): New.
* builtins.def: Update DEF_BUILTIN comment to include COND argument.
Move all DEF_SYNC_BUILTIN () and DEF_GOMP_BUILTIN () builtins
into separate files.
(DEF_GOMP_BUILTIN): New.
(BUILT_IN_OMP_GET_THREAD_NUM, BUILT_IN_GOMP_BARRIER,
BUILT_IN_GOMP_CRITICAL_START, BUILT_IN_GOMP_CRITICAL_END,
BUILT_IN_GOMP_CRITICAL_NAME_START, BUILT_IN_GOMP_CRITICAL_NAME_END,
BUILT_IN_GOMP_LOOP_STATIC_START, BUILT_IN_GOMP_LOOP_DYNAMIC_START,
BUILT_IN_GOMP_LOOP_GUIDED_START, BUILT_IN_GOMP_LOOP_RUNTIME_START,
BUILT_IN_GOMP_LOOP_ORDERED_STATIC_START,
BUILT_IN_GOMP_LOOP_ORDERED_DYNAMIC_START,
BUILT_IN_GOMP_LOOP_ORDERED_GUIDED_START,
BUILT_IN_GOMP_LOOP_ORDERED_RUNTIME_START,
BUILT_IN_GOMP_LOOP_STATIC_NEXT, BUILT_IN_GOMP_LOOP_DYNAMIC_NEXT,
BUILT_IN_GOMP_LOOP_GUIDED_NEXT, BUILT_IN_GOMP_LOOP_RUNTIME_NEXT,
BUILT_IN_GOMP_LOOP_ORDERED_STATIC_NEXT,
BUILT_IN_GOMP_LOOP_ORDERED_DYNAMIC_NEXT,
BUILT_IN_GOMP_LOOP_ORDERED_GUIDED_NEXT,
BUILT_IN_GOMP_LOOP_ORDERED_RUNTIME_NEXT,
BUILT_IN_GOMP_PARALLEL_LOOP_STATIC_START,
BUILT_IN_GOMP_PARALLEL_LOOP_DYNAMIC_START,
BUILT_IN_GOMP_PARALLEL_LOOP_GUIDED_START,
BUILT_IN_GOMP_PARALLEL_LOOP_RUNTIME_START,
BUILT_IN_GOMP_LOOP_END, BUILT_IN_GOMP_LOOP_END_NOWAIT,
BUILT_IN_GOMP_ORDERED_START, BUILT_IN_GOMP_ORDERED_END,
BUILT_IN_GOMP_PARALLEL_START, BUILT_IN_GOMP_PARALLEL_END,
BUILT_IN_GOMP_SECTIONS_START, BUILT_IN_GOMP_SECTIONS_NEXT,
BUILT_IN_GOMP_PARALLEL_SECTIONS_START, BUILT_IN_GOMP_SECTIONS_END,
BUILT_IN_GOMP_SECTIONS_END_NOWAIT, BUILT_IN_GOMP_SINGLE_START,
BUILT_IN_GOMP_SINGLE_COPY_START, BUILT_IN_GOMP_SINGLE_COPY_END): New.
* sync-builtins.def: New file, moved from builtins.def.
* omp-builtins.def: New file, moved from builtins.def.
* c-objc-common.h (LANG_HOOKS_OMP_PREDETERMINED_SHARING): Redefine.
* gimple-low.c (lower_function_body): Clear data.
(lower_stmt): Do not handle COMPOUND_EXPR.
Remove call to print_node_brief.
* c-tree.h (c_finish_omp_clauses): New prototype.
(C_DECL_THREADPRIVATE_P): Define.
(lookup_name_no_remap, c_omp_remap_private): Remove
(c_begin_omp_parallel, c_finish_omp_parallel): Update.
(check_for_loop_decls): Update decl.
(lookup_name_no_remap, c_omp_remap_private): Declare.
(build_indirect_ref, build_modify_expr, pushdecl,
pushdecl_top_level): Move to c-common.h.
* dwarf2out.c (loc_descriptor_from_tree_1): Don't set unsignedp
before the switch, but just in the 2 places that need it.
* c-decl.c (diagnose_mismatched_decls): Do not check for
mismatched thread-local attributes when OLDDECL is marked
threadprivate and NEWDECL has no thread-local attributes.
(merge_decls): Merge C_DECL_THREADPRIVATE_P.
(c_gimple_diagnostics_recursively): Rename from
c_warn_unused_result_recursively. Invoke
diagnose_omp_structured_block_errors.
(check_for_loop_decls): Return a singular decl found.
* langhooks.c (lhd_omp_predetermined_sharing): Return
OMP_CLAUSE_DEFAULT_SHARED for DECL_ARTIFICIAL decls.
(lhd_omp_firstprivatize_type_sizes): New.
(lhd_omp_assignment): New.
(lhd_omp_predetermined_sharing): New.
* langhooks.h (struct gimplify_omp_ctx): Forward declare.
(struct lang_hooks_for_types): Add
omp_firstprivatize_type_sizes, omp_privatize_by_reference,
omp_predetermined_sharing, omp_disregard_value_expr,
omp_private_debug_clause, omp_clause_default_ctor,
omp_clause_copy_ctor, omp_clause_assign_op, omp_clause_dtor.
(c_finish_omp_clauses): New.
(c_finish_bc_stmt): Diagnose break within omp for.
(c_begin_omp_parallel, c_finish_omp_parallel): New.
(build_unary_op): Return error_mark after reporting
a readonly_error.
(build_modify_expr): Likewise.
* gimplify.c: Include optabs.h and pointer-set.h.
(enum gimplify_omp_var_data): Declare.
(struct gimplify_omp_ctx): Declare.
(struct gimplify_ctx): Add fields prev_context, combined_pre_p
and combined_ctxp.
(gimplify_ctxp, gimplify_omp_ctxp): New local variables.
(push_gimplify_context, pop_gimplify_context): Allow nesting.
(splay_tree_compare_decl_uid): New.
(new_omp_context): New.
(delete_omp_context): New.
(gimple_add_tmp_var): Call omp_add_variable.
(gimplify_bind_expr): Likewise.
(gimplify_var_or_parm_decl): If omp_notice_variable returned
true, disregard DECL_VALUE_EXPR on the decl if any.
(gimplify_expr_in_ctx): New.
(omp_firstprivatize_variable, omp_firstprivatize_type_sizes
omp_add_variable, omp_notice_variable, omp_is_private
gimplify_scan_omp_clauses, gimplify_adjust_omp_clauses_1
gimplify_adjust_omp_clauses, gimplify_omp_parallel
gimplify_omp_for, gimplify_omp_workshare, goa_lhs_expr_p
gimplify_omp_atomic_fetch_op, goa_stabilize_expr
gimplify_omp_atomic_pipeline, gimplify_omp_atomic_mutex
gimplify_omp_atomic): New.
(gimplify_expr): Handle OMP_PARALLEL, OMP_FOR, OMP_SECTIONS,
OMP_SINGLE, OMP_SECTION, OMP_MASTER, OMP_ORDERED,
OMP_CRITICAL and OMP_ATOMIC.
(gimplify_body): Verify gimplify_ctxp is empty after gimplification.
* c-pragma.h (enum pragma_kind): Add
PRAGMA_OMP_ATOMIC, PRAGMA_OMP_BARRIER,
PRAGMA_OMP_CRITICAL, PRAGMA_OMP_FLUSH, PRAGMA_OMP_FOR,
PRAGMA_OMP_MASTER, PRAGMA_OMP_ORDERED,
PRAGMA_OMP_PARALLEL, PRAGMA_OMP_PARALLEL_FOR,
PRAGMA_OMP_PARALLEL_SECTIONS, PRAGMA_OMP_SECTION,
PRAGMA_OMP_SECTIONS, PRAGMA_OMP_SINGLE,
PRAGMA_OMP_THREADPRIVATE.
* tree.def (OMP_PARALLEL, OMP_FOR, OMP_SECTIONS,
OMP_SINGLE, OMP_SECTION, OMP_MASTER, OMP_ORDERED,
OMP_CRITICAL, OMP_ATOMIC, OMP_CLAUSE_PRIVATE,
OMP_CLAUSE_SHARED, OMP_CLAUSE_FIRSTPRIVATE,
OMP_CLAUSE_LASTPRIVATE, OMP_CLAUSE_REDUCTION,
OMP_CLAUSE_COPYIN, OMP_CLAUSE_COPYPRIVATE,
OMP_CLAUSE_IF, OMP_CLAUSE_NUM_THREADS,
OMP_CLAUSE_SCHEDULE, OMP_CLAUSE_NOWAIT,
OMP_CLAUSE_ORDERED, OMP_CLAUSE_DEFAULT): Define.
* print-tree.c (print_node): Dump DECL_VALUE_EXPR.
* tree-ssa-dce.c (find_control_dependence): Do not assume that
ENTRY_BLOCK_PTR->next_bb == single_succ (ENTRY_BLOCK_PTR).
* tree-nested.c (convert_call_expr): Call walk_body on OMP_BODY for
OpenMP directives.
(struct nesting_info): Add field_map,
suppress_expansion, debug_var_chain.
(create_nesting_tree): Initialize them.
(lookup_field_for_decl): Use field_map.
(get_nonlocal_debug_decl, get_local_debug_decl): New.
(convert_local_omp_clauses): New.
(finalize_nesting_tree_1): Add debug_var_chain to toplevel block.
(walk_body): Split out of walk_function.
(convert_nonlocal_omp_clauses, convert_local_omp_clauses): New.
(convert_nonlocal_reference): Handle omp statements.
(convert_local_reference): Likewise.
(unnest_nesting_tree_1): Split out of finalize_nesting_tree_1.
(unnest_nesting_tree): New.
(lower_nested_functions): Call it.
(insert_field_into_struct): Make extern.
(struct walk_stmt_info): Move to tree-gimple.h.
(walk_stmts): Make extern.
* omp-builtins.def: New file.
* tree-iterator.c (expr_only): Clarify comment.
* c-common.h (pushdecl_top_level, pushdecl,
build_modify_expr, build_indirect_ref,
c_finish_omp_master, c_finish_omp_critical,
c_finish_omp_ordered, c_finish_omp_barrier,
c_finish_omp_atomic, c_finish_omp_flush,
c_finish_omp_for, c_split_parallel_clauses,
omp_clause_default_kind, c_omp_sharing_predetermined,
c_omp_remap_decl): Declare.
* Makefile.in (BUILTINS_DEF): Add omp-builtins.def.
(OBJS-common): Add omp-low.o.
(c-omp.o, omp-low.o): Add.
(gimplify.o): Add dependency on $(OPTABS_H).
(GTFILES): Add omp-low.c.
(gt-stringpool.h): Add.
* tree-cfg.c (set_bb_for_stmt): Do not update the
block-to-labels map if we are currently expanding to RTL.
(tree_node_can_be_shared): Remove unnecessary CONSTANT_CLASS_P
checks.
Handle IDENTIFIER_NODE.
(tree_verify_flow_info): Do not ICE when emitting error
messages about invalid labels.
(dump_function_to_file): Reset CFUN before emitting the body
of the function.
(debug_function): New.
* passes.c (init_optimization_passes): Schedule
pass_lower_omp.
* langhooks-def.h (lhd_omp_predetermined_sharing,
lhd_omp_assignment, lhd_omp_firstprivatize_type_sizes):
Declare.
(LANG_HOOKS_OMP_FIRSTPRIVATIZE_TYPE_SIZES): Define.
(LANG_HOOKS_FOR_TYPES_INITIALIZER): Use it.
(LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE,
LANG_HOOKS_OMP_PREDETERMINED_SHARING,
LANG_HOOKS_OMP_DISREGARD_VALUE_EXPR,
LANG_HOOKS_OMP_PRIVATE_DEBUG_CLAUSE,
LANG_HOOKS_OMP_CLAUSE_DEFAULT_CTOR,
LANG_HOOKS_OMP_CLAUSE_COPY_CTOR,
LANG_HOOKS_OMP_CLAUSE_ASSIGN_OP,
LANG_HOOKS_OMP_CLAUSE_DTOR): Define.
(LANG_HOOK_DECLS): Use them.
2006-01-18 Dmitry Kurochkin <dmitry.kurochkin@gmail.com>
Richard Henderson <rth@redhat.com>
Jakub Jelinek <jakub@redhat.com>
Diego Novillo <dnovillo@redhat.com>
* c-parser.c (pragma_omp_clause): Define.
(c_parser_declaration_or_fndef): Document OpenMP syntax.
(c_parser_compound_statement): Likewise.
(c_parser_statement): Likewise.
(c_parser_pragma): Handle omp pragmas.
(OMP_FOR_CLAUSE_MASK, OMP_SECTIONS_CLAUSE_MASK,
OMP_PARALLEL_CLAUSE_MASK, OMP_SINGLE_CLAUSE_MASK): Define.
(c_parser_omp_clause_name, check_no_duplicate_clause,
c_parser_omp_variable_list,
c_parser_omp_var_list_parens, c_parser_omp_clause_copyin,
c_parser_omp_clause_copyprivate,
c_parser_omp_clause_default,
c_parser_omp_clause_firstprivate, c_parser_omp_clause_if,
c_parser_omp_clause_lastprivate,
c_parser_omp_clause_nowait,
c_parser_omp_clause_num_threads,
c_parser_omp_clause_ordered, c_parser_omp_clause_private,
c_parser_omp_clause_reduction,
c_parser_omp_clause_schedule, c_parser_omp_clause_shared,
c_parser_omp_all_clauses, c_parser_omp_structured_block,
c_parser_omp_atomic, c_parser_omp_barrier,
c_parser_omp_critical, c_parser_omp_flush,
c_parser_omp_for_loop, c_parser_omp_for,
c_parser_omp_master, c_parser_omp_ordered,
c_parser_omp_sections_scope, c_parser_omp_sections,
c_parser_omp_parallel, c_parser_omp_single,
c_parser_omp_construct, c_parser_omp_threadprivate): New.
* c-pragma.c (init_pragma): Do omp pragma registration here.
* c.opt (fopenmp): New flag.
2006-01-18 Eric Christopher <echristo@apple.com>
* gcc.c (GOMP_SELF_SPECS): Bracket in #ifndef/#endif.
* config/darwin.h (GOMP_SELF_SPECS): Define.
testsuite/
2006-01-18 Richard Henderson <rth@redhat.com>
Aldy Hernandez <aldyh@redhat.com>
Jakub Jelinek <jakub@redhat.com>
Diego Novillo <dnovillo@redhat.com>
Uros Bizjak <uros@kss-loka.si>
* testsuite/gcc.dg/gomp: New directory.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@109902 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/c-parser.c')
-rw-r--r-- | gcc/c-parser.c | 1351 |
1 files changed, 1343 insertions, 8 deletions
diff --git a/gcc/c-parser.c b/gcc/c-parser.c index 522f2d2e4a5..e594d1fbd34 100644 --- a/gcc/c-parser.c +++ b/gcc/c-parser.c @@ -200,6 +200,26 @@ static const struct resword reswords[] = }; #define N_reswords (sizeof reswords / sizeof (struct resword)) +/* All OpenMP clauses. OpenMP 2.5. */ +typedef enum pragma_omp_clause { + PRAGMA_OMP_CLAUSE_NONE = 0, + + PRAGMA_OMP_CLAUSE_COPYIN, + PRAGMA_OMP_CLAUSE_COPYPRIVATE, + PRAGMA_OMP_CLAUSE_DEFAULT, + PRAGMA_OMP_CLAUSE_FIRSTPRIVATE, + PRAGMA_OMP_CLAUSE_IF, + PRAGMA_OMP_CLAUSE_LASTPRIVATE, + PRAGMA_OMP_CLAUSE_NOWAIT, + PRAGMA_OMP_CLAUSE_NUM_THREADS, + PRAGMA_OMP_CLAUSE_ORDERED, + PRAGMA_OMP_CLAUSE_PRIVATE, + PRAGMA_OMP_CLAUSE_REDUCTION, + PRAGMA_OMP_CLAUSE_SCHEDULE, + PRAGMA_OMP_CLAUSE_SHARED +} pragma_omp_clause; + + /* Initialization routine for this file. */ void @@ -981,6 +1001,10 @@ static struct c_expr c_parser_postfix_expression_after_primary (c_parser *, static struct c_expr c_parser_expression (c_parser *); static struct c_expr c_parser_expression_conv (c_parser *); static tree c_parser_expr_list (c_parser *, bool); +static void c_parser_omp_construct (c_parser *); +static void c_parser_omp_threadprivate (c_parser *); +static void c_parser_omp_barrier (c_parser *); +static void c_parser_omp_flush (c_parser *); enum pragma_context { pragma_external, pragma_stmt, pragma_compound }; static bool c_parser_pragma (c_parser *, enum pragma_context); @@ -1189,7 +1213,12 @@ c_parser_external_declaration (c_parser *parser) absence is diagnosed through the diagnosis of implicit int. In GNU C we also allow but diagnose declarations without declaration specifiers, but only at top level (elsewhere they conflict with - other syntax). */ + other syntax). + + OpenMP: + + declaration: + threadprivate-directive */ static void c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool empty_ok, @@ -3256,7 +3285,16 @@ c_parser_initval (c_parser *parser, struct c_expr *after) prefix attributes on the declaration. ??? The syntax follows the old parser in requiring something after label declarations. Although they are erroneous if the labels declared aren't defined, - is it useful for the syntax to be this way? */ + is it useful for the syntax to be this way? + + OpenMP: + + block-item: + openmp-directive + + openmp-directive: + barrier-directive + flush-directive */ static tree c_parser_compound_statement (c_parser *parser) @@ -3527,7 +3565,53 @@ c_parser_label (c_parser *parser) objc-throw-statement: @throw expression ; @throw ; -*/ + + OpenMP: + + statement: + openmp-construct + + openmp-construct: + parallel-construct + for-construct + sections-construct + single-construct + parallel-for-construct + parallel-sections-construct + master-construct + critical-construct + atomic-construct + ordered-construct + + parallel-construct: + parallel-directive structured-block + + for-construct: + for-directive iteration-statement + + sections-construct: + sections-directive section-scope + + single-construct: + single-directive structured-block + + parallel-for-construct: + parallel-for-directive iteration-statement + + parallel-sections-construct: + parallel-sections-directive section-scope + + master-construct: + master-directive structured-block + + critical-construct: + critical-directive structured-block + + atomic-construct: + atomic-directive expression-statement + + ordered-construct: + ordered-directive structured-block */ static void c_parser_statement (c_parser *parser) @@ -6344,12 +6428,13 @@ c_parser_objc_keywordexpr (c_parser *parser) } -/* Handle pragmas. ALLOW_STMT is true if we're within the context of - a function and such pragmas are to be allowed. Returns true if we - actually parsed such a pragma. */ +/* Handle pragmas. Some OpenMP pragmas are associated with, and therefore + should be considered, statements. ALLOW_STMT is true if we're within + the context of a function and such pragmas are to be allowed. Returns + true if we actually parsed such a pragma. */ static bool -c_parser_pragma (c_parser *parser, enum pragma_context context ATTRIBUTE_UNUSED) +c_parser_pragma (c_parser *parser, enum pragma_context context) { unsigned int id; @@ -6358,13 +6443,56 @@ c_parser_pragma (c_parser *parser, enum pragma_context context ATTRIBUTE_UNUSED) switch (id) { + case PRAGMA_OMP_BARRIER: + if (context != pragma_compound) + { + if (context == pragma_stmt) + c_parser_error (parser, "%<#pragma omp barrier%> may only be " + "used in compound statements"); + goto bad_stmt; + } + c_parser_omp_barrier (parser); + return false; + + case PRAGMA_OMP_FLUSH: + if (context != pragma_compound) + { + if (context == pragma_stmt) + c_parser_error (parser, "%<#pragma omp flush%> may only be " + "used in compound statements"); + goto bad_stmt; + } + c_parser_omp_flush (parser); + return false; + + case PRAGMA_OMP_THREADPRIVATE: + c_parser_omp_threadprivate (parser); + return false; + + case PRAGMA_OMP_SECTION: + error ("%<#pragma omp section%> may only be used in " + "%<#pragma omp sections%> construct"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + 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); return false; default: - gcc_assert (id >= PRAGMA_FIRST_EXTERNAL); + if (id < PRAGMA_FIRST_EXTERNAL) + { + if (context == pragma_external) + { + bad_stmt: + c_parser_error (parser, "expected declaration specifiers"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + } + c_parser_omp_construct (parser); + return true; + } break; } @@ -6420,6 +6548,1213 @@ c_parser_pragma_pch_preprocess (c_parser *parser) c_common_pch_pragma (parse_in, TREE_STRING_POINTER (name)); } +/* OpenMP 2.5 parsing routines. */ + +/* Returns name of the next clause. + If the clause is not recognized PRAGMA_OMP_CLAUSE_NONE is returned and + the token is not consumed. Otherwise appropriate pragma_omp_clause is + returned and the token is consumed. */ + +static pragma_omp_clause +c_parser_omp_clause_name (c_parser *parser) +{ + pragma_omp_clause result = PRAGMA_OMP_CLAUSE_NONE; + + if (c_parser_next_token_is_keyword (parser, RID_IF)) + 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 (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + switch (p[0]) + { + case 'c': + if (!strcmp ("copyin", p)) + result = PRAGMA_OMP_CLAUSE_COPYIN; + else if (!strcmp ("copyprivate", p)) + result = PRAGMA_OMP_CLAUSE_COPYPRIVATE; + break; + case 'f': + if (!strcmp ("firstprivate", p)) + result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE; + break; + case 'l': + if (!strcmp ("lastprivate", p)) + result = PRAGMA_OMP_CLAUSE_LASTPRIVATE; + break; + case 'n': + if (!strcmp ("nowait", p)) + result = PRAGMA_OMP_CLAUSE_NOWAIT; + else if (!strcmp ("num_threads", p)) + result = PRAGMA_OMP_CLAUSE_NUM_THREADS; + break; + case 'o': + if (!strcmp ("ordered", p)) + result = PRAGMA_OMP_CLAUSE_ORDERED; + break; + case 'p': + if (!strcmp ("private", p)) + result = PRAGMA_OMP_CLAUSE_PRIVATE; + break; + case 'r': + if (!strcmp ("reduction", p)) + result = PRAGMA_OMP_CLAUSE_REDUCTION; + break; + case 's': + if (!strcmp ("schedule", p)) + result = PRAGMA_OMP_CLAUSE_SCHEDULE; + else if (!strcmp ("shared", p)) + result = PRAGMA_OMP_CLAUSE_SHARED; + break; + } + } + + if (result != PRAGMA_OMP_CLAUSE_NONE) + c_parser_consume_token (parser); + + return result; +} + +/* Validate that a clause of the given type does not already exist. */ + +static void +check_no_duplicate_clause (tree clauses, enum tree_code code, const char *name) +{ + tree c; + + for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c)) + if (TREE_CODE (c) == code) + { + error ("too many %qs clauses", name); + break; + } +} + +/* OpenMP 2.5: + variable-list: + identifier + variable-list , identifier + + If KIND is nonzero, create the appropriate node and install the decl + in OMP_CLAUSE_DECL and add the node to the head of the list. + + If KIND is zero, create a TREE_LIST with the decl in TREE_PURPOSE; + return the list created. */ + +static tree +c_parser_omp_variable_list (c_parser *parser, enum tree_code kind, tree list) +{ + if (c_parser_next_token_is_not (parser, CPP_NAME) + || c_parser_peek_token (parser)->id_kind != C_ID_ID) + c_parser_error (parser, "expected identifier"); + + while (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_token (parser)->id_kind == C_ID_ID) + { + tree t = lookup_name (c_parser_peek_token (parser)->value); + + if (t == NULL_TREE) + undeclared_variable (c_parser_peek_token (parser)->value, + c_parser_peek_token (parser)->location); + else if (t == error_mark_node) + ; + else if (kind != 0) + { + tree u = make_node (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; + + c_parser_consume_token (parser); + } + + return list; +} + +/* Similarly, but expect leading and trailing parenthesis. This is a very + common case for omp clauses. */ + +static tree +c_parser_omp_var_list_parens (c_parser *parser, enum tree_code kind, tree list) +{ + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + list = c_parser_omp_variable_list (parser, kind, list); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + } + return list; +} + +/* OpenMP 2.5: + copyin ( variable-list ) */ + +static tree +c_parser_omp_clause_copyin (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_COPYIN, list); +} + +/* OpenMP 2.5: + copyprivate ( variable-list ) */ + +static tree +c_parser_omp_clause_copyprivate (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_COPYPRIVATE, list); +} + +/* OpenMP 2.5: + default ( shared | none ) */ + +static tree +c_parser_omp_clause_default (c_parser *parser, tree list) +{ + enum omp_clause_default_kind kind = OMP_CLAUSE_DEFAULT_UNSPECIFIED; + 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); + + switch (p[0]) + { + case 'n': + if (strcmp ("none", p) != 0) + goto invalid_kind; + kind = OMP_CLAUSE_DEFAULT_NONE; + break; + + case 's': + if (strcmp ("shared", p) != 0) + goto invalid_kind; + kind = OMP_CLAUSE_DEFAULT_SHARED; + break; + + default: + goto invalid_kind; + } + + c_parser_consume_token (parser); + } + else + { + invalid_kind: + c_parser_error (parser, "expected %<none%> or %<shared%>"); + } + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + if (kind == OMP_CLAUSE_DEFAULT_UNSPECIFIED) + return list; + + check_no_duplicate_clause (list, OMP_CLAUSE_DEFAULT, "default"); + c = make_node (OMP_CLAUSE_DEFAULT); + OMP_CLAUSE_CHAIN (c) = list; + OMP_CLAUSE_DEFAULT_KIND (c) = kind; + + return c; +} + +/* OpenMP 2.5: + firstprivate ( variable-list ) */ + +static tree +c_parser_omp_clause_firstprivate (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FIRSTPRIVATE, list); +} + +/* OpenMP 2.5: + if ( expression ) */ + +static tree +c_parser_omp_clause_if (c_parser *parser, tree list) +{ + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + tree t = c_parser_paren_condition (parser); + tree c; + + check_no_duplicate_clause (list, OMP_CLAUSE_IF, "if"); + + c = make_node (OMP_CLAUSE_IF); + OMP_CLAUSE_IF_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + else + c_parser_error (parser, "expected %<(%>"); + + return list; +} + +/* OpenMP 2.5: + lastprivate ( variable-list ) */ + +static tree +c_parser_omp_clause_lastprivate (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_LASTPRIVATE, list); +} + +/* OpenMP 2.5: + nowait */ + +static tree +c_parser_omp_clause_nowait (c_parser *parser ATTRIBUTE_UNUSED, tree list) +{ + tree c; + + check_no_duplicate_clause (list, OMP_CLAUSE_NOWAIT, "nowait"); + + c = make_node (OMP_CLAUSE_NOWAIT); + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 2.5: + num_threads ( expression ) */ + +static tree +c_parser_omp_clause_num_threads (c_parser *parser, tree list) +{ + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + tree c, t = c_parser_expression (parser).value; + + 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 (LE_EXPR, boolean_type_node, t, + build_int_cst (TREE_TYPE (t), 0)); + if (c == boolean_true_node) + { + warning (0, "%<num_threads%> value must be positive"); + t = integer_one_node; + } + + check_no_duplicate_clause (list, OMP_CLAUSE_NUM_THREADS, "num_threads"); + + c = make_node (OMP_CLAUSE_NUM_THREADS); + OMP_CLAUSE_NUM_THREADS_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + +/* OpenMP 2.5: + ordered */ + +static tree +c_parser_omp_clause_ordered (c_parser *parser ATTRIBUTE_UNUSED, tree list) +{ + tree c; + + check_no_duplicate_clause (list, OMP_CLAUSE_ORDERED, "ordered"); + + c = make_node (OMP_CLAUSE_ORDERED); + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 2.5: + private ( variable-list ) */ + +static tree +c_parser_omp_clause_private (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_PRIVATE, list); +} + +/* OpenMP 2.5: + reduction ( reduction-operator : variable-list ) + + reduction-operator: + One of: + * - & ^ | && || */ + +static tree +c_parser_omp_clause_reduction (c_parser *parser, tree list) +{ + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + enum tree_code code; + + switch (c_parser_peek_token (parser)->type) + { + case CPP_PLUS: + code = PLUS_EXPR; + break; + case CPP_MULT: + code = MULT_EXPR; + break; + case CPP_MINUS: + code = MINUS_EXPR; + break; + case CPP_AND: + code = BIT_AND_EXPR; + break; + case CPP_XOR: + code = BIT_XOR_EXPR; + break; + case CPP_OR: + code = BIT_IOR_EXPR; + break; + case CPP_AND_AND: + code = TRUTH_ANDIF_EXPR; + break; + case CPP_OR_OR: + code = TRUTH_ORIF_EXPR; + break; + default: + c_parser_error (parser, + "expected %<+%>, %<*%>, %<-%>, %<&%>, " + "%<^%>, %<|%>, %<&&%>, or %<||%>"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0); + return list; + } + c_parser_consume_token (parser); + if (c_parser_require (parser, CPP_COLON, "expected %<:%>")) + { + tree nl, c; + + nl = c_parser_omp_variable_list (parser, OMP_CLAUSE_REDUCTION, list); + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_REDUCTION_CODE (c) = code; + + list = nl; + } + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + } + return list; +} + +/* OpenMP 2.5: + schedule ( schedule-kind ) + schedule ( schedule-kind , expression ) + + schedule-kind: + static | dynamic | guided | runtime +*/ + +static tree +c_parser_omp_clause_schedule (c_parser *parser, tree list) +{ + tree c, t; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + + c = make_node (OMP_CLAUSE_SCHEDULE); + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + tree kind = c_parser_peek_token (parser)->value; + const char *p = IDENTIFIER_POINTER (kind); + + switch (p[0]) + { + case 'd': + if (strcmp ("dynamic", p) != 0) + goto invalid_kind; + OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_DYNAMIC; + break; + + case 'g': + if (strcmp ("guided", p) != 0) + goto invalid_kind; + OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_GUIDED; + break; + + case 'r': + if (strcmp ("runtime", p) != 0) + goto invalid_kind; + OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_RUNTIME; + break; + + default: + goto invalid_kind; + } + } + else if (c_parser_next_token_is_keyword (parser, RID_STATIC)) + OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_STATIC; + else + goto invalid_kind; + + 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; + + if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_RUNTIME) + error ("schedule %<runtime%> does not take " + "a %<chunk_size%> parameter"); + else if (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE) + OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c) = t; + else + c_parser_error (parser, "expected integer expression"); + + 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"); + OMP_CLAUSE_CHAIN (c) = list; + return c; + + invalid_kind: + c_parser_error (parser, "invalid schedule kind"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0); + return list; +} + +/* OpenMP 2.5: + shared ( variable-list ) */ + +static tree +c_parser_omp_clause_shared (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_SHARED, 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) +{ + tree clauses = NULL; + + while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + { + const pragma_omp_clause c_kind = c_parser_omp_clause_name (parser); + const char *c_name; + tree prev = clauses; + + switch (c_kind) + { + case PRAGMA_OMP_CLAUSE_COPYIN: + clauses = c_parser_omp_clause_copyin (parser, clauses); + c_name = "copyin"; + break; + case PRAGMA_OMP_CLAUSE_COPYPRIVATE: + clauses = c_parser_omp_clause_copyprivate (parser, clauses); + c_name = "copyprivate"; + break; + case PRAGMA_OMP_CLAUSE_DEFAULT: + clauses = c_parser_omp_clause_default (parser, clauses); + c_name = "default"; + break; + case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE: + clauses = c_parser_omp_clause_firstprivate (parser, clauses); + c_name = "firstprivate"; + break; + case PRAGMA_OMP_CLAUSE_IF: + clauses = c_parser_omp_clause_if (parser, clauses); + c_name = "if"; + break; + case PRAGMA_OMP_CLAUSE_LASTPRIVATE: + clauses = c_parser_omp_clause_lastprivate (parser, clauses); + c_name = "lastprivate"; + break; + case PRAGMA_OMP_CLAUSE_NOWAIT: + clauses = c_parser_omp_clause_nowait (parser, clauses); + c_name = "nowait"; + break; + case PRAGMA_OMP_CLAUSE_NUM_THREADS: + clauses = c_parser_omp_clause_num_threads (parser, clauses); + c_name = "num_threads"; + break; + case PRAGMA_OMP_CLAUSE_ORDERED: + clauses = c_parser_omp_clause_ordered (parser, clauses); + c_name = "ordered"; + break; + case PRAGMA_OMP_CLAUSE_PRIVATE: + clauses = c_parser_omp_clause_private (parser, clauses); + c_name = "private"; + break; + case PRAGMA_OMP_CLAUSE_REDUCTION: + clauses = c_parser_omp_clause_reduction (parser, clauses); + c_name = "reduction"; + break; + case PRAGMA_OMP_CLAUSE_SCHEDULE: + clauses = c_parser_omp_clause_schedule (parser, clauses); + c_name = "schedule"; + break; + case PRAGMA_OMP_CLAUSE_SHARED: + clauses = c_parser_omp_clause_shared (parser, clauses); + c_name = "shared"; + break; + default: + c_parser_error (parser, "expected %<#pragma omp%> clause"); + goto saw_error; + } + + if (((mask >> c_kind) & 1) == 0 && !parser->error) + { + /* Remove the invalid clause(s) from the list to avoid + confusing the rest of the compiler. */ + clauses = prev; + error ("%qs is not valid for %qs", c_name, where); + } + } + + saw_error: + c_parser_skip_to_pragma_eol (parser); + + return c_finish_omp_clauses (clauses); +} + +/* OpenMP 2.5: + structured-block: + statement + + In practice, we're also interested in adding the statement to an + outer node. So it is convenient if we work around the fact that + c_parser_statement calls add_stmt. */ + +static tree +c_parser_omp_structured_block (c_parser *parser) +{ + tree stmt = push_stmt_list (); + c_parser_statement (parser); + return pop_stmt_list (stmt); +} + +/* OpenMP 2.5: + # pragma omp atomic new-line + expression-stmt + + expression-stmt: + x binop= expr | x++ | ++x | x-- | --x + binop: + +, *, -, /, &, ^, |, <<, >> + + where x is an lvalue expression with scalar type. */ + +static void +c_parser_omp_atomic (c_parser *parser) +{ + tree lhs, rhs; + enum tree_code code; + + c_parser_skip_to_pragma_eol (parser); + + lhs = c_parser_unary_expression (parser).value; + switch (TREE_CODE (lhs)) + { + case ERROR_MARK: + saw_error: + c_parser_skip_to_end_of_block_or_statement (parser); + return; + + case PREINCREMENT_EXPR: + case POSTINCREMENT_EXPR: + lhs = TREE_OPERAND (lhs, 0); + code = PLUS_EXPR; + rhs = integer_one_node; + break; + + case PREDECREMENT_EXPR: + case POSTDECREMENT_EXPR: + lhs = TREE_OPERAND (lhs, 0); + code = MINUS_EXPR; + rhs = integer_one_node; + break; + + default: + switch (c_parser_peek_token (parser)->type) + { + case CPP_MULT_EQ: + code = MULT_EXPR; + break; + case CPP_DIV_EQ: + code = TRUNC_DIV_EXPR; + break; + case CPP_PLUS_EQ: + code = PLUS_EXPR; + break; + case CPP_MINUS_EQ: + code = MINUS_EXPR; + break; + case CPP_LSHIFT_EQ: + code = LSHIFT_EXPR; + break; + case CPP_RSHIFT_EQ: + code = RSHIFT_EXPR; + break; + case CPP_AND_EQ: + code = BIT_AND_EXPR; + break; + case CPP_OR_EQ: + code = BIT_IOR_EXPR; + break; + case CPP_XOR_EQ: + code = BIT_XOR_EXPR; + break; + default: + c_parser_error (parser, + "invalid operator for %<#pragma omp atomic%>"); + goto saw_error; + } + + c_parser_consume_token (parser); + rhs = c_parser_expression (parser).value; + break; + } + c_finish_omp_atomic (code, lhs, rhs); + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); +} + + +/* OpenMP 2.5: + # pragma omp barrier new-line +*/ + +static void +c_parser_omp_barrier (c_parser *parser) +{ + c_parser_consume_pragma (parser); + c_parser_skip_to_pragma_eol (parser); + + c_finish_omp_barrier (); +} + +/* OpenMP 2.5: + # pragma omp critical [(name)] new-line + structured-block +*/ + +static tree +c_parser_omp_critical (c_parser *parser) +{ + tree stmt, name = NULL; + + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + name = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + } + else + c_parser_error (parser, "expected identifier"); + } + else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + c_parser_error (parser, "expected %<(%> or end of line"); + c_parser_skip_to_pragma_eol (parser); + + stmt = c_parser_omp_structured_block (parser); + return c_finish_omp_critical (stmt, name); +} + +/* OpenMP 2.5: + # pragma omp flush flush-vars[opt] new-line + + flush-vars: + ( variable-list ) */ + +static void +c_parser_omp_flush (c_parser *parser) +{ + c_parser_consume_pragma (parser); + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + c_parser_omp_var_list_parens (parser, 0, NULL); + else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + c_parser_error (parser, "expected %<(%> or end of line"); + c_parser_skip_to_pragma_eol (parser); + + c_finish_omp_flush (); +} + +/* Parse the restricted form of the for statment allowed by OpenMP. + The real trick here is to determine the loop control variable early + so that we can push a new decl if necessary to make it private. */ + +static tree +c_parser_omp_for_loop (c_parser *parser) +{ + tree decl, cond, incr, save_break, save_cont, body, init; + location_t loc; + + if (!c_parser_next_token_is_keyword (parser, RID_FOR)) + { + c_parser_error (parser, "for statement expected"); + return NULL; + } + loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return NULL; + + /* Parse the initialization declaration or expression. */ + if (c_parser_next_token_starts_declspecs (parser)) + { + c_parser_declaration_or_fndef (parser, true, true, true, true); + decl = check_for_loop_decls (); + if (decl == NULL) + goto error_init; + init = decl; + } + else if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_EQ) + { + decl = c_parser_postfix_expression (parser).value; + + c_parser_require (parser, CPP_EQ, "expected %<=%>"); + + init = c_parser_expr_no_commas (parser, NULL).value; + init = build_modify_expr (decl, NOP_EXPR, init); + init = c_process_expr_stmt (init); + + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + } + else + goto error_init; + + /* Parse the loop condition. */ + cond = NULL_TREE; + if (c_parser_next_token_is_not (parser, CPP_SEMICOLON)) + { + cond = c_parser_expression_conv (parser).value; + cond = c_objc_common_truthvalue_conversion (cond); + if (EXPR_P (cond)) + SET_EXPR_LOCATION (cond, input_location); + } + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + + /* Parse the increment expression. */ + incr = NULL_TREE; + if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)) + incr = c_process_expr_stmt (c_parser_expression (parser).value); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + parse_body: + save_break = c_break_label; + c_break_label = size_one_node; + save_cont = c_cont_label; + c_cont_label = NULL_TREE; + body = push_stmt_list (); + + add_stmt (c_parser_c99_block_statement (parser)); + if (c_cont_label) + add_stmt (build1 (LABEL_EXPR, void_type_node, c_cont_label)); + + body = pop_stmt_list (body); + c_break_label = save_break; + c_cont_label = save_cont; + + /* Only bother calling c_finish_omp_for if we havn't already generated + an error from the initialization parsing. */ + if (decl != NULL) + return c_finish_omp_for (loc, decl, init, cond, incr, body, NULL); + return NULL; + + error_init: + c_parser_error (parser, "expected iteration declaration or initialization"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + decl = init = cond = incr = NULL_TREE; + goto parse_body; +} + +/* OpenMP 2.5: + #pragma omp for for-clause[optseq] new-line + for-loop +*/ + +#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_NOWAIT)) + +static tree +c_parser_omp_for (c_parser *parser) +{ + tree block, clauses, ret; + + clauses = c_parser_omp_all_clauses (parser, OMP_FOR_CLAUSE_MASK, + "#pragma omp for"); + + block = c_begin_compound_stmt (true); + ret = c_parser_omp_for_loop (parser); + if (ret) + OMP_FOR_CLAUSES (ret) = clauses; + block = c_end_compound_stmt (block, true); + add_stmt (block); + + return ret; +} + +/* OpenMP 2.5: + # pragma omp master new-line + structured-block +*/ + +static tree +c_parser_omp_master (c_parser *parser) +{ + c_parser_skip_to_pragma_eol (parser); + return c_finish_omp_master (c_parser_omp_structured_block (parser)); +} + +/* OpenMP 2.5: + # pragma omp ordered new-line + structured-block +*/ + +static tree +c_parser_omp_ordered (c_parser *parser) +{ + c_parser_skip_to_pragma_eol (parser); + return c_finish_omp_ordered (c_parser_omp_structured_block (parser)); +} + +/* OpenMP 2.5: + + section-scope: + { section-sequence } + + section-sequence: + section-directive[opt] structured-block + section-sequence section-directive structured-block */ + +static tree +c_parser_omp_sections_scope (c_parser *parser) +{ + tree stmt, substmt; + bool error_suppress = false; + location_t loc; + + if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) + { + /* Avoid skipping until the end of the block. */ + parser->error = false; + return NULL_TREE; + } + + stmt = push_stmt_list (); + + loc = c_parser_peek_token (parser)->location; + 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 = build1 (OMP_SECTION, void_type_node, substmt); + SET_EXPR_LOCATION (substmt, loc); + add_stmt (substmt); + } + + while (1) + { + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + break; + if (c_parser_next_token_is (parser, CPP_EOF)) + break; + + loc = c_parser_peek_token (parser)->location; + if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION) + { + c_parser_consume_pragma (parser); + c_parser_skip_to_pragma_eol (parser); + error_suppress = false; + } + else if (!error_suppress) + { + error ("expected %<#pragma omp section%> or %<}%>"); + error_suppress = true; + } + + substmt = c_parser_omp_structured_block (parser); + substmt = build1 (OMP_SECTION, void_type_node, substmt); + SET_EXPR_LOCATION (substmt, loc); + add_stmt (substmt); + } + c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, + "expected %<#pragma omp section%> or %<}%>"); + + substmt = pop_stmt_list (stmt); + + stmt = make_node (OMP_SECTIONS); + TREE_TYPE (stmt) = void_type_node; + OMP_SECTIONS_BODY (stmt) = substmt; + + return add_stmt (stmt); +} + +/* OpenMP 2.5: + # pragma omp sections sections-clause[optseq] newline + sections-scope +*/ + +#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)) + +static tree +c_parser_omp_sections (c_parser *parser) +{ + tree block, clauses, ret; + + clauses = c_parser_omp_all_clauses (parser, OMP_SECTIONS_CLAUSE_MASK, + "#pragma omp sections"); + + block = c_begin_compound_stmt (true); + ret = c_parser_omp_sections_scope (parser); + if (ret) + OMP_SECTIONS_CLAUSES (ret) = clauses; + block = c_end_compound_stmt (block, true); + add_stmt (block); + + return ret; +} + +/* OpenMP 2.5: + # pragma parallel parallel-clause new-line + # pragma parallel for parallel-for-clause new-line + # pragma parallel sections parallel-sections-clause new-line +*/ + +#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)) + +static tree +c_parser_omp_parallel (c_parser *parser) +{ + 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; + + if (c_parser_next_token_is_keyword (parser, RID_FOR)) + { + 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); + } + 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) + { + 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); + } + } + + 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 (clauses, block); + break; + + case PRAGMA_OMP_PARALLEL_FOR: + block = c_begin_omp_parallel (); + c_split_parallel_clauses (clauses, &par_clause, &ws_clause); + stmt = c_parser_omp_for_loop (parser); + if (stmt) + OMP_FOR_CLAUSES (stmt) = ws_clause; + stmt = c_finish_omp_parallel (par_clause, block); + break; + + case PRAGMA_OMP_PARALLEL_SECTIONS: + block = c_begin_omp_parallel (); + c_split_parallel_clauses (clauses, &par_clause, &ws_clause); + stmt = c_parser_omp_sections_scope (parser); + if (stmt) + OMP_SECTIONS_CLAUSES (stmt) = ws_clause; + stmt = c_finish_omp_parallel (par_clause, block); + break; + + default: + gcc_unreachable (); + } + + return stmt; +} + +/* OpenMP 2.5: + # pragma omp single single-clause[optseq] new-line + structured-block +*/ + +#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)) + +static tree +c_parser_omp_single (c_parser *parser) +{ + tree stmt = make_node (OMP_SINGLE); + TREE_TYPE (stmt) = void_type_node; + + OMP_SINGLE_CLAUSES (stmt) + = c_parser_omp_all_clauses (parser, OMP_SINGLE_CLAUSE_MASK, + "#pragma omp single"); + OMP_SINGLE_BODY (stmt) = c_parser_omp_structured_block (parser); + + return add_stmt (stmt); +} + + +/* Main entry point to parsing most OpenMP pragmas. */ + +static void +c_parser_omp_construct (c_parser *parser) +{ + enum pragma_kind p_kind; + location_t loc; + tree stmt; + + loc = c_parser_peek_token (parser)->location; + p_kind = c_parser_peek_token (parser)->pragma_kind; + c_parser_consume_pragma (parser); + + switch (p_kind) + { + case PRAGMA_OMP_ATOMIC: + c_parser_omp_atomic (parser); + return; + case PRAGMA_OMP_CRITICAL: + stmt = c_parser_omp_critical (parser); + break; + case PRAGMA_OMP_FOR: + stmt = c_parser_omp_for (parser); + break; + case PRAGMA_OMP_MASTER: + stmt = c_parser_omp_master (parser); + break; + case PRAGMA_OMP_ORDERED: + stmt = c_parser_omp_ordered (parser); + break; + case PRAGMA_OMP_PARALLEL: + stmt = c_parser_omp_parallel (parser); + break; + case PRAGMA_OMP_SECTIONS: + stmt = c_parser_omp_sections (parser); + break; + case PRAGMA_OMP_SINGLE: + stmt = c_parser_omp_single (parser); + break; + default: + gcc_unreachable (); + } + + if (stmt) + SET_EXPR_LOCATION (stmt, loc); +} + + +/* OpenMP 2.5: + # pragma omp threadprivate (variable-list) */ + +static void +c_parser_omp_threadprivate (c_parser *parser) +{ + tree vars, t; + + c_parser_consume_pragma (parser); + vars = c_parser_omp_var_list_parens (parser, 0, NULL); + + if (!targetm.have_tls) + sorry ("threadprivate variables not supported in this target"); + + /* Mark every variable in VARS to be assigned thread local storage. */ + for (t = vars; t; t = TREE_CHAIN (t)) + { + tree v = TREE_PURPOSE (t); + + /* If V had already been marked threadprivate, it doesn't matter + whether it had been used prior to this point. */ + if (TREE_USED (v) && !C_DECL_THREADPRIVATE_P (v)) + error ("%qE declared %<threadprivate%> after first use", v); + else if (! TREE_STATIC (v) && ! DECL_EXTERNAL (v)) + error ("automatic variable %qE cannot be %<threadprivate%>", v); + else if (! COMPLETE_TYPE_P (TREE_TYPE (v))) + error ("%<threadprivate%> %qE has incomplete type", v); + else + { + if (! DECL_THREAD_LOCAL_P (v)) + { + DECL_TLS_MODEL (v) = decl_default_tls_model (v); + /* If rtl has been already set for this var, call + make_decl_rtl once again, so that encode_section_info + has a chance to look at the new decl flags. */ + if (DECL_RTL_SET_P (v)) + make_decl_rtl (v); + } + C_DECL_THREADPRIVATE_P (v) = 1; + } + } + + c_parser_skip_to_pragma_eol (parser); +} + + /* Parse a single source file. */ void |