OSDN Git Service

* c-cppbuiltin.c (c_cpp_builtins): Change _OPENMP value to
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 6 Jun 2008 13:01:54 +0000 (13:01 +0000)
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 6 Jun 2008 13:01:54 +0000 (13:01 +0000)
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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@136433 138bc75d-0d04-0410-961f-82ee72b054a4

193 files changed:
gcc/ChangeLog
gcc/bitmap.c
gcc/builtin-types.def
gcc/c-common.h
gcc/c-cppbuiltin.c
gcc/c-omp.c
gcc/c-parser.c
gcc/c-pragma.c
gcc/c-pragma.h
gcc/c-tree.h
gcc/c-typeck.c
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-gimplify.c
gcc/cp/cp-objcp-common.h
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/fortran/ChangeLog
gcc/fortran/dump-parse-tree.c
gcc/fortran/f95-lang.c
gcc/fortran/gfortran.h
gcc/fortran/match.h
gcc/fortran/openmp.c
gcc/fortran/parse.c
gcc/fortran/resolve.c
gcc/fortran/scanner.c
gcc/fortran/st.c
gcc/fortran/trans-openmp.c
gcc/fortran/trans.c
gcc/fortran/trans.h
gcc/fortran/types.def
gcc/gimple-low.c
gcc/gimplify.c
gcc/hooks.c
gcc/hooks.h
gcc/ipa-struct-reorg.c
gcc/langhooks-def.h
gcc/langhooks.h
gcc/matrix-reorg.c
gcc/omp-builtins.def
gcc/omp-low.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/gomp/for-16.C
gcc/testsuite/g++.dg/gomp/pr27499.C
gcc/testsuite/g++.dg/gomp/pr34607.C
gcc/testsuite/g++.dg/gomp/predetermined-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/gomp/task-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/gomp/tls-3.C
gcc/testsuite/g++.dg/gomp/tls-4.C [new file with mode: 0644]
gcc/testsuite/gcc.dg/gomp/appendix-a/a.35.4.c
gcc/testsuite/gcc.dg/gomp/appendix-a/a.35.6.c
gcc/testsuite/gcc.dg/gomp/collapse-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/gomp/nesting-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/gomp/pr27499.c
gcc/testsuite/gfortran.dg/gomp/appendix-a/a.33.4.f90
gcc/testsuite/gfortran.dg/gomp/appendix-a/a.35.4.f90
gcc/testsuite/gfortran.dg/gomp/appendix-a/a.35.6.f90
gcc/testsuite/gfortran.dg/gomp/collapse1.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/gomp/omp_parse1.f90
gcc/testsuite/gfortran.dg/gomp/reduction1.f90
gcc/testsuite/gfortran.dg/gomp/sharing-3.f90 [new file with mode: 0644]
gcc/tree-cfg.c
gcc/tree-gimple.c
gcc/tree-inline.c
gcc/tree-nested.c
gcc/tree-parloops.c
gcc/tree-pretty-print.c
gcc/tree-ssa-operands.c
gcc/tree.c
gcc/tree.def
gcc/tree.h
libgomp/ChangeLog
libgomp/Makefile.am
libgomp/Makefile.in
libgomp/barrier.c
libgomp/config.h.in
libgomp/config/linux/affinity.c
libgomp/config/linux/alpha/futex.h
libgomp/config/linux/bar.c
libgomp/config/linux/bar.h
libgomp/config/linux/ia64/futex.h
libgomp/config/linux/lock.c
libgomp/config/linux/mutex.c
libgomp/config/linux/omp-lock.h
libgomp/config/linux/powerpc/futex.h
libgomp/config/linux/proc.c
libgomp/config/linux/ptrlock.c [new file with mode: 0644]
libgomp/config/linux/ptrlock.h [new file with mode: 0644]
libgomp/config/linux/s390/futex.h
libgomp/config/linux/sem.c
libgomp/config/linux/sparc/futex.h
libgomp/config/linux/wait.h [new file with mode: 0644]
libgomp/config/linux/x86/futex.h
libgomp/config/mingw32/proc.c
libgomp/config/posix/bar.c
libgomp/config/posix/bar.h
libgomp/config/posix/lock.c
libgomp/config/posix/omp-lock.h
libgomp/config/posix/proc.c
libgomp/config/posix/ptrlock.c [new file with mode: 0644]
libgomp/config/posix/ptrlock.h [new file with mode: 0644]
libgomp/config/posix95/lock.c
libgomp/config/posix95/omp-lock.h
libgomp/configure
libgomp/configure.ac
libgomp/env.c
libgomp/fortran.c
libgomp/iter.c
libgomp/iter_ull.c [new file with mode: 0644]
libgomp/libgomp.h
libgomp/libgomp.map
libgomp/libgomp_f.h.in
libgomp/libgomp_g.h
libgomp/loop.c
libgomp/loop_ull.c [new file with mode: 0644]
libgomp/omp.h.in
libgomp/omp_lib.f90.in
libgomp/omp_lib.h.in
libgomp/parallel.c
libgomp/sections.c
libgomp/single.c
libgomp/task.c [new file with mode: 0644]
libgomp/team.c
libgomp/testsuite/Makefile.in
libgomp/testsuite/libgomp.c++/c++.exp
libgomp/testsuite/libgomp.c++/collapse-1.C [new file with mode: 0644]
libgomp/testsuite/libgomp.c++/collapse-2.C [new file with mode: 0644]
libgomp/testsuite/libgomp.c++/ctor-10.C [new file with mode: 0644]
libgomp/testsuite/libgomp.c++/for-1.C [new file with mode: 0644]
libgomp/testsuite/libgomp.c++/for-2.C [new file with mode: 0644]
libgomp/testsuite/libgomp.c++/for-3.C [new file with mode: 0644]
libgomp/testsuite/libgomp.c++/for-4.C [new file with mode: 0644]
libgomp/testsuite/libgomp.c++/for-5.C [new file with mode: 0644]
libgomp/testsuite/libgomp.c++/loop-10.C [new file with mode: 0644]
libgomp/testsuite/libgomp.c++/loop-8.C [new file with mode: 0644]
libgomp/testsuite/libgomp.c++/loop-9.C [new file with mode: 0644]
libgomp/testsuite/libgomp.c++/task-1.C [new file with mode: 0644]
libgomp/testsuite/libgomp.c++/task-2.C [new file with mode: 0644]
libgomp/testsuite/libgomp.c++/task-3.C [new file with mode: 0644]
libgomp/testsuite/libgomp.c++/task-4.C [new file with mode: 0644]
libgomp/testsuite/libgomp.c++/task-5.C [new file with mode: 0644]
libgomp/testsuite/libgomp.c++/task-6.C [new file with mode: 0644]
libgomp/testsuite/libgomp.c/collapse-1.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c/collapse-2.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c/collapse-3.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c/icv-1.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c/icv-2.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c/lib-2.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c/lock-1.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c/lock-2.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c/lock-3.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c/loop-4.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c/loop-5.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c/loop-6.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c/loop-7.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c/loop-8.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c/loop-9.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c/nested-3.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c/nestedfn-6.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c/pr26943-2.c
libgomp/testsuite/libgomp.c/pr26943-3.c
libgomp/testsuite/libgomp.c/pr26943-4.c
libgomp/testsuite/libgomp.c/sort-1.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c/task-1.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c/task-2.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c/task-3.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c/task-4.c [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/allocatable1.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/allocatable2.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/allocatable3.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/allocatable4.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/collapse1.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/collapse2.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/collapse3.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/collapse4.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/lastprivate1.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/lastprivate2.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/lib4.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/lock-1.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/lock-2.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/nested1.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/nestedfn4.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/strassen.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/tabs1.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/tabs2.f [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/task1.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/task2.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/vla4.f90
libgomp/testsuite/libgomp.fortran/vla5.f90
libgomp/work.c

index e4cc387..ce1eae6 100644 (file)
@@ -1,3 +1,265 @@
+2008-06-06  Jakub Jelinek  <jakub@redhat.com>
+
+       * 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.
+
 2008-06-06  Uros Bizjak  <ubizjak@gmail.com>
 
        * config/i386/i386.md (*indirect_jump): Macroize using P
index c2a66f9..97e60de 100644 (file)
@@ -119,6 +119,7 @@ register_overhead (bitmap b, int amount)
 /* Global data */
 bitmap_element bitmap_zero_bits;  /* An element of all zero bits.  */
 bitmap_obstack bitmap_default_obstack;    /* The default bitmap obstack.  */
+static int bitmap_default_obstack_depth;
 static GTY((deletable)) bitmap_element *bitmap_ggc_free; /* Freelist of
                                                            GC'd elements.  */
 
@@ -302,7 +303,11 @@ void
 bitmap_obstack_initialize (bitmap_obstack *bit_obstack)
 {
   if (!bit_obstack)
-    bit_obstack = &bitmap_default_obstack;
+    {
+      if (bitmap_default_obstack_depth++)
+       return;
+      bit_obstack = &bitmap_default_obstack;
+    }
 
 #if !defined(__GNUC__) || (__GNUC__ < 2)
 #define __alignof__(type) 0
@@ -323,7 +328,14 @@ void
 bitmap_obstack_release (bitmap_obstack *bit_obstack)
 {
   if (!bit_obstack)
-    bit_obstack = &bitmap_default_obstack;
+    {
+      if (--bitmap_default_obstack_depth)
+       {
+         gcc_assert (bitmap_default_obstack_depth > 0);
+         return;
+       }
+      bit_obstack = &bitmap_default_obstack;
+    }
 
   bit_obstack->elements = NULL;
   bit_obstack->heads = NULL;
index 25b5a09..7d25e5a 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007
+/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -121,6 +121,7 @@ DEF_PRIMITIVE_TYPE (BT_I16, builtin_type_for_size (BITS_PER_UNIT*16, 1))
 
 DEF_POINTER_TYPE (BT_PTR_CONST_STRING, BT_CONST_STRING)
 DEF_POINTER_TYPE (BT_PTR_LONG, BT_LONG)
+DEF_POINTER_TYPE (BT_PTR_ULONGLONG, BT_ULONGLONG)
 DEF_POINTER_TYPE (BT_PTR_PTR, BT_PTR)
 
 DEF_FUNCTION_TYPE_0 (BT_FN_VOID, BT_VOID)
@@ -308,6 +309,10 @@ DEF_FUNCTION_TYPE_2 (BT_FN_I8_VPTR_I8, BT_I8, BT_VOLATILE_PTR, BT_I8)
 DEF_FUNCTION_TYPE_2 (BT_FN_I16_VPTR_I16, BT_I16, BT_VOLATILE_PTR, BT_I16)
 DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_LONGPTR_LONGPTR,
                     BT_BOOL, BT_PTR_LONG, BT_PTR_LONG)
+DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_ULONGLONGPTR_ULONGLONGPTR,
+                    BT_BOOL, BT_PTR_ULONGLONG, BT_PTR_ULONGLONG)
+
+DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR)
 
 DEF_FUNCTION_TYPE_3 (BT_FN_STRING_STRING_CONST_STRING_SIZE,
                     BT_STRING, BT_STRING, BT_CONST_STRING, BT_SIZE)
@@ -410,10 +415,21 @@ DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_LONG_LONG_LONG_LONG_LONGPTR_LONGPTR,
 DEF_FUNCTION_TYPE_6 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG,
                     BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT,
                     BT_LONG, BT_LONG, BT_LONG)
+DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULLPTR_ULLPTR,
+                    BT_BOOL, BT_BOOL, BT_ULONGLONG, BT_ULONGLONG,
+                    BT_ULONGLONG, BT_PTR_ULONGLONG, BT_PTR_ULONGLONG)
 
 DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG,
                     BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT,
                     BT_LONG, BT_LONG, BT_LONG, BT_LONG)
+DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT,
+                    BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR,
+                    BT_PTR_FN_VOID_PTR_PTR, BT_LONG, BT_LONG,
+                    BT_BOOL, BT_UINT)
+DEF_FUNCTION_TYPE_7 (BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULL_ULLPTR_ULLPTR,
+                    BT_BOOL, BT_BOOL, BT_ULONGLONG, BT_ULONGLONG,
+                    BT_ULONGLONG, BT_ULONGLONG,
+                    BT_PTR_ULONGLONG, BT_PTR_ULONGLONG)
 
 DEF_FUNCTION_TYPE_VAR_0 (BT_FN_VOID_VAR, BT_VOID)
 DEF_FUNCTION_TYPE_VAR_0 (BT_FN_INT_VAR, BT_INT)
index 7ad0be5..82c018b 100644 (file)
@@ -995,6 +995,7 @@ extern tree c_finish_omp_ordered (tree);
 extern void c_finish_omp_barrier (void);
 extern tree c_finish_omp_atomic (enum tree_code, tree, tree);
 extern void c_finish_omp_flush (void);
+extern void c_finish_omp_taskwait (void);
 extern tree c_finish_omp_for (location_t, tree, tree, tree, tree, tree, tree);
 extern void c_split_parallel_clauses (tree, tree *, tree *);
 extern enum omp_clause_default_kind c_omp_predetermined_sharing (tree);
index 5948fbd..82bd5c2 100644 (file)
@@ -659,7 +659,7 @@ c_cpp_builtins (cpp_reader *pfile)
     cpp_define (pfile, "__SSP__=1");
 
   if (flag_openmp)
-    cpp_define (pfile, "_OPENMP=200505");
+    cpp_define (pfile, "_OPENMP=200805");
 
   builtin_define_type_sizeof ("__SIZEOF_INT__", integer_type_node);
   builtin_define_type_sizeof ("__SIZEOF_LONG__", long_integer_type_node);
index cdca2bc..1da71d2 100644 (file)
@@ -1,7 +1,7 @@
 /* This file contains routines to construct GNU OpenMP constructs, 
    called from parsing in the C and C++ front ends.
 
-   Copyright (C) 2005, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2007, 2008 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>,
                  Diego Novillo <dnovillo@redhat.com>.
 
@@ -80,6 +80,19 @@ c_finish_omp_barrier (void)
 }
 
 
+/* Complete a #pragma omp taskwait construct.  */
+
+void
+c_finish_omp_taskwait (void)
+{
+  tree x;
+
+  x = built_in_decls[BUILT_IN_GOMP_TASKWAIT];
+  x = build_call_expr (x, 0);
+  add_stmt (x);
+}
+
+
 /* Complete a #pragma omp atomic construct.  The expression to be 
    implemented atomically is LHS code= RHS.  The value returned is
    either error_mark_node (if the construct was erroneous) or an
@@ -197,170 +210,205 @@ check_omp_for_incr_expr (tree exp, tree decl)
 }
 
 /* Validate and emit code for the OpenMP directive #pragma omp for.
-   INIT, COND, INCR, BODY and PRE_BODY are the five basic elements
-   of the loop (initialization expression, controlling predicate, increment
-   expression, body of the loop and statements to go before the loop).
-   DECL is the iteration variable.  */
+   DECLV is a vector of iteration variables, for each collapsed loop.
+   INITV, CONDV and INCRV are vectors containing initialization
+   expressions, controlling predicates and increment expressions.
+   BODY is the body of the loop and PRE_BODY statements that go before
+   the loop.  */
 
 tree
-c_finish_omp_for (location_t locus, tree decl, tree init, tree cond,
-                 tree incr, tree body, tree pre_body)
+c_finish_omp_for (location_t locus, tree declv, tree initv, tree condv,
+                 tree incrv, tree body, tree pre_body)
 {
-  location_t elocus = locus;
+  location_t elocus;
   bool fail = false;
+  int i;
 
-  if (EXPR_HAS_LOCATION (init))
-    elocus = EXPR_LOCATION (init);
-
-  /* Validate the iteration variable.  */
-  if (!INTEGRAL_TYPE_P (TREE_TYPE (decl)))
+  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++)
     {
-      error ("%Hinvalid type for iteration variable %qE", &elocus, decl);
-      fail = true;
-    }
-  if (TYPE_UNSIGNED (TREE_TYPE (decl)))
-    warning (0, "%Hiteration variable %qE is unsigned", &elocus, decl);
+      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);
+
+      elocus = locus;
+      if (EXPR_HAS_LOCATION (init))
+       elocus = EXPR_LOCATION (init);
+
+      /* Validate the iteration variable.  */
+      if (!INTEGRAL_TYPE_P (TREE_TYPE (decl))
+         && TREE_CODE (TREE_TYPE (decl)) != POINTER_TYPE)
+       {
+         error ("%Hinvalid type for iteration variable %qE", &elocus, decl);
+         fail = true;
+       }
 
