diff options
author | Jakub Jelinek <jakub@redhat.com> | 2008-06-06 15:01:54 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2008-06-06 15:01:54 +0200 |
commit | a68ab3517348178c71d9adcdefbc81de2d8c7390 (patch) | |
tree | 5d5537ea17855b77cca7b9c90a262e584c441592 /gcc/cp | |
parent | c4fe74e01a64d983bd068284c2aedfe146514256 (diff) | |
download | gcc-a68ab3517348178c71d9adcdefbc81de2d8c7390.zip gcc-a68ab3517348178c71d9adcdefbc81de2d8c7390.tar.gz gcc-a68ab3517348178c71d9adcdefbc81de2d8c7390.tar.bz2 |
c-cppbuiltin.c (c_cpp_builtins): Change _OPENMP value to 200805.
* c-cppbuiltin.c (c_cpp_builtins): Change _OPENMP value to
200805.
* langhooks.h (struct lang_hooks_for_decls): Add omp_finish_clause.
Add omp_private_outer_ref hook, add another argument to
omp_clause_default_ctor hook.
* langhooks-def.h (LANG_HOOKS_OMP_FINISH_CLAUSE): Define.
(LANG_HOOKS_OMP_PRIVATE_OUTER_REF): Define.
(LANG_HOOKS_OMP_CLAUSE_DEFAULT_CTOR): Change to
hook_tree_tree_tree_tree_null.
(LANG_HOOKS_DECLS): Add LANG_HOOKS_OMP_FINISH_CLAUSE and
LANG_HOOKS_OMP_PRIVATE_OUTER_REF.
* hooks.c (hook_tree_tree_tree_tree_null): New function.
* hooks.h (hook_tree_tree_tree_tree_null): New prototype.
* tree.def (OMP_TASK): New tree code.
* tree.h (OMP_TASK_COPYFN, OMP_TASK_ARG_SIZE, OMP_TASK_ARG_ALIGN,
OMP_CLAUSE_PRIVATE_OUTER_REF, OMP_CLAUSE_LASTPRIVATE_STMT,
OMP_CLAUSE_COLLAPSE_ITERVAR, OMP_CLAUSE_COLLAPSE_COUNT,
OMP_TASKREG_CHECK, OMP_TASKREG_BODY, OMP_TASKREG_CLAUSES,
OMP_TASKREG_FN, OMP_TASKREG_DATA_ARG, OMP_TASK_BODY,
OMP_TASK_CLAUSES, OMP_TASK_FN, OMP_TASK_DATA_ARG,
OMP_CLAUSE_COLLAPSE_EXPR): Define.
(enum omp_clause_default_kind): Add OMP_CLAUSE_DEFAULT_FIRSTPRIVATE.
(OMP_DIRECTIVE_P): Add OMP_TASK.
(OMP_CLAUSE_COLLAPSE, OMP_CLAUSE_UNTIED): New clause codes.
(OMP_CLAUSE_SCHEDULE_AUTO): New schedule kind.
* tree.c (omp_clause_code_name): Add OMP_CLAUSE_COLLAPSE
and OMP_CLAUSE_UNTIED entries.
(omp_clause_num_ops): Likewise. Increase OMP_CLAUSE_LASTPRIVATE
num_ops to 2.
(walk_tree_1): Handle OMP_CLAUSE_COLLAPSE and OMP_CLAUSE_UNTIED.
Walk OMP_CLAUSE_LASTPRIVATE_STMT.
* tree-pretty-print.c (dump_omp_clause): Handle
OMP_CLAUSE_SCHEDULE_AUTO, OMP_CLAUSE_UNTIED, OMP_CLAUSE_COLLAPSE,
OMP_CLAUSE_DEFAULT_FIRSTPRIVATE.
(dump_generic_node): Handle OMP_TASK and collapsed OMP_FOR loops.
* c-omp.c (c_finish_omp_for): Allow pointer iterators. Remove
warning about unsigned iterators. Change decl/init/cond/incr
arguments to TREE_VECs, check arguments for all collapsed loops.
(c_finish_omp_taskwait): New function.
(c_split_parallel_clauses): Put OMP_CLAUSE_COLLAPSE clause to
ws_clauses.
* c-parser.c (c_parser_omp_for_loop): Parse collapsed loops. Call
default_function_array_conversion on init. Add par_clauses argument.
If decl is present in parallel's lastprivate clause, change it to
shared and add lastprivate clause for decl to OMP_FOR_CLAUSES.
Add clauses argument, on success set OMP_FOR_CLAUSES to it. Look up
collapse count in clauses.
(c_parser_omp_for, c_parser_omp_parallel): Adjust
c_parser_omp_for_loop callers.
(OMP_FOR_CLAUSE_MASK): Add 1 << PRAGMA_OMP_CLAUSE_COLLAPSE.
(c_parser_pragma): Handle PRAGMA_OMP_TASKWAIT.
(c_parser_omp_clause_name): Handle collapse and untied clauses.
(c_parser_omp_clause_collapse, c_parser_omp_clause_untied): New
functions.
(c_parser_omp_clause_schedule): Handle schedule(auto).
Include correct location in the error message.
(c_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_COLLAPSE
and PRAGMA_OMP_CLAUSE_UNTIED.
(OMP_TASK_CLAUSE_MASK): Define.
(c_parser_omp_task, c_parser_omp_taskwait): New functions.
(c_parser_omp_construct): Handle PRAGMA_OMP_TASK.
* tree-nested.c (convert_nonlocal_omp_clauses,
convert_local_omp_clauses): Handle OMP_CLAUSE_LASTPRIVATE_STMT,
OMP_CLAUSE_REDUCTION_INIT, OMP_CLAUSE_REDUCTION_MERGE,
OMP_CLAUSE_COLLAPSE and OMP_CLAUSE_UNTIED.
Don't handle TREE_STATIC or DECL_EXTERNAL VAR_DECLs in
OMP_CLAUSE_DECL.
(conver_nonlocal_reference, convert_local_reference,
convert_call_expr): Handle OMP_TASK the same as OMP_PARALLEL. Use
OMP_TASKREG_* macros rather than OMP_PARALLEL_*.
(walk_omp_for): Adjust for OMP_FOR_{INIT,COND,INCR} changes.
* tree-gimple.c (is_gimple_stmt): Handle OMP_TASK.
* c-tree.h (c_begin_omp_task, c_finish_omp_task): New prototypes.
* c-pragma.h (PRAGMA_OMP_TASK, PRAGMA_OMP_TASKWAIT): New.
(PRAGMA_OMP_CLAUSE_COLLAPSE, PRAGMA_OMP_CLAUSE_UNTIED): New.
* c-typeck.c (c_begin_omp_task, c_finish_omp_task): New functions.
(c_finish_omp_clauses): Handle OMP_CLAUSE_COLLAPSE and
OMP_CLAUSE_UNTIED.
* c-pragma.c (init_pragma): Init omp task and omp taskwait pragmas.
* c-common.h (c_finish_omp_taskwait): New prototype.
* gimple-low.c (lower_stmt): Handle OMP_TASK.
* tree-parloops.c (create_parallel_loop): Create 1 entry
vectors for OMP_FOR_{INIT,COND,INCR}.
* tree-cfg.c (remove_useless_stmts_1): Handle OMP_* containers.
(make_edges): Handle OMP_TASK.
* tree-ssa-operands.c (get_expr_operands): Handle collapsed OMP_FOR
loops, adjust for OMP_FOR_{INIT,COND,INCR} changes.
* tree-inline.c (estimate_num_insns_1): Handle OMP_TASK.
* builtin-types.def (BT_PTR_ULONGLONG, BT_PTR_FN_VOID_PTR_PTR,
BT_FN_BOOL_ULONGLONGPTR_ULONGLONGPTR,
BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULLPTR_ULLPTR,
BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULL_ULLPTR_ULLPTR,
BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT): New.
* omp-builtins.def (BUILT_IN_GOMP_TASK, BUILT_IN_GOMP_TASKWAIT,
BUILT_IN_GOMP_LOOP_ULL_STATIC_START,
BUILT_IN_GOMP_LOOP_ULL_DYNAMIC_START,
BUILT_IN_GOMP_LOOP_ULL_GUIDED_START,
BUILT_IN_GOMP_LOOP_ULL_RUNTIME_START,
BUILT_IN_GOMP_LOOP_ULL_ORDERED_STATIC_START,
BUILT_IN_GOMP_LOOP_ULL_ORDERED_DYNAMIC_START,
BUILT_IN_GOMP_LOOP_ULL_ORDERED_GUIDED_START,
BUILT_IN_GOMP_LOOP_ULL_ORDERED_RUNTIME_START,
BUILT_IN_GOMP_LOOP_ULL_STATIC_NEXT,
BUILT_IN_GOMP_LOOP_ULL_DYNAMIC_NEXT,
BUILT_IN_GOMP_LOOP_ULL_GUIDED_NEXT,
BUILT_IN_GOMP_LOOP_ULL_RUNTIME_NEXT,
BUILT_IN_GOMP_LOOP_ULL_ORDERED_STATIC_NEXT,
BUILT_IN_GOMP_LOOP_ULL_ORDERED_DYNAMIC_NEXT,
BUILT_IN_GOMP_LOOP_ULL_ORDERED_GUIDED_NEXT,
BUILT_IN_GOMP_LOOP_ULL_ORDERED_RUNTIME_NEXT): New builtins.
* gimplify.c (gimplify_omp_for): Allow pointer type for decl,
handle POINTER_PLUS_EXPR. If loop counter has been replaced and
original iterator is present in lastprivate clause or if
collapse > 1, set OMP_CLAUSE_LASTPRIVATE_STMT. Handle collapsed
OMP_FOR loops, adjust for OMP_FOR_{INIT,COND,INCR} changes.
(gimplify_expr): Handle OMP_SECTIONS_SWITCH and OMP_TASK.
(enum gimplify_omp_var_data): Add GOVD_PRIVATE_OUTER_REF.
(omp_notice_variable): Set GOVD_PRIVATE_OUTER_REF if needed,
if it is set, lookup var in outer contexts too. Handle
OMP_CLAUSE_DEFAULT_FIRSTPRIVATE. Handle vars that are supposed
to be implicitly determined firstprivate for task regions.
(gimplify_scan_omp_clauses): Set GOVD_PRIVATE_OUTER_REF if needed,
if it is set, lookup var in outer contexts too. Set
OMP_CLAUSE_PRIVATE_OUTER_REF if GOVD_PRIVATE_OUTER_REF is set.
Handle OMP_CLAUSE_LASTPRIVATE_STMT, OMP_CLAUSE_COLLAPSE and
OMP_CLAUSE_UNTIED. Take region_type as last argument
instead of in_parallel and in_combined_parallel.
(gimplify_omp_parallel, gimplify_omp_for, gimplify_omp_workshare):
Adjust callers.
(gimplify_adjust_omp_clauses_1): Set OMP_CLAUSE_PRIVATE_OUTER_REF if
GOVD_PRIVATE_OUTER_REF is set. Call omp_finish_clause
langhook.
(new_omp_context): Set default_kind to
OMP_CLAUSE_DEFAULT_UNSPECIFIED for OMP_TASK regions.
(omp_region_type): New enum.
(struct gimplify_omp_ctx): Remove is_parallel and is_combined_parallel
fields, add region_type.
(new_omp_context): Take region_type as argument instead of is_parallel
and is_combined_parallel.
(gimple_add_tmp_var, omp_firstprivatize_variable, omp_notice_variable,
omp_is_private, omp_check_private): Adjust ctx->is_parallel and
ctx->is_combined_parallel checks.
(gimplify_omp_task): New function.
(gimplify_adjust_omp_clauses): Handle OMP_CLAUSE_COLLAPSE and
OMP_CLAUSE_UNTIED.
* omp-low.c (extract_omp_for_data): Use schedule(static)
for schedule(auto). Handle pointer and unsigned iterators.
Compute fd->iter_type. Handle POINTER_PLUS_EXPR increments.
Add loops argument. Extract data for collapsed OMP_FOR loops.
(expand_parallel_call): Assert sched_kind isn't auto,
map runtime schedule to index 3.
(struct omp_for_data_loop): New type.
(struct omp_for_data): Remove v, n1, n2, step, cond_code fields.
Add loop, loops, collapse and iter_type fields.
(workshare_safe_to_combine_p): Disallow combined for if
iter_type is unsigned long long. Don't combine collapse > 1 loops
unless all bounds and steps are constant. Adjust extract_omp_for_data
caller.
(expand_omp_for_generic): Handle pointer, unsigned and long long
iterators. Handle collapsed OMP_FOR loops. Adjust
for struct omp_for_data changes. If libgomp function doesn't return
boolean_type_node, add comparison of the return value with 0.
(expand_omp_for_static_nochunk, expand_omp_for_static_chunk): Handle
pointer, unsigned and long long iterators. Adjust for struct
omp_for_data changes.
(expand_omp_for): Assert sched_kind isn't auto, map runtime schedule
to index 3. Use GOMP_loop_ull*{start,next} if iter_type is
unsigned long long. Allocate loops array, pass it to
extract_omp_for_data. For collapse > 1 loops use always
expand_omp_for_generic.
(omp_context): Add sfield_map and srecord_type fields.
(is_task_ctx, lookup_sfield): New functions.
(use_pointer_for_field): Use is_task_ctx helper. Change first
argument's type from const_tree to tree. Clarify comment.
In OMP_TASK disallow copy-in/out sharing.
(build_sender_ref): Call lookup_sfield instead of lookup_field.
(install_var_field): Add mask argument. Populate both record_type
and srecord_type if needed.
(delete_omp_context): Destroy sfield_map, clear DECL_ABSTRACT_ORIGIN
in srecord_type.
(fixup_child_record_type): Also remap FIELD_DECL's DECL_SIZE{,_UNIT}
and DECL_FIELD_OFFSET.
(scan_sharing_clauses): Adjust install_var_field callers. For
firstprivate clauses on explicit tasks allocate the var by value in
record_type unconditionally, rather than by reference.
Handle OMP_CLAUSE_PRIVATE_OUTER_REF. Scan OMP_CLAUSE_LASTPRIVATE_STMT.
Use is_taskreg_ctx instead of is_parallel_ctx.
Handle OMP_CLAUSE_COLLAPSE and OMP_CLAUSE_UNTIED.
(create_omp_child_function_name): Add task_copy argument, use
*_omp_cpyfn* names if it is true.
(create_omp_child_function): Add task_copy argument, if true create
*_omp_cpyfn* helper function.
(scan_omp_parallel): Adjust create_omp_child_function callers.
Rename parallel_nesting_level to taskreg_nesting_level.
(scan_omp_task): New function.
(lower_rec_input_clauses): Don't run constructors for firstprivate
explicit task vars which are initialized by *_omp_cpyfn*.
Pass outer var ref to omp_clause_default_ctor hook if
OMP_CLAUSE_PRIVATE_OUTER_REF or OMP_CLAUSE_LASTPRIVATE.
Replace OMP_CLAUSE_REDUCTION_PLACEHOLDER decls in
OMP_CLAUSE_REDUCTION_INIT.
(lower_send_clauses): Clear DECL_ABSTRACT_ORIGIN if in task to
avoid duplicate setting of fields. Handle
OMP_CLAUSE_PRIVATE_OUTER_REF.
(lower_send_shared_vars): Use srecord_type if non-NULL. Don't
copy-out if TREE_READONLY, only copy-in.
(expand_task_copyfn): New function.
(expand_task_call): New function.
(struct omp_taskcopy_context): New type.
(task_copyfn_copy_decl, task_copyfn_remap_type, create_task_copyfn):
New functions.
(lower_omp_parallel): Rename to...
(lower_omp_taskreg): ... this. Use OMP_TASKREG_* macros where needed.
Call create_task_copyfn if srecord_type is needed. Adjust
sender_decl type.
(task_shared_vars): New variable.
(check_omp_nesting_restrictions): Warn if work-sharing,
barrier, master or ordered region is closely nested inside OMP_TASK.
Add warnings for barrier if closely nested inside of work-sharing,
ordered, or master region.
(scan_omp_1): Call check_omp_nesting_restrictions even for
GOMP_barrier calls. Rename parallel_nesting_level to
taskreg_nesting_level. Handle OMP_TASK.
(lower_lastprivate_clauses): Even if some lastprivate is found on a
work-sharing construct, continue looking for them on parent parallel
construct.
(lower_omp_for_lastprivate): Add lastprivate clauses
to the beginning of dlist rather than end. Adjust for struct
omp_for_data changes.
(lower_omp_for): Add rec input clauses before OMP_FOR_PRE_BODY,
not after it. Handle collapsed OMP_FOR loops, adjust for
OMP_FOR_{INIT,COND,INCR} changes, adjust extract_omp_for_data
caller.
(get_ws_args_for): Adjust extract_omp_for_data caller.
(scan_omp_for): Handle collapsed OMP_FOR
loops, adjust for OMP_FOR_{INIT,COND,INCR} changes.
(lower_omp_single_simple): If libgomp function doesn't return
boolean_type_node, add comparison of the return value with 0.
(diagnose_sb_1, diagnose_sb_2): Handle collapsed OMP_FOR
loops, adjust for OMP_FOR_{INIT,COND,INCR} changes. Handle OMP_TASK.
(parallel_nesting_level): Rename to...
(taskreg_nesting_level): ... this.
(is_taskreg_ctx): New function.
(build_outer_var_ref, omp_copy_decl): Use is_taskreg_ctx instead
of is_parallel_ctx.
(execute_lower_omp): Rename parallel_nesting_level to
taskreg_nesting_level.
(expand_omp_parallel): Rename to...
(expand_omp_taskreg): ... this. Use OMP_TASKREG_* macros where needed.
Call omp_task_call for OMP_TASK regions.
(expand_omp): Adjust caller, handle OMP_TASK.
(lower_omp_1): Adjust lower_omp_taskreg caller, handle OMP_TASK.
* bitmap.c (bitmap_default_obstack_depth): New variable.
(bitmap_obstack_initialize, bitmap_obstack_release): Do nothing
if argument is NULL and bitmap_default_obstack is already initialized.
* ipa-struct-reorg.c (do_reorg_1): Call bitmap_obstack_release
at the end.
* matrix-reorg.c (matrix_reorg): Likewise.
cp/
* cp-tree.h (cxx_omp_finish_clause, cxx_omp_create_clause_info,
dependent_omp_for_p, begin_omp_task, finish_omp_task,
finish_omp_taskwait): New prototypes.
(cxx_omp_clause_default_ctor): Add outer argument.
(finish_omp_for): Add new clauses argument.
* cp-gimplify.c (cxx_omp_finish_clause): New function.
(cxx_omp_predetermined_sharing): Moved from semantics.c, rewritten.
(cxx_omp_clause_default_ctor): Add outer argument.
(cp_genericize_r): Walk OMP_CLAUSE_LASTPRIVATE_STMT.
* cp-objcp-common.h (LANG_HOOKS_OMP_FINISH_CLAUSE): Define.
* parser.c (cp_parser_omp_for_loop): Parse collapsed for loops.
Add par_clauses argument. If decl is present in parallel's
lastprivate clause, change that clause to shared and add
a lastprivate clause for decl to OMP_FOR_CLAUSES.
Fix wording of error messages. Adjust finish_omp_for caller.
Add clauses argument. Parse loops with random access iterators.
(cp_parser_omp_clause_collapse, cp_parser_omp_clause_untied): New
functions.
(cp_parser_omp_for, cp_parser_omp_parallel): Adjust
cp_parser_omp_for_loop callers.
(cp_parser_omp_for_cond, cp_parser_omp_for_incr): New helper
functions.
(cp_parser_omp_clause_name): Handle collapse and untied
clauses.
(cp_parser_omp_clause_schedule): Handle auto schedule.
(cp_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_COLLAPSE
and PRAGMA_OMP_CLAUSE_UNTIED.
(OMP_FOR_CLAUSE_MASK): Add PRAGMA_OMP_CLAUSE_COLLAPSE.
(OMP_TASK_CLAUSE_MASK): Define.
(cp_parser_omp_task, cp_parser_omp_taskwait): New functions.
(cp_parser_omp_construct): Handle PRAGMA_OMP_TASK.
(cp_parser_pragma): Handle PRAGMA_OMP_TASK and
PRAGMA_OMP_TASKWAIT.
* pt.c (tsubst_omp_clauses): Handle OMP_CLAUSE_COLLAPSE and
OMP_CLAUSE_UNTIED. Handle OMP_CLAUSE_LASTPRIVATE_STMT.
(tsubst_omp_for_iterator): New function.
(dependent_omp_for_p): New function.
(tsubst_expr) <case OMP_FOR>: Use it. Handle collapsed OMP_FOR
loops. Adjust finish_omp_for caller. Handle loops with random
access iterators. Adjust for OMP_FOR_{INIT,COND,INCR} changes.
(tsubst_expr): Handle OMP_TASK.
* semantics.c (cxx_omp_create_clause_info): New function.
(finish_omp_clauses): Call it. Handle OMP_CLAUSE_UNTIED and
OMP_CLAUSE_COLLAPSE.
(cxx_omp_predetermined_sharing): Removed.
* semantics.c (finish_omp_for): Allow pointer iterators. Use
handle_omp_for_class_iterator and dependent_omp_for_p. Handle
collapsed for loops. Adjust c_finish_omp_for caller. Add new
clauses argument. Fix check for type dependent cond or incr.
Set OMP_FOR_CLAUSES to clauses. Use cp_convert instead of
fold_convert to convert incr amount to difference_type. Only
fold if not in template. If decl is mentioned in lastprivate
clause, set OMP_CLAUSE_LASTPRIVATE_STMT. Handle loops with random
access iterators. Adjust for OMP_FOR_{INIT,COND,INCR}
changes.
(finish_omp_threadprivate): Allow static class members of the
current class.
(handle_omp_for_class_iterator, begin_omp_task, finish_omp_task,
finish_omp_taskwait): New functions.
* parser.c (cp_parser_binary_expression): Add prec argument.
(cp_parser_assignment_expression): Adjust caller.
* cp-tree.h (outer_curly_brace_block): New prototype.
* decl.c (outer_curly_brace_block): No longer static.
fortran/
* scanner.c (skip_free_comments, skip_fixed_comments): Handle tabs.
* parse.c (next_free): Allow tab after !$omp.
(decode_omp_directive): Handle !$omp task, !$omp taskwait
and !$omp end task.
(case_executable): Add ST_OMP_TASKWAIT.
(case_exec_markers): Add ST_OMP_TASK.
(gfc_ascii_statement): Handle ST_OMP_TASK, ST_OMP_END_TASK and
ST_OMP_TASKWAIT.
(parse_omp_structured_block, parse_executable): Handle ST_OMP_TASK.
* gfortran.h (gfc_find_sym_in_expr): New prototype.
(gfc_statement): Add ST_OMP_TASK, ST_OMP_END_TASK and ST_OMP_TASKWAIT.
(gfc_omp_clauses): Add OMP_SCHED_AUTO to sched_kind,
OMP_DEFAULT_FIRSTPRIVATE to default_sharing. Add collapse and
untied fields.
(gfc_exec_op): Add EXEC_OMP_TASK and EXEC_OMP_TASKWAIT.
* f95-lang.c (LANG_HOOKS_OMP_CLAUSE_COPY_CTOR,
LANG_HOOKS_OMP_CLAUSE_ASSIGN_OP, LANG_HOOKS_OMP_CLAUSE_DTOR,
LANG_HOOKS_OMP_PRIVATE_OUTER_REF): Define.
* trans.h (gfc_omp_clause_default_ctor): Add another argument.
(gfc_omp_clause_copy_ctor, gfc_omp_clause_assign_op,
gfc_omp_clause_dtor, gfc_omp_private_outer_ref): New prototypes.
* types.def (BT_ULONGLONG, BT_PTR_ULONGLONG,
BT_FN_BOOL_ULONGLONGPTR_ULONGLONGPTR,
BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULLPTR_ULLPTR,
BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULL_ULLPTR_ULLPTR,
BT_FN_VOID_PTR_PTR, BT_PTR_FN_VOID_PTR_PTR,
BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT): New.
(BT_BOOL): Use integer type with BOOL_TYPE_SIZE rather
than boolean_type_node.
* dump-parse-tree.c (gfc_show_omp_node): Handle EXEC_OMP_TASK,
EXEC_OMP_TASKWAIT, OMP_SCHED_AUTO, OMP_DEFAULT_FIRSTPRIVATE,
untied and collapse clauses.
(gfc_show_code_node): Handle EXEC_OMP_TASK and EXEC_OMP_TASKWAIT.
* trans.c (gfc_trans_code): Handle EXEC_OMP_TASK and
EXEC_OMP_TASKWAIT.
* st.c (gfc_free_statement): Likewise.
* resolve.c (gfc_resolve_blocks, resolve_code): Likewise.
(find_sym_in_expr): Rename to...
(gfc_find_sym_in_expr): ... this. No longer static.
(resolve_allocate_expr, resolve_ordinary_assign): Adjust caller.
* match.h (gfc_match_omp_task, gfc_match_omp_taskwait): New
prototypes.
* openmp.c (resolve_omp_clauses): Allow allocatable arrays in
firstprivate, lastprivate, reduction, copyprivate and copyin
clauses.
(omp_current_do_code): Made static.
(omp_current_do_collapse): New variable.
(gfc_resolve_omp_do_blocks): Compute omp_current_do_collapse,
clear omp_current_do_code and omp_current_do_collapse on return.
(gfc_resolve_do_iterator): Handle collapsed do loops.
(resolve_omp_do): Likewise, diagnose errorneous collapsed do loops.
(OMP_CLAUSE_COLLAPSE, OMP_CLAUSE_UNTIED): Define.
(gfc_match_omp_clauses): Handle default (firstprivate),
schedule (auto), untied and collapse (n) clauses.
(OMP_DO_CLAUSES): Add OMP_CLAUSE_COLLAPSE.
(OMP_TASK_CLAUSES): Define.
(gfc_match_omp_task, gfc_match_omp_taskwait): New functions.
* trans-openmp.c (gfc_omp_private_outer_ref): New function.
(gfc_omp_clause_default_ctor): Add outer argument. For allocatable
arrays allocate them with the bounds of the outer var if outer
var is allocated.
(gfc_omp_clause_copy_ctor, gfc_omp_clause_assign_op,
gfc_omp_clause_dtor): New functions.
(gfc_trans_omp_array_reduction): If decl is allocatable array,
allocate it with outer var's bounds in OMP_CLAUSE_REDUCTION_INIT
and deallocate it in OMP_CLAUSE_REDUCTION_MERGE.
(gfc_omp_predetermined_sharing): Return OMP_CLAUSE_DEFAULT_SHARED
for assumed-size arrays.
(gfc_trans_omp_do): Add par_clauses argument. If dovar is
present in lastprivate clause and do loop isn't simple,
set OMP_CLAUSE_LASTPRIVATE_STMT. If dovar is present in
parallel's lastprivate clause, change it to shared and add
lastprivate clause to OMP_FOR_CLAUSES. Handle collapsed do loops.
(gfc_trans_omp_directive): Adjust gfc_trans_omp_do callers.
(gfc_trans_omp_parallel_do): Likewise. Move collapse clause to
OMP_FOR from OMP_PARALLEL.
(gfc_trans_omp_clauses): Handle OMP_SCHED_AUTO,
OMP_DEFAULT_FIRSTPRIVATE, untied and collapse clauses.
(gfc_trans_omp_task, gfc_trans_omp_taskwait): New functions.
(gfc_trans_omp_directive): Handle EXEC_OMP_TASK and
EXEC_OMP_TASKWAIT.
gcc/testsuite/
* gcc.dg/gomp/collapse-1.c: New test.
* gcc.dg/gomp/nesting-1.c: New test.
* g++.dg/gomp/task-1.C: New test.
* g++.dg/gomp/predetermined-1.C: New test.
* g++.dg/gomp/tls-4.C: New test.
* gfortran.dg/gomp/collapse1.f90: New test.
* gfortran.dg/gomp/sharing-3.f90: New test.
* gcc.dg/gomp/pr27499.c (foo): Remove is unsigned dg-warning.
* g++.dg/gomp/pr27499.C (foo): Likewise.
* g++.dg/gomp/for-16.C (foo): Likewise.
* g++.dg/gomp/tls-3.C: Remove dg-error, add S::s definition.
* g++.dg/gomp/pr34607.C: Adjust dg-error location.
* g++.dg/gomp/for-16.C (foo): Add a new dg-error.
* gcc.dg/gomp/appendix-a/a.35.4.c: Add dg-warning.
* gcc.dg/gomp/appendix-a/a.35.6.c: Likewise.
* gfortran.dg/gomp/appendix-a/a.35.4.f90: Likewise.
* gfortran.dg/gomp/appendix-a/a.35.6.f90: Likewise.
* gfortran.dg/gomp/omp_parse1.f90: Remove !$omp tab test.
* gfortran.dg/gomp/appendix-a/a.33.4.f90: Remove dg-error
about allocatable array.
* gfortran.dg/gomp/reduction1.f90: Likewise.
libgomp/
* configure.ac (LIBGOMP_GNU_SYMBOL_VERSIONING): New AC_DEFINE.
Substitute also OMP_*LOCK_25*.
* configure: Regenerated.
* config.h.in: Regenerated.
* Makefile.am (libgomp_la_SOURCES): Add loop_ull.c, iter_ull.c,
ptrlock.c and task.c.
* Makefile.in: Regenerated.
* testsuite/Makefile.in: Regenerated.
* task.c: New file.
* loop_ull.c: New file.
* iter_ull.c: New file.
* libgomp.h: Include ptrlock.h.
(enum gomp_task_kind): New type.
(struct gomp_team): Add task_lock, task_queue, task_count,
task_running_count, single_count fields. Add
work_share_list_free_lock ifndef HAVE_SYNC_BUILTINS.
Remove work_share_lock, generation_mask,
oldest_live_gen, num_live_gen and init_work_shares fields, add
work work_share_list_alloc, work_share_list_free and work_share_chunk
fields. Change work_shares from pointer to pointers into an array.
Change ordered_release field into gomp_sem_t ** from flexible array
member. Add implicit_task and initial_work_shares fields.
Move close to the end of the struct.
(struct gomp_team_state): Add single_count, last_work_share,
active_level and level fields, remove work_share_generation.
(gomp_barrier_handle_tasks): New prototype.
(gomp_finish_task): New inline function.
(struct gomp_work_share): Move chunk_size, end, incr into
transparent union/struct, add chunk_size_ull, end_ll, incr_ll and
next_ll fields. Reshuffle fields. Add next_alloc,
next_ws, next_free and inline_ordered_team_ids fields, change
ordered_team_ids into pointer from flexible array member.
Add mode field. Put lock and next into a different cache line
from most of the write-once fields.
(gomp_iter_ull_static_next, gomp_iter_ull_dynamic_next_locked,
gomp_iter_ull_guided_next_locked, gomp_iter_ull_dynamic_next,
gomp_iter_ull_guided_next): New prototypes.
(gomp_new_icv): New prototype.
(struct gomp_thread): Add thread_pool and task fields.
(struct gomp_thread_pool): New type.
(gomp_new_team): New prototype.
(gomp_team_start): Change type of last argument.
(gomp_new_work_share): Removed.
(gomp_init_work_share, gomp_fini_work_share): New prototypes.
(gomp_work_share_init_done): New static inline.
(gomp_throttled_spin_count_var, gomp_available_cpus,
gomp_managed_threads): New extern decls.
(gomp_init_task): New prototype.
(gomp_spin_count_var): New extern var decl.
(LIBGOMP_GNU_SYMBOL_VERSIONING): Undef if no visibility
or no alias support, or if not PIC.
(gomp_init_lock_30, gomp_destroy_lock_30, gomp_set_lock_30,
gomp_unset_lock_30, gomp_test_lock_30, gomp_init_nest_lock_30,
gomp_destroy_nest_lock_30, gomp_set_nest_lock_30,
gomp_unset_nest_lock_30, gomp_test_nest_lock_30, gomp_init_lock_25,
gomp_destroy_lock_25, gomp_set_lock_25, gomp_unset_lock_25,
gomp_test_lock_25, gomp_init_nest_lock_25, gomp_destroy_nest_lock_25,
gomp_set_nest_lock_25, gomp_unset_nest_lock_25,
gomp_test_nest_lock_25): New prototypes.
(omp_lock_symver, strong_alias): Define.
(gomp_remaining_threads_count, gomp_remaining_threads_lock): New
decls.
(gomp_end_task): New.
(struct gomp_task_icv, gomp_global_icv): New.
(gomp_thread_limit_var, gomp_max_active_levels_var): New.
(struct gomp_task): New.
(gomp_nthreads_var, gomp_dyn_var, gomp_nest_var,
gomp_run_sched_var, gomp_run_sched_chunk): Remove.
(gomp_icv): New.
(gomp_schedule_type): Reorder enum to match
omp_sched_t.
* team.c (struct gomp_thread_start_data): Add thread_pool and task
fields.
(gomp_thread_start): Add gomp_team_barrier_wait call.
For non-nested case remove clearing of docked thread thr fields.
Use pool fields instead of global gomp_* variables. Use
gomp_barrier_wait_last when needed. Initialize ts.active_level.
Create tasks for each member thread.
(free_team): Only destroy team barrier, task_lock here and free it.
(gomp_free_thread): Free last_team if non-NULL.
(gomp_team_end): Call gomp_team_barrier_wait instead of
gomp_barrier_wait. For nested case call one extra
gomp_barrier_wait. Move here some destruction from free_team.
Call free_team on pool->last_team if any, rather than freeing
current team. Destroy work_share_list_free_lock ifndef
HAVE_SYNC_BUILTINS.
(gomp_new_icv): New function.
(gomp_threads, gomp_threads_size, gomp_threads_used,
gomp_threads_dock): Removed.
(gomp_thread_destructor): New variable.
(gomp_new_thread_pool, gomp_free_pool_helper, gomp_free_thread): New
functions.
(gomp_team_start): Create new pool if current thread doesn't have
one. Use pool fields instead of global gomp_* variables.
Initialize thread_pool field for new threads. Clear single_count.
Change last argument from ws to team, don't create
new team, set ts.work_share to &team->work_shares[0] and clear
ts.last_work_share. Don't clear ts.work_share_generation.
If number of threads changed, adjust atomically gomp_managed_threads.
Use gomp_init_task instead of gomp_new_task,
set thr->task to the corresponding implicit_task array entry.
Create tasks for each member thread. Initialize ts.level.
(initialize_team): Call pthread_key_create on
gomp_thread_destructor.
(team_destructor): New function.
(new_team): Removed.
(gomp_new_team): New function.
(free_team): Free gomp_work_share blocks chained through next_alloc,
instead of freeing work_shares and destroying work_share_lock.
(gomp_team_end): Call gomp_fini_work_share. If number of threads
changed, adjust atomically gomp_managed_threads. Use gomp_end_task.
* barrier.c (GOMP_barrier): Call gomp_team_barrier_wait instead
of gomp_barrier_wait.
* single.c (GOMP_single_copy_start): Call gomp_team_barrier_wait
instead of gomp_barrier_wait. Call gomp_work_share_init_done
if gomp_work_share_start returned true. Don't unlock ws->lock.
(GOMP_single_copy_end): Call gomp_team_barrier_wait instead
of gomp_barrier_wait.
(GOMP_single_start): Rewritten if HAVE_SYNC_BUILTINS. Call
gomp_work_share_init_done if gomp_work_share_start returned true.
Don't unlock ws->lock.
* work.c: Include stddef.h.
(free_work_share): Use work_share_list_free_lock instead
of atomic chaining ifndef HAVE_SYNC_BUILTINS. Add team argument.
Call gomp_fini_work_share and then either free ws if orphaned, or
put it into work_share_list_free list of the current team.
(alloc_work_share, gomp_init_work_share, gomp_fini_work_share): New
functions.
(gomp_work_share_start, gomp_work_share_end,
gomp_work_share_end_nowait): Rewritten.
* omp_lib.f90.in Change some tabs to spaces to prevent warnings.
(openmp_version): Set to 200805.
(omp_sched_kind, omp_sched_static, omp_sched_dynamic,
omp_sched_guided, omp_sched_auto): New parameters.
(omp_set_schedule, omp_get_schedule, omp_get_thread_limit,
omp_set_max_active_levels, omp_get_max_active_levels,
omp_get_level, omp_get_ancestor_thread_num, omp_get_team_size,
omp_get_active_level): New interfaces.
* omp_lib.h.in (openmp_version): Set to 200805.
(omp_sched_kind, omp_sched_static, omp_sched_dynamic,
omp_sched_guided, omp_sched_auto): New parameters.
(omp_set_schedule, omp_get_schedule, omp_get_thread_limit,
omp_set_max_active_levels, omp_get_max_active_levels,
omp_get_level, omp_get_ancestor_thread_num, omp_get_team_size,
omp_get_active_level): New externals.
* loop.c: Include limits.h.
(GOMP_loop_runtime_next, GOMP_loop_ordered_runtime_next): Handle
GFS_AUTO.
(GOMP_loop_runtime_start, GOMP_loop_ordered_runtime_start):
Likewise. Use gomp_icv.
(gomp_loop_static_start, gomp_loop_dynamic_start): Clear
ts.static_trip here.
(gomp_loop_static_start, gomp_loop_ordered_static_start): Call
gomp_work_share_init_done after gomp_loop_init. Don't unlock ws->lock.
(gomp_loop_dynamic_start, gomp_loop_guided_start): Call
gomp_work_share_init_done after gomp_loop_init. If HAVE_SYNC_BUILTINS,
don't unlock ws->lock, otherwise lock it.
(gomp_loop_ordered_dynamic_start, gomp_loop_ordered_guided_start): Call
gomp_work_share_init_done after gomp_loop_init. Lock ws->lock.
(gomp_parallel_loop_start): Call gomp_new_team instead of
gomp_new_work_share. Call gomp_loop_init on &team->work_shares[0].
Adjust gomp_team_start caller. Pass 0 as second argument to
gomp_resolve_num_threads.
(gomp_loop_init): For GFS_DYNAMIC, multiply ws->chunk_size by incr.
If adding ws->chunk_size nthreads + 1 times after end won't
overflow, set ws->mode to 1.
* libgomp_g.h (GOMP_loop_ull_static_start, GOMP_loop_ull_dynamic_start,
GOMP_loop_ull_guided_start, GOMP_loop_ull_runtime_start,
GOMP_loop_ull_ordered_static_start,
GOMP_loop_ull_ordered_dynamic_start,
GOMP_loop_ull_ordered_guided_start,
GOMP_loop_ull_ordered_runtime_start, GOMP_loop_ull_static_next,
GOMP_loop_ull_dynamic_next, GOMP_loop_ull_guided_next,
GOMP_loop_ull_runtime_next, GOMP_loop_ull_ordered_static_next,
GOMP_loop_ull_ordered_dynamic_next, GOMP_loop_ull_ordered_guided_next,
GOMP_loop_ull_ordered_runtime_next, GOMP_task, GOMP_taskwait): New
prototypes.
* libgomp.map: Export lock routines also @@OMP_2.0.
(GOMP_loop_ordered_dynamic_first,
GOMP_loop_ordered_guided_first, GOMP_loop_ordered_runtime_first,
GOMP_loop_ordered_static_first): Remove.
(GOMP_loop_ull_dynamic_next, GOMP_loop_ull_dynamic_start,
GOMP_loop_ull_guided_next, GOMP_loop_ull_guided_start,
GOMP_loop_ull_ordered_dynamic_next,
GOMP_loop_ull_ordered_dynamic_start,
GOMP_loop_ull_ordered_guided_next,
GOMP_loop_ull_ordered_guided_start,
GOMP_loop_ull_ordered_runtime_next,
GOMP_loop_ull_ordered_runtime_start,
GOMP_loop_ull_ordered_static_next,
GOMP_loop_ull_ordered_static_start,
GOMP_loop_ull_runtime_next, GOMP_loop_ull_runtime_start,
GOMP_loop_ull_static_next, GOMP_loop_ull_static_start,
GOMP_task, GOMP_taskwait): Export @@GOMP_2.0.
(omp_set_schedule, omp_get_schedule,
omp_get_thread_limit, omp_set_max_active_levels,
omp_get_max_active_levels, omp_get_level,
omp_get_ancestor_thread_num, omp_get_team_size, omp_get_active_level,
omp_set_schedule_, omp_set_schedule_8_,
omp_get_schedule_, omp_get_schedule_8_, omp_get_thread_limit_,
omp_set_max_active_levels_, omp_set_max_active_levels_8_,
omp_get_max_active_levels_, omp_get_level_,
omp_get_ancestor_thread_num_, omp_get_ancestor_thread_num_8_,
omp_get_team_size_, omp_get_team_size_8_, omp_get_active_level_):
New exports @@OMP_3.0.
* omp.h.in (omp_sched_t): New type.
(omp_set_schedule, omp_get_schedule, omp_get_thread_limit,
omp_set_max_active_levels, omp_get_max_active_levels,
omp_get_level, omp_get_ancestor_thread_num, omp_get_team_size,
omp_get_active_level): New prototypes.
* env.c (gomp_spin_count_var, gomp_throttled_spin_count_var,
gomp_available_cpus, gomp_managed_threads, gomp_max_active_levels_var,
gomp_thread_limit_var, gomp_remaining_threads_count,
gomp_remaining_threads_lock): New variables.
(parse_spincount): New function.
(initialize_env): Call gomp_init_num_threads unconditionally.
Initialize gomp_available_cpus. Call parse_spincount,
initialize gomp_{,throttled_}spin_count_var
depending on presence and value of OMP_WAIT_POLICY and
GOMP_SPINCOUNT env vars. Handle GOMP_BLOCKTIME env var.
Handle OMP_WAIT_POLICY, OMP_MAX_ACTIVE_LEVELS,
OMP_THREAD_LIMIT, OMP_STACKSIZE env vars. Handle unit specification
for GOMP_STACKSIZE. Initialize gomp_remaining_threads_count and
gomp_remaining_threads_lock if needed. Use gomp_global_icv.
(gomp_nthreads_var, gomp_dyn_var, gomp_nest_var,
gomp_run_sched_var, gomp_run_sched_chunk): Remove.
(gomp_global_icv): New.
(parse_schedule): Use it. Parse "auto".
(omp_set_num_threads): Use gomp_icv.
(omp_set_dynamic, omp_get_dynamic, omp_set_nested, omp_get_nested):
Likewise.
(omp_get_max_threads): Move from parallel.c.
(omp_set_schedule, omp_get_schedule, omp_get_thread_limit,
omp_set_max_active_levels, omp_get_max_active_levels): New functions,
add ialias.
(parse_stacksize, parse_wait_policy): New functions.
* fortran.c: Rewrite lock wrappers, if symbol versioning provide
both wrappers for compatibility and new locks.
(omp_set_schedule, omp_get_schedule,
omp_get_thread_limit, omp_set_max_active_levels,
omp_get_max_active_levels, omp_get_level,
omp_get_ancestor_thread_num, omp_get_team_size,
omp_get_active_level): New ialias_redirect.
(omp_set_schedule_, omp_set_schedule_8_,
omp_get_schedule_, omp_get_schedule_8_, omp_get_thread_limit_,
omp_set_max_active_levels_, omp_set_max_active_levels_8_,
omp_get_max_active_levels_, omp_get_level_,
omp_get_ancestor_thread_num_, omp_get_ancestor_thread_num_8_,
omp_get_team_size_, omp_get_team_size_8_, omp_get_active_level_):
New functions.
* parallel.c: Include limits.h.
(gomp_resolve_num_threads): Add count argument. Rewritten.
(GOMP_parallel_start): Call gomp_new_team and pass that as last
argument to gomp_team_start. Pass 0 as second argument to
gomp_resolve_num_threads.
(GOMP_parallel_end): Decrease gomp_remaining_threads_count
if gomp_thread_limit_var != ULONG_MAX.
(omp_in_parallel): Implement using ts.active_level.
(omp_get_max_threads): Move to env.c.
(omp_get_level, omp_get_ancestor_thread_num,
omp_get_team_size, omp_get_active_level): New functions,
add ialias.
* sections.c (GOMP_sections_start): Call gomp_work_share_init_done
after gomp_sections_init. If HAVE_SYNC_BUILTINS, call
gomp_iter_dynamic_next instead of the _locked variant and don't take
lock around it, otherwise acquire it before calling
gomp_iter_dynamic_next_locked.
(GOMP_sections_next): If HAVE_SYNC_BUILTINS, call
gomp_iter_dynamic_next instead of the _locked variant and don't take
lock around it.
(GOMP_parallel_sections_start): Call gomp_new_team instead of
gomp_new_work_share. Call gomp_sections_init on &team->work_shares[0].
Adjust gomp_team_start caller. Pass count as second argument to
gomp_resolve_num_threads, don't adjust num_threads after the call.
Use gomp_icv.
* iter.c (gomp_iter_dynamic_next_locked): Don't multiply
ws->chunk_size by incr.
(gomp_iter_dynamic_next): Likewise. If ws->mode, use more efficient
code.
* libgomp_f.h.in (omp_lock_25_arg_t, omp_nest_lock_25_arg_t): New
types.
(omp_lock_25_arg, omp_nest_lock_25_arg): New macros.
(omp_check_defines): Check even the compat defines.
* config/linux/ptrlock.c: New file.
* config/linux/ptrlock.h: New file.
* config/linux/wait.h: New file.
* config/posix/ptrlock.c: New file.
* config/posix/ptrlock.h: New file.
* config/linux/bar.h (gomp_team_barrier_wait,
gomp_team_barrier_wait_end, gomp_team_barrier_wake): New prototypes.
(gomp_team_barrier_set_task_pending,
gomp_team_barrier_clear_task_pending,
gomp_team_barrier_set_waiting_for_tasks,
gomp_team_barrier_waiting_for_tasks,
gomp_team_barrier_done): New inlines.
(gomp_barrier_t): Rewritten.
(gomp_barrier_state_t): New typedef.
(gomp_barrier_init, gomp_barrier_reinit, gomp_barrier_destroy,
gomp_barrier_wait_start): Rewritten.
(gomp_barrier_wait_end): Change second argument to
gomp_barrier_state_t.
(gomp_barrier_last_thread, gomp_barrier_wait_last): New static
inlines.
* config/linux/bar.c: Include wait.h instead of libgomp.h and
futex.h.
(gomp_barrier_wait_end): Rewritten.
(gomp_team_barrier_wait, gomp_team_barrier_wait_end,
gomp_team_barrier_wake, gomp_barrier_wait_last): New functions.
* config/posix/bar.h (gomp_barrier_t): Add generation field.
(gomp_barrier_state_t): New typedef.
(gomp_team_barrier_wait,
gomp_team_barrier_wait_end, gomp_team_barrier_wake): New prototypes.
(gomp_barrier_wait_start): Or all but low 2 bits from generation
into the return value. Return gomp_barrier_state_t.
(gomp_team_barrier_set_task_pending,
gomp_team_barrier_clear_task_pending,
gomp_team_barrier_set_waiting_for_tasks,
gomp_team_barrier_waiting_for_tasks,
gomp_team_barrier_done): New inlines.
(gomp_barrier_wait_end): Change second argument to
gomp_barrier_state_t.
(gomp_barrier_last_thread, gomp_barrier_wait_last): New static
inlines.
* config/posix/bar.c (gomp_barrier_init): Clear generation field.
(gomp_barrier_wait_end): Change second argument to
gomp_barrier_state_t.
(gomp_team_barrier_wait, gomp_team_barrier_wait_end,
gomp_team_barrier_wake): New functions.
* config/linux/mutex.c: Include wait.h instead of libgomp.h and
futex.h.
(gomp_futex_wake, gomp_futex_wait): New variables.
(gomp_mutex_lock_slow): Call do_wait instead of futex_wait.
* config/linux/lock.c: Rewrite to make locks task owned,
for backwards compatibility provide the old entrypoints
if symbol versioning. Include wait.h instead of libgomp.h and
futex.h.
(gomp_set_nest_lock_25): Call do_wait instead of futex_wait.
* config/posix95/lock.c: Rewrite to make locks task owned,
for backwards compatibility provide the old entrypoints
if symbol versioning.
* config/posix/lock.c: Rewrite to make locks task owned,
for backwards compatibility provide the old entrypoints
if symbol versioning.
* config/linux/proc.c (gomp_init_num_threads): Use gomp_global_icv.
(get_num_procs, gomp_dynamic_max_threads): Use gomp_icv.
* config/posix/proc.c, config/mingw32/proc.c: Similarly.
* config/linux/powerpc/futex.h (FUTEX_WAIT, FUTEX_WAKE): Remove.
(sys_futex0): Return error code.
(futex_wake, futex_wait): If ENOSYS was returned, clear
FUTEX_PRIVATE_FLAG in gomp_futex_wa{ke,it} and retry.
(cpu_relax, atomic_write_barrier): New static inlines.
* config/linux/alpha/futex.h (FUTEX_WAIT, FUTEX_WAKE): Remove.
(futex_wake, futex_wait): If ENOSYS was returned, clear
FUTEX_PRIVATE_FLAG in gomp_futex_wa{ke,it} and retry.
(cpu_relax, atomic_write_barrier): New static inlines.
* config/linux/x86/futex.h (FUTEX_WAIT, FUTEX_WAKE): Remove.
(sys_futex0): Return error code.
(futex_wake, futex_wait): If ENOSYS was returned, clear
FUTEX_PRIVATE_FLAG in gomp_futex_wa{ke,it} and retry.
(cpu_relax, atomic_write_barrier): New static inlines.
* config/linux/s390/futex.h (FUTEX_WAIT, FUTEX_WAKE): Remove.
(sys_futex0): Return error code.
(futex_wake, futex_wait): If ENOSYS was returned, clear
FUTEX_PRIVATE_FLAG in gomp_futex_wa{ke,it} and retry.
(cpu_relax, atomic_write_barrier): New static inlines.
* config/linux/ia64/futex.h (FUTEX_WAIT, FUTEX_WAKE): Remove.
(sys_futex0): Return error code.
(futex_wake, futex_wait): If ENOSYS was returned, clear
FUTEX_PRIVATE_FLAG in gomp_futex_wa{ke,it} and retry.
(cpu_relax, atomic_write_barrier): New static inlines.
* config/linux/sparc/futex.h (FUTEX_WAIT, FUTEX_WAKE): Remove.
(sys_futex0): Return error code.
(futex_wake, futex_wait): If ENOSYS was returned, clear
FUTEX_PRIVATE_FLAG in gomp_futex_wa{ke,it} and retry.
(cpu_relax, atomic_write_barrier): New static inlines.
* config/linux/sem.c: Include wait.h instead of libgomp.h and
futex.h.
(gomp_sem_wait_slow): Call do_wait instead of futex_wait.
* config/linux/affinity.c: Assume HAVE_SYNC_BUILTINS.
* config/linux/omp-lock.h (omp_lock_25_t, omp_nest_lock_25_t): New
types.
(omp_nest_lock_t): Change owner into void *, add lock field.
* config/posix95/omp-lock.h: Include semaphore.h.
(omp_lock_25_t, omp_nest_lock_25_t): New types.
(omp_lock_t): Use sem_t instead of mutex if semaphores
aren't broken.
(omp_nest_lock_t): Likewise. Change owner to void *.
* config/posix/omp-lock.h: Include semaphore.h.
(omp_lock_25_t, omp_nest_lock_25_t): New types.
(omp_lock_t): Use sem_t instead of mutex if semaphores
aren't broken.
(omp_nest_lock_t): Likewise. Add owner field.
* testsuite/libgomp.c/collapse-1.c: New test.
* testsuite/libgomp.c/collapse-2.c: New test.
* testsuite/libgomp.c/collapse-3.c: New test.
* testsuite/libgomp.c/icv-1.c: New test.
* testsuite/libgomp.c/icv-2.c: New test.
* testsuite/libgomp.c/lib-2.c: New test.
* testsuite/libgomp.c/lock-1.c: New test.
* testsuite/libgomp.c/lock-2.c: New test.
* testsuite/libgomp.c/lock-3.c: New test.
* testsuite/libgomp.c/loop-4.c: New test.
* testsuite/libgomp.c/loop-5.c: New test.
* testsuite/libgomp.c/loop-6.c: New test.
* testsuite/libgomp.c/loop-7.c: New test.
* testsuite/libgomp.c/loop-8.c: New test.
* testsuite/libgomp.c/loop-9.c: New test.
* testsuite/libgomp.c/nested-3.c: New test.
* testsuite/libgomp.c/nestedfn-6.c: New test.
* testsuite/libgomp.c/sort-1.c: New test.
* testsuite/libgomp.c/task-1.c: New test.
* testsuite/libgomp.c/task-2.c: New test.
* testsuite/libgomp.c/task-3.c: New test.
* testsuite/libgomp.c/task-4.c: New test.
* testsuite/libgomp.c++/c++.exp: Add libstdc++-v3 build includes
to C++ testsuite default compiler options.
* testsuite/libgomp.c++/collapse-1.C: New test.
* testsuite/libgomp.c++/collapse-2.C: New test.
* testsuite/libgomp.c++/ctor-10.C: New test.
* testsuite/libgomp.c++/for-1.C: New test.
* testsuite/libgomp.c++/for-2.C: New test.
* testsuite/libgomp.c++/for-3.C: New test.
* testsuite/libgomp.c++/for-4.C: New test.
* testsuite/libgomp.c++/for-5.C: New test.
* testsuite/libgomp.c++/loop-8.C: New test.
* testsuite/libgomp.c++/loop-9.C: New test.
* testsuite/libgomp.c++/loop-10.C: New test.
* testsuite/libgomp.c++/task-1.C: New test.
* testsuite/libgomp.c++/task-2.C: New test.
* testsuite/libgomp.c++/task-3.C: New test.
* testsuite/libgomp.c++/task-4.C: New test.
* testsuite/libgomp.c++/task-5.C: New test.
* testsuite/libgomp.c++/task-6.C: New test.
* testsuite/libgomp.fortran/allocatable1.f90: New test.
* testsuite/libgomp.fortran/allocatable2.f90: New test.
* testsuite/libgomp.fortran/allocatable3.f90: New test.
* testsuite/libgomp.fortran/allocatable4.f90: New test.
* testsuite/libgomp.fortran/collapse1.f90: New test.
* testsuite/libgomp.fortran/collapse2.f90: New test.
* testsuite/libgomp.fortran/collapse3.f90: New test.
* testsuite/libgomp.fortran/collapse4.f90: New test.
* testsuite/libgomp.fortran/lastprivate1.f90: New test.
* testsuite/libgomp.fortran/lastprivate2.f90: New test.
* testsuite/libgomp.fortran/lib4.f90: New test.
* testsuite/libgomp.fortran/lock-1.f90: New test.
* testsuite/libgomp.fortran/lock-2.f90: New test.
* testsuite/libgomp.fortran/nested1.f90: New test.
* testsuite/libgomp.fortran/nestedfn4.f90: New test.
* testsuite/libgomp.fortran/strassen.f90: New test.
* testsuite/libgomp.fortran/tabs1.f90: New test.
* testsuite/libgomp.fortran/tabs2.f: New test.
* testsuite/libgomp.fortran/task1.f90: New test.
* testsuite/libgomp.fortran/task2.f90: New test.
* testsuite/libgomp.fortran/vla4.f90: Add dg-warning.
* testsuite/libgomp.fortran/vla5.f90: Likewise.
* testsuite/libgomp.c/pr26943-2.c: Likewise.
* testsuite/libgomp.c/pr26943-3.c: Likewise.
* testsuite/libgomp.c/pr26943-4.c: Likewise.
Co-Authored-By: Jakob Blomer <jakob.blomer@ira.uka.de>
Co-Authored-By: Richard Henderson <rth@redhat.com>
Co-Authored-By: Ulrich Drepper <drepper@redhat.com>
From-SVN: r136433
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/ChangeLog | 67 | ||||
-rw-r--r-- | gcc/cp/call.c | 2 | ||||
-rw-r--r-- | gcc/cp/cp-gimplify.c | 111 | ||||
-rw-r--r-- | gcc/cp/cp-objcp-common.h | 2 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 11 | ||||
-rw-r--r-- | gcc/cp/decl.c | 2 | ||||
-rw-r--r-- | gcc/cp/parser.c | 676 | ||||
-rw-r--r-- | gcc/cp/pt.c | 255 | ||||
-rw-r--r-- | gcc/cp/semantics.c | 691 |
9 files changed, 1534 insertions, 283 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 54afddc..936db24 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,70 @@ +2008-06-06 Jakub Jelinek <jakub@redhat.com> + + * cp-tree.h (cxx_omp_finish_clause, cxx_omp_create_clause_info, + dependent_omp_for_p, begin_omp_task, finish_omp_task, + finish_omp_taskwait): New prototypes. + (cxx_omp_clause_default_ctor): Add outer argument. + (finish_omp_for): Add new clauses argument. + * cp-gimplify.c (cxx_omp_finish_clause): New function. + (cxx_omp_predetermined_sharing): Moved from semantics.c, rewritten. + (cxx_omp_clause_default_ctor): Add outer argument. + (cp_genericize_r): Walk OMP_CLAUSE_LASTPRIVATE_STMT. + * cp-objcp-common.h (LANG_HOOKS_OMP_FINISH_CLAUSE): Define. + * parser.c (cp_parser_omp_for_loop): Parse collapsed for loops. + Add par_clauses argument. If decl is present in parallel's + lastprivate clause, change that clause to shared and add + a lastprivate clause for decl to OMP_FOR_CLAUSES. + Fix wording of error messages. Adjust finish_omp_for caller. + Add clauses argument. Parse loops with random access iterators. + (cp_parser_omp_clause_collapse, cp_parser_omp_clause_untied): New + functions. + (cp_parser_omp_for, cp_parser_omp_parallel): Adjust + cp_parser_omp_for_loop callers. + (cp_parser_omp_for_cond, cp_parser_omp_for_incr): New helper + functions. + (cp_parser_omp_clause_name): Handle collapse and untied + clauses. + (cp_parser_omp_clause_schedule): Handle auto schedule. + (cp_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_COLLAPSE + and PRAGMA_OMP_CLAUSE_UNTIED. + (OMP_FOR_CLAUSE_MASK): Add PRAGMA_OMP_CLAUSE_COLLAPSE. + (OMP_TASK_CLAUSE_MASK): Define. + (cp_parser_omp_task, cp_parser_omp_taskwait): New functions. + (cp_parser_omp_construct): Handle PRAGMA_OMP_TASK. + (cp_parser_pragma): Handle PRAGMA_OMP_TASK and + PRAGMA_OMP_TASKWAIT. + * pt.c (tsubst_omp_clauses): Handle OMP_CLAUSE_COLLAPSE and + OMP_CLAUSE_UNTIED. Handle OMP_CLAUSE_LASTPRIVATE_STMT. + (tsubst_omp_for_iterator): New function. + (dependent_omp_for_p): New function. + (tsubst_expr) <case OMP_FOR>: Use it. Handle collapsed OMP_FOR + loops. Adjust finish_omp_for caller. Handle loops with random + access iterators. Adjust for OMP_FOR_{INIT,COND,INCR} changes. + (tsubst_expr): Handle OMP_TASK. + * semantics.c (cxx_omp_create_clause_info): New function. + (finish_omp_clauses): Call it. Handle OMP_CLAUSE_UNTIED and + OMP_CLAUSE_COLLAPSE. + (cxx_omp_predetermined_sharing): Removed. + * semantics.c (finish_omp_for): Allow pointer iterators. Use + handle_omp_for_class_iterator and dependent_omp_for_p. Handle + collapsed for loops. Adjust c_finish_omp_for caller. Add new + clauses argument. Fix check for type dependent cond or incr. + Set OMP_FOR_CLAUSES to clauses. Use cp_convert instead of + fold_convert to convert incr amount to difference_type. Only + fold if not in template. If decl is mentioned in lastprivate + clause, set OMP_CLAUSE_LASTPRIVATE_STMT. Handle loops with random + access iterators. Adjust for OMP_FOR_{INIT,COND,INCR} + changes. + (finish_omp_threadprivate): Allow static class members of the + current class. + (handle_omp_for_class_iterator, begin_omp_task, finish_omp_task, + finish_omp_taskwait): New functions. + + * parser.c (cp_parser_binary_expression): Add prec argument. + (cp_parser_assignment_expression): Adjust caller. + * cp-tree.h (outer_curly_brace_block): New prototype. + * decl.c (outer_curly_brace_block): No longer static. + 2008-06-02 Paolo Carlini <paolo.carlini@oracle.com> PR c++/36404 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 0948c79..1d54e7c 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -333,7 +333,7 @@ build_call_a (tree function, int n, tree *argarray) nothrow = ((decl && TREE_NOTHROW (decl)) || TYPE_NOTHROW_P (TREE_TYPE (TREE_TYPE (function)))); - if (decl && TREE_THIS_VOLATILE (decl) && cfun) + if (decl && TREE_THIS_VOLATILE (decl) && cfun && cp_function_chain) current_function_returns_abnormally = 1; if (decl && TREE_DEPRECATED (decl)) diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index cc3e847..c6d64df 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -694,10 +694,19 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) else if (TREE_CODE (stmt) == OMP_CLAUSE) switch (OMP_CLAUSE_CODE (stmt)) { + case OMP_CLAUSE_LASTPRIVATE: + /* Don't dereference an invisiref in OpenMP clauses. */ + if (is_invisiref_parm (OMP_CLAUSE_DECL (stmt))) + { + *walk_subtrees = 0; + if (OMP_CLAUSE_LASTPRIVATE_STMT (stmt)) + cp_walk_tree (&OMP_CLAUSE_LASTPRIVATE_STMT (stmt), + cp_genericize_r, p_set, NULL); + } + break; case OMP_CLAUSE_PRIVATE: case OMP_CLAUSE_SHARED: case OMP_CLAUSE_FIRSTPRIVATE: - case OMP_CLAUSE_LASTPRIVATE: case OMP_CLAUSE_COPYIN: case OMP_CLAUSE_COPYPRIVATE: /* Don't dereference an invisiref in OpenMP clauses. */ @@ -893,7 +902,8 @@ cxx_omp_clause_apply_fn (tree fn, tree arg1, tree arg2) NULL if there's nothing to do. */ tree -cxx_omp_clause_default_ctor (tree clause, tree decl) +cxx_omp_clause_default_ctor (tree clause, tree decl, + tree outer ATTRIBUTE_UNUSED) { tree info = CP_OMP_CLAUSE_INFO (clause); tree ret = NULL; @@ -958,3 +968,100 @@ cxx_omp_privatize_by_reference (const_tree decl) { return is_invisiref_parm (decl); } + +/* True if OpenMP sharing attribute of DECL is predetermined. */ + +enum omp_clause_default_kind +cxx_omp_predetermined_sharing (tree decl) +{ + tree type; + + /* Static data members are predetermined as shared. */ + if (TREE_STATIC (decl)) + { + tree ctx = CP_DECL_CONTEXT (decl); + if (TYPE_P (ctx) && MAYBE_CLASS_TYPE_P (ctx)) + return OMP_CLAUSE_DEFAULT_SHARED; + } + + type = TREE_TYPE (decl); + if (TREE_CODE (type) == REFERENCE_TYPE) + { + if (!is_invisiref_parm (decl)) + return OMP_CLAUSE_DEFAULT_UNSPECIFIED; + type = TREE_TYPE (type); + + if (TREE_CODE (decl) == RESULT_DECL && DECL_NAME (decl)) + { + /* NVR doesn't preserve const qualification of the + variable's type. */ + tree outer = outer_curly_brace_block (current_function_decl); + tree var; + + if (outer) + for (var = BLOCK_VARS (outer); var; var = TREE_CHAIN (var)) + if (DECL_NAME (decl) == DECL_NAME (var) + && (TYPE_MAIN_VARIANT (type) + == TYPE_MAIN_VARIANT (TREE_TYPE (var)))) + { + if (TYPE_READONLY (TREE_TYPE (var))) + type = TREE_TYPE (var); + break; + } + } + } + + if (type == error_mark_node) + return OMP_CLAUSE_DEFAULT_UNSPECIFIED; + + /* Variables with const-qualified type having no mutable member + are predetermined shared. */ + if (TYPE_READONLY (type) && !cp_has_mutable_p (type)) + return OMP_CLAUSE_DEFAULT_SHARED; + + return OMP_CLAUSE_DEFAULT_UNSPECIFIED; +} + +/* Finalize an implicitly determined clause. */ + +void +cxx_omp_finish_clause (tree c) +{ + tree decl, inner_type; + bool make_shared = false; + + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_FIRSTPRIVATE) + return; + + decl = OMP_CLAUSE_DECL (c); + decl = require_complete_type (decl); + inner_type = TREE_TYPE (decl); + if (decl == error_mark_node) + make_shared = true; + else if (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE) + { + if (is_invisiref_parm (decl)) + inner_type = TREE_TYPE (inner_type); + else + { + error ("%qE implicitly determined as %<firstprivate%> has reference type", + decl); + make_shared = true; + } + } + + /* We're interested in the base element, not arrays. */ + while (TREE_CODE (inner_type) == ARRAY_TYPE) + inner_type = TREE_TYPE (inner_type); + + /* Check for special function availability by building a call to one. + Save the results, because later we won't be in the right context + for making these queries. */ + if (!make_shared + && CLASS_TYPE_P (inner_type) + && cxx_omp_create_clause_info (c, inner_type, false, true, false)) + make_shared = true; + + if (make_shared) + OMP_CLAUSE_CODE (c) = OMP_CLAUSE_SHARED; +} diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h index b2b8405..1121eb0 100644 --- a/gcc/cp/cp-objcp-common.h +++ b/gcc/cp/cp-objcp-common.h @@ -141,6 +141,8 @@ extern tree objcp_tsubst_copy_and_build (tree, tree, tsubst_flags_t, #define LANG_HOOKS_OMP_CLAUSE_ASSIGN_OP cxx_omp_clause_assign_op #undef LANG_HOOKS_OMP_CLAUSE_DTOR #define LANG_HOOKS_OMP_CLAUSE_DTOR cxx_omp_clause_dtor +#undef LANG_HOOKS_OMP_FINISH_CLAUSE +#define LANG_HOOKS_OMP_FINISH_CLAUSE cxx_omp_finish_clause #undef LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE #define LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE cxx_omp_privatize_by_reference diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 0c3d0dd..952020a 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4235,6 +4235,7 @@ extern void start_preparsed_function (tree, tree, int); extern int start_function (cp_decl_specifier_seq *, const cp_declarator *, tree); extern tree begin_function_body (void); extern void finish_function_body (tree); +extern tree outer_curly_brace_block (tree); extern tree finish_function (int); extern tree start_method (cp_decl_specifier_seq *, const cp_declarator *, tree); extern tree finish_method (tree); @@ -4468,6 +4469,7 @@ extern bool type_dependent_expression_p (tree); extern bool any_type_dependent_arguments_p (const_tree); extern bool value_dependent_expression_p (tree); extern bool any_value_dependent_elements_p (const_tree); +extern bool dependent_omp_for_p (tree, tree, tree, tree); extern tree resolve_typename_type (tree, bool); extern tree template_for_substitution (tree); extern tree build_non_dependent_expr (tree); @@ -4666,17 +4668,22 @@ extern tree begin_omp_structured_block (void); extern tree finish_omp_structured_block (tree); extern tree begin_omp_parallel (void); extern tree finish_omp_parallel (tree, tree); +extern tree begin_omp_task (void); +extern tree finish_omp_task (tree, tree); extern tree finish_omp_for (location_t, tree, tree, - tree, tree, tree, tree); + tree, tree, tree, tree, tree); extern void finish_omp_atomic (enum tree_code, tree, tree); extern void finish_omp_barrier (void); extern void finish_omp_flush (void); +extern void finish_omp_taskwait (void); extern enum omp_clause_default_kind cxx_omp_predetermined_sharing (tree); -extern tree cxx_omp_clause_default_ctor (tree, tree); +extern tree cxx_omp_clause_default_ctor (tree, tree, tree); extern tree cxx_omp_clause_copy_ctor (tree, tree, tree); extern tree cxx_omp_clause_assign_op (tree, tree, tree); extern tree cxx_omp_clause_dtor (tree, tree); +extern void cxx_omp_finish_clause (tree); extern bool cxx_omp_privatize_by_reference (const_tree); +extern bool cxx_omp_create_clause_info (tree, tree, bool, bool, bool); extern tree baselink_for_fns (tree); extern void finish_static_assert (tree, tree, location_t, bool); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 0898d5d..8056518 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -11759,7 +11759,7 @@ finish_function_body (tree compstmt) of curly braces, skipping the artificial block created for constructor initializers. */ -static tree +tree outer_curly_brace_block (tree fndecl) { tree block = BLOCK_SUBBLOCKS (DECL_INITIAL (fndecl)); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index c3383e6..5ca1bd7 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1611,7 +1611,7 @@ static tree cp_parser_delete_expression static tree cp_parser_cast_expression (cp_parser *, bool, bool); static tree cp_parser_binary_expression - (cp_parser *, bool); + (cp_parser *, bool, enum cp_parser_prec); static tree cp_parser_question_colon_clause (cp_parser *, tree); static tree cp_parser_assignment_expression @@ -6008,14 +6008,15 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p) : binops_by_token[token->type].prec) static tree -cp_parser_binary_expression (cp_parser* parser, bool cast_p) +cp_parser_binary_expression (cp_parser* parser, bool cast_p, + enum cp_parser_prec prec) { cp_parser_expression_stack stack; cp_parser_expression_stack_entry *sp = &stack[0]; tree lhs, rhs; cp_token *token; enum tree_code tree_type, lhs_type, rhs_type; - enum cp_parser_prec prec = PREC_NOT_OPERATOR, new_prec, lookahead_prec; + enum cp_parser_prec new_prec, lookahead_prec; bool overloaded_p; /* Parse the first expression. */ @@ -6192,7 +6193,7 @@ cp_parser_assignment_expression (cp_parser* parser, bool cast_p) else { /* Parse the binary expressions (logical-or-expression). */ - expr = cp_parser_binary_expression (parser, cast_p); + expr = cp_parser_binary_expression (parser, cast_p, PREC_NOT_OPERATOR); /* If the next token is a `?' then we're actually looking at a conditional-expression. */ if (cp_lexer_next_token_is (parser->lexer, CPP_QUERY)) @@ -19493,7 +19494,9 @@ cp_parser_omp_clause_name (cp_parser *parser) switch (p[0]) { case 'c': - if (!strcmp ("copyin", p)) + if (!strcmp ("collapse", p)) + result = PRAGMA_OMP_CLAUSE_COLLAPSE; + else if (!strcmp ("copyin", p)) result = PRAGMA_OMP_CLAUSE_COPYIN; else if (!strcmp ("copyprivate", p)) result = PRAGMA_OMP_CLAUSE_COPYPRIVATE; @@ -19526,6 +19529,10 @@ cp_parser_omp_clause_name (cp_parser *parser) else if (!strcmp ("shared", p)) result = PRAGMA_OMP_CLAUSE_SHARED; break; + case 'u': + if (!strcmp ("untied", p)) + result = PRAGMA_OMP_CLAUSE_UNTIED; + break; } } @@ -19628,6 +19635,47 @@ cp_parser_omp_var_list (cp_parser *parser, enum omp_clause_code kind, tree list) return list; } +/* OpenMP 3.0: + collapse ( constant-expression ) */ + +static tree +cp_parser_omp_clause_collapse (cp_parser *parser, tree list) +{ + tree c, num; + location_t loc; + HOST_WIDE_INT n; + + loc = cp_lexer_peek_token (parser->lexer)->location; + if (!cp_parser_require (parser, CPP_OPEN_PAREN, "%<(%>")) + return list; + + num = cp_parser_constant_expression (parser, false, NULL); + + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "%<)%>")) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + if (num == error_mark_node) + return list; + num = fold_non_dependent_expr (num); + if (!INTEGRAL_TYPE_P (TREE_TYPE (num)) + || !host_integerp (num, 0) + || (n = tree_low_cst (num, 0)) <= 0 + || (int) n != n) + { + error ("%Hcollapse argument needs positive constant integer expression", &loc); + return list; + } + + check_no_duplicate_clause (list, OMP_CLAUSE_COLLAPSE, "collapse"); + c = build_omp_clause (OMP_CLAUSE_COLLAPSE); + OMP_CLAUSE_CHAIN (c) = list; + OMP_CLAUSE_COLLAPSE_EXPR (c) = num; + + return c; +} + /* OpenMP 2.5: default ( shared | none ) */ @@ -19839,7 +19887,7 @@ cp_parser_omp_clause_reduction (cp_parser *parser, tree list) schedule ( schedule-kind , expression ) schedule-kind: - static | dynamic | guided | runtime */ + static | dynamic | guided | runtime | auto */ static tree cp_parser_omp_clause_schedule (cp_parser *parser, tree list) @@ -19882,6 +19930,8 @@ cp_parser_omp_clause_schedule (cp_parser *parser, tree list) } else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_STATIC)) OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_STATIC; + else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_AUTO)) + OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_AUTO; else goto invalid_kind; cp_lexer_consume_token (parser->lexer); @@ -19897,6 +19947,9 @@ cp_parser_omp_clause_schedule (cp_parser *parser, tree list) else if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_RUNTIME) error ("schedule %<runtime%> does not take " "a %<chunk_size%> parameter"); + else if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_AUTO) + error ("schedule %<auto%> does not take " + "a %<chunk_size%> parameter"); else OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c) = t; @@ -19919,6 +19972,21 @@ cp_parser_omp_clause_schedule (cp_parser *parser, tree list) return list; } +/* OpenMP 3.0: + untied */ + +static tree +cp_parser_omp_clause_untied (cp_parser *parser ATTRIBUTE_UNUSED, tree list) +{ + tree c; + + check_no_duplicate_clause (list, OMP_CLAUSE_UNTIED, "untied"); + + c = build_omp_clause (OMP_CLAUSE_UNTIED); + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + /* 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. */ @@ -19944,6 +20012,10 @@ cp_parser_omp_all_clauses (cp_parser *parser, unsigned int mask, switch (c_kind) { + case PRAGMA_OMP_CLAUSE_COLLAPSE: + clauses = cp_parser_omp_clause_collapse (parser, clauses); + c_name = "collapse"; + break; case PRAGMA_OMP_CLAUSE_COPYIN: clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_COPYIN, clauses); c_name = "copyin"; @@ -20001,6 +20073,10 @@ cp_parser_omp_all_clauses (cp_parser *parser, unsigned int mask, clauses); c_name = "shared"; break; + case PRAGMA_OMP_CLAUSE_UNTIED: + clauses = cp_parser_omp_clause_untied (parser, clauses); + c_name = "nowait"; + break; default: cp_parser_error (parser, "expected %<#pragma omp%> clause"); goto saw_error; @@ -20210,94 +20286,454 @@ cp_parser_omp_flush (cp_parser *parser, cp_token *pragma_tok) finish_omp_flush (); } -/* Parse the restricted form of the for statment allowed by OpenMP. */ +/* Helper function, to parse omp for increment expression. */ static tree -cp_parser_omp_for_loop (cp_parser *parser) +cp_parser_omp_for_cond (cp_parser *parser, tree decl) { - tree init, cond, incr, body, decl, pre_body; - location_t loc; + tree lhs = cp_parser_cast_expression (parser, false, false), rhs; + enum tree_code op; + cp_token *token; - if (!cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR)) + if (lhs != decl) { - cp_parser_error (parser, "for statement expected"); - return NULL; + cp_parser_skip_to_end_of_statement (parser); + return error_mark_node; } - loc = cp_lexer_consume_token (parser->lexer)->location; - if (!cp_parser_require (parser, CPP_OPEN_PAREN, "%<(%>")) - return NULL; - init = decl = NULL; - pre_body = push_stmt_list (); - if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) + token = cp_lexer_peek_token (parser->lexer); + op = binops_by_token [token->type].tree_type; + switch (op) + { + case LT_EXPR: + case LE_EXPR: + case GT_EXPR: + case GE_EXPR: + break; + default: + cp_parser_skip_to_end_of_statement (parser); + return error_mark_node; + } + + cp_lexer_consume_token (parser->lexer); + rhs = cp_parser_binary_expression (parser, false, + PREC_RELATIONAL_EXPRESSION); + if (rhs == error_mark_node + || cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) { - cp_decl_specifier_seq type_specifiers; + cp_parser_skip_to_end_of_statement (parser); + return error_mark_node; + } - /* First, try to parse as an initialized declaration. See - cp_parser_condition, from whence the bulk of this is copied. */ + return build2 (op, boolean_type_node, lhs, rhs); +} - cp_parser_parse_tentatively (parser); - cp_parser_type_specifier_seq (parser, /*is_condition=*/false, - &type_specifiers); - if (!cp_parser_error_occurred (parser)) +/* Helper function, to parse omp for increment expression. */ + +static tree +cp_parser_omp_for_incr (cp_parser *parser, tree decl) +{ + cp_token *token = cp_lexer_peek_token (parser->lexer); + enum tree_code op; + tree lhs, rhs; + cp_id_kind idk; + bool decl_first; + + if (token->type == CPP_PLUS_PLUS || token->type == CPP_MINUS_MINUS) + { + op = (token->type == CPP_PLUS_PLUS + ? PREINCREMENT_EXPR : PREDECREMENT_EXPR); + cp_lexer_consume_token (parser->lexer); + lhs = cp_parser_cast_expression (parser, false, false); + if (lhs != decl) + return error_mark_node; + return build2 (op, TREE_TYPE (decl), decl, NULL_TREE); + } + + lhs = cp_parser_primary_expression (parser, false, false, false, &idk); + if (lhs != decl) + return error_mark_node; + + token = cp_lexer_peek_token (parser->lexer); + if (token->type == CPP_PLUS_PLUS || token->type == CPP_MINUS_MINUS) + { + op = (token->type == CPP_PLUS_PLUS + ? POSTINCREMENT_EXPR : POSTDECREMENT_EXPR); + cp_lexer_consume_token (parser->lexer); + return build2 (op, TREE_TYPE (decl), decl, NULL_TREE); + } + + op = cp_parser_assignment_operator_opt (parser); + if (op == ERROR_MARK) + return error_mark_node; + + if (op != NOP_EXPR) + { + rhs = cp_parser_assignment_expression (parser, false); + rhs = build2 (op, TREE_TYPE (decl), decl, rhs); + return build2 (MODIFY_EXPR, TREE_TYPE (decl), decl, rhs); + } + + lhs = cp_parser_binary_expression (parser, false, + PREC_ADDITIVE_EXPRESSION); + token = cp_lexer_peek_token (parser->lexer); + decl_first = lhs == decl; + if (decl_first) + lhs = NULL_TREE; + if (token->type != CPP_PLUS + && token->type != CPP_MINUS) + return error_mark_node; + + do + { + op = token->type == CPP_PLUS ? PLUS_EXPR : MINUS_EXPR; + cp_lexer_consume_token (parser->lexer); + rhs = cp_parser_binary_expression (parser, false, + PREC_ADDITIVE_EXPRESSION); + token = cp_lexer_peek_token (parser->lexer); + if (token->type == CPP_PLUS || token->type == CPP_MINUS || decl_first) { - tree asm_specification, attributes; - cp_declarator *declarator; - - declarator = cp_parser_declarator (parser, - CP_PARSER_DECLARATOR_NAMED, - /*ctor_dtor_or_conv_p=*/NULL, - /*parenthesized_p=*/NULL, - /*member_p=*/false); - attributes = cp_parser_attributes_opt (parser); - asm_specification = cp_parser_asm_specification_opt (parser); + if (lhs == NULL_TREE) + { + if (op == PLUS_EXPR) + lhs = rhs; + else + lhs = build_x_unary_op (NEGATE_EXPR, rhs, tf_warning_or_error); + } + else + lhs = build_x_binary_op (op, lhs, ERROR_MARK, rhs, ERROR_MARK, + NULL, tf_warning_or_error); + } + } + while (token->type == CPP_PLUS || token->type == CPP_MINUS); - cp_parser_require (parser, CPP_EQ, "%<=%>"); - if (cp_parser_parse_definitely (parser)) + if (!decl_first) + { + if (rhs != decl || op == MINUS_EXPR) + return error_mark_node; + rhs = build2 (op, TREE_TYPE (decl), lhs, decl); + } + else + rhs = build2 (PLUS_EXPR, TREE_TYPE (decl), decl, lhs); + + return build2 (MODIFY_EXPR, TREE_TYPE (decl), decl, rhs); +} + +/* Parse the restricted form of the for statment allowed by OpenMP. */ + +static tree +cp_parser_omp_for_loop (cp_parser *parser, tree clauses, tree *par_clauses) +{ + tree init, cond, incr, body, decl, pre_body = NULL_TREE, ret; + tree for_block = NULL_TREE, real_decl, initv, condv, incrv, declv; + tree this_pre_body, cl; + location_t loc_first; + bool collapse_err = false; + int i, collapse = 1, nbraces = 0; + + for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl)) + if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_COLLAPSE) + collapse = tree_low_cst (OMP_CLAUSE_COLLAPSE_EXPR (cl), 0); + + gcc_assert (collapse >= 1); + + declv = make_tree_vec (collapse); + initv = make_tree_vec (collapse); + condv = make_tree_vec (collapse); + incrv = make_tree_vec (collapse); + + loc_first = cp_lexer_peek_token (parser->lexer)->location; + + for (i = 0; i < collapse; i++) + { + int bracecount = 0; + bool add_private_clause = false; + location_t loc; + + if (!cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR)) + { + cp_parser_error (parser, "for statement expected"); + return NULL; + } + loc = cp_lexer_consume_token (parser->lexer)->location; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, "%<(%>")) + return NULL; + + init = decl = real_decl = NULL; + this_pre_body = push_stmt_list (); + if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) + { + cp_decl_specifier_seq type_specifiers; + + /* First, try to parse as an initialized declaration. See + cp_parser_condition, from whence the bulk of this is copied. */ + + cp_parser_parse_tentatively (parser); + cp_parser_type_specifier_seq (parser, /*is_condition=*/false, + &type_specifiers); + if (!cp_parser_error_occurred (parser)) { - tree pushed_scope; + tree asm_specification, attributes; + cp_declarator *declarator; + + declarator = cp_parser_declarator (parser, + CP_PARSER_DECLARATOR_NAMED, + /*ctor_dtor_or_conv_p=*/NULL, + /*parenthesized_p=*/NULL, + /*member_p=*/false); + attributes = cp_parser_attributes_opt (parser); + asm_specification = cp_parser_asm_specification_opt (parser); + + if (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ)) + cp_parser_require (parser, CPP_EQ, "%<=%>"); + if (cp_parser_parse_definitely (parser)) + { + tree pushed_scope; + + decl = start_decl (declarator, &type_specifiers, + /*initialized_p=*/false, attributes, + /*prefix_attributes=*/NULL_TREE, + &pushed_scope); + + if (CLASS_TYPE_P (TREE_TYPE (decl)) + || type_dependent_expression_p (decl)) + { + bool is_parenthesized_init, is_non_constant_init; + + init = cp_parser_initializer (parser, + &is_parenthesized_init, + &is_non_constant_init); + + cp_finish_decl (decl, init, !is_non_constant_init, + asm_specification, + LOOKUP_ONLYCONVERTING); + if (CLASS_TYPE_P (TREE_TYPE (decl))) + { + for_block + = tree_cons (NULL, this_pre_body, for_block); + init = NULL_TREE; + } + else + init = pop_stmt_list (this_pre_body); + this_pre_body = NULL_TREE; + } + else + { + cp_parser_require (parser, CPP_EQ, "%<=%>"); + init = cp_parser_assignment_expression (parser, false); - decl = start_decl (declarator, &type_specifiers, - /*initialized_p=*/false, attributes, - /*prefix_attributes=*/NULL_TREE, - &pushed_scope); + if (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE) + init = error_mark_node; + else + cp_finish_decl (decl, NULL_TREE, + /*init_const_expr_p=*/false, + asm_specification, + LOOKUP_ONLYCONVERTING); + } - init = cp_parser_assignment_expression (parser, false); + if (pushed_scope) + pop_scope (pushed_scope); + } + } + else + cp_parser_abort_tentative_parse (parser); - if (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE) - init = error_mark_node; + /* If parsing as an initialized declaration failed, try again as + a simple expression. */ + if (decl == NULL) + { + cp_id_kind idk; + cp_parser_parse_tentatively (parser); + decl = cp_parser_primary_expression (parser, false, false, + false, &idk); + if (!cp_parser_error_occurred (parser) + && decl + && DECL_P (decl) + && CLASS_TYPE_P (TREE_TYPE (decl))) + { + tree rhs; + + cp_parser_parse_definitely (parser); + cp_parser_require (parser, CPP_EQ, "%<=%>"); + rhs = cp_parser_assignment_expression (parser, false); + finish_expr_stmt (build_x_modify_expr (decl, NOP_EXPR, + rhs, + tf_warning_or_error)); + add_private_clause = true; + } else - cp_finish_decl (decl, NULL_TREE, /*init_const_expr_p=*/false, - asm_specification, LOOKUP_ONLYCONVERTING); + { + decl = NULL; + cp_parser_abort_tentative_parse (parser); + init = cp_parser_expression (parser, false); + if (init) + { + if (TREE_CODE (init) == MODIFY_EXPR + || TREE_CODE (init) == MODOP_EXPR) + real_decl = TREE_OPERAND (init, 0); + } + } + } + } + cp_parser_require (parser, CPP_SEMICOLON, "%<;%>"); + if (this_pre_body) + { + this_pre_body = pop_stmt_list (this_pre_body); + if (pre_body) + { + tree t = pre_body; + pre_body = push_stmt_list (); + add_stmt (t); + add_stmt (this_pre_body); + pre_body = pop_stmt_list (pre_body); + } + else + pre_body = this_pre_body; + } - if (pushed_scope) - pop_scope (pushed_scope); + if (decl) + real_decl = decl; + if (par_clauses != NULL && real_decl != NULL_TREE) + { + tree *c; + for (c = par_clauses; *c ; ) + if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_FIRSTPRIVATE + && OMP_CLAUSE_DECL (*c) == real_decl) + { + error ("%Hiteration variable %qD should not be firstprivate", + &loc, real_decl); + *c = OMP_CLAUSE_CHAIN (*c); + } + else if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_LASTPRIVATE + && OMP_CLAUSE_DECL (*c) == real_decl) + { + /* Add lastprivate (decl) clause to OMP_FOR_CLAUSES, + change it to shared (decl) in OMP_PARALLEL_CLAUSES. */ + tree l = build_omp_clause (OMP_CLAUSE_LASTPRIVATE); + OMP_CLAUSE_DECL (l) = real_decl; + OMP_CLAUSE_CHAIN (l) = clauses; + CP_OMP_CLAUSE_INFO (l) = CP_OMP_CLAUSE_INFO (*c); + clauses = l; + OMP_CLAUSE_SET_CODE (*c, OMP_CLAUSE_SHARED); + CP_OMP_CLAUSE_INFO (*c) = NULL; + add_private_clause = false; + } + else + { + if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_PRIVATE + && OMP_CLAUSE_DECL (*c) == real_decl) + add_private_clause = false; + c = &OMP_CLAUSE_CHAIN (*c); + } + } + + if (add_private_clause) + { + tree c; + for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c)) + { + if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE) + && OMP_CLAUSE_DECL (c) == decl) + break; + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE + && OMP_CLAUSE_DECL (c) == decl) + error ("%Hiteration variable %qD should not be firstprivate", + &loc, decl); + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + && OMP_CLAUSE_DECL (c) == decl) + error ("%Hiteration variable %qD should not be reduction", + &loc, decl); + } + if (c == NULL) + { + c = build_omp_clause (OMP_CLAUSE_PRIVATE); + OMP_CLAUSE_DECL (c) = decl; + c = finish_omp_clauses (c); + if (c) + { + OMP_CLAUSE_CHAIN (c) = clauses; + clauses = c; + } } } - else - cp_parser_abort_tentative_parse (parser); - /* If parsing as an initialized declaration failed, try again as - a simple expression. */ - if (decl == NULL) - init = cp_parser_expression (parser, false); - } - cp_parser_require (parser, CPP_SEMICOLON, "%<;%>"); - pre_body = pop_stmt_list (pre_body); + cond = NULL; + if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) + { + /* If decl is an iterator, preserve LHS and RHS of the relational + expr until finish_omp_for. */ + if (decl + && (type_dependent_expression_p (decl) + || CLASS_TYPE_P (TREE_TYPE (decl)))) + cond = cp_parser_omp_for_cond (parser, decl); + else + cond = cp_parser_condition (parser); + } + cp_parser_require (parser, CPP_SEMICOLON, "%<;%>"); - cond = NULL; - if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) - cond = cp_parser_condition (parser); - cp_parser_require (parser, CPP_SEMICOLON, "%<;%>"); + incr = NULL; + if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN)) + { + /* If decl is an iterator, preserve the operator on decl + until finish_omp_for. */ + if (decl + && (type_dependent_expression_p (decl) + || CLASS_TYPE_P (TREE_TYPE (decl)))) + incr = cp_parser_omp_for_incr (parser, decl); + else + incr = cp_parser_expression (parser, false); + } - incr = NULL; - if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN)) - incr = cp_parser_expression (parser, false); + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "%<)%>")) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); - if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "%<)%>")) - cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, - /*or_comma=*/false, - /*consume_paren=*/true); + TREE_VEC_ELT (declv, i) = decl; + TREE_VEC_ELT (initv, i) = init; + TREE_VEC_ELT (condv, i) = cond; + TREE_VEC_ELT (incrv, i) = incr; + + if (i == collapse - 1) + break; + + /* FIXME: OpenMP 3.0 draft isn't very clear on what exactly is allowed + in between the collapsed for loops to be still considered perfectly + nested. Hopefully the final version clarifies this. + For now handle (multiple) {'s and empty statements. */ + cp_parser_parse_tentatively (parser); + do + { + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR)) + break; + else if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + { + cp_lexer_consume_token (parser->lexer); + bracecount++; + } + else if (bracecount + && cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) + cp_lexer_consume_token (parser->lexer); + else + { + loc = cp_lexer_peek_token (parser->lexer)->location; + error ("%Hnot enough collapsed for loops", &loc); + collapse_err = true; + cp_parser_abort_tentative_parse (parser); + declv = NULL_TREE; + break; + } + } + while (1); + + if (declv) + { + cp_parser_parse_definitely (parser); + nbraces += bracecount; + } + } /* Note that we saved the original contents of this flag when we entered the structured block, and so we don't need to re-save it here. */ @@ -20309,7 +20745,38 @@ cp_parser_omp_for_loop (cp_parser *parser) cp_parser_statement (parser, NULL_TREE, false, NULL); body = pop_stmt_list (body); - return finish_omp_for (loc, decl, init, cond, incr, body, pre_body); + if (declv == NULL_TREE) + ret = NULL_TREE; + else + ret = finish_omp_for (loc_first, declv, initv, condv, incrv, body, + pre_body, clauses); + + while (nbraces) + { + if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE)) + { + cp_lexer_consume_token (parser->lexer); + nbraces--; + } + else if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) + cp_lexer_consume_token (parser->lexer); + else + { + if (!collapse_err) + error ("collapsed loops not perfectly nested"); + collapse_err = true; + cp_parser_statement_seq_opt (parser, NULL); + cp_parser_require (parser, CPP_CLOSE_BRACE, "%<}%>"); + } + } + + while (for_block) + { + add_stmt (pop_stmt_list (TREE_VALUE (for_block))); + for_block = TREE_CHAIN (for_block); + } + + return ret; } /* OpenMP 2.5: @@ -20323,7 +20790,8 @@ cp_parser_omp_for_loop (cp_parser *parser) | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ | (1u << PRAGMA_OMP_CLAUSE_ORDERED) \ | (1u << PRAGMA_OMP_CLAUSE_SCHEDULE) \ - | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) + | (1u << PRAGMA_OMP_CLAUSE_NOWAIT) \ + | (1u << PRAGMA_OMP_CLAUSE_COLLAPSE)) static tree cp_parser_omp_for (cp_parser *parser, cp_token *pragma_tok) @@ -20337,9 +20805,7 @@ cp_parser_omp_for (cp_parser *parser, cp_token *pragma_tok) sb = begin_omp_structured_block (); save = cp_parser_begin_omp_structured_block (parser); - ret = cp_parser_omp_for_loop (parser); - if (ret) - OMP_FOR_CLAUSES (ret) = clauses; + ret = cp_parser_omp_for_loop (parser, clauses, NULL); cp_parser_end_omp_structured_block (parser, save); add_stmt (finish_omp_structured_block (sb)); @@ -20537,9 +21003,7 @@ cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok) case PRAGMA_OMP_PARALLEL_FOR: c_split_parallel_clauses (clauses, &par_clause, &ws_clause); - stmt = cp_parser_omp_for_loop (parser); - if (stmt) - OMP_FOR_CLAUSES (stmt) = ws_clause; + cp_parser_omp_for_loop (parser, ws_clause, &par_clause); break; case PRAGMA_OMP_PARALLEL_SECTIONS: @@ -20584,6 +21048,43 @@ cp_parser_omp_single (cp_parser *parser, cp_token *pragma_tok) return add_stmt (stmt); } +/* OpenMP 3.0: + # pragma omp task task-clause[optseq] new-line + structured-block */ + +#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)) + +static tree +cp_parser_omp_task (cp_parser *parser, cp_token *pragma_tok) +{ + tree clauses, block; + unsigned int save; + + clauses = cp_parser_omp_all_clauses (parser, OMP_TASK_CLAUSE_MASK, + "#pragma omp task", pragma_tok); + block = begin_omp_task (); + save = cp_parser_begin_omp_structured_block (parser); + cp_parser_statement (parser, NULL_TREE, false, NULL); + cp_parser_end_omp_structured_block (parser, save); + return finish_omp_task (clauses, block); +} + +/* OpenMP 3.0: + # pragma omp taskwait new-line */ + +static void +cp_parser_omp_taskwait (cp_parser *parser, cp_token *pragma_tok) +{ + cp_parser_require_pragma_eol (parser, pragma_tok); + finish_omp_taskwait (); +} + /* OpenMP 2.5: # pragma omp threadprivate (variable-list) */ @@ -20631,6 +21132,9 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok) case PRAGMA_OMP_SINGLE: stmt = cp_parser_omp_single (parser, pragma_tok); break; + case PRAGMA_OMP_TASK: + stmt = cp_parser_omp_task (parser, pragma_tok); + break; default: gcc_unreachable (); } @@ -20738,6 +21242,21 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context) } break; + case PRAGMA_OMP_TASKWAIT: + switch (context) + { + case pragma_compound: + cp_parser_omp_taskwait (parser, pragma_tok); + return false; + case pragma_stmt: + error ("%<#pragma omp taskwait%> may only be " + "used in compound statements"); + break; + default: + goto bad_stmt; + } + break; + case PRAGMA_OMP_THREADPRIVATE: cp_parser_omp_threadprivate (parser, pragma_tok); return false; @@ -20750,6 +21269,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context) case PRAGMA_OMP_PARALLEL: case PRAGMA_OMP_SECTIONS: case PRAGMA_OMP_SINGLE: + case PRAGMA_OMP_TASK: if (context == pragma_external) goto bad_stmt; cp_parser_omp_construct (parser, pragma_tok); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 4bb43ad..f141b74 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -10214,16 +10214,26 @@ tsubst_omp_clauses (tree clauses, tree args, tsubst_flags_t complain, switch (OMP_CLAUSE_CODE (nc)) { + case OMP_CLAUSE_LASTPRIVATE: + if (OMP_CLAUSE_LASTPRIVATE_STMT (oc)) + { + OMP_CLAUSE_LASTPRIVATE_STMT (nc) = push_stmt_list (); + tsubst_expr (OMP_CLAUSE_LASTPRIVATE_STMT (oc), args, complain, + in_decl, /*integral_constant_expression_p=*/false); + OMP_CLAUSE_LASTPRIVATE_STMT (nc) + = pop_stmt_list (OMP_CLAUSE_LASTPRIVATE_STMT (nc)); + } + /* FALLTHRU */ case OMP_CLAUSE_PRIVATE: case OMP_CLAUSE_SHARED: case OMP_CLAUSE_FIRSTPRIVATE: - case OMP_CLAUSE_LASTPRIVATE: case OMP_CLAUSE_REDUCTION: case OMP_CLAUSE_COPYIN: case OMP_CLAUSE_COPYPRIVATE: case OMP_CLAUSE_IF: case OMP_CLAUSE_NUM_THREADS: case OMP_CLAUSE_SCHEDULE: + case OMP_CLAUSE_COLLAPSE: OMP_CLAUSE_OPERAND (nc, 0) = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 0), args, complain, in_decl, /*integral_constant_expression_p=*/false); @@ -10231,6 +10241,7 @@ tsubst_omp_clauses (tree clauses, tree args, tsubst_flags_t complain, case OMP_CLAUSE_NOWAIT: case OMP_CLAUSE_ORDERED: case OMP_CLAUSE_DEFAULT: + case OMP_CLAUSE_UNTIED: break; default: gcc_unreachable (); @@ -10274,6 +10285,137 @@ tsubst_copy_asm_operands (tree t, tree args, tsubst_flags_t complain, #undef RECUR } +/* Substitute one OMP_FOR iterator. */ + +static void +tsubst_omp_for_iterator (tree t, int i, tree declv, tree initv, + tree condv, tree incrv, tree *clauses, + tree args, tsubst_flags_t complain, tree in_decl, + bool integral_constant_expression_p) +{ +#define RECUR(NODE) \ + tsubst_expr ((NODE), args, complain, in_decl, \ + integral_constant_expression_p) + tree decl, init, cond, incr; + + init = TREE_VEC_ELT (OMP_FOR_INIT (t), i); + gcc_assert (TREE_CODE (init) == MODIFY_EXPR); + decl = RECUR (TREE_OPERAND (init, 0)); + init = TREE_OPERAND (init, 1); + gcc_assert (!type_dependent_expression_p (decl)); + + if (!CLASS_TYPE_P (TREE_TYPE (decl))) + { + cond = RECUR (TREE_VEC_ELT (OMP_FOR_COND (t), i)); + incr = TREE_VEC_ELT (OMP_FOR_INCR (t), i); + if (TREE_CODE (incr) == MODIFY_EXPR) + incr = build_x_modify_expr (RECUR (TREE_OPERAND (incr, 0)), NOP_EXPR, + RECUR (TREE_OPERAND (incr, 1)), + complain); + else + incr = RECUR (incr); + TREE_VEC_ELT (declv, i) = decl; + TREE_VEC_ELT (initv, i) = init; + TREE_VEC_ELT (condv, i) = cond; + TREE_VEC_ELT (incrv, i) = incr; + return; + } + + if (init && TREE_CODE (init) != DECL_EXPR) + { + tree c; + for (c = *clauses; c ; c = OMP_CLAUSE_CHAIN (c)) + { + if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE) + && OMP_CLAUSE_DECL (c) == decl) + break; + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE + && OMP_CLAUSE_DECL (c) == decl) + error ("iteration variable %qD should not be firstprivate", decl); + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + && OMP_CLAUSE_DECL (c) == decl) + error ("iteration variable %qD should not be reduction", decl); + } + if (c == NULL) + { + c = build_omp_clause (OMP_CLAUSE_PRIVATE); + OMP_CLAUSE_DECL (c) = decl; + c = finish_omp_clauses (c); + if (c) + { + OMP_CLAUSE_CHAIN (c) = *clauses; + *clauses = c; + } + } + } + cond = TREE_VEC_ELT (OMP_FOR_COND (t), i); + if (COMPARISON_CLASS_P (cond)) + cond = build2 (TREE_CODE (cond), boolean_type_node, + RECUR (TREE_OPERAND (cond, 0)), + RECUR (TREE_OPERAND (cond, 1))); + else + cond = RECUR (cond); + incr = TREE_VEC_ELT (OMP_FOR_INCR (t), i); + switch (TREE_CODE (incr)) + { + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + incr = build2 (TREE_CODE (incr), TREE_TYPE (decl), + RECUR (TREE_OPERAND (incr, 0)), NULL_TREE); + break; + case MODIFY_EXPR: + if (TREE_CODE (TREE_OPERAND (incr, 1)) == PLUS_EXPR + || TREE_CODE (TREE_OPERAND (incr, 1)) == MINUS_EXPR) + { + tree rhs = TREE_OPERAND (incr, 1); + incr = build2 (MODIFY_EXPR, TREE_TYPE (decl), + RECUR (TREE_OPERAND (incr, 0)), + build2 (TREE_CODE (rhs), TREE_TYPE (decl), + RECUR (TREE_OPERAND (rhs, 0)), + RECUR (TREE_OPERAND (rhs, 1)))); + } + else + incr = RECUR (incr); + break; + case MODOP_EXPR: + if (TREE_CODE (TREE_OPERAND (incr, 1)) == PLUS_EXPR + || TREE_CODE (TREE_OPERAND (incr, 1)) == MINUS_EXPR) + { + tree lhs = RECUR (TREE_OPERAND (incr, 0)); + incr = build2 (MODIFY_EXPR, TREE_TYPE (decl), lhs, + build2 (TREE_CODE (TREE_OPERAND (incr, 1)), + TREE_TYPE (decl), lhs, + RECUR (TREE_OPERAND (incr, 2)))); + } + else if (TREE_CODE (TREE_OPERAND (incr, 1)) == NOP_EXPR + && (TREE_CODE (TREE_OPERAND (incr, 2)) == PLUS_EXPR + || (TREE_CODE (TREE_OPERAND (incr, 2)) == MINUS_EXPR))) + { + tree rhs = TREE_OPERAND (incr, 2); + incr = build2 (MODIFY_EXPR, TREE_TYPE (decl), + RECUR (TREE_OPERAND (incr, 0)), + build2 (TREE_CODE (rhs), TREE_TYPE (decl), + RECUR (TREE_OPERAND (rhs, 0)), + RECUR (TREE_OPERAND (rhs, 1)))); + } + else + incr = RECUR (incr); + break; + default: + incr = RECUR (incr); + break; + } + + TREE_VEC_ELT (declv, i) = decl; + TREE_VEC_ELT (initv, i) = init; + TREE_VEC_ELT (condv, i) = cond; + TREE_VEC_ELT (incrv, i) = incr; +#undef RECUR +} + /* Like tsubst_copy for expressions, etc. but also does semantic processing. */ @@ -10597,21 +10739,55 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, = OMP_PARALLEL_COMBINED (t); break; + case OMP_TASK: + tmp = tsubst_omp_clauses (OMP_TASK_CLAUSES (t), + args, complain, in_decl); + stmt = begin_omp_task (); + RECUR (OMP_TASK_BODY (t)); + finish_omp_task (tmp, stmt); + break; + case OMP_FOR: { - tree clauses, decl, init, cond, incr, body, pre_body; + tree clauses, body, pre_body; + tree declv, initv, condv, incrv; + int i; clauses = tsubst_omp_clauses (OMP_FOR_CLAUSES (t), args, complain, in_decl); - init = OMP_FOR_INIT (t); - gcc_assert (TREE_CODE (init) == MODIFY_EXPR); - decl = RECUR (TREE_OPERAND (init, 0)); - init = RECUR (TREE_OPERAND (init, 1)); - cond = RECUR (OMP_FOR_COND (t)); - incr = RECUR (OMP_FOR_INCR (t)); + declv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t))); + initv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t))); + condv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t))); + incrv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t))); + + for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (t)); i++) + tsubst_omp_for_iterator (t, i, declv, initv, condv, incrv, + &clauses, args, complain, in_decl, + integral_constant_expression_p); stmt = begin_omp_structured_block (); + for (i = 0; i < TREE_VEC_LENGTH (initv); i++) + if (TREE_VEC_ELT (initv, i) == NULL + || TREE_CODE (TREE_VEC_ELT (initv, i)) != DECL_EXPR) + TREE_VEC_ELT (initv, i) = RECUR (TREE_VEC_ELT (initv, i)); + else if (CLASS_TYPE_P (TREE_TYPE (TREE_VEC_ELT (initv, i)))) + { + tree init = RECUR (TREE_VEC_ELT (initv, i)); + gcc_assert (init == TREE_VEC_ELT (declv, i)); + TREE_VEC_ELT (initv, i) = NULL_TREE; + } + else + { + tree decl_expr = TREE_VEC_ELT (initv, i); + tree init = DECL_INITIAL (DECL_EXPR_DECL (decl_expr)); + gcc_assert (init != NULL); + TREE_VEC_ELT (initv, i) = RECUR (init); + DECL_INITIAL (DECL_EXPR_DECL (decl_expr)) = NULL; + RECUR (decl_expr); + DECL_INITIAL (DECL_EXPR_DECL (decl_expr)) = init; + } + pre_body = push_stmt_list (); RECUR (OMP_FOR_PRE_BODY (t)); pre_body = pop_stmt_list (pre_body); @@ -10620,10 +10796,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, RECUR (OMP_FOR_BODY (t)); body = pop_stmt_list (body); - t = finish_omp_for (EXPR_LOCATION (t), decl, init, cond, incr, body, - pre_body); - if (t) - OMP_FOR_CLAUSES (t) = clauses; + t = finish_omp_for (EXPR_LOCATION (t), declv, initv, condv, incrv, + body, pre_body, clauses); add_stmt (finish_omp_structured_block (stmt)); } @@ -16195,6 +16369,63 @@ dependent_template_id_p (tree tmpl, tree args) || any_dependent_template_arguments_p (args)); } +/* Returns TRUE if OMP_FOR with DECLV, INITV, CONDV and INCRV vectors + is dependent. */ + +bool +dependent_omp_for_p (tree declv, tree initv, tree condv, tree incrv) +{ + int i; + + if (!processing_template_decl) + return false; + + for (i = 0; i < TREE_VEC_LENGTH (declv); i++) + { + tree decl = TREE_VEC_ELT (declv, i); + tree init = TREE_VEC_ELT (initv, i); + tree cond = TREE_VEC_ELT (condv, i); + tree incr = TREE_VEC_ELT (incrv, i); + + if (type_dependent_expression_p (decl)) + return true; + + if (init && type_dependent_expression_p (init)) + return true; + + if (type_dependent_expression_p (cond)) + return true; + + if (COMPARISON_CLASS_P (cond) + && (type_dependent_expression_p (TREE_OPERAND (cond, 0)) + || type_dependent_expression_p (TREE_OPERAND (cond, 1)))) + return true; + + if (TREE_CODE (incr) == MODOP_EXPR) + { + if (type_dependent_expression_p (TREE_OPERAND (incr, 0)) + || type_dependent_expression_p (TREE_OPERAND (incr, 2))) + return true; + } + else if (type_dependent_expression_p (incr)) + return true; + else if (TREE_CODE (incr) == MODIFY_EXPR) + { + if (type_dependent_expression_p (TREE_OPERAND (incr, 0))) + return true; + else if (BINARY_CLASS_P (TREE_OPERAND (incr, 1))) + { + tree t = TREE_OPERAND (incr, 1); + if (type_dependent_expression_p (TREE_OPERAND (t, 0)) + || type_dependent_expression_p (TREE_OPERAND (t, 1))) + return true; + } + } + } + + return false; +} + /* TYPE is a TYPENAME_TYPE. Returns the ordinary TYPE to which the TYPENAME_TYPE corresponds. Returns the original TYPENAME_TYPE if no such TYPE can be found. Note that this function peers inside diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 96999bf..83d2339 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -3359,6 +3359,94 @@ omp_clause_info_fndecl (tree t, tree type) return NULL_TREE; } +/* Create CP_OMP_CLAUSE_INFO for clause C. Returns true if it is invalid. */ + +bool +cxx_omp_create_clause_info (tree c, tree type, bool need_default_ctor, + bool need_copy_ctor, bool need_copy_assignment) +{ + int save_errorcount = errorcount; + tree info, t; + + /* Always allocate 3 elements for simplicity. These are the + function decls for the ctor, dtor, and assignment op. + This layout is known to the three lang hooks, + cxx_omp_clause_default_init, cxx_omp_clause_copy_init, + and cxx_omp_clause_assign_op. */ + info = make_tree_vec (3); + CP_OMP_CLAUSE_INFO (c) = info; + + if (need_default_ctor + || (need_copy_ctor && !TYPE_HAS_TRIVIAL_INIT_REF (type))) + { + if (need_default_ctor) + t = NULL; + else + { + t = build_int_cst (build_pointer_type (type), 0); + t = build1 (INDIRECT_REF, type, t); + t = build_tree_list (NULL, t); + } + t = build_special_member_call (NULL_TREE, complete_ctor_identifier, + t, type, LOOKUP_NORMAL, + tf_warning_or_error); + + if (targetm.cxx.cdtor_returns_this () || errorcount) + /* Because constructors and destructors return this, + the call will have been cast to "void". Remove the + cast here. We would like to use STRIP_NOPS, but it + wouldn't work here because TYPE_MODE (t) and + TYPE_MODE (TREE_OPERAND (t, 0)) are different. + They are VOIDmode and Pmode, respectively. */ + if (TREE_CODE (t) == NOP_EXPR) + t = TREE_OPERAND (t, 0); + + TREE_VEC_ELT (info, 0) = get_callee_fndecl (t); + } + + if ((need_default_ctor || need_copy_ctor) + && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) + { + t = build_int_cst (build_pointer_type (type), 0); + t = build1 (INDIRECT_REF, type, t); + t = build_special_member_call (t, complete_dtor_identifier, + NULL, type, LOOKUP_NORMAL, + tf_warning_or_error); + + if (targetm.cxx.cdtor_returns_this () || errorcount) + /* Because constructors and destructors return this, + the call will have been cast to "void". Remove the + cast here. We would like to use STRIP_NOPS, but it + wouldn't work here because TYPE_MODE (t) and + TYPE_MODE (TREE_OPERAND (t, 0)) are different. + They are VOIDmode and Pmode, respectively. */ + if (TREE_CODE (t) == NOP_EXPR) + t = TREE_OPERAND (t, 0); + + TREE_VEC_ELT (info, 1) = omp_clause_info_fndecl (t, type); + } + + if (need_copy_assignment && !TYPE_HAS_TRIVIAL_ASSIGN_REF (type)) + { + t = build_int_cst (build_pointer_type (type), 0); + t = build1 (INDIRECT_REF, type, t); + t = build_special_member_call (t, ansi_assopname (NOP_EXPR), + build_tree_list (NULL, t), + type, LOOKUP_NORMAL, + tf_warning_or_error); + + /* We'll have called convert_from_reference on the call, which + may well have added an indirect_ref. It's unneeded here, + and in the way, so kill it. */ + if (TREE_CODE (t) == INDIRECT_REF) + t = TREE_OPERAND (t, 0); + + TREE_VEC_ELT (info, 2) = omp_clause_info_fndecl (t, type); + } + + return errorcount != save_errorcount; +} + /* For all elements of CLAUSES, validate them vs OpenMP constraints. Remove any elements from the list that are invalid. */ @@ -3499,6 +3587,8 @@ finish_omp_clauses (tree clauses) case OMP_CLAUSE_NOWAIT: case OMP_CLAUSE_ORDERED: case OMP_CLAUSE_DEFAULT: + case OMP_CLAUSE_UNTIED: + case OMP_CLAUSE_COLLAPSE: break; default: @@ -3662,93 +3752,10 @@ finish_omp_clauses (tree clauses) for making these queries. */ if (CLASS_TYPE_P (inner_type) && (need_default_ctor || need_copy_ctor || need_copy_assignment) - && !type_dependent_expression_p (t)) - { - int save_errorcount = errorcount; - tree info; - - /* Always allocate 3 elements for simplicity. These are the - function decls for the ctor, dtor, and assignment op. - This layout is known to the three lang hooks, - cxx_omp_clause_default_init, cxx_omp_clause_copy_init, - and cxx_omp_clause_assign_op. */ - info = make_tree_vec (3); - CP_OMP_CLAUSE_INFO (c) = info; - - if (need_default_ctor - || (need_copy_ctor - && !TYPE_HAS_TRIVIAL_INIT_REF (inner_type))) - { - if (need_default_ctor) - t = NULL; - else - { - t = build_int_cst (build_pointer_type (inner_type), 0); - t = build1 (INDIRECT_REF, inner_type, t); - t = build_tree_list (NULL, t); - } - t = build_special_member_call (NULL_TREE, - complete_ctor_identifier, - t, inner_type, LOOKUP_NORMAL, - tf_warning_or_error); - - if (targetm.cxx.cdtor_returns_this () || errorcount) - /* Because constructors and destructors return this, - the call will have been cast to "void". Remove the - cast here. We would like to use STRIP_NOPS, but it - wouldn't work here because TYPE_MODE (t) and - TYPE_MODE (TREE_OPERAND (t, 0)) are different. - They are VOIDmode and Pmode, respectively. */ - if (TREE_CODE (t) == NOP_EXPR) - t = TREE_OPERAND (t, 0); - - TREE_VEC_ELT (info, 0) = get_callee_fndecl (t); - } - - if ((need_default_ctor || need_copy_ctor) - && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (inner_type)) - { - t = build_int_cst (build_pointer_type (inner_type), 0); - t = build1 (INDIRECT_REF, inner_type, t); - t = build_special_member_call (t, complete_dtor_identifier, - NULL, inner_type, LOOKUP_NORMAL, - tf_warning_or_error); - - if (targetm.cxx.cdtor_returns_this () || errorcount) - /* Because constructors and destructors return this, - the call will have been cast to "void". Remove the - cast here. We would like to use STRIP_NOPS, but it - wouldn't work here because TYPE_MODE (t) and - TYPE_MODE (TREE_OPERAND (t, 0)) are different. - They are VOIDmode and Pmode, respectively. */ - if (TREE_CODE (t) == NOP_EXPR) - t = TREE_OPERAND (t, 0); - - TREE_VEC_ELT (info, 1) = omp_clause_info_fndecl (t, inner_type); - } - - if (need_copy_assignment - && !TYPE_HAS_TRIVIAL_ASSIGN_REF (inner_type)) - { - t = build_int_cst (build_pointer_type (inner_type), 0); - t = build1 (INDIRECT_REF, inner_type, t); - t = build_special_member_call (t, ansi_assopname (NOP_EXPR), - build_tree_list (NULL, t), - inner_type, LOOKUP_NORMAL, - tf_warning_or_error); - - /* We'll have called convert_from_reference on the call, which - may well have added an indirect_ref. It's unneeded here, - and in the way, so kill it. */ - if (TREE_CODE (t) == INDIRECT_REF) - t = TREE_OPERAND (t, 0); - - TREE_VEC_ELT (info, 2) = omp_clause_info_fndecl (t, inner_type); - } - - if (errorcount != save_errorcount) - remove = true; - } + && !type_dependent_expression_p (t) + && cxx_omp_create_clause_info (c, inner_type, need_default_ctor, + need_copy_ctor, need_copy_assignment)) + remove = true; if (remove) *pc = OMP_CLAUSE_CHAIN (c); @@ -3787,9 +3794,10 @@ finish_omp_threadprivate (tree vars) 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 (TREE_STATIC (v) && TYPE_P (CP_DECL_CONTEXT (v))) - error ("%<threadprivate%> %qE is not file, namespace " - "or block scope variable", v); + else if (TREE_STATIC (v) && TYPE_P (CP_DECL_CONTEXT (v)) + && CP_DECL_CONTEXT (v) != current_class_type) + error ("%<threadprivate%> %qE directive not " + "in %qT definition", v, CP_DECL_CONTEXT (v)); else { /* Allocate a LANG_SPECIFIC structure for V, if needed. */ @@ -3855,6 +3863,252 @@ finish_omp_parallel (tree clauses, tree body) return add_stmt (stmt); } +tree +begin_omp_task (void) +{ + keep_next_level (true); + return begin_omp_structured_block (); +} + +tree +finish_omp_task (tree clauses, tree body) +{ + tree stmt; + + body = finish_omp_structured_block (body); + + stmt = make_node (OMP_TASK); + TREE_TYPE (stmt) = void_type_node; + OMP_TASK_CLAUSES (stmt) = clauses; + OMP_TASK_BODY (stmt) = body; + + return add_stmt (stmt); +} + +/* Helper function for finish_omp_for. Convert Ith random access iterator + into integral iterator. Return FALSE if successful. */ + +static bool +handle_omp_for_class_iterator (int i, location_t locus, tree declv, tree initv, + tree condv, tree incrv, tree *body, + tree *pre_body, tree clauses) +{ + tree diff, iter_init, iter_incr = NULL, last; + tree incr_var = NULL, orig_pre_body, orig_body, c; + tree decl = TREE_VEC_ELT (declv, i); + tree init = TREE_VEC_ELT (initv, i); + tree cond = TREE_VEC_ELT (condv, i); + tree incr = TREE_VEC_ELT (incrv, i); + tree iter = decl; + location_t elocus = locus; + + if (init && EXPR_HAS_LOCATION (init)) + elocus = EXPR_LOCATION (init); + + switch (TREE_CODE (cond)) + { + case GT_EXPR: + case GE_EXPR: + case LT_EXPR: + case LE_EXPR: + if (TREE_OPERAND (cond, 0) != iter) + cond = error_mark_node; + else + { + tree tem = build_x_binary_op (TREE_CODE (cond), iter, ERROR_MARK, + TREE_OPERAND (cond, 1), ERROR_MARK, + NULL, tf_warning_or_error); + if (error_operand_p (tem)) + return true; + } + break; + default: + cond = error_mark_node; + break; + } + if (cond == error_mark_node) + { + error ("%Hinvalid controlling predicate", &elocus); + return true; + } + diff = build_x_binary_op (MINUS_EXPR, TREE_OPERAND (cond, 1), + ERROR_MARK, iter, ERROR_MARK, NULL, + tf_warning_or_error); + if (error_operand_p (diff)) + return true; + if (TREE_CODE (TREE_TYPE (diff)) != INTEGER_TYPE) + { + error ("%Hdifference between %qE and %qD does not have integer type", + &elocus, TREE_OPERAND (cond, 1), iter); + return true; + } + + switch (TREE_CODE (incr)) + { + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + if (TREE_OPERAND (incr, 0) != iter) + { + incr = error_mark_node; + break; + } + iter_incr = build_x_unary_op (TREE_CODE (incr), iter, + tf_warning_or_error); + if (error_operand_p (iter_incr)) + return true; + else if (TREE_CODE (incr) == PREINCREMENT_EXPR + || TREE_CODE (incr) == POSTINCREMENT_EXPR) + incr = integer_one_node; + else + incr = integer_minus_one_node; + break; + case MODIFY_EXPR: + if (TREE_OPERAND (incr, 0) != iter) + incr = error_mark_node; + else if (TREE_CODE (TREE_OPERAND (incr, 1)) == PLUS_EXPR + || TREE_CODE (TREE_OPERAND (incr, 1)) == MINUS_EXPR) + { + tree rhs = TREE_OPERAND (incr, 1); + if (TREE_OPERAND (rhs, 0) == iter) + { + if (TREE_CODE (TREE_TYPE (TREE_OPERAND (rhs, 1))) + != INTEGER_TYPE) + incr = error_mark_node; + else + { + iter_incr = build_x_modify_expr (iter, TREE_CODE (rhs), + TREE_OPERAND (rhs, 1), + tf_warning_or_error); + if (error_operand_p (iter_incr)) + return true; + incr = TREE_OPERAND (rhs, 1); + incr = cp_convert (TREE_TYPE (diff), incr); + if (TREE_CODE (rhs) == MINUS_EXPR) + { + incr = build1 (NEGATE_EXPR, TREE_TYPE (diff), incr); + incr = fold_if_not_in_template (incr); + } + if (TREE_CODE (incr) != INTEGER_CST + && (TREE_CODE (incr) != NOP_EXPR + || (TREE_CODE (TREE_OPERAND (incr, 0)) + != INTEGER_CST))) + iter_incr = NULL; + } + } + else if (TREE_OPERAND (rhs, 1) == iter) + { + if (TREE_CODE (TREE_TYPE (TREE_OPERAND (rhs, 0))) != INTEGER_TYPE + || TREE_CODE (rhs) != PLUS_EXPR) + incr = error_mark_node; + else + { + iter_incr = build_x_binary_op (PLUS_EXPR, + TREE_OPERAND (rhs, 0), + ERROR_MARK, iter, + ERROR_MARK, NULL, + tf_warning_or_error); + if (error_operand_p (iter_incr)) + return true; + iter_incr = build_x_modify_expr (iter, NOP_EXPR, + iter_incr, + tf_warning_or_error); + if (error_operand_p (iter_incr)) + return true; + incr = TREE_OPERAND (rhs, 0); + iter_incr = NULL; + } + } + else + incr = error_mark_node; + } + else + incr = error_mark_node; + break; + default: + incr = error_mark_node; + break; + } + + if (incr == error_mark_node) + { + error ("%Hinvalid increment expression", &elocus); + return true; + } + + incr = cp_convert (TREE_TYPE (diff), incr); + for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE + && OMP_CLAUSE_DECL (c) == iter) + break; + + decl = create_temporary_var (TREE_TYPE (diff)); + pushdecl (decl); + add_decl_expr (decl); + last = create_temporary_var (TREE_TYPE (diff)); + pushdecl (last); + add_decl_expr (last); + if (c && iter_incr == NULL) + { + incr_var = create_temporary_var (TREE_TYPE (diff)); + pushdecl (incr_var); + add_decl_expr (incr_var); + } + gcc_assert (stmts_are_full_exprs_p ()); + + orig_pre_body = *pre_body; + *pre_body = push_stmt_list (); + if (orig_pre_body) + add_stmt (orig_pre_body); + if (init != NULL) + finish_expr_stmt (build_x_modify_expr (iter, NOP_EXPR, init, + tf_warning_or_error)); + init = build_int_cst (TREE_TYPE (diff), 0); + if (c && iter_incr == NULL) + { + finish_expr_stmt (build_x_modify_expr (incr_var, NOP_EXPR, + incr, tf_warning_or_error)); + incr = incr_var; + iter_incr = build_x_modify_expr (iter, PLUS_EXPR, incr, + tf_warning_or_error); + } + finish_expr_stmt (build_x_modify_expr (last, NOP_EXPR, init, + tf_warning_or_error)); + *pre_body = pop_stmt_list (*pre_body); + + cond = cp_build_binary_op (TREE_CODE (cond), decl, diff, + tf_warning_or_error); + incr = build_modify_expr (decl, PLUS_EXPR, incr); + + orig_body = *body; + *body = push_stmt_list (); + iter_init = build2 (MINUS_EXPR, TREE_TYPE (diff), decl, last); + iter_init = build_x_modify_expr (iter, PLUS_EXPR, iter_init, + tf_warning_or_error); + iter_init = build1 (NOP_EXPR, void_type_node, iter_init); + finish_expr_stmt (iter_init); + finish_expr_stmt (build_x_modify_expr (last, NOP_EXPR, decl, + tf_warning_or_error)); + add_stmt (orig_body); + *body = pop_stmt_list (*body); + + if (c) + { + OMP_CLAUSE_LASTPRIVATE_STMT (c) = push_stmt_list (); + finish_expr_stmt (iter_incr); + OMP_CLAUSE_LASTPRIVATE_STMT (c) + = pop_stmt_list (OMP_CLAUSE_LASTPRIVATE_STMT (c)); + } + + TREE_VEC_ELT (declv, i) = decl; + TREE_VEC_ELT (initv, i) = init; + TREE_VEC_ELT (condv, i) = cond; + TREE_VEC_ELT (incrv, i) = incr; + + return false; +} + /* Build and validate an OMP_FOR statement. CLAUSES, BODY, COND, INCR are directly for their associated operands in the statement. DECL and INIT are a combo; if DECL is NULL then INIT ought to be a @@ -3863,126 +4117,203 @@ finish_omp_parallel (tree clauses, tree body) sk_omp scope. */ tree -finish_omp_for (location_t locus, tree decl, tree init, tree cond, - tree incr, tree body, tree pre_body) +finish_omp_for (location_t locus, tree declv, tree initv, tree condv, + tree incrv, tree body, tree pre_body, tree clauses) { - tree omp_for = NULL; + tree omp_for = NULL, orig_incr = NULL; + tree decl, init, cond, incr; + location_t elocus; + int i; - if (decl == NULL) + gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (initv)); + gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (condv)); + gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (incrv)); + for (i = 0; i < TREE_VEC_LENGTH (declv); i++) { - if (init != NULL) - switch (TREE_CODE (init)) - { - case MODIFY_EXPR: - decl = TREE_OPERAND (init, 0); - init = TREE_OPERAND (init, 1); - break; - case MODOP_EXPR: - if (TREE_CODE (TREE_OPERAND (init, 1)) == NOP_EXPR) + decl = TREE_VEC_ELT (declv, i); + init = TREE_VEC_ELT (initv, i); + cond = TREE_VEC_ELT (condv, i); + incr = TREE_VEC_ELT (incrv, i); + elocus = locus; + + if (decl == NULL) + { + if (init != NULL) + switch (TREE_CODE (init)) { + case MODIFY_EXPR: decl = TREE_OPERAND (init, 0); - init = TREE_OPERAND (init, 2); + init = TREE_OPERAND (init, 1); + break; + case MODOP_EXPR: + if (TREE_CODE (TREE_OPERAND (init, 1)) == NOP_EXPR) + { + decl = TREE_OPERAND (init, 0); + init = TREE_OPERAND (init, 2); + } + break; + default: + break; } - break; - default: - break; - } - if (decl == NULL) - { - error ("expected iteration declaration or initialization"); - return NULL; + if (decl == NULL) + { + error ("%Hexpected iteration declaration or initialization", + &locus); + return NULL; + } } - } - if (type_dependent_expression_p (decl) - || type_dependent_expression_p (init) - || (cond && type_dependent_expression_p (cond)) - || (incr && type_dependent_expression_p (incr))) - { - tree stmt; + if (init && EXPR_HAS_LOCATION (init)) + elocus = EXPR_LOCATION (init); if (cond == NULL) { - error ("%Hmissing controlling predicate", &locus); + error ("%Hmissing controlling predicate", &elocus); return NULL; } if (incr == NULL) { - error ("%Hmissing increment expression", &locus); + error ("%Hmissing increment expression", &elocus); return NULL; } + TREE_VEC_ELT (declv, i) = decl; + TREE_VEC_ELT (initv, i) = init; + } + + if (dependent_omp_for_p (declv, initv, condv, incrv)) + { + tree stmt; + stmt = make_node (OMP_FOR); - /* This is really just a place-holder. We'll be decomposing this - again and going through the build_modify_expr path below when - we instantiate the thing. */ - init = build2 (MODIFY_EXPR, void_type_node, decl, init); + for (i = 0; i < TREE_VEC_LENGTH (declv); i++) + { + /* This is really just a place-holder. We'll be decomposing this + again and going through the cp_build_modify_expr path below when + we instantiate the thing. */ + TREE_VEC_ELT (initv, i) + = build2 (MODIFY_EXPR, void_type_node, TREE_VEC_ELT (declv, i), + TREE_VEC_ELT (initv, i)); + } TREE_TYPE (stmt) = void_type_node; - OMP_FOR_INIT (stmt) = init; - OMP_FOR_COND (stmt) = cond; - OMP_FOR_INCR (stmt) = incr; + OMP_FOR_INIT (stmt) = initv; + OMP_FOR_COND (stmt) = condv; + OMP_FOR_INCR (stmt) = incrv; OMP_FOR_BODY (stmt) = body; OMP_FOR_PRE_BODY (stmt) = pre_body; + OMP_FOR_CLAUSES (stmt) = clauses; SET_EXPR_LOCATION (stmt, locus); return add_stmt (stmt); } - if (!DECL_P (decl)) - { - error ("expected iteration declaration or initialization"); - return NULL; - } + if (processing_template_decl) + orig_incr = make_tree_vec (TREE_VEC_LENGTH (incrv)); - if (!INTEGRAL_TYPE_P (TREE_TYPE (decl))) + for (i = 0; i < TREE_VEC_LENGTH (declv); ) { - location_t elocus = locus; - - if (EXPR_HAS_LOCATION (init)) + decl = TREE_VEC_ELT (declv, i); + init = TREE_VEC_ELT (initv, i); + cond = TREE_VEC_ELT (condv, i); + incr = TREE_VEC_ELT (incrv, i); + if (orig_incr) + TREE_VEC_ELT (orig_incr, i) = incr; + elocus = locus; + + if (init && EXPR_HAS_LOCATION (init)) elocus = EXPR_LOCATION (init); - error ("%Hinvalid type for iteration variable %qE", &elocus, decl); - return NULL; - } - if (pre_body == NULL || IS_EMPTY_STMT (pre_body)) - pre_body = NULL; - else if (! processing_template_decl) - { - add_stmt (pre_body); - pre_body = NULL; - } + if (!DECL_P (decl)) + { + error ("%Hexpected iteration declaration or initialization", + &elocus); + return NULL; + } - if (!processing_template_decl) - init = fold_build_cleanup_point_expr (TREE_TYPE (init), init); - init = cp_build_modify_expr (decl, NOP_EXPR, init, tf_warning_or_error); - if (cond && TREE_SIDE_EFFECTS (cond) && COMPARISON_CLASS_P (cond)) - { - int n = TREE_SIDE_EFFECTS (TREE_OPERAND (cond, 1)) != 0; - tree t = TREE_OPERAND (cond, n); + if (incr && TREE_CODE (incr) == MODOP_EXPR) + { + if (orig_incr) + TREE_VEC_ELT (orig_incr, i) = incr; + incr = cp_build_modify_expr (TREE_OPERAND (incr, 0), + TREE_CODE (TREE_OPERAND (incr, 1)), + TREE_OPERAND (incr, 2), + tf_warning_or_error); + } + + if (CLASS_TYPE_P (TREE_TYPE (decl))) + { + if (handle_omp_for_class_iterator (i, locus, declv, initv, condv, + incrv, &body, &pre_body, clauses)) + return NULL; + continue; + } + + if (!INTEGRAL_TYPE_P (TREE_TYPE (decl)) + && TREE_CODE (TREE_TYPE (decl)) != POINTER_TYPE) + { + error ("%Hinvalid type for iteration variable %qE", &elocus, decl); + return NULL; + } if (!processing_template_decl) - TREE_OPERAND (cond, n) - = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + init = fold_build_cleanup_point_expr (TREE_TYPE (init), init); + init = cp_build_modify_expr (decl, NOP_EXPR, init, tf_warning_or_error); + if (cond && TREE_SIDE_EFFECTS (cond) && COMPARISON_CLASS_P (cond)) + { + int n = TREE_SIDE_EFFECTS (TREE_OPERAND (cond, 1)) != 0; + tree t = TREE_OPERAND (cond, n); + + if (!processing_template_decl) + TREE_OPERAND (cond, n) + = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + } + if (decl == error_mark_node || init == error_mark_node) + return NULL; + + TREE_VEC_ELT (declv, i) = decl; + TREE_VEC_ELT (initv, i) = init; + TREE_VEC_ELT (condv, i) = cond; + TREE_VEC_ELT (incrv, i) = incr; + i++; } - if (decl != error_mark_node && init != error_mark_node) - omp_for = c_finish_omp_for (locus, decl, init, cond, incr, body, pre_body); - if (omp_for != NULL - && TREE_CODE (OMP_FOR_INCR (omp_for)) == MODIFY_EXPR - && TREE_SIDE_EFFECTS (TREE_OPERAND (OMP_FOR_INCR (omp_for), 1)) - && BINARY_CLASS_P (TREE_OPERAND (OMP_FOR_INCR (omp_for), 1))) + + if (IS_EMPTY_STMT (pre_body)) + pre_body = NULL; + + omp_for = c_finish_omp_for (locus, declv, initv, condv, incrv, + body, pre_body); + + if (omp_for == NULL) + return NULL; + + for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INCR (omp_for)); i++) { - tree t = TREE_OPERAND (OMP_FOR_INCR (omp_for), 1); - int n = TREE_SIDE_EFFECTS (TREE_OPERAND (t, 1)) != 0; + tree incr = TREE_VEC_ELT (OMP_FOR_INCR (omp_for), i); - if (!processing_template_decl) - TREE_OPERAND (t, n) - = fold_build_cleanup_point_expr (TREE_TYPE (TREE_OPERAND (t, n)), - TREE_OPERAND (t, n)); + if (TREE_CODE (incr) != MODIFY_EXPR) + continue; + + if (TREE_SIDE_EFFECTS (TREE_OPERAND (incr, 1)) + && BINARY_CLASS_P (TREE_OPERAND (incr, 1))) + { + tree t = TREE_OPERAND (incr, 1); + int n = TREE_SIDE_EFFECTS (TREE_OPERAND (t, 1)) != 0; + + if (!processing_template_decl) + TREE_OPERAND (t, n) + = fold_build_cleanup_point_expr (TREE_TYPE (TREE_OPERAND (t, n)), + TREE_OPERAND (t, n)); + } + + if (orig_incr) + TREE_VEC_ELT (OMP_FOR_INCR (omp_for), i) = TREE_VEC_ELT (orig_incr, i); } + if (omp_for != NULL) + OMP_FOR_CLAUSES (omp_for) = clauses; return omp_for; } @@ -4039,26 +4370,12 @@ finish_omp_flush (void) finish_expr_stmt (stmt); } -/* True if OpenMP sharing attribute of DECL is predetermined. */ - -enum omp_clause_default_kind -cxx_omp_predetermined_sharing (tree decl) +void +finish_omp_taskwait (void) { - enum omp_clause_default_kind kind; - - kind = c_omp_predetermined_sharing (decl); - if (kind != OMP_CLAUSE_DEFAULT_UNSPECIFIED) - return kind; - - /* Static data members are predetermined as shared. */ - if (TREE_STATIC (decl)) - { - tree ctx = CP_DECL_CONTEXT (decl); - if (TYPE_P (ctx) && MAYBE_CLASS_TYPE_P (ctx)) - return OMP_CLAUSE_DEFAULT_SHARED; - } - - return OMP_CLAUSE_DEFAULT_UNSPECIFIED; + tree fn = built_in_decls[BUILT_IN_GOMP_TASKWAIT]; + tree stmt = finish_call_expr (fn, NULL, false, false, tf_warning_or_error); + finish_expr_stmt (stmt); } void |