-  /* In the case of "for (int i = 0...)", init will be a decl.  It should
-     have a DECL_INITIAL that we can turn into an assignment.  */
-  if (init == decl)
-    {
-      elocus = DECL_SOURCE_LOCATION (decl);
+      /* In the case of "for (int i = 0...)", init will be a decl.  It should
+        have a DECL_INITIAL that we can turn into an assignment.  */
+      if (init == decl)
+       {
+         elocus = DECL_SOURCE_LOCATION (decl);
+
+         init = DECL_INITIAL (decl);
+         if (init == NULL)
+           {
+             error ("%H%qE is not initialized", &elocus, decl);
+             init = integer_zero_node;
+             fail = true;
+           }
 
-      init = DECL_INITIAL (decl);
-      if (init == NULL)
+         init = build_modify_expr (decl, NOP_EXPR, init);
+         SET_EXPR_LOCATION (init, elocus);
+       }
+      gcc_assert (TREE_CODE (init) == MODIFY_EXPR);
+      gcc_assert (TREE_OPERAND (init, 0) == decl);
+
+      if (cond == NULL_TREE)
        {
-         error ("%H%qE is not initialized", &elocus, decl);
-         init = integer_zero_node;
+         error ("%Hmissing controlling predicate", &elocus);
          fail = true;
        }
+      else
+       {
+         bool cond_ok = false;
 
-      init = build_modify_expr (decl, NOP_EXPR, init);
-      SET_EXPR_LOCATION (init, elocus);
-    }
-  gcc_assert (TREE_CODE (init) == MODIFY_EXPR);
-  gcc_assert (TREE_OPERAND (init, 0) == decl);
-  
-  if (cond == NULL_TREE)
-    {
-      error ("%Hmissing controlling predicate", &elocus);
-      fail = true;
-    }
-  else
-    {
-      bool cond_ok = false;
+         if (EXPR_HAS_LOCATION (cond))
+           elocus = EXPR_LOCATION (cond);
 
-      if (EXPR_HAS_LOCATION (cond))
-       elocus = EXPR_LOCATION (cond);
+         if (TREE_CODE (cond) == LT_EXPR
+             || TREE_CODE (cond) == LE_EXPR
+             || TREE_CODE (cond) == GT_EXPR
+             || TREE_CODE (cond) == GE_EXPR)
+           {
+             tree op0 = TREE_OPERAND (cond, 0);
+             tree op1 = TREE_OPERAND (cond, 1);
 
-      if (TREE_CODE (cond) == LT_EXPR
-         || TREE_CODE (cond) == LE_EXPR
-         || TREE_CODE (cond) == GT_EXPR
-         || TREE_CODE (cond) == GE_EXPR)
-       {
-         tree op0 = TREE_OPERAND (cond, 0);
-         tree op1 = TREE_OPERAND (cond, 1);
+             /* 2.5.1.  The comparison in the condition is computed in
+                the type of DECL, otherwise the behavior is undefined.
 
-         /* 2.5.1.  The comparison in the condition is computed in the type
-            of DECL, otherwise the behavior is undefined.
+                For example:
+                long n; int i;
+                i < n;
 
-            For example:
-            long n; int i;
-            i < n;
+                according to ISO will be evaluated as:
+                (long)i < n;
 
-            according to ISO will be evaluated as:
-            (long)i < n;
+                We want to force:
+                i < (int)n;  */
+             if (TREE_CODE (op0) == NOP_EXPR
+                 && decl == TREE_OPERAND (op0, 0))
+               {
+                 TREE_OPERAND (cond, 0) = TREE_OPERAND (op0, 0);
+                 TREE_OPERAND (cond, 1)
+                   = fold_build1 (NOP_EXPR, TREE_TYPE (decl),
+                                  TREE_OPERAND (cond, 1));
+               }
+             else if (TREE_CODE (op1) == NOP_EXPR
+                      && decl == TREE_OPERAND (op1, 0))
+               {
+                 TREE_OPERAND (cond, 1) = TREE_OPERAND (op1, 0);
+                 TREE_OPERAND (cond, 0)
+                   = fold_build1 (NOP_EXPR, TREE_TYPE (decl),
+                                  TREE_OPERAND (cond, 0));
+               }
 
-            We want to force:
-            i < (int)n;  */
-         if (TREE_CODE (op0) == NOP_EXPR
-             && decl == TREE_OPERAND (op0, 0))
-           {
-             TREE_OPERAND (cond, 0) = TREE_OPERAND (op0, 0);
-             TREE_OPERAND (cond, 1) = fold_build1 (NOP_EXPR, TREE_TYPE (decl),
-                                                   TREE_OPERAND (cond, 1));
-           }
-         else if (TREE_CODE (op1) == NOP_EXPR
-                  && decl == TREE_OPERAND (op1, 0))
-           {
-             TREE_OPERAND (cond, 1) = TREE_OPERAND (op1, 0);
-             TREE_OPERAND (cond, 0) = fold_build1 (NOP_EXPR, TREE_TYPE (decl),
-                                                   TREE_OPERAND (cond, 0));
+             if (decl == TREE_OPERAND (cond, 0))
+               cond_ok = true;
+             else if (decl == TREE_OPERAND (cond, 1))
+               {
+                 TREE_SET_CODE (cond,
+                                swap_tree_comparison (TREE_CODE (cond)));
+                 TREE_OPERAND (cond, 1) = TREE_OPERAND (cond, 0);
+                 TREE_OPERAND (cond, 0) = decl;
+                 cond_ok = true;
+               }
            }
 
-         if (decl == TREE_OPERAND (cond, 0))
-           cond_ok = true;
-         else if (decl == TREE_OPERAND (cond, 1))
+         if (!cond_ok)
            {
-             TREE_SET_CODE (cond, swap_tree_comparison (TREE_CODE (cond)));
-             TREE_OPERAND (cond, 1) = TREE_OPERAND (cond, 0);
-             TREE_OPERAND (cond, 0) = decl;
-             cond_ok = true;
+             error ("%Hinvalid controlling predicate", &elocus);
+             fail = true;
            }
        }
 
-      if (!cond_ok)
+      if (incr == NULL_TREE)
        {
-         error ("%Hinvalid controlling predicate", &elocus);
+         error ("%Hmissing increment expression", &elocus);
          fail = true;
        }
-    }
-
-  if (incr == NULL_TREE)
-    {
-      error ("%Hmissing increment expression", &elocus);
-      fail = true;
-    }
-  else
-    {
-      bool incr_ok = false;
-
-      if (EXPR_HAS_LOCATION (incr))
-       elocus = EXPR_LOCATION (incr);
-
-      /* Check all the valid increment expressions: v++, v--, ++v, --v,
-        v = v + incr, v = incr + v and v = v - incr.  */
-      switch (TREE_CODE (incr))
+      else
        {
-       case POSTINCREMENT_EXPR:
-       case PREINCREMENT_EXPR:
-       case POSTDECREMENT_EXPR:
-       case PREDECREMENT_EXPR:
-         incr_ok = (TREE_OPERAND (incr, 0) == decl);
-         break;
+         bool incr_ok = false;
 
-       case MODIFY_EXPR:
-         if (TREE_OPERAND (incr, 0) != decl)
-           break;
-         if (TREE_OPERAND (incr, 1) == decl)
-           break;
-         if (TREE_CODE (TREE_OPERAND (incr, 1)) == PLUS_EXPR
-             && (TREE_OPERAND (TREE_OPERAND (incr, 1), 0) == decl
-                 || TREE_OPERAND (TREE_OPERAND (incr, 1), 1) == decl))
-           incr_ok = true;
-         else if (TREE_CODE (TREE_OPERAND (incr, 1)) == MINUS_EXPR
-                  && TREE_OPERAND (TREE_OPERAND (incr, 1), 0) == decl)
-           incr_ok = true;
-         else
+         if (EXPR_HAS_LOCATION (incr))
+           elocus = EXPR_LOCATION (incr);
+
+         /* Check all the valid increment expressions: v++, v--, ++v, --v,
+            v = v + incr, v = incr + v and v = v - incr.  */
+         switch (TREE_CODE (incr))
            {
-             tree t = check_omp_for_incr_expr (TREE_OPERAND (incr, 1), decl);
-             if (t != error_mark_node)
+           case POSTINCREMENT_EXPR:
+           case PREINCREMENT_EXPR:
+           case POSTDECREMENT_EXPR:
+           case PREDECREMENT_EXPR:
+             if (TREE_OPERAND (incr, 0) != decl)
+               break;
+
+             incr_ok = true;
+             if (POINTER_TYPE_P (TREE_TYPE (decl)))
                {
-                 incr_ok = true;
-                 t = build2 (PLUS_EXPR, TREE_TYPE (decl), decl, t);
+                 tree t = fold_convert (sizetype, TREE_OPERAND (incr, 1));
+
+                 if (TREE_CODE (incr) == POSTDECREMENT_EXPR
+                     || TREE_CODE (incr) == PREDECREMENT_EXPR)
+                   t = fold_build1 (NEGATE_EXPR, sizetype, t);
+                 t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (decl), decl, t);
                  incr = build2 (MODIFY_EXPR, void_type_node, decl, t);
                }
-           }
-         break;
+             break;
+
+           case MODIFY_EXPR:
+             if (TREE_OPERAND (incr, 0) != decl)
+               break;
+             if (TREE_OPERAND (incr, 1) == decl)
+               break;
+             if (TREE_CODE (TREE_OPERAND (incr, 1)) == PLUS_EXPR
+                 && (TREE_OPERAND (TREE_OPERAND (incr, 1), 0) == decl
+                     || TREE_OPERAND (TREE_OPERAND (incr, 1), 1) == decl))
+               incr_ok = true;
+             else if ((TREE_CODE (TREE_OPERAND (incr, 1)) == MINUS_EXPR
+                       || (TREE_CODE (TREE_OPERAND (incr, 1))
+                           == POINTER_PLUS_EXPR))
+                      && TREE_OPERAND (TREE_OPERAND (incr, 1), 0) == decl)
+               incr_ok = true;
+             else
+               {
+                 tree t = check_omp_for_incr_expr (TREE_OPERAND (incr, 1),
+                                                   decl);
+                 if (t != error_mark_node)
+                   {
+                     incr_ok = true;
+                     t = build2 (PLUS_EXPR, TREE_TYPE (decl), decl, t);
+                     incr = build2 (MODIFY_EXPR, void_type_node, decl, t);
+                   }
+               }
+             break;
 
-       default:
-         break;
-       }
-      if (!incr_ok)
-       {
-         error ("%Hinvalid increment expression", &elocus);
-         fail = true;
+           default:
+             break;
+           }
+         if (!incr_ok)
+           {
+             error ("%Hinvalid increment expression", &elocus);
+             fail = true;
+           }
        }
+
+      TREE_VEC_ELT (initv, i) = init;
+      TREE_VEC_ELT (incrv, i) = incr;
     }
 
   if (fail)
@@ -370,9 +418,9 @@ c_finish_omp_for (location_t locus, tree decl, tree init, tree cond,
       tree t = make_node (OMP_FOR);
 
       TREE_TYPE (t) = void_type_node;
-      OMP_FOR_INIT (t) = init;
-      OMP_FOR_COND (t) = cond;
-      OMP_FOR_INCR (t) = incr;
+      OMP_FOR_INIT (t) = initv;
+      OMP_FOR_COND (t) = condv;
+      OMP_FOR_INCR (t) = incrv;
       OMP_FOR_BODY (t) = body;
       OMP_FOR_PRE_BODY (t) = pre_body;
 
@@ -416,6 +464,7 @@ c_split_parallel_clauses (tree clauses, tree *par_clauses, tree *ws_clauses)
 
        case OMP_CLAUSE_SCHEDULE:
        case OMP_CLAUSE_ORDERED:
+       case OMP_CLAUSE_COLLAPSE:
          OMP_CLAUSE_CHAIN (clauses) = *ws_clauses;
          *ws_clauses = clauses;
          break;
index d28ec9c..7607a8d 100644 (file)
@@ -1018,6 +1018,7 @@ static void c_parser_omp_construct (c_parser *);
 static void c_parser_omp_threadprivate (c_parser *);
 static void c_parser_omp_barrier (c_parser *);
 static void c_parser_omp_flush (c_parser *);
+static void c_parser_omp_taskwait (c_parser *);
 
 enum pragma_context { pragma_external, pragma_stmt, pragma_compound };
 static bool c_parser_pragma (c_parser *, enum pragma_context);
@@ -6674,6 +6675,17 @@ c_parser_pragma (c_parser *parser, enum pragma_context context)
       c_parser_omp_flush (parser);
       return false;
 
+    case PRAGMA_OMP_TASKWAIT:
+      if (context != pragma_compound)
+       {
+         if (context == pragma_stmt)
+           c_parser_error (parser, "%<#pragma omp taskwait%> may only be "
+                           "used in compound statements");
+         goto bad_stmt;
+       }
+      c_parser_omp_taskwait (parser);
+      return false;
+
     case PRAGMA_OMP_THREADPRIVATE:
       c_parser_omp_threadprivate (parser);
       return false;
@@ -6781,7 +6793,9 @@ c_parser_omp_clause_name (c_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;
@@ -6818,6 +6832,10 @@ c_parser_omp_clause_name (c_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;
        }
     }
 
@@ -6906,6 +6924,41 @@ c_parser_omp_var_list_parens (c_parser *parser, enum tree_code kind, tree list)
   return list;
 }
 
+/* OpenMP 3.0:
+   collapse ( constant-expression ) */
+
+static tree
+c_parser_omp_clause_collapse (c_parser *parser, tree list)
+{
+  tree c, num = error_mark_node;
+  HOST_WIDE_INT n;
+  location_t loc;
+
+  check_no_duplicate_clause (list, OMP_CLAUSE_COLLAPSE, "collapse");
+
+  loc = c_parser_peek_token (parser)->location;
+  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    {
+      num = c_parser_expr_no_commas (parser, NULL).value;
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+    }
+  if (num == error_mark_node)
+    return list;
+  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;
+    }
+  c = build_omp_clause (OMP_CLAUSE_COLLAPSE);
+  OMP_CLAUSE_COLLAPSE_EXPR (c) = num;
+  OMP_CLAUSE_CHAIN (c) = list;
+  return c;
+}
+
 /* OpenMP 2.5:
    copyin ( variable-list ) */
 
@@ -7164,7 +7217,7 @@ c_parser_omp_clause_reduction (c_parser *parser, tree list)
    schedule ( schedule-kind , expression )
 
    schedule-kind:
-     static | dynamic | guided | runtime
+     static | dynamic | guided | runtime | auto
 */
 
 static tree
@@ -7208,6 +7261,8 @@ c_parser_omp_clause_schedule (c_parser *parser, tree list)
     }
   else if (c_parser_next_token_is_keyword (parser, RID_STATIC))
     OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_STATIC;
+  else if (c_parser_next_token_is_keyword (parser, RID_AUTO))
+    OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_AUTO;
   else
     goto invalid_kind;
 
@@ -7223,6 +7278,9 @@ c_parser_omp_clause_schedule (c_parser *parser, tree list)
       if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_RUNTIME)
        error ("%Hschedule %<runtime%> does not take "
               "a %<chunk_size%> parameter", &here);
+      else if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_AUTO)
+       error ("%Hschedule %<auto%> does not take "
+              "a %<chunk_size%> parameter", &here);
       else if (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE)
        OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c) = t;
       else
@@ -7253,6 +7311,22 @@ c_parser_omp_clause_shared (c_parser *parser, tree list)
   return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_SHARED, list);
 }
 
+/* OpenMP 3.0:
+   untied */
+
+static tree
+c_parser_omp_clause_untied (c_parser *parser ATTRIBUTE_UNUSED, tree list)
+{
+  tree c;
+
+  /* FIXME: Should we allow duplicates?  */
+  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.  */
@@ -7280,6 +7354,10 @@ c_parser_omp_all_clauses (c_parser *parser, unsigned int mask,
 
       switch (c_kind)
        {
+       case PRAGMA_OMP_CLAUSE_COLLAPSE:
+         clauses = c_parser_omp_clause_collapse (parser, clauses);
+         c_name = "collapse";
+         break;
        case PRAGMA_OMP_CLAUSE_COPYIN:
          clauses = c_parser_omp_clause_copyin (parser, clauses);
          c_name = "copyin";
@@ -7332,6 +7410,10 @@ c_parser_omp_all_clauses (c_parser *parser, unsigned int mask,
          clauses = c_parser_omp_clause_shared (parser, clauses);
          c_name = "shared";
          break;
+       case PRAGMA_OMP_CLAUSE_UNTIED:
+         clauses = c_parser_omp_clause_untied (parser, clauses);
+         c_name = "untied";
+         break;
        default:
          c_parser_error (parser, "expected %<#pragma omp%> clause");
          goto saw_error;
@@ -7527,10 +7609,24 @@ c_parser_omp_flush (c_parser *parser)
    so that we can push a new decl if necessary to make it private.  */
 
 static tree
-c_parser_omp_for_loop (c_parser *parser)
+c_parser_omp_for_loop (c_parser *parser, tree clauses, tree *par_clauses)
 {
-  tree decl, cond, incr, save_break, save_cont, body, init;
+  tree decl, cond, incr, save_break, save_cont, body, init, stmt, cl;
+  tree declv, condv, incrv, initv, for_block = NULL, ret = NULL;
   location_t loc;
+  bool fail = false, open_brace_parsed = 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);
 
   if (!c_parser_next_token_is_keyword (parser, RID_FOR))
     {
@@ -7540,61 +7636,136 @@ c_parser_omp_for_loop (c_parser *parser)
   loc = c_parser_peek_token (parser)->location;
   c_parser_consume_token (parser);
 
-  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
-    return NULL;
-
-  /* Parse the initialization declaration or expression.  */
-  if (c_parser_next_token_starts_declspecs (parser))
+  for (i = 0; i < collapse; i++)
     {
-      c_parser_declaration_or_fndef (parser, true, true, true, true);
-      decl = check_for_loop_decls ();
-      if (decl == NULL)
-       goto error_init;
-      if (DECL_INITIAL (decl) == error_mark_node)
-       decl = error_mark_node;
-      init = decl;
-    }
-  else if (c_parser_next_token_is (parser, CPP_NAME)
-          && c_parser_peek_2nd_token (parser)->type == CPP_EQ)
-    {
-      decl = c_parser_postfix_expression (parser).value;
+      int bracecount = 0;
 
-      c_parser_require (parser, CPP_EQ, "expected %<=%>");
+      if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+       goto pop_scopes;
 
-      init = c_parser_expr_no_commas (parser, NULL).value;
-      init = build_modify_expr (decl, NOP_EXPR, init);
-      init = c_process_expr_stmt (init);
+      /* Parse the initialization declaration or expression.  */
+      if (c_parser_next_token_starts_declspecs (parser))
+       {
+         if (i > 0)
+           for_block
+             = tree_cons (NULL, c_begin_compound_stmt (true), for_block);
+         c_parser_declaration_or_fndef (parser, true, true, true, true);
+         decl = check_for_loop_decls ();
+         if (decl == NULL)
+           goto error_init;
+         if (DECL_INITIAL (decl) == error_mark_node)
+           decl = error_mark_node;
+         init = decl;
+       }
+      else if (c_parser_next_token_is (parser, CPP_NAME)
+              && c_parser_peek_2nd_token (parser)->type == CPP_EQ)
+       {
+         struct c_expr init_exp;
+
+         decl = c_parser_postfix_expression (parser).value;
+
+         c_parser_require (parser, CPP_EQ, "expected %<=%>");
+
+         init_exp = c_parser_expr_no_commas (parser, NULL);
+         init_exp = default_function_array_conversion (init_exp);
+         init = build_modify_expr (decl, NOP_EXPR, init_exp.value);
+         init = c_process_expr_stmt (init);
 
+         c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+       }
+      else
+       {
+       error_init:
+         c_parser_error (parser,
+                         "expected iteration declaration or initialization");
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         fail = true;
+         goto parse_next;
+       }
+
+      /* Parse the loop condition.  */
+      cond = NULL_TREE;
+      if (c_parser_next_token_is_not (parser, CPP_SEMICOLON))
+       {
+         cond = c_parser_expression_conv (parser).value;
+         cond = c_objc_common_truthvalue_conversion (cond);
+         if (CAN_HAVE_LOCATION_P (cond))
+           SET_EXPR_LOCATION (cond, input_location);
+       }
       c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
-    }
-  else
-    goto error_init;
 
-  /* Parse the loop condition.  */
-  cond = NULL_TREE;
-  if (c_parser_next_token_is_not (parser, CPP_SEMICOLON))
-    {
-      cond = c_parser_expression_conv (parser).value;
-      cond = c_objc_common_truthvalue_conversion (cond);
-      if (CAN_HAVE_LOCATION_P (cond))
-       SET_EXPR_LOCATION (cond, input_location);
-    }
-  c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+      /* Parse the increment expression.  */
+      incr = NULL_TREE;
+      if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN))
+       incr = c_process_expr_stmt (c_parser_expression (parser).value);
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
 
-  /* Parse the increment expression.  */
-  incr = NULL_TREE;
-  if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN))
-    incr = c_process_expr_stmt (c_parser_expression (parser).value);
-  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+      if (decl == NULL || decl == error_mark_node || init == error_mark_node)
+       fail = true;
+      else
+       {
+         TREE_VEC_ELT (declv, i) = decl;
+         TREE_VEC_ELT (initv, i) = init;
+         TREE_VEC_ELT (condv, i) = cond;
+         TREE_VEC_ELT (incrv, i) = incr;
+       }
+
+    parse_next:
+      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.  */
+      do
+       {
+         if (c_parser_next_token_is_keyword (parser, RID_FOR))
+           {
+             c_parser_consume_token (parser);
+             break;
+           }
+         else if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+           {
+             c_parser_consume_token (parser);
+             bracecount++;
+           }
+         else if (bracecount
+                  && c_parser_next_token_is (parser, CPP_SEMICOLON))
+           c_parser_consume_token (parser);
+         else
+           {
+             c_parser_error (parser, "not enough perfectly nested loops");
+             if (bracecount)
+               {
+                 open_brace_parsed = true;
+                 bracecount--;
+               }
+             fail = true;
+             collapse = 0;
+             break;
+           }
+       }
+      while (1);
+
+      nbraces += bracecount;
+    }
 
- parse_body:
   save_break = c_break_label;
   c_break_label = size_one_node;
   save_cont = c_cont_label;
   c_cont_label = NULL_TREE;
   body = push_stmt_list ();
 
-  add_stmt (c_parser_c99_block_statement (parser));
+  if (open_brace_parsed)
+    {
+      stmt = c_begin_compound_stmt (true);
+      c_parser_compound_statement_nostart (parser);
+      add_stmt (c_end_compound_stmt (stmt, true));
+    }
+  else
+    add_stmt (c_parser_c99_block_statement (parser));
   if (c_cont_label)
     add_stmt (build1 (LABEL_EXPR, void_type_node, c_cont_label));
 
@@ -7602,17 +7773,82 @@ c_parser_omp_for_loop (c_parser *parser)
   c_break_label = save_break;
   c_cont_label = save_cont;
 
+  while (nbraces)
+    {
+      if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+       {
+         c_parser_consume_token (parser);
+         nbraces--;
+       }
+      else if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+       c_parser_consume_token (parser);
+      else
+       {
+         c_parser_error (parser, "collapsed loops not perfectly nested");
+         while (nbraces)
+           {
+             stmt = c_begin_compound_stmt (true);
+             add_stmt (body);
+             c_parser_compound_statement_nostart (parser);
+             body = c_end_compound_stmt (stmt, true);
+             nbraces--;
+           }
+         goto pop_scopes;
+       }
+    }
+
   /* Only bother calling c_finish_omp_for if we haven't already generated
      an error from the initialization parsing.  */
-  if (decl != NULL && decl != error_mark_node && init != error_mark_node)
-    return c_finish_omp_for (loc, decl, init, cond, incr, body, NULL);
-  return NULL;
-
- error_init:
-  c_parser_error (parser, "expected iteration declaration or initialization");
-  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
-  decl = init = cond = incr = NULL_TREE;
-  goto parse_body;
+  if (!fail)
+    {
+      stmt = c_finish_omp_for (loc, declv, initv, condv, incrv, body, NULL);
+      if (stmt)
+       {
+         if (par_clauses != NULL)
+           {
+             tree *c;
+             for (c = par_clauses; *c ; )
+               if (OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_FIRSTPRIVATE
+                   && OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_LASTPRIVATE)
+                 c = &OMP_CLAUSE_CHAIN (*c);
+               else
+                 {
+                   for (i = 0; i < collapse; i++)
+                     if (TREE_VEC_ELT (declv, i) == OMP_CLAUSE_DECL (*c))
+                       break;
+                   if (i == collapse)
+                     c = &OMP_CLAUSE_CHAIN (*c);
+                   else if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_FIRSTPRIVATE)
+                     {
+                       error ("%Hiteration variable %qD should not be firstprivate",
+                              &loc, OMP_CLAUSE_DECL (*c));
+                       *c = OMP_CLAUSE_CHAIN (*c);
+                     }
+                   else
+                     {
+                       /* Copy 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) = OMP_CLAUSE_DECL (*c);
+                       OMP_CLAUSE_CHAIN (l) = clauses;
+                       clauses = l;
+                       OMP_CLAUSE_SET_CODE (*c, OMP_CLAUSE_SHARED);
+                     }
+                 }
+           }
+         OMP_FOR_CLAUSES (stmt) = clauses;
+       }
+      ret = stmt;
+    }
+pop_scopes:
+  while (for_block)
+    {
+      stmt = c_end_compound_stmt (TREE_VALUE (for_block), true);
+      add_stmt (stmt);
+      for_block = TREE_CHAIN (for_block);
+    }
+  return ret;
 }
 
 /* OpenMP 2.5:
@@ -7627,6 +7863,7 @@ c_parser_omp_for_loop (c_parser *parser)
        | (1u << PRAGMA_OMP_CLAUSE_REDUCTION)           \
        | (1u << PRAGMA_OMP_CLAUSE_ORDERED)             \
        | (1u << PRAGMA_OMP_CLAUSE_SCHEDULE)            \
+       | (1u << PRAGMA_OMP_CLAUSE_COLLAPSE)            \
        | (1u << PRAGMA_OMP_CLAUSE_NOWAIT))
 
 static tree
@@ -7638,9 +7875,7 @@ c_parser_omp_for (c_parser *parser)
                                      "#pragma omp for");
 
   block = c_begin_compound_stmt (true);
-  ret = c_parser_omp_for_loop (parser);
-  if (ret)
-    OMP_FOR_CLAUSES (ret) = clauses;
+  ret = c_parser_omp_for_loop (parser, clauses, NULL);
   block = c_end_compound_stmt (block, true);
   add_stmt (block);
 
@@ -7845,9 +8080,7 @@ c_parser_omp_parallel (c_parser *parser)
     case PRAGMA_OMP_PARALLEL_FOR:
       block = c_begin_omp_parallel ();
       c_split_parallel_clauses (clauses, &par_clause, &ws_clause);
-      stmt = c_parser_omp_for_loop (parser);
-      if (stmt)
-       OMP_FOR_CLAUSES (stmt) = ws_clause;
+      c_parser_omp_for_loop (parser, ws_clause, &par_clause);
       stmt = c_finish_omp_parallel (par_clause, block);
       OMP_PARALLEL_COMBINED (stmt) = 1;
       break;
@@ -7894,6 +8127,43 @@ c_parser_omp_single (c_parser *parser)
   return add_stmt (stmt);
 }
 
+/* OpenMP 3.0:
+   # pragma omp task task-clause[optseq] new-line
+*/
+
+#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
+c_parser_omp_task (c_parser *parser)
+{
+  tree clauses, block;
+
+  clauses = c_parser_omp_all_clauses (parser, OMP_TASK_CLAUSE_MASK,
+                                     "#pragma omp task");
+
+  block = c_begin_omp_task ();
+  c_parser_statement (parser);
+  return c_finish_omp_task (clauses, block);
+}
+
+/* OpenMP 3.0:
+   # pragma omp taskwait new-line
+*/
+
+static void
+c_parser_omp_taskwait (c_parser *parser)
+{
+  c_parser_consume_pragma (parser);
+  c_parser_skip_to_pragma_eol (parser);
+
+  c_finish_omp_taskwait ();
+}
 
 /* Main entry point to parsing most OpenMP pragmas.  */
 
@@ -7940,6 +8210,9 @@ c_parser_omp_construct (c_parser *parser)
     case PRAGMA_OMP_SINGLE:
       stmt = c_parser_omp_single (parser);
       break;
+    case PRAGMA_OMP_TASK:
+      stmt = c_parser_omp_task (parser);
+      break;
     default:
       gcc_unreachable ();
     }
index 44e95b8..81b9910 100644 (file)
@@ -896,6 +896,8 @@ static const struct omp_pragma_def omp_pragmas[] = {
   { "section", PRAGMA_OMP_SECTION },
   { "sections", PRAGMA_OMP_SECTIONS },
   { "single", PRAGMA_OMP_SINGLE },
+  { "task", PRAGMA_OMP_TASK },
+  { "taskwait", PRAGMA_OMP_TASKWAIT },
   { "threadprivate", PRAGMA_OMP_THREADPRIVATE }
 };
 
index 747a053..188afb8 100644 (file)
@@ -41,6 +41,8 @@ typedef enum pragma_kind {
   PRAGMA_OMP_SECTION,
   PRAGMA_OMP_SECTIONS,
   PRAGMA_OMP_SINGLE,
+  PRAGMA_OMP_TASK,
+  PRAGMA_OMP_TASKWAIT,
   PRAGMA_OMP_THREADPRIVATE,
 
   PRAGMA_GCC_PCH_PREPROCESS,
@@ -49,11 +51,12 @@ typedef enum pragma_kind {
 } pragma_kind;
 
 
-/* All clauses defined by OpenMP 2.5.
+/* All clauses defined by OpenMP 2.5 and 3.0.
    Used internally by both C and C++ parsers.  */
 typedef enum pragma_omp_clause {
   PRAGMA_OMP_CLAUSE_NONE = 0,
 
+  PRAGMA_OMP_CLAUSE_COLLAPSE,
   PRAGMA_OMP_CLAUSE_COPYIN,
   PRAGMA_OMP_CLAUSE_COPYPRIVATE,
   PRAGMA_OMP_CLAUSE_DEFAULT,
@@ -66,7 +69,8 @@ typedef enum pragma_omp_clause {
   PRAGMA_OMP_CLAUSE_PRIVATE,
   PRAGMA_OMP_CLAUSE_REDUCTION,
   PRAGMA_OMP_CLAUSE_SCHEDULE,
-  PRAGMA_OMP_CLAUSE_SHARED
+  PRAGMA_OMP_CLAUSE_SHARED,
+  PRAGMA_OMP_CLAUSE_UNTIED
 } pragma_omp_clause;
 
 extern struct cpp_reader* parse_in;
index 02dfc61..14df044 100644 (file)
@@ -596,6 +596,8 @@ extern void c_end_vm_scope (unsigned int);
 extern tree c_expr_to_decl (tree, bool *, bool *);
 extern tree c_begin_omp_parallel (void);
 extern tree c_finish_omp_parallel (tree, tree);
+extern tree c_begin_omp_task (void);
+extern tree c_finish_omp_task (tree, tree);
 extern tree c_finish_omp_clauses (tree);
 
 /* Set to 0 at beginning of a function definition, set to 1 if
index b52a349..23880d1 100644 (file)
@@ -8681,6 +8681,8 @@ c_begin_omp_parallel (void)
   return block;
 }
 
+/* Generate OMP_PARALLEL, with CLAUSES and BLOCK as its compound statement.  */
+
 tree
 c_finish_omp_parallel (tree clauses, tree block)
 {
@@ -8696,6 +8698,36 @@ c_finish_omp_parallel (tree clauses, tree block)
   return add_stmt (stmt);
 }
 
+/* Like c_begin_compound_stmt, except force the retention of the BLOCK.  */
+
+tree
+c_begin_omp_task (void)
+{
+  tree block;
+
+  keep_next_level ();
+  block = c_begin_compound_stmt (true);
+
+  return block;
+}
+
+/* Generate OMP_TASK, with CLAUSES and BLOCK as its compound statement.  */
+
+tree
+c_finish_omp_task (tree clauses, tree block)
+{
+  tree stmt;
+
+  block = c_end_compound_stmt (block, true);
+
+  stmt = make_node (OMP_TASK);
+  TREE_TYPE (stmt) = void_type_node;
+  OMP_TASK_CLAUSES (stmt) = clauses;
+  OMP_TASK_BODY (stmt) = block;
+
+  return add_stmt (stmt);
+}
+
 /* For all elements of CLAUSES, validate them vs OpenMP constraints.
    Remove any elements from the list that are invalid.  */
 
@@ -8856,6 +8888,8 @@ c_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:
          pc = &OMP_CLAUSE_CHAIN (c);
          continue;
 
index 54afddc..936db24 100644 (file)
@@ -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
index 0948c79..1d54e7c 100644 (file)
@@ -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))
index cc3e847..c6d64df 100644 (file)
@@ -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;
+}
index b2b8405..1121eb0 100644 (file)
@@ -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
 
index 0c3d0dd..952020a 100644 (file)
@@ -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);
index 0898d5d..8056518 100644 (file)
@@ -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));
index c3383e6..5ca1bd7 100644 (file)
@@ -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);
index 4bb43ad..f141b74 100644 (file)
@@ -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
index 96999bf..83d2339 100644 (file)
@@ -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);
 }
 \f
 void
index 826b409..5df5de5 100644 (file)
@@ -1,3 +1,87 @@
+2008-06-06  Jakub Jelinek  <jakub@redhat.com>
+
+       * 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.
+
 2008-06-04  Janus Weil  <janus@gcc.gnu.org>
 
        PR fortran/36322
index 44a4941..80ff5bc 100644 (file)
@@ -848,6 +848,8 @@ show_omp_node (int level, gfc_code *c)
     case EXEC_OMP_PARALLEL_WORKSHARE: name = "PARALLEL WORKSHARE"; break;
     case EXEC_OMP_SECTIONS: name = "SECTIONS"; break;
     case EXEC_OMP_SINGLE: name = "SINGLE"; break;
+    case EXEC_OMP_TASK: name = "TASK"; break;
+    case EXEC_OMP_TASKWAIT: name = "TASKWAIT"; break;
     case EXEC_OMP_WORKSHARE: name = "WORKSHARE"; break;
     default:
       gcc_unreachable ();
@@ -863,6 +865,7 @@ show_omp_node (int level, gfc_code *c)
     case EXEC_OMP_SINGLE:
     case EXEC_OMP_WORKSHARE:
     case EXEC_OMP_PARALLEL_WORKSHARE:
+    case EXEC_OMP_TASK:
       omp_clauses = c->ext.omp_clauses;
       break;
     case EXEC_OMP_CRITICAL:
@@ -878,6 +881,7 @@ show_omp_node (int level, gfc_code *c)
        }
       return;
     case EXEC_OMP_BARRIER:
+    case EXEC_OMP_TASKWAIT:
       return;
     default:
       break;
@@ -907,6 +911,7 @@ show_omp_node (int level, gfc_code *c)
            case OMP_SCHED_DYNAMIC: type = "DYNAMIC"; break;
            case OMP_SCHED_GUIDED: type = "GUIDED"; break;
            case OMP_SCHED_RUNTIME: type = "RUNTIME"; break;
+           case OMP_SCHED_AUTO: type = "AUTO"; break;
            default:
              gcc_unreachable ();
            }
@@ -926,7 +931,7 @@ show_omp_node (int level, gfc_code *c)
            case OMP_DEFAULT_NONE: type = "NONE"; break;
            case OMP_DEFAULT_PRIVATE: type = "PRIVATE"; break;
            case OMP_DEFAULT_SHARED: type = "SHARED"; break;
-           case OMP_SCHED_RUNTIME: type = "RUNTIME"; break;
+           case OMP_DEFAULT_FIRSTPRIVATE: type = "FIRSTPRIVATE"; break;
            default:
              gcc_unreachable ();
            }
@@ -934,6 +939,10 @@ show_omp_node (int level, gfc_code *c)
        }
       if (omp_clauses->ordered)
        fputs (" ORDERED", dumpfile);
+      if (omp_clauses->untied)
+       fputs (" UNTIED", dumpfile);
+      if (omp_clauses->collapse)
+       fprintf (dumpfile, " COLLAPSE(%d)", omp_clauses->collapse);
       for (list_type = 0; list_type < OMP_LIST_NUM; list_type++)
        if (omp_clauses->lists[list_type] != NULL
            && list_type != OMP_LIST_COPYPRIVATE)
@@ -1806,6 +1815,8 @@ show_code_node (int level, gfc_code *c)
     case EXEC_OMP_PARALLEL_WORKSHARE:
     case EXEC_OMP_SECTIONS:
     case EXEC_OMP_SINGLE:
+    case EXEC_OMP_TASK:
+    case EXEC_OMP_TASKWAIT:
     case EXEC_OMP_WORKSHARE:
       show_omp_node (level, c);
       break;
index 63c380b..42ab57a 100644 (file)
@@ -115,8 +115,12 @@ static alias_set_type gfc_get_alias_set (tree);
 #undef LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE
 #undef LANG_HOOKS_OMP_PREDETERMINED_SHARING
 #undef LANG_HOOKS_OMP_CLAUSE_DEFAULT_CTOR
+#undef LANG_HOOKS_OMP_CLAUSE_COPY_CTOR
+#undef LANG_HOOKS_OMP_CLAUSE_ASSIGN_OP
+#undef LANG_HOOKS_OMP_CLAUSE_DTOR
 #undef LANG_HOOKS_OMP_DISREGARD_VALUE_EXPR
 #undef LANG_HOOKS_OMP_PRIVATE_DEBUG_CLAUSE
+#undef LANG_HOOKS_OMP_PRIVATE_OUTER_REF
 #undef LANG_HOOKS_OMP_FIRSTPRIVATIZE_TYPE_SIZES
 #undef LANG_HOOKS_BUILTIN_FUNCTION
 #undef LANG_HOOKS_GET_ARRAY_DESCR_INFO
@@ -137,8 +141,12 @@ static alias_set_type gfc_get_alias_set (tree);
 #define LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE  gfc_omp_privatize_by_reference
 #define LANG_HOOKS_OMP_PREDETERMINED_SHARING   gfc_omp_predetermined_sharing
 #define LANG_HOOKS_OMP_CLAUSE_DEFAULT_CTOR     gfc_omp_clause_default_ctor
+#define LANG_HOOKS_OMP_CLAUSE_COPY_CTOR                gfc_omp_clause_copy_ctor
+#define LANG_HOOKS_OMP_CLAUSE_ASSIGN_OP                gfc_omp_clause_assign_op
+#define LANG_HOOKS_OMP_CLAUSE_DTOR             gfc_omp_clause_dtor
 #define LANG_HOOKS_OMP_DISREGARD_VALUE_EXPR    gfc_omp_disregard_value_expr
 #define LANG_HOOKS_OMP_PRIVATE_DEBUG_CLAUSE    gfc_omp_private_debug_clause
+#define LANG_HOOKS_OMP_PRIVATE_OUTER_REF       gfc_omp_private_outer_ref
 #define LANG_HOOKS_OMP_FIRSTPRIVATIZE_TYPE_SIZES \
   gfc_omp_firstprivatize_type_sizes
 #define LANG_HOOKS_BUILTIN_FUNCTION          gfc_builtin_function
index d4f9771..8665a48 100644 (file)
@@ -228,7 +228,8 @@ typedef enum
   ST_OMP_END_WORKSHARE, ST_OMP_DO, ST_OMP_FLUSH, ST_OMP_MASTER, ST_OMP_ORDERED,
   ST_OMP_PARALLEL, ST_OMP_PARALLEL_DO, ST_OMP_PARALLEL_SECTIONS,
   ST_OMP_PARALLEL_WORKSHARE, ST_OMP_SECTIONS, ST_OMP_SECTION, ST_OMP_SINGLE,
-  ST_OMP_THREADPRIVATE, ST_OMP_WORKSHARE, ST_PROCEDURE,
+  ST_OMP_THREADPRIVATE, ST_OMP_WORKSHARE, ST_OMP_TASK, ST_OMP_END_TASK,
+  ST_OMP_TASKWAIT, ST_PROCEDURE,
   ST_GET_FCN_CHARACTERISTICS, ST_NONE
 }
 gfc_statement;
@@ -927,7 +928,8 @@ typedef struct gfc_omp_clauses
       OMP_SCHED_STATIC,
       OMP_SCHED_DYNAMIC,
       OMP_SCHED_GUIDED,
-      OMP_SCHED_RUNTIME
+      OMP_SCHED_RUNTIME,
+      OMP_SCHED_AUTO
     } sched_kind;
   struct gfc_expr *chunk_size;
   enum
@@ -935,9 +937,11 @@ typedef struct gfc_omp_clauses
       OMP_DEFAULT_UNKNOWN,
       OMP_DEFAULT_NONE,
       OMP_DEFAULT_PRIVATE,
-      OMP_DEFAULT_SHARED
+      OMP_DEFAULT_SHARED,
+      OMP_DEFAULT_FIRSTPRIVATE
     } default_sharing;
-  bool nowait, ordered;
+  int collapse;
+  bool nowait, ordered, untied;
 }
 gfc_omp_clauses;
 
@@ -1760,7 +1764,7 @@ typedef enum
   EXEC_OMP_PARALLEL_SECTIONS, EXEC_OMP_PARALLEL_WORKSHARE,
   EXEC_OMP_SECTIONS, EXEC_OMP_SINGLE, EXEC_OMP_WORKSHARE,
   EXEC_OMP_ATOMIC, EXEC_OMP_BARRIER, EXEC_OMP_END_NOWAIT,
-  EXEC_OMP_END_SINGLE
+  EXEC_OMP_END_SINGLE, EXEC_OMP_TASK, EXEC_OMP_TASKWAIT
 }
 gfc_exec_op;
 
@@ -2040,6 +2044,7 @@ bool gfc_post_options (const char **);
 
 /* iresolve.c */
 const char * gfc_get_string (const char *, ...) ATTRIBUTE_PRINTF_1;
+bool gfc_find_sym_in_expr (gfc_symbol *, gfc_expr *);
 
 /* error.c */
 
index 3f8d310..5ee91fb 100644 (file)
@@ -119,6 +119,8 @@ match gfc_match_omp_parallel_sections (void);
 match gfc_match_omp_parallel_workshare (void);
 match gfc_match_omp_sections (void);
 match gfc_match_omp_single (void);
+match gfc_match_omp_task (void);
+match gfc_match_omp_taskwait (void);
 match gfc_match_omp_threadprivate (void);
 match gfc_match_omp_workshare (void);
 match gfc_match_omp_end_nowait (void);
index 9c0bae4..28f1cc2 100644 (file)
@@ -182,6 +182,8 @@ cleanup:
 #define OMP_CLAUSE_SCHEDULE    (1 << 9)
 #define OMP_CLAUSE_DEFAULT     (1 << 10)
 #define OMP_CLAUSE_ORDERED     (1 << 11)
+#define OMP_CLAUSE_COLLAPSE    (1 << 12)
+#define OMP_CLAUSE_UNTIED      (1 << 13)
 
 /* Match OpenMP directive clauses. MASK is a bitmask of
    clauses that are allowed for a particular directive.  */
@@ -335,6 +337,8 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, int mask)
            c->default_sharing = OMP_DEFAULT_PRIVATE;
          else if (gfc_match ("default ( none )") == MATCH_YES)
            c->default_sharing = OMP_DEFAULT_NONE;
+         else if (gfc_match ("default ( firstprivate )") == MATCH_YES)
+           c->default_sharing = OMP_DEFAULT_FIRSTPRIVATE;
          if (c->default_sharing != OMP_DEFAULT_UNKNOWN)
            continue;
        }
@@ -351,10 +355,13 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, int mask)
            c->sched_kind = OMP_SCHED_GUIDED;
          else if (gfc_match ("runtime") == MATCH_YES)
            c->sched_kind = OMP_SCHED_RUNTIME;
+         else if (gfc_match ("auto") == MATCH_YES)
+           c->sched_kind = OMP_SCHED_AUTO;
          if (c->sched_kind != OMP_SCHED_NONE)
            {
              match m = MATCH_NO;
-             if (c->sched_kind != OMP_SCHED_RUNTIME)
+             if (c->sched_kind != OMP_SCHED_RUNTIME
+                 && c->sched_kind != OMP_SCHED_AUTO)
                m = gfc_match (" , %e )", &c->chunk_size);
              if (m != MATCH_YES)
                m = gfc_match_char (')');
@@ -372,6 +379,36 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, int mask)
          c->ordered = needs_space = true;
          continue;
        }
+      if ((mask & OMP_CLAUSE_UNTIED) && !c->untied
+         && gfc_match ("untied") == MATCH_YES)
+       {
+         c->untied = needs_space = true;
+         continue;
+       }
+      if ((mask & OMP_CLAUSE_COLLAPSE) && !c->collapse)
+       {
+         gfc_expr *cexpr = NULL;
+         match m = gfc_match ("collapse ( %e )", &cexpr);
+
+         if (m == MATCH_YES)
+           {
+             int collapse;
+             const char *p = gfc_extract_int (cexpr, &collapse);
+             if (p)
+               {
+                 gfc_error (p);
+                 collapse = 1;
+               }
+             else if (collapse <= 0)
+               {
+                 gfc_error ("COLLAPSE clause argument not constant positive integer at %C");
+                 collapse = 1;
+               }
+             c->collapse = collapse;
+             gfc_free_expr (cexpr);
+             continue;
+           }
+       }
 
       break;
     }
@@ -393,10 +430,13 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, int mask)
 #define OMP_DO_CLAUSES \
   (OMP_CLAUSE_PRIVATE | OMP_CLAUSE_FIRSTPRIVATE                                \
    | OMP_CLAUSE_LASTPRIVATE | OMP_CLAUSE_REDUCTION                     \
-   | OMP_CLAUSE_SCHEDULE | OMP_CLAUSE_ORDERED)
+   | OMP_CLAUSE_SCHEDULE | OMP_CLAUSE_ORDERED | OMP_CLAUSE_COLLAPSE)
 #define OMP_SECTIONS_CLAUSES \
   (OMP_CLAUSE_PRIVATE | OMP_CLAUSE_FIRSTPRIVATE                                \
    | OMP_CLAUSE_LASTPRIVATE | OMP_CLAUSE_REDUCTION)
+#define OMP_TASK_CLAUSES \
+  (OMP_CLAUSE_PRIVATE | OMP_CLAUSE_FIRSTPRIVATE | OMP_CLAUSE_SHARED    \
+   | OMP_CLAUSE_IF | OMP_CLAUSE_DEFAULT | OMP_CLAUSE_UNTIED)
 
 match
 gfc_match_omp_parallel (void)
@@ -411,6 +451,29 @@ gfc_match_omp_parallel (void)
 
 
 match
+gfc_match_omp_task (void)
+{
+  gfc_omp_clauses *c;
+  if (gfc_match_omp_clauses (&c, OMP_TASK_CLAUSES) != MATCH_YES)
+    return MATCH_ERROR;
+  new_st.op = EXEC_OMP_TASK;
+  new_st.ext.omp_clauses = c;
+  return MATCH_YES;
+}
+
+
+match
+gfc_match_omp_taskwait (void)
+{
+  if (gfc_match_omp_eos () != MATCH_YES)
+    return MATCH_ERROR;
+  new_st.op = EXEC_OMP_TASKWAIT;
+  new_st.ext.omp_clauses = NULL;
+  return MATCH_YES;
+}
+
+
+match
 gfc_match_omp_critical (void)
 {
   char n[GFC_MAX_SYMBOL_LEN+1];
@@ -809,9 +872,6 @@ resolve_omp_clauses (gfc_code *code)
                if (!n->sym->attr.threadprivate)
                  gfc_error ("Non-THREADPRIVATE object '%s' in COPYIN clause"
                             " at %L", n->sym->name, &code->loc);
-               if (n->sym->attr.allocatable)
-                 gfc_error ("COPYIN clause object '%s' is ALLOCATABLE at %L",
-                            n->sym->name, &code->loc);
                if (n->sym->ts.type == BT_DERIVED && n->sym->ts.derived->attr.alloc_comp)
                  gfc_error ("COPYIN clause object '%s' at %L has ALLOCATABLE components",
                             n->sym->name, &code->loc);
@@ -823,9 +883,6 @@ resolve_omp_clauses (gfc_code *code)
                if (n->sym->as && n->sym->as->type == AS_ASSUMED_SIZE)
                  gfc_error ("Assumed size array '%s' in COPYPRIVATE clause "
                             "at %L", n->sym->name, &code->loc);
-               if (n->sym->attr.allocatable)
-                 gfc_error ("COPYPRIVATE clause object '%s' is ALLOCATABLE "
-                            "at %L", n->sym->name, &code->loc);
                if (n->sym->ts.type == BT_DERIVED && n->sym->ts.derived->attr.alloc_comp)
                  gfc_error ("COPYPRIVATE clause object '%s' at %L has ALLOCATABLE components",
                             n->sym->name, &code->loc);
@@ -856,9 +913,6 @@ resolve_omp_clauses (gfc_code *code)
                    if (n->sym->attr.pointer)
                      gfc_error ("POINTER object '%s' in %s clause at %L",
                                 n->sym->name, name, &code->loc);
-                   if (n->sym->attr.allocatable)
-                     gfc_error ("%s clause object '%s' is ALLOCATABLE at %L",
-                                name, n->sym->name, &code->loc);
                    /* Variables in REDUCTION-clauses must be of intrinsic type (flagged below).  */
                    if ((list < OMP_LIST_REDUCTION_FIRST || list > OMP_LIST_REDUCTION_LAST) &&
                        n->sym->ts.type == BT_DERIVED && n->sym->ts.derived->attr.alloc_comp)
@@ -1246,15 +1300,34 @@ struct omp_context
   struct pointer_set_t *private_iterators;
   struct omp_context *previous;
 } *omp_current_ctx;
-gfc_code *omp_current_do_code;
-
+static gfc_code *omp_current_do_code;
+static int omp_current_do_collapse;
 
 void
 gfc_resolve_omp_do_blocks (gfc_code *code, gfc_namespace *ns)
 {
   if (code->block->next && code->block->next->op == EXEC_DO)
-    omp_current_do_code = code->block->next;
+    {
+      int i;
+      gfc_code *c;
+
+      omp_current_do_code = code->block->next;
+      omp_current_do_collapse = code->ext.omp_clauses->collapse;
+      for (i = 1, c = omp_current_do_code; i < omp_current_do_collapse; i++)
+       {
+         c = c->block;
+         if (c->op != EXEC_DO || c->next == NULL)
+           break;
+         c = c->next;
+         if (c->op != EXEC_DO)
+           break;
+       }
+      if (i < omp_current_do_collapse || omp_current_do_collapse <= 0)
+       omp_current_do_collapse = 1;
+    }
   gfc_resolve_blocks (code->block, ns);
+  omp_current_do_collapse = 0;
+  omp_current_do_code = NULL;
 }
 
 
@@ -1294,6 +1367,8 @@ void
 gfc_resolve_do_iterator (gfc_code *code, gfc_symbol *sym)
 {
   struct omp_context *ctx;
+  int i = omp_current_do_collapse;
+  gfc_code *c = omp_current_do_code;
 
   if (sym->attr.threadprivate)
     return;
@@ -1301,8 +1376,14 @@ gfc_resolve_do_iterator (gfc_code *code, gfc_symbol *sym)
   /* !$omp do and !$omp parallel do iteration variable is predetermined
      private just in the !$omp do resp. !$omp parallel do construct,
      with no implications for the outer parallel constructs.  */
-  if (code == omp_current_do_code)
-    return;
+
+  while (i-- >= 1)
+    {
+      if (code == c)
+       return;
+
+      c = c->block->next;
+    }
 
   for (ctx = omp_current_ctx; ctx; ctx = ctx->previous)
     {
@@ -1326,8 +1407,8 @@ gfc_resolve_do_iterator (gfc_code *code, gfc_symbol *sym)
 static void
 resolve_omp_do (gfc_code *code)
 {
-  gfc_code *do_code;
-  int list;
+  gfc_code *do_code, *c;
+  int list, i, collapse;
   gfc_namelist *n;
   gfc_symbol *dovar;
 
@@ -1335,11 +1416,17 @@ resolve_omp_do (gfc_code *code)
     resolve_omp_clauses (code);
 
   do_code = code->block->next;
-  if (do_code->op == EXEC_DO_WHILE)
-    gfc_error ("!$OMP DO cannot be a DO WHILE or DO without loop control "
-              "at %L", &do_code->loc);
-  else
+  collapse = code->ext.omp_clauses->collapse;
+  if (collapse <= 0)
+    collapse = 1;
+  for (i = 1; i <= collapse; i++)
     {
+      if (do_code->op == EXEC_DO_WHILE)
+       {
+         gfc_error ("!$OMP DO cannot be a DO WHILE or DO without loop control "
+                    "at %L", &do_code->loc);
+         break;
+       }
       gcc_assert (do_code->op == EXEC_DO);
       if (do_code->ext.iterator->var->ts.type != BT_INTEGER)
        gfc_error ("!$OMP DO iteration variable must be of type integer at %L",
@@ -1359,6 +1446,53 @@ resolve_omp_do (gfc_code *code)
                             &do_code->loc);
                  break;
                }
+      if (i > 1)
+       {
+         gfc_code *do_code2 = code->block->next;
+         int j;
+
+         for (j = 1; j < i; j++)
+           {
+             gfc_symbol *ivar = do_code2->ext.iterator->var->symtree->n.sym;
+             if (dovar == ivar
+                 || gfc_find_sym_in_expr (ivar, do_code->ext.iterator->start)
+                 || gfc_find_sym_in_expr (ivar, do_code->ext.iterator->end)
+                 || gfc_find_sym_in_expr (ivar, do_code->ext.iterator->step))
+               {
+                 gfc_error ("!$OMP DO collapsed loops don't form rectangular iteration space at %L",
+                            &do_code->loc);
+                 break;
+               }
+             if (j < i)
+               break;
+             do_code2 = do_code2->block->next;
+           }
+       }
+      if (i == collapse)
+       break;
+      for (c = do_code->next; c; c = c->next)
+       if (c->op != EXEC_NOP && c->op != EXEC_CONTINUE)
+         {
+           gfc_error ("collapsed !$OMP DO loops not perfectly nested at %L",
+                      &c->loc);
+           break;
+         }
+      if (c)
+       break;
+      do_code = do_code->block;
+      if (do_code->op != EXEC_DO && do_code->op != EXEC_DO_WHILE)
+       {
+         gfc_error ("not enough DO loops for collapsed !$OMP DO at %L",
+                    &code->loc);
+         break;
+       }
+      do_code = do_code->next;
+      if (do_code->op != EXEC_DO && do_code->op != EXEC_DO_WHILE)
+       {
+         gfc_error ("not enough DO loops for collapsed !$OMP DO at %L",
+                    &code->loc);
+         break;
+       }
     }
 }
 
index 33f13c9..c35db2d 100644 (file)
@@ -515,6 +515,7 @@ decode_omp_directive (void)
       match ("end parallel", gfc_match_omp_eos, ST_OMP_END_PARALLEL);
       match ("end sections", gfc_match_omp_end_nowait, ST_OMP_END_SECTIONS);
       match ("end single", gfc_match_omp_end_single, ST_OMP_END_SINGLE);
+      match ("end task", gfc_match_omp_eos, ST_OMP_END_TASK);
       match ("end workshare", gfc_match_omp_end_nowait,
             ST_OMP_END_WORKSHARE);
       break;
@@ -541,6 +542,8 @@ decode_omp_directive (void)
       match ("single", gfc_match_omp_single, ST_OMP_SINGLE);
       break;
     case 't':
+      match ("task", gfc_match_omp_task, ST_OMP_TASK);
+      match ("taskwait", gfc_match_omp_taskwait, ST_OMP_TASKWAIT);
       match ("threadprivate", gfc_match_omp_threadprivate,
             ST_OMP_THREADPRIVATE);
     case 'w':
@@ -641,7 +644,7 @@ next_free (void)
          for (i = 0; i < 5; i++, c = gfc_next_ascii_char ())
            gcc_assert (c == "!$omp"[i]);
 
-         gcc_assert (c == ' ');
+         gcc_assert (c == ' ' || c == '\t');
          gfc_gobble_whitespace ();
          return decode_omp_directive ();
        }
@@ -870,7 +873,7 @@ next_statement (void)
   case ST_POINTER_ASSIGNMENT: case ST_EXIT: case ST_CYCLE: \
   case ST_ASSIGNMENT: case ST_ARITHMETIC_IF: case ST_WHERE: case ST_FORALL: \
   case ST_LABEL_ASSIGNMENT: case ST_FLUSH: case ST_OMP_FLUSH: \
-  case ST_OMP_BARRIER
+  case ST_OMP_BARRIER: case ST_OMP_TASKWAIT
 
 /* Statements that mark other executable statements.  */
 
@@ -879,7 +882,8 @@ next_statement (void)
   case ST_OMP_PARALLEL_SECTIONS: case ST_OMP_SECTIONS: case ST_OMP_ORDERED: \
   case ST_OMP_CRITICAL: case ST_OMP_MASTER: case ST_OMP_SINGLE: \
   case ST_OMP_DO: case ST_OMP_PARALLEL_DO: case ST_OMP_ATOMIC: \
-  case ST_OMP_WORKSHARE: case ST_OMP_PARALLEL_WORKSHARE
+  case ST_OMP_WORKSHARE: case ST_OMP_PARALLEL_WORKSHARE: \
+  case ST_OMP_TASK
 
 /* Declaration statements */
 
@@ -1351,6 +1355,9 @@ gfc_ascii_statement (gfc_statement st)
     case ST_OMP_END_SINGLE:
       p = "!$OMP END SINGLE";
       break;
+    case ST_OMP_END_TASK:
+      p = "!$OMP END TASK";
+      break;
     case ST_OMP_END_WORKSHARE:
       p = "!$OMP END WORKSHARE";
       break;
@@ -1384,6 +1391,12 @@ gfc_ascii_statement (gfc_statement st)
     case ST_OMP_SINGLE:
       p = "!$OMP SINGLE";
       break;
+    case ST_OMP_TASK:
+      p = "!$OMP TASK";
+      break;
+    case ST_OMP_TASKWAIT:
+      p = "!$OMP TASKWAIT";
+      break;
     case ST_OMP_THREADPRIVATE:
       p = "!$OMP THREADPRIVATE";
       break;
@@ -2857,6 +2870,9 @@ parse_omp_structured_block (gfc_statement omp_st, bool workshare_stmts_only)
     case ST_OMP_SINGLE:
       omp_end_st = ST_OMP_END_SINGLE;
       break;
+    case ST_OMP_TASK:
+      omp_end_st = ST_OMP_END_TASK;
+      break;
     case ST_OMP_WORKSHARE:
       omp_end_st = ST_OMP_END_WORKSHARE;
       break;
@@ -3067,6 +3083,7 @@ parse_executable (gfc_statement st)
        case ST_OMP_CRITICAL:
        case ST_OMP_MASTER:
        case ST_OMP_SINGLE:
+       case ST_OMP_TASK:
          parse_omp_structured_block (st, false);
          break;
 
index b5b76b6..2787e29 100644 (file)
@@ -4670,8 +4670,8 @@ sym_in_expr (gfc_expr *e, gfc_symbol *sym, int *f ATTRIBUTE_UNUSED)
   return false;
 }
 
-static bool
-find_sym_in_expr (gfc_symbol *sym, gfc_expr *e)
+bool
+gfc_find_sym_in_expr (gfc_symbol *sym, gfc_expr *e)
 {
   return gfc_traverse_expr (e, sym, sym_in_expr, 0);
 }
@@ -4868,8 +4868,10 @@ check_symbols:
          if (sym->ts.type == BT_DERIVED)
            continue;
 
-         if ((ar->start[i] != NULL && find_sym_in_expr (sym, ar->start[i]))
-                || (ar->end[i] != NULL && find_sym_in_expr (sym, ar->end[i])))
+         if ((ar->start[i] != NULL
+              && gfc_find_sym_in_expr (sym, ar->start[i]))
+             || (ar->end[i] != NULL
+                 && gfc_find_sym_in_expr (sym, ar->end[i])))
            {
              gfc_error ("'%s' must not appear an the array specification at "
                         "%L in the same ALLOCATE statement where it is "
@@ -5982,6 +5984,8 @@ gfc_resolve_blocks (gfc_code *b, gfc_namespace *ns)
        case EXEC_OMP_PARALLEL_WORKSHARE:
        case EXEC_OMP_SECTIONS:
        case EXEC_OMP_SINGLE:
+       case EXEC_OMP_TASK:
+       case EXEC_OMP_TASKWAIT:
        case EXEC_OMP_WORKSHARE:
          break;
 
@@ -6100,8 +6104,8 @@ resolve_ordinary_assign (gfc_code *code, gfc_namespace *ns)
          {
            for (n = 0; n < ref->u.ar.dimen; n++)
              if (ref->u.ar.dimen_type[n] == DIMEN_VECTOR
-                   && find_sym_in_expr (lhs->symtree->n.sym,
-                                        ref->u.ar.start[n]))
+                 && gfc_find_sym_in_expr (lhs->symtree->n.sym,
+                                          ref->u.ar.start[n]))
                ref->u.ar.start[n]
                        = gfc_get_parentheses (ref->u.ar.start[n]);
          }
@@ -6176,6 +6180,7 @@ resolve_code (gfc_code *code, gfc_namespace *ns)
            case EXEC_OMP_PARALLEL:
            case EXEC_OMP_PARALLEL_DO:
            case EXEC_OMP_PARALLEL_SECTIONS:
+           case EXEC_OMP_TASK:
              omp_workshare_save = omp_workshare_flag;
              omp_workshare_flag = 0;
              gfc_resolve_omp_parallel_blocks (code, ns);
@@ -6418,6 +6423,7 @@ resolve_code (gfc_code *code, gfc_namespace *ns)
        case EXEC_OMP_ORDERED:
        case EXEC_OMP_SECTIONS:
        case EXEC_OMP_SINGLE:
+       case EXEC_OMP_TASKWAIT:
        case EXEC_OMP_WORKSHARE:
          gfc_resolve_omp_directive (code, ns);
          break;
@@ -6426,6 +6432,7 @@ resolve_code (gfc_code *code, gfc_namespace *ns)
        case EXEC_OMP_PARALLEL_DO:
        case EXEC_OMP_PARALLEL_SECTIONS:
        case EXEC_OMP_PARALLEL_WORKSHARE:
+       case EXEC_OMP_TASK:
          omp_workshare_save = omp_workshare_flag;
          omp_workshare_flag = 0;
          gfc_resolve_omp_directive (code, ns);
index 02d87b4..1b0eeca 100644 (file)
@@ -702,7 +702,8 @@ skip_free_comments (void)
                      if (((c = next_char ()) == 'm' || c == 'M')
                          && ((c = next_char ()) == 'p' || c == 'P'))
                        {
-                         if ((c = next_char ()) == ' ' || continue_flag)
+                         if ((c = next_char ()) == ' ' || c == '\t'
+                             || continue_flag)
                            {
                              while (gfc_is_whitespace (c))
                                c = next_char ();
@@ -724,7 +725,7 @@ skip_free_comments (void)
                      next_char ();
                      c = next_char ();
                    }
-                 if (continue_flag || c == ' ')
+                 if (continue_flag || c == ' ' || c == '\t')
                    {
                      gfc_current_locus = old_loc;
                      next_char ();
@@ -820,11 +821,11 @@ skip_fixed_comments (void)
                          c = next_char ();
                          if (c != '\n'
                              && ((openmp_flag && continue_flag)
-                                 || c == ' ' || c == '0'))
+                                 || c == ' ' || c == '\t' || c == '0'))
                            {
-                             c = next_char ();
-                             while (gfc_is_whitespace (c))
+                             do
                                c = next_char ();
+                             while (gfc_is_whitespace (c));
                              if (c != '\n' && c != '!')
                                {
                                  /* Canonicalize to *$omp.  */
@@ -843,6 +844,11 @@ skip_fixed_comments (void)
                      for (col = 3; col < 6; col++, c = next_char ())
                        if (c == ' ')
                          continue;
+                       else if (c == '\t')
+                         {
+                           col = 6;
+                           break;
+                         }
                        else if (c < '0' || c > '9')
                          break;
                        else
@@ -850,7 +856,7 @@ skip_fixed_comments (void)
 
                      if (col == 6 && c != '\n'
                          && ((continue_flag && !digit_seen)
-                             || c == ' ' || c == '0'))
+                             || c == ' ' || c == '\t' || c == '0'))
                        {
                          gfc_current_locus = start;
                          start.nextc[0] = ' ';
index 0f0e481..abe7b94 100644 (file)
@@ -171,6 +171,7 @@ gfc_free_statement (gfc_code *p)
     case EXEC_OMP_PARALLEL_SECTIONS:
     case EXEC_OMP_SECTIONS:
     case EXEC_OMP_SINGLE:
+    case EXEC_OMP_TASK:
     case EXEC_OMP_WORKSHARE:
     case EXEC_OMP_PARALLEL_WORKSHARE:
       gfc_free_omp_clauses (p->ext.omp_clauses);
@@ -189,6 +190,7 @@ gfc_free_statement (gfc_code *p)
     case EXEC_OMP_MASTER:
     case EXEC_OMP_ORDERED:
     case EXEC_OMP_END_NOWAIT:
+    case EXEC_OMP_TASKWAIT:
       break;
 
     default:
index c6c4bae..6f99800 100644 (file)
@@ -84,6 +84,17 @@ gfc_omp_predetermined_sharing (tree decl)
   if (GFC_DECL_CRAY_POINTEE (decl))
     return OMP_CLAUSE_DEFAULT_PRIVATE;
 
+  /* Assumed-size arrays are predetermined to inherit sharing
+     attributes of the associated actual argument, which is shared
+     for all we care.  */
+  if (TREE_CODE (decl) == PARM_DECL
+      && GFC_ARRAY_TYPE_P (TREE_TYPE (decl))
+      && GFC_TYPE_ARRAY_AKIND (TREE_TYPE (decl)) == GFC_ARRAY_UNKNOWN
+      && GFC_TYPE_ARRAY_UBOUND (TREE_TYPE (decl),
+                               GFC_TYPE_ARRAY_RANK (TREE_TYPE (decl)) - 1)
+        == NULL)
+    return OMP_CLAUSE_DEFAULT_SHARED;
+
   /* COMMON and EQUIVALENCE decls are shared.  They
      are only referenced through DECL_VALUE_EXPR of the variables
      contained in them.  If those are privatized, they will not be
@@ -98,27 +109,179 @@ gfc_omp_predetermined_sharing (tree decl)
 }
 
 
+/* Return true if DECL in private clause needs
+   OMP_CLAUSE_PRIVATE_OUTER_REF on the private clause.  */
+bool
+gfc_omp_private_outer_ref (tree decl)
+{
+  tree type = TREE_TYPE (decl);
+
+  if (GFC_DESCRIPTOR_TYPE_P (type)
+      && GFC_TYPE_ARRAY_AKIND (type) == GFC_ARRAY_ALLOCATABLE)
+    return true;
+
+  return false;
+}
+
 /* Return code to initialize DECL with its default constructor, or
    NULL if there's nothing to do.  */
 
 tree
-gfc_omp_clause_default_ctor (tree clause ATTRIBUTE_UNUSED, tree decl)
+gfc_omp_clause_default_ctor (tree clause, tree decl, tree outer)
 {
-  tree type = TREE_TYPE (decl);
-  stmtblock_t block;
+  tree type = TREE_TYPE (decl), rank, size, esize, ptr, cond, then_b, else_b;
+  stmtblock_t block, cond_block;
 
-  if (! GFC_DESCRIPTOR_TYPE_P (type))
+  if (! GFC_DESCRIPTOR_TYPE_P (type)
+      || GFC_TYPE_ARRAY_AKIND (type) != GFC_ARRAY_ALLOCATABLE)
     return NULL;
 
+  gcc_assert (outer != NULL);
+  gcc_assert (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_PRIVATE
+             || OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_LASTPRIVATE);
+
   /* Allocatable arrays in PRIVATE clauses need to be set to
-     "not currently allocated" allocation status.  */
-  gfc_init_block (&block);
+     "not currently allocated" allocation status if outer
+     array is "not currently allocated", otherwise should be allocated.  */
+  gfc_start_block (&block);
+
+  gfc_init_block (&cond_block);
+
+  gfc_add_modify_expr (&cond_block, decl, outer);
+  rank = gfc_rank_cst[GFC_TYPE_ARRAY_RANK (type) - 1];
+  size = gfc_conv_descriptor_ubound (decl, rank);
+  size = fold_build2 (MINUS_EXPR, gfc_array_index_type, size,
+                     gfc_conv_descriptor_lbound (decl, rank));
+  size = fold_build2 (PLUS_EXPR, gfc_array_index_type, size,
+                     gfc_index_one_node);
+  if (GFC_TYPE_ARRAY_RANK (type) > 1)
+    size = fold_build2 (MULT_EXPR, gfc_array_index_type, size,
+                       gfc_conv_descriptor_stride (decl, rank));
+  esize = fold_convert (gfc_array_index_type,
+                       TYPE_SIZE_UNIT (gfc_get_element_type (type)));
+  size = fold_build2 (MULT_EXPR, gfc_array_index_type, size, esize);
+  size = gfc_evaluate_now (fold_convert (size_type_node, size), &cond_block);
+  ptr = gfc_allocate_array_with_status (&cond_block,
+                                       build_int_cst (pvoid_type_node, 0),
+                                       size, NULL);
+  gfc_conv_descriptor_data_set_tuples (&cond_block, decl, ptr);
+  then_b = gfc_finish_block (&cond_block);
+
+  gfc_init_block (&cond_block);
+  gfc_conv_descriptor_data_set_tuples (&cond_block, decl, null_pointer_node);
+  else_b = gfc_finish_block (&cond_block);
+
+  cond = fold_build2 (NE_EXPR, boolean_type_node,
+                     fold_convert (pvoid_type_node,
+                                   gfc_conv_descriptor_data_get (outer)),
+                     null_pointer_node);
+  gfc_add_expr_to_block (&block, build3 (COND_EXPR, void_type_node,
+                        cond, then_b, else_b));
 
-  gfc_conv_descriptor_data_set_tuples (&block, decl, null_pointer_node);
+  return gfc_finish_block (&block);
+}
+
+/* Build and return code for a copy constructor from SRC to DEST.  */
+
+tree
+gfc_omp_clause_copy_ctor (tree clause, tree dest, tree src)
+{
+  tree type = TREE_TYPE (dest), ptr, size, esize, rank, call;
+  stmtblock_t block;
+
+  if (! GFC_DESCRIPTOR_TYPE_P (type)
+      || GFC_TYPE_ARRAY_AKIND (type) != GFC_ARRAY_ALLOCATABLE)
+    return build_gimple_modify_stmt (dest, src);
+
+  gcc_assert (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_FIRSTPRIVATE);
+
+  /* Allocatable arrays in FIRSTPRIVATE clauses need to be allocated
+     and copied from SRC.  */
+  gfc_start_block (&block);
+
+  gfc_add_modify_expr (&block, dest, src);
+  rank = gfc_rank_cst[GFC_TYPE_ARRAY_RANK (type) - 1];
+  size = gfc_conv_descriptor_ubound (dest, rank);
+  size = fold_build2 (MINUS_EXPR, gfc_array_index_type, size,
+                     gfc_conv_descriptor_lbound (dest, rank));
+  size = fold_build2 (PLUS_EXPR, gfc_array_index_type, size,
+                     gfc_index_one_node);
+  if (GFC_TYPE_ARRAY_RANK (type) > 1)
+    size = fold_build2 (MULT_EXPR, gfc_array_index_type, size,
+                       gfc_conv_descriptor_stride (dest, rank));
+  esize = fold_convert (gfc_array_index_type,
+                       TYPE_SIZE_UNIT (gfc_get_element_type (type)));
+  size = fold_build2 (MULT_EXPR, gfc_array_index_type, size, esize);
+  size = gfc_evaluate_now (fold_convert (size_type_node, size), &block);
+  ptr = gfc_allocate_array_with_status (&block,
+                                       build_int_cst (pvoid_type_node, 0),
+                                       size, NULL);
+  gfc_conv_descriptor_data_set_tuples (&block, dest, ptr);
+  call = build_call_expr (built_in_decls[BUILT_IN_MEMCPY], 3, ptr,
+                         fold_convert (pvoid_type_node,
+                                       gfc_conv_descriptor_data_get (src)),
+                         size);
+  gfc_add_expr_to_block (&block, fold_convert (void_type_node, call));
 
   return gfc_finish_block (&block);
 }
 
+/* Similarly, except use an assignment operator instead.  */
+
+tree
+gfc_omp_clause_assign_op (tree clause ATTRIBUTE_UNUSED, tree dest, tree src)
+{
+  tree type = TREE_TYPE (dest), rank, size, esize, call;
+  stmtblock_t block;
+
+  if (! GFC_DESCRIPTOR_TYPE_P (type)
+      || GFC_TYPE_ARRAY_AKIND (type) != GFC_ARRAY_ALLOCATABLE)
+    return build_gimple_modify_stmt (dest, src);
+
+  /* Handle copying allocatable arrays.  */
+  gfc_start_block (&block);
+
+  rank = gfc_rank_cst[GFC_TYPE_ARRAY_RANK (type) - 1];
+  size = gfc_conv_descriptor_ubound (dest, rank);
+  size = fold_build2 (MINUS_EXPR, gfc_array_index_type, size,
+                     gfc_conv_descriptor_lbound (dest, rank));
+  size = fold_build2 (PLUS_EXPR, gfc_array_index_type, size,
+                     gfc_index_one_node);
+  if (GFC_TYPE_ARRAY_RANK (type) > 1)
+    size = fold_build2 (MULT_EXPR, gfc_array_index_type, size,
+                       gfc_conv_descriptor_stride (dest, rank));
+  esize = fold_convert (gfc_array_index_type,
+                       TYPE_SIZE_UNIT (gfc_get_element_type (type)));
+  size = fold_build2 (MULT_EXPR, gfc_array_index_type, size, esize);
+  size = gfc_evaluate_now (fold_convert (size_type_node, size), &block);
+  call = build_call_expr (built_in_decls[BUILT_IN_MEMCPY], 3,
+                         fold_convert (pvoid_type_node,
+                                       gfc_conv_descriptor_data_get (dest)),
+                         fold_convert (pvoid_type_node,
+                                       gfc_conv_descriptor_data_get (src)),
+                         size);
+  gfc_add_expr_to_block (&block, fold_convert (void_type_node, call));
+
+  return gfc_finish_block (&block);
+}
+
+/* Build and return code destructing DECL.  Return NULL if nothing
+   to be done.  */
+
+tree
+gfc_omp_clause_dtor (tree clause ATTRIBUTE_UNUSED, tree decl)
+{
+  tree type = TREE_TYPE (decl);
+
+  if (! GFC_DESCRIPTOR_TYPE_P (type)
+      || GFC_TYPE_ARRAY_AKIND (type) != GFC_ARRAY_ALLOCATABLE)
+    return NULL;
+
+  /* Allocatable arrays in FIRSTPRIVATE/LASTPRIVATE etc. clauses need
+     to be deallocated if they were allocated.  */
+  return gfc_trans_dealloc_allocated (decl);
+}
+
 
 /* Return true if DECL's DECL_VALUE_EXPR (if any) should be
    disregarded in OpenMP construct, because it is going to be
@@ -429,7 +592,39 @@ gfc_trans_omp_array_reduction (tree c, gfc_symbol *sym, locus where)
 
   /* Create the init statement list.  */
   pushlevel (0);
-  stmt = gfc_trans_assignment (e1, e2, false);
+  if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (decl))
+      && GFC_TYPE_ARRAY_AKIND (TREE_TYPE (decl)) == GFC_ARRAY_ALLOCATABLE)
+    {
+      /* If decl is an allocatable array, it needs to be allocated
+        with the same bounds as the outer var.  */
+      tree type = TREE_TYPE (decl), rank, size, esize, ptr;
+      stmtblock_t block;
+
+      gfc_start_block (&block);
+
+      gfc_add_modify_expr (&block, decl, outer_sym.backend_decl);
+      rank = gfc_rank_cst[GFC_TYPE_ARRAY_RANK (type) - 1];
+      size = gfc_conv_descriptor_ubound (decl, rank);
+      size = fold_build2 (MINUS_EXPR, gfc_array_index_type, size,
+                         gfc_conv_descriptor_lbound (decl, rank));
+      size = fold_build2 (PLUS_EXPR, gfc_array_index_type, size,
+                         gfc_index_one_node);
+      if (GFC_TYPE_ARRAY_RANK (type) > 1)
+       size = fold_build2 (MULT_EXPR, gfc_array_index_type, size,
+                           gfc_conv_descriptor_stride (decl, rank));
+      esize = fold_convert (gfc_array_index_type,
+                           TYPE_SIZE_UNIT (gfc_get_element_type (type)));
+      size = fold_build2 (MULT_EXPR, gfc_array_index_type, size, esize);
+      size = gfc_evaluate_now (fold_convert (size_type_node, size), &block);
+      ptr = gfc_allocate_array_with_status (&block,
+                                           build_int_cst (pvoid_type_node, 0),
+                                           size, NULL);
+      gfc_conv_descriptor_data_set_tuples (&block, decl, ptr);
+      gfc_add_expr_to_block (&block, gfc_trans_assignment (e1, e2, false));
+      stmt = gfc_finish_block (&block);
+    }
+  else
+    stmt = gfc_trans_assignment (e1, e2, false);
   if (TREE_CODE (stmt) != BIND_EXPR)
     stmt = build3_v (BIND_EXPR, NULL, stmt, poplevel (1, 0, 0));
   else
@@ -438,7 +633,20 @@ gfc_trans_omp_array_reduction (tree c, gfc_symbol *sym, locus where)
 
   /* Create the merge statement list.  */
   pushlevel (0);
-  stmt = gfc_trans_assignment (e3, e4, false);
+  if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (decl))
+      && GFC_TYPE_ARRAY_AKIND (TREE_TYPE (decl)) == GFC_ARRAY_ALLOCATABLE)
+    {
+      /* If decl is an allocatable array, it needs to be deallocated
+        afterwards.  */
+      stmtblock_t block;
+
+      gfc_start_block (&block);
+      gfc_add_expr_to_block (&block, gfc_trans_assignment (e3, e4, false));
+      gfc_add_expr_to_block (&block, gfc_trans_dealloc_allocated (decl));
+      stmt = gfc_finish_block (&block);
+    }
+  else
+    stmt = gfc_trans_assignment (e3, e4, false);
   if (TREE_CODE (stmt) != BIND_EXPR)
     stmt = build3_v (BIND_EXPR, NULL, stmt, poplevel (1, 0, 0));
   else
@@ -639,6 +847,9 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
        case OMP_SCHED_RUNTIME:
          OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_RUNTIME;
          break;
+       case OMP_SCHED_AUTO:
+         OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_AUTO;
+         break;
        default:
          gcc_unreachable ();
        }
@@ -659,6 +870,9 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
        case OMP_DEFAULT_PRIVATE:
          OMP_CLAUSE_DEFAULT_KIND (c) = OMP_CLAUSE_DEFAULT_PRIVATE;
          break;
+       case OMP_DEFAULT_FIRSTPRIVATE:
+         OMP_CLAUSE_DEFAULT_KIND (c) = OMP_CLAUSE_DEFAULT_FIRSTPRIVATE;
+         break;
        default:
          gcc_unreachable ();
        }
@@ -677,6 +891,19 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
       omp_clauses = gfc_trans_add_clause (c, omp_clauses);
     }
 
+  if (clauses->untied)
+    {
+      c = build_omp_clause (OMP_CLAUSE_UNTIED);
+      omp_clauses = gfc_trans_add_clause (c, omp_clauses);
+    }
+
+  if (clauses->collapse)
+    {
+      c = build_omp_clause (OMP_CLAUSE_COLLAPSE);
+      OMP_CLAUSE_COLLAPSE_EXPR (c) = build_int_cst (NULL, clauses->collapse);
+      omp_clauses = gfc_trans_add_clause (c, omp_clauses);
+    }
+
   return omp_clauses;
 }
 
@@ -893,20 +1120,28 @@ gfc_trans_omp_critical (gfc_code *code)
 
 static tree
 gfc_trans_omp_do (gfc_code *code, stmtblock_t *pblock,
-                 gfc_omp_clauses *do_clauses)
+                 gfc_omp_clauses *do_clauses, tree par_clauses)
 {
   gfc_se se;
   tree dovar, stmt, from, to, step, type, init, cond, incr;
   tree count = NULL_TREE, cycle_label, tmp, omp_clauses;
   stmtblock_t block;
   stmtblock_t body;
-  int simple = 0;
-  bool dovar_found = false;
   gfc_omp_clauses *clauses = code->ext.omp_clauses;
+  gfc_code *outermost;
+  int i, collapse = clauses->collapse;
+  tree dovar_init = NULL_TREE;
 
-  code = code->block->next;
+  if (collapse <= 0)
+    collapse = 1;
+
+  outermost = code = code->block->next;
   gcc_assert (code->op == EXEC_DO);
 
+  init = make_tree_vec (collapse);
+  cond = make_tree_vec (collapse);
+  incr = make_tree_vec (collapse);
+
   if (pblock == NULL)
     {
       gfc_start_block (&block);
@@ -914,107 +1149,168 @@ gfc_trans_omp_do (gfc_code *code, stmtblock_t *pblock,
     }
 
   omp_clauses = gfc_trans_omp_clauses (pblock, do_clauses, code->loc);
-  if (clauses)
-    {
-      gfc_namelist *n;
-      for (n = clauses->lists[OMP_LIST_LASTPRIVATE]; n != NULL; n = n->next)
-       if (code->ext.iterator->var->symtree->n.sym == n->sym)
-         break;
-      if (n == NULL)
-       for (n = clauses->lists[OMP_LIST_PRIVATE]; n != NULL; n = n->next)
-         if (code->ext.iterator->var->symtree->n.sym == n->sym)
-           break;
-      if (n != NULL)
-       dovar_found = true;
-    }
 
-  /* Evaluate all the expressions in the iterator.  */
-  gfc_init_se (&se, NULL);
-  gfc_conv_expr_lhs (&se, code->ext.iterator->var);
-  gfc_add_block_to_block (pblock, &se.pre);
-  dovar = se.expr;
-  type = TREE_TYPE (dovar);
-  gcc_assert (TREE_CODE (type) == INTEGER_TYPE);
-
-  gfc_init_se (&se, NULL);
-  gfc_conv_expr_val (&se, code->ext.iterator->start);
-  gfc_add_block_to_block (pblock, &se.pre);
-  from = gfc_evaluate_now (se.expr, pblock);
-
-  gfc_init_se (&se, NULL);
-  gfc_conv_expr_val (&se, code->ext.iterator->end);
-  gfc_add_block_to_block (pblock, &se.pre);
-  to = gfc_evaluate_now (se.expr, pblock);
-
-  gfc_init_se (&se, NULL);
-  gfc_conv_expr_val (&se, code->ext.iterator->step);
-  gfc_add_block_to_block (pblock, &se.pre);
-  step = gfc_evaluate_now (se.expr, pblock);
-
-  /* Special case simple loops.  */
-  if (integer_onep (step))
-    simple = 1;
-  else if (tree_int_cst_equal (step, integer_minus_one_node))
-    simple = -1;
-
-  /* Loop body.  */
-  if (simple)
+  for (i = 0; i < collapse; i++)
     {
-      init = build2_v (GIMPLE_MODIFY_STMT, dovar, from);
-      cond = fold_build2 (simple > 0 ? LE_EXPR : GE_EXPR, boolean_type_node,
-                         dovar, to);
-      incr = fold_build2 (PLUS_EXPR, type, dovar, step);
-      incr = fold_build2 (GIMPLE_MODIFY_STMT, type, dovar, incr);
-      if (pblock != &block)
+      int simple = 0;
+      int dovar_found = 0;
+
+      if (clauses)
        {
-         pushlevel (0);
-         gfc_start_block (&block);
+         gfc_namelist *n;
+         for (n = clauses->lists[OMP_LIST_LASTPRIVATE]; n != NULL;
+              n = n->next)
+           if (code->ext.iterator->var->symtree->n.sym == n->sym)
+             break;
+         if (n != NULL)
+           dovar_found = 1;
+         else if (n == NULL)
+           for (n = clauses->lists[OMP_LIST_PRIVATE]; n != NULL; n = n->next)
+             if (code->ext.iterator->var->symtree->n.sym == n->sym)
+               break;
+         if (n != NULL)
+           dovar_found++;
        }
-      gfc_start_block (&body);
-    }
-  else
-    {
-      /* STEP is not 1 or -1.  Use:
-        for (count = 0; count < (to + step - from) / step; count++)
-          {
-            dovar = from + count * step;
-            body;
-          cycle_label:;
-          }  */
-      tmp = fold_build2 (MINUS_EXPR, type, step, from);
-      tmp = fold_build2 (PLUS_EXPR, type, to, tmp);
-      tmp = fold_build2 (TRUNC_DIV_EXPR, type, tmp, step);
-      tmp = gfc_evaluate_now (tmp, pblock);
-      count = gfc_create_var (type, "count");
-      init = build2_v (GIMPLE_MODIFY_STMT, count, build_int_cst (type, 0));
-      cond = fold_build2 (LT_EXPR, boolean_type_node, count, tmp);
-      incr = fold_build2 (PLUS_EXPR, type, count, build_int_cst (type, 1));
-      incr = fold_build2 (GIMPLE_MODIFY_STMT, type, count, incr);
-
-      if (pblock != &block)
+
+      /* Evaluate all the expressions in the iterator.  */
+      gfc_init_se (&se, NULL);
+      gfc_conv_expr_lhs (&se, code->ext.iterator->var);
+      gfc_add_block_to_block (pblock, &se.pre);
+      dovar = se.expr;
+      type = TREE_TYPE (dovar);
+      gcc_assert (TREE_CODE (type) == INTEGER_TYPE);
+
+      gfc_init_se (&se, NULL);
+      gfc_conv_expr_val (&se, code->ext.iterator->start);
+      gfc_add_block_to_block (pblock, &se.pre);
+      from = gfc_evaluate_now (se.expr, pblock);
+
+      gfc_init_se (&se, NULL);
+      gfc_conv_expr_val (&se, code->ext.iterator->end);
+      gfc_add_block_to_block (pblock, &se.pre);
+      to = gfc_evaluate_now (se.expr, pblock);
+
+      gfc_init_se (&se, NULL);
+      gfc_conv_expr_val (&se, code->ext.iterator->step);
+      gfc_add_block_to_block (pblock, &se.pre);
+      step = gfc_evaluate_now (se.expr, pblock);
+
+      /* Special case simple loops.  */
+      if (integer_onep (step))
+       simple = 1;
+      else if (tree_int_cst_equal (step, integer_minus_one_node))
+       simple = -1;
+
+      /* Loop body.  */
+      if (simple)
        {
-         pushlevel (0);
-         gfc_start_block (&block);
+         TREE_VEC_ELT (init, i) = build2_v (GIMPLE_MODIFY_STMT, dovar, from);
+         TREE_VEC_ELT (cond, i) = fold_build2 (simple > 0 ? LE_EXPR : GE_EXPR,
+                                               boolean_type_node, dovar, to);
+         TREE_VEC_ELT (incr, i) = fold_build2 (PLUS_EXPR, type, dovar, step);
+         TREE_VEC_ELT (incr, i) = fold_build2 (GIMPLE_MODIFY_STMT, type, dovar,
+                                               TREE_VEC_ELT (incr, i));
+       }
+      else
+       {
+         /* STEP is not 1 or -1.  Use:
+            for (count = 0; count < (to + step - from) / step; count++)
+              {
+                dovar = from + count * step;
+                body;
+              cycle_label:;
+              }  */
+         tmp = fold_build2 (MINUS_EXPR, type, step, from);
+         tmp = fold_build2 (PLUS_EXPR, type, to, tmp);
+         tmp = fold_build2 (TRUNC_DIV_EXPR, type, tmp, step);
+         tmp = gfc_evaluate_now (tmp, pblock);
+         count = gfc_create_var (type, "count");
+         TREE_VEC_ELT (init, i) = build2_v (GIMPLE_MODIFY_STMT, count,
+                                            build_int_cst (type, 0));
+         TREE_VEC_ELT (cond, i) = fold_build2 (LT_EXPR, boolean_type_node,
+                                               count, tmp);
+         TREE_VEC_ELT (incr, i) = fold_build2 (PLUS_EXPR, type, count,
+                                               build_int_cst (type, 1));
+         TREE_VEC_ELT (incr, i) = fold_build2 (GIMPLE_MODIFY_STMT, type,
+                                               count, TREE_VEC_ELT (incr, i));
+
+         /* Initialize DOVAR.  */
+         tmp = fold_build2 (MULT_EXPR, type, count, step);
+         tmp = fold_build2 (PLUS_EXPR, type, from, tmp);
+         dovar_init = tree_cons (dovar, tmp, dovar_init);
        }
-      gfc_start_block (&body);
 
-      /* Initialize DOVAR.  */
-      tmp = fold_build2 (MULT_EXPR, type, count, step);
-      tmp = fold_build2 (PLUS_EXPR, type, from, tmp);
-      gfc_add_modify_stmt (&body, dovar, tmp);
+      if (!dovar_found)
+       {
+         tmp = build_omp_clause (OMP_CLAUSE_PRIVATE);
+         OMP_CLAUSE_DECL (tmp) = dovar;
+         omp_clauses = gfc_trans_add_clause (tmp, omp_clauses);
+       }
+      else if (dovar_found == 2)
+       {
+         tree c = NULL;
+
+         tmp = NULL;
+         if (!simple)
+           {
+             /* If dovar is lastprivate, but different counter is used,
+                dovar += step needs to be added to
+                OMP_CLAUSE_LASTPRIVATE_STMT, otherwise the copied dovar
+                will have the value on entry of the last loop, rather
+                than value after iterator increment.  */
+             tmp = gfc_evaluate_now (step, pblock);
+             tmp = fold_build2 (PLUS_EXPR, type, dovar, tmp);
+             tmp = fold_build2 (GIMPLE_MODIFY_STMT, type, dovar, tmp);
+             for (c = omp_clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+               if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
+                   && OMP_CLAUSE_DECL (c) == dovar)
+                 {
+                   OMP_CLAUSE_LASTPRIVATE_STMT (c) = tmp;
+                   break;
+                 }
+           }
+         if (c == NULL && par_clauses != NULL)
+           {
+             for (c = par_clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+               if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
+                   && OMP_CLAUSE_DECL (c) == dovar)
+                 {
+                   tree l = build_omp_clause (OMP_CLAUSE_LASTPRIVATE);
+                   OMP_CLAUSE_DECL (l) = dovar;
+                   OMP_CLAUSE_CHAIN (l) = omp_clauses;
+                   OMP_CLAUSE_LASTPRIVATE_STMT (l) = tmp;
+                   omp_clauses = l;
+                   OMP_CLAUSE_SET_CODE (c, OMP_CLAUSE_SHARED);
+                   break;
+                 }
+           }
+         gcc_assert (simple || c != NULL);
+       }
+      if (!simple)
+       {
+         tmp = build_omp_clause (OMP_CLAUSE_PRIVATE);
+         OMP_CLAUSE_DECL (tmp) = count;
+         omp_clauses = gfc_trans_add_clause (tmp, omp_clauses);
+       }
+
+      if (i + 1 < collapse)
+       code = code->block->next;
     }
 
-  if (!dovar_found)
+  if (pblock != &block)
     {
-      tmp = build_omp_clause (OMP_CLAUSE_PRIVATE);
-      OMP_CLAUSE_DECL (tmp) = dovar;
-      omp_clauses = gfc_trans_add_clause (tmp, omp_clauses);
+      pushlevel (0);
+      gfc_start_block (&block);
     }
-  if (!simple)
+
+  gfc_start_block (&body);
+
+  dovar_init = nreverse (dovar_init);
+  while (dovar_init)
     {
-      tmp = build_omp_clause (OMP_CLAUSE_PRIVATE);
-      OMP_CLAUSE_DECL (tmp) = count;
-      omp_clauses = gfc_trans_add_clause (tmp, omp_clauses);
+      gfc_add_modify_stmt (&body, TREE_PURPOSE (dovar_init),
+                          TREE_VALUE (dovar_init));
+      dovar_init = TREE_CHAIN (dovar_init);
     }
 
   /* Cycle statement is implemented with a goto.  Exit statement must not be
@@ -1107,9 +1403,11 @@ gfc_trans_omp_parallel_do (gfc_code *code)
       do_clauses.sched_kind = parallel_clauses.sched_kind;
       do_clauses.chunk_size = parallel_clauses.chunk_size;
       do_clauses.ordered = parallel_clauses.ordered;
+      do_clauses.collapse = parallel_clauses.collapse;
       parallel_clauses.sched_kind = OMP_SCHED_NONE;
       parallel_clauses.chunk_size = NULL;
       parallel_clauses.ordered = false;
+      parallel_clauses.collapse = 0;
       omp_clauses = gfc_trans_omp_clauses (&block, &parallel_clauses,
                                           code->loc);
     }
@@ -1118,7 +1416,7 @@ gfc_trans_omp_parallel_do (gfc_code *code)
     pblock = &block;
   else
     pushlevel (0);
-  stmt = gfc_trans_omp_do (code, pblock, &do_clauses);
+  stmt = gfc_trans_omp_do (code, pblock, &do_clauses, omp_clauses);
   if (TREE_CODE (stmt) != BIND_EXPR)
     stmt = build3_v (BIND_EXPR, NULL, stmt, poplevel (1, 0, 0));
   else
@@ -1221,6 +1519,31 @@ gfc_trans_omp_single (gfc_code *code, gfc_omp_clauses *clauses)
 }
 
 static tree
+gfc_trans_omp_task (gfc_code *code)
+{
+  stmtblock_t block;
+  tree stmt, body_stmt, omp_clauses;
+
+  gfc_start_block (&block);
+  omp_clauses = gfc_trans_omp_clauses (&block, code->ext.omp_clauses,
+                                      code->loc);
+  body_stmt = gfc_trans_omp_code (code->block->next, true);
+  stmt = make_node (OMP_TASK);
+  TREE_TYPE (stmt) = void_type_node;
+  OMP_TASK_CLAUSES (stmt) = omp_clauses;
+  OMP_TASK_BODY (stmt) = body_stmt;
+  gfc_add_expr_to_block (&block, stmt);
+  return gfc_finish_block (&block);
+}
+
+static tree
+gfc_trans_omp_taskwait (void)
+{
+  tree decl = built_in_decls [BUILT_IN_GOMP_TASKWAIT];
+  return build_call_expr (decl, 0);
+}
+
+static tree
 gfc_trans_omp_workshare (gfc_code *code, gfc_omp_clauses *clauses)
 {
   /* XXX */
@@ -1239,7 +1562,7 @@ gfc_trans_omp_directive (gfc_code *code)
     case EXEC_OMP_CRITICAL:
       return gfc_trans_omp_critical (code);
     case EXEC_OMP_DO:
-      return gfc_trans_omp_do (code, NULL, code->ext.omp_clauses);
+      return gfc_trans_omp_do (code, NULL, code->ext.omp_clauses, NULL);
     case EXEC_OMP_FLUSH:
       return gfc_trans_omp_flush ();
     case EXEC_OMP_MASTER:
@@ -1258,6 +1581,10 @@ gfc_trans_omp_directive (gfc_code *code)
       return gfc_trans_omp_sections (code, code->ext.omp_clauses);
     case EXEC_OMP_SINGLE:
       return gfc_trans_omp_single (code, code->ext.omp_clauses);
+    case EXEC_OMP_TASK:
+      return gfc_trans_omp_task (code);
+    case EXEC_OMP_TASKWAIT:
+      return gfc_trans_omp_taskwait ();
     case EXEC_OMP_WORKSHARE:
       return gfc_trans_omp_workshare (code, code->ext.omp_clauses);
     default:
index f303128..51e0cdd 100644 (file)
@@ -1135,6 +1135,8 @@ gfc_trans_code (gfc_code * code)
        case EXEC_OMP_PARALLEL_WORKSHARE:
        case EXEC_OMP_SECTIONS:
        case EXEC_OMP_SINGLE:
+       case EXEC_OMP_TASK:
+       case EXEC_OMP_TASKWAIT:
        case EXEC_OMP_WORKSHARE:
          res = gfc_trans_omp_directive (code);
          break;
index d0ce235..3a07d71 100644 (file)
@@ -493,9 +493,13 @@ bool gfc_get_array_descr_info (const_tree, struct array_descr_info *);
 /* In trans-openmp.c */
 bool gfc_omp_privatize_by_reference (const_tree);
 enum omp_clause_default_kind gfc_omp_predetermined_sharing (tree);
-tree gfc_omp_clause_default_ctor (tree, tree);
+tree gfc_omp_clause_default_ctor (tree, tree, tree);
+tree gfc_omp_clause_copy_ctor (tree, tree, tree);
+tree gfc_omp_clause_assign_op (tree, tree, tree);
+tree gfc_omp_clause_dtor (tree, tree);
 bool gfc_omp_disregard_value_expr (tree, bool);
 bool gfc_omp_private_debug_clause (tree, bool);
+bool gfc_omp_private_outer_ref (tree);
 struct gimplify_omp_ctx;
 void gfc_omp_firstprivatize_type_sizes (struct gimplify_omp_ctx *, tree);
 
index 22dcafd..5bcdb52 100644 (file)
@@ -50,10 +50,12 @@ along with GCC; see the file COPYING3.  If not see
     the type pointed to.  */
 
 DEF_PRIMITIVE_TYPE (BT_VOID, void_type_node)
-DEF_PRIMITIVE_TYPE (BT_BOOL, boolean_type_node)
+DEF_PRIMITIVE_TYPE (BT_BOOL,
+                   (*lang_hooks.types.type_for_size) (BOOL_TYPE_SIZE, 1))
 DEF_PRIMITIVE_TYPE (BT_INT, integer_type_node)
 DEF_PRIMITIVE_TYPE (BT_UINT, unsigned_type_node)
 DEF_PRIMITIVE_TYPE (BT_LONG, long_integer_type_node)
+DEF_PRIMITIVE_TYPE (BT_ULONGLONG, long_long_unsigned_type_node)
 DEF_PRIMITIVE_TYPE (BT_WORD, (*lang_hooks.types.type_for_mode) (word_mode, 1))
 
 DEF_PRIMITIVE_TYPE (BT_I1, builtin_type_for_size (BITS_PER_UNIT*1, 1))
@@ -70,6 +72,7 @@ DEF_PRIMITIVE_TYPE (BT_VOLATILE_PTR,
                                             TYPE_QUAL_VOLATILE)))
 
 DEF_POINTER_TYPE (BT_PTR_LONG, BT_LONG)
+DEF_POINTER_TYPE (BT_PTR_ULONGLONG, BT_ULONGLONG)
 DEF_POINTER_TYPE (BT_PTR_PTR, BT_PTR)
 DEF_FUNCTION_TYPE_0 (BT_FN_BOOL, BT_BOOL)
 DEF_FUNCTION_TYPE_0 (BT_FN_PTR, BT_PTR)
@@ -87,11 +90,16 @@ DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR, BT_FN_VOID_PTR)
 
 DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_LONGPTR_LONGPTR,
                      BT_BOOL, BT_PTR_LONG, BT_PTR_LONG)
+DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_ULONGLONGPTR_ULONGLONGPTR,
+                    BT_BOOL, BT_PTR_ULONGLONG, BT_PTR_ULONGLONG)
 DEF_FUNCTION_TYPE_2 (BT_FN_I1_VPTR_I1, BT_I1, BT_VOLATILE_PTR, BT_I1)
 DEF_FUNCTION_TYPE_2 (BT_FN_I2_VPTR_I2, BT_I2, BT_VOLATILE_PTR, BT_I2)
 DEF_FUNCTION_TYPE_2 (BT_FN_I4_VPTR_I4, BT_I4, BT_VOLATILE_PTR, BT_I4)
 DEF_FUNCTION_TYPE_2 (BT_FN_I8_VPTR_I8, BT_I8, BT_VOLATILE_PTR, BT_I8)
 DEF_FUNCTION_TYPE_2 (BT_FN_I16_VPTR_I16, BT_I16, BT_VOLATILE_PTR, BT_I16)
+DEF_FUNCTION_TYPE_2 (BT_FN_VOID_PTR_PTR, BT_VOID, BT_PTR, BT_PTR)
+
+DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR)
 
 DEF_FUNCTION_TYPE_3 (BT_FN_BOOL_VPTR_I1_I1, BT_BOOL, BT_VOLATILE_PTR,
                      BT_I1, BT_I1)
@@ -127,9 +135,20 @@ DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_LONG_LONG_LONG_LONG_LONGPTR_LONGPTR,
 DEF_FUNCTION_TYPE_6 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG,
                      BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT,
                      BT_LONG, BT_LONG, BT_LONG)
+DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULLPTR_ULLPTR,
+                    BT_BOOL, BT_BOOL, BT_ULONGLONG, BT_ULONGLONG,
+                    BT_ULONGLONG, BT_PTR_ULONGLONG, BT_PTR_ULONGLONG)
 
 DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG,
                      BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT,
                      BT_LONG, BT_LONG, BT_LONG, BT_LONG)
+DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT,
+                    BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR,
+                    BT_PTR_FN_VOID_PTR_PTR, BT_LONG, BT_LONG,
+                    BT_BOOL, BT_UINT)
+DEF_FUNCTION_TYPE_7 (BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULL_ULLPTR_ULLPTR,
+                    BT_BOOL, BT_BOOL, BT_ULONGLONG, BT_ULONGLONG,
+                    BT_ULONGLONG, BT_ULONGLONG,
+                    BT_PTR_ULONGLONG, BT_PTR_ULONGLONG)
 
 DEF_FUNCTION_TYPE_VAR_0 (BT_FN_VOID_VAR, BT_VOID)
index fd1a19d..99175d5 100644 (file)
@@ -277,6 +277,7 @@ lower_stmt (tree_stmt_iterator *tsi, struct lower_data *data)
       break;
 
     case OMP_PARALLEL:
+    case OMP_TASK:
       lower_omp_directive (tsi, data);
       return;
 
index 462e4a2..0c2e5e2 100644 (file)
@@ -62,10 +62,19 @@ enum gimplify_omp_var_data
   GOVD_REDUCTION = 64,
   GOVD_LOCAL = 128,
   GOVD_DEBUG_PRIVATE = 256,
+  GOVD_PRIVATE_OUTER_REF = 512,
   GOVD_DATA_SHARE_CLASS = (GOVD_SHARED | GOVD_PRIVATE | GOVD_FIRSTPRIVATE
                           | GOVD_LASTPRIVATE | GOVD_REDUCTION | GOVD_LOCAL)
 };
 
+enum omp_region_type
+{
+  ORT_WORKSHARE = 0,
+  ORT_TASK = 1,
+  ORT_PARALLEL = 2,
+  ORT_COMBINED_PARALLEL = 3
+};
+
 struct gimplify_omp_ctx
 {
   struct gimplify_omp_ctx *outer_context;
@@ -73,8 +82,7 @@ struct gimplify_omp_ctx
   struct pointer_set_t *privatized_types;
   location_t location;
   enum omp_clause_default_kind default_kind;
-  bool is_parallel;
-  bool is_combined_parallel;
+  enum omp_region_type region_type;
 };
 
 struct gimplify_ctx
@@ -270,7 +278,7 @@ splay_tree_compare_decl_uid (splay_tree_key xa, splay_tree_key xb)
 /* Create a new omp construct that deals with variable remapping.  */
 
 static struct gimplify_omp_ctx *
-new_omp_context (bool is_parallel, bool is_combined_parallel)
+new_omp_context (enum omp_region_type region_type)
 {
   struct gimplify_omp_ctx *c;
 
@@ -279,9 +287,11 @@ new_omp_context (bool is_parallel, bool is_combined_parallel)
   c->variables = splay_tree_new (splay_tree_compare_decl_uid, 0, 0);
   c->privatized_types = pointer_set_create ();
   c->location = input_location;
-  c->is_parallel = is_parallel;
-  c->is_combined_parallel = is_combined_parallel;
-  c->default_kind = OMP_CLAUSE_DEFAULT_SHARED;
+  c->region_type = region_type;
+  if (region_type != ORT_TASK)
+    c->default_kind = OMP_CLAUSE_DEFAULT_SHARED;
+  else
+    c->default_kind = OMP_CLAUSE_DEFAULT_UNSPECIFIED;
 
   return c;
 }
@@ -756,7 +766,7 @@ gimple_add_tmp_var (tree tmp)
       if (gimplify_omp_ctxp)
        {
          struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp;
-         while (ctx && !ctx->is_parallel)
+         while (ctx && ctx->region_type == ORT_WORKSHARE)
            ctx = ctx->outer_context;
          if (ctx)
            omp_add_variable (ctx, tmp, GOVD_LOCAL | GOVD_SEEN);
@@ -4711,7 +4721,7 @@ omp_firstprivatize_variable (struct gimplify_omp_ctx *ctx, tree decl)
          else
            return;
        }
-      else if (ctx->is_parallel)
+      else if (ctx->region_type != ORT_WORKSHARE)
        omp_add_variable (ctx, decl, GOVD_FIRSTPRIVATE);
 
       ctx = ctx->outer_context;
@@ -4904,8 +4914,9 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code)
   if (n == NULL)
     {
       enum omp_clause_default_kind default_kind, kind;
+      struct gimplify_omp_ctx *octx;
 
-      if (!ctx->is_parallel)
+      if (ctx->region_type == ORT_WORKSHARE)
        goto do_outer;
 
       /* ??? Some compiler-generated variables (like SAVE_EXPRs) could be
@@ -4929,10 +4940,47 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code)
        case OMP_CLAUSE_DEFAULT_PRIVATE:
          flags |= GOVD_PRIVATE;
          break;
+       case OMP_CLAUSE_DEFAULT_FIRSTPRIVATE:
+         flags |= GOVD_FIRSTPRIVATE;
+         break;
+       case OMP_CLAUSE_DEFAULT_UNSPECIFIED:
+         /* decl will be either GOVD_FIRSTPRIVATE or GOVD_SHARED.  */
+         gcc_assert (ctx->region_type == ORT_TASK);
+         if (ctx->outer_context)
+           omp_notice_variable (ctx->outer_context, decl, in_code);
+         for (octx = ctx->outer_context; octx; octx = octx->outer_context)
+           {
+             splay_tree_node n2;
+
+             n2 = splay_tree_lookup (octx->variables, (splay_tree_key) decl);
+             if (n2 && (n2->value & GOVD_DATA_SHARE_CLASS) != GOVD_SHARED)
+               {
+                 flags |= GOVD_FIRSTPRIVATE;
+                 break;
+               }
+             if ((octx->region_type & ORT_PARALLEL) != 0)
+               break;
+           }
+         if (flags & GOVD_FIRSTPRIVATE)
+           break;
+         if (octx == NULL
+             && (TREE_CODE (decl) == PARM_DECL
+                 || (!is_global_var (decl)
+                     && DECL_CONTEXT (decl) == current_function_decl)))
+           {
+             flags |= GOVD_FIRSTPRIVATE;
+             break;
+           }
+         flags |= GOVD_SHARED;
+         break;
        default:
          gcc_unreachable ();
        }
 
+      if ((flags & GOVD_PRIVATE)
+         && lang_hooks.decls.omp_private_outer_ref (decl))
+       flags |= GOVD_PRIVATE_OUTER_REF;
+
       omp_add_variable (ctx, decl, flags);
 
       shared = (flags & GOVD_SHARED) != 0;
@@ -4952,7 +5000,7 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code)
  do_outer:
   /* If the variable is private in the current context, then we don't
      need to propagate anything to an outer context.  */
-  if (flags & GOVD_PRIVATE)
+  if ((flags & GOVD_PRIVATE) && !(flags & GOVD_PRIVATE_OUTER_REF))
     return ret;
   if (ctx->outer_context
       && omp_notice_variable (ctx->outer_context, decl, in_code))
@@ -4985,7 +5033,7 @@ omp_is_private (struct gimplify_omp_ctx *ctx, tree decl)
        }
       else if ((n->value & GOVD_EXPLICIT) != 0
               && (ctx == gimplify_omp_ctxp
-                  || (ctx->is_combined_parallel
+                  || (ctx->region_type == ORT_COMBINED_PARALLEL
                       && gimplify_omp_ctxp->outer_context == ctx)))
        {
          if ((n->value & GOVD_FIRSTPRIVATE) != 0)
@@ -4998,7 +5046,7 @@ omp_is_private (struct gimplify_omp_ctx *ctx, tree decl)
       return true;
     }
 
-  if (ctx->is_parallel)
+  if (ctx->region_type != ORT_WORKSHARE)
     return false;
   else if (ctx->outer_context)
     return omp_is_private (ctx->outer_context, decl);
@@ -5027,7 +5075,7 @@ omp_check_private (struct gimplify_omp_ctx *ctx, tree decl)
       if (n != NULL)
        return (n->value & GOVD_SHARED) == 0;
     }
-  while (!ctx->is_parallel);
+  while (ctx->region_type == ORT_WORKSHARE);
   return false;
 }
 
@@ -5035,13 +5083,13 @@ omp_check_private (struct gimplify_omp_ctx *ctx, tree decl)
    and previous omp contexts.  */
 
 static void
-gimplify_scan_omp_clauses (tree *list_p, tree *pre_p, bool in_parallel,
-                          bool in_combined_parallel)
+gimplify_scan_omp_clauses (tree *list_p, tree *pre_p,
+                          enum omp_region_type region_type)
 {
   struct gimplify_omp_ctx *ctx, *outer_ctx;
   tree c;
 
-  ctx = new_omp_context (in_parallel, in_combined_parallel);
+  ctx = new_omp_context (region_type);
   outer_ctx = ctx->outer_context;
 
   while ((c = *list_p) != NULL)
@@ -5057,7 +5105,13 @@ gimplify_scan_omp_clauses (tree *list_p, tree *pre_p, bool in_parallel,
        {
        case OMP_CLAUSE_PRIVATE:
          flags = GOVD_PRIVATE | GOVD_EXPLICIT;
-         notice_outer = false;
+         if (lang_hooks.decls.omp_private_outer_ref (OMP_CLAUSE_DECL (c)))
+           {
+             flags |= GOVD_PRIVATE_OUTER_REF;
+             OMP_CLAUSE_PRIVATE_OUTER_REF (c) = 1;
+           }
+         else
+           notice_outer = false;
          goto do_add;
        case OMP_CLAUSE_SHARED:
          flags = GOVD_SHARED | GOVD_EXPLICIT;
@@ -5097,6 +5151,23 @@ gimplify_scan_omp_clauses (tree *list_p, tree *pre_p, bool in_parallel,
              pop_gimplify_context (OMP_CLAUSE_REDUCTION_MERGE (c));
              gimplify_omp_ctxp = outer_ctx;
            }
+         else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
+                  && OMP_CLAUSE_LASTPRIVATE_STMT (c))
+           {
+             gimplify_omp_ctxp = ctx;
+             push_gimplify_context ();
+             if (TREE_CODE (OMP_CLAUSE_LASTPRIVATE_STMT (c)) != BIND_EXPR)
+               {
+                 tree bind = build3 (BIND_EXPR, void_type_node, NULL,
+                                     NULL, NULL);
+                 TREE_SIDE_EFFECTS (bind) = 1;
+                 BIND_EXPR_BODY (bind) = OMP_CLAUSE_LASTPRIVATE_STMT (c);
+                 OMP_CLAUSE_LASTPRIVATE_STMT (c) = bind;
+               }
+             gimplify_stmt (&OMP_CLAUSE_LASTPRIVATE_STMT (c));
+             pop_gimplify_context (OMP_CLAUSE_LASTPRIVATE_STMT (c));
+             gimplify_omp_ctxp = outer_ctx;
+           }
          if (notice_outer)
            goto do_notice;
          break;
@@ -5113,7 +5184,7 @@ gimplify_scan_omp_clauses (tree *list_p, tree *pre_p, bool in_parallel,
          if (outer_ctx)
            omp_notice_variable (outer_ctx, decl, true);
          if (check_non_private
-             && !in_parallel
+             && region_type == ORT_WORKSHARE
              && omp_check_private (ctx, decl))
            {
              error ("%s variable %qs is private in outer context",
@@ -5137,6 +5208,8 @@ gimplify_scan_omp_clauses (tree *list_p, tree *pre_p, bool in_parallel,
 
        case OMP_CLAUSE_NOWAIT:
        case OMP_CLAUSE_ORDERED:
+       case OMP_CLAUSE_UNTIED:
+       case OMP_CLAUSE_COLLAPSE:
          break;
 
        case OMP_CLAUSE_DEFAULT:
@@ -5215,7 +5288,10 @@ gimplify_adjust_omp_clauses_1 (splay_tree_node n, void *data)
   OMP_CLAUSE_CHAIN (clause) = *list_p;
   if (private_debug)
     OMP_CLAUSE_PRIVATE_DEBUG (clause) = 1;
+  else if (code == OMP_CLAUSE_PRIVATE && (flags & GOVD_PRIVATE_OUTER_REF))
+    OMP_CLAUSE_PRIVATE_OUTER_REF (clause) = 1;
   *list_p = clause;
+  lang_hooks.decls.omp_finish_clause (clause);
 
   return 0;
 }
@@ -5272,6 +5348,8 @@ gimplify_adjust_omp_clauses (tree *list_p)
        case OMP_CLAUSE_NOWAIT:
        case OMP_CLAUSE_ORDERED:
        case OMP_CLAUSE_DEFAULT:
+       case OMP_CLAUSE_UNTIED:
+       case OMP_CLAUSE_COLLAPSE:
          break;
 
        default:
@@ -5301,8 +5379,10 @@ gimplify_omp_parallel (tree *expr_p, tree *pre_p)
 {
   tree expr = *expr_p;
 
-  gimplify_scan_omp_clauses (&OMP_PARALLEL_CLAUSES (expr), pre_p, true,
-                            OMP_PARALLEL_COMBINED (expr));
+  gimplify_scan_omp_clauses (&OMP_PARALLEL_CLAUSES (expr), pre_p,
+                            OMP_PARALLEL_COMBINED (expr)
+                            ? ORT_COMBINED_PARALLEL
+                            : ORT_PARALLEL);
 
   push_gimplify_context ();
 
@@ -5318,124 +5398,187 @@ gimplify_omp_parallel (tree *expr_p, tree *pre_p)
   return GS_ALL_DONE;
 }
 
-/* Gimplify the gross structure of an OMP_FOR statement.  */
+/* Gimplify the contents of an OMP_TASK statement.  This involves
+   gimplification of the body, as well as scanning the body for used
+   variables.  We need to do this scan now, because variable-sized
+   decls will be decomposed during gimplification.  */
 
 static enum gimplify_status
-gimplify_omp_for (tree *expr_p, tree *pre_p)
+gimplify_omp_task (tree *expr_p, tree *pre_p)
 {
-  tree for_stmt, decl, var, t;
-  enum gimplify_status ret = GS_OK;
-  tree body, init_decl = NULL_TREE;
+  tree expr = *expr_p;
 
-  for_stmt = *expr_p;
+  gimplify_scan_omp_clauses (&OMP_TASK_CLAUSES (expr), pre_p, ORT_TASK);
 
-  gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p, false, false);
+  push_gimplify_context ();
 
-  t = OMP_FOR_INIT (for_stmt);
-  gcc_assert (TREE_CODE (t) == MODIFY_EXPR
-             || TREE_CODE (t) == GIMPLE_MODIFY_STMT);
-  decl = GENERIC_TREE_OPERAND (t, 0);
-  gcc_assert (DECL_P (decl));
-  gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (decl)));
+  gimplify_stmt (&OMP_TASK_BODY (expr));
 
-  /* Make sure the iteration variable is private.  */
-  if (omp_is_private (gimplify_omp_ctxp, decl))
-    omp_notice_variable (gimplify_omp_ctxp, decl, true);
+  if (TREE_CODE (OMP_TASK_BODY (expr)) == BIND_EXPR)
+    pop_gimplify_context (OMP_TASK_BODY (expr));
   else
-    omp_add_variable (gimplify_omp_ctxp, decl, GOVD_PRIVATE | GOVD_SEEN);
+    pop_gimplify_context (NULL_TREE);
 
-  /* If DECL is not a gimple register, create a temporary variable to act as an
-     iteration counter.  This is valid, since DECL cannot be modified in the
-     body of the loop.  */
-  if (!is_gimple_reg (decl))
-    {
-      var = create_tmp_var (TREE_TYPE (decl), get_name (decl));
-      GENERIC_TREE_OPERAND (t, 0) = var;
+  gimplify_adjust_omp_clauses (&OMP_TASK_CLAUSES (expr));
 
-      init_decl = build_gimple_modify_stmt (decl, var);
-      omp_add_variable (gimplify_omp_ctxp, var, GOVD_PRIVATE | GOVD_SEEN);
-    }
-  else
-    var = decl;
+  return GS_ALL_DONE;
+}
+
+/* Gimplify the gross structure of an OMP_FOR statement.  */
+
+static enum gimplify_status
+gimplify_omp_for (tree *expr_p, tree *pre_p)
+{
+  tree for_stmt, decl, var, t, bodylist;
+  enum gimplify_status ret = GS_OK;
+  tree body, init_decl = NULL_TREE;
+  int i;
+
+  for_stmt = *expr_p;
+
+  gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p,
+                            ORT_WORKSHARE);
 
   /* If OMP_FOR is re-gimplified, ensure all variables in pre-body
      are noticed.  */
   gimplify_stmt (&OMP_FOR_PRE_BODY (for_stmt));
 
-  ret |= gimplify_expr (&GENERIC_TREE_OPERAND (t, 1),
-                       &OMP_FOR_PRE_BODY (for_stmt),
-                       NULL, is_gimple_val, fb_rvalue);
+  bodylist = alloc_stmt_list ();
+
+  gcc_assert (TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt))
+             == TREE_VEC_LENGTH (OMP_FOR_COND (for_stmt)));
+  gcc_assert (TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt))
+             == TREE_VEC_LENGTH (OMP_FOR_INCR (for_stmt)));
+  for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++)
+    {
+      t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i);
+      gcc_assert (TREE_CODE (t) == MODIFY_EXPR
+                 || TREE_CODE (t) == GIMPLE_MODIFY_STMT);
+      decl = GENERIC_TREE_OPERAND (t, 0);
+      gcc_assert (DECL_P (decl));
+      gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (decl))
+                 || POINTER_TYPE_P (TREE_TYPE (decl)));
+
+      /* Make sure the iteration variable is private.  */
+      if (omp_is_private (gimplify_omp_ctxp, decl))
+       omp_notice_variable (gimplify_omp_ctxp, decl, true);
+      else
+       omp_add_variable (gimplify_omp_ctxp, decl, GOVD_PRIVATE | GOVD_SEEN);
+
+      /* If DECL is not a gimple register, create a temporary variable to act
+        as an iteration counter.  This is valid, since DECL cannot be
+        modified in the body of the loop.  */
+      if (!is_gimple_reg (decl))
+       {
+         var = create_tmp_var (TREE_TYPE (decl), get_name (decl));
+         GENERIC_TREE_OPERAND (t, 0) = var;
 
-  tree_to_gimple_tuple (&OMP_FOR_INIT (for_stmt));
+         init_decl = build_gimple_modify_stmt (decl, var);
+         omp_add_variable (gimplify_omp_ctxp, var, GOVD_PRIVATE | GOVD_SEEN);
+       }
+      else
+       var = decl;
 
-  t = OMP_FOR_COND (for_stmt);
-  gcc_assert (COMPARISON_CLASS_P (t));
-  gcc_assert (GENERIC_TREE_OPERAND (t, 0) == decl);
-  TREE_OPERAND (t, 0) = var;
+      ret |= gimplify_expr (&GENERIC_TREE_OPERAND (t, 1),
+                           &OMP_FOR_PRE_BODY (for_stmt),
+                           NULL, is_gimple_val, fb_rvalue);
 
-  ret |= gimplify_expr (&GENERIC_TREE_OPERAND (t, 1),
-                       &OMP_FOR_PRE_BODY (for_stmt),
-                       NULL, is_gimple_val, fb_rvalue);
+      tree_to_gimple_tuple (&TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i));
 
-  tree_to_gimple_tuple (&OMP_FOR_INCR (for_stmt));
-  t = OMP_FOR_INCR (for_stmt);
-  switch (TREE_CODE (t))
-    {
-    case PREINCREMENT_EXPR:
-    case POSTINCREMENT_EXPR:
-      t = build_int_cst (TREE_TYPE (decl), 1);
-      t = build2 (PLUS_EXPR, TREE_TYPE (decl), var, t);
-      t = build_gimple_modify_stmt (var, t);
-      OMP_FOR_INCR (for_stmt) = t;
-      break;
+      t = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), i);
+      gcc_assert (COMPARISON_CLASS_P (t));
+      gcc_assert (GENERIC_TREE_OPERAND (t, 0) == decl);
+      TREE_OPERAND (t, 0) = var;
 
-    case PREDECREMENT_EXPR:
-    case POSTDECREMENT_EXPR:
-      t = build_int_cst (TREE_TYPE (decl), -1);
-      t = build2 (PLUS_EXPR, TREE_TYPE (decl), var, t);
-      t = build_gimple_modify_stmt (var, t);
-      OMP_FOR_INCR (for_stmt) = t;
-      break;
-      
-    case GIMPLE_MODIFY_STMT:
-      gcc_assert (GIMPLE_STMT_OPERAND (t, 0) == decl);
-      GIMPLE_STMT_OPERAND (t, 0) = var;
+      ret |= gimplify_expr (&GENERIC_TREE_OPERAND (t, 1),
+                           &OMP_FOR_PRE_BODY (for_stmt),
+                           NULL, is_gimple_val, fb_rvalue);
 
-      t = GIMPLE_STMT_OPERAND (t, 1);
+      tree_to_gimple_tuple (&TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i));
+      t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i);
       switch (TREE_CODE (t))
        {
-       case PLUS_EXPR:
-         if (TREE_OPERAND (t, 1) == decl)
+       case PREINCREMENT_EXPR:
+       case POSTINCREMENT_EXPR:
+         t = build_int_cst (TREE_TYPE (decl), 1);
+         t = build2 (PLUS_EXPR, TREE_TYPE (decl), var, t);
+         t = build_gimple_modify_stmt (var, t);
+         TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i) = t;
+         break;
+
+       case PREDECREMENT_EXPR:
+       case POSTDECREMENT_EXPR:
+         t = build_int_cst (TREE_TYPE (decl), -1);
+         t = build2 (PLUS_EXPR, TREE_TYPE (decl), var, t);
+         t = build_gimple_modify_stmt (var, t);
+         TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i) = t;
+         break;
+
+       case GIMPLE_MODIFY_STMT:
+         gcc_assert (GIMPLE_STMT_OPERAND (t, 0) == decl);
+         GIMPLE_STMT_OPERAND (t, 0) = var;
+
+         t = GIMPLE_STMT_OPERAND (t, 1);
+         switch (TREE_CODE (t))
            {
-             TREE_OPERAND (t, 1) = TREE_OPERAND (t, 0);
+           case PLUS_EXPR:
+             if (TREE_OPERAND (t, 1) == decl)
+               {
+                 TREE_OPERAND (t, 1) = TREE_OPERAND (t, 0);
+                 TREE_OPERAND (t, 0) = var;
+                 break;
+               }
+
+             /* Fallthru.  */
+           case MINUS_EXPR:
+           case POINTER_PLUS_EXPR:
+             gcc_assert (TREE_OPERAND (t, 0) == decl);
              TREE_OPERAND (t, 0) = var;
              break;
+           default:
+             gcc_unreachable ();
            }
 
-         /* Fallthru.  */
-       case MINUS_EXPR:
-         gcc_assert (TREE_OPERAND (t, 0) == decl);
-         TREE_OPERAND (t, 0) = var;
+         ret |= gimplify_expr (&TREE_OPERAND (t, 1),
+                               &OMP_FOR_PRE_BODY (for_stmt),
+                               NULL, is_gimple_val, fb_rvalue);
          break;
+
        default:
          gcc_unreachable ();
        }
 
-      ret |= gimplify_expr (&TREE_OPERAND (t, 1), &OMP_FOR_PRE_BODY (for_stmt),
-                           NULL, is_gimple_val, fb_rvalue);
-      break;
+      if (init_decl)
+       append_to_statement_list (init_decl, &bodylist);
 
-    default:
-      gcc_unreachable ();
+      if (var != decl || TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) > 1)
+       {
+         tree c;
+         for (c = OMP_FOR_CLAUSES (for_stmt); c ; c = OMP_CLAUSE_CHAIN (c))
+         if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
+             && OMP_CLAUSE_DECL (c) == decl
+             && OMP_CLAUSE_LASTPRIVATE_STMT (c) == NULL)
+           {
+             t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i);
+             gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
+             gcc_assert (GIMPLE_STMT_OPERAND (t, 0) == var);
+             t = GIMPLE_STMT_OPERAND (t, 1);
+             gcc_assert (TREE_CODE (t) == PLUS_EXPR
+                         || TREE_CODE (t) == MINUS_EXPR
+                         || TREE_CODE (t) == POINTER_PLUS_EXPR);
+             gcc_assert (TREE_OPERAND (t, 0) == var);
+             t = build2 (TREE_CODE (t), TREE_TYPE (decl), decl,
+                         TREE_OPERAND (t, 1));
+             OMP_CLAUSE_LASTPRIVATE_STMT (c)
+               = build_gimple_modify_stmt (decl, t);
+           }
+       }
     }
 
   body = OMP_FOR_BODY (for_stmt);
   gimplify_to_stmt_list (&body);
-  t = alloc_stmt_list ();
-  if (init_decl)
-    append_to_statement_list (init_decl, &t);
-  append_to_statement_list (body, &t);
-  OMP_FOR_BODY (for_stmt) = t;
+  append_to_statement_list (body, &bodylist);
+  OMP_FOR_BODY (for_stmt) = bodylist;
   gimplify_adjust_omp_clauses (&OMP_FOR_CLAUSES (for_stmt));
 
   return ret == GS_ALL_DONE ? GS_ALL_DONE : GS_ERROR;
@@ -5449,7 +5592,7 @@ gimplify_omp_workshare (tree *expr_p, tree *pre_p)
 {
   tree stmt = *expr_p;
 
-  gimplify_scan_omp_clauses (&OMP_CLAUSES (stmt), pre_p, false, false);
+  gimplify_scan_omp_clauses (&OMP_CLAUSES (stmt), pre_p, ORT_WORKSHARE);
   gimplify_to_stmt_list (&OMP_BODY (stmt));
   gimplify_adjust_omp_clauses (&OMP_CLAUSES (stmt));
 
@@ -6025,6 +6168,10 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          ret = gimplify_omp_parallel (expr_p, pre_p);
          break;
 
+       case OMP_TASK:
+         ret = gimplify_omp_task (expr_p, pre_p);
+         break;
+
        case OMP_FOR:
          ret = gimplify_omp_for (expr_p, pre_p);
          break;
@@ -6048,6 +6195,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
        case OMP_RETURN:
        case OMP_CONTINUE:
        case OMP_ATOMIC_STORE:
+       case OMP_SECTIONS_SWITCH:
          ret = GS_ALL_DONE;
          break;
 
index 289275e..50761b6 100644 (file)
@@ -291,6 +291,14 @@ hook_tree_tree_tree_null (tree t0 ATTRIBUTE_UNUSED, tree t1 ATTRIBUTE_UNUSED)
   return NULL;
 }
 
+tree
+hook_tree_tree_tree_tree_null (tree t0 ATTRIBUTE_UNUSED,
+                              tree t1 ATTRIBUTE_UNUSED,
+                              tree t2 ATTRIBUTE_UNUSED)
+{
+  return NULL;
+}
+
 /* Generic hook that takes a rtx and returns a NULL string.  */
 const char *
 hook_constcharptr_const_rtx_null (const_rtx r ATTRIBUTE_UNUSED)
index 838a422..d6bbc4c 100644 (file)
@@ -63,6 +63,7 @@ extern int hook_int_size_t_constcharptr_int_0 (size_t, const char *, int);
 extern int hook_int_void_no_regs (void);
 
 extern tree hook_tree_tree_tree_null (tree, tree);
+extern tree hook_tree_tree_tree_tree_null (tree, tree, tree);
 extern tree hook_tree_tree_tree_tree_3rd_identity (tree, tree, tree);
 extern tree hook_tree_tree_tree_bool_null (tree, tree, bool);
 
index 908681d..cce9b3f 100644 (file)
@@ -3727,6 +3727,7 @@ do_reorg_1 (void)
       }
 
   set_cfun (NULL);
+  bitmap_obstack_release (NULL);
 }
 
 /* This function creates new global struct variables.
index aae4640..dd4916c 100644 (file)
@@ -199,10 +199,12 @@ extern tree lhd_make_node (enum tree_code);
 #define LANG_HOOKS_OMP_PREDETERMINED_SHARING lhd_omp_predetermined_sharing
 #define LANG_HOOKS_OMP_DISREGARD_VALUE_EXPR hook_bool_tree_bool_false
 #define LANG_HOOKS_OMP_PRIVATE_DEBUG_CLAUSE hook_bool_tree_bool_false
-#define LANG_HOOKS_OMP_CLAUSE_DEFAULT_CTOR hook_tree_tree_tree_null
+#define LANG_HOOKS_OMP_PRIVATE_OUTER_REF hook_bool_tree_false
+#define LANG_HOOKS_OMP_CLAUSE_DEFAULT_CTOR hook_tree_tree_tree_tree_null
 #define LANG_HOOKS_OMP_CLAUSE_COPY_CTOR lhd_omp_assignment
 #define LANG_HOOKS_OMP_CLAUSE_ASSIGN_OP lhd_omp_assignment
 #define LANG_HOOKS_OMP_CLAUSE_DTOR hook_tree_tree_tree_null
+#define LANG_HOOKS_OMP_FINISH_CLAUSE hook_void_tree
 
 #define LANG_HOOKS_DECLS { \
   LANG_HOOKS_GLOBAL_BINDINGS_P, \
@@ -216,10 +218,12 @@ extern tree lhd_make_node (enum tree_code);
   LANG_HOOKS_OMP_PREDETERMINED_SHARING, \
   LANG_HOOKS_OMP_DISREGARD_VALUE_EXPR, \
   LANG_HOOKS_OMP_PRIVATE_DEBUG_CLAUSE, \
+  LANG_HOOKS_OMP_PRIVATE_OUTER_REF, \
   LANG_HOOKS_OMP_CLAUSE_DEFAULT_CTOR, \
   LANG_HOOKS_OMP_CLAUSE_COPY_CTOR, \
   LANG_HOOKS_OMP_CLAUSE_ASSIGN_OP, \
-  LANG_HOOKS_OMP_CLAUSE_DTOR \
+  LANG_HOOKS_OMP_CLAUSE_DTOR, \
+  LANG_HOOKS_OMP_FINISH_CLAUSE \
 }
 
 /* The whole thing.  The structure is defined in langhooks.h.  */
index 6a54b01..1f64cf1 100644 (file)
@@ -1,5 +1,5 @@
 /* The lang_hooks data structure.
-   Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -197,9 +197,14 @@ struct lang_hooks_for_decls
      be put into OMP_CLAUSE_PRIVATE_DEBUG.  */
   bool (*omp_private_debug_clause) (tree, bool);
 
+  /* Return true if DECL in private clause needs
+     OMP_CLAUSE_PRIVATE_OUTER_REF on the private clause.  */
+  bool (*omp_private_outer_ref) (tree);
+
   /* Build and return code for a default constructor for DECL in
-     response to CLAUSE.  Return NULL if nothing to be done.  */
-  tree (*omp_clause_default_ctor) (tree clause, tree decl);
+     response to CLAUSE.  OUTER is corresponding outer region's
+     variable if needed.  Return NULL if nothing to be done.  */
+  tree (*omp_clause_default_ctor) (tree clause, tree decl, tree outer);
 
   /* Build and return code for a copy constructor from SRC to DST.  */
   tree (*omp_clause_copy_ctor) (tree clause, tree dst, tree src);
@@ -210,6 +215,9 @@ struct lang_hooks_for_decls
   /* Build and return code destructing DECL.  Return NULL if nothing
      to be done.  */
   tree (*omp_clause_dtor) (tree clause, tree decl);
+
+  /* Do language specific checking on an implicitly determined clause.  */
+  void (*omp_finish_clause) (tree clause);
 };
 
 /* Language-specific hooks.  See langhooks-def.h for defaults.  */
index eee4ddf..50ac7e8 100644 (file)
@@ -2235,6 +2235,7 @@ matrix_reorg (void)
            free_dominance_info (CDI_POST_DOMINATORS);
            pop_cfun ();
            current_function_decl = temp_fn;
+           bitmap_obstack_release (NULL);
 
            return 0;
          }
@@ -2249,6 +2250,7 @@ matrix_reorg (void)
            free_dominance_info (CDI_POST_DOMINATORS);
            pop_cfun ();
            current_function_decl = temp_fn;
+           bitmap_obstack_release (NULL);
 
            return 0;
          }
@@ -2279,6 +2281,7 @@ matrix_reorg (void)
        free_dominance_info (CDI_POST_DOMINATORS);
        pop_cfun ();
        current_function_decl = temp_fn;
+       bitmap_obstack_release (NULL);
       }
   htab_traverse (matrices_to_reorg, transform_allocation_sites, NULL);
   /* Now transform the accesses.  */
@@ -2299,6 +2302,7 @@ matrix_reorg (void)
        free_dominance_info (CDI_POST_DOMINATORS);
        pop_cfun ();
        current_function_decl = temp_fn;
+       bitmap_obstack_release (NULL);
       }
   htab_traverse (matrices_to_reorg, dump_matrix_reorg_analysis, NULL);
 
index cc450f6..5fd4f9a 100644 (file)
@@ -1,6 +1,6 @@
 /* This file contains the definitions and documentation for the
    OpenMP builtins used in the GNU compiler.
-   Copyright (C) 2005, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2007, 2008 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -35,6 +35,8 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_ATOMIC_END, "GOMP_atomic_end",
                  BT_FN_VOID, ATTR_NOTHROW_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_BARRIER, "GOMP_barrier",
                  BT_FN_VOID, ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKWAIT, "GOMP_taskwait",
+                 BT_FN_VOID, ATTR_NOTHROW_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_CRITICAL_START, "GOMP_critical_start",
                  BT_FN_VOID, ATTR_NOTHROW_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_CRITICAL_END, "GOMP_critical_end",
@@ -100,6 +102,58 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ORDERED_GUIDED_NEXT,
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ORDERED_RUNTIME_NEXT,
                  "GOMP_loop_ordered_runtime_next",
                  BT_FN_BOOL_LONGPTR_LONGPTR, ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ULL_STATIC_START,
+                 "GOMP_loop_ull_static_start",
+                 BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULL_ULLPTR_ULLPTR,
+                 ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ULL_DYNAMIC_START,
+                 "GOMP_loop_ull_dynamic_start",
+                 BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULL_ULLPTR_ULLPTR,
+                 ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ULL_GUIDED_START,
+                 "GOMP_loop_ull_guided_start",
+                 BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULL_ULLPTR_ULLPTR,
+                 ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ULL_RUNTIME_START,
+                 "GOMP_loop_ull_runtime_start",
+                 BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULLPTR_ULLPTR,
+                 ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ULL_ORDERED_STATIC_START,
+                 "GOMP_loop_ull_ordered_static_start",
+                 BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULL_ULLPTR_ULLPTR,
+                 ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ULL_ORDERED_DYNAMIC_START,
+                 "GOMP_loop_ull_ordered_dynamic_start",
+                 BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULL_ULLPTR_ULLPTR,
+                 ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ULL_ORDERED_GUIDED_START,
+                 "GOMP_loop_ull_ordered_guided_start",
+                 BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULL_ULLPTR_ULLPTR,
+                 ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ULL_ORDERED_RUNTIME_START,
+                 "GOMP_loop_ull_ordered_runtime_start",
+                 BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULLPTR_ULLPTR,
+                 ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ULL_STATIC_NEXT, "GOMP_loop_ull_static_next",
+                 BT_FN_BOOL_ULONGLONGPTR_ULONGLONGPTR, ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ULL_DYNAMIC_NEXT, "GOMP_loop_ull_dynamic_next",
+                 BT_FN_BOOL_ULONGLONGPTR_ULONGLONGPTR, ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ULL_GUIDED_NEXT, "GOMP_loop_ull_guided_next",
+                 BT_FN_BOOL_ULONGLONGPTR_ULONGLONGPTR, ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ULL_RUNTIME_NEXT, "GOMP_loop_ull_runtime_next",
+                 BT_FN_BOOL_ULONGLONGPTR_ULONGLONGPTR, ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ULL_ORDERED_STATIC_NEXT,
+                 "GOMP_loop_ull_ordered_static_next",
+                 BT_FN_BOOL_ULONGLONGPTR_ULONGLONGPTR, ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ULL_ORDERED_DYNAMIC_NEXT,
+                 "GOMP_loop_ull_ordered_dynamic_next",
+                 BT_FN_BOOL_ULONGLONGPTR_ULONGLONGPTR, ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ULL_ORDERED_GUIDED_NEXT,
+                 "GOMP_loop_ull_ordered_guided_next",
+                 BT_FN_BOOL_ULONGLONGPTR_ULONGLONGPTR, ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ULL_ORDERED_RUNTIME_NEXT,
+                 "GOMP_loop_ull_ordered_runtime_next",
+                 BT_FN_BOOL_ULONGLONGPTR_ULONGLONGPTR, ATTR_NOTHROW_LIST)
 /* NOTE: Do not change the order of BUILT_IN_GOMP_PARALLEL_LOOP_*_START.
    They are used in index arithmetic with enum omp_clause_schedule_kind
    in omp-low.c.  */
@@ -131,6 +185,9 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_START, "GOMP_parallel_start",
                  BT_FN_VOID_OMPFN_PTR_UINT, ATTR_NOTHROW_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_END, "GOMP_parallel_end",
                  BT_FN_VOID, ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASK, "GOMP_task",
+                 BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT,
+                 ATTR_NOTHROW_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SECTIONS_START, "GOMP_sections_start",
                  BT_FN_UINT_UINT, ATTR_NOTHROW_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SECTIONS_NEXT, "GOMP_sections_next",
index c608ae4..e9223b2 100644 (file)
@@ -77,6 +77,14 @@ typedef struct omp_context
   tree sender_decl;
   tree receiver_decl;
 
+  /* These are used just by task contexts, if task firstprivate fn is
+     needed.  srecord_type is used to communicate from the thread
+     that encountered the task construct to task firstprivate fn,
+     record_type is allocated by GOMP_task, initialized by task firstprivate
+     fn and passed to the task body fn.  */
+  splay_tree sfield_map;
+  tree srecord_type;
+
   /* A chain of variables to add to the top-level block surrounding the
      construct.  In the case of a parallel, this is in the child function.  */
   tree block_vars;
@@ -95,21 +103,30 @@ typedef struct omp_context
 } omp_context;
 
 
+struct omp_for_data_loop
+{
+  tree v, n1, n2, step;
+  enum tree_code cond_code;
+};
+
 /* A structure describing the main elements of a parallel loop.  */
 
 struct omp_for_data
 {
-  tree v, n1, n2, step, chunk_size, for_stmt;
-  enum tree_code cond_code;
-  tree pre;
+  struct omp_for_data_loop loop;
+  tree chunk_size, for_stmt;
+  tree pre, iter_type;
+  int collapse;
   bool have_nowait, have_ordered;
   enum omp_clause_schedule_kind sched_kind;
+  struct omp_for_data_loop *loops;
 };
 
 
 static splay_tree all_contexts;
-static int parallel_nesting_level;
+static int taskreg_nesting_level;
 struct omp_region *root_omp_region;
+static bitmap task_shared_vars;
 
 static void scan_omp (tree *, omp_context *);
 static void lower_omp (tree *, omp_context *);
@@ -137,6 +154,25 @@ is_parallel_ctx (omp_context *ctx)
 }
 
 
+/* Return true if CTX is for an omp task.  */
+
+static inline bool
+is_task_ctx (omp_context *ctx)
+{
+  return TREE_CODE (ctx->stmt) == OMP_TASK;
+}
+
+
+/* Return true if CTX is for an omp parallel or omp task.  */
+
+static inline bool
+is_taskreg_ctx (omp_context *ctx)
+{
+  return TREE_CODE (ctx->stmt) == OMP_PARALLEL
+        || TREE_CODE (ctx->stmt) == OMP_TASK;
+}
+
+
 /* Return true if REGION is a combined parallel+workshare region.  */
 
 static inline bool
@@ -150,65 +186,28 @@ is_combined_parallel (struct omp_region *region)
    them into *FD.  */
 
 static void
-extract_omp_for_data (tree for_stmt, struct omp_for_data *fd)
+extract_omp_for_data (tree for_stmt, struct omp_for_data *fd,
+                     struct omp_for_data_loop *loops)
 {
-  tree t, var;
+  tree t, var, *collapse_iter, *collapse_count;
+  tree count = NULL_TREE, iter_type = long_integer_type_node;
+  struct omp_for_data_loop *loop;
+  int i;
+  struct omp_for_data_loop dummy_loop;
 
   fd->for_stmt = for_stmt;
   fd->pre = NULL;
-
-  t = OMP_FOR_INIT (for_stmt);
-  gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
-  fd->v = GIMPLE_STMT_OPERAND (t, 0);
-  gcc_assert (SSA_VAR_P (fd->v));
-  gcc_assert (TREE_CODE (TREE_TYPE (fd->v)) == INTEGER_TYPE);
-  var = TREE_CODE (fd->v) == SSA_NAME ? SSA_NAME_VAR (fd->v) : fd->v;
-  fd->n1 = GIMPLE_STMT_OPERAND (t, 1);
-
-  t = OMP_FOR_COND (for_stmt);
-  fd->cond_code = TREE_CODE (t);
-  gcc_assert (TREE_OPERAND (t, 0) == var);
-  fd->n2 = TREE_OPERAND (t, 1);
-  switch (fd->cond_code)
-    {
-    case LT_EXPR:
-    case GT_EXPR:
-      break;
-    case LE_EXPR:
-      fd->n2 = fold_build2 (PLUS_EXPR, TREE_TYPE (fd->n2), fd->n2,
-                          build_int_cst (TREE_TYPE (fd->n2), 1));
-      fd->cond_code = LT_EXPR;
-      break;
-    case GE_EXPR:
-      fd->n2 = fold_build2 (MINUS_EXPR, TREE_TYPE (fd->n2), fd->n2,
-                          build_int_cst (TREE_TYPE (fd->n2), 1));
-      fd->cond_code = GT_EXPR;
-      break;
-    default:
-      gcc_unreachable ();
-    }
-
-  t = OMP_FOR_INCR (fd->for_stmt);
-  gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
-  gcc_assert (GIMPLE_STMT_OPERAND (t, 0) == var);
-  t = GIMPLE_STMT_OPERAND (t, 1);
-  gcc_assert (TREE_OPERAND (t, 0) == var);
-  switch (TREE_CODE (t))
-    {
-    case PLUS_EXPR:
-      fd->step = TREE_OPERAND (t, 1);
-      break;
-    case MINUS_EXPR:
-      fd->step = TREE_OPERAND (t, 1);
<