c-cppbuiltin.c (c_cpp_builtins): Change _OPENMP value to 200805.
authorJakub Jelinek <jakub@redhat.com>
Fri, 6 Jun 2008 13:01:54 +0000 (15:01 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 6 Jun 2008 13:01:54 +0000 (15:01 +0200)
* c-cppbuiltin.c (c_cpp_builtins): Change _OPENMP value to
200805.
* langhooks.h (struct lang_hooks_for_decls): Add omp_finish_clause.
Add omp_private_outer_ref hook, add another argument to
omp_clause_default_ctor hook.
* langhooks-def.h (LANG_HOOKS_OMP_FINISH_CLAUSE): Define.
(LANG_HOOKS_OMP_PRIVATE_OUTER_REF): Define.
(LANG_HOOKS_OMP_CLAUSE_DEFAULT_CTOR): Change to
hook_tree_tree_tree_tree_null.
(LANG_HOOKS_DECLS): Add LANG_HOOKS_OMP_FINISH_CLAUSE and
LANG_HOOKS_OMP_PRIVATE_OUTER_REF.
* hooks.c (hook_tree_tree_tree_tree_null): New function.
* hooks.h (hook_tree_tree_tree_tree_null): New prototype.
* tree.def (OMP_TASK): New tree code.
* tree.h (OMP_TASK_COPYFN, OMP_TASK_ARG_SIZE, OMP_TASK_ARG_ALIGN,
OMP_CLAUSE_PRIVATE_OUTER_REF, OMP_CLAUSE_LASTPRIVATE_STMT,
OMP_CLAUSE_COLLAPSE_ITERVAR, OMP_CLAUSE_COLLAPSE_COUNT,
OMP_TASKREG_CHECK, OMP_TASKREG_BODY, OMP_TASKREG_CLAUSES,
OMP_TASKREG_FN, OMP_TASKREG_DATA_ARG, OMP_TASK_BODY,
OMP_TASK_CLAUSES, OMP_TASK_FN, OMP_TASK_DATA_ARG,
OMP_CLAUSE_COLLAPSE_EXPR): Define.
(enum omp_clause_default_kind): Add OMP_CLAUSE_DEFAULT_FIRSTPRIVATE.
(OMP_DIRECTIVE_P): Add OMP_TASK.
(OMP_CLAUSE_COLLAPSE, OMP_CLAUSE_UNTIED): New clause codes.
(OMP_CLAUSE_SCHEDULE_AUTO): New schedule kind.
* tree.c (omp_clause_code_name): Add OMP_CLAUSE_COLLAPSE
and OMP_CLAUSE_UNTIED entries.
(omp_clause_num_ops): Likewise.  Increase OMP_CLAUSE_LASTPRIVATE
num_ops to 2.
(walk_tree_1): Handle OMP_CLAUSE_COLLAPSE and OMP_CLAUSE_UNTIED.
Walk OMP_CLAUSE_LASTPRIVATE_STMT.
* tree-pretty-print.c (dump_omp_clause): Handle
OMP_CLAUSE_SCHEDULE_AUTO, OMP_CLAUSE_UNTIED, OMP_CLAUSE_COLLAPSE,
OMP_CLAUSE_DEFAULT_FIRSTPRIVATE.
(dump_generic_node): Handle OMP_TASK and collapsed OMP_FOR loops.
* c-omp.c (c_finish_omp_for): Allow pointer iterators.  Remove
warning about unsigned iterators.  Change decl/init/cond/incr
arguments to TREE_VECs, check arguments for all collapsed loops.
(c_finish_omp_taskwait): New function.
(c_split_parallel_clauses): Put OMP_CLAUSE_COLLAPSE clause to
ws_clauses.
* c-parser.c (c_parser_omp_for_loop): Parse collapsed loops.  Call
default_function_array_conversion on init.  Add par_clauses argument.
If decl is present in parallel's lastprivate clause, change it to
shared and add lastprivate clause for decl to OMP_FOR_CLAUSES.
Add clauses argument, on success set OMP_FOR_CLAUSES to it.  Look up
collapse count in clauses.
(c_parser_omp_for, c_parser_omp_parallel): Adjust
c_parser_omp_for_loop callers.
(OMP_FOR_CLAUSE_MASK): Add 1 << PRAGMA_OMP_CLAUSE_COLLAPSE.
(c_parser_pragma): Handle PRAGMA_OMP_TASKWAIT.
(c_parser_omp_clause_name): Handle collapse and untied clauses.
(c_parser_omp_clause_collapse, c_parser_omp_clause_untied): New
functions.
(c_parser_omp_clause_schedule): Handle schedule(auto).
Include correct location in the error message.
(c_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_COLLAPSE
and PRAGMA_OMP_CLAUSE_UNTIED.
(OMP_TASK_CLAUSE_MASK): Define.
(c_parser_omp_task, c_parser_omp_taskwait): New functions.
(c_parser_omp_construct): Handle PRAGMA_OMP_TASK.
* tree-nested.c (convert_nonlocal_omp_clauses,
convert_local_omp_clauses): Handle OMP_CLAUSE_LASTPRIVATE_STMT,
OMP_CLAUSE_REDUCTION_INIT, OMP_CLAUSE_REDUCTION_MERGE,
OMP_CLAUSE_COLLAPSE and OMP_CLAUSE_UNTIED.
Don't handle TREE_STATIC or DECL_EXTERNAL VAR_DECLs in
OMP_CLAUSE_DECL.
(conver_nonlocal_reference, convert_local_reference,
convert_call_expr): Handle OMP_TASK the same as OMP_PARALLEL.  Use
OMP_TASKREG_* macros rather than OMP_PARALLEL_*.
(walk_omp_for): Adjust for OMP_FOR_{INIT,COND,INCR} changes.
* tree-gimple.c (is_gimple_stmt): Handle OMP_TASK.
* c-tree.h (c_begin_omp_task, c_finish_omp_task): New prototypes.
* c-pragma.h (PRAGMA_OMP_TASK, PRAGMA_OMP_TASKWAIT): New.
(PRAGMA_OMP_CLAUSE_COLLAPSE, PRAGMA_OMP_CLAUSE_UNTIED): New.
* c-typeck.c (c_begin_omp_task, c_finish_omp_task): New functions.
(c_finish_omp_clauses): Handle OMP_CLAUSE_COLLAPSE and
OMP_CLAUSE_UNTIED.
* c-pragma.c (init_pragma): Init omp task and omp taskwait pragmas.
* c-common.h (c_finish_omp_taskwait): New prototype.
* gimple-low.c (lower_stmt): Handle OMP_TASK.
* tree-parloops.c (create_parallel_loop): Create 1 entry
vectors for OMP_FOR_{INIT,COND,INCR}.
* tree-cfg.c (remove_useless_stmts_1): Handle OMP_* containers.
(make_edges): Handle OMP_TASK.
* tree-ssa-operands.c (get_expr_operands): Handle collapsed OMP_FOR
loops, adjust for OMP_FOR_{INIT,COND,INCR} changes.
* tree-inline.c (estimate_num_insns_1): Handle OMP_TASK.
* builtin-types.def (BT_PTR_ULONGLONG, BT_PTR_FN_VOID_PTR_PTR,
BT_FN_BOOL_ULONGLONGPTR_ULONGLONGPTR,
BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULLPTR_ULLPTR,
BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULL_ULLPTR_ULLPTR,
BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT): New.
* omp-builtins.def (BUILT_IN_GOMP_TASK, BUILT_IN_GOMP_TASKWAIT,
BUILT_IN_GOMP_LOOP_ULL_STATIC_START,
BUILT_IN_GOMP_LOOP_ULL_DYNAMIC_START,
BUILT_IN_GOMP_LOOP_ULL_GUIDED_START,
BUILT_IN_GOMP_LOOP_ULL_RUNTIME_START,
BUILT_IN_GOMP_LOOP_ULL_ORDERED_STATIC_START,
BUILT_IN_GOMP_LOOP_ULL_ORDERED_DYNAMIC_START,
BUILT_IN_GOMP_LOOP_ULL_ORDERED_GUIDED_START,
BUILT_IN_GOMP_LOOP_ULL_ORDERED_RUNTIME_START,
BUILT_IN_GOMP_LOOP_ULL_STATIC_NEXT,
BUILT_IN_GOMP_LOOP_ULL_DYNAMIC_NEXT,
BUILT_IN_GOMP_LOOP_ULL_GUIDED_NEXT,
BUILT_IN_GOMP_LOOP_ULL_RUNTIME_NEXT,
BUILT_IN_GOMP_LOOP_ULL_ORDERED_STATIC_NEXT,
BUILT_IN_GOMP_LOOP_ULL_ORDERED_DYNAMIC_NEXT,
BUILT_IN_GOMP_LOOP_ULL_ORDERED_GUIDED_NEXT,
BUILT_IN_GOMP_LOOP_ULL_ORDERED_RUNTIME_NEXT): New builtins.
* gimplify.c (gimplify_omp_for): Allow pointer type for decl,
handle POINTER_PLUS_EXPR.  If loop counter has been replaced and
original iterator is present in lastprivate clause or if
collapse > 1, set OMP_CLAUSE_LASTPRIVATE_STMT.  Handle collapsed
OMP_FOR loops, adjust for OMP_FOR_{INIT,COND,INCR} changes.
(gimplify_expr): Handle OMP_SECTIONS_SWITCH and OMP_TASK.
(enum gimplify_omp_var_data): Add GOVD_PRIVATE_OUTER_REF.
(omp_notice_variable): Set GOVD_PRIVATE_OUTER_REF if needed,
if it is set, lookup var in outer contexts too.  Handle
OMP_CLAUSE_DEFAULT_FIRSTPRIVATE.  Handle vars that are supposed
to be implicitly determined firstprivate for task regions.
(gimplify_scan_omp_clauses): Set GOVD_PRIVATE_OUTER_REF if needed,
if it is set, lookup var in outer contexts too.  Set
OMP_CLAUSE_PRIVATE_OUTER_REF if GOVD_PRIVATE_OUTER_REF is set.
Handle OMP_CLAUSE_LASTPRIVATE_STMT, OMP_CLAUSE_COLLAPSE and
OMP_CLAUSE_UNTIED.  Take region_type as last argument
instead of in_parallel and in_combined_parallel.
(gimplify_omp_parallel, gimplify_omp_for, gimplify_omp_workshare):
Adjust callers.
(gimplify_adjust_omp_clauses_1): Set OMP_CLAUSE_PRIVATE_OUTER_REF if
GOVD_PRIVATE_OUTER_REF is set.  Call omp_finish_clause
langhook.
(new_omp_context): Set default_kind to
OMP_CLAUSE_DEFAULT_UNSPECIFIED for OMP_TASK regions.
(omp_region_type): New enum.
(struct gimplify_omp_ctx): Remove is_parallel and is_combined_parallel
fields, add region_type.
(new_omp_context): Take region_type as argument instead of is_parallel
and is_combined_parallel.
(gimple_add_tmp_var, omp_firstprivatize_variable, omp_notice_variable,
omp_is_private, omp_check_private): Adjust ctx->is_parallel and
ctx->is_combined_parallel checks.
(gimplify_omp_task): New function.
(gimplify_adjust_omp_clauses): Handle OMP_CLAUSE_COLLAPSE and
OMP_CLAUSE_UNTIED.
* omp-low.c (extract_omp_for_data): Use schedule(static)
for schedule(auto).  Handle pointer and unsigned iterators.
Compute fd->iter_type.  Handle POINTER_PLUS_EXPR increments.
Add loops argument.  Extract data for collapsed OMP_FOR loops.
(expand_parallel_call): Assert sched_kind isn't auto,
map runtime schedule to index 3.
(struct omp_for_data_loop): New type.
(struct omp_for_data): Remove v, n1, n2, step, cond_code fields.
Add loop, loops, collapse and iter_type fields.
(workshare_safe_to_combine_p): Disallow combined for if
iter_type is unsigned long long.  Don't combine collapse > 1 loops
unless all bounds and steps are constant.  Adjust extract_omp_for_data
caller.
(expand_omp_for_generic): Handle pointer, unsigned and long long
iterators.  Handle collapsed OMP_FOR loops.  Adjust
for struct omp_for_data changes.  If libgomp function doesn't return
boolean_type_node, add comparison of the return value with 0.
(expand_omp_for_static_nochunk, expand_omp_for_static_chunk): Handle
pointer, unsigned and long long iterators.  Adjust for struct
omp_for_data changes.
(expand_omp_for): Assert sched_kind isn't auto, map runtime schedule
to index 3.  Use GOMP_loop_ull*{start,next} if iter_type is
unsigned long long.  Allocate loops array, pass it to
extract_omp_for_data.  For collapse > 1 loops use always
expand_omp_for_generic.
(omp_context): Add sfield_map and srecord_type fields.
(is_task_ctx, lookup_sfield): New functions.
(use_pointer_for_field): Use is_task_ctx helper.  Change first
argument's type from const_tree to tree.  Clarify comment.
In OMP_TASK disallow copy-in/out sharing.
(build_sender_ref): Call lookup_sfield instead of lookup_field.
(install_var_field): Add mask argument.  Populate both record_type
and srecord_type if needed.
(delete_omp_context): Destroy sfield_map, clear DECL_ABSTRACT_ORIGIN
in srecord_type.
(fixup_child_record_type): Also remap FIELD_DECL's DECL_SIZE{,_UNIT}
and DECL_FIELD_OFFSET.
(scan_sharing_clauses): Adjust install_var_field callers.  For
firstprivate clauses on explicit tasks allocate the var by value in
record_type unconditionally, rather than by reference.
Handle OMP_CLAUSE_PRIVATE_OUTER_REF.  Scan OMP_CLAUSE_LASTPRIVATE_STMT.
Use is_taskreg_ctx instead of is_parallel_ctx.
Handle OMP_CLAUSE_COLLAPSE and OMP_CLAUSE_UNTIED.
(create_omp_child_function_name): Add task_copy argument, use
*_omp_cpyfn* names if it is true.
(create_omp_child_function): Add task_copy argument, if true create
*_omp_cpyfn* helper function.
(scan_omp_parallel): Adjust create_omp_child_function callers.
Rename parallel_nesting_level to taskreg_nesting_level.
(scan_omp_task): New function.
(lower_rec_input_clauses): Don't run constructors for firstprivate
explicit task vars which are initialized by *_omp_cpyfn*.
Pass outer var ref to omp_clause_default_ctor hook if
OMP_CLAUSE_PRIVATE_OUTER_REF or OMP_CLAUSE_LASTPRIVATE.
Replace OMP_CLAUSE_REDUCTION_PLACEHOLDER decls in
OMP_CLAUSE_REDUCTION_INIT.
(lower_send_clauses): Clear DECL_ABSTRACT_ORIGIN if in task to
avoid duplicate setting of fields.  Handle
OMP_CLAUSE_PRIVATE_OUTER_REF.
(lower_send_shared_vars): Use srecord_type if non-NULL.  Don't
copy-out if TREE_READONLY, only copy-in.
(expand_task_copyfn): New function.
(expand_task_call): New function.
(struct omp_taskcopy_context): New type.
(task_copyfn_copy_decl, task_copyfn_remap_type, create_task_copyfn):
New functions.
(lower_omp_parallel): Rename to...
(lower_omp_taskreg): ... this.  Use OMP_TASKREG_* macros where needed.
Call create_task_copyfn if srecord_type is needed.  Adjust
sender_decl type.
(task_shared_vars): New variable.
(check_omp_nesting_restrictions): Warn if work-sharing,
barrier, master or ordered region is closely nested inside OMP_TASK.
Add warnings for barrier if closely nested inside of work-sharing,
ordered, or master region.
(scan_omp_1): Call check_omp_nesting_restrictions even for
GOMP_barrier calls.  Rename parallel_nesting_level to
taskreg_nesting_level.  Handle OMP_TASK.
(lower_lastprivate_clauses): Even if some lastprivate is found on a
work-sharing construct, continue looking for them on parent parallel
construct.
(lower_omp_for_lastprivate): Add lastprivate clauses
to the beginning of dlist rather than end.  Adjust for struct
omp_for_data changes.
(lower_omp_for): Add rec input clauses before OMP_FOR_PRE_BODY,
not after it.  Handle collapsed OMP_FOR loops, adjust for
OMP_FOR_{INIT,COND,INCR} changes, adjust extract_omp_for_data
caller.
(get_ws_args_for): Adjust extract_omp_for_data caller.
(scan_omp_for): Handle collapsed OMP_FOR
loops, adjust for OMP_FOR_{INIT,COND,INCR} changes.
(lower_omp_single_simple): If libgomp function doesn't return
boolean_type_node, add comparison of the return value with 0.
(diagnose_sb_1, diagnose_sb_2): Handle collapsed OMP_FOR
loops, adjust for OMP_FOR_{INIT,COND,INCR} changes.  Handle OMP_TASK.
(parallel_nesting_level): Rename to...
(taskreg_nesting_level): ... this.
(is_taskreg_ctx): New function.
(build_outer_var_ref, omp_copy_decl): Use is_taskreg_ctx instead
of is_parallel_ctx.
(execute_lower_omp): Rename parallel_nesting_level to
taskreg_nesting_level.
(expand_omp_parallel): Rename to...
(expand_omp_taskreg): ... this.  Use OMP_TASKREG_* macros where needed.
Call omp_task_call for OMP_TASK regions.
(expand_omp): Adjust caller, handle OMP_TASK.
(lower_omp_1): Adjust lower_omp_taskreg caller, handle OMP_TASK.

* bitmap.c (bitmap_default_obstack_depth): New variable.
(bitmap_obstack_initialize, bitmap_obstack_release): Do nothing
if argument is NULL and bitmap_default_obstack is already initialized.
* ipa-struct-reorg.c (do_reorg_1): Call bitmap_obstack_release
at the end.
* matrix-reorg.c (matrix_reorg): Likewise.
cp/
* cp-tree.h (cxx_omp_finish_clause, cxx_omp_create_clause_info,
dependent_omp_for_p, begin_omp_task, finish_omp_task,
finish_omp_taskwait): New prototypes.
(cxx_omp_clause_default_ctor): Add outer argument.
(finish_omp_for): Add new clauses argument.
* cp-gimplify.c (cxx_omp_finish_clause): New function.
(cxx_omp_predetermined_sharing): Moved from semantics.c, rewritten.
(cxx_omp_clause_default_ctor): Add outer argument.
(cp_genericize_r): Walk OMP_CLAUSE_LASTPRIVATE_STMT.
* cp-objcp-common.h (LANG_HOOKS_OMP_FINISH_CLAUSE): Define.
* parser.c (cp_parser_omp_for_loop): Parse collapsed for loops.
Add par_clauses argument.  If decl is present in parallel's
lastprivate clause, change that clause to shared and add
a lastprivate clause for decl to OMP_FOR_CLAUSES.
Fix wording of error messages.  Adjust finish_omp_for caller.
Add clauses argument.  Parse loops with random access iterators.
(cp_parser_omp_clause_collapse, cp_parser_omp_clause_untied): New
functions.
(cp_parser_omp_for, cp_parser_omp_parallel): Adjust
cp_parser_omp_for_loop callers.
(cp_parser_omp_for_cond, cp_parser_omp_for_incr): New helper
functions.
(cp_parser_omp_clause_name): Handle collapse and untied
clauses.
(cp_parser_omp_clause_schedule): Handle auto schedule.
(cp_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_COLLAPSE
and PRAGMA_OMP_CLAUSE_UNTIED.
(OMP_FOR_CLAUSE_MASK): Add PRAGMA_OMP_CLAUSE_COLLAPSE.
(OMP_TASK_CLAUSE_MASK): Define.
(cp_parser_omp_task, cp_parser_omp_taskwait): New functions.
(cp_parser_omp_construct): Handle PRAGMA_OMP_TASK.
(cp_parser_pragma): Handle PRAGMA_OMP_TASK and
PRAGMA_OMP_TASKWAIT.
* pt.c (tsubst_omp_clauses): Handle OMP_CLAUSE_COLLAPSE and
OMP_CLAUSE_UNTIED.  Handle OMP_CLAUSE_LASTPRIVATE_STMT.
(tsubst_omp_for_iterator): New function.
(dependent_omp_for_p): New function.
(tsubst_expr) <case OMP_FOR>: Use it.  Handle collapsed OMP_FOR
loops.  Adjust finish_omp_for caller.  Handle loops with random
access iterators.  Adjust for OMP_FOR_{INIT,COND,INCR} changes.
(tsubst_expr): Handle OMP_TASK.
* semantics.c (cxx_omp_create_clause_info): New function.
(finish_omp_clauses): Call it.  Handle OMP_CLAUSE_UNTIED and
OMP_CLAUSE_COLLAPSE.
(cxx_omp_predetermined_sharing): Removed.
* semantics.c (finish_omp_for): Allow pointer iterators.  Use
handle_omp_for_class_iterator and dependent_omp_for_p.  Handle
collapsed for loops.  Adjust c_finish_omp_for caller.  Add new
clauses argument.  Fix check for type dependent cond or incr.
Set OMP_FOR_CLAUSES to clauses.  Use cp_convert instead of
fold_convert to convert incr amount to difference_type.  Only
fold if not in template.  If decl is mentioned in lastprivate
clause, set OMP_CLAUSE_LASTPRIVATE_STMT.  Handle loops with random
access iterators.  Adjust for OMP_FOR_{INIT,COND,INCR}
changes.
(finish_omp_threadprivate): Allow static class members of the
current class.
(handle_omp_for_class_iterator, begin_omp_task, finish_omp_task,
finish_omp_taskwait): New functions.

* parser.c (cp_parser_binary_expression): Add prec argument.
(cp_parser_assignment_expression): Adjust caller.
* cp-tree.h (outer_curly_brace_block): New prototype.
* decl.c (outer_curly_brace_block): No longer static.
fortran/
* scanner.c (skip_free_comments, skip_fixed_comments): Handle tabs.
* parse.c (next_free): Allow tab after !$omp.
(decode_omp_directive): Handle !$omp task, !$omp taskwait
and !$omp end task.
(case_executable): Add ST_OMP_TASKWAIT.
(case_exec_markers): Add ST_OMP_TASK.
(gfc_ascii_statement): Handle ST_OMP_TASK, ST_OMP_END_TASK and
ST_OMP_TASKWAIT.
(parse_omp_structured_block, parse_executable): Handle ST_OMP_TASK.
* gfortran.h (gfc_find_sym_in_expr): New prototype.
(gfc_statement): Add ST_OMP_TASK, ST_OMP_END_TASK and ST_OMP_TASKWAIT.
(gfc_omp_clauses): Add OMP_SCHED_AUTO to sched_kind,
OMP_DEFAULT_FIRSTPRIVATE to default_sharing.  Add collapse and
untied fields.
(gfc_exec_op): Add EXEC_OMP_TASK and EXEC_OMP_TASKWAIT.
* f95-lang.c (LANG_HOOKS_OMP_CLAUSE_COPY_CTOR,
LANG_HOOKS_OMP_CLAUSE_ASSIGN_OP, LANG_HOOKS_OMP_CLAUSE_DTOR,
LANG_HOOKS_OMP_PRIVATE_OUTER_REF): Define.
* trans.h (gfc_omp_clause_default_ctor): Add another argument.
(gfc_omp_clause_copy_ctor, gfc_omp_clause_assign_op,
gfc_omp_clause_dtor, gfc_omp_private_outer_ref): New prototypes.
* types.def (BT_ULONGLONG, BT_PTR_ULONGLONG,
BT_FN_BOOL_ULONGLONGPTR_ULONGLONGPTR,
BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULLPTR_ULLPTR,
BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULL_ULLPTR_ULLPTR,
BT_FN_VOID_PTR_PTR, BT_PTR_FN_VOID_PTR_PTR,
BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT): New.
(BT_BOOL): Use integer type with BOOL_TYPE_SIZE rather
than boolean_type_node.
* dump-parse-tree.c (gfc_show_omp_node): Handle EXEC_OMP_TASK,
EXEC_OMP_TASKWAIT, OMP_SCHED_AUTO, OMP_DEFAULT_FIRSTPRIVATE,
untied and collapse clauses.
(gfc_show_code_node): Handle EXEC_OMP_TASK and EXEC_OMP_TASKWAIT.
* trans.c (gfc_trans_code): Handle EXEC_OMP_TASK and
EXEC_OMP_TASKWAIT.
* st.c (gfc_free_statement): Likewise.
* resolve.c (gfc_resolve_blocks, resolve_code): Likewise.
(find_sym_in_expr): Rename to...
(gfc_find_sym_in_expr): ... this.  No longer static.
(resolve_allocate_expr, resolve_ordinary_assign): Adjust caller.
* match.h (gfc_match_omp_task, gfc_match_omp_taskwait): New
prototypes.
* openmp.c (resolve_omp_clauses): Allow allocatable arrays in
firstprivate, lastprivate, reduction, copyprivate and copyin
clauses.
(omp_current_do_code): Made static.
(omp_current_do_collapse): New variable.
(gfc_resolve_omp_do_blocks): Compute omp_current_do_collapse,
clear omp_current_do_code and omp_current_do_collapse on return.
(gfc_resolve_do_iterator): Handle collapsed do loops.
(resolve_omp_do): Likewise, diagnose errorneous collapsed do loops.
(OMP_CLAUSE_COLLAPSE, OMP_CLAUSE_UNTIED): Define.
(gfc_match_omp_clauses): Handle default (firstprivate),
schedule (auto), untied and collapse (n) clauses.
(OMP_DO_CLAUSES): Add OMP_CLAUSE_COLLAPSE.
(OMP_TASK_CLAUSES): Define.
(gfc_match_omp_task, gfc_match_omp_taskwait): New functions.
* trans-openmp.c (gfc_omp_private_outer_ref): New function.
(gfc_omp_clause_default_ctor): Add outer argument.  For allocatable
arrays allocate them with the bounds of the outer var if outer
var is allocated.
(gfc_omp_clause_copy_ctor, gfc_omp_clause_assign_op,
gfc_omp_clause_dtor): New functions.
(gfc_trans_omp_array_reduction): If decl is allocatable array,
allocate it with outer var's bounds in OMP_CLAUSE_REDUCTION_INIT
and deallocate it in OMP_CLAUSE_REDUCTION_MERGE.
(gfc_omp_predetermined_sharing): Return OMP_CLAUSE_DEFAULT_SHARED
for assumed-size arrays.
(gfc_trans_omp_do): Add par_clauses argument.  If dovar is
present in lastprivate clause and do loop isn't simple,
set OMP_CLAUSE_LASTPRIVATE_STMT.  If dovar is present in
parallel's lastprivate clause, change it to shared and add
lastprivate clause to OMP_FOR_CLAUSES.  Handle collapsed do loops.
(gfc_trans_omp_directive): Adjust gfc_trans_omp_do callers.
(gfc_trans_omp_parallel_do): Likewise.  Move collapse clause to
OMP_FOR from OMP_PARALLEL.
(gfc_trans_omp_clauses): Handle OMP_SCHED_AUTO,
OMP_DEFAULT_FIRSTPRIVATE, untied and collapse clauses.
(gfc_trans_omp_task, gfc_trans_omp_taskwait): New functions.
(gfc_trans_omp_directive): Handle EXEC_OMP_TASK and
EXEC_OMP_TASKWAIT.
gcc/testsuite/
* gcc.dg/gomp/collapse-1.c: New test.
* gcc.dg/gomp/nesting-1.c: New test.
* g++.dg/gomp/task-1.C: New test.
* g++.dg/gomp/predetermined-1.C: New test.
* g++.dg/gomp/tls-4.C: New test.
* gfortran.dg/gomp/collapse1.f90: New test.
* gfortran.dg/gomp/sharing-3.f90: New test.
* gcc.dg/gomp/pr27499.c (foo): Remove is unsigned dg-warning.
* g++.dg/gomp/pr27499.C (foo): Likewise.
* g++.dg/gomp/for-16.C (foo): Likewise.
* g++.dg/gomp/tls-3.C: Remove dg-error, add S::s definition.
* g++.dg/gomp/pr34607.C: Adjust dg-error location.
* g++.dg/gomp/for-16.C (foo): Add a new dg-error.
* gcc.dg/gomp/appendix-a/a.35.4.c: Add dg-warning.
* gcc.dg/gomp/appendix-a/a.35.6.c: Likewise.
* gfortran.dg/gomp/appendix-a/a.35.4.f90: Likewise.
* gfortran.dg/gomp/appendix-a/a.35.6.f90: Likewise.
* gfortran.dg/gomp/omp_parse1.f90: Remove !$omp tab test.
* gfortran.dg/gomp/appendix-a/a.33.4.f90: Remove dg-error
about allocatable array.
* gfortran.dg/gomp/reduction1.f90: Likewise.
libgomp/
* configure.ac (LIBGOMP_GNU_SYMBOL_VERSIONING): New AC_DEFINE.
Substitute also OMP_*LOCK_25*.
* configure: Regenerated.
* config.h.in: Regenerated.
* Makefile.am (libgomp_la_SOURCES): Add loop_ull.c, iter_ull.c,
ptrlock.c and task.c.
* Makefile.in: Regenerated.
* testsuite/Makefile.in: Regenerated.
* task.c: New file.
* loop_ull.c: New file.
* iter_ull.c: New file.
* libgomp.h: Include ptrlock.h.
(enum gomp_task_kind): New type.
(struct gomp_team): Add task_lock, task_queue, task_count,
task_running_count, single_count fields.  Add
work_share_list_free_lock ifndef HAVE_SYNC_BUILTINS.
Remove work_share_lock, generation_mask,
oldest_live_gen, num_live_gen and init_work_shares fields, add
work work_share_list_alloc, work_share_list_free and work_share_chunk
fields.  Change work_shares from pointer to pointers into an array.
Change ordered_release field into gomp_sem_t ** from flexible array
member.  Add implicit_task and initial_work_shares fields.
Move close to the end of the struct.
(struct gomp_team_state): Add single_count, last_work_share,
active_level and level fields, remove work_share_generation.
(gomp_barrier_handle_tasks): New prototype.
(gomp_finish_task): New inline function.
(struct gomp_work_share): Move chunk_size, end, incr into
transparent union/struct, add chunk_size_ull, end_ll, incr_ll and
next_ll fields.  Reshuffle fields.  Add next_alloc,
next_ws, next_free and inline_ordered_team_ids fields, change
ordered_team_ids into pointer from flexible array member.
Add mode field.  Put lock and next into a different cache line
from most of the write-once fields.
(gomp_iter_ull_static_next, gomp_iter_ull_dynamic_next_locked,
gomp_iter_ull_guided_next_locked, gomp_iter_ull_dynamic_next,
gomp_iter_ull_guided_next): New prototypes.
(gomp_new_icv): New prototype.
(struct gomp_thread): Add thread_pool and task fields.
(struct gomp_thread_pool): New type.
(gomp_new_team): New prototype.
(gomp_team_start): Change type of last argument.
(gomp_new_work_share): Removed.
(gomp_init_work_share, gomp_fini_work_share): New prototypes.
(gomp_work_share_init_done): New static inline.
(gomp_throttled_spin_count_var, gomp_available_cpus,
gomp_managed_threads): New extern decls.
(gomp_init_task): New prototype.
(gomp_spin_count_var): New extern var decl.
(LIBGOMP_GNU_SYMBOL_VERSIONING): Undef if no visibility
or no alias support, or if not PIC.
(gomp_init_lock_30, gomp_destroy_lock_30, gomp_set_lock_30,
gomp_unset_lock_30, gomp_test_lock_30, gomp_init_nest_lock_30,
gomp_destroy_nest_lock_30, gomp_set_nest_lock_30,
gomp_unset_nest_lock_30, gomp_test_nest_lock_30, gomp_init_lock_25,
gomp_destroy_lock_25, gomp_set_lock_25, gomp_unset_lock_25,
gomp_test_lock_25, gomp_init_nest_lock_25, gomp_destroy_nest_lock_25,
gomp_set_nest_lock_25, gomp_unset_nest_lock_25,
gomp_test_nest_lock_25): New prototypes.
(omp_lock_symver, strong_alias): Define.
(gomp_remaining_threads_count, gomp_remaining_threads_lock): New
decls.
(gomp_end_task): New.
(struct gomp_task_icv, gomp_global_icv): New.
(gomp_thread_limit_var, gomp_max_active_levels_var): New.
(struct gomp_task): New.
(gomp_nthreads_var, gomp_dyn_var, gomp_nest_var,
gomp_run_sched_var, gomp_run_sched_chunk): Remove.
(gomp_icv): New.
(gomp_schedule_type): Reorder enum to match
omp_sched_t.
* team.c (struct gomp_thread_start_data): Add thread_pool and task
fields.
(gomp_thread_start): Add gomp_team_barrier_wait call.
For non-nested case remove clearing of docked thread thr fields.
Use pool fields instead of global gomp_* variables.  Use
gomp_barrier_wait_last when needed.  Initialize ts.active_level.
Create tasks for each member thread.
(free_team): Only destroy team barrier, task_lock here and free it.
(gomp_free_thread): Free last_team if non-NULL.
(gomp_team_end): Call gomp_team_barrier_wait instead of
gomp_barrier_wait.  For nested case call one extra
gomp_barrier_wait.  Move here some destruction from free_team.
Call free_team on pool->last_team if any, rather than freeing
current team.  Destroy work_share_list_free_lock ifndef
HAVE_SYNC_BUILTINS.
(gomp_new_icv): New function.
(gomp_threads, gomp_threads_size, gomp_threads_used,
gomp_threads_dock): Removed.
(gomp_thread_destructor): New variable.
(gomp_new_thread_pool, gomp_free_pool_helper, gomp_free_thread): New
functions.
(gomp_team_start): Create new pool if current thread doesn't have
one.  Use pool fields instead of global gomp_* variables.
Initialize thread_pool field for new threads.  Clear single_count.
Change last argument from ws to team, don't create
new team, set ts.work_share to &team->work_shares[0] and clear
ts.last_work_share.  Don't clear ts.work_share_generation.
If number of threads changed, adjust atomically gomp_managed_threads.
Use gomp_init_task instead of gomp_new_task,
set thr->task to the corresponding implicit_task array entry.
Create tasks for each member thread.  Initialize ts.level.
(initialize_team): Call pthread_key_create on
gomp_thread_destructor.
(team_destructor): New function.
(new_team): Removed.
(gomp_new_team): New function.
(free_team): Free gomp_work_share blocks chained through next_alloc,
instead of freeing work_shares and destroying work_share_lock.
(gomp_team_end): Call gomp_fini_work_share.  If number of threads
changed, adjust atomically gomp_managed_threads.  Use gomp_end_task.
* barrier.c (GOMP_barrier): Call gomp_team_barrier_wait instead
of gomp_barrier_wait.
* single.c (GOMP_single_copy_start): Call gomp_team_barrier_wait
instead of gomp_barrier_wait.  Call gomp_work_share_init_done
if gomp_work_share_start returned true.  Don't unlock ws->lock.
(GOMP_single_copy_end): Call gomp_team_barrier_wait instead
of gomp_barrier_wait.
(GOMP_single_start): Rewritten if HAVE_SYNC_BUILTINS.  Call
gomp_work_share_init_done if gomp_work_share_start returned true.
Don't unlock ws->lock.
* work.c: Include stddef.h.
(free_work_share): Use work_share_list_free_lock instead
of atomic chaining ifndef HAVE_SYNC_BUILTINS.  Add team argument.
Call gomp_fini_work_share and then either free ws if orphaned, or
put it into work_share_list_free list of the current team.
(alloc_work_share, gomp_init_work_share, gomp_fini_work_share): New
functions.
(gomp_work_share_start, gomp_work_share_end,
gomp_work_share_end_nowait): Rewritten.
* omp_lib.f90.in Change some tabs to spaces to prevent warnings.
(openmp_version): Set to 200805.
(omp_sched_kind, omp_sched_static, omp_sched_dynamic,
omp_sched_guided, omp_sched_auto): New parameters.
(omp_set_schedule, omp_get_schedule, omp_get_thread_limit,
omp_set_max_active_levels, omp_get_max_active_levels,
omp_get_level, omp_get_ancestor_thread_num, omp_get_team_size,
omp_get_active_level): New interfaces.
* omp_lib.h.in (openmp_version): Set to 200805.
(omp_sched_kind, omp_sched_static, omp_sched_dynamic,
omp_sched_guided, omp_sched_auto): New parameters.
(omp_set_schedule, omp_get_schedule, omp_get_thread_limit,
omp_set_max_active_levels, omp_get_max_active_levels,
omp_get_level, omp_get_ancestor_thread_num, omp_get_team_size,
omp_get_active_level): New externals.
* loop.c: Include limits.h.
(GOMP_loop_runtime_next, GOMP_loop_ordered_runtime_next): Handle
GFS_AUTO.
(GOMP_loop_runtime_start, GOMP_loop_ordered_runtime_start):
Likewise.  Use gomp_icv.
(gomp_loop_static_start, gomp_loop_dynamic_start): Clear
ts.static_trip here.
(gomp_loop_static_start, gomp_loop_ordered_static_start): Call
gomp_work_share_init_done after gomp_loop_init.  Don't unlock ws->lock.
(gomp_loop_dynamic_start, gomp_loop_guided_start): Call
gomp_work_share_init_done after gomp_loop_init.  If HAVE_SYNC_BUILTINS,
don't unlock ws->lock, otherwise lock it.
(gomp_loop_ordered_dynamic_start, gomp_loop_ordered_guided_start): Call
gomp_work_share_init_done after gomp_loop_init.  Lock ws->lock.
(gomp_parallel_loop_start): Call gomp_new_team instead of
gomp_new_work_share.  Call gomp_loop_init on &team->work_shares[0].
Adjust gomp_team_start caller.  Pass 0 as second argument to
gomp_resolve_num_threads.
(gomp_loop_init): For GFS_DYNAMIC, multiply ws->chunk_size by incr.
If adding ws->chunk_size nthreads + 1 times after end won't
overflow, set ws->mode to 1.
* libgomp_g.h (GOMP_loop_ull_static_start, GOMP_loop_ull_dynamic_start,
GOMP_loop_ull_guided_start, GOMP_loop_ull_runtime_start,
GOMP_loop_ull_ordered_static_start,
GOMP_loop_ull_ordered_dynamic_start,
GOMP_loop_ull_ordered_guided_start,
GOMP_loop_ull_ordered_runtime_start, GOMP_loop_ull_static_next,
GOMP_loop_ull_dynamic_next, GOMP_loop_ull_guided_next,
GOMP_loop_ull_runtime_next, GOMP_loop_ull_ordered_static_next,
GOMP_loop_ull_ordered_dynamic_next, GOMP_loop_ull_ordered_guided_next,
GOMP_loop_ull_ordered_runtime_next, GOMP_task, GOMP_taskwait): New
prototypes.
* libgomp.map: Export lock routines also @@OMP_2.0.
(GOMP_loop_ordered_dynamic_first,
GOMP_loop_ordered_guided_first, GOMP_loop_ordered_runtime_first,
GOMP_loop_ordered_static_first): Remove.
(GOMP_loop_ull_dynamic_next, GOMP_loop_ull_dynamic_start,
GOMP_loop_ull_guided_next, GOMP_loop_ull_guided_start,
GOMP_loop_ull_ordered_dynamic_next,
GOMP_loop_ull_ordered_dynamic_start,
GOMP_loop_ull_ordered_guided_next,
GOMP_loop_ull_ordered_guided_start,
GOMP_loop_ull_ordered_runtime_next,
GOMP_loop_ull_ordered_runtime_start,
GOMP_loop_ull_ordered_static_next,
GOMP_loop_ull_ordered_static_start,
GOMP_loop_ull_runtime_next, GOMP_loop_ull_runtime_start,
GOMP_loop_ull_static_next, GOMP_loop_ull_static_start,
GOMP_task, GOMP_taskwait): Export @@GOMP_2.0.
(omp_set_schedule, omp_get_schedule,
omp_get_thread_limit, omp_set_max_active_levels,
omp_get_max_active_levels, omp_get_level,
omp_get_ancestor_thread_num, omp_get_team_size, omp_get_active_level,
omp_set_schedule_, omp_set_schedule_8_,
omp_get_schedule_, omp_get_schedule_8_, omp_get_thread_limit_,
omp_set_max_active_levels_, omp_set_max_active_levels_8_,
omp_get_max_active_levels_, omp_get_level_,
omp_get_ancestor_thread_num_, omp_get_ancestor_thread_num_8_,
omp_get_team_size_, omp_get_team_size_8_, omp_get_active_level_):
New exports @@OMP_3.0.
* omp.h.in (omp_sched_t): New type.
(omp_set_schedule, omp_get_schedule, omp_get_thread_limit,
omp_set_max_active_levels, omp_get_max_active_levels,
omp_get_level, omp_get_ancestor_thread_num, omp_get_team_size,
omp_get_active_level): New prototypes.
* env.c (gomp_spin_count_var, gomp_throttled_spin_count_var,
gomp_available_cpus, gomp_managed_threads, gomp_max_active_levels_var,
gomp_thread_limit_var, gomp_remaining_threads_count,
gomp_remaining_threads_lock): New variables.
(parse_spincount): New function.
(initialize_env): Call gomp_init_num_threads unconditionally.
Initialize gomp_available_cpus.  Call parse_spincount,
initialize gomp_{,throttled_}spin_count_var
depending on presence and value of OMP_WAIT_POLICY and
GOMP_SPINCOUNT env vars.  Handle GOMP_BLOCKTIME env var.
Handle OMP_WAIT_POLICY, OMP_MAX_ACTIVE_LEVELS,
OMP_THREAD_LIMIT, OMP_STACKSIZE env vars.  Handle unit specification
for GOMP_STACKSIZE.  Initialize gomp_remaining_threads_count and
gomp_remaining_threads_lock if needed.  Use gomp_global_icv.
(gomp_nthreads_var, gomp_dyn_var, gomp_nest_var,
gomp_run_sched_var, gomp_run_sched_chunk): Remove.
(gomp_global_icv): New.
(parse_schedule): Use it.  Parse "auto".
(omp_set_num_threads): Use gomp_icv.
(omp_set_dynamic, omp_get_dynamic, omp_set_nested, omp_get_nested):
Likewise.
(omp_get_max_threads): Move from parallel.c.
(omp_set_schedule, omp_get_schedule, omp_get_thread_limit,
omp_set_max_active_levels, omp_get_max_active_levels): New functions,
add ialias.
(parse_stacksize, parse_wait_policy): New functions.
* fortran.c: Rewrite lock wrappers, if symbol versioning provide
both wrappers for compatibility and new locks.
(omp_set_schedule, omp_get_schedule,
omp_get_thread_limit, omp_set_max_active_levels,
omp_get_max_active_levels, omp_get_level,
omp_get_ancestor_thread_num, omp_get_team_size,
omp_get_active_level): New ialias_redirect.
(omp_set_schedule_, omp_set_schedule_8_,
omp_get_schedule_, omp_get_schedule_8_, omp_get_thread_limit_,
omp_set_max_active_levels_, omp_set_max_active_levels_8_,
omp_get_max_active_levels_, omp_get_level_,
omp_get_ancestor_thread_num_, omp_get_ancestor_thread_num_8_,
omp_get_team_size_, omp_get_team_size_8_, omp_get_active_level_):
New functions.
* parallel.c: Include limits.h.
(gomp_resolve_num_threads): Add count argument.  Rewritten.
(GOMP_parallel_start): Call gomp_new_team and pass that as last
argument to gomp_team_start.  Pass 0 as second argument to
gomp_resolve_num_threads.
(GOMP_parallel_end): Decrease gomp_remaining_threads_count
if gomp_thread_limit_var != ULONG_MAX.
(omp_in_parallel): Implement using ts.active_level.
(omp_get_max_threads): Move to env.c.
(omp_get_level, omp_get_ancestor_thread_num,
omp_get_team_size, omp_get_active_level): New functions,
add ialias.
* sections.c (GOMP_sections_start): Call gomp_work_share_init_done
after gomp_sections_init.  If HAVE_SYNC_BUILTINS, call
gomp_iter_dynamic_next instead of the _locked variant and don't take
lock around it, otherwise acquire it before calling
gomp_iter_dynamic_next_locked.
(GOMP_sections_next): If HAVE_SYNC_BUILTINS, call
gomp_iter_dynamic_next instead of the _locked variant and don't take
lock around it.
(GOMP_parallel_sections_start): Call gomp_new_team instead of
gomp_new_work_share.  Call gomp_sections_init on &team->work_shares[0].
Adjust gomp_team_start caller.  Pass count as second argument to
gomp_resolve_num_threads, don't adjust num_threads after the call.
Use gomp_icv.
* iter.c (gomp_iter_dynamic_next_locked): Don't multiply
ws->chunk_size by incr.
(gomp_iter_dynamic_next): Likewise.  If ws->mode, use more efficient
code.
* libgomp_f.h.in (omp_lock_25_arg_t, omp_nest_lock_25_arg_t): New
types.
(omp_lock_25_arg, omp_nest_lock_25_arg): New macros.
(omp_check_defines): Check even the compat defines.
* config/linux/ptrlock.c: New file.
* config/linux/ptrlock.h: New file.
* config/linux/wait.h: New file.
* config/posix/ptrlock.c: New file.
* config/posix/ptrlock.h: New file.
* config/linux/bar.h (gomp_team_barrier_wait,
gomp_team_barrier_wait_end, gomp_team_barrier_wake): New prototypes.
(gomp_team_barrier_set_task_pending,
gomp_team_barrier_clear_task_pending,
gomp_team_barrier_set_waiting_for_tasks,
gomp_team_barrier_waiting_for_tasks,
gomp_team_barrier_done): New inlines.
(gomp_barrier_t): Rewritten.
(gomp_barrier_state_t): New typedef.
(gomp_barrier_init, gomp_barrier_reinit, gomp_barrier_destroy,
gomp_barrier_wait_start): Rewritten.
(gomp_barrier_wait_end): Change second argument to
gomp_barrier_state_t.
(gomp_barrier_last_thread, gomp_barrier_wait_last): New static
inlines.
* config/linux/bar.c: Include wait.h instead of libgomp.h and
futex.h.
(gomp_barrier_wait_end): Rewritten.
(gomp_team_barrier_wait, gomp_team_barrier_wait_end,
gomp_team_barrier_wake, gomp_barrier_wait_last): New functions.
* config/posix/bar.h (gomp_barrier_t): Add generation field.
(gomp_barrier_state_t): New typedef.
(gomp_team_barrier_wait,
gomp_team_barrier_wait_end, gomp_team_barrier_wake): New prototypes.
(gomp_barrier_wait_start): Or all but low 2 bits from generation
into the return value.  Return gomp_barrier_state_t.
(gomp_team_barrier_set_task_pending,
gomp_team_barrier_clear_task_pending,
gomp_team_barrier_set_waiting_for_tasks,
gomp_team_barrier_waiting_for_tasks,
gomp_team_barrier_done): New inlines.
(gomp_barrier_wait_end): Change second argument to
gomp_barrier_state_t.
(gomp_barrier_last_thread, gomp_barrier_wait_last): New static
inlines.
* config/posix/bar.c (gomp_barrier_init): Clear generation field.
(gomp_barrier_wait_end): Change second argument to
gomp_barrier_state_t.
(gomp_team_barrier_wait, gomp_team_barrier_wait_end,
gomp_team_barrier_wake): New functions.
* config/linux/mutex.c: Include wait.h instead of libgomp.h and
futex.h.
(gomp_futex_wake, gomp_futex_wait): New variables.
(gomp_mutex_lock_slow): Call do_wait instead of futex_wait.
* config/linux/lock.c: Rewrite to make locks task owned,
for backwards compatibility provide the old entrypoints
if symbol versioning.  Include wait.h instead of libgomp.h and
futex.h.
(gomp_set_nest_lock_25): Call do_wait instead of futex_wait.
* config/posix95/lock.c: Rewrite to make locks task owned,
for backwards compatibility provide the old entrypoints
if symbol versioning.
* config/posix/lock.c: Rewrite to make locks task owned,
for backwards compatibility provide the old entrypoints
if symbol versioning.
* config/linux/proc.c (gomp_init_num_threads): Use gomp_global_icv.
(get_num_procs, gomp_dynamic_max_threads): Use gomp_icv.
* config/posix/proc.c, config/mingw32/proc.c: Similarly.
* config/linux/powerpc/futex.h (FUTEX_WAIT, FUTEX_WAKE): Remove.
(sys_futex0): Return error code.
(futex_wake, futex_wait): If ENOSYS was returned, clear
FUTEX_PRIVATE_FLAG in gomp_futex_wa{ke,it} and retry.
(cpu_relax, atomic_write_barrier): New static inlines.
* config/linux/alpha/futex.h (FUTEX_WAIT, FUTEX_WAKE): Remove.
(futex_wake, futex_wait): If ENOSYS was returned, clear
FUTEX_PRIVATE_FLAG in gomp_futex_wa{ke,it} and retry.
(cpu_relax, atomic_write_barrier): New static inlines.
* config/linux/x86/futex.h (FUTEX_WAIT, FUTEX_WAKE): Remove.
(sys_futex0): Return error code.
(futex_wake, futex_wait): If ENOSYS was returned, clear
FUTEX_PRIVATE_FLAG in gomp_futex_wa{ke,it} and retry.
(cpu_relax, atomic_write_barrier): New static inlines.
* config/linux/s390/futex.h (FUTEX_WAIT, FUTEX_WAKE): Remove.
(sys_futex0): Return error code.
(futex_wake, futex_wait): If ENOSYS was returned, clear
FUTEX_PRIVATE_FLAG in gomp_futex_wa{ke,it} and retry.
(cpu_relax, atomic_write_barrier): New static inlines.
* config/linux/ia64/futex.h (FUTEX_WAIT, FUTEX_WAKE): Remove.
(sys_futex0): Return error code.
(futex_wake, futex_wait): If ENOSYS was returned, clear
FUTEX_PRIVATE_FLAG in gomp_futex_wa{ke,it} and retry.
(cpu_relax, atomic_write_barrier): New static inlines.
* config/linux/sparc/futex.h (FUTEX_WAIT, FUTEX_WAKE): Remove.
(sys_futex0): Return error code.
(futex_wake, futex_wait): If ENOSYS was returned, clear
FUTEX_PRIVATE_FLAG in gomp_futex_wa{ke,it} and retry.
(cpu_relax, atomic_write_barrier): New static inlines.
* config/linux/sem.c: Include wait.h instead of libgomp.h and
futex.h.
(gomp_sem_wait_slow): Call do_wait instead of futex_wait.
* config/linux/affinity.c: Assume HAVE_SYNC_BUILTINS.
* config/linux/omp-lock.h (omp_lock_25_t, omp_nest_lock_25_t): New
types.
(omp_nest_lock_t): Change owner into void *, add lock field.
* config/posix95/omp-lock.h: Include semaphore.h.
(omp_lock_25_t, omp_nest_lock_25_t): New types.
(omp_lock_t): Use sem_t instead of mutex if semaphores
aren't broken.
(omp_nest_lock_t): Likewise.  Change owner to void *.
* config/posix/omp-lock.h: Include semaphore.h.
(omp_lock_25_t, omp_nest_lock_25_t): New types.
(omp_lock_t): Use sem_t instead of mutex if semaphores
aren't broken.
(omp_nest_lock_t): Likewise.  Add owner field.

* testsuite/libgomp.c/collapse-1.c: New test.
* testsuite/libgomp.c/collapse-2.c: New test.
* testsuite/libgomp.c/collapse-3.c: New test.
* testsuite/libgomp.c/icv-1.c: New test.
* testsuite/libgomp.c/icv-2.c: New test.
* testsuite/libgomp.c/lib-2.c: New test.
* testsuite/libgomp.c/lock-1.c: New test.
* testsuite/libgomp.c/lock-2.c: New test.
* testsuite/libgomp.c/lock-3.c: New test.
* testsuite/libgomp.c/loop-4.c: New test.
* testsuite/libgomp.c/loop-5.c: New test.
* testsuite/libgomp.c/loop-6.c: New test.
* testsuite/libgomp.c/loop-7.c: New test.
* testsuite/libgomp.c/loop-8.c: New test.
* testsuite/libgomp.c/loop-9.c: New test.
* testsuite/libgomp.c/nested-3.c: New test.
* testsuite/libgomp.c/nestedfn-6.c: New test.
* testsuite/libgomp.c/sort-1.c: New test.
* testsuite/libgomp.c/task-1.c: New test.
* testsuite/libgomp.c/task-2.c: New test.
* testsuite/libgomp.c/task-3.c: New test.
* testsuite/libgomp.c/task-4.c: New test.
* testsuite/libgomp.c++/c++.exp: Add libstdc++-v3 build includes
to C++ testsuite default compiler options.
* testsuite/libgomp.c++/collapse-1.C: New test.
* testsuite/libgomp.c++/collapse-2.C: New test.
* testsuite/libgomp.c++/ctor-10.C: New test.
* testsuite/libgomp.c++/for-1.C: New test.
* testsuite/libgomp.c++/for-2.C: New test.
* testsuite/libgomp.c++/for-3.C: New test.
* testsuite/libgomp.c++/for-4.C: New test.
* testsuite/libgomp.c++/for-5.C: New test.
* testsuite/libgomp.c++/loop-8.C: New test.
* testsuite/libgomp.c++/loop-9.C: New test.
* testsuite/libgomp.c++/loop-10.C: New test.
* testsuite/libgomp.c++/task-1.C: New test.
* testsuite/libgomp.c++/task-2.C: New test.
* testsuite/libgomp.c++/task-3.C: New test.
* testsuite/libgomp.c++/task-4.C: New test.
* testsuite/libgomp.c++/task-5.C: New test.
* testsuite/libgomp.c++/task-6.C: New test.
* testsuite/libgomp.fortran/allocatable1.f90: New test.
* testsuite/libgomp.fortran/allocatable2.f90: New test.
* testsuite/libgomp.fortran/allocatable3.f90: New test.
* testsuite/libgomp.fortran/allocatable4.f90: New test.
* testsuite/libgomp.fortran/collapse1.f90: New test.
* testsuite/libgomp.fortran/collapse2.f90: New test.
* testsuite/libgomp.fortran/collapse3.f90: New test.
* testsuite/libgomp.fortran/collapse4.f90: New test.
* testsuite/libgomp.fortran/lastprivate1.f90: New test.
* testsuite/libgomp.fortran/lastprivate2.f90: New test.
* testsuite/libgomp.fortran/lib4.f90: New test.
* testsuite/libgomp.fortran/lock-1.f90: New test.
* testsuite/libgomp.fortran/lock-2.f90: New test.
* testsuite/libgomp.fortran/nested1.f90: New test.
* testsuite/libgomp.fortran/nestedfn4.f90: New test.
* testsuite/libgomp.fortran/strassen.f90: New test.
* testsuite/libgomp.fortran/tabs1.f90: New test.
* testsuite/libgomp.fortran/tabs2.f: New test.
* testsuite/libgomp.fortran/task1.f90: New test.
* testsuite/libgomp.fortran/task2.f90: New test.
* testsuite/libgomp.fortran/vla4.f90: Add dg-warning.
* testsuite/libgomp.fortran/vla5.f90: Likewise.
* testsuite/libgomp.c/pr26943-2.c: Likewise.
* testsuite/libgomp.c/pr26943-3.c: Likewise.
* testsuite/libgomp.c/pr26943-4.c: Likewise.

Co-Authored-By: Jakob Blomer <jakob.blomer@ira.uka.de>
Co-Authored-By: Richard Henderson <rth@redhat.com>
Co-Authored-By: Ulrich Drepper <drepper@redhat.com>
From-SVN: r136433

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 e4cc38734c0ae809a059d8291d310ac4b33e3922..ce1eae639916ae579f3e8b771b966e4194dc1679 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 c2a66f96a73f2e1bd9090b49b05f2ddd2f778c0b..97e60de6b3c1f631ea5be24b6651c0ba8405a929 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 25b5a0964f5ca7f97b38415828f323f58d16310d..7d25e5aad6da83e5ad86eb0ef6e6335981614fd6 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 7ad0be5a42548ecf79c98e4330dde9ec6e36317f..82c018b559f55cf644d0d93325fb1b972bf93748 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 5948fbd64f6f6d4014e5f949e01441dc9ebae14f..82bd5c27313e080d7a3605c89de5ea29e4b6584d 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 cdca2bcd4a9cf852b688629cff4608542534ba08..1da71d27b9c83902eb156be71703ce785288458c 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 d28ec9c91a9fa82bc16626f2ed0bcb9989df853c..7607a8dfdcfb5c8df4234f983570d8f3c74c5a69 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 44e95b81c0a0c92f9e17d31a367d1362e4353820..81b9910b41a9687e4685105b98660bfbd574a268 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 747a053b2e8cb71fb58f22bbeca4e197f5b62b28..188afb8dbaaee26fd02f568f02619a2415a675cc 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 02dfc6122d1be62986a56e8c7b7fa13a56033107..14df044437774d558ec68caef4154abedbf88aae 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 b52a349ac6fdb08578e73c94d616f99c9872b53e..23880d16a4377c442792405dab0d1b8e0a3eba82 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 54afddc98519bfe287aa36716ee7d12809d784d4..936db240b429eed4f7613e9672bc92c7f0be13dd 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 0948c790c41e3d7cf11bc33f4547312d32055b84..1d54e7cb43ecf69df6e41d66f6f30cf82672f507 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 cc3e8479921063334ada4d34bac171f48a7dbc69..c6d64dfbb752dc81e89f9d1170c24f500db83f20 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 b2b8405fccdb6d74b20ade50903de2b5d7975c05..1121eb0847949e32e6469940ae36e8a80d22136e 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 0c3d0dd21aab2a1100f0811ef0be1b5dca7a6cab..952020ad0457981cc7511c43318f9a5a680b1f39 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 0898d5d7fd2feccafc5c0c097df103fb0a182da2..8056518e746b7a440edc132635f01209bcf80448 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 c3383e6441e088974d9fa41ee61f83fecd5ea27f..5ca1bd7e5334dfa49543c3e220f9ca2eb9bebfd1 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 4bb43addb74b730e487781e54d38fe8f40b34503..f141b74a6fd4594ac9b175f72dcf610e8e812831 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 96999bf7e895625cf0c0e461b2b1745e35004f49..83d23394cb5baa7f3b31ee2861fe9d9bc9f313cf 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 826b40972f9bb5e980d91f14a1058c6777afca2c..5df5de5cf749d44c42fe1ebb0aee7ce661577a11 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 44a4941e7b422f2bf49f1bf5e2f62dfb1ba23fbf..80ff5bcecb70b6a5d00aa8b47f1b071a10abbdfb 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 63c380b61ea62053b77c0e6879466e6a57f9079f..42ab57a96067fcad69f615c5d5d3eb582cd9c30b 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 d4f9771e610e3d5737a1a3ecd43b2aa450d69d2c..8665a48c566540388e9f5b69ac452548f4cf9ed8 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 3f8d31074e835854442212f5ede280cdb8c88480..5ee91fb62dec8aff731c35a6bc09960fbe147dce 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 9c0bae497bf92f59821091d17cfa215f7850f39e..28f1cc24dfd4338315eebccf09d6cfa0bd79b830 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)
@@ -410,6 +450,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)
 {
@@ -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 33f13c92200734062929b67e12b63d0165f6d258..c35db2d9cf6745d0cfac26de25681e857b9db7cd 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 b5b76b6f7a04f83df0fef943fc3f83d63d234591..2787e293021d32e0c48cb154e74267b4aa79df6f 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 02d87b4f4cea8218d13a68f6c3cda815982cb51a..1b0eeca1e6593a59a654731161349ccdc558f6b8 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 0f0e4813d288801ed3a9da8153ac567f4a8e9fb8..abe7b94865c88f421c027ab8bbe26ac5a76946b9 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 c6c4baeca63cfc7d04b28634063697fd4db7611f..6f99800a0147f528a3faa72be365a7ef65e25eb4 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
@@ -1220,6 +1518,31 @@ gfc_trans_omp_single (gfc_code *code, gfc_omp_clauses *clauses)
   return stmt;
 }
 
+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)
 {
@@ -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 f303128a28d21edf3d3872bff32a52c61269c2b6..51e0cdd6aadf9e45e2cc2392edc03c0167578f46 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 d0ce235412072d6b876c0964529b2a555ae388e8..3a07d7127912f102a99032ea547aa980461335a2 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 22dcafd2397b1fd03cbf9854281c1b35bffde090..5bcdb5261d943ff880e9d7e00cddf06f16a0300f 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 fd1a19dfd3264b64b639271488f37a475b3f8f2e..99175d5b2f1ca6bf54402d77ec647d9dd5f26a6a 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 462e4a2cb85f3b543becd0185ae91a2423a186fa..0c2e5e244057127fc0f00810dbf57cde16e7db95 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 289275e84415d156fcb6619bff1c0eb0be525d88..50761b69ca551c5fe784afe45ec4224225bd83d4 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 838a4223fe31112310ec3eb446f8f9acb1ba4444..d6bbc4c2f07fa257f7c8b599e8b4f8dcc4f85ce4 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 908681dc12f454c239506fb575389cddd97566d0..cce9b3f6fc758cefb918b1f82663f8ee7d1b4b29 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 aae46406515b9bcd7b27214df11e6c8e425dc6fd..dd4916caff6fb9e6634eccd5897fd0b80f13230a 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 6a54b01f060362911358c51923e34942f9e8af37..1f64cf18d52c1f880b5137120ebe4de47dfb7055 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 eee4ddf322fecf297e02e5846abd4635e526ea4b..50ac7e87b0ba7ee6a0c9d32cd70c5815f452e2d6 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 cc450f6d4d628f2ebc775b1e6a9d7827c506dd66..5fd4f9aea75ea97320b0d77d6ba1fe4a51cadcbd 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 c608ae4521eae87eb313d1c68087c7bfdd2d4d86..e9223b2afb208747dbc70e75c1a2c039527d596b 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);
-      fd->step = fold_build1 (NEGATE_EXPR, TREE_TYPE (fd->step), fd->step);
-      break;
-    default:
-      gcc_unreachable ();
-    }
+  fd->collapse = TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt));
+  if (fd->collapse > 1)
+    fd->loops = loops;
+  else
+    fd->loops = &fd->loop;
 
   fd->have_nowait = fd->have_ordered = false;
   fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC;
   fd->chunk_size = NULL_TREE;
+  collapse_iter = NULL;
+  collapse_count = NULL;
 
   for (t = OMP_FOR_CLAUSES (for_stmt); t ; t = OMP_CLAUSE_CHAIN (t))
     switch (OMP_CLAUSE_CODE (t))
@@ -223,20 +222,223 @@ extract_omp_for_data (tree for_stmt, struct omp_for_data *fd)
        fd->sched_kind = OMP_CLAUSE_SCHEDULE_KIND (t);
        fd->chunk_size = OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (t);
        break;
+      case OMP_CLAUSE_COLLAPSE:
+       if (fd->collapse > 1)
+         {
+           collapse_iter = &OMP_CLAUSE_COLLAPSE_ITERVAR (t);
+           collapse_count = &OMP_CLAUSE_COLLAPSE_COUNT (t);
+         }
       default:
        break;
       }
 
+  /* FIXME: for now map schedule(auto) to schedule(static).
+     There should be analysis to determine whether all iterations
+     are approximately the same amount of work (then schedule(static)
+     is best) or if it varries (then schedule(dynamic,N) is better).  */
+  if (fd->sched_kind == OMP_CLAUSE_SCHEDULE_AUTO)
+    {
+      fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC;
+      gcc_assert (fd->chunk_size == NULL);
+    }
+  gcc_assert (fd->collapse == 1 || collapse_iter != NULL);
   if (fd->sched_kind == OMP_CLAUSE_SCHEDULE_RUNTIME)
     gcc_assert (fd->chunk_size == NULL);
   else if (fd->chunk_size == NULL)
     {
       /* We only need to compute a default chunk size for ordered
         static loops and dynamic loops.  */
-      if (fd->sched_kind != OMP_CLAUSE_SCHEDULE_STATIC || fd->have_ordered)
+      if (fd->sched_kind != OMP_CLAUSE_SCHEDULE_STATIC
+         || fd->have_ordered
+         || fd->collapse > 1)
        fd->chunk_size = (fd->sched_kind == OMP_CLAUSE_SCHEDULE_STATIC)
                         ? integer_zero_node : integer_one_node;
     }
+
+  for (i = 0; i < fd->collapse; i++)
+    {
+      if (fd->collapse == 1)
+       loop = &fd->loop;
+      else if (loops != NULL)
+       loop = loops + i;
+      else
+       loop = &dummy_loop;
+
+      t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i);
+      gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
+      loop->v = GIMPLE_STMT_OPERAND (t, 0);
+      gcc_assert (SSA_VAR_P (loop->v));
+      gcc_assert (TREE_CODE (TREE_TYPE (loop->v)) == INTEGER_TYPE
+                 || TREE_CODE (TREE_TYPE (loop->v)) == POINTER_TYPE);
+      var = TREE_CODE (loop->v) == SSA_NAME ? SSA_NAME_VAR (loop->v) : loop->v;
+      loop->n1 = GIMPLE_STMT_OPERAND (t, 1);
+
+      t = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), i);
+      loop->cond_code = TREE_CODE (t);
+      gcc_assert (TREE_OPERAND (t, 0) == var);
+      loop->n2 = TREE_OPERAND (t, 1);
+      switch (loop->cond_code)
+       {
+       case LT_EXPR:
+       case GT_EXPR:
+         break;
+       case LE_EXPR:
+         if (POINTER_TYPE_P (TREE_TYPE (loop->n2)))
+           loop->n2 = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (loop->n2),
+                                   loop->n2, size_one_node);
+         else
+           loop->n2 = fold_build2 (PLUS_EXPR, TREE_TYPE (loop->n2), loop->n2,
+                                   build_int_cst (TREE_TYPE (loop->n2), 1));
+         loop->cond_code = LT_EXPR;
+         break;
+       case GE_EXPR:
+         if (POINTER_TYPE_P (TREE_TYPE (loop->n2)))
+           loop->n2 = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (loop->n2),
+                                   loop->n2, size_int (-1));
+         else
+           loop->n2 = fold_build2 (MINUS_EXPR, TREE_TYPE (loop->n2), loop->n2,
+                                   build_int_cst (TREE_TYPE (loop->n2), 1));
+         loop->cond_code = GT_EXPR;
+         break;
+       default:
+         gcc_unreachable ();
+       }
+
+      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_OPERAND (t, 0) == var);
+      switch (TREE_CODE (t))
+       {
+       case PLUS_EXPR:
+       case POINTER_PLUS_EXPR:
+         loop->step = TREE_OPERAND (t, 1);
+         break;
+       case MINUS_EXPR:
+         loop->step = TREE_OPERAND (t, 1);
+         loop->step = fold_build1 (NEGATE_EXPR, TREE_TYPE (loop->step),
+                                   loop->step);
+         break;
+       default:
+         gcc_unreachable ();
+       }
+
+      if (iter_type != long_long_unsigned_type_node)
+       {
+         if (POINTER_TYPE_P (TREE_TYPE (loop->v)))
+           iter_type = long_long_unsigned_type_node;
+         else if (TYPE_UNSIGNED (TREE_TYPE (loop->v))
+                  && TYPE_PRECISION (TREE_TYPE (loop->v))
+                     >= TYPE_PRECISION (iter_type))
+           {
+             tree n;
+
+             if (loop->cond_code == LT_EXPR)
+               n = fold_build2 (PLUS_EXPR, TREE_TYPE (loop->v),
+                                loop->n2, loop->step);
+             else
+               n = loop->n1;
+             if (TREE_CODE (n) != INTEGER_CST
+                 || tree_int_cst_lt (TYPE_MAX_VALUE (iter_type), n))
+               iter_type = long_long_unsigned_type_node;
+           }
+         else if (TYPE_PRECISION (TREE_TYPE (loop->v))
+                  > TYPE_PRECISION (iter_type))
+           {
+             tree n1, n2;
+
+             if (loop->cond_code == LT_EXPR)
+               {
+                 n1 = loop->n1;
+                 n2 = fold_build2 (PLUS_EXPR, TREE_TYPE (loop->v),
+                                   loop->n2, loop->step);
+               }
+             else
+               {
+                 n1 = fold_build2 (MINUS_EXPR, TREE_TYPE (loop->v),
+                                   loop->n2, loop->step);
+                 n2 = loop->n1;
+               }
+             if (TREE_CODE (n1) != INTEGER_CST
+                 || TREE_CODE (n2) != INTEGER_CST
+                 || !tree_int_cst_lt (TYPE_MIN_VALUE (iter_type), n1)
+                 || !tree_int_cst_lt (n2, TYPE_MAX_VALUE (iter_type)))
+               iter_type = long_long_unsigned_type_node;
+           }
+       }
+
+      if (collapse_count && *collapse_count == NULL)
+       {
+         if ((i == 0 || count != NULL_TREE)
+             && TREE_CODE (TREE_TYPE (loop->v)) == INTEGER_TYPE
+             && TREE_CONSTANT (loop->n1)
+             && TREE_CONSTANT (loop->n2)
+             && TREE_CODE (loop->step) == INTEGER_CST)
+           {
+             tree itype = TREE_TYPE (loop->v);
+
+             if (POINTER_TYPE_P (itype))
+               itype
+                 = lang_hooks.types.type_for_size (TYPE_PRECISION (itype), 0);
+             t = build_int_cst (itype, (loop->cond_code == LT_EXPR ? -1 : 1));
+             t = fold_build2 (PLUS_EXPR, itype,
+                              fold_convert (itype, loop->step), t);
+             t = fold_build2 (PLUS_EXPR, itype, t,
+                              fold_convert (itype, loop->n2));
+             t = fold_build2 (MINUS_EXPR, itype, t,
+                              fold_convert (itype, loop->n1));
+             if (TYPE_UNSIGNED (itype) && loop->cond_code == GT_EXPR)
+               t = fold_build2 (TRUNC_DIV_EXPR, itype,
+                                fold_build1 (NEGATE_EXPR, itype, t),
+                                fold_build1 (NEGATE_EXPR, itype,
+                                             fold_convert (itype,
+                                                           loop->step)));
+             else
+               t = fold_build2 (TRUNC_DIV_EXPR, itype, t,
+                                fold_convert (itype, loop->step));
+             t = fold_convert (long_long_unsigned_type_node, t);
+             if (count != NULL_TREE)
+               count = fold_build2 (MULT_EXPR, long_long_unsigned_type_node,
+                                    count, t);
+             else
+               count = t;
+             if (TREE_CODE (count) != INTEGER_CST)
+               count = NULL_TREE;
+           }
+         else
+           count = NULL_TREE;
+       }
+    }
+
+  if (count)
+    {
+      if (!tree_int_cst_lt (count, TYPE_MAX_VALUE (long_integer_type_node)))
+       iter_type = long_long_unsigned_type_node;
+      else
+       iter_type = long_integer_type_node;
+    }
+  else if (collapse_iter && *collapse_iter != NULL)
+    iter_type = TREE_TYPE (*collapse_iter);
+  fd->iter_type = iter_type;
+  if (collapse_iter && *collapse_iter == NULL)
+    *collapse_iter = create_tmp_var (iter_type, ".iter");
+  if (collapse_count && *collapse_count == NULL)
+    {
+      if (count)
+       *collapse_count = fold_convert (iter_type, count);
+      else
+       *collapse_count = create_tmp_var (iter_type, ".count");
+    }
+
+  if (fd->collapse > 1)
+    {
+      fd->loop.v = *collapse_iter;
+      fd->loop.n1 = build_int_cst (TREE_TYPE (fd->loop.v), 0);
+      fd->loop.n2 = *collapse_count;
+      fd->loop.step = build_int_cst (TREE_TYPE (fd->loop.v), 1);
+      fd->loop.cond_code = LT_EXPR;
+    }
 }
 
 
@@ -296,16 +498,21 @@ workshare_safe_to_combine_p (basic_block par_entry_bb, basic_block ws_entry_bb)
 
   gcc_assert (TREE_CODE (ws_stmt) == OMP_FOR);
 
-  extract_omp_for_data (ws_stmt, &fd);
+  extract_omp_for_data (ws_stmt, &fd, NULL);
+
+  if (fd.collapse > 1 && TREE_CODE (fd.loop.n2) != INTEGER_CST)
+    return false;
+  if (fd.iter_type != long_integer_type_node)
+    return false;
 
   /* FIXME.  We give up too easily here.  If any of these arguments
      are not constants, they will likely involve variables that have
      been mapped into fields of .omp_data_s for sharing with the child
      function.  With appropriate data flow, it would be possible to
      see through this.  */
-  if (!is_gimple_min_invariant (fd.n1)
-      || !is_gimple_min_invariant (fd.n2)
-      || !is_gimple_min_invariant (fd.step)
+  if (!is_gimple_min_invariant (fd.loop.n1)
+      || !is_gimple_min_invariant (fd.loop.n2)
+      || !is_gimple_min_invariant (fd.loop.step)
       || (fd.chunk_size && !is_gimple_min_invariant (fd.chunk_size)))
     return false;
 
@@ -327,7 +534,7 @@ get_ws_args_for (tree ws_stmt)
       struct omp_for_data fd;
       tree ws_args;
 
-      extract_omp_for_data (ws_stmt, &fd);
+      extract_omp_for_data (ws_stmt, &fd, NULL);
 
       ws_args = NULL_TREE;
       if (fd.chunk_size)
@@ -336,13 +543,13 @@ get_ws_args_for (tree ws_stmt)
          ws_args = tree_cons (NULL, t, ws_args);
        }
 
-      t = fold_convert (long_integer_type_node, fd.step);
+      t = fold_convert (long_integer_type_node, fd.loop.step);
       ws_args = tree_cons (NULL, t, ws_args);
 
-      t = fold_convert (long_integer_type_node, fd.n2);
+      t = fold_convert (long_integer_type_node, fd.loop.n2);
       ws_args = tree_cons (NULL, t, ws_args);
 
-      t = fold_convert (long_integer_type_node, fd.n1);
+      t = fold_convert (long_integer_type_node, fd.loop.n1);
       ws_args = tree_cons (NULL, t, ws_args);
 
       return ws_args;
@@ -471,6 +678,16 @@ lookup_field (tree var, omp_context *ctx)
   return (tree) n->value;
 }
 
+static inline tree
+lookup_sfield (tree var, omp_context *ctx)
+{
+  splay_tree_node n;
+  n = splay_tree_lookup (ctx->sfield_map
+                        ? ctx->sfield_map : ctx->field_map,
+                        (splay_tree_key) var);
+  return (tree) n->value;
+}
+
 static inline tree
 maybe_lookup_field (tree var, omp_context *ctx)
 {
@@ -483,7 +700,7 @@ maybe_lookup_field (tree var, omp_context *ctx)
    the parallel context if DECL is to be shared.  */
 
 static bool
-use_pointer_for_field (const_tree decl, omp_context *shared_ctx)
+use_pointer_for_field (tree decl, omp_context *shared_ctx)
 {
   if (AGGREGATE_TYPE_P (TREE_TYPE (decl)))
     return true;
@@ -524,11 +741,11 @@ use_pointer_for_field (const_tree decl, omp_context *shared_ctx)
            if (maybe_lookup_decl (decl, up))
              break;
 
-         if (up && is_parallel_ctx (up))
+         if (up && is_taskreg_ctx (up))
            {
              tree c;
 
-             for (c = OMP_PARALLEL_CLAUSES (up->stmt);
+             for (c = OMP_TASKREG_CLAUSES (up->stmt);
                   c; c = OMP_CLAUSE_CHAIN (c))
                if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED
                    && OMP_CLAUSE_DECL (c) == decl)
@@ -538,6 +755,26 @@ use_pointer_for_field (const_tree decl, omp_context *shared_ctx)
                return true;
            }
        }
+
+      /* For tasks avoid using copy-in/out, unless they are readonly
+        (in which case just copy-in is used).  As tasks can be
+        deferred or executed in different thread, when GOMP_task
+        returns, the task hasn't necessarily terminated.  */
+      if (!TREE_READONLY (decl) && is_task_ctx (shared_ctx))
+       {
+         tree outer = maybe_lookup_decl_in_outer_ctx (decl, shared_ctx);
+         if (is_gimple_reg (outer))
+           {
+             /* Taking address of OUTER in lower_send_shared_vars
+                might need regimplification of everything that uses the
+                variable.  */
+             if (!task_shared_vars)
+               task_shared_vars = BITMAP_ALLOC (NULL);
+             bitmap_set_bit (task_shared_vars, DECL_UID (outer));
+             TREE_ADDRESSABLE (outer) = 1;
+           }
+         return true;
+       }
     }
 
   return false;
@@ -622,7 +859,7 @@ build_outer_var_ref (tree var, omp_context *ctx)
       x = build_outer_var_ref (x, ctx);
       x = build_fold_indirect_ref (x);
     }
-  else if (is_parallel_ctx (ctx))
+  else if (is_taskreg_ctx (ctx))
     {
       bool by_ref = use_pointer_for_field (var, NULL);
       x = build_receiver_ref (var, by_ref, ctx);
@@ -647,7 +884,7 @@ build_outer_var_ref (tree var, omp_context *ctx)
 static tree
 build_sender_ref (tree var, omp_context *ctx)
 {
-  tree field = lookup_field (var, ctx);
+  tree field = lookup_sfield (var, ctx);
   return build3 (COMPONENT_REF, TREE_TYPE (field),
                 ctx->sender_decl, field, NULL);
 }
@@ -655,15 +892,20 @@ build_sender_ref (tree var, omp_context *ctx)
 /* Add a new field for VAR inside the structure CTX->SENDER_DECL.  */
 
 static void
-install_var_field (tree var, bool by_ref, omp_context *ctx)
+install_var_field (tree var, bool by_ref, int mask, omp_context *ctx)
 {
-  tree field, type;
+  tree field, type, sfield = NULL_TREE;
 
-  gcc_assert (!splay_tree_lookup (ctx->field_map, (splay_tree_key) var));
+  gcc_assert ((mask & 1) == 0
+             || !splay_tree_lookup (ctx->field_map, (splay_tree_key) var));
+  gcc_assert ((mask & 2) == 0 || !ctx->sfield_map
+             || !splay_tree_lookup (ctx->sfield_map, (splay_tree_key) var));
 
   type = TREE_TYPE (var);
   if (by_ref)
     type = build_pointer_type (type);
+  else if ((mask & 3) == 1 && is_reference (var))
+    type = TREE_TYPE (type);
 
   field = build_decl (FIELD_DECL, DECL_NAME (var), type);
 
@@ -671,11 +913,57 @@ install_var_field (tree var, bool by_ref, omp_context *ctx)
      side effect of making dwarf2out ignore this member, so for helpful
      debugging we clear it later in delete_omp_context.  */
   DECL_ABSTRACT_ORIGIN (field) = var;
+  if (type == TREE_TYPE (var))
+    {
+      DECL_ALIGN (field) = DECL_ALIGN (var);
+      DECL_USER_ALIGN (field) = DECL_USER_ALIGN (var);
+      TREE_THIS_VOLATILE (field) = TREE_THIS_VOLATILE (var);
+    }
+  else
+    DECL_ALIGN (field) = TYPE_ALIGN (type);
 
-  insert_field_into_struct (ctx->record_type, field);
+  if ((mask & 3) == 3)
+    {
+      insert_field_into_struct (ctx->record_type, field);
+      if (ctx->srecord_type)
+       {
+         sfield = build_decl (FIELD_DECL, DECL_NAME (var), type);
+         DECL_ABSTRACT_ORIGIN (sfield) = var;
+         DECL_ALIGN (sfield) = DECL_ALIGN (field);
+         DECL_USER_ALIGN (sfield) = DECL_USER_ALIGN (field);
+         TREE_THIS_VOLATILE (sfield) = TREE_THIS_VOLATILE (field);
+         insert_field_into_struct (ctx->srecord_type, sfield);
+       }
+    }
+  else
+    {
+      if (ctx->srecord_type == NULL_TREE)
+       {
+         tree t;
+
+         ctx->srecord_type = lang_hooks.types.make_type (RECORD_TYPE);
+         ctx->sfield_map = splay_tree_new (splay_tree_compare_pointers, 0, 0);
+         for (t = TYPE_FIELDS (ctx->record_type); t ; t = TREE_CHAIN (t))
+           {
+             sfield = build_decl (FIELD_DECL, DECL_NAME (t), TREE_TYPE (t));
+             DECL_ABSTRACT_ORIGIN (sfield) = DECL_ABSTRACT_ORIGIN (t);
+             insert_field_into_struct (ctx->srecord_type, sfield);
+             splay_tree_insert (ctx->sfield_map,
+                                (splay_tree_key) DECL_ABSTRACT_ORIGIN (t),
+                                (splay_tree_value) sfield);
+           }
+       }
+      sfield = field;
+      insert_field_into_struct ((mask & 1) ? ctx->record_type
+                               : ctx->srecord_type, field);
+    }
 
-  splay_tree_insert (ctx->field_map, (splay_tree_key) var,
-                    (splay_tree_value) field);
+  if (mask & 1)
+    splay_tree_insert (ctx->field_map, (splay_tree_key) var,
+                      (splay_tree_value) field);
+  if ((mask & 2) && ctx->sfield_map)
+    splay_tree_insert (ctx->sfield_map, (splay_tree_key) var,
+                      (splay_tree_value) sfield);
 }
 
 static tree
@@ -740,7 +1028,7 @@ omp_copy_decl (tree var, copy_body_data *cb)
       return new_var;
     }
 
-  while (!is_parallel_ctx (ctx))
+  while (!is_taskreg_ctx (ctx))
     {
       ctx = ctx->outer;
       if (ctx == NULL)
@@ -912,6 +1200,8 @@ delete_omp_context (splay_tree_value value)
 
   if (ctx->field_map)
     splay_tree_delete (ctx->field_map);
+  if (ctx->sfield_map)
+    splay_tree_delete (ctx->sfield_map);
 
   /* We hijacked DECL_ABSTRACT_ORIGIN earlier.  We need to clear it before
      it produces corrupt debug information.  */
@@ -921,6 +1211,12 @@ delete_omp_context (splay_tree_value value)
       for (t = TYPE_FIELDS (ctx->record_type); t ; t = TREE_CHAIN (t))
        DECL_ABSTRACT_ORIGIN (t) = NULL;
     }
+  if (ctx->srecord_type)
+    {
+      tree t;
+      for (t = TYPE_FIELDS (ctx->srecord_type); t ; t = TREE_CHAIN (t))
+       DECL_ABSTRACT_ORIGIN (t) = NULL;
+    }
 
   XDELETE (ctx);
 }
@@ -955,6 +1251,9 @@ fixup_child_record_type (omp_context *ctx)
          DECL_CONTEXT (new_f) = type;
          TREE_TYPE (new_f) = remap_type (TREE_TYPE (f), &ctx->cb);
          TREE_CHAIN (new_f) = new_fields;
+         walk_tree (&DECL_SIZE (new_f), copy_body_r, &ctx->cb, NULL);
+         walk_tree (&DECL_SIZE_UNIT (new_f), copy_body_r, &ctx->cb, NULL);
+         walk_tree (&DECL_FIELD_OFFSET (new_f), copy_body_r, &ctx->cb, NULL);
          new_fields = new_f;
 
          /* Arrange to be able to look up the receiver field
@@ -986,26 +1285,28 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
        {
        case OMP_CLAUSE_PRIVATE:
          decl = OMP_CLAUSE_DECL (c);
-         if (!is_variable_sized (decl))
+         if (OMP_CLAUSE_PRIVATE_OUTER_REF (c))
+           goto do_private;
+         else if (!is_variable_sized (decl))
            install_var_local (decl, ctx);
          break;
 
        case OMP_CLAUSE_SHARED:
-         gcc_assert (is_parallel_ctx (ctx));
+         gcc_assert (is_taskreg_ctx (ctx));
          decl = OMP_CLAUSE_DECL (c);
          gcc_assert (!COMPLETE_TYPE_P (TREE_TYPE (decl))
                      || !is_variable_sized (decl));
-         by_ref = use_pointer_for_field (decl, ctx);
          /* Global variables don't need to be copied,
             the receiver side will use them directly.  */
          if (is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx)))
            break;
+         by_ref = use_pointer_for_field (decl, ctx);
          if (! TREE_READONLY (decl)
              || TREE_ADDRESSABLE (decl)
              || by_ref
              || is_reference (decl))
            {
-             install_var_field (decl, by_ref, ctx);
+             install_var_field (decl, by_ref, 3, ctx);
              install_var_local (decl, ctx);
              break;
            }
@@ -1025,13 +1326,26 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
          decl = OMP_CLAUSE_DECL (c);
        do_private:
          if (is_variable_sized (decl))
-           break;
-         else if (is_parallel_ctx (ctx)
-                  && ! is_global_var (maybe_lookup_decl_in_outer_ctx (decl,
-                                                                      ctx)))
            {
+             if (is_task_ctx (ctx))
+               install_var_field (decl, false, 1, ctx);
+             break;
+           }
+         else if (is_taskreg_ctx (ctx))
+           {
+             bool global
+               = is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx));
              by_ref = use_pointer_for_field (decl, NULL);
-             install_var_field (decl, by_ref, ctx);
+
+             if (is_task_ctx (ctx)
+                 && (global || by_ref || is_reference (decl)))
+               {
+                 install_var_field (decl, false, 1, ctx);
+                 if (!global)
+                   install_var_field (decl, by_ref, 2, ctx);
+               }
+             else if (!global)
+               install_var_field (decl, by_ref, 3, ctx);
            }
          install_var_local (decl, ctx);
          break;
@@ -1044,7 +1358,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
        case OMP_CLAUSE_COPYIN:
          decl = OMP_CLAUSE_DECL (c);
          by_ref = use_pointer_for_field (decl, NULL);
-         install_var_field (decl, by_ref, ctx);
+         install_var_field (decl, by_ref, 3, ctx);
          break;
 
        case OMP_CLAUSE_DEFAULT:
@@ -1060,6 +1374,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 
        case OMP_CLAUSE_NOWAIT:
        case OMP_CLAUSE_ORDERED:
+       case OMP_CLAUSE_COLLAPSE:
+       case OMP_CLAUSE_UNTIED:
          break;
 
        default:
@@ -1074,6 +1390,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
        case OMP_CLAUSE_LASTPRIVATE:
          /* Let the corresponding firstprivate clause create
             the variable.  */
+         if (OMP_CLAUSE_LASTPRIVATE_STMT (c))
+           scan_array_reductions = true;
          if (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c))
            break;
          /* FALLTHRU */
@@ -1106,6 +1424,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
        case OMP_CLAUSE_SCHEDULE:
        case OMP_CLAUSE_NOWAIT:
        case OMP_CLAUSE_ORDERED:
+       case OMP_CLAUSE_COLLAPSE:
+       case OMP_CLAUSE_UNTIED:
          break;
 
        default:
@@ -1121,6 +1441,9 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
          scan_omp (&OMP_CLAUSE_REDUCTION_INIT (c), ctx);
          scan_omp (&OMP_CLAUSE_REDUCTION_MERGE (c), ctx);
        }
+      else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
+              && OMP_CLAUSE_LASTPRIVATE_STMT (c))
+       scan_omp (&OMP_CLAUSE_LASTPRIVATE_STMT (c), ctx);
 }
 
 /* Create a new name for omp child function.  Returns an identifier.  */
@@ -1128,15 +1451,17 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 static GTY(()) unsigned int tmp_ompfn_id_num;
 
 static tree
-create_omp_child_function_name (void)
+create_omp_child_function_name (bool task_copy)
 {
   tree name = DECL_ASSEMBLER_NAME (current_function_decl);
   size_t len = IDENTIFIER_LENGTH (name);
   char *tmp_name, *prefix;
+  const char *suffix;
 
-  prefix = alloca (len + sizeof ("_omp_fn"));
+  suffix = task_copy ? "_omp_cpyfn" : "_omp_fn";
+  prefix = alloca (len + strlen (suffix) + 1);
   memcpy (prefix, IDENTIFIER_POINTER (name), len);
-  strcpy (prefix + len, "_omp_fn");
+  strcpy (prefix + len, suffix);
 #ifndef NO_DOT_IN_LABEL
   prefix[len] = '.';
 #elif !defined NO_DOLLAR_IN_LABEL
@@ -1150,17 +1475,24 @@ create_omp_child_function_name (void)
    yet, just the bare decl.  */
 
 static void
-create_omp_child_function (omp_context *ctx)
+create_omp_child_function (omp_context *ctx, bool task_copy)
 {
   tree decl, type, name, t;
 
-  name = create_omp_child_function_name ();
-  type = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
+  name = create_omp_child_function_name (task_copy);
+  if (task_copy)
+    type = build_function_type_list (void_type_node, ptr_type_node,
+                                    ptr_type_node, NULL_TREE);
+  else
+    type = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
 
   decl = build_decl (FUNCTION_DECL, name, type);
   decl = lang_hooks.decls.pushdecl (decl);
 
-  ctx->cb.dst_fn = decl;
+  if (!task_copy)
+    ctx->cb.dst_fn = decl;
+  else
+    OMP_TASK_COPYFN (ctx->stmt) = decl;
 
   TREE_STATIC (decl) = 1;
   TREE_USED (decl) = 1;
@@ -1183,7 +1515,19 @@ create_omp_child_function (omp_context *ctx)
   DECL_CONTEXT (t) = current_function_decl;
   TREE_USED (t) = 1;
   DECL_ARGUMENTS (decl) = t;
-  ctx->receiver_decl = t;
+  if (!task_copy)
+    ctx->receiver_decl = t;
+  else
+    {
+      t = build_decl (PARM_DECL, get_identifier (".omp_data_o"),
+                     ptr_type_node);
+      DECL_ARTIFICIAL (t) = 1;
+      DECL_ARG_TYPE (t) = ptr_type_node;
+      DECL_CONTEXT (t) = current_function_decl;
+      TREE_USED (t) = 1;
+      TREE_CHAIN (t) = DECL_ARGUMENTS (decl);
+      DECL_ARGUMENTS (decl) = t;
+    }
 
   /* Allocate memory for the function structure.  The call to 
      allocate_struct_function clobbers CFUN, so we need to restore
@@ -1214,7 +1558,7 @@ scan_omp_parallel (tree *stmt_p, omp_context *outer_ctx)
     }
 
   ctx = new_omp_context (*stmt_p, outer_ctx);
-  if (parallel_nesting_level > 1)
+  if (taskreg_nesting_level > 1)
     ctx->is_nested = true;
   ctx->field_map = splay_tree_new (splay_tree_compare_pointers, 0, 0);
   ctx->default_kind = OMP_CLAUSE_DEFAULT_SHARED;
@@ -1222,7 +1566,7 @@ scan_omp_parallel (tree *stmt_p, omp_context *outer_ctx)
   name = create_tmp_var_name (".omp_data_s");
   name = build_decl (TYPE_DECL, name, ctx->record_type);
   TYPE_NAME (ctx->record_type) = name;
-  create_omp_child_function (ctx);
+  create_omp_child_function (ctx, false);
   OMP_PARALLEL_FN (*stmt_p) = ctx->cb.dst_fn;
 
   scan_sharing_clauses (OMP_PARALLEL_CLAUSES (*stmt_p), ctx);
@@ -1237,6 +1581,84 @@ scan_omp_parallel (tree *stmt_p, omp_context *outer_ctx)
     }
 }
 
+/* Scan an OpenMP task directive.  */
+
+static void
+scan_omp_task (tree *stmt_p, omp_context *outer_ctx)
+{
+  omp_context *ctx;
+  tree name;
+
+  /* Ignore task directives with empty bodies.  */
+  if (optimize > 0
+      && empty_body_p (OMP_TASK_BODY (*stmt_p)))
+    {
+      *stmt_p = build_empty_stmt ();
+      return;
+    }
+
+  ctx = new_omp_context (*stmt_p, outer_ctx);
+  if (taskreg_nesting_level > 1)
+    ctx->is_nested = true;
+  ctx->field_map = splay_tree_new (splay_tree_compare_pointers, 0, 0);
+  ctx->default_kind = OMP_CLAUSE_DEFAULT_SHARED;
+  ctx->record_type = lang_hooks.types.make_type (RECORD_TYPE);
+  name = create_tmp_var_name (".omp_data_s");
+  name = build_decl (TYPE_DECL, name, ctx->record_type);
+  TYPE_NAME (ctx->record_type) = name;
+  create_omp_child_function (ctx, false);
+  OMP_TASK_FN (*stmt_p) = ctx->cb.dst_fn;
+
+  scan_sharing_clauses (OMP_TASK_CLAUSES (*stmt_p), ctx);
+
+  if (ctx->srecord_type)
+    {
+      name = create_tmp_var_name (".omp_data_a");
+      name = build_decl (TYPE_DECL, name, ctx->srecord_type);
+      TYPE_NAME (ctx->srecord_type) = name;
+      create_omp_child_function (ctx, true);
+    }
+
+  scan_omp (&OMP_TASK_BODY (*stmt_p), ctx);
+
+  if (TYPE_FIELDS (ctx->record_type) == NULL)
+    {
+      ctx->record_type = ctx->receiver_decl = NULL;
+      OMP_TASK_ARG_SIZE (*stmt_p)
+       = build_int_cst (long_integer_type_node, 0);
+      OMP_TASK_ARG_ALIGN (*stmt_p)
+       = build_int_cst (long_integer_type_node, 1);
+    }
+  else
+    {
+      tree *p, vla_fields = NULL_TREE, *q = &vla_fields;
+      /* Move VLA fields to the end.  */
+      p = &TYPE_FIELDS (ctx->record_type);
+      while (*p)
+       if (!TYPE_SIZE_UNIT (TREE_TYPE (*p))
+           || ! TREE_CONSTANT (TYPE_SIZE_UNIT (TREE_TYPE (*p))))
+         {
+           *q = *p;
+           *p = TREE_CHAIN (*p);
+           TREE_CHAIN (*q) = NULL_TREE;
+           q = &TREE_CHAIN (*q);
+         }
+       else
+         p = &TREE_CHAIN (*p);
+      *p = vla_fields;
+      layout_type (ctx->record_type);
+      fixup_child_record_type (ctx);
+      if (ctx->srecord_type)
+       layout_type (ctx->srecord_type);
+      OMP_TASK_ARG_SIZE (*stmt_p)
+       = fold_convert (long_integer_type_node,
+                       TYPE_SIZE_UNIT (ctx->record_type));
+      OMP_TASK_ARG_ALIGN (*stmt_p)
+       = build_int_cst (long_integer_type_node,
+                        TYPE_ALIGN_UNIT (ctx->record_type));
+    }
+}
+
 
 /* Scan an OpenMP loop directive.  */
 
@@ -1245,6 +1667,7 @@ scan_omp_for (tree *stmt_p, omp_context *outer_ctx)
 {
   omp_context *ctx;
   tree stmt;
+  int i;
 
   stmt = *stmt_p;
   ctx = new_omp_context (stmt, outer_ctx);
@@ -1252,9 +1675,12 @@ scan_omp_for (tree *stmt_p, omp_context *outer_ctx)
   scan_sharing_clauses (OMP_FOR_CLAUSES (stmt), ctx);
 
   scan_omp (&OMP_FOR_PRE_BODY (stmt), ctx);
-  scan_omp (&OMP_FOR_INIT (stmt), ctx);
-  scan_omp (&OMP_FOR_COND (stmt), ctx);
-  scan_omp (&OMP_FOR_INCR (stmt), ctx);
+  for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (stmt)); i++)
+    {
+      scan_omp (&TREE_VEC_ELT (OMP_FOR_INIT (stmt), i), ctx);
+      scan_omp (&TREE_VEC_ELT (OMP_FOR_COND (stmt), i), ctx);
+      scan_omp (&TREE_VEC_ELT (OMP_FOR_INCR (stmt), i), ctx);
+    }
   scan_omp (&OMP_FOR_BODY (stmt), ctx);
 }
 
@@ -1307,6 +1733,7 @@ check_omp_nesting_restrictions (tree t, omp_context *ctx)
     case OMP_FOR:
     case OMP_SECTIONS:
     case OMP_SINGLE:
+    case CALL_EXPR:
       for (; ctx != NULL; ctx = ctx->outer)
        switch (TREE_CODE (ctx->stmt))
          {
@@ -1315,8 +1742,17 @@ check_omp_nesting_restrictions (tree t, omp_context *ctx)
          case OMP_SINGLE:
          case OMP_ORDERED:
          case OMP_MASTER:
+         case OMP_TASK:
+           if (TREE_CODE (t) == CALL_EXPR)
+             {
+               warning (0, "barrier region may not be closely nested inside "
+                           "of work-sharing, critical, ordered, master or "
+                           "explicit task region");
+               return;
+             }
            warning (0, "work-sharing region may not be closely nested inside "
-                       "of work-sharing, critical, ordered or master region");
+                       "of work-sharing, critical, ordered, master or explicit "
+                       "task region");
            return;
          case OMP_PARALLEL:
            return;
@@ -1331,8 +1767,9 @@ check_omp_nesting_restrictions (tree t, omp_context *ctx)
          case OMP_FOR:
          case OMP_SECTIONS:
          case OMP_SINGLE:
+         case OMP_TASK:
            warning (0, "master region may not be closely nested inside "
-                       "of work-sharing region");
+                       "of work-sharing or explicit task region");
            return;
          case OMP_PARALLEL:
            return;
@@ -1345,8 +1782,9 @@ check_omp_nesting_restrictions (tree t, omp_context *ctx)
        switch (TREE_CODE (ctx->stmt))
          {
          case OMP_CRITICAL:
+         case OMP_TASK:
            warning (0, "ordered region may not be closely nested inside "
-                       "of critical region");
+                       "of critical or explicit task region");
            return;
          case OMP_FOR:
            if (find_omp_clause (OMP_CLAUSES (ctx->stmt),
@@ -1389,16 +1827,32 @@ scan_omp_1 (tree *tp, int *walk_subtrees, void *data)
     input_location = EXPR_LOCATION (t);
 
   /* Check the OpenMP nesting restrictions.  */
-  if (OMP_DIRECTIVE_P (t) && ctx != NULL)
-    check_omp_nesting_restrictions (t, ctx);
+  if (ctx != NULL)
+    {
+      if (OMP_DIRECTIVE_P (t))
+       check_omp_nesting_restrictions (t, ctx);
+      else if (TREE_CODE (t) == CALL_EXPR)
+       {
+         tree fndecl = get_callee_fndecl (t);
+         if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+             && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_GOMP_BARRIER)
+           check_omp_nesting_restrictions (t, ctx);
+       }
+    }
 
   *walk_subtrees = 0;
   switch (TREE_CODE (t))
     {
     case OMP_PARALLEL:
-      parallel_nesting_level++;
+      taskreg_nesting_level++;
       scan_omp_parallel (tp, ctx);
-      parallel_nesting_level--;
+      taskreg_nesting_level--;
+      break;
+
+    case OMP_TASK:
+      taskreg_nesting_level++;
+      scan_omp_task (tp, ctx);
+      taskreg_nesting_level--;
       break;
 
     case OMP_FOR:
@@ -1715,16 +2169,18 @@ lower_rec_input_clauses (tree clauses, tree *ilist, tree *dlist,
              if (pass == 0)
                continue;
 
-             ptr = DECL_VALUE_EXPR (new_var);
-             gcc_assert (TREE_CODE (ptr) == INDIRECT_REF);
-             ptr = TREE_OPERAND (ptr, 0);
-             gcc_assert (DECL_P (ptr));
-
-             x = TYPE_SIZE_UNIT (TREE_TYPE (new_var));
-             x = build_call_expr (built_in_decls[BUILT_IN_ALLOCA], 1, x);
-             x = fold_convert (TREE_TYPE (ptr), x);
-             x = build_gimple_modify_stmt (ptr, x);
-             gimplify_and_add (x, ilist);
+             if (c_kind != OMP_CLAUSE_FIRSTPRIVATE || !is_task_ctx (ctx))
+               {
+                 ptr = DECL_VALUE_EXPR (new_var);
+                 gcc_assert (TREE_CODE (ptr) == INDIRECT_REF);
+                 ptr = TREE_OPERAND (ptr, 0);
+                 gcc_assert (DECL_P (ptr));
+                 x = TYPE_SIZE_UNIT (TREE_TYPE (new_var));
+                 x = build_call_expr (built_in_decls[BUILT_IN_ALLOCA], 1, x);
+                 x = fold_convert (TREE_TYPE (ptr), x);
+                 x = build_gimple_modify_stmt (ptr, x);
+                 gimplify_and_add (x, ilist);
+               }
            }
          else if (is_reference (var))
            {
@@ -1740,7 +2196,12 @@ lower_rec_input_clauses (tree clauses, tree *ilist, tree *dlist,
                continue;
 
              x = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (new_var)));
-             if (TREE_CONSTANT (x))
+             if (c_kind == OMP_CLAUSE_FIRSTPRIVATE && is_task_ctx (ctx))
+               {
+                 x = build_receiver_ref (var, false, ctx);
+                 x = build_fold_addr_expr (x);
+               }
+             else if (TREE_CONSTANT (x))
                {
                  const char *name = NULL;
                  if (DECL_NAME (var))
@@ -1800,7 +2261,18 @@ lower_rec_input_clauses (tree clauses, tree *ilist, tree *dlist,
              /* FALLTHRU */
 
            case OMP_CLAUSE_PRIVATE:
-             x = lang_hooks.decls.omp_clause_default_ctor (c, new_var);
+             if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_PRIVATE)
+               x = build_outer_var_ref (var, ctx);
+             else if (OMP_CLAUSE_PRIVATE_OUTER_REF (c))
+               {
+                 if (is_task_ctx (ctx))
+                   x = build_receiver_ref (var, false, ctx);
+                 else
+                   x = build_outer_var_ref (var, ctx);
+               }
+             else
+               x = NULL;
+             x = lang_hooks.decls.omp_clause_default_ctor (c, new_var, x);
              if (x)
                gimplify_and_add (x, ilist);
              /* FALLTHRU */
@@ -1816,6 +2288,20 @@ lower_rec_input_clauses (tree clauses, tree *ilist, tree *dlist,
              break;
 
            case OMP_CLAUSE_FIRSTPRIVATE:
+             if (is_task_ctx (ctx))
+               {
+                 if (is_reference (var) || is_variable_sized (var))
+                   goto do_dtor;
+                 else if (is_global_var (maybe_lookup_decl_in_outer_ctx (var,
+                                                                         ctx))
+                          || use_pointer_for_field (var, NULL))
+                   {
+                     x = build_receiver_ref (var, false, ctx);
+                     SET_DECL_VALUE_EXPR (new_var, x);
+                     DECL_HAS_VALUE_EXPR_P (new_var) = 1;
+                     goto do_dtor;
+                   }
+               }
              x = build_outer_var_ref (var, ctx);
              x = lang_hooks.decls.omp_clause_copy_ctor (c, new_var, x);
              gimplify_and_add (x, ilist);
@@ -1833,8 +2319,16 @@ lower_rec_input_clauses (tree clauses, tree *ilist, tree *dlist,
            case OMP_CLAUSE_REDUCTION:
              if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
                {
+                 tree placeholder = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c);
+                 x = build_outer_var_ref (var, ctx);
+
+                 if (is_reference (var))
+                   x = build_fold_addr_expr (x);
+                 SET_DECL_VALUE_EXPR (placeholder, x);
+                 DECL_HAS_VALUE_EXPR_P (placeholder) = 1;
                  gimplify_and_add (OMP_CLAUSE_REDUCTION_INIT (c), ilist);
                  OMP_CLAUSE_REDUCTION_INIT (c) = NULL;
+                 DECL_HAS_VALUE_EXPR_P (placeholder) = 0;
                }
              else
                {
@@ -1879,9 +2373,10 @@ lower_rec_input_clauses (tree clauses, tree *ilist, tree *dlist,
 
 static void
 lower_lastprivate_clauses (tree clauses, tree predicate, tree *stmt_list,
-                           omp_context *ctx)
+                          omp_context *ctx)
 {
   tree sub_list, x, c;
+  bool par_clauses = false;
 
   /* Early exit if there are no lastprivate clauses.  */
   clauses = find_omp_clause (clauses, OMP_CLAUSE_LASTPRIVATE);
@@ -1901,25 +2396,47 @@ lower_lastprivate_clauses (tree clauses, tree predicate, tree *stmt_list,
                                 OMP_CLAUSE_LASTPRIVATE);
       if (clauses == NULL)
        return;
+      par_clauses = true;
     }
 
   sub_list = alloc_stmt_list ();
 
-  for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+  for (c = clauses; c ;)
     {
       tree var, new_var;
 
-      if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_LASTPRIVATE)
-       continue;
+      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE)
+       {
+         var = OMP_CLAUSE_DECL (c);
+         new_var = lookup_decl (var, ctx);
 
-      var = OMP_CLAUSE_DECL (c);
-      new_var = lookup_decl (var, ctx);
+         if (OMP_CLAUSE_LASTPRIVATE_STMT (c))
+           gimplify_and_add (OMP_CLAUSE_LASTPRIVATE_STMT (c), &sub_list);
+         OMP_CLAUSE_LASTPRIVATE_STMT (c) = NULL;
 
-      x = build_outer_var_ref (var, ctx);
-      if (is_reference (var))
-       new_var = build_fold_indirect_ref (new_var);
-      x = lang_hooks.decls.omp_clause_assign_op (c, x, new_var);
-      append_to_statement_list (x, &sub_list);
+         x = build_outer_var_ref (var, ctx);
+         if (is_reference (var))
+           new_var = build_fold_indirect_ref (new_var);
+         x = lang_hooks.decls.omp_clause_assign_op (c, x, new_var);
+         append_to_statement_list (x, &sub_list);
+       }
+      c = OMP_CLAUSE_CHAIN (c);
+      if (c == NULL && !par_clauses)
+       {
+         /* If this was a workshare clause, see if it had been combined
+            with its parallel.  In that case, continue looking for the
+            clauses also on the parallel statement itself.  */
+         if (is_parallel_ctx (ctx))
+           break;
+
+         ctx = ctx->outer;
+         if (ctx == NULL || !is_parallel_ctx (ctx))
+           break;
+
+         c = find_omp_clause (OMP_PARALLEL_CLAUSES (ctx->stmt),
+                              OMP_CLAUSE_LASTPRIVATE);
+         par_clauses = true;
+       }
     }
 
   if (predicate)
@@ -2071,6 +2588,10 @@ lower_send_clauses (tree clauses, tree *ilist, tree *olist, omp_context *ctx)
 
       switch (OMP_CLAUSE_CODE (c))
        {
+       case OMP_CLAUSE_PRIVATE:
+         if (OMP_CLAUSE_PRIVATE_OUTER_REF (c))
+           break;
+         continue;
        case OMP_CLAUSE_FIRSTPRIVATE:
        case OMP_CLAUSE_COPYIN:
        case OMP_CLAUSE_LASTPRIVATE:
@@ -2092,6 +2613,7 @@ lower_send_clauses (tree clauses, tree *ilist, tree *olist, omp_context *ctx)
 
       switch (OMP_CLAUSE_CODE (c))
        {
+       case OMP_CLAUSE_PRIVATE:
        case OMP_CLAUSE_FIRSTPRIVATE:
        case OMP_CLAUSE_COPYIN:
          do_in = true;
@@ -2105,7 +2627,11 @@ lower_send_clauses (tree clauses, tree *ilist, tree *olist, omp_context *ctx)
              do_in = true;
            }
          else
-           do_out = true;
+           {
+             do_out = true;
+             if (lang_hooks.decls.omp_private_outer_ref (val))
+               do_in = true;
+           }
          break;
 
        case OMP_CLAUSE_REDUCTION:
@@ -2123,6 +2649,8 @@ lower_send_clauses (tree clauses, tree *ilist, tree *olist, omp_context *ctx)
          x = by_ref ? build_fold_addr_expr (var) : var;
          x = build_gimple_modify_stmt (ref, x);
          gimplify_and_add (x, ilist);
+         if (is_task_ctx (ctx))
+           DECL_ABSTRACT_ORIGIN (TREE_OPERAND (ref, 1)) = NULL;
        }
 
       if (do_out)
@@ -2141,12 +2669,13 @@ lower_send_clauses (tree clauses, tree *ilist, tree *olist, omp_context *ctx)
 static void
 lower_send_shared_vars (tree *ilist, tree *olist, omp_context *ctx)
 {
-  tree var, ovar, nvar, f, x;
+  tree var, ovar, nvar, f, x, record_type;
 
   if (ctx->record_type == NULL)
     return;
 
-  for (f = TYPE_FIELDS (ctx->record_type); f ; f = TREE_CHAIN (f))
+  record_type = ctx->srecord_type ? ctx->srecord_type : ctx->record_type;
+  for (f = TYPE_FIELDS (record_type); f ; f = TREE_CHAIN (f))
     {
       ovar = DECL_ABSTRACT_ORIGIN (f);
       nvar = maybe_lookup_decl (ovar, ctx);
@@ -2171,9 +2700,12 @@ lower_send_shared_vars (tree *ilist, tree *olist, omp_context *ctx)
          x = build_gimple_modify_stmt (x, var);
          gimplify_and_add (x, ilist);
 
-         x = build_sender_ref (ovar, ctx);
-         x = build_gimple_modify_stmt (var, x);
-         gimplify_and_add (x, olist);
+         if (!TREE_READONLY (var))
+           {
+             x = build_sender_ref (ovar, ctx);
+             x = build_gimple_modify_stmt (var, x);
+             gimplify_and_add (x, olist);
+           }
        }
     }
 }
@@ -2203,8 +2735,11 @@ expand_parallel_call (struct omp_region *region, basic_block bb,
       switch (region->inner->type)
        {
        case OMP_FOR:
+         gcc_assert (region->inner->sched_kind != OMP_CLAUSE_SCHEDULE_AUTO);
          start_ix = BUILT_IN_GOMP_PARALLEL_LOOP_STATIC_START
-                    + region->inner->sched_kind;
+                    + (region->inner->sched_kind
+                       == OMP_CLAUSE_SCHEDULE_RUNTIME
+                       ? 3 : region->inner->sched_kind);
          break;
        case OMP_SECTIONS:
          start_ix = BUILT_IN_GOMP_PARALLEL_SECTIONS_START;
@@ -2347,6 +2882,80 @@ expand_parallel_call (struct omp_region *region, basic_block bb,
 }
 
 
+static void maybe_catch_exception (tree *stmt_p);
+
+
+/* Finalize task copyfn.  */
+
+static void
+expand_task_copyfn (tree task_stmt)
+{
+  struct function *child_cfun;
+  tree child_fn, old_fn;
+
+  child_fn = OMP_TASK_COPYFN (task_stmt);
+  child_cfun = DECL_STRUCT_FUNCTION (child_fn);
+
+  /* Inform the callgraph about the new function.  */
+  DECL_STRUCT_FUNCTION (child_fn)->curr_properties
+    = cfun->curr_properties;
+
+  old_fn = current_function_decl;
+  push_cfun (child_cfun);
+  current_function_decl = child_fn;
+  gimplify_body (&DECL_SAVED_TREE (child_fn), child_fn, false);
+  maybe_catch_exception (&BIND_EXPR_BODY (DECL_SAVED_TREE (child_fn)));
+  pop_cfun ();
+  current_function_decl = old_fn;
+
+  cgraph_add_new_function (child_fn, false);
+}
+
+/* Build the function call to GOMP_task to actually
+   generate the task operation.  BB is the block where to insert the code.  */
+
+static void
+expand_task_call (basic_block bb, tree entry_stmt)
+{
+  tree t, t1, t2, t3, flags, cond, c, clauses;
+  block_stmt_iterator si;
+
+  clauses = OMP_TASK_CLAUSES (entry_stmt);
+
+  if (OMP_TASK_COPYFN (entry_stmt))
+    expand_task_copyfn (entry_stmt);
+
+  c = find_omp_clause (clauses, OMP_CLAUSE_IF);
+  if (c)
+    cond = gimple_boolify (OMP_CLAUSE_IF_EXPR (c));
+  else
+    cond = boolean_true_node;
+
+  c = find_omp_clause (clauses, OMP_CLAUSE_UNTIED);
+  flags = build_int_cst (unsigned_type_node, (c ? 1 : 0));
+
+  si = bsi_last (bb);
+  t = OMP_TASK_DATA_ARG (entry_stmt);
+  if (t == NULL)
+    t2 = null_pointer_node;
+  else
+    t2 = build_fold_addr_expr (t);
+  t1 = build_fold_addr_expr (OMP_TASK_FN (entry_stmt));
+  t = OMP_TASK_COPYFN (entry_stmt);
+  if (t == NULL)
+    t3 = null_pointer_node;
+  else
+    t3 = build_fold_addr_expr (t);
+
+  t = build_call_expr (built_in_decls[BUILT_IN_GOMP_TASK], 7, t1, t2, t3,
+                      OMP_TASK_ARG_SIZE (entry_stmt),
+                      OMP_TASK_ARG_ALIGN (entry_stmt), cond, flags);
+
+  force_gimple_operand_bsi (&si, t, true, NULL_TREE,
+                           false, BSI_CONTINUE_LINKING);
+}
+
+
 /* If exceptions are enabled, wrap *STMT_P in a MUST_NOT_THROW catch
    handler.  This prevents programs from violating the structured
    block semantics with throws.  */
@@ -2460,10 +3069,12 @@ remove_exit_barriers (struct omp_region *region)
    calls.  These can't be declared as const functions, but
    within one parallel body they are constant, so they can be
    transformed there into __builtin_omp_get_{thread_num,num_threads} ()
-   which are declared const.  */
+   which are declared const.  Similarly for task body, except
+   that in untied task omp_get_thread_num () can change at any task
+   scheduling point.  */
 
 static void
-optimize_omp_library_calls (void)
+optimize_omp_library_calls (tree entry_stmt)
 {
   basic_block bb;
   block_stmt_iterator bsi;
@@ -2471,6 +3082,9 @@ optimize_omp_library_calls (void)
     = DECL_ASSEMBLER_NAME (built_in_decls [BUILT_IN_OMP_GET_THREAD_NUM]);
   tree num_thr_id
     = DECL_ASSEMBLER_NAME (built_in_decls [BUILT_IN_OMP_GET_NUM_THREADS]);
+  bool untied_task = (TREE_CODE (entry_stmt) == OMP_TASK
+                     && find_omp_clause (OMP_TASK_CLAUSES (entry_stmt),
+                                         OMP_CLAUSE_UNTIED) != NULL);
 
   FOR_EACH_BB (bb)
     for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
@@ -2488,7 +3102,13 @@ optimize_omp_library_calls (void)
            tree built_in;
 
            if (DECL_NAME (decl) == thr_num_id)
-             built_in = built_in_decls [BUILT_IN_OMP_GET_THREAD_NUM];
+             {
+               /* In #pragma omp task untied omp_get_thread_num () can change
+                  during the execution of the task region.  */
+               if (untied_task)
+                 continue;
+               built_in = built_in_decls [BUILT_IN_OMP_GET_THREAD_NUM];
+             }
            else if (DECL_NAME (decl) == num_thr_id)
              built_in = built_in_decls [BUILT_IN_OMP_GET_NUM_THREADS];
            else
@@ -2511,10 +3131,10 @@ optimize_omp_library_calls (void)
       }
 }
 
-/* Expand the OpenMP parallel directive starting at REGION.  */
+/* Expand the OpenMP parallel or task directive starting at REGION.  */
 
 static void
-expand_omp_parallel (struct omp_region *region)
+expand_omp_taskreg (struct omp_region *region)
 {
   basic_block entry_bb, exit_bb, new_bb;
   struct function *child_cfun;
@@ -2524,7 +3144,7 @@ expand_omp_parallel (struct omp_region *region)
   edge e;
 
   entry_stmt = last_stmt (region->entry);
-  child_fn = OMP_PARALLEL_FN (entry_stmt);
+  child_fn = OMP_TASKREG_FN (entry_stmt);
   child_cfun = DECL_STRUCT_FUNCTION (child_fn);
   /* If this function has been already instrumented, make sure
      the child function isn't instrumented again.  */
@@ -2549,7 +3169,8 @@ expand_omp_parallel (struct omp_region *region)
       entry_succ_e = single_succ_edge (entry_bb);
 
       si = bsi_last (entry_bb);
-      gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_PARALLEL);
+      gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_PARALLEL
+                 || TREE_CODE (bsi_stmt (si)) == OMP_TASK);
       bsi_remove (&si, true);
 
       new_bb = entry_bb;
@@ -2575,7 +3196,7 @@ expand_omp_parallel (struct omp_region *region)
         a function call that has been inlined, the original PARM_DECL
         .OMP_DATA_I may have been converted into a different local
         variable.  In which case, we need to keep the assignment.  */
-      if (OMP_PARALLEL_DATA_ARG (entry_stmt))
+      if (OMP_TASKREG_DATA_ARG (entry_stmt))
        {
          basic_block entry_succ_bb = single_succ (entry_bb);
          block_stmt_iterator si;
@@ -2594,7 +3215,7 @@ expand_omp_parallel (struct omp_region *region)
              STRIP_NOPS (arg);
              if (TREE_CODE (arg) == ADDR_EXPR
                  && TREE_OPERAND (arg, 0)
-                    == OMP_PARALLEL_DATA_ARG (entry_stmt))
+                    == OMP_TASKREG_DATA_ARG (entry_stmt))
                {
                  parcopy_stmt = stmt;
                  break;
@@ -2633,11 +3254,12 @@ expand_omp_parallel (struct omp_region *region)
       for (t = DECL_ARGUMENTS (child_fn); t; t = TREE_CHAIN (t))
        DECL_CONTEXT (t) = child_fn;
 
-      /* Split ENTRY_BB at OMP_PARALLEL so that it can be moved to the
-        child function.  */
+      /* Split ENTRY_BB at OMP_PARALLEL or OMP_TASK, so that it can be
+        moved to the child function.  */
       si = bsi_last (entry_bb);
       t = bsi_stmt (si);
-      gcc_assert (t && TREE_CODE (t) == OMP_PARALLEL);
+      gcc_assert (t && (TREE_CODE (t) == OMP_PARALLEL
+                       || TREE_CODE (t) == OMP_TASK));
       bsi_remove (&si, true);
       e = split_block (entry_bb, t);
       entry_bb = e->dest;
@@ -2677,7 +3299,7 @@ expand_omp_parallel (struct omp_region *region)
         fixed in a following pass.  */
       push_cfun (child_cfun);
       if (optimize)
-       optimize_omp_library_calls ();
+       optimize_omp_library_calls (entry_stmt);
       rebuild_cgraph_edges ();
 
       /* Some EH regions might become dead, see PR34608.  If
@@ -2701,7 +3323,10 @@ expand_omp_parallel (struct omp_region *region)
     }
   
   /* Emit a library call to launch the children threads.  */
-  expand_parallel_call (region, new_bb, entry_stmt, ws_args);
+  if (TREE_CODE (entry_stmt) == OMP_PARALLEL)
+    expand_parallel_call (region, new_bb, entry_stmt, ws_args);
+  else
+    expand_task_call (new_bb, entry_stmt);
   update_ssa (TODO_update_ssa_only_virtuals);
 }
 
@@ -2727,7 +3352,64 @@ expand_omp_parallel (struct omp_region *region)
     L3:
 
     If this is a combined omp parallel loop, instead of the call to
-    GOMP_loop_foo_start, we call GOMP_loop_foo_next.  */
+    GOMP_loop_foo_start, we call GOMP_loop_foo_next.
+
+    For collapsed loops, given parameters:
+      collapse(3)
+      for (V1 = N11; V1 cond1 N12; V1 += STEP1)
+       for (V2 = N21; V2 cond2 N22; V2 += STEP2)
+         for (V3 = N31; V3 cond3 N32; V3 += STEP3)
+           BODY;
+
+    we generate pseudocode
+
+       if (cond3 is <)
+         adj = STEP3 - 1;
+       else
+         adj = STEP3 + 1;
+       count3 = (adj + N32 - N31) / STEP3;
+       if (cond2 is <)
+         adj = STEP2 - 1;
+       else
+         adj = STEP2 + 1;
+       count2 = (adj + N22 - N21) / STEP2;
+       if (cond1 is <)
+         adj = STEP1 - 1;
+       else
+         adj = STEP1 + 1;
+       count1 = (adj + N12 - N11) / STEP1;
+       count = count1 * count2 * count3;
+       more = GOMP_loop_foo_start (0, count, 1, CHUNK, &istart0, &iend0);
+       if (more) goto L0; else goto L3;
+    L0:
+       V = istart0;
+       T = V;
+       V3 = N31 + (T % count3) * STEP3;
+       T = T / count3;
+       V2 = N21 + (T % count2) * STEP2;
+       T = T / count2;
+       V1 = N11 + T * STEP1;
+       iend = iend0;
+    L1:
+       BODY;
+       V += 1;
+       if (V < iend) goto L10; else goto L2;
+    L10:
+       V3 += STEP3;
+       if (V3 cond3 N32) goto L1; else goto L11;
+    L11:
+       V3 = N31;
+       V2 += STEP2;
+       if (V2 cond2 N22) goto L1; else goto L12;
+    L12:
+       V2 = N21;
+       V1 += STEP1;
+       goto L1;
+    L2:
+       if (GOMP_loop_foo_next (&istart0, &iend0)) goto L0; else goto L3;
+    L3:
+
+      */
 
 static void
 expand_omp_for_generic (struct omp_region *region,
@@ -2736,20 +3418,23 @@ expand_omp_for_generic (struct omp_region *region,
                        enum built_in_function next_fn)
 {
   tree type, istart0, iend0, iend, phi;
-  tree t, vmain, vback;
-  basic_block entry_bb, cont_bb, exit_bb, l0_bb, l1_bb;
+  tree t, vmain, vback, bias = NULL_TREE;
+  basic_block entry_bb, cont_bb, exit_bb, l0_bb, l1_bb, collapse_bb;
   basic_block l2_bb = NULL, l3_bb = NULL;
   block_stmt_iterator si;
   bool in_combined_parallel = is_combined_parallel (region);
   bool broken_loop = region->cont == NULL;
   edge e, ne;
+  tree *counts = NULL;
+  int i;
 
   gcc_assert (!broken_loop || !in_combined_parallel);
+  gcc_assert (fd->iter_type == long_integer_type_node
+             || !in_combined_parallel);
 
-  type = TREE_TYPE (fd->v);
-
-  istart0 = create_tmp_var (long_integer_type_node, ".istart0");
-  iend0 = create_tmp_var (long_integer_type_node, ".iend0");
+  type = TREE_TYPE (fd->loop.v);
+  istart0 = create_tmp_var (fd->iter_type, ".istart0");
+  iend0 = create_tmp_var (fd->iter_type, ".iend0");
   TREE_ADDRESSABLE (istart0) = 1;
   TREE_ADDRESSABLE (iend0) = 1;
   if (gimple_in_ssa_p (cfun))
@@ -2758,8 +3443,32 @@ expand_omp_for_generic (struct omp_region *region,
       add_referenced_var (iend0);
     }
 
+  /* See if we need to bias by LLONG_MIN.  */
+  if (fd->iter_type == long_long_unsigned_type_node
+      && TREE_CODE (type) == INTEGER_TYPE
+      && !TYPE_UNSIGNED (type))
+    {
+      tree n1, n2;
+
+      if (fd->loop.cond_code == LT_EXPR)
+       {
+         n1 = fd->loop.n1;
+         n2 = fold_build2 (PLUS_EXPR, type, fd->loop.n2, fd->loop.step);
+       }
+      else
+       {
+         n1 = fold_build2 (MINUS_EXPR, type, fd->loop.n2, fd->loop.step);
+         n2 = fd->loop.n1;
+       }
+      if (TREE_CODE (n1) != INTEGER_CST
+         || TREE_CODE (n2) != INTEGER_CST
+         || ((tree_int_cst_sgn (n1) < 0) ^ (tree_int_cst_sgn (n2) < 0)))
+       bias = fold_convert (fd->iter_type, TYPE_MIN_VALUE (type));
+    }
+
   entry_bb = region->entry;
   cont_bb = region->cont;
+  collapse_bb = NULL;
   gcc_assert (EDGE_COUNT (entry_bb->succs) == 2);
   gcc_assert (broken_loop
              || BRANCH_EDGE (entry_bb)->dest == FALLTHRU_EDGE (cont_bb)->dest);
@@ -2777,7 +3486,60 @@ expand_omp_for_generic (struct omp_region *region,
   exit_bb = region->exit;
 
   si = bsi_last (entry_bb);
+
   gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_FOR);
+  if (fd->collapse > 1)
+    {
+      /* collapsed loops need work for expansion in SSA form.  */
+      gcc_assert (!gimple_in_ssa_p (cfun));
+      counts = (tree *) alloca (fd->collapse * sizeof (tree));
+      for (i = 0; i < fd->collapse; i++)
+       {
+         tree itype = TREE_TYPE (fd->loops[i].v);
+
+         if (POINTER_TYPE_P (itype))
+           itype = lang_hooks.types.type_for_size (TYPE_PRECISION (itype), 0);
+         t = build_int_cst (itype, (fd->loops[i].cond_code == LT_EXPR
+                                    ? -1 : 1));
+         t = fold_build2 (PLUS_EXPR, itype,
+                          fold_convert (itype, fd->loops[i].step), t);
+         t = fold_build2 (PLUS_EXPR, itype, t,
+                          fold_convert (itype, fd->loops[i].n2));
+         t = fold_build2 (MINUS_EXPR, itype, t,
+                          fold_convert (itype, fd->loops[i].n1));
+         if (TYPE_UNSIGNED (itype) && fd->loops[i].cond_code == GT_EXPR)
+           t = fold_build2 (TRUNC_DIV_EXPR, itype,
+                            fold_build1 (NEGATE_EXPR, itype, t),
+                            fold_build1 (NEGATE_EXPR, itype,
+                                         fold_convert (itype,
+                                                       fd->loops[i].step)));
+         else
+           t = fold_build2 (TRUNC_DIV_EXPR, itype, t,
+                            fold_convert (itype, fd->loops[i].step));
+         t = fold_convert (type, t);
+         if (TREE_CODE (t) == INTEGER_CST)
+           counts[i] = t;
+         else
+           {
+             counts[i] = create_tmp_var (type, ".count");
+             t = build_gimple_modify_stmt (counts[i], t);
+             force_gimple_operand_bsi (&si, t, true, NULL_TREE,
+                                       true, BSI_SAME_STMT);
+           }
+         if (SSA_VAR_P (fd->loop.n2))
+           {
+             if (i == 0)
+               t = build_gimple_modify_stmt (fd->loop.n2, counts[0]);
+             else
+               {
+                 t = fold_build2 (MULT_EXPR, type, fd->loop.n2, counts[i]);
+                 t = build_gimple_modify_stmt (fd->loop.n2, t);
+               }
+             force_gimple_operand_bsi (&si, t, true, NULL_TREE,
+                                       true, BSI_SAME_STMT);
+           }
+       }
+    }
   if (in_combined_parallel)
     {
       /* In a combined parallel loop, emit a call to
@@ -2793,19 +3555,52 @@ expand_omp_for_generic (struct omp_region *region,
         GOMP_loop_foo_start in ENTRY_BB.  */
       t4 = build_fold_addr_expr (iend0);
       t3 = build_fold_addr_expr (istart0);
-      t2 = fold_convert (long_integer_type_node, fd->step);
-      t1 = fold_convert (long_integer_type_node, fd->n2);
-      t0 = fold_convert (long_integer_type_node, fd->n1);
-      if (fd->chunk_size)
+      t2 = fold_convert (fd->iter_type, fd->loop.step);
+      t1 = fold_convert (fd->iter_type, fd->loop.n2);
+      t0 = fold_convert (fd->iter_type, fd->loop.n1);
+      if (bias)
        {
-         t = fold_convert (long_integer_type_node, fd->chunk_size);
-         t = build_call_expr (built_in_decls[start_fn], 6,
-                              t0, t1, t2, t, t3, t4);
+         t1 = fold_build2 (PLUS_EXPR, fd->iter_type, t1, bias);
+         t0 = fold_build2 (PLUS_EXPR, fd->iter_type, t0, bias);
+       }
+      if (fd->iter_type == long_integer_type_node)
+       {
+         if (fd->chunk_size)
+           {
+             t = fold_convert (fd->iter_type, fd->chunk_size);
+             t = build_call_expr (built_in_decls[start_fn], 6,
+                                  t0, t1, t2, t, t3, t4);
+           }
+         else
+           t = build_call_expr (built_in_decls[start_fn], 5,
+                                t0, t1, t2, t3, t4);
        }
       else
-       t = build_call_expr (built_in_decls[start_fn], 5,
-                            t0, t1, t2, t3, t4);
+       {
+         tree t5;
+         tree c_bool_type;
+
+         /* The GOMP_loop_ull_*start functions have additional boolean
+            argument, true for < loops and false for > loops.
+            In Fortran, the C bool type can be different from
+            boolean_type_node.  */
+         c_bool_type = TREE_TYPE (TREE_TYPE (built_in_decls[start_fn]));
+         t5 = build_int_cst (c_bool_type,
+                             fd->loop.cond_code == LT_EXPR ? 1 : 0);
+         if (fd->chunk_size)
+           {
+             t = fold_convert (fd->iter_type, fd->chunk_size);
+             t = build_call_expr (built_in_decls[start_fn], 7,
+                                  t5, t0, t1, t2, t, t3, t4);
+           }
+         else
+           t = build_call_expr (built_in_decls[start_fn], 6,
+                                t5, t0, t1, t2, t3, t4);
+       }
     }
+  if (TREE_TYPE (t) != boolean_type_node)
+    t = fold_build2 (NE_EXPR, boolean_type_node,
+                    t, build_int_cst (TREE_TYPE (t), 0));
   t = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
                                true, BSI_SAME_STMT);
   t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
@@ -2816,17 +3611,57 @@ expand_omp_for_generic (struct omp_region *region,
 
   /* Iteration setup for sequential loop goes in L0_BB.  */
   si = bsi_start (l0_bb);
-  t = fold_convert (type, istart0);
+  if (bias)
+    t = fold_convert (type, fold_build2 (MINUS_EXPR, fd->iter_type,
+                                        istart0, bias));
+  else
+    t = fold_convert (type, istart0);
   t = force_gimple_operand_bsi (&si, t, false, NULL_TREE,
                                false, BSI_CONTINUE_LINKING);
-  t = build_gimple_modify_stmt (fd->v, t);
+  t = build_gimple_modify_stmt (fd->loop.v, t);
   bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
   if (gimple_in_ssa_p (cfun))
-    SSA_NAME_DEF_STMT (fd->v) = t;
+    SSA_NAME_DEF_STMT (fd->loop.v) = t;
 
-  t = fold_convert (type, iend0);
+  if (bias)
+    t = fold_convert (type, fold_build2 (MINUS_EXPR, fd->iter_type,
+                                        iend0, bias));
+  else
+    t = fold_convert (type, iend0);
   iend = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
                                   false, BSI_CONTINUE_LINKING);
+  if (fd->collapse > 1)
+    {
+      tree tem = create_tmp_var (type, ".tem");
+
+      t = build_gimple_modify_stmt (tem, fd->loop.v);
+      bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
+      for (i = fd->collapse - 1; i >= 0; i--)
+       {
+         tree vtype = TREE_TYPE (fd->loops[i].v), itype;
+         itype = vtype;
+         if (POINTER_TYPE_P (vtype))
+           itype = lang_hooks.types.type_for_size (TYPE_PRECISION (vtype), 0);
+         t = fold_build2 (TRUNC_MOD_EXPR, type, tem, counts[i]);
+         t = fold_convert (itype, t);
+         t = fold_build2 (MULT_EXPR, itype, t, fd->loops[i].step);
+         if (POINTER_TYPE_P (vtype))
+           t = fold_build2 (POINTER_PLUS_EXPR, vtype,
+                            fd->loops[i].n1, fold_convert (sizetype, t));
+         else
+           t = fold_build2 (PLUS_EXPR, itype, fd->loops[i].n1, t);
+         t = build_gimple_modify_stmt (fd->loops[i].v, t);
+         force_gimple_operand_bsi (&si, t, true, NULL_TREE,
+                                   false, BSI_CONTINUE_LINKING);
+         if (i != 0)
+           {
+             t = fold_build2 (TRUNC_DIV_EXPR, type, tem, counts[i]);
+             t = build_gimple_modify_stmt (tem, t);
+             force_gimple_operand_bsi (&si, t, true, NULL_TREE,
+                                       false, BSI_CONTINUE_LINKING);
+           }
+       }
+    }
 
   if (!broken_loop)
     {
@@ -2838,7 +3673,11 @@ expand_omp_for_generic (struct omp_region *region,
       vmain = TREE_OPERAND (t, 1);
       vback = TREE_OPERAND (t, 0);
 
-      t = fold_build2 (PLUS_EXPR, type, vmain, fd->step);
+      if (POINTER_TYPE_P (type))
+       t = fold_build2 (POINTER_PLUS_EXPR, type, vmain,
+                        fold_convert (sizetype, fd->loop.step));
+      else
+       t = fold_build2 (PLUS_EXPR, type, vmain, fd->loop.step);
       t = force_gimple_operand_bsi (&si, t, false, NULL_TREE,
                                    true, BSI_SAME_STMT);
       t = build_gimple_modify_stmt (vback, t);
@@ -2846,19 +3685,78 @@ expand_omp_for_generic (struct omp_region *region,
       if (gimple_in_ssa_p (cfun))
        SSA_NAME_DEF_STMT (vback) = t;
   
-      t = build2 (fd->cond_code, boolean_type_node, vback, iend);
+      t = build2 (fd->loop.cond_code, boolean_type_node, vback, iend);
       t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
       bsi_insert_before (&si, t, BSI_SAME_STMT);
 
       /* Remove OMP_CONTINUE.  */
       bsi_remove (&si, true);
 
+      if (fd->collapse > 1)
+       {
+         basic_block last_bb, bb;
+
+         last_bb = cont_bb;
+         for (i = fd->collapse - 1; i >= 0; i--)
+           {
+             tree vtype = TREE_TYPE (fd->loops[i].v);
+
+             bb = create_empty_bb (last_bb);
+             si = bsi_start (bb);
+
+             if (i < fd->collapse - 1)
+               {
+                 e = make_edge (last_bb, bb, EDGE_FALSE_VALUE);
+                 e->probability = REG_BR_PROB_BASE / 8;
+
+                 t = build_gimple_modify_stmt (fd->loops[i + 1].v,
+                                               fd->loops[i + 1].n1);
+                 force_gimple_operand_bsi (&si, t, true, NULL_TREE,
+                                           false, BSI_CONTINUE_LINKING);
+               }
+             else
+               collapse_bb = bb;
+
+             set_immediate_dominator (CDI_DOMINATORS, bb, last_bb);
+
+             if (POINTER_TYPE_P (vtype))
+               t = fold_build2 (POINTER_PLUS_EXPR, vtype,
+                                fd->loops[i].v,
+                                fold_convert (sizetype, fd->loops[i].step));
+             else
+               t = fold_build2 (PLUS_EXPR, vtype, fd->loops[i].v,
+                                fd->loops[i].step);
+             t = build_gimple_modify_stmt (fd->loops[i].v, t);
+             force_gimple_operand_bsi (&si, t, true, NULL_TREE,
+                                       false, BSI_CONTINUE_LINKING);
+
+             if (i > 0)
+               {
+                 t = fold_build2 (fd->loops[i].cond_code, boolean_type_node,
+                                  fd->loops[i].v, fd->loops[i].n2);
+                 t = force_gimple_operand_bsi (&si, t, false, NULL_TREE,
+                                               false, BSI_CONTINUE_LINKING);
+                 t = build3 (COND_EXPR, void_type_node, t,
+                             NULL_TREE, NULL_TREE);
+                 bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
+                 e = make_edge (bb, l1_bb, EDGE_TRUE_VALUE);
+                 e->probability = REG_BR_PROB_BASE * 7 / 8;
+               }
+             else
+               make_edge (bb, l1_bb, EDGE_FALLTHRU);
+             last_bb = bb;
+           }
+       }
+
       /* Emit code to get the next parallel iteration in L2_BB.  */
       si = bsi_start (l2_bb);
 
       t = build_call_expr (built_in_decls[next_fn], 2,
                           build_fold_addr_expr (istart0),
                           build_fold_addr_expr (iend0));
+      if (TREE_TYPE (t) != boolean_type_node)
+       t = fold_build2 (NE_EXPR, boolean_type_node,
+                        t, build_int_cst (TREE_TYPE (t), 0));
       t = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
                                    false, BSI_CONTINUE_LINKING);
       t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
@@ -2889,8 +3787,20 @@ expand_omp_for_generic (struct omp_region *region,
                 PHI_ARG_DEF_FROM_EDGE (phi, e));
       remove_edge (e);
 
-      find_edge (cont_bb, l1_bb)->flags = EDGE_TRUE_VALUE;
       make_edge (cont_bb, l2_bb, EDGE_FALSE_VALUE);
+      if (fd->collapse > 1)
+       {
+         e = find_edge (cont_bb, l1_bb);
+         remove_edge (e);
+         e = make_edge (cont_bb, collapse_bb, EDGE_TRUE_VALUE);
+       }
+      else
+       {
+         e = find_edge (cont_bb, l1_bb);
+         e->flags = EDGE_TRUE_VALUE;
+       }
+      e->probability = REG_BR_PROB_BASE * 7 / 8;
+      find_edge (cont_bb, l2_bb)->probability = REG_BR_PROB_BASE / 8;
       make_edge (l2_bb, l0_bb, EDGE_TRUE_VALUE);
 
       set_immediate_dominator (CDI_DOMINATORS, l2_bb,
@@ -2917,7 +3827,10 @@ expand_omp_for_generic (struct omp_region *region,
          adj = STEP - 1;
        else
          adj = STEP + 1;
-       n = (adj + N2 - N1) / STEP;
+       if ((__typeof (V)) -1 > 0 && cond is >)
+         n = -(adj + N2 - N1) / -STEP;
+       else
+         n = (adj + N2 - N1) / STEP;
        q = n / nthreads;
        q += (q * nthreads != n);
        s0 = q * threadid;
@@ -2938,12 +3851,14 @@ expand_omp_for_static_nochunk (struct omp_region *region,
                               struct omp_for_data *fd)
 {
   tree n, q, s0, e0, e, t, nthreads, threadid;
-  tree type, vmain, vback;
+  tree type, itype, vmain, vback;
   basic_block entry_bb, exit_bb, seq_start_bb, body_bb, cont_bb;
   basic_block fin_bb;
   block_stmt_iterator si;
 
-  type = TREE_TYPE (fd->v);
+  itype = type = TREE_TYPE (fd->loop.v);
+  if (POINTER_TYPE_P (type))
+    itype = lang_hooks.types.type_for_size (TYPE_PRECISION (type), 0);
 
   entry_bb = region->entry;
   cont_bb = region->cont;
@@ -2961,51 +3876,51 @@ expand_omp_for_static_nochunk (struct omp_region *region,
   gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_FOR);
 
   t = build_call_expr (built_in_decls[BUILT_IN_OMP_GET_NUM_THREADS], 0);
-  t = fold_convert (type, t);
+  t = fold_convert (itype, t);
   nthreads = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
                                       true, BSI_SAME_STMT);
   
   t = build_call_expr (built_in_decls[BUILT_IN_OMP_GET_THREAD_NUM], 0);
-  t = fold_convert (type, t);
+  t = fold_convert (itype, t);
   threadid = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
                                       true, BSI_SAME_STMT);
 
-  fd->n1 = force_gimple_operand_bsi (&si,
-                                    fold_convert (type, fd->n1),
-                                    true, NULL_TREE,
-                                    true, BSI_SAME_STMT);
-
-  fd->n2 = force_gimple_operand_bsi (&si,
-                                   fold_convert (type, fd->n2),
-                                   true, NULL_TREE,
-                                   true, BSI_SAME_STMT);
-
-  fd->step = force_gimple_operand_bsi (&si,
-                                      fold_convert (type, fd->step),
-                                      true, NULL_TREE,
-                                      true, BSI_SAME_STMT);
-
-  t = build_int_cst (type, (fd->cond_code == LT_EXPR ? -1 : 1));
-  t = fold_build2 (PLUS_EXPR, type, fd->step, t);
-  t = fold_build2 (PLUS_EXPR, type, t, fd->n2);
-  t = fold_build2 (MINUS_EXPR, type, t, fd->n1);
-  t = fold_build2 (TRUNC_DIV_EXPR, type, t, fd->step);
-  t = fold_convert (type, t);
+  fd->loop.n1
+    = force_gimple_operand_bsi (&si, fold_convert (type, fd->loop.n1),
+                               true, NULL_TREE, true, BSI_SAME_STMT);
+  fd->loop.n2
+    = force_gimple_operand_bsi (&si, fold_convert (itype, fd->loop.n2),
+                               true, NULL_TREE, true, BSI_SAME_STMT);
+  fd->loop.step
+    = force_gimple_operand_bsi (&si, fold_convert (itype, fd->loop.step),
+                               true, NULL_TREE, true, BSI_SAME_STMT);
+
+  t = build_int_cst (itype, (fd->loop.cond_code == LT_EXPR ? -1 : 1));
+  t = fold_build2 (PLUS_EXPR, itype, fd->loop.step, t);
+  t = fold_build2 (PLUS_EXPR, itype, t, fd->loop.n2);
+  t = fold_build2 (MINUS_EXPR, itype, t, fold_convert (itype, fd->loop.n1));
+  if (TYPE_UNSIGNED (itype) && fd->loop.cond_code == GT_EXPR)
+    t = fold_build2 (TRUNC_DIV_EXPR, itype,
+                    fold_build1 (NEGATE_EXPR, itype, t),
+                    fold_build1 (NEGATE_EXPR, itype, fd->loop.step));
+  else
+    t = fold_build2 (TRUNC_DIV_EXPR, itype, t, fd->loop.step);
+  t = fold_convert (itype, t);
   n = force_gimple_operand_bsi (&si, t, true, NULL_TREE, true, BSI_SAME_STMT);
 
-  t = fold_build2 (TRUNC_DIV_EXPR, type, n, nthreads);
+  t = fold_build2 (TRUNC_DIV_EXPR, itype, n, nthreads);
   q = force_gimple_operand_bsi (&si, t, true, NULL_TREE, true, BSI_SAME_STMT);
 
-  t = fold_build2 (MULT_EXPR, type, q, nthreads);
-  t = fold_build2 (NE_EXPR, type, t, n);
-  t = fold_build2 (PLUS_EXPR, type, q, t);
+  t = fold_build2 (MULT_EXPR, itype, q, nthreads);
+  t = fold_build2 (NE_EXPR, itype, t, n);
+  t = fold_build2 (PLUS_EXPR, itype, q, t);
   q = force_gimple_operand_bsi (&si, t, true, NULL_TREE, true, BSI_SAME_STMT);
 
-  t = build2 (MULT_EXPR, type, q, threadid);
+  t = build2 (MULT_EXPR, itype, q, threadid);
   s0 = force_gimple_operand_bsi (&si, t, true, NULL_TREE, true, BSI_SAME_STMT);
 
-  t = fold_build2 (PLUS_EXPR, type, s0, q);
-  t = fold_build2 (MIN_EXPR, type, t, n);
+  t = fold_build2 (PLUS_EXPR, itype, s0, q);
+  t = fold_build2 (MIN_EXPR, itype, t, n);
   e0 = force_gimple_operand_bsi (&si, t, true, NULL_TREE, true, BSI_SAME_STMT);
 
   t = build2 (GE_EXPR, boolean_type_node, s0, e0);
@@ -3018,19 +3933,27 @@ expand_omp_for_static_nochunk (struct omp_region *region,
   /* Setup code for sequential iteration goes in SEQ_START_BB.  */
   si = bsi_start (seq_start_bb);
 
-  t = fold_convert (type, s0);
-  t = fold_build2 (MULT_EXPR, type, t, fd->step);
-  t = fold_build2 (PLUS_EXPR, type, t, fd->n1);
+  t = fold_convert (itype, s0);
+  t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step);
+  if (POINTER_TYPE_P (type))
+    t = fold_build2 (POINTER_PLUS_EXPR, type, fd->loop.n1,
+                    fold_convert (sizetype, t));
+  else
+    t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1);
   t = force_gimple_operand_bsi (&si, t, false, NULL_TREE,
                                false, BSI_CONTINUE_LINKING);
-  t = build_gimple_modify_stmt (fd->v, t);
+  t = build_gimple_modify_stmt (fd->loop.v, t);
   bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
   if (gimple_in_ssa_p (cfun))
-    SSA_NAME_DEF_STMT (fd->v) = t;
+    SSA_NAME_DEF_STMT (fd->loop.v) = t;
 
-  t = fold_convert (type, e0);
-  t = fold_build2 (MULT_EXPR, type, t, fd->step);
-  t = fold_build2 (PLUS_EXPR, type, t, fd->n1);
+  t = fold_convert (itype, e0);
+  t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step);
+  if (POINTER_TYPE_P (type))
+    t = fold_build2 (POINTER_PLUS_EXPR, type, fd->loop.n1,
+                    fold_convert (sizetype, t));
+  else
+    t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1);
   e = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
                                false, BSI_CONTINUE_LINKING);
 
@@ -3041,7 +3964,11 @@ expand_omp_for_static_nochunk (struct omp_region *region,
   vmain = TREE_OPERAND (t, 1);
   vback = TREE_OPERAND (t, 0);
 
-  t = fold_build2 (PLUS_EXPR, type, vmain, fd->step);
+  if (POINTER_TYPE_P (type))
+    t = fold_build2 (POINTER_PLUS_EXPR, type, vmain,
+                    fold_convert (sizetype, fd->loop.step));
+  else
+    t = fold_build2 (PLUS_EXPR, type, vmain, fd->loop.step);
   t = force_gimple_operand_bsi (&si, t, false, NULL_TREE,
                                true, BSI_SAME_STMT);
   t = build_gimple_modify_stmt (vback, t);
@@ -3049,7 +3976,7 @@ expand_omp_for_static_nochunk (struct omp_region *region,
   if (gimple_in_ssa_p (cfun))
     SSA_NAME_DEF_STMT (vback) = t;
 
-  t = build2 (fd->cond_code, boolean_type_node, vback, e);
+  t = build2 (fd->loop.cond_code, boolean_type_node, vback, e);
   t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
   bsi_insert_before (&si, t, BSI_SAME_STMT);
 
@@ -3090,7 +4017,10 @@ expand_omp_for_static_nochunk (struct omp_region *region,
          adj = STEP - 1;
        else
          adj = STEP + 1;
-       n = (adj + N2 - N1) / STEP;
+       if ((__typeof (V)) -1 > 0 && cond is >)
+         n = -(adj + N2 - N1) / -STEP;
+       else
+         n = (adj + N2 - N1) / STEP;
        trip = 0;
        V = threadid * CHUNK * STEP + N1;  -- this extra definition of V is
                                              here so that V is defined
@@ -3113,17 +4043,20 @@ expand_omp_for_static_nochunk (struct omp_region *region,
 */
 
 static void
-expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd)
+expand_omp_for_static_chunk (struct omp_region *region,
+                            struct omp_for_data *fd)
 {
   tree n, s0, e0, e, t, phi, nphi, args;
   tree trip_var, trip_init, trip_main, trip_back, nthreads, threadid;
-  tree type, cont, v_main, v_back, v_extra;
+  tree type, itype, cont, v_main, v_back, v_extra;
   basic_block entry_bb, exit_bb, body_bb, seq_start_bb, iter_part_bb;
   basic_block trip_update_bb, cont_bb, fin_bb;
   block_stmt_iterator si;
   edge se, re, ene;
 
-  type = TREE_TYPE (fd->v);
+  itype = type = TREE_TYPE (fd->loop.v);
+  if (POINTER_TYPE_P (type))
+    itype = lang_hooks.types.type_for_size (TYPE_PRECISION (type), 0);
 
   entry_bb = region->entry;
   se = split_block (entry_bb, last_stmt (entry_bb));
@@ -3146,40 +4079,43 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd)
   gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_FOR);
 
   t = build_call_expr (built_in_decls[BUILT_IN_OMP_GET_NUM_THREADS], 0);
-  t = fold_convert (type, t);
+  t = fold_convert (itype, t);
   nthreads = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
                                       true, BSI_SAME_STMT);
   
   t = build_call_expr (built_in_decls[BUILT_IN_OMP_GET_THREAD_NUM], 0);
-  t = fold_convert (type, t);
+  t = fold_convert (itype, t);
   threadid = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
                                       true, BSI_SAME_STMT);
 
-  fd->n1 = force_gimple_operand_bsi (&si, fold_convert (type, fd->n1),
-                                    true, NULL_TREE,
-                                    true, BSI_SAME_STMT);
-  fd->n2 = force_gimple_operand_bsi (&si, fold_convert (type, fd->n2),
-                                    true, NULL_TREE,
-                                    true, BSI_SAME_STMT);
-  fd->step = force_gimple_operand_bsi (&si, fold_convert (type, fd->step),
-                                      true, NULL_TREE,
-                                      true, BSI_SAME_STMT);
+  fd->loop.n1
+    = force_gimple_operand_bsi (&si, fold_convert (type, fd->loop.n1),
+                               true, NULL_TREE, true, BSI_SAME_STMT);
+  fd->loop.n2
+    = force_gimple_operand_bsi (&si, fold_convert (itype, fd->loop.n2),
+                               true, NULL_TREE, true, BSI_SAME_STMT);
+  fd->loop.step
+    = force_gimple_operand_bsi (&si, fold_convert (itype, fd->loop.step),
+                               true, NULL_TREE, true, BSI_SAME_STMT);
   fd->chunk_size
-         = force_gimple_operand_bsi (&si, fold_convert (type,
-                                                        fd->chunk_size),
-                                     true, NULL_TREE,
-                                     true, BSI_SAME_STMT);
-
-  t = build_int_cst (type, (fd->cond_code == LT_EXPR ? -1 : 1));
-  t = fold_build2 (PLUS_EXPR, type, fd->step, t);
-  t = fold_build2 (PLUS_EXPR, type, t, fd->n2);
-  t = fold_build2 (MINUS_EXPR, type, t, fd->n1);
-  t = fold_build2 (TRUNC_DIV_EXPR, type, t, fd->step);
-  t = fold_convert (type, t);
+    = force_gimple_operand_bsi (&si, fold_convert (itype, fd->chunk_size),
+                               true, NULL_TREE, true, BSI_SAME_STMT);
+
+  t = build_int_cst (itype, (fd->loop.cond_code == LT_EXPR ? -1 : 1));
+  t = fold_build2 (PLUS_EXPR, itype, fd->loop.step, t);
+  t = fold_build2 (PLUS_EXPR, itype, t, fd->loop.n2);
+  t = fold_build2 (MINUS_EXPR, itype, t, fold_convert (itype, fd->loop.n1));
+  if (TYPE_UNSIGNED (itype) && fd->loop.cond_code == GT_EXPR)
+    t = fold_build2 (TRUNC_DIV_EXPR, itype,
+                    fold_build1 (NEGATE_EXPR, itype, t),
+                    fold_build1 (NEGATE_EXPR, itype, fd->loop.step));
+  else
+    t = fold_build2 (TRUNC_DIV_EXPR, itype, t, fd->loop.step);
+  t = fold_convert (itype, t);
   n = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
                                true, BSI_SAME_STMT);
 
-  trip_var = create_tmp_var (type, ".trip");
+  trip_var = create_tmp_var (itype, ".trip");
   if (gimple_in_ssa_p (cfun))
     {
       add_referenced_var (trip_var);
@@ -3194,14 +4130,18 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd)
       trip_back = trip_var;
     }
 
-  t = build_gimple_modify_stmt (trip_init, build_int_cst (type, 0));
+  t = build_gimple_modify_stmt (trip_init, build_int_cst (itype, 0));
   bsi_insert_before (&si, t, BSI_SAME_STMT);
   if (gimple_in_ssa_p (cfun))
     SSA_NAME_DEF_STMT (trip_init) = t;
 
-  t = fold_build2 (MULT_EXPR, type, threadid, fd->chunk_size);
-  t = fold_build2 (MULT_EXPR, type, t, fd->step);
-  t = fold_build2 (PLUS_EXPR, type, t, fd->n1);
+  t = fold_build2 (MULT_EXPR, itype, threadid, fd->chunk_size);
+  t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step);
+  if (POINTER_TYPE_P (type))
+    t = fold_build2 (POINTER_PLUS_EXPR, type, fd->loop.n1,
+                    fold_convert (sizetype, t));
+  else
+    t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1);
   v_extra = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
                                      true, BSI_SAME_STMT);
 
@@ -3211,14 +4151,14 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd)
   /* Iteration space partitioning goes in ITER_PART_BB.  */
   si = bsi_last (iter_part_bb);
 
-  t = fold_build2 (MULT_EXPR, type, trip_main, nthreads);
-  t = fold_build2 (PLUS_EXPR, type, t, threadid);
-  t = fold_build2 (MULT_EXPR, type, t, fd->chunk_size);
+  t = fold_build2 (MULT_EXPR, itype, trip_main, nthreads);
+  t = fold_build2 (PLUS_EXPR, itype, t, threadid);
+  t = fold_build2 (MULT_EXPR, itype, t, fd->chunk_size);
   s0 = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
                                 false, BSI_CONTINUE_LINKING);
 
-  t = fold_build2 (PLUS_EXPR, type, s0, fd->chunk_size);
-  t = fold_build2 (MIN_EXPR, type, t, n);
+  t = fold_build2 (PLUS_EXPR, itype, s0, fd->chunk_size);
+  t = fold_build2 (MIN_EXPR, itype, t, n);
   e0 = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
                                 false, BSI_CONTINUE_LINKING);
 
@@ -3229,19 +4169,27 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd)
   /* Setup code for sequential iteration goes in SEQ_START_BB.  */
   si = bsi_start (seq_start_bb);
 
-  t = fold_convert (type, s0);
-  t = fold_build2 (MULT_EXPR, type, t, fd->step);
-  t = fold_build2 (PLUS_EXPR, type, t, fd->n1);
+  t = fold_convert (itype, s0);
+  t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step);
+  if (POINTER_TYPE_P (type))
+    t = fold_build2 (POINTER_PLUS_EXPR, type, fd->loop.n1,
+                    fold_convert (sizetype, t));
+  else
+    t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1);
   t = force_gimple_operand_bsi (&si, t, false, NULL_TREE,
                                false, BSI_CONTINUE_LINKING);
-  t = build_gimple_modify_stmt (fd->v, t);
+  t = build_gimple_modify_stmt (fd->loop.v, t);
   bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
   if (gimple_in_ssa_p (cfun))
-    SSA_NAME_DEF_STMT (fd->v) = t;
+    SSA_NAME_DEF_STMT (fd->loop.v) = t;
 
-  t = fold_convert (type, e0);
-  t = fold_build2 (MULT_EXPR, type, t, fd->step);
-  t = fold_build2 (PLUS_EXPR, type, t, fd->n1);
+  t = fold_convert (itype, e0);
+  t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step);
+  if (POINTER_TYPE_P (type))
+    t = fold_build2 (POINTER_PLUS_EXPR, type, fd->loop.n1,
+                    fold_convert (sizetype, t));
+  else
+    t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1);
   e = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
                                false, BSI_CONTINUE_LINKING);
 
@@ -3253,13 +4201,17 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd)
   v_main = TREE_OPERAND (cont, 1);
   v_back = TREE_OPERAND (cont, 0);
 
-  t = build2 (PLUS_EXPR, type, v_main, fd->step);
+  if (POINTER_TYPE_P (type))
+    t = fold_build2 (POINTER_PLUS_EXPR, type, v_main,
+                    fold_convert (sizetype, fd->loop.step));
+  else
+    t = build2 (PLUS_EXPR, type, v_main, fd->loop.step);
   t = build_gimple_modify_stmt (v_back, t);
   bsi_insert_before (&si, t, BSI_SAME_STMT);
   if (gimple_in_ssa_p (cfun))
     SSA_NAME_DEF_STMT (v_back) = t;
 
-  t = build2 (fd->cond_code, boolean_type_node, v_back, e);
+  t = build2 (fd->loop.cond_code, boolean_type_node, v_back, e);
   t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
   bsi_insert_before (&si, t, BSI_SAME_STMT);
   
@@ -3269,8 +4221,8 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd)
   /* Trip update code goes into TRIP_UPDATE_BB.  */
   si = bsi_start (trip_update_bb);
 
-  t = build_int_cst (type, 1);
-  t = build2 (PLUS_EXPR, type, trip_main, t);
+  t = build_int_cst (itype, 1);
+  t = build2 (PLUS_EXPR, itype, trip_main, t);
   t = build_gimple_modify_stmt (trip_back, t);
   bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
   if (gimple_in_ssa_p (cfun))
@@ -3313,9 +4265,9 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd)
          SSA_NAME_DEF_STMT (t) = nphi;
 
          t = PHI_ARG_DEF_FROM_EDGE (phi, se);
-         /* A special case -- fd->v is not yet computed in iter_part_bb, we
-            need to use v_extra instead.  */
-         if (t == fd->v)
+         /* A special case -- fd->loop.v is not yet computed in
+            iter_part_bb, we need to use v_extra instead.  */
+         if (t == fd->loop.v)
            t = v_extra;
          add_phi_arg (nphi, t, ene);
          add_phi_arg (nphi, TREE_VALUE (args), re);
@@ -3349,8 +4301,14 @@ static void
 expand_omp_for (struct omp_region *region)
 {
   struct omp_for_data fd;
+  struct omp_for_data_loop *loops;
 
-  extract_omp_for_data (last_stmt (region->entry), &fd);
+  loops
+    = (struct omp_for_data_loop *)
+      alloca (TREE_VEC_LENGTH (OMP_FOR_INIT (last_stmt (region->entry)))
+             * sizeof (struct omp_for_data_loop));
+
+  extract_omp_for_data (last_stmt (region->entry), &fd, loops);
   region->sched_kind = fd.sched_kind;
 
   gcc_assert (EDGE_COUNT (region->entry->succs) == 2);
@@ -3365,6 +4323,7 @@ expand_omp_for (struct omp_region *region)
 
   if (fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC
       && !fd.have_ordered
+      && fd.collapse == 1
       && region->cont != NULL)
     {
       if (fd.chunk_size == NULL)
@@ -3374,9 +4333,21 @@ expand_omp_for (struct omp_region *region)
     }
   else
     {
-      int fn_index = fd.sched_kind + fd.have_ordered * 4;
-      int start_ix = BUILT_IN_GOMP_LOOP_STATIC_START + fn_index;
-      int next_ix = BUILT_IN_GOMP_LOOP_STATIC_NEXT + fn_index;
+      int fn_index, start_ix, next_ix;
+
+      gcc_assert (fd.sched_kind != OMP_CLAUSE_SCHEDULE_AUTO);
+      fn_index = (fd.sched_kind == OMP_CLAUSE_SCHEDULE_RUNTIME)
+                ? 3 : fd.sched_kind;
+      fn_index += fd.have_ordered * 4;
+      start_ix = BUILT_IN_GOMP_LOOP_STATIC_START + fn_index;
+      next_ix = BUILT_IN_GOMP_LOOP_STATIC_NEXT + fn_index;
+      if (fd.iter_type == long_long_unsigned_type_node)
+       {
+         start_ix += BUILT_IN_GOMP_LOOP_ULL_STATIC_START
+                     - BUILT_IN_GOMP_LOOP_STATIC_START;
+         next_ix += BUILT_IN_GOMP_LOOP_ULL_STATIC_NEXT
+                    - BUILT_IN_GOMP_LOOP_STATIC_NEXT;
+       }
       expand_omp_for_generic (region, &fd, start_ix, next_ix);
     }
 
@@ -4037,7 +5008,11 @@ expand_omp (struct omp_region *region)
       switch (region->type)
        {
        case OMP_PARALLEL:
-         expand_omp_parallel (region);
+         expand_omp_taskreg (region);
+         break;
+
+       case OMP_TASK:
+         expand_omp_taskreg (region);
          break;
 
        case OMP_FOR:
@@ -4355,6 +5330,9 @@ lower_omp_single_simple (tree single_stmt, tree *pre_p)
   tree t;
 
   t = build_call_expr (built_in_decls[BUILT_IN_GOMP_SINGLE_START], 0);
+  if (TREE_TYPE (t) != boolean_type_node)
+    t = fold_build2 (NE_EXPR, boolean_type_node,
+                    t, build_int_cst (TREE_TYPE (t), 0));
   t = build3 (COND_EXPR, void_type_node, t,
              OMP_SINGLE_BODY (single_stmt), NULL);
   gimplify_and_add (t, pre_p);
@@ -4661,37 +5639,38 @@ lower_omp_for_lastprivate (struct omp_for_data *fd, tree *body_p,
   tree clauses, cond, stmts, vinit, t;
   enum tree_code cond_code;
   
-  cond_code = fd->cond_code;
+  cond_code = fd->loop.cond_code;
   cond_code = cond_code == LT_EXPR ? GE_EXPR : LE_EXPR;
 
   /* When possible, use a strict equality expression.  This can let VRP
      type optimizations deduce the value and remove a copy.  */
-  if (host_integerp (fd->step, 0))
+  if (host_integerp (fd->loop.step, 0))
     {
-      HOST_WIDE_INT step = TREE_INT_CST_LOW (fd->step);
+      HOST_WIDE_INT step = TREE_INT_CST_LOW (fd->loop.step);
       if (step == 1 || step == -1)
        cond_code = EQ_EXPR;
     }
 
-  cond = build2 (cond_code, boolean_type_node, fd->v, fd->n2);
+  cond = build2 (cond_code, boolean_type_node, fd->loop.v, fd->loop.n2);
 
   clauses = OMP_FOR_CLAUSES (fd->for_stmt);
   stmts = NULL;
   lower_lastprivate_clauses (clauses, cond, &stmts, ctx);
   if (stmts != NULL)
     {
-      append_to_statement_list (stmts, dlist);
+      append_to_statement_list (*dlist, &stmts);
+      *dlist = stmts;
 
       /* Optimize: v = 0; is usually cheaper than v = some_other_constant.  */
-      vinit = fd->n1;
+      vinit = fd->loop.n1;
       if (cond_code == EQ_EXPR
-         && host_integerp (fd->n2, 0)
-         && ! integer_zerop (fd->n2))
-       vinit = build_int_cst (TREE_TYPE (fd->v), 0);
+         && host_integerp (fd->loop.n2, 0)
+         && ! integer_zerop (fd->loop.n2))
+       vinit = build_int_cst (TREE_TYPE (fd->loop.v), 0);
 
       /* Initialize the iterator variable, so that threads that don't execute
         any iterations don't execute the lastprivate clauses by accident.  */
-      t = build_gimple_modify_stmt (fd->v, vinit);
+      t = build_gimple_modify_stmt (fd->loop.v, vinit);
       gimplify_and_add (t, body_p);
     }
 }
@@ -4704,6 +5683,7 @@ lower_omp_for (tree *stmt_p, omp_context *ctx)
 {
   tree t, stmt, ilist, dlist, new_stmt, *body_p, *rhs_p;
   struct omp_for_data fd;
+  int i;
 
   stmt = *stmt_p;
 
@@ -4724,8 +5704,8 @@ lower_omp_for (tree *stmt_p, omp_context *ctx)
   /* The pre-body and input clauses go before the lowered OMP_FOR.  */
   ilist = NULL;
   dlist = NULL;
-  append_to_statement_list (OMP_FOR_PRE_BODY (stmt), body_p);
   lower_rec_input_clauses (OMP_FOR_CLAUSES (stmt), body_p, &dlist, ctx);
+  append_to_statement_list (OMP_FOR_PRE_BODY (stmt), body_p);
 
   /* Lower the header expressions.  At this point, we can assume that
      the header is of the form:
@@ -4734,20 +5714,24 @@ lower_omp_for (tree *stmt_p, omp_context *ctx)
 
      We just need to make sure that VAL1, VAL2 and VAL3 are lowered
      using the .omp_data_s mapping, if needed.  */
-  rhs_p = &GIMPLE_STMT_OPERAND (OMP_FOR_INIT (stmt), 1);
-  if (!is_gimple_min_invariant (*rhs_p))
-    *rhs_p = get_formal_tmp_var (*rhs_p, body_p);
-
-  rhs_p = &TREE_OPERAND (OMP_FOR_COND (stmt), 1);
-  if (!is_gimple_min_invariant (*rhs_p))
-    *rhs_p = get_formal_tmp_var (*rhs_p, body_p);
-
-  rhs_p = &TREE_OPERAND (GIMPLE_STMT_OPERAND (OMP_FOR_INCR (stmt), 1), 1);
-  if (!is_gimple_min_invariant (*rhs_p))
-    *rhs_p = get_formal_tmp_var (*rhs_p, body_p);
+  for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (stmt)); i++)
+    {
+      rhs_p = &GIMPLE_STMT_OPERAND (TREE_VEC_ELT (OMP_FOR_INIT (stmt), i), 1);
+      if (!is_gimple_min_invariant (*rhs_p))
+       *rhs_p = get_formal_tmp_var (*rhs_p, body_p);
+
+      rhs_p = &TREE_OPERAND (TREE_VEC_ELT (OMP_FOR_COND (stmt), i), 1);
+      if (!is_gimple_min_invariant (*rhs_p))
+       *rhs_p = get_formal_tmp_var (*rhs_p, body_p);
+
+      rhs_p = &TREE_OPERAND (GIMPLE_STMT_OPERAND
+                              (TREE_VEC_ELT (OMP_FOR_INCR (stmt), i), 1), 1);
+      if (!is_gimple_min_invariant (*rhs_p))
+       *rhs_p = get_formal_tmp_var (*rhs_p, body_p);
+    }
 
   /* Once lowered, extract the bounds and clauses.  */
-  extract_omp_for_data (stmt, &fd);
+  extract_omp_for_data (stmt, &fd, NULL);
 
   lower_omp_for_lastprivate (&fd, body_p, &dlist, ctx);
 
@@ -4755,7 +5739,7 @@ lower_omp_for (tree *stmt_p, omp_context *ctx)
 
   append_to_statement_list (OMP_FOR_BODY (stmt), body_p);
 
-  t = build2 (OMP_CONTINUE, void_type_node, fd.v, fd.v);
+  t = build2 (OMP_CONTINUE, void_type_node, fd.loop.v, fd.loop.v);
   append_to_statement_list (t, body_p);
 
   /* After the loop, add exit clauses.  */
@@ -4800,11 +5784,290 @@ check_combined_parallel (tree *tp, int *walk_subtrees, void *data)
   return NULL;
 }
 
-/* Lower the OpenMP parallel directive in *STMT_P.  CTX holds context
+struct omp_taskcopy_context
+{
+  /* This field must be at the beginning, as we do "inheritance": Some
+     callback functions for tree-inline.c (e.g., omp_copy_decl)
+     receive a copy_body_data pointer that is up-casted to an
+     omp_context pointer.  */
+  copy_body_data cb;
+  omp_context *ctx;
+};
+
+static tree
+task_copyfn_copy_decl (tree var, copy_body_data *cb)
+{
+  struct omp_taskcopy_context *tcctx = (struct omp_taskcopy_context *) cb;
+
+  if (splay_tree_lookup (tcctx->ctx->sfield_map, (splay_tree_key) var))
+    return create_tmp_var (TREE_TYPE (var), NULL);
+
+  return var;
+}
+
+static tree
+task_copyfn_remap_type (struct omp_taskcopy_context *tcctx, tree orig_type)
+{
+  tree name, new_fields = NULL, type, f;
+
+  type = lang_hooks.types.make_type (RECORD_TYPE);
+  name = DECL_NAME (TYPE_NAME (orig_type));
+  name = build_decl (TYPE_DECL, name, type);
+  TYPE_NAME (type) = name;
+
+  for (f = TYPE_FIELDS (orig_type); f ; f = TREE_CHAIN (f))
+    {
+      tree new_f = copy_node (f);
+      DECL_CONTEXT (new_f) = type;
+      TREE_TYPE (new_f) = remap_type (TREE_TYPE (f), &tcctx->cb);
+      TREE_CHAIN (new_f) = new_fields;
+      walk_tree (&DECL_SIZE (new_f), copy_body_r, &tcctx->cb, NULL);
+      walk_tree (&DECL_SIZE_UNIT (new_f), copy_body_r, &tcctx->cb, NULL);
+      walk_tree (&DECL_FIELD_OFFSET (new_f), copy_body_r, &tcctx->cb, NULL);
+      new_fields = new_f;
+      *pointer_map_insert (tcctx->cb.decl_map, f) = new_f;
+    }
+  TYPE_FIELDS (type) = nreverse (new_fields);
+  layout_type (type);
+  return type;
+}
+
+/* Create task copyfn.  */
+
+static void
+create_task_copyfn (tree task_stmt, omp_context *ctx)
+{
+  struct function *child_cfun;
+  tree child_fn, t, c, src, dst, f, sf, arg, sarg, decl;
+  tree record_type, srecord_type, bind, list;
+  bool record_needs_remap = false, srecord_needs_remap = false;
+  splay_tree_node n;
+  struct omp_taskcopy_context tcctx;
+
+  child_fn = OMP_TASK_COPYFN (task_stmt);
+  child_cfun = DECL_STRUCT_FUNCTION (child_fn);
+  gcc_assert (child_cfun->cfg == NULL);
+  child_cfun->dont_save_pending_sizes_p = 1;
+  DECL_SAVED_TREE (child_fn) = alloc_stmt_list ();
+
+  /* Reset DECL_CONTEXT on function arguments.  */
+  for (t = DECL_ARGUMENTS (child_fn); t; t = TREE_CHAIN (t))
+    DECL_CONTEXT (t) = child_fn;
+
+  /* Populate the function.  */
+  push_gimplify_context ();
+  current_function_decl = child_fn;
+
+  bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL);
+  TREE_SIDE_EFFECTS (bind) = 1;
+  list = NULL;
+  DECL_SAVED_TREE (child_fn) = bind;
+  DECL_SOURCE_LOCATION (child_fn) = EXPR_LOCATION (task_stmt);
+
+  /* Remap src and dst argument types if needed.  */
+  record_type = ctx->record_type;
+  srecord_type = ctx->srecord_type;
+  for (f = TYPE_FIELDS (record_type); f ; f = TREE_CHAIN (f))
+    if (variably_modified_type_p (TREE_TYPE (f), ctx->cb.src_fn))
+      {
+       record_needs_remap = true;
+       break;
+      }
+  for (f = TYPE_FIELDS (srecord_type); f ; f = TREE_CHAIN (f))
+    if (variably_modified_type_p (TREE_TYPE (f), ctx->cb.src_fn))
+      {
+       srecord_needs_remap = true;
+       break;
+      }
+
+  if (record_needs_remap || srecord_needs_remap)
+    {
+      memset (&tcctx, '\0', sizeof (tcctx));
+      tcctx.cb.src_fn = ctx->cb.src_fn;
+      tcctx.cb.dst_fn = child_fn;
+      tcctx.cb.src_node = cgraph_node (tcctx.cb.src_fn);
+      tcctx.cb.dst_node = tcctx.cb.src_node;
+      tcctx.cb.src_cfun = ctx->cb.src_cfun;
+      tcctx.cb.copy_decl = task_copyfn_copy_decl;
+      tcctx.cb.eh_region = -1;
+      tcctx.cb.transform_call_graph_edges = CB_CGE_MOVE;
+      tcctx.cb.decl_map = pointer_map_create ();
+      tcctx.ctx = ctx;
+
+      if (record_needs_remap)
+       record_type = task_copyfn_remap_type (&tcctx, record_type);
+      if (srecord_needs_remap)
+       srecord_type = task_copyfn_remap_type (&tcctx, srecord_type);
+    }
+  else
+    tcctx.cb.decl_map = NULL;
+
+  push_cfun (child_cfun);
+
+  arg = DECL_ARGUMENTS (child_fn);
+  TREE_TYPE (arg) = build_pointer_type (record_type);
+  sarg = TREE_CHAIN (arg);
+  TREE_TYPE (sarg) = build_pointer_type (srecord_type);
+
+  /* First pass: initialize temporaries used in record_type and srecord_type
+     sizes and field offsets.  */
+  if (tcctx.cb.decl_map)
+    for (c = OMP_TASK_CLAUSES (task_stmt); c; c = OMP_CLAUSE_CHAIN (c))
+      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE)
+       {
+         tree *p;
+
+         decl = OMP_CLAUSE_DECL (c);
+         p = (tree *) pointer_map_contains (tcctx.cb.decl_map, decl);
+         if (p == NULL)
+           continue;
+         n = splay_tree_lookup (ctx->sfield_map, (splay_tree_key) decl);
+         sf = (tree) n->value;
+         sf = *(tree *) pointer_map_contains (tcctx.cb.decl_map, sf);
+         src = build_fold_indirect_ref (sarg);
+         src = build3 (COMPONENT_REF, TREE_TYPE (sf), src, sf, NULL);
+         t = build_gimple_modify_stmt (*p, src);
+         append_to_statement_list (t, &list);
+       }
+
+  /* Second pass: copy shared var pointers and copy construct non-VLA
+     firstprivate vars.  */
+  for (c = OMP_TASK_CLAUSES (task_stmt); c; c = OMP_CLAUSE_CHAIN (c))
+    switch (OMP_CLAUSE_CODE (c))
+      {
+      case OMP_CLAUSE_SHARED:
+       decl = OMP_CLAUSE_DECL (c);
+       n = splay_tree_lookup (ctx->field_map, (splay_tree_key) decl);
+       if (n == NULL)
+         break;
+       f = (tree) n->value;
+       if (tcctx.cb.decl_map)
+         f = *(tree *) pointer_map_contains (tcctx.cb.decl_map, f);
+       n = splay_tree_lookup (ctx->sfield_map, (splay_tree_key) decl);
+       sf = (tree) n->value;
+       if (tcctx.cb.decl_map)
+         sf = *(tree *) pointer_map_contains (tcctx.cb.decl_map, sf);
+       src = build_fold_indirect_ref (sarg);
+       src = build3 (COMPONENT_REF, TREE_TYPE (sf), src, sf, NULL);
+       dst = build_fold_indirect_ref (arg);
+       dst = build3 (COMPONENT_REF, TREE_TYPE (f), dst, f, NULL);
+       t = build_gimple_modify_stmt (dst, src);
+       append_to_statement_list (t, &list);
+       break;
+      case OMP_CLAUSE_FIRSTPRIVATE:
+       decl = OMP_CLAUSE_DECL (c);
+       if (is_variable_sized (decl))
+         break;
+       n = splay_tree_lookup (ctx->field_map, (splay_tree_key) decl);
+       if (n == NULL)
+         break;
+       f = (tree) n->value;
+       if (tcctx.cb.decl_map)
+         f = *(tree *) pointer_map_contains (tcctx.cb.decl_map, f);
+       n = splay_tree_lookup (ctx->sfield_map, (splay_tree_key) decl);
+       if (n != NULL)
+         {
+           sf = (tree) n->value;
+           if (tcctx.cb.decl_map)
+             sf = *(tree *) pointer_map_contains (tcctx.cb.decl_map, sf);
+           src = build_fold_indirect_ref (sarg);
+           src = build3 (COMPONENT_REF, TREE_TYPE (sf), src, sf, NULL);
+           if (use_pointer_for_field (decl, NULL) || is_reference (decl))
+             src = build_fold_indirect_ref (src);
+         }
+       else
+         src = decl;
+       dst = build_fold_indirect_ref (arg);
+       dst = build3 (COMPONENT_REF, TREE_TYPE (f), dst, f, NULL);
+       t = lang_hooks.decls.omp_clause_copy_ctor (c, dst, src);
+       append_to_statement_list (t, &list);
+       break;
+      case OMP_CLAUSE_PRIVATE:
+       if (! OMP_CLAUSE_PRIVATE_OUTER_REF (c))
+         break;
+       decl = OMP_CLAUSE_DECL (c);
+       n = splay_tree_lookup (ctx->field_map, (splay_tree_key) decl);
+       f = (tree) n->value;
+       if (tcctx.cb.decl_map)
+         f = *(tree *) pointer_map_contains (tcctx.cb.decl_map, f);
+       n = splay_tree_lookup (ctx->sfield_map, (splay_tree_key) decl);
+       if (n != NULL)
+         {
+           sf = (tree) n->value;
+           if (tcctx.cb.decl_map)
+             sf = *(tree *) pointer_map_contains (tcctx.cb.decl_map, sf);
+           src = build_fold_indirect_ref (sarg);
+           src = build3 (COMPONENT_REF, TREE_TYPE (sf), src, sf, NULL);
+           if (use_pointer_for_field (decl, NULL))
+             src = build_fold_indirect_ref (src);
+         }
+       else
+         src = decl;
+       dst = build_fold_indirect_ref (arg);
+       dst = build3 (COMPONENT_REF, TREE_TYPE (f), dst, f, NULL);
+       t = build_gimple_modify_stmt (dst, src);
+       append_to_statement_list (t, &list);
+       break;
+      default:
+       break;
+      }
+
+  /* Last pass: handle VLA firstprivates.  */
+  if (tcctx.cb.decl_map)
+    for (c = OMP_TASK_CLAUSES (task_stmt); c; c = OMP_CLAUSE_CHAIN (c))
+      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE)
+       {
+         tree ind, ptr, df;
+
+         decl = OMP_CLAUSE_DECL (c);
+         if (!is_variable_sized (decl))
+           continue;
+         n = splay_tree_lookup (ctx->field_map, (splay_tree_key) decl);
+         if (n == NULL)
+           continue;
+         f = (tree) n->value;
+         f = *(tree *) pointer_map_contains (tcctx.cb.decl_map, f);
+         gcc_assert (DECL_HAS_VALUE_EXPR_P (decl));
+         ind = DECL_VALUE_EXPR (decl);
+         gcc_assert (TREE_CODE (ind) == INDIRECT_REF);
+         gcc_assert (DECL_P (TREE_OPERAND (ind, 0)));
+         n = splay_tree_lookup (ctx->sfield_map,
+                                (splay_tree_key) TREE_OPERAND (ind, 0));
+         sf = (tree) n->value;
+         sf = *(tree *) pointer_map_contains (tcctx.cb.decl_map, sf);
+         src = build_fold_indirect_ref (sarg);
+         src = build3 (COMPONENT_REF, TREE_TYPE (sf), src, sf, NULL);
+         src = build_fold_indirect_ref (src);
+         dst = build_fold_indirect_ref (arg);
+         dst = build3 (COMPONENT_REF, TREE_TYPE (f), dst, f, NULL);
+         t = lang_hooks.decls.omp_clause_copy_ctor (c, dst, src);
+         append_to_statement_list (t, &list);
+         n = splay_tree_lookup (ctx->field_map,
+                                (splay_tree_key) TREE_OPERAND (ind, 0));
+         df = (tree) n->value;
+         df = *(tree *) pointer_map_contains (tcctx.cb.decl_map, df);
+         ptr = build_fold_indirect_ref (arg);
+         ptr = build3 (COMPONENT_REF, TREE_TYPE (df), ptr, df, NULL);
+         t = build_gimple_modify_stmt (ptr, build_fold_addr_expr (dst));
+         append_to_statement_list (t, &list);
+       }
+
+  t = build1 (RETURN_EXPR, void_type_node, NULL);
+  append_to_statement_list (t, &list);
+
+  if (tcctx.cb.decl_map)
+    pointer_map_destroy (tcctx.cb.decl_map);
+  pop_gimplify_context (NULL);
+  BIND_EXPR_BODY (bind) = list;
+  pop_cfun ();
+  current_function_decl = ctx->cb.src_fn;
+}
+
+/* Lower the OpenMP parallel or task directive in *STMT_P.  CTX holds context
    information for the directive.  */
 
 static void
-lower_omp_parallel (tree *stmt_p, omp_context *ctx)
+lower_omp_taskreg (tree *stmt_p, omp_context *ctx)
 {
   tree clauses, par_bind, par_body, new_body, bind;
   tree olist, ilist, par_olist, par_ilist;
@@ -4812,11 +6075,11 @@ lower_omp_parallel (tree *stmt_p, omp_context *ctx)
 
   stmt = *stmt_p;
 
-  clauses = OMP_PARALLEL_CLAUSES (stmt);
-  par_bind = OMP_PARALLEL_BODY (stmt);
+  clauses = OMP_TASKREG_CLAUSES (stmt);
+  par_bind = OMP_TASKREG_BODY (stmt);
   par_body = BIND_EXPR_BODY (par_bind);
   child_fn = ctx->cb.dst_fn;
-  if (!OMP_PARALLEL_COMBINED (stmt))
+  if (TREE_CODE (stmt) == OMP_PARALLEL && !OMP_PARALLEL_COMBINED (stmt))
     {
       struct walk_stmt_info wi;
       int ws_num = 0;
@@ -4829,6 +6092,8 @@ lower_omp_parallel (tree *stmt_p, omp_context *ctx)
       if (ws_num == 1)
        OMP_PARALLEL_COMBINED (stmt) = 1;
     }
+  if (ctx->srecord_type)
+    create_task_copyfn (stmt, ctx);
 
   push_gimplify_context ();
 
@@ -4836,7 +6101,8 @@ lower_omp_parallel (tree *stmt_p, omp_context *ctx)
   par_ilist = NULL_TREE;
   lower_rec_input_clauses (clauses, &par_ilist, &par_olist, ctx);
   lower_omp (&par_body, ctx);
-  lower_reduction_clauses (clauses, &par_olist, ctx);
+  if (TREE_CODE (stmt) == OMP_PARALLEL)
+    lower_reduction_clauses (clauses, &par_olist, ctx);
 
   /* Declare all the variables created by mapping and the variables
      declared in the scope of the parallel body.  */
@@ -4845,8 +6111,10 @@ lower_omp_parallel (tree *stmt_p, omp_context *ctx)
 
   if (ctx->record_type)
     {
-      ctx->sender_decl = create_tmp_var (ctx->record_type, ".omp_data_o");
-      OMP_PARALLEL_DATA_ARG (stmt) = ctx->sender_decl;
+      ctx->sender_decl
+       = create_tmp_var (ctx->srecord_type ? ctx->srecord_type
+                         : ctx->record_type, ".omp_data_o");
+      OMP_TASKREG_DATA_ARG (stmt) = ctx->sender_decl;
     }
 
   olist = NULL_TREE;
@@ -4855,7 +6123,7 @@ lower_omp_parallel (tree *stmt_p, omp_context *ctx)
   lower_send_shared_vars (&ilist, &olist, ctx);
 
   /* Once all the expansions are done, sequence all the different
-     fragments inside OMP_PARALLEL_BODY.  */
+     fragments inside OMP_TASKREG_BODY.  */
   bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL);
   append_to_statement_list (ilist, &BIND_EXPR_BODY (bind));
 
@@ -4876,7 +6144,7 @@ lower_omp_parallel (tree *stmt_p, omp_context *ctx)
   maybe_catch_exception (&new_body);
   t = make_node (OMP_RETURN);
   append_to_statement_list (t, &new_body);
-  OMP_PARALLEL_BODY (stmt) = new_body;
+  OMP_TASKREG_BODY (stmt) = new_body;
 
   append_to_statement_list (stmt, &BIND_EXPR_BODY (bind));
   append_to_statement_list (olist, &BIND_EXPR_BODY (bind));
@@ -4890,17 +6158,21 @@ lower_omp_parallel (tree *stmt_p, omp_context *ctx)
    regimplified.  */
 
 static tree
-lower_omp_2 (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
+lower_omp_2 (tree *tp, int *walk_subtrees, void *data)
 {
   tree t = *tp;
+  omp_context *ctx = data;
 
   /* Any variable with DECL_VALUE_EXPR needs to be regimplified.  */
-  if (TREE_CODE (t) == VAR_DECL && DECL_HAS_VALUE_EXPR_P (t))
+  if (TREE_CODE (t) == VAR_DECL
+      && ((ctx && DECL_HAS_VALUE_EXPR_P (t))
+         || (task_shared_vars
+             && bitmap_bit_p (task_shared_vars, DECL_UID (t)))))
     return t;
 
   /* If a global variable has been privatized, TREE_CONSTANT on
      ADDR_EXPR might be wrong.  */
-  if (TREE_CODE (t) == ADDR_EXPR)
+  if (ctx && TREE_CODE (t) == ADDR_EXPR)
     recompute_tree_invariant_for_addr_expr (t);
 
   *walk_subtrees = !TYPE_P (t) && !DECL_P (t);
@@ -4940,7 +6212,7 @@ lower_omp_1 (tree *tp, omp_context *ctx, tree_stmt_iterator *tsi)
     case COND_EXPR:
       lower_omp_1 (&COND_EXPR_THEN (t), ctx, NULL);
       lower_omp_1 (&COND_EXPR_ELSE (t), ctx, NULL);
-      if (ctx
+      if ((ctx || task_shared_vars)
          && walk_tree (&COND_EXPR_COND (t), lower_omp_2, ctx, NULL))
        {
          tree pre = NULL;
@@ -4977,8 +6249,9 @@ lower_omp_1 (tree *tp, omp_context *ctx, tree_stmt_iterator *tsi)
       break;
 
     case OMP_PARALLEL:
+    case OMP_TASK:
       ctx = maybe_lookup_ctx (t);
-      lower_omp_parallel (tp, ctx);
+      lower_omp_taskreg (tp, ctx);
       break;
     case OMP_FOR:
       ctx = maybe_lookup_ctx (t);
@@ -5012,7 +6285,8 @@ lower_omp_1 (tree *tp, omp_context *ctx, tree_stmt_iterator *tsi)
       break;
 
     default:
-      if (ctx && walk_tree (tp, lower_omp_2, ctx, NULL))
+      if ((ctx || task_shared_vars)
+         && walk_tree (tp, lower_omp_2, ctx, NULL))
        {
          /* The gimplifier doesn't gimplify CALL_EXPR_STATIC_CHAIN.
             Handle that here.  */
@@ -5068,16 +6342,23 @@ execute_lower_omp (void)
                                 delete_omp_context);
 
   scan_omp (&DECL_SAVED_TREE (current_function_decl), NULL);
-  gcc_assert (parallel_nesting_level == 0);
+  gcc_assert (taskreg_nesting_level == 0);
 
   if (all_contexts->root)
-    lower_omp (&DECL_SAVED_TREE (current_function_decl), NULL);
+    {
+      if (task_shared_vars)
+       push_gimplify_context ();
+      lower_omp (&DECL_SAVED_TREE (current_function_decl), NULL);
+      if (task_shared_vars)
+       pop_gimplify_context (NULL);
+    }
 
   if (all_contexts)
     {
       splay_tree_delete (all_contexts);
       all_contexts = NULL;
     }
+  BITMAP_FREE (task_shared_vars);
   return 0;
 }
 
@@ -5160,11 +6441,13 @@ diagnose_sb_1 (tree *tp, int *walk_subtrees, void *data)
   tree context = (tree) wi->info;
   tree inner_context;
   tree t = *tp;
+  int i;
 
   *walk_subtrees = 0;
   switch (TREE_CODE (t))
     {
     case OMP_PARALLEL:
+    case OMP_TASK:
     case OMP_SECTIONS:
     case OMP_SINGLE:
       walk_tree (&OMP_CLAUSES (t), diagnose_sb_1, wi, NULL);
@@ -5184,9 +6467,15 @@ diagnose_sb_1 (tree *tp, int *walk_subtrees, void *data)
       walk_tree (&OMP_FOR_CLAUSES (t), diagnose_sb_1, wi, NULL);
       inner_context = tree_cons (NULL, t, context);
       wi->info = inner_context;
-      walk_tree (&OMP_FOR_INIT (t), diagnose_sb_1, wi, NULL);
-      walk_tree (&OMP_FOR_COND (t), diagnose_sb_1, wi, NULL);
-      walk_tree (&OMP_FOR_INCR (t), diagnose_sb_1, wi, NULL);
+      for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (t)); i++)
+       {
+         walk_tree (&TREE_VEC_ELT (OMP_FOR_INIT (t), i), diagnose_sb_1,
+                    wi, NULL);
+         walk_tree (&TREE_VEC_ELT (OMP_FOR_COND (t), i), diagnose_sb_1,
+                    wi, NULL);
+         walk_tree (&TREE_VEC_ELT (OMP_FOR_INCR (t), i), diagnose_sb_1,
+                    wi, NULL);
+       }
       walk_stmts (wi, &OMP_FOR_PRE_BODY (t));
       walk_stmts (wi, &OMP_FOR_BODY (t));
       wi->info = context;
@@ -5214,11 +6503,13 @@ diagnose_sb_2 (tree *tp, int *walk_subtrees, void *data)
   tree context = (tree) wi->info;
   splay_tree_node n;
   tree t = *tp;
+  int i;
 
   *walk_subtrees = 0;
   switch (TREE_CODE (t))
     {
     case OMP_PARALLEL:
+    case OMP_TASK:
     case OMP_SECTIONS:
     case OMP_SINGLE:
       walk_tree (&OMP_CLAUSES (t), diagnose_sb_2, wi, NULL);
@@ -5235,9 +6526,15 @@ diagnose_sb_2 (tree *tp, int *walk_subtrees, void *data)
     case OMP_FOR:
       walk_tree (&OMP_FOR_CLAUSES (t), diagnose_sb_2, wi, NULL);
       wi->info = t;
-      walk_tree (&OMP_FOR_INIT (t), diagnose_sb_2, wi, NULL);
-      walk_tree (&OMP_FOR_COND (t), diagnose_sb_2, wi, NULL);
-      walk_tree (&OMP_FOR_INCR (t), diagnose_sb_2, wi, NULL);
+      for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (t)); i++)
+       {
+         walk_tree (&TREE_VEC_ELT (OMP_FOR_INIT (t), i), diagnose_sb_2,
+                    wi, NULL);
+         walk_tree (&TREE_VEC_ELT (OMP_FOR_COND (t), i), diagnose_sb_2,
+                    wi, NULL);
+         walk_tree (&TREE_VEC_ELT (OMP_FOR_INCR (t), i), diagnose_sb_2,
+                    wi, NULL);
+       }
       walk_stmts (wi, &OMP_FOR_PRE_BODY (t));
       walk_stmts (wi, &OMP_FOR_BODY (t));
       wi->info = context;
index fb43d809e49cd28b996165b808a6d4a22b184d2e..73e4a5e6c2ac4ad16f7e9d3b55dc39da64701d32 100644 (file)
@@ -1,3 +1,27 @@
+2008-06-06  Jakub Jelinek  <jakub@redhat.com>
+
+       * 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.
+
 2008-06-06  Richard Guenther  <rguenther@suse.de>
 
        * gcc.dg/tree-ssa/alias-18.c: XFAIL some sub-tests.
index 76231751f703f8414e2600170d8e7f0dd469ce39..dbbed8fe505214bbb0b9dd9480edfc6c7a94c00f 100644 (file)
@@ -4,7 +4,7 @@ template<typename T>
 void foo ()
 {
 #pragma omp for
-  for (unsigned int i = 0; i < 10; i++); // { dg-warning "is unsigned" }
+  for (unsigned int i = 0; i < 10; i++);
 #pragma omp for
   for (int j = 0; ; j++); // { dg-error "missing controlling predicate" }
 #pragma omp for
@@ -12,8 +12,7 @@ void foo ()
 #pragma omp for
   for (int l = 0; l < 10; ); // { dg-error "missing increment expression" }
 #pragma omp for
-  for (int m = 0; m < 10; m *= 3); // Error here is emitted only during
-                                  // instantiation
+  for (int m = 0; m < 10; m *= 3); // { dg-error "invalid increment expression" }
 #pragma omp for
   for (T n = 0; ; n++); // { dg-error "missing controlling predicate" }
 #pragma omp for
index 293ef8fb08e5449d90e7effdd5950e49d5321f63..4e0d5b1a5b80389a6a48f24110b634afb9f0a093 100644 (file)
@@ -8,6 +8,6 @@ foo (void)
 {
   unsigned int i;
 #pragma omp for
-  for (i = 0; i < 64; ++i)     // { dg-warning "is unsigned" }
+  for (i = 0; i < 64; ++i)
     bar (i);
 }
index 1dbba4a74140850d560351a8cbdfa1f7731b783d..f032aa45d50f7fc182833d6385c901e98c7f99ca 100644 (file)
@@ -13,6 +13,6 @@ foo ()
     ;
   T j;                         // { dg-error "was not declared|expected" }
 #pragma omp for
-  for (j = 1; j < 3; j++)      // { dg-error "was not declared" }
-    ;                          // { dg-error "expected" }
+  for (j = 1; j < 3; j++)      // { dg-error "was not declared|expected" }
+    ;
 }
diff --git a/gcc/testsuite/g++.dg/gomp/predetermined-1.C b/gcc/testsuite/g++.dg/gomp/predetermined-1.C
new file mode 100644 (file)
index 0000000..dd09855
--- /dev/null
@@ -0,0 +1,33 @@
+// { dg-do compile }
+// { dg-options "-fopenmp" }
+
+struct A { int i; A (); ~A (); };
+struct B { int i; };
+struct C { int i; mutable int j; C (); ~C (); };
+
+template <typename T> void bar (const T *);
+
+const A a;
+const C c;
+
+const A foo (const A d, const C e)
+{
+  const A f;
+  const B b = { 4 };
+  A g;
+  #pragma omp parallel default (none)
+    bar (&a);
+  #pragma omp parallel default (none)
+    bar (&b);
+  #pragma omp parallel default (none)  // { dg-error "enclosing parallel" }
+    bar (&c);                          // { dg-error "not specified" }
+  #pragma omp parallel default (none)
+    bar (&d);
+  #pragma omp parallel default (none)  // { dg-error "enclosing parallel" }
+    bar (&e);                          // { dg-error "not specified" }
+  #pragma omp parallel default (none)
+    bar (&f);
+  #pragma omp parallel default (none)  // { dg-error "enclosing parallel" }
+    bar (&g);                          // { dg-error "not specified" }
+  return f;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/task-1.C b/gcc/testsuite/g++.dg/gomp/task-1.C
new file mode 100644 (file)
index 0000000..0000e6f
--- /dev/null
@@ -0,0 +1,17 @@
+// { dg-do compile }
+// { dg-options "-fopenmp" }
+
+struct A { A (); ~A (); int i; };
+
+template <typename T> void bar (T &);
+
+const A a;
+
+void foo (A &p)
+{
+  const A &q = a;
+#pragma omp task       // { dg-error "has reference type" }
+  bar (p);
+#pragma omp task       // { dg-error "has reference type" }
+  bar (q);
+}
index 96baec9453eef93cec59adb0ea4c3442acf2e837..04f6bbea4081a37d9203040e385b3596d997deab 100644 (file)
@@ -13,9 +13,11 @@ namespace N
 struct S
 {
   static int s;
-#pragma omp thr (s) // { dg-error "is not file, namespace or block scope" }
+#pragma omp thr (s)
 };
 
+int S::s = 5;
+
 int
 foo ()
 {
diff --git a/gcc/testsuite/g++.dg/gomp/tls-4.C b/gcc/testsuite/g++.dg/gomp/tls-4.C
new file mode 100644 (file)
index 0000000..e4377c5
--- /dev/null
@@ -0,0 +1,16 @@
+// { dg-do compile }
+// { dg-require-effective-target tls_native }
+
+#define thr threadprivate
+
+struct S
+{
+  static int s;
+};
+struct T : public S
+{
+  static int t;
+#pragma omp thr (s)    // { dg-error "directive not in" }
+};
+
+#pragma omp thr (T::t) // { dg-error "directive not in" }
index 88824031cc2bb3187a92ec9908d4289c2c0d937b..d7579e6e7358e7bb7e2e25e8f85889d94921f29f 100644 (file)
@@ -11,7 +11,7 @@ wrong4 (int n)
       {
        work (i, 0);
        /* incorrect nesting of barrier region in a loop region */
-#pragma omp barrier
+#pragma omp barrier    /* { dg-warning "may not be closely nested" } */
        work (i, 1);
       }
   }
index 6385db308970b44d1e864bd5d02487ad7a330774..ac850e5410a5e79dae584c69a2b8cf5f51b990c1 100644 (file)
@@ -9,7 +9,7 @@ wrong6 (int n)
     {
       work (n, 0);
 /* incorrect nesting of barrier region in a single region */
-#pragma omp barrier
+#pragma omp barrier    /* { dg-warning "may not be closely nested" } */
       work (n, 1);
     }
   }
diff --git a/gcc/testsuite/gcc.dg/gomp/collapse-1.c b/gcc/testsuite/gcc.dg/gomp/collapse-1.c
new file mode 100644 (file)
index 0000000..89b76bb
--- /dev/null
@@ -0,0 +1,92 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+int i, j, k;
+extern int foo (void);
+
+void
+f1 (void)
+{
+  #pragma omp for collapse (2)
+  for (i = 0; i < 5; i++)
+    ;                                  /* { dg-error "not enough perfectly nested" } */
+  {
+    for (j = 0; j < 5; j++)
+      ;
+  }
+}
+
+void
+f2 (void)
+{
+  #pragma omp for collapse (2)
+  for (i = 0; i < 5; i++)
+    {
+      {
+       {
+         for (j = 0; j < 5; j++)
+           {
+           }
+       }
+      }
+    }
+}
+
+void
+f3 (void)
+{
+  #pragma omp for collapse (2)
+  for (i = 0; i < 5; i++)
+    {
+      int k = foo ();                  /* { dg-error "not enough perfectly nested" } */
+      {
+       {
+         for (j = 0; j < 5; j++)
+           {
+           }
+       }
+      }
+    }
+}
+
+void
+f4 (void)
+{
+  #pragma omp for collapse (2)
+  for (i = 0; i < 5; i++)
+    {
+      {
+       for (j = 0; j < 5; j++)
+         ;
+       foo ();                         /* { dg-error "collapsed loops not perfectly nested before" } */
+      }
+    }
+}
+
+void
+f5 (void)
+{
+  #pragma omp for collapse (2)
+  for (i = 0; i < 5; i++)
+    {
+      {
+       for (j = 0; j < 5; j++)
+         ;
+      }
+      foo ();                          /* { dg-error "collapsed loops not perfectly nested before" } */
+    }
+}
+
+void
+f6 (void)
+{
+  #pragma omp for collapse (2)
+  for (i = 0; i < 5; i++)
+    {
+      {
+       for (j = 0; j < 5; j++)
+         ;
+      }
+    }
+  foo ();
+}
diff --git a/gcc/testsuite/gcc.dg/gomp/nesting-1.c b/gcc/testsuite/gcc.dg/gomp/nesting-1.c
new file mode 100644 (file)
index 0000000..6f27b90
--- /dev/null
@@ -0,0 +1,198 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+void
+f1 (void)
+{
+  int i, j;
+  #pragma omp for
+  for (i = 0; i < 3; i++)
+    {
+      #pragma omp for          /* { dg-warning "may not be closely nested" } */
+      for (j = 0; j < 3; j++)
+       ;
+      #pragma omp sections     /* { dg-warning "may not be closely nested" } */
+      {
+       ;
+      #pragma omp section
+       ;
+      }
+      #pragma omp single       /* { dg-warning "may not be closely nested" } */
+       ;
+    #pragma omp master         /* { dg-warning "may not be closely nested" } */
+      ;
+      #pragma omp barrier      /* { dg-warning "may not be closely nested" } */
+    }
+  #pragma omp sections
+  {
+    #pragma omp for            /* { dg-warning "may not be closely nested" } */
+    for (j = 0; j < 3; j++)
+      ;
+    #pragma omp sections       /* { dg-warning "may not be closely nested" } */
+    {
+      ;
+    #pragma omp section
+      ;
+    }
+    #pragma omp single         /* { dg-warning "may not be closely nested" } */
+      ;
+    #pragma omp master         /* { dg-warning "may not be closely nested" } */
+      ;
+    #pragma omp section
+      ;
+  }
+  #pragma omp single
+  {
+    #pragma omp for            /* { dg-warning "may not be closely nested" } */
+    for (j = 0; j < 3; j++)
+      ;
+    #pragma omp sections       /* { dg-warning "may not be closely nested" } */
+    {
+      ;
+    #pragma omp section
+      ;
+    }
+    #pragma omp single         /* { dg-warning "may not be closely nested" } */
+      ;
+    #pragma omp master         /* { dg-warning "may not be closely nested" } */
+      ;
+    #pragma omp barrier                /* { dg-warning "may not be closely nested" } */
+  }
+  #pragma omp master
+  {
+    #pragma omp for            /* { dg-warning "may not be closely nested" } */
+    for (j = 0; j < 3; j++)
+      ;
+    #pragma omp sections       /* { dg-warning "may not be closely nested" } */
+    {
+      ;
+    #pragma omp section
+      ;
+    }
+    #pragma omp single         /* { dg-warning "may not be closely nested" } */
+      ;
+    #pragma omp master
+      ;
+    #pragma omp barrier                /* { dg-warning "may not be closely nested" } */
+  }
+  #pragma omp task
+  {
+    #pragma omp for            /* { dg-warning "may not be closely nested" } */
+    for (j = 0; j < 3; j++)
+      ;
+    #pragma omp sections       /* { dg-warning "may not be closely nested" } */
+    {
+      ;
+    #pragma omp section
+      ;
+    }
+    #pragma omp single         /* { dg-warning "may not be closely nested" } */
+      ;
+    #pragma omp master         /* { dg-warning "may not be closely nested" } */
+      ;
+    #pragma omp barrier                /* { dg-warning "may not be closely nested" } */
+  }
+  #pragma omp parallel
+  {
+    #pragma omp for
+    for (j = 0; j < 3; j++)
+      ;
+    #pragma omp sections
+    {
+      ;
+    #pragma omp section
+      ;
+    }
+    #pragma omp single
+      ;
+    #pragma omp master
+      ;
+    #pragma omp barrier
+  }
+}
+
+void
+f2 (void)
+{
+  int i, j;
+  #pragma omp ordered
+  {
+    #pragma omp for            /* { dg-warning "may not be closely nested" } */
+    for (j = 0; j < 3; j++)
+      ;
+    #pragma omp sections       /* { dg-warning "may not be closely nested" } */
+    {
+      ;
+    #pragma omp section
+      ;
+    }
+    #pragma omp single         /* { dg-warning "may not be closely nested" } */
+      ;
+    #pragma omp master
+      ;
+    #pragma omp barrier                /* { dg-warning "may not be closely nested" } */
+  }
+}
+
+void
+f3 (void)
+{
+  #pragma omp critical
+  {
+    #pragma omp ordered                /* { dg-warning "may not be closely nested" } */
+      ;
+  }
+}
+
+void
+f4 (void)
+{
+  #pragma omp task
+  {
+    #pragma omp ordered                /* { dg-warning "may not be closely nested" } */
+      ;
+  }
+}
+
+void
+f5 (void)
+{
+  int i;
+  #pragma omp for
+  for (i = 0; i < 10; i++)
+    {
+      #pragma omp ordered              /* { dg-warning "must be closely nested" } */
+       ;
+    }
+  #pragma omp for ordered
+  for (i = 0; i < 10; i++)
+    {
+      #pragma omp ordered
+       ;
+    }
+}
+
+void
+f6 (void)
+{
+  #pragma omp critical (foo)
+    #pragma omp critical (bar)
+      ;
+  #pragma omp critical
+    #pragma omp critical (baz)
+      ;
+}
+
+void
+f7 (void)
+{
+  #pragma omp critical (foo2)
+    #pragma omp critical
+      ;
+  #pragma omp critical (bar)
+    #pragma omp critical (bar)         /* { dg-warning "may not be nested" } */
+      ;
+  #pragma omp critical
+    #pragma omp critical               /* { dg-warning "may not be nested" } */
+      ;
+}
index e8c1db496d701186b05a7141d0c2ed84ccf07edb..0de2e0686f15bebd1e98a48a177ff8fa0a7ff297 100644 (file)
@@ -8,6 +8,6 @@ foo (void)
 {
   unsigned int i;
 #pragma omp parallel for
-  for (i = 0; i < 64; ++i)     /* { dg-warning "is unsigned" } */
+  for (i = 0; i < 64; ++i)
     bar (i);
 }
index 9685b5939c81575aeaea22a734fa502c10bea527..7a9e1840b2445290977571ddb4c5845fd38ced5e 100644 (file)
@@ -4,7 +4,7 @@
         REAL, DIMENSION(:), ALLOCATABLE :: A
         REAL, DIMENSION(:), POINTER :: B
         ALLOCATE (A(N))
-!$OMP SINGLE            ! { dg-error "COPYPRIVATE clause object 'a'" }
+!$OMP SINGLE
             ALLOCATE (B(N))
         READ (11) A,B
 !$OMP END SINGLE COPYPRIVATE(A,B)
index e44952263f1ac39d34a4db2b90bb4f92cd14f814..f130dd5f480742aeb6f2526492d852055c01009d 100644 (file)
@@ -8,7 +8,7 @@
           DO I = 1, N
              CALL WORK(I, 1)
 ! incorrect nesting of barrier region in a loop region
-!$OMP BARRIER
+!$OMP BARRIER  ! { dg-warning "may not be closely nested" }
              CALL WORK(I, 2)
           END DO
 !$OMP END PARALLEL
index 0488537dd1039de6e3c8a07cfefeec710ca2c2db..62ba245236b1a96c584f00f3092cb41f0f72804c 100644 (file)
@@ -6,7 +6,7 @@
 !$OMP SINGLE
            CALL WORK(N,1)
 ! incorrect nesting of barrier region in a single region
-!$OMP BARRIER
+!$OMP BARRIER  ! { dg-warning "may not be closely nested" }
             CALL WORK(N,2)
 !$OMP END SINGLE
 !$OMP END PARALLEL
diff --git a/gcc/testsuite/gfortran.dg/gomp/collapse1.f90 b/gcc/testsuite/gfortran.dg/gomp/collapse1.f90
new file mode 100644 (file)
index 0000000..f16a780
--- /dev/null
@@ -0,0 +1,57 @@
+! { dg-do compile }
+! { dg-options "-fopenmp" }
+
+subroutine collapse1
+  integer :: i, j, k, a(1:3, 4:6, 5:7)
+  real :: r
+  logical :: l
+  integer, save :: thr
+  !$omp threadprivate (thr)
+  l = .false.
+  a(:, :, :) = 0
+  !$omp parallel do collapse(4) schedule(static, 4) ! { dg-error "not enough DO loops for collapsed" }
+    do i = 1, 3
+      do j = 4, 6
+        do k = 5, 7
+          a(i, j, k) = i + j + k
+        end do
+      end do
+    end do
+  !$omp parallel do collapse(2)
+    do i = 1, 5, 2
+      do j = i + 1, 7, i       ! { dg-error "collapsed loops don.t form rectangular iteration space" }
+      end do
+    end do
+  !$omp parallel do collapse(2) shared(j)
+    do i = 1, 3
+      do j = 4, 6              ! { dg-error "iteration variable present on clause other than PRIVATE or LASTPRIVATE" }
+      end do
+    end do
+  !$omp parallel do collapse(2)
+    do i = 1, 3
+      do j = 4, 6
+      end do
+      k = 4
+    end do
+  !$omp parallel do collapse(2)
+    do i = 1, 3
+      do                       ! { dg-error "cannot be a DO WHILE or DO without loop control" }
+      end do
+    end do
+  !$omp parallel do collapse(2)
+    do i = 1, 3
+      do r = 4, 6              ! { dg-warning "must be integer" }
+      end do
+    end do
+end subroutine collapse1
+
+subroutine collapse1_2
+  integer :: i
+  !$omp parallel do collapse(2)
+    do i = -6, 6               ! { dg-error "cannot be redefined inside loop beginning" }
+      do i = 4, 6              ! { dg-error "collapsed loops don.t form rectangular iteration space|cannot be redefined" }
+      end do
+    end do
+end subroutine collapse1_2
+
+! { dg-error "iteration variable must be of type integer" "integer" { target *-*-* } 43 }
index d4137cd11ec2f375a3efb38af7ed7b76d3f6309c..3ab43670762c4740169d928a32d823cde35980b5 100644 (file)
@@ -14,10 +14,6 @@ call bar
 !$omp rallel
 call bar
 !$omp end parallel
-! Non-continuation !$omp must be followed by space, and my reading
-! doesn't seem to allow tab there.  So such lines should be completely
-! ignored.
-!$omp  strange  !  { dg-warning "starts a commented line" }
 end
 
 ! { dg-final { scan-tree-dump-times "pragma omp parallel" 3 "omplower" } }
index 108e5dc4155a943aeaba85294da5a878f3251525..9c55d173c11828fc38c33841aaa2799ed34c6f15 100644 (file)
@@ -56,7 +56,7 @@ common /blk/ i1
 !$omp end parallel
 !$omp parallel reduction (*:p1)                ! { dg-error "POINTER object" }
 !$omp end parallel
-!$omp parallel reduction (-:aa1)       ! { dg-error "is ALLOCATABLE" }
+!$omp parallel reduction (-:aa1)
 !$omp end parallel
 !$omp parallel reduction (*:ia1)       ! { dg-error "Assumed size" }
 !$omp end parallel
diff --git a/gcc/testsuite/gfortran.dg/gomp/sharing-3.f90 b/gcc/testsuite/gfortran.dg/gomp/sharing-3.f90
new file mode 100644 (file)
index 0000000..5c15814
--- /dev/null
@@ -0,0 +1,37 @@
+! { dg-do compile }
+! { dg-options "-fopenmp" }
+
+subroutine foo (vara, varb, varc, vard, n)
+  integer :: n, vara(n), varb(*), varc(:), vard(6), vare(6)
+  vare(:) = 0
+  !$omp parallel default(none) shared(vara, varb, varc, vard, vare)
+    !$omp master
+      vara(1) = 1
+      varb(1) = 1
+      varc(1) = 1
+      vard(1) = 1
+      vare(1) = 1
+    !$omp end master
+  !$omp end parallel
+  !$omp parallel default(none) private(vara, varc, vard, vare)
+    vara(1) = 1
+    varc(1) = 1
+    vard(1) = 1
+    vare(1) = 1
+  !$omp end parallel
+  !$omp parallel default(none) firstprivate(vara, varc, vard, vare)
+    vara(1) = 1
+    varc(1) = 1
+    vard(1) = 1
+    vare(1) = 1
+  !$omp end parallel
+  !$omp parallel default(none) ! { dg-error "enclosing parallel" }
+    !$omp master
+      vara(1) = 1              ! { dg-error "not specified" }
+      varb(1) = 1              ! Assumed-size is predetermined
+      varc(1) = 1              ! { dg-error "not specified" "" { xfail *-*-* } }
+      vard(1) = 1              ! { dg-error "not specified" }
+      vare(1) = 1              ! { dg-error "not specified" }
+    !$omp end master
+  !$omp end parallel
+end subroutine foo
index c0cb7b87488924b8f1c2e26271a6a5f57b0175f8..3034ba339e1e2600fbd2e3f6302e1142064ebde6 100644 (file)
@@ -523,6 +523,7 @@ make_edges (void)
              break;
 
            case OMP_PARALLEL:
+           case OMP_TASK:
            case OMP_FOR:
            case OMP_SINGLE:
            case OMP_MASTER:
@@ -1936,16 +1937,17 @@ remove_useless_stmts_1 (tree *tp, struct rus_data *data)
       break;
 
     case OMP_PARALLEL:
+    case OMP_TASK:
       /* Make sure the outermost BIND_EXPR in OMP_BODY isn't removed
         as useless.  */
-      remove_useless_stmts_1 (&BIND_EXPR_BODY (OMP_BODY (*tp)), data);
+      remove_useless_stmts_1 (&BIND_EXPR_BODY (OMP_TASKREG_BODY (*tp)), data);
       data->last_goto = NULL;
       break;
 
     case OMP_SECTIONS:
     case OMP_SINGLE:
     case OMP_SECTION:
-    case OMP_MASTER :
+    case OMP_MASTER:
     case OMP_ORDERED:
     case OMP_CRITICAL:
       remove_useless_stmts_1 (&OMP_BODY (*tp), data);
index 2334e12634340ecb234825634dbb18afd6354466..8b05f93d5052535d99bfbc3f6e01b5008e698c46 100644 (file)
@@ -322,6 +322,7 @@ is_gimple_stmt (tree t)
     case OMP_CRITICAL:
     case OMP_RETURN:
     case OMP_CONTINUE:
+    case OMP_TASK:
     case OMP_ATOMIC_LOAD:
     case OMP_ATOMIC_STORE:
       /* These are always void.  */
index 48a6a2366ee5b1b652ff7eb2bcc4c4556c8724da..a9ca33b14d4689cbac1e7508ee9847ae61e4e0ef 100644 (file)
@@ -2478,6 +2478,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
       }
 
     case OMP_PARALLEL:
+    case OMP_TASK:
     case OMP_FOR:
     case OMP_SECTIONS:
     case OMP_SINGLE:
index 562e39a173a476c16a1ac0a48c647998f547d281..be5e87ca316a668dca5e553cb0f5189e9ad65b38 100644 (file)
@@ -677,6 +677,7 @@ walk_omp_for (walk_tree_fn callback, struct nesting_info *info, tree for_stmt)
 {
   struct walk_stmt_info wi;
   tree t, list = NULL, empty;
+  int i;
 
   walk_body (callback, info, &OMP_FOR_PRE_BODY (for_stmt));
 
@@ -687,36 +688,39 @@ walk_omp_for (walk_tree_fn callback, struct nesting_info *info, tree for_stmt)
   wi.info = info;
   wi.tsi = tsi_last (list);
 
-  t = OMP_FOR_INIT (for_stmt);
-  gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
-  SET_EXPR_LOCUS (empty, EXPR_LOCUS (t));
-  wi.val_only = false;
-  walk_tree (&GIMPLE_STMT_OPERAND (t, 0), callback, &wi, NULL);
-  wi.val_only = true;
-  wi.is_lhs = false;
-  walk_tree (&GIMPLE_STMT_OPERAND (t, 1), callback, &wi, NULL);
-
-  t = OMP_FOR_COND (for_stmt);
-  gcc_assert (COMPARISON_CLASS_P (t));
-  SET_EXPR_LOCUS (empty, EXPR_LOCUS (t));
-  wi.val_only = false;
-  walk_tree (&TREE_OPERAND (t, 0), callback, &wi, NULL);
-  wi.val_only = true;
-  wi.is_lhs = false;
-  walk_tree (&TREE_OPERAND (t, 1), callback, &wi, NULL);
-
-  t = OMP_FOR_INCR (for_stmt);
-  gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
-  SET_EXPR_LOCUS (empty, EXPR_LOCUS (t));
-  wi.val_only = false;
-  walk_tree (&GIMPLE_STMT_OPERAND (t, 0), callback, &wi, NULL);
-  t = GIMPLE_STMT_OPERAND (t, 1);
-  gcc_assert (BINARY_CLASS_P (t));
-  wi.val_only = false;
-  walk_tree (&TREE_OPERAND (t, 0), callback, &wi, NULL);
-  wi.val_only = true;
-  wi.is_lhs = false;
-  walk_tree (&TREE_OPERAND (t, 1), callback, &wi, NULL);
+  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) == GIMPLE_MODIFY_STMT);
+      SET_EXPR_LOCUS (empty, EXPR_LOCUS (t));
+      wi.val_only = false;
+      walk_tree (&GIMPLE_STMT_OPERAND (t, 0), callback, &wi, NULL);
+      wi.val_only = true;
+      wi.is_lhs = false;
+      walk_tree (&GIMPLE_STMT_OPERAND (t, 1), callback, &wi, NULL);
+
+      t = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), i);
+      gcc_assert (COMPARISON_CLASS_P (t));
+      SET_EXPR_LOCUS (empty, EXPR_LOCUS (t));
+      wi.val_only = false;
+      walk_tree (&TREE_OPERAND (t, 0), callback, &wi, NULL);
+      wi.val_only = true;
+      wi.is_lhs = false;
+      walk_tree (&TREE_OPERAND (t, 1), callback, &wi, NULL);
+
+      t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i);
+      gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
+      SET_EXPR_LOCUS (empty, EXPR_LOCUS (t));
+      wi.val_only = false;
+      walk_tree (&GIMPLE_STMT_OPERAND (t, 0), callback, &wi, NULL);
+      t = GIMPLE_STMT_OPERAND (t, 1);
+      gcc_assert (BINARY_CLASS_P (t));
+      wi.val_only = false;
+      walk_tree (&TREE_OPERAND (t, 0), callback, &wi, NULL);
+      wi.val_only = true;
+      wi.is_lhs = false;
+      walk_tree (&TREE_OPERAND (t, 1), callback, &wi, NULL);
+    }
 
   /* Remove empty statement added above from the end of statement list.  */
   tsi_delink (&wi.tsi);
@@ -1100,24 +1104,25 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
       break;
 
     case OMP_PARALLEL:
+    case OMP_TASK:
       save_suppress = info->suppress_expansion;
-      if (convert_nonlocal_omp_clauses (&OMP_PARALLEL_CLAUSES (t), wi))
+      if (convert_nonlocal_omp_clauses (&OMP_TASKREG_CLAUSES (t), wi))
        {
          tree c, decl;
          decl = get_chain_decl (info);
          c = build_omp_clause (OMP_CLAUSE_FIRSTPRIVATE);
          OMP_CLAUSE_DECL (c) = decl;
-         OMP_CLAUSE_CHAIN (c) = OMP_PARALLEL_CLAUSES (t);
-         OMP_PARALLEL_CLAUSES (t) = c;
+         OMP_CLAUSE_CHAIN (c) = OMP_TASKREG_CLAUSES (t);
+         OMP_TASKREG_CLAUSES (t) = c;
        }
 
       save_local_var_chain = info->new_local_var_chain;
       info->new_local_var_chain = NULL;
 
-      walk_body (convert_nonlocal_reference, info, &OMP_PARALLEL_BODY (t));
+      walk_body (convert_nonlocal_reference, info, &OMP_TASKREG_BODY (t));
 
       if (info->new_local_var_chain)
-       declare_vars (info->new_local_var_chain, OMP_PARALLEL_BODY (t), false);
+       declare_vars (info->new_local_var_chain, OMP_TASKREG_BODY (t), false);
       info->new_local_var_chain = save_local_var_chain;
       info->suppress_expansion = save_suppress;
       break;
@@ -1161,7 +1166,7 @@ static bool
 convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
 {
   struct nesting_info *info = wi->info;
-  bool need_chain = false;
+  bool need_chain = false, need_stmts = false;
   tree clause, decl;
   int dummy;
   bitmap new_suppress;
@@ -1173,13 +1178,25 @@ convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
     {
       switch (OMP_CLAUSE_CODE (clause))
        {
+       case OMP_CLAUSE_REDUCTION:
+         if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+           need_stmts = true;
+         goto do_decl_clause;
+
+       case OMP_CLAUSE_LASTPRIVATE:
+         if (OMP_CLAUSE_LASTPRIVATE_STMT (clause))
+           need_stmts = true;
+         goto do_decl_clause;
+
        case OMP_CLAUSE_PRIVATE:
        case OMP_CLAUSE_FIRSTPRIVATE:
-       case OMP_CLAUSE_LASTPRIVATE:
-       case OMP_CLAUSE_REDUCTION:
        case OMP_CLAUSE_COPYPRIVATE:
        case OMP_CLAUSE_SHARED:
+       do_decl_clause:
          decl = OMP_CLAUSE_DECL (clause);
+         if (TREE_CODE (decl) == VAR_DECL
+             && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
+           break;
          if (decl_function_context (decl) != info->context)
            {
              bitmap_set_bit (new_suppress, DECL_UID (decl));
@@ -1204,6 +1221,8 @@ convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
        case OMP_CLAUSE_ORDERED:
        case OMP_CLAUSE_DEFAULT:
        case OMP_CLAUSE_COPYIN:
+       case OMP_CLAUSE_COLLAPSE:
+       case OMP_CLAUSE_UNTIED:
          break;
 
        default:
@@ -1213,6 +1232,35 @@ convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
 
   info->suppress_expansion = new_suppress;
 
+  if (need_stmts)
+    for (clause = *pclauses; clause ; clause = OMP_CLAUSE_CHAIN (clause))
+      switch (OMP_CLAUSE_CODE (clause))
+       {
+       case OMP_CLAUSE_REDUCTION:
+         if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+           {
+             tree old_context
+               = DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause));
+             DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+               = info->context;
+             walk_body (convert_nonlocal_reference, info,
+                        &OMP_CLAUSE_REDUCTION_INIT (clause));
+             walk_body (convert_nonlocal_reference, info,
+                        &OMP_CLAUSE_REDUCTION_MERGE (clause));
+             DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+               = old_context;
+           }
+         break;
+
+       case OMP_CLAUSE_LASTPRIVATE:
+         walk_body (convert_nonlocal_reference, info,
+                    &OMP_CLAUSE_LASTPRIVATE_STMT (clause));
+         break;
+
+       default:
+         break;
+       }
+
   return need_chain;
 }
 
@@ -1392,24 +1440,25 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data)
       break;
 
     case OMP_PARALLEL:
+    case OMP_TASK:
       save_suppress = info->suppress_expansion;
-      if (convert_local_omp_clauses (&OMP_PARALLEL_CLAUSES (t), wi))
+      if (convert_local_omp_clauses (&OMP_TASKREG_CLAUSES (t), wi))
        {
          tree c;
          (void) get_frame_type (info);
          c = build_omp_clause (OMP_CLAUSE_SHARED);
          OMP_CLAUSE_DECL (c) = info->frame_decl;
-         OMP_CLAUSE_CHAIN (c) = OMP_PARALLEL_CLAUSES (t);
-         OMP_PARALLEL_CLAUSES (t) = c;
+         OMP_CLAUSE_CHAIN (c) = OMP_TASKREG_CLAUSES (t);
+         OMP_TASKREG_CLAUSES (t) = c;
        }
 
       save_local_var_chain = info->new_local_var_chain;
       info->new_local_var_chain = NULL;
 
-      walk_body (convert_local_reference, info, &OMP_PARALLEL_BODY (t));
+      walk_body (convert_local_reference, info, &OMP_TASKREG_BODY (t));
 
       if (info->new_local_var_chain)
-       declare_vars (info->new_local_var_chain, OMP_PARALLEL_BODY (t), false);
+       declare_vars (info->new_local_var_chain, OMP_TASKREG_BODY (t), false);
       info->new_local_var_chain = save_local_var_chain;
       info->suppress_expansion = save_suppress;
       break;
@@ -1453,7 +1502,7 @@ static bool
 convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
 {
   struct nesting_info *info = wi->info;
-  bool need_frame = false;
+  bool need_frame = false, need_stmts = false;
   tree clause, decl;
   int dummy;
   bitmap new_suppress;
@@ -1465,13 +1514,25 @@ convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
     {
       switch (OMP_CLAUSE_CODE (clause))
        {
+       case OMP_CLAUSE_REDUCTION:
+         if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+           need_stmts = true;
+         goto do_decl_clause;
+
+       case OMP_CLAUSE_LASTPRIVATE:
+         if (OMP_CLAUSE_LASTPRIVATE_STMT (clause))
+           need_stmts = true;
+         goto do_decl_clause;
+
        case OMP_CLAUSE_PRIVATE:
        case OMP_CLAUSE_FIRSTPRIVATE:
-       case OMP_CLAUSE_LASTPRIVATE:
-       case OMP_CLAUSE_REDUCTION:
        case OMP_CLAUSE_COPYPRIVATE:
        case OMP_CLAUSE_SHARED:
+       do_decl_clause:
          decl = OMP_CLAUSE_DECL (clause);
+         if (TREE_CODE (decl) == VAR_DECL
+             && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
+           break;
          if (decl_function_context (decl) == info->context
              && !use_pointer_in_frame (decl))
            {
@@ -1501,6 +1562,8 @@ convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
        case OMP_CLAUSE_ORDERED:
        case OMP_CLAUSE_DEFAULT:
        case OMP_CLAUSE_COPYIN:
+       case OMP_CLAUSE_COLLAPSE:
+       case OMP_CLAUSE_UNTIED:
          break;
 
        default:
@@ -1510,6 +1573,35 @@ convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
 
   info->suppress_expansion = new_suppress;
 
+  if (need_stmts)
+    for (clause = *pclauses; clause ; clause = OMP_CLAUSE_CHAIN (clause))
+      switch (OMP_CLAUSE_CODE (clause))
+       {
+       case OMP_CLAUSE_REDUCTION:
+         if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+           {
+             tree old_context
+               = DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause));
+             DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+               = info->context;
+             walk_body (convert_local_reference, info,
+                        &OMP_CLAUSE_REDUCTION_INIT (clause));
+             walk_body (convert_local_reference, info,
+                        &OMP_CLAUSE_REDUCTION_MERGE (clause));
+             DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+               = old_context;
+           }
+         break;
+
+       case OMP_CLAUSE_LASTPRIVATE:
+         walk_body (convert_local_reference, info,
+                    &OMP_CLAUSE_LASTPRIVATE_STMT (clause));
+         break;
+
+       default:
+         break;
+       }
+
   return need_frame;
 }
 
@@ -1731,9 +1823,10 @@ convert_call_expr (tree *tp, int *walk_subtrees, void *data)
       break;
 
     case OMP_PARALLEL:
+    case OMP_TASK:
       save_static_chain_added = info->static_chain_added;
       info->static_chain_added = 0;
-      walk_body (convert_call_expr, info, &OMP_PARALLEL_BODY (t));
+      walk_body (convert_call_expr, info, &OMP_TASKREG_BODY (t));
       for (i = 0; i < 2; i++)
        {
          tree c, decl;
@@ -1741,7 +1834,7 @@ convert_call_expr (tree *tp, int *walk_subtrees, void *data)
            continue;
          decl = i ? get_chain_decl (info) : info->frame_decl;
          /* Don't add CHAIN.* or FRAME.* twice.  */
-         for (c = OMP_PARALLEL_CLAUSES (t); c; c = OMP_CLAUSE_CHAIN (c))
+         for (c = OMP_TASKREG_CLAUSES (t); c; c = OMP_CLAUSE_CHAIN (c))
            if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
                 || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED)
                && OMP_CLAUSE_DECL (c) == decl)
@@ -1751,8 +1844,8 @@ convert_call_expr (tree *tp, int *walk_subtrees, void *data)
              c = build_omp_clause (i ? OMP_CLAUSE_FIRSTPRIVATE
                                      : OMP_CLAUSE_SHARED);
              OMP_CLAUSE_DECL (c) = decl;
-             OMP_CLAUSE_CHAIN (c) = OMP_PARALLEL_CLAUSES (t);
-             OMP_PARALLEL_CLAUSES (t) = c;
+             OMP_CLAUSE_CHAIN (c) = OMP_TASKREG_CLAUSES (t);
+             OMP_TASKREG_CLAUSES (t) = c;
            }
        }
       info->static_chain_added |= save_static_chain_added;
index 8754432eb301b0c9a83e9c90863f1882111794ef..8344093ba6bc4c67a71fec2628495fb2cc6fe783 100644 (file)
@@ -1617,13 +1617,16 @@ create_parallel_loop (struct loop *loop, tree loop_fn, tree data,
   for_stmt = make_node (OMP_FOR);
   TREE_TYPE (for_stmt) = void_type_node;
   OMP_FOR_CLAUSES (for_stmt) = t;
-  OMP_FOR_INIT (for_stmt) = build_gimple_modify_stmt (initvar, cvar_init);
-  OMP_FOR_COND (for_stmt) = cond;
-  OMP_FOR_INCR (for_stmt) = build_gimple_modify_stmt (cvar_base,
-                                                     build2 (PLUS_EXPR, type,
-                                                             cvar_base,
-                                                             build_int_cst
-                                                             (type, 1)));
+  OMP_FOR_INIT (for_stmt) = make_tree_vec (1);
+  TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), 0)
+    = build_gimple_modify_stmt (initvar, cvar_init);
+  OMP_FOR_COND (for_stmt) = make_tree_vec (1);
+  TREE_VEC_ELT (OMP_FOR_COND (for_stmt), 0) = cond;
+  OMP_FOR_INCR (for_stmt) = make_tree_vec (2);
+  TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), 0)
+    = build_gimple_modify_stmt (cvar_base,
+                               build2 (PLUS_EXPR, type, cvar_base,
+                                       build_int_cst (type, 1)));
   OMP_FOR_BODY (for_stmt) = NULL_TREE;
   OMP_FOR_PRE_BODY (for_stmt) = NULL_TREE;
 
index a15e49b575974a305df2d85f0af224e905a4daa6..2f7de8f1c7d671a7c872b749ab4fe6f9e6570aeb 100644 (file)
@@ -334,19 +334,22 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags)
       pp_string (buffer, "default(");
       switch (OMP_CLAUSE_DEFAULT_KIND (clause))
        {
-      case OMP_CLAUSE_DEFAULT_UNSPECIFIED:
-       break;
-      case OMP_CLAUSE_DEFAULT_SHARED:
-       pp_string (buffer, "shared");
-       break;
-      case OMP_CLAUSE_DEFAULT_NONE:
-       pp_string (buffer, "none");
-       break;
-      case OMP_CLAUSE_DEFAULT_PRIVATE:
-       pp_string (buffer, "private");
-       break;
-      default:
-       gcc_unreachable ();
+       case OMP_CLAUSE_DEFAULT_UNSPECIFIED:
+         break;
+       case OMP_CLAUSE_DEFAULT_SHARED:
+         pp_string (buffer, "shared");
+         break;
+       case OMP_CLAUSE_DEFAULT_NONE:
+         pp_string (buffer, "none");
+         break;
+       case OMP_CLAUSE_DEFAULT_PRIVATE:
+         pp_string (buffer, "private");
+         break;
+       case OMP_CLAUSE_DEFAULT_FIRSTPRIVATE:
+         pp_string (buffer, "firstprivate");
+         break;
+       default:
+         gcc_unreachable ();
        }
       pp_character (buffer, ')');
       break;
@@ -367,6 +370,9 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags)
       case OMP_CLAUSE_SCHEDULE_RUNTIME:
        pp_string (buffer, "runtime");
        break;
+      case OMP_CLAUSE_SCHEDULE_AUTO:
+       pp_string (buffer, "auto");
+       break;
       default:
        gcc_unreachable ();
        }
@@ -380,6 +386,18 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags)
       pp_character (buffer, ')');
       break;
 
+    case OMP_CLAUSE_UNTIED:
+      pp_string (buffer, "untied");
+      break;
+
+    case OMP_CLAUSE_COLLAPSE:
+      pp_string (buffer, "collapse(");
+      dump_generic_node (buffer,
+                        OMP_CLAUSE_COLLAPSE_EXPR (clause),
+                        spc, flags, false);
+      pp_character (buffer, ')');
+      break;
+
     default:
       /* Should never happen.  */
       dump_generic_node (buffer, clause, spc, flags, false);
@@ -1863,12 +1881,41 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
       is_expr = false;
       break;
 
+    case OMP_TASK:
+      pp_string (buffer, "#pragma omp task");
+      dump_omp_clauses (buffer, OMP_TASK_CLAUSES (node), spc, flags);
+      if (OMP_TASK_FN (node))
+       {
+         pp_string (buffer, " [child fn: ");
+         dump_generic_node (buffer, OMP_TASK_FN (node), spc, flags, false);
+
+         pp_string (buffer, " (");
+
+         if (OMP_TASK_DATA_ARG (node))
+           dump_generic_node (buffer, OMP_TASK_DATA_ARG (node), spc, flags,
+                              false);
+         else
+           pp_string (buffer, "???");
+
+         pp_character (buffer, ')');
+         if (OMP_TASK_COPYFN (node))
+           {
+             pp_string (buffer, ", copy fn: ");
+             dump_generic_node (buffer, OMP_TASK_COPYFN (node), spc,
+                                flags, false);
+           }
+         pp_character (buffer, ']');
+       }
+      goto dump_omp_body;
+
     case OMP_FOR:
       pp_string (buffer, "#pragma omp for");
       dump_omp_clauses (buffer, OMP_FOR_CLAUSES (node), spc, flags);
 
       if (!(flags & TDF_SLIM))
        {
+         int i;
+
          if (OMP_FOR_PRE_BODY (node))
            {
              newline_and_indent (buffer, spc + 2);
@@ -1878,14 +1925,22 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
              dump_generic_node (buffer, OMP_FOR_PRE_BODY (node),
                  spc, flags, false);
            }
-         newline_and_indent (buffer, spc);
-         pp_string (buffer, "for (");
-         dump_generic_node (buffer, OMP_FOR_INIT (node), spc, flags, false);
-         pp_string (buffer, "; ");
-         dump_generic_node (buffer, OMP_FOR_COND (node), spc, flags, false);
-         pp_string (buffer, "; ");
-         dump_generic_node (buffer, OMP_FOR_INCR (node), spc, flags, false);
-         pp_string (buffer, ")");
+         spc -= 2;
+         for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (node)); i++)
+           {
+             spc += 2;
+             newline_and_indent (buffer, spc);
+             pp_string (buffer, "for (");
+             dump_generic_node (buffer, TREE_VEC_ELT (OMP_FOR_INIT (node), i),
+                                spc, flags, false);
+             pp_string (buffer, "; ");
+             dump_generic_node (buffer, TREE_VEC_ELT (OMP_FOR_COND (node), i),
+                                spc, flags, false);
+             pp_string (buffer, "; ");
+             dump_generic_node (buffer, TREE_VEC_ELT (OMP_FOR_INCR (node), i),
+                                spc, flags, false);
+             pp_string (buffer, ")");
+           }
          if (OMP_FOR_BODY (node))
            {
              newline_and_indent (buffer, spc + 2);
@@ -1896,6 +1951,7 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
              newline_and_indent (buffer, spc + 2);
              pp_character (buffer, '}');
            }
+         spc -= 2 * TREE_VEC_LENGTH (OMP_FOR_INIT (node)) - 2;
          if (OMP_FOR_PRE_BODY (node))
            {
              spc -= 4;
index 102ed5af3d47f51308d8789dce7ef50e0125190d..71fb883f84a4f101bd8a1e47a289efc57a37e916 100644 (file)
@@ -2093,17 +2093,22 @@ get_expr_operands (tree stmt, tree *expr_p, int flags)
 
     case OMP_FOR:
       {
-       tree init = OMP_FOR_INIT (expr);
-       tree cond = OMP_FOR_COND (expr);
-       tree incr = OMP_FOR_INCR (expr);
        tree c, clauses = OMP_FOR_CLAUSES (stmt);
+       int i;
 
-       get_expr_operands (stmt, &GIMPLE_STMT_OPERAND (init, 0), opf_def);
-       get_expr_operands (stmt, &GIMPLE_STMT_OPERAND (init, 1), opf_use);
-       get_expr_operands (stmt, &TREE_OPERAND (cond, 1), opf_use);
-       get_expr_operands (stmt,
-                          &TREE_OPERAND (GIMPLE_STMT_OPERAND (incr, 1), 1),
-                          opf_use);
+       for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (expr)); i++)
+         {
+           tree init = TREE_VEC_ELT (OMP_FOR_INIT (expr), i);
+           tree cond = TREE_VEC_ELT (OMP_FOR_COND (expr), i);
+           tree incr = TREE_VEC_ELT (OMP_FOR_INCR (expr), i);
+
+           get_expr_operands (stmt, &GIMPLE_STMT_OPERAND (init, 0), opf_def);
+           get_expr_operands (stmt, &GIMPLE_STMT_OPERAND (init, 1), opf_use);
+           get_expr_operands (stmt, &TREE_OPERAND (cond, 1), opf_use);
+           get_expr_operands (stmt,
+                              &TREE_OPERAND (GIMPLE_STMT_OPERAND (incr, 1),
+                                             1), opf_use);
+         }
 
        c = find_omp_clause (clauses, OMP_CLAUSE_SCHEDULE);
        if (c)
index 2d0ddc330738822b4d1d876b85fca183361f1ad2..8bf2b7718afa065674a5a4fb168a4dd019cf8b0c 100644 (file)
@@ -177,7 +177,7 @@ unsigned const char omp_clause_num_ops[] =
   1, /* OMP_CLAUSE_PRIVATE  */
   1, /* OMP_CLAUSE_SHARED  */
   1, /* OMP_CLAUSE_FIRSTPRIVATE  */
-  1, /* OMP_CLAUSE_LASTPRIVATE  */
+  2, /* OMP_CLAUSE_LASTPRIVATE  */
   4, /* OMP_CLAUSE_REDUCTION  */
   1, /* OMP_CLAUSE_COPYIN  */
   1, /* OMP_CLAUSE_COPYPRIVATE  */
@@ -186,7 +186,9 @@ unsigned const char omp_clause_num_ops[] =
   1, /* OMP_CLAUSE_SCHEDULE  */
   0, /* OMP_CLAUSE_NOWAIT  */
   0, /* OMP_CLAUSE_ORDERED  */
-  0  /* OMP_CLAUSE_DEFAULT  */
+  0, /* OMP_CLAUSE_DEFAULT  */
+  3, /* OMP_CLAUSE_COLLAPSE  */
+  0  /* OMP_CLAUSE_UNTIED   */
 };
 
 const char * const omp_clause_code_name[] =
@@ -204,7 +206,9 @@ const char * const omp_clause_code_name[] =
   "schedule",
   "nowait",
   "ordered",
-  "default"
+  "default",
+  "collapse",
+  "untied"
 };
 \f
 /* Init tree.c.  */
@@ -8452,7 +8456,6 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data,
        case OMP_CLAUSE_PRIVATE:
        case OMP_CLAUSE_SHARED:
        case OMP_CLAUSE_FIRSTPRIVATE:
-       case OMP_CLAUSE_LASTPRIVATE:
        case OMP_CLAUSE_COPYIN:
        case OMP_CLAUSE_COPYPRIVATE:
        case OMP_CLAUSE_IF:
@@ -8464,8 +8467,22 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data,
        case OMP_CLAUSE_NOWAIT:
        case OMP_CLAUSE_ORDERED:
        case OMP_CLAUSE_DEFAULT:
+       case OMP_CLAUSE_UNTIED:
          WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp));
 
+       case OMP_CLAUSE_LASTPRIVATE:
+         WALK_SUBTREE (OMP_CLAUSE_DECL (*tp));
+         WALK_SUBTREE (OMP_CLAUSE_LASTPRIVATE_STMT (*tp));
+         WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp));
+
+       case OMP_CLAUSE_COLLAPSE:
+         {
+           int i;
+           for (i = 0; i < 3; i++)
+             WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, i));
+           WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp));
+         }
+
        case OMP_CLAUSE_REDUCTION:
          {
            int i;
index 2c0e9f63d5ba791c7cff2e49238f34e81b78b9fa..7474f2e68f1e2b370442e6669e0d9f0ab450fb0d 100644 (file)
@@ -1001,6 +1001,23 @@ DEFTREECODE (TARGET_MEM_REF, "target_mem_ref", tcc_reference, 7)
 
 DEFTREECODE (OMP_PARALLEL, "omp_parallel", tcc_statement, 4)
 
+/* OpenMP - #pragma omp task [clause1 ... clauseN]
+   Operand 0: OMP_TASK_BODY: Code to be executed by all threads.
+   Operand 1: OMP_TASK_CLAUSES: List of clauses.
+   Operand 2: OMP_TASK_FN: FUNCTION_DECL used when outlining the
+             body of the task region.  Only valid after
+             pass_lower_omp.
+   Operand 3: OMP_TASK_DATA_ARG: Local variable in the parent
+             function containing data to be shared with the child
+             function.
+   Operand 4: OMP_TASK_COPYFN: FUNCTION_DECL used for constructing
+             firstprivate variables.
+   Operand 5: OMP_TASK_ARG_SIZE: Length of the task argument block.
+   Operand 6: OMP_TASK_ARG_ALIGN: Required alignment of the task
+             argument block.  */
+
+DEFTREECODE (OMP_TASK, "omp_task", tcc_statement, 7)
+
 /* OpenMP - #pragma omp for [clause1 ... clauseN]
    Operand 0: OMP_FOR_BODY: Loop body.
    Operand 1: OMP_FOR_CLAUSES: List of clauses.
index c10cc0380e71ddfa06f69f88db9639c8baea8f38..c3d2abe6978fbae6e626578710762c83406bb2f7 100644 (file)
@@ -186,6 +186,7 @@ extern const enum tree_code_class tree_code_type[];
 
 #define OMP_DIRECTIVE_P(NODE)                          \
     (TREE_CODE (NODE) == OMP_PARALLEL                  \
+     || TREE_CODE (NODE) == OMP_TASK                   \
      || TREE_CODE (NODE) == OMP_FOR                    \
      || TREE_CODE (NODE) == OMP_SECTIONS               \
      || TREE_CODE (NODE) == OMP_SECTIONS_SWITCH                \
@@ -315,7 +316,7 @@ enum omp_clause_code
      Operand 2: OMP_CLAUSE_REDUCTION_MERGE: Stmt-list to merge private var
                 into the shared one.
      Operand 3: OMP_CLAUSE_REDUCTION_PLACEHOLDER: A dummy VAR_DECL
-                placeholder used in OMP_CLAUSE_REDUCTION_MERGE.  */
+                placeholder used in OMP_CLAUSE_REDUCTION_{INIT,MERGE}.  */
   OMP_CLAUSE_REDUCTION,
 
   /* OpenMP clause: copyin (variable_list).  */
@@ -340,7 +341,13 @@ enum omp_clause_code
   OMP_CLAUSE_ORDERED,
 
   /* OpenMP clause: default.  */
-  OMP_CLAUSE_DEFAULT
+  OMP_CLAUSE_DEFAULT,
+
+  /* OpenMP clause: collapse (constant-integer-expression).  */
+  OMP_CLAUSE_COLLAPSE,
+
+  /* OpenMP clause: untied.  */
+  OMP_CLAUSE_UNTIED
 };
 \f
 /* The definition of tree nodes fills the next several pages.  */
@@ -524,6 +531,8 @@ struct gimple_stmt GTY(())
 
        OMP_PARALLEL_COMBINED in
            OMP_PARALLEL
+       OMP_CLAUSE_PRIVATE_OUTER_REF in
+          OMP_CLAUSE_PRIVATE
 
    protected_flag:
 
@@ -1796,6 +1805,20 @@ struct tree_constructor GTY(())
 #define OMP_PARALLEL_FN(NODE) TREE_OPERAND (OMP_PARALLEL_CHECK (NODE), 2)
 #define OMP_PARALLEL_DATA_ARG(NODE) TREE_OPERAND (OMP_PARALLEL_CHECK (NODE), 3)
 
+#define OMP_TASK_BODY(NODE)       TREE_OPERAND (OMP_TASK_CHECK (NODE), 0)
+#define OMP_TASK_CLAUSES(NODE)    TREE_OPERAND (OMP_TASK_CHECK (NODE), 1)
+#define OMP_TASK_FN(NODE)         TREE_OPERAND (OMP_TASK_CHECK (NODE), 2)
+#define OMP_TASK_DATA_ARG(NODE)           TREE_OPERAND (OMP_TASK_CHECK (NODE), 3)
+#define OMP_TASK_COPYFN(NODE)     TREE_OPERAND (OMP_TASK_CHECK (NODE), 4)
+#define OMP_TASK_ARG_SIZE(NODE)           TREE_OPERAND (OMP_TASK_CHECK (NODE), 5)
+#define OMP_TASK_ARG_ALIGN(NODE)   TREE_OPERAND (OMP_TASK_CHECK (NODE), 6)
+
+#define OMP_TASKREG_CHECK(NODE)          TREE_RANGE_CHECK (NODE, OMP_PARALLEL, OMP_TASK)
+#define OMP_TASKREG_BODY(NODE)    TREE_OPERAND (OMP_TASKREG_CHECK (NODE), 0)
+#define OMP_TASKREG_CLAUSES(NODE) TREE_OPERAND (OMP_TASKREG_CHECK (NODE), 1)
+#define OMP_TASKREG_FN(NODE) TREE_OPERAND (OMP_TASKREG_CHECK (NODE), 2)
+#define OMP_TASKREG_DATA_ARG(NODE) TREE_OPERAND (OMP_TASKREG_CHECK (NODE), 3)
+
 #define OMP_FOR_BODY(NODE)        TREE_OPERAND (OMP_FOR_CHECK (NODE), 0)
 #define OMP_FOR_CLAUSES(NODE)     TREE_OPERAND (OMP_FOR_CHECK (NODE), 1)
 #define OMP_FOR_INIT(NODE)        TREE_OPERAND (OMP_FOR_CHECK (NODE), 2)
@@ -1848,10 +1871,19 @@ struct tree_constructor GTY(())
 #define OMP_CLAUSE_PRIVATE_DEBUG(NODE) \
   (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_PRIVATE)->base.public_flag)
 
+/* True on a PRIVATE clause if ctor needs access to outer region's
+   variable.  */
+#define OMP_CLAUSE_PRIVATE_OUTER_REF(NODE) \
+  TREE_PRIVATE (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_PRIVATE))
+
 /* True on a LASTPRIVATE clause if a FIRSTPRIVATE clause for the same
    decl is present in the chain.  */
 #define OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE(NODE) \
   (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_LASTPRIVATE)->base.public_flag)
+#define OMP_CLAUSE_LASTPRIVATE_STMT(NODE) \
+  OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE,                  \
+                                               OMP_CLAUSE_LASTPRIVATE),\
+                     1)
 
 #define OMP_CLAUSE_IF_EXPR(NODE) \
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_IF), 0)
@@ -1860,6 +1892,13 @@ struct tree_constructor GTY(())
 #define OMP_CLAUSE_SCHEDULE_CHUNK_EXPR(NODE) \
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_SCHEDULE), 0)
 
+#define OMP_CLAUSE_COLLAPSE_EXPR(NODE) \
+  OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_COLLAPSE), 0)
+#define OMP_CLAUSE_COLLAPSE_ITERVAR(NODE) \
+  OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_COLLAPSE), 1)
+#define OMP_CLAUSE_COLLAPSE_COUNT(NODE) \
+  OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_COLLAPSE), 2)
+
 #define OMP_CLAUSE_REDUCTION_CODE(NODE)        \
   (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_REDUCTION)->omp_clause.subcode.reduction_code)
 #define OMP_CLAUSE_REDUCTION_INIT(NODE) \
@@ -1874,6 +1913,7 @@ enum omp_clause_schedule_kind
   OMP_CLAUSE_SCHEDULE_STATIC,
   OMP_CLAUSE_SCHEDULE_DYNAMIC,
   OMP_CLAUSE_SCHEDULE_GUIDED,
+  OMP_CLAUSE_SCHEDULE_AUTO,
   OMP_CLAUSE_SCHEDULE_RUNTIME
 };
 
@@ -1885,7 +1925,8 @@ enum omp_clause_default_kind
   OMP_CLAUSE_DEFAULT_UNSPECIFIED,
   OMP_CLAUSE_DEFAULT_SHARED,
   OMP_CLAUSE_DEFAULT_NONE,
-  OMP_CLAUSE_DEFAULT_PRIVATE
+  OMP_CLAUSE_DEFAULT_PRIVATE,
+  OMP_CLAUSE_DEFAULT_FIRSTPRIVATE
 };
 
 #define OMP_CLAUSE_DEFAULT_KIND(NODE) \
index f67375898d1eb7c835dec8a576e98cfc053825bf..73a0aa70c0ca5a59a889602882426e86d33f0b37 100644 (file)
@@ -1,3 +1,470 @@
+2008-06-06  Jakub Jelinek  <jakub@redhat.com>
+           Richard Henderson  <rth@redhat.com>
+           Ulrich Drepper  <drepper@redhat.com>
+           Jakob Blomer  <jakob.blomer@ira.uka.de>
+
+       * 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.
+
+2008-06-06  Jakub Jelinek  <jakub@redhat.com>
+
+       * 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.
+
 2008-05-23  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/36308
index 55e3bf3ee15ceec173d1af99eb9d2df20c074b56..996802a913a7a9b5a7eb2617f8ee54aa886b99c1 100644 (file)
@@ -30,8 +30,9 @@ libgomp_version_info = -version-info $(libtool_VERSION)
 libgomp_la_LDFLAGS = $(libgomp_version_info) $(libgomp_version_script)
 
 libgomp_la_SOURCES = alloc.c barrier.c critical.c env.c error.c iter.c \
-       loop.c ordered.c parallel.c sections.c single.c team.c work.c \
-       lock.c mutex.c proc.c sem.c bar.c time.c fortran.c affinity.c
+       iter_ull.c loop.c loop_ull.c ordered.c parallel.c sections.c single.c \
+       task.c team.c work.c lock.c mutex.c proc.c sem.c bar.c ptrlock.c \
+       time.c fortran.c affinity.c
 
 nodist_noinst_HEADERS = libgomp_f.h
 nodist_libsubinclude_HEADERS = omp.h
index 0bdf07721cc3c5547338a2c89d9f776192cc0256..8e0f546c6dfdffdfe98295010c527aae77dfee3c 100644 (file)
@@ -83,9 +83,10 @@ toolexeclibLTLIBRARIES_INSTALL = $(INSTALL)
 LTLIBRARIES = $(toolexeclib_LTLIBRARIES)
 libgomp_la_LIBADD =
 am_libgomp_la_OBJECTS = alloc.lo barrier.lo critical.lo env.lo \
-       error.lo iter.lo loop.lo ordered.lo parallel.lo sections.lo \
-       single.lo team.lo work.lo lock.lo mutex.lo proc.lo sem.lo \
-       bar.lo time.lo fortran.lo affinity.lo
+       error.lo iter.lo iter_ull.lo loop.lo loop_ull.lo ordered.lo \
+       parallel.lo sections.lo single.lo task.lo team.lo work.lo \
+       lock.lo mutex.lo proc.lo sem.lo bar.lo ptrlock.lo time.lo \
+       fortran.lo affinity.lo
 libgomp_la_OBJECTS = $(am_libgomp_la_OBJECTS)
 DEFAULT_INCLUDES = -I. -I$(srcdir) -I.
 depcomp = $(SHELL) $(top_srcdir)/../depcomp
@@ -193,9 +194,15 @@ MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
 MAKEINFO = @MAKEINFO@
 NM = @NM@
 OBJEXT = @OBJEXT@
+OMP_LOCK_25_ALIGN = @OMP_LOCK_25_ALIGN@
+OMP_LOCK_25_KIND = @OMP_LOCK_25_KIND@
+OMP_LOCK_25_SIZE = @OMP_LOCK_25_SIZE@
 OMP_LOCK_ALIGN = @OMP_LOCK_ALIGN@
 OMP_LOCK_KIND = @OMP_LOCK_KIND@
 OMP_LOCK_SIZE = @OMP_LOCK_SIZE@
+OMP_NEST_LOCK_25_ALIGN = @OMP_NEST_LOCK_25_ALIGN@
+OMP_NEST_LOCK_25_KIND = @OMP_NEST_LOCK_25_KIND@
+OMP_NEST_LOCK_25_SIZE = @OMP_NEST_LOCK_25_SIZE@
 OMP_NEST_LOCK_ALIGN = @OMP_NEST_LOCK_ALIGN@
 OMP_NEST_LOCK_KIND = @OMP_NEST_LOCK_KIND@
 OMP_NEST_LOCK_SIZE = @OMP_NEST_LOCK_SIZE@
@@ -289,8 +296,9 @@ nodist_toolexeclib_HEADERS = libgomp.spec
 libgomp_version_info = -version-info $(libtool_VERSION)
 libgomp_la_LDFLAGS = $(libgomp_version_info) $(libgomp_version_script)
 libgomp_la_SOURCES = alloc.c barrier.c critical.c env.c error.c iter.c \
-       loop.c ordered.c parallel.c sections.c single.c team.c work.c \
-       lock.c mutex.c proc.c sem.c bar.c time.c fortran.c affinity.c
+       iter_ull.c loop.c loop_ull.c ordered.c parallel.c sections.c single.c \
+       task.c team.c work.c lock.c mutex.c proc.c sem.c bar.c ptrlock.c \
+       time.c fortran.c affinity.c
 
 nodist_noinst_HEADERS = libgomp_f.h
 nodist_libsubinclude_HEADERS = omp.h
@@ -426,15 +434,19 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/error.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fortran.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iter.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iter_ull.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lock.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loop.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loop_ull.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mutex.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ordered.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parallel.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ptrlock.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sections.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sem.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/single.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/task.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/team.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/time.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/work.Plo@am__quote@
index bcad683af5e86f4a8e7c12732198ae462f4ae448..24037aba17b7864bb6baf9e28a68ece0fc58e5b5 100644 (file)
@@ -40,5 +40,5 @@ GOMP_barrier (void)
   if (team == NULL)
     return;
 
-  gomp_barrier_wait (&team->barrier);
+  gomp_team_barrier_wait (&team->barrier);
 }
index eed8a8837af28001cde9d79a142fe992355edcd6..88a616ca1eddd783835de1718102de2c2d7bf2a5 100644 (file)
@@ -69,6 +69,9 @@
 /* Define to 1 if you have the <unistd.h> header file. */
 #undef HAVE_UNISTD_H
 
+/* Define to 1 if GNU symbol versioning is used for libgomp. */
+#undef LIBGOMP_GNU_SYMBOL_VERSIONING
+
 /* Define to the sub-directory in which libtool stores uninstalled libraries.
    */
 #undef LT_OBJDIR
index 8fcce5f3a5b4b303a02a3842e4fb821a8fb0517d..7b6d6c008d7b477065d488801eb0052a2b785822 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+/* Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
    Contributed by Jakub Jelinek <jakub@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
@@ -38,9 +38,6 @@
 #ifdef HAVE_PTHREAD_AFFINITY_NP
 
 static unsigned int affinity_counter;
-#ifndef HAVE_SYNC_BUILTINS
-static gomp_mutex_t affinity_lock;
-#endif
 
 void
 gomp_init_affinity (void)
@@ -76,9 +73,6 @@ gomp_init_affinity (void)
   CPU_SET (gomp_cpu_affinity[0], &cpuset);
   pthread_setaffinity_np (pthread_self (), sizeof (cpuset), &cpuset);
   affinity_counter = 1;
-#ifndef HAVE_SYNC_BUILTINS
-  gomp_mutex_init (&affinity_lock);
-#endif
 }
 
 void
@@ -87,13 +81,7 @@ gomp_init_thread_affinity (pthread_attr_t *attr)
   unsigned int cpu;
   cpu_set_t cpuset;
 
-#ifdef HAVE_SYNC_BUILTINS
   cpu = __sync_fetch_and_add (&affinity_counter, 1);
-#else
-  gomp_mutex_lock (&affinity_lock);
-  cpu = affinity_counter++;
-  gomp_mutex_unlock (&affinity_lock);
-#endif
   cpu %= gomp_cpu_affinity_len;
   CPU_ZERO (&cpuset);
   CPU_SET (gomp_cpu_affinity[cpu], &cpuset);
index 98681a8526ec7f3621f6e3e53bdc44efd4f3996a..4f0bda2424c07886b554992aa8ed203d9acd8bc4 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2008 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
@@ -30,8 +30,6 @@
 #ifndef SYS_futex
 #define SYS_futex               394
 #endif
-#define FUTEX_WAIT              0
-#define FUTEX_WAKE              1
 
 
 static inline void
@@ -45,7 +43,7 @@ futex_wait (int *addr, int val)
 
   sc_0 = SYS_futex;
   sc_16 = (long) addr;
-  sc_17 = FUTEX_WAIT;
+  sc_17 = gomp_futex_wait;
   sc_18 = val;
   sc_19 = 0;
   __asm volatile ("callsys"
@@ -53,6 +51,20 @@ futex_wait (int *addr, int val)
                  : "0"(sc_0), "r" (sc_16), "r"(sc_17), "r"(sc_18), "1"(sc_19)
                  : "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8",
                    "$22", "$23", "$24", "$25", "$27", "$28", "memory");
+  if (__builtin_expect (sc_19, 0) && sc_0 == ENOSYS)
+    {
+      gomp_futex_wait &= ~FUTEX_PRIVATE_FLAG;
+      gomp_futex_wake &= ~FUTEX_PRIVATE_FLAG;
+      sc_0 = SYS_futex;
+      sc_17 &= ~FUTEX_PRIVATE_FLAG;
+      sc_19 = 0;
+      __asm volatile ("callsys"
+                     : "=r" (sc_0), "=r"(sc_19)
+                     : "0"(sc_0), "r" (sc_16), "r"(sc_17), "r"(sc_18),
+                       "1"(sc_19)
+                     : "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8",
+                       "$22", "$23", "$24", "$25", "$27", "$28", "memory");
+    }
 }
 
 static inline void
@@ -66,11 +78,35 @@ futex_wake (int *addr, int count)
 
   sc_0 = SYS_futex;
   sc_16 = (long) addr;
-  sc_17 = FUTEX_WAKE;
+  sc_17 = gomp_futex_wake;
   sc_18 = count;
   __asm volatile ("callsys"
                  : "=r" (sc_0), "=r"(sc_19)
                  : "0"(sc_0), "r" (sc_16), "r"(sc_17), "r"(sc_18)
                  : "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8",
                    "$22", "$23", "$24", "$25", "$27", "$28", "memory");
+  if (__builtin_expect (sc_19, 0) && sc_0 == ENOSYS)
+    {
+      gomp_futex_wait &= ~FUTEX_PRIVATE_FLAG;
+      gomp_futex_wake &= ~FUTEX_PRIVATE_FLAG;
+      sc_0 = SYS_futex;
+      sc_17 &= ~FUTEX_PRIVATE_FLAG;
+      __asm volatile ("callsys"
+                     : "=r" (sc_0), "=r"(sc_19)
+                     : "0"(sc_0), "r" (sc_16), "r"(sc_17), "r"(sc_18)
+                     : "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8",
+                       "$22", "$23", "$24", "$25", "$27", "$28", "memory");
+    }
+}
+
+static inline void
+cpu_relax (void)
+{
+  __asm volatile ("" : : : "memory");
+}
+
+static inline void
+atomic_write_barrier (void)
+{
+  __asm volatile ("wmb" : : : "memory");
 }
index 5c4f32e6f8b4c4871e3addeccec08cd42fb36cdd..7af36d2c42180408aa7e180f31c413da9660d249 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2008 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
    mechanism for libgomp.  This type is private to the library.  This 
    implementation uses atomic instructions and the futex syscall.  */
 
-#include "libgomp.h"
-#include "futex.h"
 #include <limits.h>
+#include "wait.h"
 
 
 void
-gomp_barrier_wait_end (gomp_barrier_t *bar, bool last)
+gomp_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state)
 {
-  if (last)
+  if (__builtin_expect ((state & 1) != 0, 0))
     {
-      bar->generation++;
-      futex_wake (&bar->generation, INT_MAX);
+      /* Next time we'll be awaiting TOTAL threads again.  */
+      bar->awaited = bar->total;
+      atomic_write_barrier ();
+      bar->generation += 4;
+      futex_wake ((int *) &bar->generation, INT_MAX);
     }
   else
     {
-      unsigned int generation = bar->generation;
-
-      gomp_mutex_unlock (&bar->mutex);
+      unsigned int generation = state;
 
       do
-       futex_wait (&bar->generation, generation);
+       do_wait ((int *) &bar->generation, generation);
       while (bar->generation == generation);
     }
+}
+
+void
+gomp_barrier_wait (gomp_barrier_t *bar)
+{
+  gomp_barrier_wait_end (bar, gomp_barrier_wait_start (bar));
+}
 
-  if (__sync_add_and_fetch (&bar->arrived, -1) == 0)
-    gomp_mutex_unlock (&bar->mutex);
+/* Like gomp_barrier_wait, except that if the encountering thread
+   is not the last one to hit the barrier, it returns immediately.
+   The intended usage is that a thread which intends to gomp_barrier_destroy
+   this barrier calls gomp_barrier_wait, while all other threads
+   call gomp_barrier_wait_last.  When gomp_barrier_wait returns,
+   the barrier can be safely destroyed.  */
+
+void
+gomp_barrier_wait_last (gomp_barrier_t *bar)
+{
+  gomp_barrier_state_t state = gomp_barrier_wait_start (bar);
+  if (state & 1)
+    gomp_barrier_wait_end (bar, state);
+}
+
+void
+gomp_team_barrier_wake (gomp_barrier_t *bar, int count)
+{
+  futex_wake ((int *) &bar->generation, count == 0 ? INT_MAX : count);
+}
+
+void
+gomp_team_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state)
+{
+  unsigned int generation;
+
+  if (__builtin_expect ((state & 1) != 0, 0))
+    {
+      /* Next time we'll be awaiting TOTAL threads again.  */
+      struct gomp_thread *thr = gomp_thread ();
+      struct gomp_team *team = thr->ts.team;
+      bar->awaited = bar->total;
+      atomic_write_barrier ();
+      if (__builtin_expect (team->task_count, 0))
+       {
+         gomp_barrier_handle_tasks (state);
+         state &= ~1;
+       }
+      else
+       {
+         bar->generation = state + 3;
+         futex_wake ((int *) &bar->generation, INT_MAX);
+         return;
+       }
+    }
+
+  generation = state;
+  do
+    {
+      do_wait ((int *) &bar->generation, generation);
+      if (__builtin_expect (bar->generation & 1, 0))
+       gomp_barrier_handle_tasks (state);
+      if ((bar->generation & 2))
+       generation |= 2;
+    }
+  while (bar->generation != state + 4);
 }
 
 void
-gomp_barrier_wait (gomp_barrier_t *barrier)
+gomp_team_barrier_wait (gomp_barrier_t *bar)
 {
-  gomp_barrier_wait_end (barrier, gomp_barrier_wait_start (barrier));
+  gomp_team_barrier_wait_end (bar, gomp_barrier_wait_start (bar));
 }
index 57268585d8bb066bcbcdaae27de94b61cfc41913..85150caf18996ff0bfd4911dbd650f86d373e175 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2008 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
 
 typedef struct
 {
-  gomp_mutex_t mutex;
-  unsigned total;
-  unsigned arrived;
-  int generation;
+  /* Make sure total/generation is in a mostly read cacheline, while
+     awaited in a separate cacheline.  */
+  unsigned total __attribute__((aligned (64)));
+  unsigned generation;
+  unsigned awaited __attribute__((aligned (64)));
 } gomp_barrier_t;
+typedef unsigned int gomp_barrier_state_t;
 
 static inline void gomp_barrier_init (gomp_barrier_t *bar, unsigned count)
 {
-  gomp_mutex_init (&bar->mutex);
   bar->total = count;
-  bar->arrived = 0;
+  bar->awaited = count;
   bar->generation = 0;
 }
 
 static inline void gomp_barrier_reinit (gomp_barrier_t *bar, unsigned count)
 {
-  gomp_mutex_lock (&bar->mutex);
+  __sync_fetch_and_add (&bar->awaited, count - bar->total);
   bar->total = count;
-  gomp_mutex_unlock (&bar->mutex);
 }
 
 static inline void gomp_barrier_destroy (gomp_barrier_t *bar)
 {
-  /* Before destroying, make sure all threads have left the barrier.  */
-  gomp_mutex_lock (&bar->mutex);
 }
 
 extern void gomp_barrier_wait (gomp_barrier_t *);
-extern void gomp_barrier_wait_end (gomp_barrier_t *, bool);
+extern void gomp_barrier_wait_last (gomp_barrier_t *);
+extern void gomp_barrier_wait_end (gomp_barrier_t *, gomp_barrier_state_t);
+extern void gomp_team_barrier_wait (gomp_barrier_t *);
+extern void gomp_team_barrier_wait_end (gomp_barrier_t *,
+                                       gomp_barrier_state_t);
+extern void gomp_team_barrier_wake (gomp_barrier_t *, int);
 
-static inline bool gomp_barrier_wait_start (gomp_barrier_t *bar)
+static inline gomp_barrier_state_t
+gomp_barrier_wait_start (gomp_barrier_t *bar)
 {
-  gomp_mutex_lock (&bar->mutex);
-  return ++bar->arrived == bar->total;
+  unsigned int ret = bar->generation & ~3;
+  /* Do we need any barrier here or is __sync_add_and_fetch acting
+     as the needed LoadLoad barrier already?  */
+  ret += __sync_add_and_fetch (&bar->awaited, -1) == 0;
+  return ret;
+}
+
+static inline bool
+gomp_barrier_last_thread (gomp_barrier_state_t state)
+{
+  return state & 1;
+}
+
+/* All the inlines below must be called with team->task_lock
+   held.  */
+
+static inline void
+gomp_team_barrier_set_task_pending (gomp_barrier_t *bar)
+{
+  bar->generation |= 1;
+}
+
+static inline void
+gomp_team_barrier_clear_task_pending (gomp_barrier_t *bar)
+{
+  bar->generation &= ~1;
+}
+
+static inline void
+gomp_team_barrier_set_waiting_for_tasks (gomp_barrier_t *bar)
+{
+  bar->generation |= 2;
+}
+
+static inline bool
+gomp_team_barrier_waiting_for_tasks (gomp_barrier_t *bar)
+{
+  return (bar->generation & 2) != 0;
+}
+
+static inline void
+gomp_team_barrier_done (gomp_barrier_t *bar, gomp_barrier_state_t state)
+{
+  bar->generation = (state & ~3) + 4;
 }
 
 #endif /* GOMP_BARRIER_H */
index 5e54982d6f758e3089448450d37193b25a0044ee..35aa4f1fea0f4b1ceb2fad7d5122b6fe48def998 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2008 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
 
 #include <sys/syscall.h>
 
-#define FUTEX_WAIT     0
-#define FUTEX_WAKE     1
 
 
-static inline void
-sys_futex0(int *addr, int op, int val)
+static inline long
+sys_futex0(int *addr, long op, int val)
 {
   register long out0 asm ("out0") = (long) addr;
   register long out1 asm ("out1") = op;
   register long out2 asm ("out2") = val;
   register long out3 asm ("out3") = 0;
+  register long r8 asm ("r8");
+  register long r10 asm ("r10");
   register long r15 asm ("r15") = SYS_futex;
 
   __asm __volatile ("break 0x100000"
-       : "=r"(r15), "=r"(out0), "=r"(out1), "=r"(out2), "=r"(out3)
+       : "=r"(r15), "=r"(out0), "=r"(out1), "=r"(out2), "=r"(out3),
+         "=r"(r8), "=r"(r10)
        : "r"(r15), "r"(out0), "r"(out1), "r"(out2), "r"(out3)
-        : "memory", "r8", "r10", "out4", "out5", "out6", "out7",
+       : "memory", "out4", "out5", "out6", "out7",
          /* Non-stacked integer registers, minus r8, r10, r15.  */
          "r2", "r3", "r9", "r11", "r12", "r13", "r14", "r16", "r17", "r18",
          "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27",
@@ -56,16 +57,41 @@ sys_futex0(int *addr, int op, int val)
          "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
          /* Branch registers.  */
          "b6");
+  return r8 & r10;
 }
 
 static inline void
 futex_wait (int *addr, int val)
 {
-  sys_futex0 (addr, FUTEX_WAIT, val);
+  long err = sys_futex0 (addr, gomp_futex_wait, val);
+  if (__builtin_expect (err == ENOSYS, 0))
+    {
+      gomp_futex_wait &= ~FUTEX_PRIVATE_FLAG;
+      gomp_futex_wake &= ~FUTEX_PRIVATE_FLAG;
+      sys_futex0 (addr, gomp_futex_wait, val);
+    }
 }
 
 static inline void
 futex_wake (int *addr, int count)
 {
-  sys_futex0 (addr, FUTEX_WAKE, count);
+  long err = sys_futex0 (addr, gomp_futex_wake, count);
+  if (__builtin_expect (err == ENOSYS, 0))
+    {
+      gomp_futex_wait &= ~FUTEX_PRIVATE_FLAG;
+      gomp_futex_wake &= ~FUTEX_PRIVATE_FLAG;
+      sys_futex0 (addr, gomp_futex_wake, count);
+    }
+}
+
+static inline void
+cpu_relax (void)
+{
+  __asm volatile ("hint @pause" : : : "memory");
+}
+
+static inline void
+atomic_write_barrier (void)
+{
+  __sync_synchronize ();
 }
index 211f6007b43b93001129de40deb4ec2074dcb7b8..a2e07d320fd5bf44a890f9963234f55b723ef4fc 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2008 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
    primitives.  This implementation uses atomic instructions and the futex
    syscall.  */
 
-#include "libgomp.h"
 #include <string.h>
 #include <unistd.h>
 #include <sys/syscall.h>
-#include "futex.h"
+#include "wait.h"
 
 
 /* The internal gomp_mutex_t and the external non-recursive omp_lock_t
    have the same form.  Re-use it.  */
 
 void
-omp_init_lock (omp_lock_t *lock)
+gomp_init_lock_30 (omp_lock_t *lock)
 {
   gomp_mutex_init (lock);
 }
 
 void
-omp_destroy_lock (omp_lock_t *lock)
+gomp_destroy_lock_30 (omp_lock_t *lock)
 {
   gomp_mutex_destroy (lock);
 }
 
 void
-omp_set_lock (omp_lock_t *lock)
+gomp_set_lock_30 (omp_lock_t *lock)
 {
   gomp_mutex_lock (lock);
 }
 
 void
-omp_unset_lock (omp_lock_t *lock)
+gomp_unset_lock_30 (omp_lock_t *lock)
 {
   gomp_mutex_unlock (lock);
 }
 
 int
-omp_test_lock (omp_lock_t *lock)
+gomp_test_lock_30 (omp_lock_t *lock)
 {
   return __sync_bool_compare_and_swap (lock, 0, 1);
 }
 
-/* The external recursive omp_nest_lock_t form requires additional work.  */
+void
+gomp_init_nest_lock_30 (omp_nest_lock_t *lock)
+{
+  memset (lock, '\0', sizeof (*lock));
+}
+
+void
+gomp_destroy_nest_lock_30 (omp_nest_lock_t *lock)
+{
+}
+
+void
+gomp_set_nest_lock_30 (omp_nest_lock_t *lock)
+{
+  void *me = gomp_icv (true);
+
+  if (lock->owner != me)
+    {
+      gomp_mutex_lock (&lock->lock);
+      lock->owner = me;
+    }
+
+  lock->count++;
+}
+
+void
+gomp_unset_nest_lock_30 (omp_nest_lock_t *lock)
+{
+  if (--lock->count == 0)
+    {
+      lock->owner = NULL;
+      gomp_mutex_unlock (&lock->lock);
+    }
+}
+
+int
+gomp_test_nest_lock_30 (omp_nest_lock_t *lock)
+{
+  void *me = gomp_icv (true);
+
+  if (lock->owner == me)
+    return ++lock->count;
+
+  if (__sync_bool_compare_and_swap (&lock->lock, 0, 1))
+    {
+      lock->owner = me;
+      lock->count = 1;
+      return 1;
+    }
+
+  return 0;
+}
+
+#ifdef LIBGOMP_GNU_SYMBOL_VERSIONING
+/* gomp_mutex_* can be safely locked in one thread and
+   unlocked in another thread, so the OpenMP 2.5 and OpenMP 3.0
+   non-nested locks can be the same.  */
+strong_alias (gomp_init_lock_30, gomp_init_lock_25)
+strong_alias (gomp_destroy_lock_30, gomp_destroy_lock_25)
+strong_alias (gomp_set_lock_30, gomp_set_lock_25)
+strong_alias (gomp_unset_lock_30, gomp_unset_lock_25)
+strong_alias (gomp_test_lock_30, gomp_test_lock_25)
+
+/* The external recursive omp_nest_lock_25_t form requires additional work.  */
 
 /* We need an integer to uniquely identify this thread.  Most generally
    this is the thread's TID, which ideally we'd get this straight from
@@ -85,17 +147,17 @@ omp_test_lock (omp_lock_t *lock)
    always available directly.  Make do with the gomp_thread pointer
    since it's handy.  */
 
-#if !defined (HAVE_TLS)
+# if !defined (HAVE_TLS)
 static inline int gomp_tid (void)
 {
   return syscall (SYS_gettid);
 }
-#elif !defined(__LP64__)
+# elif !defined(__LP64__)
 static inline int gomp_tid (void)
 {
   return (int) gomp_thread ();
 }
-#else
+# else
 static __thread int tid_cache;
 static inline int gomp_tid (void)
 {
@@ -104,22 +166,22 @@ static inline int gomp_tid (void)
     tid_cache = tid = syscall (SYS_gettid);
   return tid;
 }
-#endif
+# endif
 
 
 void
-omp_init_nest_lock (omp_nest_lock_t *lock)
+gomp_init_nest_lock_25 (omp_nest_lock_25_t *lock)
 {
   memset (lock, 0, sizeof (lock));
 }
 
 void
-omp_destroy_nest_lock (omp_nest_lock_t *lock)
+gomp_destroy_nest_lock_25 (omp_nest_lock_25_t *lock)
 {
 }
 
 void
-omp_set_nest_lock (omp_nest_lock_t *lock)
+gomp_set_nest_lock_25 (omp_nest_lock_25_t *lock)
 {
   int otid, tid = gomp_tid ();
 
@@ -137,12 +199,12 @@ omp_set_nest_lock (omp_nest_lock_t *lock)
          return;
        }
 
-      futex_wait (&lock->owner, otid);
+      do_wait (&lock->owner, otid);
     }
 }
 
 void
-omp_unset_nest_lock (omp_nest_lock_t *lock)
+gomp_unset_nest_lock_25 (omp_nest_lock_25_t *lock)
 {
   /* ??? Validate that we own the lock here.  */
 
@@ -154,7 +216,7 @@ omp_unset_nest_lock (omp_nest_lock_t *lock)
 }
 
 int
-omp_test_nest_lock (omp_nest_lock_t *lock)
+gomp_test_nest_lock_25 (omp_nest_lock_25_t *lock)
 {
   int otid, tid = gomp_tid ();
 
@@ -170,6 +232,19 @@ omp_test_nest_lock (omp_nest_lock_t *lock)
   return 0;
 }
 
+omp_lock_symver (omp_init_lock)
+omp_lock_symver (omp_destroy_lock)
+omp_lock_symver (omp_set_lock)
+omp_lock_symver (omp_unset_lock)
+omp_lock_symver (omp_test_lock)
+omp_lock_symver (omp_init_nest_lock)
+omp_lock_symver (omp_destroy_nest_lock)
+omp_lock_symver (omp_set_nest_lock)
+omp_lock_symver (omp_unset_nest_lock)
+omp_lock_symver (omp_test_nest_lock)
+
+#else
+
 ialias (omp_init_lock)
 ialias (omp_init_nest_lock)
 ialias (omp_destroy_lock)
@@ -180,3 +255,5 @@ ialias (omp_unset_lock)
 ialias (omp_unset_nest_lock)
 ialias (omp_test_lock)
 ialias (omp_test_nest_lock)
+
+#endif
index fa3dfd1cb036dc06927815d9c42880b6aa2ccc9b..36c362eb27464b5dadb71520e308c94ff22699ea 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2008 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
    mechanism for libgomp.  This type is private to the library.  This
    implementation uses atomic instructions and the futex syscall.  */
 
-#include "libgomp.h"
-#include "futex.h"
+#include "wait.h"
 
+long int gomp_futex_wake = FUTEX_WAKE | FUTEX_PRIVATE_FLAG;
+long int gomp_futex_wait = FUTEX_WAIT | FUTEX_PRIVATE_FLAG;
 
 void
 gomp_mutex_lock_slow (gomp_mutex_t *mutex)
@@ -40,7 +41,7 @@ gomp_mutex_lock_slow (gomp_mutex_t *mutex)
     {
       int oldval = __sync_val_compare_and_swap (mutex, 1, 2);
       if (oldval != 0)
-        futex_wait (mutex, 2);
+       do_wait (mutex, 2);
     }
   while (!__sync_bool_compare_and_swap (mutex, 0, 2));
 }
index 350cba16056aa886016ef44ad8af41b6269edb66..e65aff7fce74145647e575a3deb1a7d86784416a 100644 (file)
@@ -3,8 +3,10 @@
    structures without polluting the namespace.
 
    When using the Linux futex primitive, non-recursive locks require
-   only one int.  Recursive locks require we identify the owning thread
-   and so require two ints.  */
+   only one int.  Recursive locks require we identify the owning task
+   and so require one int and a pointer.  */
 
 typedef int omp_lock_t;
-typedef struct { int owner, count; } omp_nest_lock_t;
+typedef struct { int lock, count; void *owner; } omp_nest_lock_t;
+typedef int omp_lock_25_t;
+typedef struct { int owner, count; } omp_nest_lock_25_t;
index 20e03573783d23b6f1283ceaedbd93c682bf45e5..c1e0d0f5651901720bb84cf973f391df761a0ce8 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2008 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
 /* Provide target-specific access to the futex system call.  */
 
 #include <sys/syscall.h>
-#define FUTEX_WAIT     0
-#define FUTEX_WAKE     1
 
-static inline void
+static inline long
 sys_futex0 (int *addr, int op, int val)
 {
   register long int r0  __asm__ ("r0");
@@ -50,21 +48,48 @@ sys_futex0 (int *addr, int op, int val)
      doesn't.  It doesn't much matter for us.  In the interest of unity,
      go ahead and clobber it always.  */
 
-  __asm volatile ("sc"
+  __asm volatile ("sc; mfcr %0"
                  : "=r"(r0), "=r"(r3), "=r"(r4), "=r"(r5), "=r"(r6)
                  : "r"(r0), "r"(r3), "r"(r4), "r"(r5), "r"(r6)
                  : "r7", "r8", "r9", "r10", "r11", "r12",
                    "cr0", "ctr", "memory");
+  if (__builtin_expect (r0 & (1 << 28), 0))
+    return r3;
+  return 0;
 }
 
 static inline void
 futex_wait (int *addr, int val)
 {
-  sys_futex0 (addr, FUTEX_WAIT, val);
+  long err = sys_futex0 (addr, gomp_futex_wait, val);
+  if (__builtin_expect (err == ENOSYS, 0))
+    {
+      gomp_futex_wait &= ~FUTEX_PRIVATE_FLAG;
+      gomp_futex_wake &= ~FUTEX_PRIVATE_FLAG;
+      sys_futex0 (addr, gomp_futex_wait, val);
+    }
 }
 
 static inline void
 futex_wake (int *addr, int count)
 {
-  sys_futex0 (addr, FUTEX_WAKE, count);
+  long err = sys_futex0 (addr, gomp_futex_wake, count);
+  if (__builtin_expect (err == ENOSYS, 0))
+    {
+      gomp_futex_wait &= ~FUTEX_PRIVATE_FLAG;
+      gomp_futex_wake &= ~FUTEX_PRIVATE_FLAG;
+      sys_futex0 (addr, gomp_futex_wake, count);
+    }
+}
+
+static inline void
+cpu_relax (void)
+{
+  __asm volatile ("" : : : "memory");
+}
+
+static inline void
+atomic_write_barrier (void)
+{
+  __asm volatile ("eieio" : : : "memory");
 }
index 2267cfbd2d1b2c5f7a13da80355e191ae2c89658..6a006f24aa3e79da0cd3c52007efe22bda9f1fff 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
    Contributed by Jakub Jelinek <jakub@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
@@ -78,14 +78,14 @@ gomp_init_num_threads (void)
   if (pthread_getaffinity_np (pthread_self (), sizeof (cpuset), &cpuset) == 0)
     {
       /* Count only the CPUs this process can use.  */
-      gomp_nthreads_var = cpuset_popcount (&cpuset);
-      if (gomp_nthreads_var == 0)
-       gomp_nthreads_var = 1;
+      gomp_global_icv.nthreads_var = cpuset_popcount (&cpuset);
+      if (gomp_global_icv.nthreads_var == 0)
+       gomp_global_icv.nthreads_var = 1;
       return;
     }
 #endif
 #ifdef _SC_NPROCESSORS_ONLN
-  gomp_nthreads_var = sysconf (_SC_NPROCESSORS_ONLN);
+  gomp_global_icv.nthreads_var = sysconf (_SC_NPROCESSORS_ONLN);
 #endif
 }
 
@@ -132,7 +132,7 @@ get_num_procs (void)
 #ifdef _SC_NPROCESSORS_ONLN
   return sysconf (_SC_NPROCESSORS_ONLN);
 #else
-  return gomp_nthreads_var;
+  return gomp_icv (false)->nthreads_var;
 #endif
 }
 
@@ -146,11 +146,11 @@ get_num_procs (void)
 unsigned
 gomp_dynamic_max_threads (void)
 {
-  unsigned n_onln, loadavg;
+  unsigned n_onln, loadavg, nthreads_var = gomp_icv (false)->nthreads_var;
 
   n_onln = get_num_procs ();
-  if (n_onln > gomp_nthreads_var)
-    n_onln = gomp_nthreads_var;
+  if (n_onln > nthreads_var)
+    n_onln = nthreads_var;
 
   loadavg = 0;
 #ifdef HAVE_GETLOADAVG
diff --git a/libgomp/config/linux/ptrlock.c b/libgomp/config/linux/ptrlock.c
new file mode 100644 (file)
index 0000000..8faa1b2
--- /dev/null
@@ -0,0 +1,70 @@
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+   Contributed by Jakub Jelinek <jakub@redhat.com>.
+
+   This file is part of the GNU OpenMP Library (libgomp).
+
+   Libgomp is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 2.1 of the License, or
+   (at your option) any later version.
+
+   Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+   FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+   more details.
+
+   You should have received a copy of the GNU Lesser General Public License 
+   along with libgomp; see the file COPYING.LIB.  If not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+/* As a special exception, if you link this library with other files, some
+   of which are compiled with GCC, to produce an executable, this library
+   does not by itself cause the resulting executable to be covered by the
+   GNU General Public License.  This exception does not however invalidate
+   any other reasons why the executable file might be covered by the GNU
+   General Public License.  */
+
+/* This is a Linux specific implementation of a mutex synchronization
+   mechanism for libgomp.  This type is private to the library.  This
+   implementation uses atomic instructions and the futex syscall.  */
+
+#include <endian.h>
+#include <limits.h>
+#include "wait.h"
+
+void *
+gomp_ptrlock_get_slow (gomp_ptrlock_t *ptrlock)
+{
+  int *intptr;
+  __sync_bool_compare_and_swap (ptrlock, 1, 2);
+
+  /* futex works on ints, not pointers.
+     But a valid work share pointer will be at least
+     8 byte aligned, so it is safe to assume the low
+     32-bits of the pointer won't contain values 1 or 2.  */
+  __asm volatile ("" : "=r" (intptr) : "0" (ptrlock));
+#if __BYTE_ORDER == __BIG_ENDIAN
+  if (sizeof (*ptrlock) > sizeof (int))
+    intptr += (sizeof (*ptrlock) / sizeof (int)) - 1;
+#endif
+  do
+    do_wait (intptr, 2);
+  while (*intptr == 2);
+  __asm volatile ("" : : : "memory");
+  return *ptrlock;
+}
+
+void
+gomp_ptrlock_set_slow (gomp_ptrlock_t *ptrlock, void *ptr)
+{
+  int *intptr;
+
+  *ptrlock = ptr;
+  __asm volatile ("" : "=r" (intptr) : "0" (ptrlock));
+#if __BYTE_ORDER == __BIG_ENDIAN
+  if (sizeof (*ptrlock) > sizeof (int))
+    intptr += (sizeof (*ptrlock) / sizeof (int)) - 1;
+#endif
+  futex_wake (intptr, INT_MAX);
+}
diff --git a/libgomp/config/linux/ptrlock.h b/libgomp/config/linux/ptrlock.h
new file mode 100644 (file)
index 0000000..bb54416
--- /dev/null
@@ -0,0 +1,65 @@
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+   Contributed by Jakub Jelinek <jakub@redhat.com>.
+
+   This file is part of the GNU OpenMP Library (libgomp).
+
+   Libgomp is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 2.1 of the License, or
+   (at your option) any later version.
+
+   Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+   FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+   more details.
+
+   You should have received a copy of the GNU Lesser General Public License 
+   along with libgomp; see the file COPYING.LIB.  If not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+/* As a special exception, if you link this library with other files, some
+   of which are compiled with GCC, to produce an executable, this library
+   does not by itself cause the resulting executable to be covered by the
+   GNU General Public License.  This exception does not however invalidate
+   any other reasons why the executable file might be covered by the GNU
+   General Public License.  */
+
+/* This is a Linux specific implementation of a mutex synchronization
+   mechanism for libgomp.  This type is private to the library.  This
+   implementation uses atomic instructions and the futex syscall.  */
+
+#ifndef GOMP_PTRLOCK_H
+#define GOMP_PTRLOCK_H 1
+
+typedef void *gomp_ptrlock_t;
+
+static inline void gomp_ptrlock_init (gomp_ptrlock_t *ptrlock, void *ptr)
+{
+  *ptrlock = ptr;
+}
+
+extern void *gomp_ptrlock_get_slow (gomp_ptrlock_t *ptrlock);
+static inline void *gomp_ptrlock_get (gomp_ptrlock_t *ptrlock)
+{
+  if ((uintptr_t) *ptrlock > 2)
+    return *ptrlock;
+
+  if (__sync_bool_compare_and_swap (ptrlock, NULL, (uintptr_t) 1))
+    return NULL;
+
+  return gomp_ptrlock_get_slow (ptrlock);
+}
+
+extern void gomp_ptrlock_set_slow (gomp_ptrlock_t *ptrlock, void *ptr);
+static inline void gomp_ptrlock_set (gomp_ptrlock_t *ptrlock, void *ptr)
+{
+  if (!__sync_bool_compare_and_swap (ptrlock, (uintptr_t) 1, ptr))
+    gomp_ptrlock_set_slow (ptrlock, ptr);
+}
+
+static inline void gomp_ptrlock_destroy (gomp_ptrlock_t *ptrlock)
+{
+}
+
+#endif /* GOMP_PTRLOCK_H */
index 9b3820c0d976e22ec89ce1f56b9e9f40eb69522b..3c4e1fc5d2571243fcf337aa4e4b494b48251306 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2008 Free Software Foundation, Inc.
    Contributed by Jakub Jelinek <jakub@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
 /* Provide target-specific access to the futex system call.  */
 
 #include <sys/syscall.h>
-#define FUTEX_WAIT     0
-#define FUTEX_WAKE     1
 
-static inline void
+static inline long
 sys_futex0 (int *addr, int op, int val)
 {
   register long int gpr2  __asm__ ("2");
@@ -49,16 +47,41 @@ sys_futex0 (int *addr, int op, int val)
                  : "i" (SYS_futex),
                    "0" (gpr2), "d" (gpr3), "d" (gpr4), "d" (gpr5)
                  : "memory");
+  return gpr2;
 }
 
 static inline void
 futex_wait (int *addr, int val)
 {
-  sys_futex0 (addr, FUTEX_WAIT, val);
+  long err = sys_futex0 (addr, gomp_futex_wait, val);
+  if (__builtin_expect (err == -ENOSYS, 0))
+    {
+      gomp_futex_wait &= ~FUTEX_PRIVATE_FLAG;
+      gomp_futex_wake &= ~FUTEX_PRIVATE_FLAG;
+      sys_futex0 (addr, gomp_futex_wait, val);
+    }
 }
 
 static inline void
 futex_wake (int *addr, int count)
 {
-  sys_futex0 (addr, FUTEX_WAKE, count);
+  long err = sys_futex0 (addr, gomp_futex_wake, count);
+  if (__builtin_expect (err == -ENOSYS, 0))
+    {
+      gomp_futex_wait &= ~FUTEX_PRIVATE_FLAG;
+      gomp_futex_wake &= ~FUTEX_PRIVATE_FLAG;
+      sys_futex0 (addr, gomp_futex_wake, count);
+    }
+}
+
+static inline void
+cpu_relax (void)
+{
+  __asm volatile ("" : : : "memory");
+}
+
+static inline void
+atomic_write_barrier (void)
+{
+  __sync_synchronize ();
 }
index 798e3f1f2c0625e89f870259a506edb7ea3a0325..5615bc580eeb35078ec71785718ace8f7e91a0b8 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2008 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
@@ -29,8 +29,7 @@
    mechanism for libgomp.  This type is private to the library.  This 
    implementation uses atomic instructions and the futex syscall.  */
 
-#include "libgomp.h"
-#include "futex.h"
+#include "wait.h"
 
 
 void
@@ -44,7 +43,7 @@ gomp_sem_wait_slow (gomp_sem_t *sem)
          if (__sync_bool_compare_and_swap (sem, val, val - 1))
            return;
        }
-      futex_wait (sem, -1);
+      do_wait (sem, -1);
     }
 }
 
index 7b1cc8379565240e82c597cb40d78ce21a803344..b9bc387355fb357df0dd565b40d632e6cddcd0a5 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2008 Free Software Foundation, Inc.
    Contributed by Jakub Jelinek <jakub@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
 /* Provide target-specific access to the futex system call.  */
 
 #include <sys/syscall.h>
-#define FUTEX_WAIT     0
-#define FUTEX_WAKE     1
 
-static inline void
+static inline long
 sys_futex0 (int *addr, int op, int val)
 {
   register long int g1  __asm__ ("g1");
@@ -47,9 +45,9 @@ sys_futex0 (int *addr, int op, int val)
   o3 = 0;
 
 #ifdef __arch64__
-# define SYSCALL_STRING "ta\t0x6d"
+# define SYSCALL_STRING "ta\t0x6d; bcs,a,pt %%xcc, 1f; sub %%g0, %%o0, %%o0; 1:"
 #else
-# define SYSCALL_STRING "ta\t0x10"
+# define SYSCALL_STRING "ta\t0x10; bcs,a 1f; sub %%g0, %%o0, %%o0; 1:"
 #endif
 
   __asm volatile (SYSCALL_STRING
@@ -65,16 +63,49 @@ sys_futex0 (int *addr, int op, int val)
                    "f48", "f50", "f52", "f54", "f56", "f58", "f60", "f62",
 #endif
                    "cc", "memory");
+  return o0;
 }
 
 static inline void
 futex_wait (int *addr, int val)
 {
-  sys_futex0 (addr, FUTEX_WAIT, val);
+  long err = sys_futex0 (addr, gomp_futex_wait, val);
+  if (__builtin_expect (err == ENOSYS, 0))
+    {
+      gomp_futex_wait &= ~FUTEX_PRIVATE_FLAG;
+      gomp_futex_wake &= ~FUTEX_PRIVATE_FLAG;
+      sys_futex0 (addr, gomp_futex_wait, val);
+    }
 }
 
 static inline void
 futex_wake (int *addr, int count)
 {
-  sys_futex0 (addr, FUTEX_WAKE, count);
+  long err = sys_futex0 (addr, gomp_futex_wake, count);
+  if (__builtin_expect (err == ENOSYS, 0))
+    {
+      gomp_futex_wait &= ~FUTEX_PRIVATE_FLAG;
+      gomp_futex_wake &= ~FUTEX_PRIVATE_FLAG;
+      sys_futex0 (addr, gomp_futex_wake, count);
+    }
+}
+
+static inline void
+cpu_relax (void)
+{
+#if defined __arch64__ || defined  __sparc_v9__
+  __asm volatile ("membar #LoadLoad" : : : "memory");
+#else
+  __asm volatile ("" : : : "memory");
+#endif
+}
+
+static inline void
+atomic_write_barrier (void)
+{
+#if defined __arch64__ || defined __sparc_v9__
+  __asm volatile ("membar #StoreStore" : : : "memory");
+#else
+  __sync_synchronize ();
+#endif
 }
diff --git a/libgomp/config/linux/wait.h b/libgomp/config/linux/wait.h
new file mode 100644 (file)
index 0000000..21f0ab8
--- /dev/null
@@ -0,0 +1,68 @@
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+   Contributed by Jakub Jelinek <jakub@redhat.com>.
+
+   This file is part of the GNU OpenMP Library (libgomp).
+
+   Libgomp is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 2.1 of the License, or
+   (at your option) any later version.
+
+   Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+   FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+   more details.
+
+   You should have received a copy of the GNU Lesser General Public License 
+   along with libgomp; see the file COPYING.LIB.  If not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+/* As a special exception, if you link this library with other files, some
+   of which are compiled with GCC, to produce an executable, this library
+   does not by itself cause the resulting executable to be covered by the
+   GNU General Public License.  This exception does not however invalidate
+   any other reasons why the executable file might be covered by the GNU
+   General Public License.  */
+
+/* This is a Linux specific implementation of a mutex synchronization
+   mechanism for libgomp.  This type is private to the library.  This
+   implementation uses atomic instructions and the futex syscall.  */
+
+#ifndef GOMP_WAIT_H
+#define GOMP_WAIT_H 1
+
+#include "libgomp.h"
+#include <errno.h>
+
+#define FUTEX_WAIT     0
+#define FUTEX_WAKE     1
+#define FUTEX_PRIVATE_FLAG     128L
+
+#ifdef HAVE_ATTRIBUTE_VISIBILITY
+# pragma GCC visibility push(hidden)
+#endif
+
+extern long int gomp_futex_wait, gomp_futex_wake;
+
+#include "futex.h"
+
+static inline void do_wait (int *addr, int val)
+{
+  unsigned long long i, count = gomp_spin_count_var;
+
+  if (__builtin_expect (gomp_managed_threads > gomp_available_cpus, 0))
+    count = gomp_throttled_spin_count_var;
+  for (i = 0; i < count; i++)
+    if (__builtin_expect (*addr != val, 0))
+      return;
+    else
+      cpu_relax ();
+  futex_wait (addr, val);
+}
+
+#ifdef HAVE_ATTRIBUTE_VISIBILITY
+# pragma GCC visibility pop
+#endif
+
+#endif /* GOMP_WAIT_H */
index 4f9aac2ddbbec14eafaf7b66961023fbc8a1347c..36af6aad93b633f07b6dda268afeb01319eb59b2 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2008 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
@@ -27,9 +27,6 @@
 
 /* Provide target-specific access to the futex system call.  */
 
-#define FUTEX_WAIT     0
-#define FUTEX_WAKE     1
-
 #ifdef __LP64__
 # ifndef SYS_futex
 #  define SYS_futex    202
 static inline void
 futex_wait (int *addr, int val)
 {
-  register long r10 __asm__("%r10") = 0;
+  register long r10 __asm__("%r10");
   long res;
 
+  r10 = 0;
   __asm volatile ("syscall"
                  : "=a" (res)
-                 : "0"(SYS_futex), "D" (addr), "S"(FUTEX_WAIT),
-                   "d"(val), "r"(r10)
+                 : "0" (SYS_futex), "D" (addr), "S" (gomp_futex_wait),
+                   "d" (val), "r" (r10)
                  : "r11", "rcx", "memory");
+  if (__builtin_expect (res == -ENOSYS, 0))
+    {
+      gomp_futex_wait &= ~FUTEX_PRIVATE_FLAG;
+      gomp_futex_wake &= ~FUTEX_PRIVATE_FLAG;
+      r10 = 0;
+      __asm volatile ("syscall"
+                     : "=a" (res)
+                     : "0" (SYS_futex), "D" (addr), "S" (gomp_futex_wait),
+                       "d" (val), "r" (r10)
+                     : "r11", "rcx", "memory");
+    }
 }
 
 static inline void
@@ -55,8 +64,19 @@ futex_wake (int *addr, int count)
 
   __asm volatile ("syscall"
                  : "=a" (res)
-                 : "0"(SYS_futex), "D" (addr), "S"(FUTEX_WAKE), "d"(count)
+                 : "0" (SYS_futex), "D" (addr), "S" (gomp_futex_wake),
+                   "d" (count)
                  : "r11", "rcx", "memory");
+  if (__builtin_expect (res == -ENOSYS, 0))
+    {
+      gomp_futex_wait &= ~FUTEX_PRIVATE_FLAG;
+      gomp_futex_wake &= ~FUTEX_PRIVATE_FLAG;
+      __asm volatile ("syscall"
+                     : "=a" (res)
+                     : "0" (SYS_futex), "D" (addr), "S" (gomp_futex_wake),
+                       "d" (count)
+                     : "r11", "rcx", "memory");
+    }
 }
 #else
 # ifndef SYS_futex
@@ -65,7 +85,7 @@ futex_wake (int *addr, int count)
 
 # ifdef __PIC__
 
-static inline void
+static inline long
 sys_futex0 (int *addr, int op, int val)
 {
   long res;
@@ -77,11 +97,12 @@ sys_futex0 (int *addr, int op, int val)
                  : "0"(SYS_futex), "r" (addr), "c"(op),
                    "d"(val), "S"(0)
                  : "memory");
+  return res;
 }
 
 # else
 
-static inline void
+static inline long
 sys_futex0 (int *addr, int op, int val)
 {
   long res;
@@ -91,6 +112,7 @@ sys_futex0 (int *addr, int op, int val)
                  : "0"(SYS_futex), "b" (addr), "c"(op),
                    "d"(val), "S"(0)
                  : "memory");
+  return res;
 }
 
 # endif /* __PIC__ */
@@ -98,13 +120,37 @@ sys_futex0 (int *addr, int op, int val)
 static inline void
 futex_wait (int *addr, int val)
 {
-  sys_futex0 (addr, FUTEX_WAIT, val);
+  long res = sys_futex0 (addr, gomp_futex_wait, val);
+  if (__builtin_expect (res == -ENOSYS, 0))
+    {
+      gomp_futex_wait &= ~FUTEX_PRIVATE_FLAG;
+      gomp_futex_wake &= ~FUTEX_PRIVATE_FLAG;
+      sys_futex0 (addr, gomp_futex_wait, val);
+    }
 }
 
 static inline void
 futex_wake (int *addr, int count)
 {
-  sys_futex0 (addr, FUTEX_WAKE, count);
+  long res = sys_futex0 (addr, gomp_futex_wake, count);
+  if (__builtin_expect (res == -ENOSYS, 0))
+    {
+      gomp_futex_wait &= ~FUTEX_PRIVATE_FLAG;
+      gomp_futex_wake &= ~FUTEX_PRIVATE_FLAG;
+      sys_futex0 (addr, gomp_futex_wake, count);
+    }
 }
 
 #endif /* __LP64__ */
+
+static inline void
+cpu_relax (void)
+{
+  __asm volatile ("rep; nop" : : : "memory");
+}
+
+static inline void
+atomic_write_barrier (void)
+{
+  __sync_synchronize ();
+}
index def7bb5e8f48a5995eed0dfb976f519ec92e5eb0..4532f45f57232ebdc6a2378cc252f691330c6e48 100644 (file)
@@ -35,7 +35,7 @@
 #include <windows.h>
 
 /* Count the CPU's currently available to this process.  */
-static int
+static unsigned int
 count_avail_process_cpus ()
 {
   DWORD_PTR process_cpus;
@@ -59,7 +59,7 @@ count_avail_process_cpus ()
 void
 gomp_init_num_threads (void)
 {
-  gomp_nthreads_var = count_avail_process_cpus ();
+  gomp_global_icv.nthreads_var = count_avail_process_cpus ();
 }
 
 /* When OMP_DYNAMIC is set, at thread launch determine the number of
@@ -69,8 +69,9 @@ gomp_init_num_threads (void)
 unsigned
 gomp_dynamic_max_threads (void)
 {
-  int n_onln = count_avail_process_cpus ();
-  return n_onln > gomp_nthreads_var ? gomp_nthreads_var : n_onln;
+  unsigned int n_onln = count_avail_process_cpus ();
+  unsigned int nthreads_var = gomp_icv (false)->nthreads_var;
+  return n_onln > nthreads_var ? nthreads_var : n_onln;
 }
 
 int
index 79721610ca75bc10a0a0471b3e6ca6ae00a15828..ff19e9353a3383bfd1eef9b3fc834923d2076f6a 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2008 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
@@ -44,6 +44,7 @@ gomp_barrier_init (gomp_barrier_t *bar, unsigned count)
   gomp_sem_init (&bar->sem2, 0);
   bar->total = count;
   bar->arrived = 0;
+  bar->generation = 0;
 }
 
 void
@@ -70,11 +71,11 @@ gomp_barrier_reinit (gomp_barrier_t *bar, unsigned count)
 }
 
 void
-gomp_barrier_wait_end (gomp_barrier_t *bar, bool last)
+gomp_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state)
 {
   unsigned int n;
 
-  if (last)
+  if (state & 1)
     {
       n = --bar->arrived;
       if (n > 0)
@@ -109,3 +110,72 @@ gomp_barrier_wait (gomp_barrier_t *barrier)
 {
   gomp_barrier_wait_end (barrier, gomp_barrier_wait_start (barrier));
 }
+
+void
+gomp_team_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state)
+{
+  unsigned int n;
+
+  if (state & 1)
+    {
+      n = --bar->arrived;
+      struct gomp_thread *thr = gomp_thread ();
+      struct gomp_team *team = thr->ts.team;
+
+      if (team->task_count)
+       {
+         gomp_barrier_handle_tasks (state);
+         if (n > 0)
+           gomp_sem_wait (&bar->sem2);
+         gomp_mutex_unlock (&bar->mutex1);
+         return;
+       }
+
+      bar->generation = state + 3;
+      if (n > 0)
+       {
+         do
+           gomp_sem_post (&bar->sem1);
+         while (--n != 0);
+         gomp_sem_wait (&bar->sem2);
+       }
+      gomp_mutex_unlock (&bar->mutex1);
+    }
+  else
+    {
+      gomp_mutex_unlock (&bar->mutex1);
+      do
+       {
+         gomp_sem_wait (&bar->sem1);
+         if (bar->generation & 1)
+           gomp_barrier_handle_tasks (state);
+       }
+      while (bar->generation != state + 4);
+
+#ifdef HAVE_SYNC_BUILTINS
+      n = __sync_add_and_fetch (&bar->arrived, -1);
+#else
+      gomp_mutex_lock (&bar->mutex2);
+      n = --bar->arrived;
+      gomp_mutex_unlock (&bar->mutex2);
+#endif
+
+      if (n == 0)
+       gomp_sem_post (&bar->sem2);
+    }
+}
+
+void
+gomp_team_barrier_wait (gomp_barrier_t *barrier)
+{
+  gomp_team_barrier_wait_end (barrier, gomp_barrier_wait_start (barrier));
+}
+
+void
+gomp_team_barrier_wake (gomp_barrier_t *bar, int count)
+{
+  if (count == 0)
+    count = bar->total - 1;
+  while (count-- > 0)
+    gomp_sem_post (&bar->sem1);
+}
index 5275efa96a728485268726a42d1c8c9589e97d07..e4d2e680af2ee38df1326c879d743f61aa25ac9d 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2008 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
@@ -45,19 +45,74 @@ typedef struct
   gomp_sem_t sem2;
   unsigned total;
   unsigned arrived;
+  unsigned generation;
 } gomp_barrier_t;
+typedef unsigned int gomp_barrier_state_t;
 
 extern void gomp_barrier_init (gomp_barrier_t *, unsigned);
 extern void gomp_barrier_reinit (gomp_barrier_t *, unsigned);
 extern void gomp_barrier_destroy (gomp_barrier_t *);
 
 extern void gomp_barrier_wait (gomp_barrier_t *);
-extern void gomp_barrier_wait_end (gomp_barrier_t *, bool);
+extern void gomp_barrier_wait_end (gomp_barrier_t *, gomp_barrier_state_t);
+extern void gomp_team_barrier_wait (gomp_barrier_t *);
+extern void gomp_team_barrier_wait_end (gomp_barrier_t *,
+                                       gomp_barrier_state_t);
+extern void gomp_team_barrier_wake (gomp_barrier_t *, int);
 
-static inline bool gomp_barrier_wait_start (gomp_barrier_t *bar)
+static inline gomp_barrier_state_t
+gomp_barrier_wait_start (gomp_barrier_t *bar)
 {
+  unsigned int ret;
   gomp_mutex_lock (&bar->mutex1);
-  return ++bar->arrived == bar->total;
+  ret = bar->generation & ~3;
+  ret += ++bar->arrived == bar->total;
+  return ret;
+}
+
+static inline bool
+gomp_barrier_last_thread (gomp_barrier_state_t state)
+{
+  return state & 1;
+}
+
+static inline void
+gomp_barrier_wait_last (gomp_barrier_t *bar)
+{
+  gomp_barrier_wait (bar);
+}
+
+/* All the inlines below must be called with team->task_lock
+   held.  */
+
+static inline void
+gomp_team_barrier_set_task_pending (gomp_barrier_t *bar)
+{
+  bar->generation |= 1;
+}
+
+static inline void
+gomp_team_barrier_clear_task_pending (gomp_barrier_t *bar)
+{
+  bar->generation &= ~1;
+}
+
+static inline void
+gomp_team_barrier_set_waiting_for_tasks (gomp_barrier_t *bar)
+{
+  bar->generation |= 2;
+}
+
+static inline bool
+gomp_team_barrier_waiting_for_tasks (gomp_barrier_t *bar)
+{
+  return (bar->generation & 2) != 0;
+}
+
+static inline void
+gomp_team_barrier_done (gomp_barrier_t *bar, gomp_barrier_state_t state)
+{
+  bar->generation = (state & ~3) + 4;
 }
 
 #endif /* GOMP_BARRIER_H */
index 59459bb86ce6b9cbe9662a029a77ba137f050d61..c2868398c664f9b29f06a464a5a8a1456091a648 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2008 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
 
 #include "libgomp.h"
 
+#ifdef HAVE_BROKEN_POSIX_SEMAPHORES
+void
+gomp_init_lock_30 (omp_lock_t *lock)
+{
+  pthread_mutex_init (lock, NULL);
+}
+
+void
+gomp_destroy_lock_30 (omp_lock_t *lock)
+{
+  pthread_mutex_destroy (lock);
+}
+
+void
+gomp_set_lock_30 (omp_lock_t *lock)
+{
+  pthread_mutex_lock (lock);
+}
+
+void
+gomp_unset_lock_30 (omp_lock_t *lock)
+{
+  pthread_mutex_unlock (lock);
+}
+
+int
+gomp_test_lock_30 (omp_lock_t *lock)
+{
+  return pthread_mutex_trylock (lock) == 0;
+}
+
+void
+gomp_init_nest_lock_30 (omp_nest_lock_t *lock)
+{
+  pthread_mutex_init (&lock->lock, NULL);
+  lock->count = 0;
+  lock->owner = NULL;
+}
+
+void
+gomp_destroy_nest_lock_30 (omp_nest_lock_t *lock)
+{
+  pthread_mutex_destroy (&lock->lock);
+}
+
+void
+gomp_set_nest_lock_30 (omp_nest_lock_t *lock)
+{
+  void *me = gomp_icv (true);
+
+  if (lock->owner != me)
+    {
+      pthread_mutex_lock (&lock->lock);
+      lock->owner = me;
+    }
+  lock->count++;
+}
+
+void
+gomp_unset_nest_lock_30 (omp_nest_lock_t *lock)
+{
+  if (--lock->count == 0)
+    {
+      lock->owner = NULL;
+      pthread_mutex_unlock (&lock->lock);
+    }
+}
+
+int
+gomp_test_nest_lock_30 (omp_nest_lock_t *lock)
+{
+  void *me = gomp_icv (true);
+
+  if (lock->owner != me)
+    {
+      if (pthread_mutex_trylock (&lock->lock) != 0)
+       return 0;
+      lock->owner = me;
+    }
+
+  return ++lock->count;
+}
+
+#else
 
 void
-omp_init_lock (omp_lock_t *lock)
+gomp_init_lock_30 (omp_lock_t *lock)
+{
+  sem_init (lock, 0, 1);
+}
+
+void
+gomp_destroy_lock_30 (omp_lock_t *lock)
+{
+  sem_destroy (lock);
+}
+
+void
+gomp_set_lock_30 (omp_lock_t *lock)
+{
+  while (sem_wait (lock) != 0)
+    ;
+}
+
+void
+gomp_unset_lock_30 (omp_lock_t *lock)
+{
+  sem_post (lock);
+}
+
+int
+gomp_test_lock_30 (omp_lock_t *lock)
+{
+  return sem_trywait (lock) == 0;
+}
+
+void
+gomp_init_nest_lock_30 (omp_nest_lock_t *lock)
+{
+  sem_init (&lock->lock, 0, 1);
+  lock->count = 0;
+  lock->owner = NULL;
+}
+
+void
+gomp_destroy_nest_lock_30 (omp_nest_lock_t *lock)
+{
+  sem_destroy (&lock->lock);
+}
+
+void
+gomp_set_nest_lock_30 (omp_nest_lock_t *lock)
+{
+  void *me = gomp_icv (true);
+
+  if (lock->owner != me)
+    {
+      while (sem_wait (&lock->lock) != 0)
+       ;
+      lock->owner = me;
+    }
+  lock->count++;
+}
+
+void
+gomp_unset_nest_lock_30 (omp_nest_lock_t *lock)
+{
+  if (--lock->count == 0)
+    {
+      lock->owner = NULL;
+      sem_post (&lock->lock);
+    }
+}
+
+int
+gomp_test_nest_lock_30 (omp_nest_lock_t *lock)
+{
+  void *me = gomp_icv (true);
+
+  if (lock->owner != me)
+    {
+      if (sem_trywait (&lock->lock) != 0)
+       return 0;
+      lock->owner = me;
+    }
+
+  return ++lock->count;
+}
+#endif
+
+#ifdef LIBGOMP_GNU_SYMBOL_VERSIONING
+void
+gomp_init_lock_25 (omp_lock_25_t *lock)
 {
   pthread_mutex_init (lock, NULL);
 }
 
 void
-omp_destroy_lock (omp_lock_t *lock)
+gomp_destroy_lock_25 (omp_lock_25_t *lock)
 {
   pthread_mutex_destroy (lock);
 }
 
 void
-omp_set_lock (omp_lock_t *lock)
+gomp_set_lock_25 (omp_lock_25_t *lock)
 {
   pthread_mutex_lock (lock);
 }
 
 void
-omp_unset_lock (omp_lock_t *lock)
+gomp_unset_lock_25 (omp_lock_25_t *lock)
 {
   pthread_mutex_unlock (lock);
 }
 
 int
-omp_test_lock (omp_lock_t *lock)
+gomp_test_lock_25 (omp_lock_25_t *lock)
 {
   return pthread_mutex_trylock (lock) == 0;
 }
 
 void
-omp_init_nest_lock (omp_nest_lock_t *lock)
+gomp_init_nest_lock_25 (omp_nest_lock_25_t *lock)
 {
   pthread_mutexattr_t attr;
 
@@ -86,33 +256,46 @@ omp_init_nest_lock (omp_nest_lock_t *lock)
 }
 
 void
-omp_destroy_nest_lock (omp_nest_lock_t *lock)
+gomp_destroy_nest_lock_25 (omp_nest_lock_25_t *lock)
 {
   pthread_mutex_destroy (&lock->lock);
 }
 
 void
-omp_set_nest_lock (omp_nest_lock_t *lock)
+gomp_set_nest_lock_25 (omp_nest_lock_25_t *lock)
 {
   pthread_mutex_lock (&lock->lock);
   lock->count++;
 }
 
 void
-omp_unset_nest_lock (omp_nest_lock_t *lock)
+gomp_unset_nest_lock_25 (omp_nest_lock_25_t *lock)
 {
   lock->count--;
   pthread_mutex_unlock (&lock->lock);
 }
 
 int
-omp_test_nest_lock (omp_nest_lock_t *lock)
+gomp_test_nest_lock_25 (omp_nest_lock_25_t *lock)
 {
   if (pthread_mutex_trylock (&lock->lock) == 0)
     return ++lock->count;
   return 0;
 }
 
+omp_lock_symver (omp_init_lock)
+omp_lock_symver (omp_destroy_lock)
+omp_lock_symver (omp_set_lock)
+omp_lock_symver (omp_unset_lock)
+omp_lock_symver (omp_test_lock)
+omp_lock_symver (omp_init_nest_lock)
+omp_lock_symver (omp_destroy_nest_lock)
+omp_lock_symver (omp_set_nest_lock)
+omp_lock_symver (omp_unset_nest_lock)
+omp_lock_symver (omp_test_nest_lock)
+
+#else
+
 ialias (omp_init_lock)
 ialias (omp_init_nest_lock)
 ialias (omp_destroy_lock)
@@ -123,3 +306,5 @@ ialias (omp_unset_lock)
 ialias (omp_unset_nest_lock)
 ialias (omp_test_lock)
 ialias (omp_test_nest_lock)
+
+#endif
index ed70618d87ded7f3960d49e6153c3eb8284ea7da..e51dc271f8ac8015ad753c4d705ae4364b89836f 100644 (file)
@@ -2,10 +2,22 @@
    alignment of the public OpenMP locks, so that we can export data
    structures without polluting the namespace.
 
-   In this default POSIX implementation, we map the two locks to the
-   same PTHREADS primitive.  */
+   In this default POSIX implementation, we used to map the two locks to the
+   same PTHREADS primitive, but for OpenMP 3.0 sem_t needs to be used
+   instead, as pthread_mutex_unlock should not be called by different
+   thread than the one that called pthread_mutex_lock.  */
 
 #include <pthread.h>
+#include <semaphore.h>
 
+typedef pthread_mutex_t omp_lock_25_t;
+typedef struct { pthread_mutex_t lock; int count; } omp_nest_lock_25_t;
+#ifdef HAVE_BROKEN_POSIX_SEMAPHORES
+/* If we don't have working semaphores, we'll make all explicit tasks
+   tied to the creating thread.  */
 typedef pthread_mutex_t omp_lock_t;
-typedef struct { pthread_mutex_t lock; int count; } omp_nest_lock_t;
+typedef struct { pthread_mutex_t lock; int count; void *owner; } omp_nest_lock_t;
+#else
+typedef sem_t omp_lock_t;
+typedef struct { sem_t lock; int count; void *owner; } omp_nest_lock_t;
+#endif
index 3ee84f5c9d6b8f54791ba9f0b9524e2ca07bdbda..0c1096fb6b112e578ab28e51916f42bbb6d25be6 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2006, 2008 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
@@ -48,7 +48,7 @@ void
 gomp_init_num_threads (void)
 {
 #ifdef _SC_NPROCESSORS_ONLN
-  gomp_nthreads_var = sysconf (_SC_NPROCESSORS_ONLN);
+  gomp_global_icv.nthreads_var = sysconf (_SC_NPROCESSORS_ONLN);
 #endif
 }
 
@@ -63,13 +63,14 @@ unsigned
 gomp_dynamic_max_threads (void)
 {
   unsigned n_onln, loadavg;
+  unsigned nthreads_var = gomp_icv (false)->nthreads_var;
 
 #ifdef _SC_NPROCESSORS_ONLN
   n_onln = sysconf (_SC_NPROCESSORS_ONLN);
-  if (n_onln > gomp_nthreads_var)
-    n_onln = gomp_nthreads_var;
+  if (n_onln > nthreads_var)
+    n_onln = nthreads_var;
 #else
-  n_onln = gomp_nthreads_var;
+  n_onln = nthreads_var;
 #endif
 
   loadavg = 0;
@@ -96,7 +97,7 @@ omp_get_num_procs (void)
 #ifdef _SC_NPROCESSORS_ONLN
   return sysconf (_SC_NPROCESSORS_ONLN);
 #else
-  return gomp_nthreads_var;
+  return gomp_icv (false)->nthreads_var;
 #endif
 }
 
diff --git a/libgomp/config/posix/ptrlock.c b/libgomp/config/posix/ptrlock.c
new file mode 100644 (file)
index 0000000..39bb64d
--- /dev/null
@@ -0,0 +1 @@
+/* Everything is in the header.  */
diff --git a/libgomp/config/posix/ptrlock.h b/libgomp/config/posix/ptrlock.h
new file mode 100644 (file)
index 0000000..1271ebb
--- /dev/null
@@ -0,0 +1,69 @@
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+   Contributed by Jakub Jelinek <jakub@redhat.com>.
+
+   This file is part of the GNU OpenMP Library (libgomp).
+
+   Libgomp is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 2.1 of the License, or
+   (at your option) any later version.
+
+   Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+   FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+   more details.
+
+   You should have received a copy of the GNU Lesser General Public License 
+   along with libgomp; see the file COPYING.LIB.  If not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+/* As a special exception, if you link this library with other files, some
+   of which are compiled with GCC, to produce an executable, this library
+   does not by itself cause the resulting executable to be covered by the
+   GNU General Public License.  This exception does not however invalidate
+   any other reasons why the executable file might be covered by the GNU
+   General Public License.  */
+
+/* This is a Linux specific implementation of a mutex synchronization
+   mechanism for libgomp.  This type is private to the library.  This
+   implementation uses atomic instructions and the futex syscall.  */
+
+#ifndef GOMP_PTRLOCK_H
+#define GOMP_PTRLOCK_H 1
+
+typedef struct { void *ptr; gomp_mutex_t lock; } gomp_ptrlock_t;
+
+static inline void gomp_ptrlock_init (gomp_ptrlock_t *ptrlock, void *ptr)
+{
+  ptrlock->ptr = ptr;
+  gomp_mutex_init (&ptrlock->lock);
+}
+
+static inline void *gomp_ptrlock_get (gomp_ptrlock_t *ptrlock)
+{
+  if (ptrlock->ptr != NULL)
+    return ptrlock->ptr;
+
+  gomp_mutex_lock (&ptrlock->lock);
+  if (ptrlock->ptr != NULL)
+    {
+      gomp_mutex_unlock (&ptrlock->lock);
+      return ptrlock->ptr;
+    }
+
+  return NULL;
+}
+
+static inline void gomp_ptrlock_set (gomp_ptrlock_t *ptrlock, void *ptr)
+{
+  ptrlock->ptr = ptr;
+  gomp_mutex_unlock (&ptrlock->lock);
+}
+
+static inline void gomp_ptrlock_destroy (gomp_ptrlock_t *ptrlock)
+{
+  gomp_mutex_destroy (&ptrlock->lock);
+}
+
+#endif /* GOMP_PTRLOCK_H */
index 2416f1131c781a10c846d01b7799b74582d9c975..e27437ead16b1110412fbb3cfa70d2a1e0a4ed4c 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 Free Software Foundation, Inc.
+/* Copyright (C) 2006, 2008 Free Software Foundation, Inc.
 
    This file is part of the GNU OpenMP Library (libgomp).
 
 
 #include "libgomp.h"
 
+#ifdef HAVE_BROKEN_POSIX_SEMAPHORES
+void
+gomp_init_lock_30 (omp_lock_t *lock)
+{
+  pthread_mutex_init (lock, NULL);
+}
+
+void
+gomp_destroy_lock_30 (omp_lock_t *lock)
+{
+  pthread_mutex_destroy (lock);
+}
+
+void
+gomp_set_lock_30 (omp_lock_t *lock)
+{
+  pthread_mutex_lock (lock);
+}
+
+void
+gomp_unset_lock_30 (omp_lock_t *lock)
+{
+  pthread_mutex_unlock (lock);
+}
+
+int
+gomp_test_lock_30 (omp_lock_t *lock)
+{
+  return pthread_mutex_trylock (lock) == 0;
+}
+
+void
+gomp_init_nest_lock_30 (omp_nest_lock_t *lock)
+{
+  pthread_mutex_init (&lock->lock, NULL);
+  lock->owner = NULL;
+  lock->count = 0;
+}
+
+void
+gomp_destroy_nest_lock_30 (omp_nest_lock_t *lock)
+{
+  pthread_mutex_destroy (&lock->lock);
+}
 
 void
-omp_init_lock (omp_lock_t *lock)
+gomp_set_nest_lock_30 (omp_nest_lock_t *lock)
+{
+  void *me = gomp_icv (true);
+
+  if (lock->owner != me)
+    {
+      pthread_mutex_lock (&lock->lock);
+      lock->owner = me;
+    }
+
+  lock->count++;
+}
+
+void
+gomp_unset_nest_lock_30 (omp_nest_lock_t *lock)
+{
+  lock->count--;
+
+  if (lock->count == 0)
+    {
+      lock->owner = NULL;
+      pthread_mutex_unlock (&lock->lock);
+    }
+}
+
+int
+gomp_test_nest_lock_30 (omp_nest_lock_t *lock)
+{
+  void *me = gomp_icv (true);
+
+  if (lock->owner != me)
+    {
+      if (pthread_mutex_trylock (&lock->lock) != 0)
+       return 0;
+      lock->owner = me;
+    }
+
+  return ++lock->count;
+}
+
+#else
+
+void
+gomp_init_lock_30 (omp_lock_t *lock)
+{
+  sem_init (lock, 0, 1);
+}
+
+void
+gomp_destroy_lock_30 (omp_lock_t *lock)
+{
+  sem_destroy (lock);
+}
+
+void
+gomp_set_lock_30 (omp_lock_t *lock)
+{
+  while (sem_wait (lock) != 0)
+    ;
+}
+
+void
+gomp_unset_lock_30 (omp_lock_t *lock)
+{
+  sem_post (lock);
+}
+
+int
+gomp_test_lock_30 (omp_lock_t *lock)
+{
+  return sem_trywait (lock) == 0;
+}
+
+void
+gomp_init_nest_lock_30 (omp_nest_lock_t *lock)
+{
+  sem_init (&lock->lock, 0, 1);
+  lock->count = 0;
+  lock->owner = NULL;
+}
+
+void
+gomp_destroy_nest_lock_30 (omp_nest_lock_t *lock)
+{
+  sem_destroy (&lock->lock);
+}
+
+void
+gomp_set_nest_lock_30 (omp_nest_lock_t *lock)
+{
+  void *me = gomp_icv (true);
+
+  if (lock->owner != me)
+    {
+      while (sem_wait (&lock->lock) != 0)
+       ;
+      lock->owner = me;
+    }
+  lock->count++;
+}
+
+void
+gomp_unset_nest_lock_30 (omp_nest_lock_t *lock)
+{
+  if (--lock->count == 0)
+    {
+      lock->owner = NULL;
+      sem_post (&lock->lock);
+    }
+}
+
+int
+gomp_test_nest_lock_30 (omp_nest_lock_t *lock)
+{
+  void *me = gomp_icv (true);
+
+  if (lock->owner != me)
+    {
+      if (sem_trywait (&lock->lock) != 0)
+       return 0;
+      lock->owner = me;
+    }
+
+  return ++lock->count;
+}
+#endif
+
+#ifdef LIBGOMP_GNU_SYMBOL_VERSIONING
+void
+gomp_init_lock_25 (omp_lock_25_t *lock)
 {
   pthread_mutex_init (lock, NULL);
 }
 
 void
-omp_destroy_lock (omp_lock_t *lock)
+gomp_destroy_lock_25 (omp_lock_25_t *lock)
 {
   pthread_mutex_destroy (lock);
 }
 
 void
-omp_set_lock (omp_lock_t *lock)
+gomp_set_lock_25 (omp_lock_25_t *lock)
 {
   pthread_mutex_lock (lock);
 }
 
 void
-omp_unset_lock (omp_lock_t *lock)
+gomp_unset_lock_25 (omp_lock_25_t *lock)
 {
   pthread_mutex_unlock (lock);
 }
 
 int
-omp_test_lock (omp_lock_t *lock)
+gomp_test_lock_25 (omp_lock_25_t *lock)
 {
   return pthread_mutex_trylock (lock) == 0;
 }
 
 void
-omp_init_nest_lock (omp_nest_lock_t *lock)
+gomp_init_nest_lock_25 (omp_nest_lock_25_t *lock)
 {
   pthread_mutex_init (&lock->lock, NULL);
   lock->owner = (pthread_t) 0;
@@ -73,13 +246,13 @@ omp_init_nest_lock (omp_nest_lock_t *lock)
 }
 
 void
-omp_destroy_nest_lock (omp_nest_lock_t *lock)
+gomp_destroy_nest_lock_25 (omp_nest_lock_25_t *lock)
 {
   pthread_mutex_destroy (&lock->lock);
 }
 
 void
-omp_set_nest_lock (omp_nest_lock_t *lock)
+gomp_set_nest_lock_25 (omp_nest_lock_25_t *lock)
 {
   pthread_t me = pthread_self ();
 
@@ -93,7 +266,7 @@ omp_set_nest_lock (omp_nest_lock_t *lock)
 }
 
 void
-omp_unset_nest_lock (omp_nest_lock_t *lock)
+gomp_unset_nest_lock_25 (omp_nest_lock_25_t *lock)
 {
   lock->count--;
 
@@ -105,7 +278,7 @@ omp_unset_nest_lock (omp_nest_lock_t *lock)
 }
 
 int
-omp_test_nest_lock (omp_nest_lock_t *lock)
+gomp_test_nest_lock_25 (omp_nest_lock_25_t *lock)
 {
   pthread_t me = pthread_self ();
 
@@ -119,6 +292,19 @@ omp_test_nest_lock (omp_nest_lock_t *lock)
   return ++lock->count;
 }
 
+omp_lock_symver (omp_init_lock)
+omp_lock_symver (omp_destroy_lock)
+omp_lock_symver (omp_set_lock)
+omp_lock_symver (omp_unset_lock)
+omp_lock_symver (omp_test_lock)
+omp_lock_symver (omp_init_nest_lock)
+omp_lock_symver (omp_destroy_nest_lock)
+omp_lock_symver (omp_set_nest_lock)
+omp_lock_symver (omp_unset_nest_lock)
+omp_lock_symver (omp_test_nest_lock)
+
+#else
+
 ialias (omp_init_lock)
 ialias (omp_init_nest_lock)
 ialias (omp_destroy_lock)
@@ -129,3 +315,5 @@ ialias (omp_unset_lock)
 ialias (omp_unset_nest_lock)
 ialias (omp_test_lock)
 ialias (omp_test_nest_lock)
+
+#endif
index c446aec01e5a680235d314b9d5bf7fd2e8293609..b542ba13192324b34d39b62097eee8af7d716589 100644 (file)
@@ -6,12 +6,16 @@
    same PTHREADS primitive.  */
 
 #include <pthread.h>
+#include <semaphore.h>
 
+typedef pthread_mutex_t omp_lock_25_t;
+typedef struct { pthread_mutex_t lock; pthread_t owner; int count; } omp_nest_lock_25_t;
+#ifdef HAVE_BROKEN_POSIX_SEMAPHORES
+/* If we don't have working semaphores, we'll make all explicit tasks
+   tied to the creating thread.  */
 typedef pthread_mutex_t omp_lock_t;
-
-typedef struct
-{
-  pthread_mutex_t lock;
-  pthread_t owner;
-  int count;
-} omp_nest_lock_t;
+typedef struct { pthread_mutex_t lock; int count; void *owner; } omp_nest_lock_t;
+#else
+typedef sem_t omp_lock_t;
+typedef struct { sem_t lock; int count; void *owner; } omp_nest_lock_t;
+#endif
index 0fda5c740a0690e5e7083509bb2222783782bb49..f22c8a06c318230c8a07542ca0a5f1c9cee3026c 100755 (executable)
@@ -457,7 +457,7 @@ ac_includes_default="\
 # include <unistd.h>
 #endif"
 
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS GENINSRC_TRUE GENINSRC_FALSE build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar multi_basedir toolexecdir toolexeclibdir CC ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CFLAGS AR ac_ct_AR RANLIB ac_ct_RANLIB PERL BUILD_INFO_TRUE BUILD_INFO_FALSE LIBTOOL SED EGREP FGREP GREP LD DUMPBIN ac_ct_DUMPBIN NM LN_S lt_ECHO CPP CPPFLAGS enable_shared enable_static MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT FC FCFLAGS LDFLAGS ac_ct_FC libtool_VERSION SECTION_LDFLAGS OPT_LDFLAGS LIBGOMP_BUILD_VERSIONED_SHLIB_TRUE LIBGOMP_BUILD_VERSIONED_SHLIB_FALSE config_path XCFLAGS XLDFLAGS link_gomp USE_FORTRAN_TRUE USE_FORTRAN_FALSE OMP_LOCK_SIZE OMP_LOCK_ALIGN OMP_NEST_LOCK_SIZE OMP_NEST_LOCK_ALIGN OMP_LOCK_KIND OMP_NEST_LOCK_KIND LIBOBJS LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS GENINSRC_TRUE GENINSRC_FALSE build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar multi_basedir toolexecdir toolexeclibdir CC ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CFLAGS AR ac_ct_AR RANLIB ac_ct_RANLIB PERL BUILD_INFO_TRUE BUILD_INFO_FALSE LIBTOOL SED EGREP FGREP GREP LD DUMPBIN ac_ct_DUMPBIN NM LN_S lt_ECHO CPP CPPFLAGS enable_shared enable_static MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT FC FCFLAGS LDFLAGS ac_ct_FC libtool_VERSION SECTION_LDFLAGS OPT_LDFLAGS LIBGOMP_BUILD_VERSIONED_SHLIB_TRUE LIBGOMP_BUILD_VERSIONED_SHLIB_FALSE config_path XCFLAGS XLDFLAGS link_gomp USE_FORTRAN_TRUE USE_FORTRAN_FALSE OMP_LOCK_SIZE OMP_LOCK_ALIGN OMP_NEST_LOCK_SIZE OMP_NEST_LOCK_ALIGN OMP_LOCK_KIND OMP_NEST_LOCK_KIND OMP_LOCK_25_SIZE OMP_LOCK_25_ALIGN OMP_NEST_LOCK_25_SIZE OMP_NEST_LOCK_25_ALIGN OMP_LOCK_25_KIND OMP_NEST_LOCK_25_KIND LIBOBJS LTLIBOBJS'
 ac_subst_files=''
 
 # Initialize some variables set by options.
 echo "$as_me: versioning on shared library symbols is $enable_symvers" >&6;}
 
 
+if test $enable_symvers = gnu; then
+
+cat >>confdefs.h <<\_ACEOF
+#define LIBGOMP_GNU_SYMBOL_VERSIONING 1
+_ACEOF
+
+fi
+
 # Get target configury.
 . ${srcdir}/configure.tgt
 CFLAGS="$save_CFLAGS $XCFLAGS"
@@ -18156,7 +18164,7 @@ fi
 save_CFLAGS="$CFLAGS"
 for i in $config_path; do
   if test -f $srcdir/config/$i/omp-lock.h; then
-    CFLAGS="$CFLAGS -include $srcdir/config/$i/omp-lock.h"
+    CFLAGS="$CFLAGS -include confdefs.h -include $srcdir/config/$i/omp-lock.h"
     break
   fi
 done
@@ -19471,20 +19479,1344 @@ rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftes
 fi
 fi
 rm -f conftest.val
+if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
 
-# If the lock fits in an integer, then arrange for Fortran to use that
-# integer.  If it doesn't, then arrange for Fortran to use a pointer.
-# Except that we don't have a way at present to multi-lib the installed
-# Fortran modules, so we assume 8 bytes for pointers, regardless of the
-# actual target.
-OMP_LOCK_KIND=$OMP_LOCK_SIZE
-OMP_NEST_LOCK_KIND=$OMP_NEST_LOCK_SIZE
-if test $OMP_LOCK_SIZE -gt 8 || test $OMP_LOCK_ALIGN -gt $OMP_LOCK_SIZE; then
-  OMP_LOCK_KIND=8
+int
+main ()
+{
+static int test_array [1 - 2 * !((sizeof (omp_lock_25_t)) >= 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+static int test_array [1 - 2 * !((sizeof (omp_lock_25_t)) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr $ac_mid + 1`
+                   if test $ac_lo -le $ac_mid; then
+                     ac_lo= ac_hi=
+                     break
+                   fi
+                   ac_mid=`expr 2 '*' $ac_mid + 1`
 fi
-if test $OMP_NEST_LOCK_SIZE -gt 8 || test $OMP_NEST_LOCK_ALIGN -gt $OMP_NEST_LOCK_SIZE; then
-  OMP_NEST_LOCK_KIND=8
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+static int test_array [1 - 2 * !((sizeof (omp_lock_25_t)) < 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+static int test_array [1 - 2 * !((sizeof (omp_lock_25_t)) >= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_hi=`expr '(' $ac_mid ')' - 1`
+                      if test $ac_mid -le $ac_hi; then
+                        ac_lo= ac_hi=
+                        break
+                      fi
+                      ac_mid=`expr 2 '*' $ac_mid`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo= ac_hi=
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+static int test_array [1 - 2 * !((sizeof (omp_lock_25_t)) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) OMP_LOCK_25_SIZE=$ac_lo;;
+'') { { echo "$as_me:$LINENO: error: unsupported system, cannot find sizeof (omp_lock_25_t)" >&5
+echo "$as_me: error: unsupported system, cannot find sizeof (omp_lock_25_t)" >&2;}
+   { (exit 1); exit 1; }; } ;;
+esac
+else
+  if test "$cross_compiling" = yes; then
+  { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+long longval () { return sizeof (omp_lock_25_t); }
+unsigned long ulongval () { return sizeof (omp_lock_25_t); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    exit (1);
+  if ((sizeof (omp_lock_25_t)) < 0)
+    {
+      long i = longval ();
+      if (i != (sizeof (omp_lock_25_t)))
+       exit (1);
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long i = ulongval ();
+      if (i != (sizeof (omp_lock_25_t)))
+       exit (1);
+      fprintf (f, "%lu\n", i);
+    }
+  exit (ferror (f) || fclose (f) != 0);
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  OMP_LOCK_25_SIZE=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+{ { echo "$as_me:$LINENO: error: unsupported system, cannot find sizeof (omp_lock_25_t)" >&5
+echo "$as_me: error: unsupported system, cannot find sizeof (omp_lock_25_t)" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.val
+if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+static int test_array [1 - 2 * !((__alignof (omp_lock_25_t)) >= 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+static int test_array [1 - 2 * !((__alignof (omp_lock_25_t)) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr $ac_mid + 1`
+                   if test $ac_lo -le $ac_mid; then
+                     ac_lo= ac_hi=
+                     break
+                   fi
+                   ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+static int test_array [1 - 2 * !((__alignof (omp_lock_25_t)) < 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+static int test_array [1 - 2 * !((__alignof (omp_lock_25_t)) >= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_hi=`expr '(' $ac_mid ')' - 1`
+                      if test $ac_mid -le $ac_hi; then
+                        ac_lo= ac_hi=
+                        break
+                      fi
+                      ac_mid=`expr 2 '*' $ac_mid`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo= ac_hi=
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+static int test_array [1 - 2 * !((__alignof (omp_lock_25_t)) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) OMP_LOCK_25_ALIGN=$ac_lo;;
+'')  ;;
+esac
+else
+  if test "$cross_compiling" = yes; then
+  { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+long longval () { return __alignof (omp_lock_25_t); }
+unsigned long ulongval () { return __alignof (omp_lock_25_t); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    exit (1);
+  if ((__alignof (omp_lock_25_t)) < 0)
+    {
+      long i = longval ();
+      if (i != (__alignof (omp_lock_25_t)))
+       exit (1);
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long i = ulongval ();
+      if (i != (__alignof (omp_lock_25_t)))
+       exit (1);
+      fprintf (f, "%lu\n", i);
+    }
+  exit (ferror (f) || fclose (f) != 0);
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  OMP_LOCK_25_ALIGN=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.val
+if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+static int test_array [1 - 2 * !((sizeof (omp_nest_lock_25_t)) >= 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+static int test_array [1 - 2 * !((sizeof (omp_nest_lock_25_t)) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr $ac_mid + 1`
+                   if test $ac_lo -le $ac_mid; then
+                     ac_lo= ac_hi=
+                     break
+                   fi
+                   ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+static int test_array [1 - 2 * !((sizeof (omp_nest_lock_25_t)) < 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+static int test_array [1 - 2 * !((sizeof (omp_nest_lock_25_t)) >= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_hi=`expr '(' $ac_mid ')' - 1`
+                      if test $ac_mid -le $ac_hi; then
+                        ac_lo= ac_hi=
+                        break
+                      fi
+                      ac_mid=`expr 2 '*' $ac_mid`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo= ac_hi=
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+static int test_array [1 - 2 * !((sizeof (omp_nest_lock_25_t)) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) OMP_NEST_LOCK_25_SIZE=$ac_lo;;
+'')  ;;
+esac
+else
+  if test "$cross_compiling" = yes; then
+  { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+long longval () { return sizeof (omp_nest_lock_25_t); }
+unsigned long ulongval () { return sizeof (omp_nest_lock_25_t); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    exit (1);
+  if ((sizeof (omp_nest_lock_25_t)) < 0)
+    {
+      long i = longval ();
+      if (i != (sizeof (omp_nest_lock_25_t)))
+       exit (1);
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long i = ulongval ();
+      if (i != (sizeof (omp_nest_lock_25_t)))
+       exit (1);
+      fprintf (f, "%lu\n", i);
+    }
+  exit (ferror (f) || fclose (f) != 0);
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  OMP_NEST_LOCK_25_SIZE=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.val
+if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+static int test_array [1 - 2 * !((__alignof (omp_nest_lock_25_t)) >= 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+static int test_array [1 - 2 * !((__alignof (omp_nest_lock_25_t)) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr $ac_mid + 1`
+                   if test $ac_lo -le $ac_mid; then
+                     ac_lo= ac_hi=
+                     break
+                   fi
+                   ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+static int test_array [1 - 2 * !((__alignof (omp_nest_lock_25_t)) < 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+static int test_array [1 - 2 * !((__alignof (omp_nest_lock_25_t)) >= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_hi=`expr '(' $ac_mid ')' - 1`
+                      if test $ac_mid -le $ac_hi; then
+                        ac_lo= ac_hi=
+                        break
+                      fi
+                      ac_mid=`expr 2 '*' $ac_mid`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo= ac_hi=
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+static int test_array [1 - 2 * !((__alignof (omp_nest_lock_25_t)) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) OMP_NEST_LOCK_25_ALIGN=$ac_lo;;
+'')  ;;
+esac
+else
+  if test "$cross_compiling" = yes; then
+  { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+long longval () { return __alignof (omp_nest_lock_25_t); }
+unsigned long ulongval () { return __alignof (omp_nest_lock_25_t); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    exit (1);
+  if ((__alignof (omp_nest_lock_25_t)) < 0)
+    {
+      long i = longval ();
+      if (i != (__alignof (omp_nest_lock_25_t)))
+       exit (1);
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long i = ulongval ();
+      if (i != (__alignof (omp_nest_lock_25_t)))
+       exit (1);
+      fprintf (f, "%lu\n", i);
+    }
+  exit (ferror (f) || fclose (f) != 0);
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  OMP_NEST_LOCK_25_ALIGN=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.val
+
+# If the lock fits in an integer, then arrange for Fortran to use that
+# integer.  If it doesn't, then arrange for Fortran to use a pointer.
+# Except that we don't have a way at present to multi-lib the installed
+# Fortran modules, so we assume 8 bytes for pointers, regardless of the
+# actual target.
+OMP_LOCK_KIND=$OMP_LOCK_SIZE
+OMP_NEST_LOCK_KIND=$OMP_NEST_LOCK_SIZE
+if test $OMP_LOCK_SIZE -gt 8 || test $OMP_LOCK_ALIGN -gt $OMP_LOCK_SIZE; then
+  OMP_LOCK_KIND=8
+fi
+if test $OMP_NEST_LOCK_SIZE -gt 8 || test $OMP_NEST_LOCK_ALIGN -gt $OMP_NEST_LOCK_SIZE; then
+  OMP_NEST_LOCK_KIND=8
+fi
+OMP_LOCK_25_KIND=$OMP_LOCK_25_SIZE
+OMP_NEST_LOCK_25_KIND=$OMP_NEST_LOCK_25_SIZE
+if test $OMP_LOCK_25_SIZE -gt 8 || test $OMP_LOCK_25_ALIGN -gt $OMP_LOCK_25_SIZE; then
+  OMP_LOCK_25_KIND=8
+fi
+if test $OMP_NEST_LOCK_25_SIZE -gt 8 || test $OMP_NEST_LOCK_25_ALIGN -gt $OMP_NEST_LOCK_25_SIZE; then
+  OMP_NEST_LOCK_25_KIND=8
+fi
+
+
+
+
+
+
 
 
 
@@ -20640,6 +21972,12 @@ s,@OMP_NEST_LOCK_SIZE@,$OMP_NEST_LOCK_SIZE,;t t
 s,@OMP_NEST_LOCK_ALIGN@,$OMP_NEST_LOCK_ALIGN,;t t
 s,@OMP_LOCK_KIND@,$OMP_LOCK_KIND,;t t
 s,@OMP_NEST_LOCK_KIND@,$OMP_NEST_LOCK_KIND,;t t
+s,@OMP_LOCK_25_SIZE@,$OMP_LOCK_25_SIZE,;t t
+s,@OMP_LOCK_25_ALIGN@,$OMP_LOCK_25_ALIGN,;t t
+s,@OMP_NEST_LOCK_25_SIZE@,$OMP_NEST_LOCK_25_SIZE,;t t
+s,@OMP_NEST_LOCK_25_ALIGN@,$OMP_NEST_LOCK_25_ALIGN,;t t
+s,@OMP_LOCK_25_KIND@,$OMP_LOCK_25_KIND,;t t
+s,@OMP_NEST_LOCK_25_KIND@,$OMP_NEST_LOCK_25_KIND,;t t
 s,@LIBOBJS@,$LIBOBJS,;t t
 s,@LTLIBOBJS@,$LTLIBOBJS,;t t
 CEOF
index 47c61bea625664726d1836c393a0954a662f7b31..12c92340e8cc747953c7fd133af0d0b83a468142 100644 (file)
@@ -228,6 +228,11 @@ LIBGOMP_CHECK_ATTRIBUTE_DLLEXPORT
 LIBGOMP_CHECK_ATTRIBUTE_ALIAS
 LIBGOMP_ENABLE_SYMVERS
 
+if test $enable_symvers = gnu; then
+  AC_DEFINE(LIBGOMP_GNU_SYMBOL_VERSIONING, 1,
+           [Define to 1 if GNU symbol versioning is used for libgomp.])
+fi
+
 # Get target configury.
 . ${srcdir}/configure.tgt
 CFLAGS="$save_CFLAGS $XCFLAGS"
@@ -272,7 +277,7 @@ AM_CONDITIONAL([USE_FORTRAN], [test "$ac_cv_fc_compiler_gnu" = yes])
 save_CFLAGS="$CFLAGS"
 for i in $config_path; do
   if test -f $srcdir/config/$i/omp-lock.h; then
-    CFLAGS="$CFLAGS -include $srcdir/config/$i/omp-lock.h"
+    CFLAGS="$CFLAGS -include confdefs.h -include $srcdir/config/$i/omp-lock.h"
     break
   fi
 done
@@ -282,6 +287,11 @@ _AC_COMPUTE_INT([sizeof (omp_lock_t)], [OMP_LOCK_SIZE],,
 _AC_COMPUTE_INT([__alignof (omp_lock_t)], [OMP_LOCK_ALIGN])
 _AC_COMPUTE_INT([sizeof (omp_nest_lock_t)], [OMP_NEST_LOCK_SIZE])
 _AC_COMPUTE_INT([__alignof (omp_nest_lock_t)], [OMP_NEST_LOCK_ALIGN])
+_AC_COMPUTE_INT([sizeof (omp_lock_25_t)], [OMP_LOCK_25_SIZE],,
+  [AC_MSG_ERROR([unsupported system, cannot find sizeof (omp_lock_25_t)])])
+_AC_COMPUTE_INT([__alignof (omp_lock_25_t)], [OMP_LOCK_25_ALIGN])
+_AC_COMPUTE_INT([sizeof (omp_nest_lock_25_t)], [OMP_NEST_LOCK_25_SIZE])
+_AC_COMPUTE_INT([__alignof (omp_nest_lock_25_t)], [OMP_NEST_LOCK_25_ALIGN])
 
 # If the lock fits in an integer, then arrange for Fortran to use that
 # integer.  If it doesn't, then arrange for Fortran to use a pointer.
@@ -296,6 +306,14 @@ fi
 if test $OMP_NEST_LOCK_SIZE -gt 8 || test $OMP_NEST_LOCK_ALIGN -gt $OMP_NEST_LOCK_SIZE; then
   OMP_NEST_LOCK_KIND=8
 fi
+OMP_LOCK_25_KIND=$OMP_LOCK_25_SIZE
+OMP_NEST_LOCK_25_KIND=$OMP_NEST_LOCK_25_SIZE
+if test $OMP_LOCK_25_SIZE -gt 8 || test $OMP_LOCK_25_ALIGN -gt $OMP_LOCK_25_SIZE; then
+  OMP_LOCK_25_KIND=8
+fi
+if test $OMP_NEST_LOCK_25_SIZE -gt 8 || test $OMP_NEST_LOCK_25_ALIGN -gt $OMP_NEST_LOCK_25_SIZE; then
+  OMP_NEST_LOCK_25_KIND=8
+fi
 
 AC_SUBST(OMP_LOCK_SIZE)
 AC_SUBST(OMP_LOCK_ALIGN)
@@ -303,6 +321,12 @@ AC_SUBST(OMP_NEST_LOCK_SIZE)
 AC_SUBST(OMP_NEST_LOCK_ALIGN)
 AC_SUBST(OMP_LOCK_KIND)
 AC_SUBST(OMP_NEST_LOCK_KIND)
+AC_SUBST(OMP_LOCK_25_SIZE)
+AC_SUBST(OMP_LOCK_25_ALIGN)
+AC_SUBST(OMP_NEST_LOCK_25_SIZE)
+AC_SUBST(OMP_NEST_LOCK_25_ALIGN)
+AC_SUBST(OMP_LOCK_25_KIND)
+AC_SUBST(OMP_NEST_LOCK_25_KIND)
 CFLAGS="$save_CFLAGS"
 
 AC_CONFIG_FILES(omp.h omp_lib.h omp_lib.f90 libgomp_f.h)
index 6c6a35228eb555bc09c37bac6f878b7e4095f956..022fb1bb0ad9a19c68ec1c6fa9a8f4ced2c66297 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
@@ -13,7 +13,7 @@
    FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
    more details.
 
-   You should have received a copy of the GNU Lesser General Public License 
+   You should have received a copy of the GNU Lesser General Public License
    along with libgomp; see the file COPYING.LIB.  If not, write to the
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
    MA 02110-1301, USA.  */
 #include <errno.h>
 
 
-unsigned long gomp_nthreads_var = 1;
-bool gomp_dyn_var = false;
-bool gomp_nest_var = false;
-enum gomp_schedule_type gomp_run_sched_var = GFS_DYNAMIC;
-unsigned long gomp_run_sched_chunk = 1;
+struct gomp_task_icv gomp_global_icv = {
+  .nthreads_var = 1,
+  .run_sched_var = GFS_DYNAMIC,
+  .run_sched_modifier = 1,
+  .dyn_var = false,
+  .nest_var = false
+};
+
 unsigned short *gomp_cpu_affinity;
 size_t gomp_cpu_affinity_len;
+unsigned long gomp_max_active_levels_var = INT_MAX;
+unsigned long gomp_thread_limit_var = ULONG_MAX;
+unsigned long gomp_remaining_threads_count;
+#ifndef HAVE_SYNC_BUILTINS
+gomp_mutex_t gomp_remaining_threads_lock;
+#endif
+unsigned long gomp_available_cpus = 1, gomp_managed_threads = 1;
+unsigned long long gomp_spin_count_var, gomp_throttled_spin_count_var;
 
 /* Parse the OMP_SCHEDULE environment variable.  */
 
@@ -72,19 +83,24 @@ parse_schedule (void)
     ++env;
   if (strncasecmp (env, "static", 6) == 0)
     {
-      gomp_run_sched_var = GFS_STATIC;
+      gomp_global_icv.run_sched_var = GFS_STATIC;
       env += 6;
     }
   else if (strncasecmp (env, "dynamic", 7) == 0)
     {
-      gomp_run_sched_var = GFS_DYNAMIC;
+      gomp_global_icv.run_sched_var = GFS_DYNAMIC;
       env += 7;
     }
   else if (strncasecmp (env, "guided", 6) == 0)
     {
-      gomp_run_sched_var = GFS_GUIDED;
+      gomp_global_icv.run_sched_var = GFS_GUIDED;
       env += 6;
     }
+  else if (strncasecmp (env, "auto", 4) == 0)
+    {
+      gomp_global_icv.run_sched_var = GFS_AUTO;
+      env += 4;
+    }
   else
     goto unknown;
 
@@ -109,7 +125,10 @@ parse_schedule (void)
   if (*end != '\0')
     goto invalid;
 
-  gomp_run_sched_chunk = value;
+  if ((int)value != value)
+    goto invalid;
+
+  gomp_global_icv.run_sched_modifier = value;
   return;
 
  unknown:
@@ -122,7 +141,7 @@ parse_schedule (void)
   return;
 }
 
-/* Parse an unsigned long environment varible.  Return true if one was
+/* Parse an unsigned long environment variable.  Return true if one was
    present and it was successfully parsed.  */
 
 static bool
@@ -158,7 +177,141 @@ parse_unsigned_long (const char *name, unsigned long *pvalue)
   return false;
 }
 
-/* Parse a boolean value for environment variable NAME and store the 
+/* Parse the OMP_STACKSIZE environment varible.  Return true if one was
+   present and it was successfully parsed.  */
+
+static bool
+parse_stacksize (const char *name, unsigned long *pvalue)
+{
+  char *env, *end;
+  unsigned long value, shift = 10;
+
+  env = getenv (name);
+  if (env == NULL)
+    return false;
+
+  while (isspace ((unsigned char) *env))
+    ++env;
+  if (*env == '\0')
+    goto invalid;
+
+  errno = 0;
+  value = strtoul (env, &end, 10);
+  if (errno)
+    goto invalid;
+
+  while (isspace ((unsigned char) *end))
+    ++end;
+  if (*end != '\0')
+    {
+      switch (tolower (*end))
+       {
+       case 'b':
+         shift = 0;
+         break;
+       case 'k':
+         break;
+       case 'm':
+         shift = 20;
+         break;
+       case 'g':
+         shift = 30;
+         break;
+       default:
+         goto invalid;
+       }
+      ++end;
+      while (isspace ((unsigned char) *end))
+       ++end;
+      if (*end != '\0')
+       goto invalid;
+    }
+
+  if (((value << shift) >> shift) != value)
+    goto invalid;
+
+  *pvalue = value << shift;
+  return true;
+
+ invalid:
+  gomp_error ("Invalid value for environment variable %s", name);
+  return false;
+}
+
+/* Parse the GOMP_SPINCOUNT environment varible.  Return true if one was
+   present and it was successfully parsed.  */
+
+static bool
+parse_spincount (const char *name, unsigned long long *pvalue)
+{
+  char *env, *end;
+  unsigned long long value, mult = 1;
+
+  env = getenv (name);
+  if (env == NULL)
+    return false;
+
+  while (isspace ((unsigned char) *env))
+    ++env;
+  if (*env == '\0')
+    goto invalid;
+
+  if (strncasecmp (env, "infinite", 8) == 0
+      || strncasecmp (env, "infinity", 8) == 0)
+    {
+      value = ~0ULL;
+      end = env + 8;
+      goto check_tail;
+    }
+
+  errno = 0;
+  value = strtoull (env, &end, 10);
+  if (errno)
+    goto invalid;
+
+  while (isspace ((unsigned char) *end))
+    ++end;
+  if (*end != '\0')
+    {
+      switch (tolower (*end))
+       {
+       case 'k':
+         mult = 1000LL;
+         break;
+       case 'm':
+         mult = 1000LL * 1000LL;
+         break;
+       case 'g':
+         mult = 1000LL * 1000LL * 1000LL;
+         break;
+       case 't':
+         mult = 1000LL * 1000LL * 1000LL * 1000LL;
+         break;
+       default:
+         goto invalid;
+       }
+      ++end;
+     check_tail:
+      while (isspace ((unsigned char) *end))
+       ++end;
+      if (*end != '\0')
+       goto invalid;
+    }
+
+  if (value > ~0ULL / mult)
+    value = ~0ULL;
+  else
+    value *= mult;
+
+  *pvalue = value;
+  return true;
+
+ invalid:
+  gomp_error ("Invalid value for environment variable %s", name);
+  return false;
+}
+
+/* Parse a boolean value for environment variable NAME and store the
    result in VALUE.  */
 
 static void
@@ -190,6 +343,41 @@ parse_boolean (const char *name, bool *value)
     gomp_error ("Invalid value for environment variable %s", name);
 }
 
+/* Parse the OMP_WAIT_POLICY environment variable and store the
+   result in gomp_active_wait_policy.  */
+
+static int
+parse_wait_policy (void)
+{
+  const char *env;
+  int ret = -1;
+
+  env = getenv ("OMP_WAIT_POLICY");
+  if (env == NULL)
+    return -1;
+
+  while (isspace ((unsigned char) *env))
+    ++env;
+  if (strncasecmp (env, "active", 6) == 0)
+    {
+      ret = 1;
+      env += 6;
+    }
+  else if (strncasecmp (env, "passive", 7) == 0)
+    {
+      ret = 0;
+      env += 7;
+    }
+  else
+    env = "X";
+  while (isspace ((unsigned char) *env))
+    ++env;
+  if (*env == '\0')
+    return ret;
+  gomp_error ("Invalid value for environment variable OMP_WAIT_POLICY");
+  return -1;
+}
+
 /* Parse the GOMP_CPU_AFFINITY environment varible.  Return true if one was
    present and it was successfully parsed.  */
 
@@ -285,27 +473,61 @@ static void __attribute__((constructor))
 initialize_env (void)
 {
   unsigned long stacksize;
+  int wait_policy;
 
   /* Do a compile time check that mkomp_h.pl did good job.  */
   omp_check_defines ();
 
   parse_schedule ();
-  parse_boolean ("OMP_DYNAMIC", &gomp_dyn_var);
-  parse_boolean ("OMP_NESTED", &gomp_nest_var);
-  if (!parse_unsigned_long ("OMP_NUM_THREADS", &gomp_nthreads_var))
-    gomp_init_num_threads ();
+  parse_boolean ("OMP_DYNAMIC", &gomp_global_icv.dyn_var);
+  parse_boolean ("OMP_NESTED", &gomp_global_icv.nest_var);
+  parse_unsigned_long ("OMP_MAX_ACTIVE_LEVELS", &gomp_max_active_levels_var);
+  parse_unsigned_long ("OMP_THREAD_LIMIT", &gomp_thread_limit_var);
+  if (gomp_thread_limit_var != ULONG_MAX)
+    {
+      gomp_remaining_threads_count = gomp_thread_limit_var - 1;
+#ifndef HAVE_SYNC_BUILTINS
+      gomp_mutex_init (&gomp_remaining_threads_lock);
+#endif
+    }
+  gomp_init_num_threads ();
+  gomp_available_cpus = gomp_global_icv.nthreads_var;
+  if (!parse_unsigned_long ("OMP_NUM_THREADS", &gomp_global_icv.nthreads_var))
+    gomp_global_icv.nthreads_var = gomp_available_cpus;
   if (parse_affinity ())
     gomp_init_affinity ();
+  wait_policy = parse_wait_policy ();
+  if (!parse_spincount ("GOMP_SPINCOUNT", &gomp_spin_count_var))
+    {
+      /* Using a rough estimation of 100000 spins per msec,
+        use 5 min blocking for OMP_WAIT_POLICY=active,
+        200 msec blocking when OMP_WAIT_POLICY is not specificed
+        and 0 when OMP_WAIT_POLICY=passive.
+        Depending on the CPU speed, this can be e.g. 5 times longer
+        or 5 times shorter.  */
+      if (wait_policy > 0)
+       gomp_spin_count_var = 30000000000LL;
+      else if (wait_policy < 0)
+       gomp_spin_count_var = 20000000LL;
+    }
+  /* gomp_throttled_spin_count_var is used when there are more libgomp
+     managed threads than available CPUs.  Use very short spinning.  */
+  if (wait_policy > 0)
+    gomp_throttled_spin_count_var = 1000LL;
+  else if (wait_policy < 0)
+    gomp_throttled_spin_count_var = 100LL;
+  if (gomp_throttled_spin_count_var > gomp_spin_count_var)
+    gomp_throttled_spin_count_var = gomp_spin_count_var;
 
   /* Not strictly environment related, but ordering constructors is tricky.  */
   pthread_attr_init (&gomp_thread_attr);
   pthread_attr_setdetachstate (&gomp_thread_attr, PTHREAD_CREATE_DETACHED);
 
-  if (parse_unsigned_long ("GOMP_STACKSIZE", &stacksize))
+  if (parse_stacksize ("OMP_STACKSIZE", &stacksize)
+      || parse_stacksize ("GOMP_STACKSIZE", &stacksize))
     {
       int err;
 
-      stacksize *= 1024;
       err = pthread_attr_setstacksize (&gomp_thread_attr, stacksize);
 
 #ifdef PTHREAD_STACK_MIN
@@ -331,31 +553,95 @@ initialize_env (void)
 void
 omp_set_num_threads (int n)
 {
-  gomp_nthreads_var = (n > 0 ? n : 1);
+  struct gomp_task_icv *icv = gomp_icv (true);
+  icv->nthreads_var = (n > 0 ? n : 1);
 }
 
 void
 omp_set_dynamic (int val)
 {
-  gomp_dyn_var = val;
+  struct gomp_task_icv *icv = gomp_icv (true);
+  icv->dyn_var = val;
 }
 
 int
 omp_get_dynamic (void)
 {
-  return gomp_dyn_var;
+  struct gomp_task_icv *icv = gomp_icv (false);
+  return icv->dyn_var;
 }
 
 void
 omp_set_nested (int val)
 {
-  gomp_nest_var = val;
+  struct gomp_task_icv *icv = gomp_icv (true);
+  icv->nest_var = val;
 }
 
 int
 omp_get_nested (void)
 {
-  return gomp_nest_var;
+  struct gomp_task_icv *icv = gomp_icv (false);
+  return icv->nest_var;
+}
+
+void
+omp_set_schedule (omp_sched_t kind, int modifier)
+{
+  struct gomp_task_icv *icv = gomp_icv (true);
+  switch (kind)
+    {
+    case omp_sched_static:
+      if (modifier < 1)
+       modifier = 0;
+      icv->run_sched_modifier = modifier;
+      break;
+    case omp_sched_dynamic:
+    case omp_sched_guided:
+      if (modifier < 1)
+       modifier = 1;
+      icv->run_sched_modifier = modifier;
+      break;
+    case omp_sched_auto:
+      break;
+    default:
+      return;
+    }
+  icv->run_sched_var = kind;
+}
+
+void
+omp_get_schedule (omp_sched_t *kind, int *modifier)
+{
+  struct gomp_task_icv *icv = gomp_icv (false);
+  *kind = icv->run_sched_var;
+  *modifier = icv->run_sched_modifier;
+}
+
+int
+omp_get_max_threads (void)
+{
+  struct gomp_task_icv *icv = gomp_icv (false);
+  return icv->nthreads_var;
+}
+
+int
+omp_get_thread_limit (void)
+{
+  return gomp_thread_limit_var > INT_MAX ? INT_MAX : gomp_thread_limit_var;
+}
+
+void
+omp_set_max_active_levels (int max_levels)
+{
+  if (max_levels > 0)
+    gomp_max_active_levels_var = max_levels;
+}
+
+int
+omp_get_max_active_levels (void)
+{
+  return gomp_max_active_levels_var;
 }
 
 ialias (omp_set_dynamic)
@@ -363,3 +649,9 @@ ialias (omp_set_nested)
 ialias (omp_set_num_threads)
 ialias (omp_get_dynamic)
 ialias (omp_get_nested)
+ialias (omp_set_schedule)
+ialias (omp_get_schedule)
+ialias (omp_get_max_threads)
+ialias (omp_get_thread_limit)
+ialias (omp_set_max_active_levels)
+ialias (omp_get_max_active_levels)
index f6f64c61be2f84df0e2d13dcbd7fed302b532b5c..1e20aea28eef241828edf3a65081f501afaabef0 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2007, 2008 Free Software Foundation, Inc.
    Contributed by Jakub Jelinek <jakub@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
 
 #ifdef HAVE_ATTRIBUTE_ALIAS
 /* Use internal aliases if possible.  */
-#define ULP    STR1(__USER_LABEL_PREFIX__)
-#define STR1(x)        STR2(x)
-#define STR2(x)        #x
+# define ULP           STR1(__USER_LABEL_PREFIX__)
+# define STR1(x)       STR2(x)
+# define STR2(x)       #x
 # define ialias_redirect(fn) \
   extern __typeof (fn) fn __asm__ (ULP "gomp_ialias_" #fn) attribute_hidden;
+# ifndef LIBGOMP_GNU_SYMBOL_VERSIONING
 ialias_redirect (omp_init_lock)
 ialias_redirect (omp_init_nest_lock)
 ialias_redirect (omp_destroy_lock)
@@ -48,6 +49,7 @@ ialias_redirect (omp_unset_lock)
 ialias_redirect (omp_unset_nest_lock)
 ialias_redirect (omp_test_lock)
 ialias_redirect (omp_test_nest_lock)
+# endif
 ialias_redirect (omp_set_dynamic)
 ialias_redirect (omp_set_nested)
 ialias_redirect (omp_set_num_threads)
@@ -60,30 +62,52 @@ ialias_redirect (omp_get_num_threads)
 ialias_redirect (omp_get_thread_num)
 ialias_redirect (omp_get_wtick)
 ialias_redirect (omp_get_wtime)
-#endif        
+ialias_redirect (omp_set_schedule)
+ialias_redirect (omp_get_schedule)
+ialias_redirect (omp_get_thread_limit)
+ialias_redirect (omp_set_max_active_levels)
+ialias_redirect (omp_get_max_active_levels)
+ialias_redirect (omp_get_level)
+ialias_redirect (omp_get_ancestor_thread_num)
+ialias_redirect (omp_get_team_size)
+ialias_redirect (omp_get_active_level)
+#endif
+
+#ifndef LIBGOMP_GNU_SYMBOL_VERSIONING
+# define gomp_init_lock__30 omp_init_lock_
+# define gomp_destroy_lock__30 omp_destroy_lock_
+# define gomp_set_lock__30 omp_set_lock_
+# define gomp_unset_lock__30 omp_unset_lock_
+# define gomp_test_lock__30 omp_test_lock_
+# define gomp_init_nest_lock__30 omp_init_nest_lock_
+# define gomp_destroy_nest_lock__30 omp_destroy_nest_lock_
+# define gomp_set_nest_lock__30 omp_set_nest_lock_
+# define gomp_unset_nest_lock__30 omp_unset_nest_lock_
+# define gomp_test_nest_lock__30 omp_test_nest_lock_
+#endif
 
 void
-omp_init_lock_ (omp_lock_arg_t lock)
+gomp_init_lock__30 (omp_lock_arg_t lock)
 {
 #ifndef OMP_LOCK_DIRECT
   omp_lock_arg (lock) = malloc (sizeof (omp_lock_t));
 #endif
-  omp_init_lock (omp_lock_arg (lock));
+  gomp_init_lock_30 (omp_lock_arg (lock));
 }
 
 void
-omp_init_nest_lock_ (omp_nest_lock_arg_t lock)
+gomp_init_nest_lock__30 (omp_nest_lock_arg_t lock)
 {
 #ifndef OMP_NEST_LOCK_DIRECT
   omp_nest_lock_arg (lock) = malloc (sizeof (omp_nest_lock_t));
 #endif
-  omp_init_nest_lock (omp_nest_lock_arg (lock));
+  gomp_init_nest_lock_30 (omp_nest_lock_arg (lock));
 }
 
 void
-omp_destroy_lock_ (omp_lock_arg_t lock)
+gomp_destroy_lock__30 (omp_lock_arg_t lock)
 {
-  omp_destroy_lock (omp_lock_arg (lock));
+  gomp_destroy_lock_30 (omp_lock_arg (lock));
 #ifndef OMP_LOCK_DIRECT
   free (omp_lock_arg (lock));
   omp_lock_arg (lock) = NULL;
@@ -91,9 +115,9 @@ omp_destroy_lock_ (omp_lock_arg_t lock)
 }
 
 void
-omp_destroy_nest_lock_ (omp_nest_lock_arg_t lock)
+gomp_destroy_nest_lock__30 (omp_nest_lock_arg_t lock)
 {
-  omp_destroy_nest_lock (omp_nest_lock_arg (lock));
+  gomp_destroy_nest_lock_30 (omp_nest_lock_arg (lock));
 #ifndef OMP_NEST_LOCK_DIRECT
   free (omp_nest_lock_arg (lock));
   omp_nest_lock_arg (lock) = NULL;
@@ -101,29 +125,128 @@ omp_destroy_nest_lock_ (omp_nest_lock_arg_t lock)
 }
 
 void
-omp_set_lock_ (omp_lock_arg_t lock)
+gomp_set_lock__30 (omp_lock_arg_t lock)
+{
+  gomp_set_lock_30 (omp_lock_arg (lock));
+}
+
+void
+gomp_set_nest_lock__30 (omp_nest_lock_arg_t lock)
 {
-  omp_set_lock (omp_lock_arg (lock));
+  gomp_set_nest_lock_30 (omp_nest_lock_arg (lock));
 }
 
 void
-omp_set_nest_lock_ (omp_nest_lock_arg_t lock)
+gomp_unset_lock__30 (omp_lock_arg_t lock)
 {
-  omp_set_nest_lock (omp_nest_lock_arg (lock));
+  gomp_unset_lock_30 (omp_lock_arg (lock));
 }
 
 void
-omp_unset_lock_ (omp_lock_arg_t lock)
+gomp_unset_nest_lock__30 (omp_nest_lock_arg_t lock)
+{
+  gomp_unset_nest_lock_30 (omp_nest_lock_arg (lock));
+}
+
+int32_t
+gomp_test_lock__30 (omp_lock_arg_t lock)
+{
+  return gomp_test_lock_30 (omp_lock_arg (lock));
+}
+
+int32_t
+gomp_test_nest_lock__30 (omp_nest_lock_arg_t lock)
 {
-  omp_unset_lock (omp_lock_arg (lock));
+  return gomp_test_nest_lock_30 (omp_nest_lock_arg (lock));
 }
 
+#ifdef LIBGOMP_GNU_SYMBOL_VERSIONING
 void
-omp_unset_nest_lock_ (omp_nest_lock_arg_t lock)
+gomp_init_lock__25 (omp_lock_25_arg_t lock)
 {
-  omp_unset_nest_lock (omp_nest_lock_arg (lock));
+#ifndef OMP_LOCK_25_DIRECT
+  omp_lock_25_arg (lock) = malloc (sizeof (omp_lock_25_t));
+#endif
+  gomp_init_lock_25 (omp_lock_25_arg (lock));
+}
+
+void
+gomp_init_nest_lock__25 (omp_nest_lock_25_arg_t lock)
+{
+#ifndef OMP_NEST_LOCK_25_DIRECT
+  omp_nest_lock_25_arg (lock) = malloc (sizeof (omp_nest_lock_25_t));
+#endif
+  gomp_init_nest_lock_25 (omp_nest_lock_25_arg (lock));
+}
+
+void
+gomp_destroy_lock__25 (omp_lock_25_arg_t lock)
+{
+  gomp_destroy_lock_25 (omp_lock_25_arg (lock));
+#ifndef OMP_LOCK_25_DIRECT
+  free (omp_lock_25_arg (lock));
+  omp_lock_25_arg (lock) = NULL;
+#endif
+}
+
+void
+gomp_destroy_nest_lock__25 (omp_nest_lock_25_arg_t lock)
+{
+  gomp_destroy_nest_lock_25 (omp_nest_lock_25_arg (lock));
+#ifndef OMP_NEST_LOCK_25_DIRECT
+  free (omp_nest_lock_25_arg (lock));
+  omp_nest_lock_25_arg (lock) = NULL;
+#endif
 }
 
+void
+gomp_set_lock__25 (omp_lock_25_arg_t lock)
+{
+  gomp_set_lock_25 (omp_lock_25_arg (lock));
+}
+
+void
+gomp_set_nest_lock__25 (omp_nest_lock_25_arg_t lock)
+{
+  gomp_set_nest_lock_25 (omp_nest_lock_25_arg (lock));
+}
+
+void
+gomp_unset_lock__25 (omp_lock_25_arg_t lock)
+{
+  gomp_unset_lock_25 (omp_lock_25_arg (lock));
+}
+
+void
+gomp_unset_nest_lock__25 (omp_nest_lock_25_arg_t lock)
+{
+  gomp_unset_nest_lock_25 (omp_nest_lock_25_arg (lock));
+}
+
+int32_t
+gomp_test_lock__25 (omp_lock_25_arg_t lock)
+{
+  return gomp_test_lock_25 (omp_lock_25_arg (lock));
+}
+
+int32_t
+gomp_test_nest_lock__25 (omp_nest_lock_25_arg_t lock)
+{
+  return gomp_test_nest_lock_25 (omp_nest_lock_25_arg (lock));
+}
+
+omp_lock_symver (omp_init_lock_)
+omp_lock_symver (omp_destroy_lock_)
+omp_lock_symver (omp_set_lock_)
+omp_lock_symver (omp_unset_lock_)
+omp_lock_symver (omp_test_lock_)
+omp_lock_symver (omp_init_nest_lock_)
+omp_lock_symver (omp_destroy_nest_lock_)
+omp_lock_symver (omp_set_nest_lock_)
+omp_lock_symver (omp_unset_nest_lock_)
+omp_lock_symver (omp_test_nest_lock_)
+#endif
+
 void
 omp_set_dynamic_ (const int32_t *set)
 {
@@ -178,12 +301,6 @@ omp_in_parallel_ (void)
   return omp_in_parallel ();
 }
 
-int32_t
-omp_test_lock_ (omp_lock_arg_t lock)
-{
-  return omp_test_lock (omp_lock_arg (lock));
-}
-
 int32_t
 omp_get_max_threads_ (void)
 {
@@ -208,12 +325,6 @@ omp_get_thread_num_ (void)
   return omp_get_thread_num ();
 }
 
-int32_t
-omp_test_nest_lock_ (omp_nest_lock_arg_t lock)
-{
-  return omp_test_nest_lock (omp_nest_lock_arg (lock));
-}
-
 double
 omp_get_wtick_ (void)
 {
@@ -225,3 +336,95 @@ omp_get_wtime_ (void)
 {
   return omp_get_wtime ();
 }
+
+void
+omp_set_schedule_ (const int32_t *kind, const int32_t *modifier)
+{
+  omp_set_schedule (*kind, *modifier);
+}
+
+void
+omp_set_schedule_8_ (const int32_t *kind, const int64_t *modifier)
+{
+  omp_set_schedule (*kind, *modifier);
+}
+
+void
+omp_get_schedule_ (int32_t *kind, int32_t *modifier)
+{
+  omp_sched_t k;
+  int m;
+  omp_get_schedule (&k, &m);
+  *kind = k;
+  *modifier = m;
+}
+
+void
+omp_get_schedule_8_ (int32_t *kind, int64_t *modifier)
+{
+  omp_sched_t k;
+  int m;
+  omp_get_schedule (&k, &m);
+  *kind = k;
+  *modifier = m;
+}
+
+int32_t
+omp_get_thread_limit_ (void)
+{
+  return omp_get_thread_limit ();
+}
+
+void
+omp_set_max_active_levels_ (const int32_t *levels)
+{
+  omp_set_max_active_levels (*levels);
+}
+
+void
+omp_set_max_active_levels_8_ (const int64_t *levels)
+{
+  omp_set_max_active_levels (*levels);
+}
+
+int32_t
+omp_get_max_active_levels_ (void)
+{
+  return omp_get_max_active_levels ();
+}
+
+int32_t
+omp_get_level_ (void)
+{
+  return omp_get_level ();
+}
+
+int32_t
+omp_get_ancestor_thread_num_ (const int32_t *level)
+{
+  return omp_get_ancestor_thread_num (*level);
+}
+
+int32_t
+omp_get_ancestor_thread_num_8_ (const int64_t *level)
+{
+  return omp_get_ancestor_thread_num (*level);
+}
+
+int32_t
+omp_get_team_size_ (const int32_t *level)
+{
+  return omp_get_team_size (*level);
+}
+
+int32_t
+omp_get_team_size_8_ (const int64_t *level)
+{
+  return omp_get_team_size (*level);
+}
+
+int32_t
+omp_get_active_level_ (void)
+{
+  return omp_get_active_level ();
+}
index 2d5dd2edd5a74f97343981b3be8f5a07d4c9f225..f186058be463c51a67bac23fcb0695f8f73843ad 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2008 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
@@ -154,7 +154,7 @@ gomp_iter_dynamic_next_locked (long *pstart, long *pend)
   if (start == ws->end)
     return false;
 
-  chunk = ws->chunk_size * ws->incr;
+  chunk = ws->chunk_size;
   left = ws->end - start;
   if (ws->incr < 0)
     {
@@ -186,11 +186,38 @@ gomp_iter_dynamic_next (long *pstart, long *pend)
   struct gomp_work_share *ws = thr->ts.work_share;
   long start, end, nend, chunk, incr;
 
-  start = ws->next;
   end = ws->end;
   incr = ws->incr;
-  chunk = ws->chunk_size * incr;
+  chunk = ws->chunk_size;
+
+  if (__builtin_expect (ws->mode, 1))
+    {
+      long tmp = __sync_fetch_and_add (&ws->next, chunk);
+      if (incr > 0)
+       {
+         if (tmp >= end)
+           return false;
+         nend = tmp + chunk;
+         if (nend > end)
+           nend = end;
+         *pstart = tmp;
+         *pend = nend;
+         return true;
+       }
+      else
+       {
+         if (tmp <= end)
+           return false;
+         nend = tmp + chunk;
+         if (nend < end)
+           nend = end;
+         *pstart = tmp;
+         *pend = nend;
+         return true;
+       }
+    }
 
+  start = ws->next;
   while (1)
     {
       long left = end - start;
diff --git a/libgomp/iter_ull.c b/libgomp/iter_ull.c
new file mode 100644 (file)
index 0000000..d6262da
--- /dev/null
@@ -0,0 +1,344 @@
+/* Copyright (C) 2005, 2008 Free Software Foundation, Inc.
+   Contributed by Richard Henderson <rth@redhat.com>.
+
+   This file is part of the GNU OpenMP Library (libgomp).
+
+   Libgomp is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 2.1 of the License, or
+   (at your option) any later version.
+
+   Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+   FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+   more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with libgomp; see the file COPYING.LIB.  If not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+/* As a special exception, if you link this library with other files, some
+   of which are compiled with GCC, to produce an executable, this library
+   does not by itself cause the resulting executable to be covered by the
+   GNU General Public License.  This exception does not however invalidate
+   any other reasons why the executable file might be covered by the GNU
+   General Public License.  */
+
+/* This file contains routines for managing work-share iteration, both
+   for loops and sections.  */
+
+#include "libgomp.h"
+#include <stdlib.h>
+
+typedef unsigned long long gomp_ull;
+
+/* This function implements the STATIC scheduling method.  The caller should
+   iterate *pstart <= x < *pend.  Return zero if there are more iterations
+   to perform; nonzero if not.  Return less than 0 if this thread had
+   received the absolutely last iteration.  */
+
+int
+gomp_iter_ull_static_next (gomp_ull *pstart, gomp_ull *pend)
+{
+  struct gomp_thread *thr = gomp_thread ();
+  struct gomp_team *team = thr->ts.team;
+  struct gomp_work_share *ws = thr->ts.work_share;
+  unsigned long nthreads = team ? team->nthreads : 1;
+
+  if (thr->ts.static_trip == -1)
+    return -1;
+
+  /* Quick test for degenerate teams and orphaned constructs.  */
+  if (nthreads == 1)
+    {
+      *pstart = ws->next_ull;
+      *pend = ws->end_ull;
+      thr->ts.static_trip = -1;
+      return ws->next_ull == ws->end_ull;
+    }
+
+  /* We interpret chunk_size zero as "unspecified", which means that we
+     should break up the iterations such that each thread makes only one
+     trip through the outer loop.  */
+  if (ws->chunk_size_ull == 0)
+    {
+      gomp_ull n, q, i, s0, e0, s, e;
+
+      if (thr->ts.static_trip > 0)
+       return 1;
+
+      /* Compute the total number of iterations.  */
+      if (__builtin_expect (ws->mode, 0) == 0)
+       n = (ws->end_ull - ws->next_ull + ws->incr_ull - 1) / ws->incr_ull;
+      else
+       n = (ws->next_ull - ws->end_ull - ws->incr_ull - 1) / -ws->incr_ull;
+      i = thr->ts.team_id;
+
+      /* Compute the "zero-based" start and end points.  That is, as
+        if the loop began at zero and incremented by one.  */
+      q = n / nthreads;
+      q += (q * nthreads != n);
+      s0 = q * i;
+      e0 = s0 + q;
+      if (e0 > n)
+       e0 = n;
+
+      /* Notice when no iterations allocated for this thread.  */
+      if (s0 >= e0)
+       {
+         thr->ts.static_trip = 1;
+         return 1;
+       }
+
+      /* Transform these to the actual start and end numbers.  */
+      s = s0 * ws->incr_ull + ws->next_ull;
+      e = e0 * ws->incr_ull + ws->next_ull;
+
+      *pstart = s;
+      *pend = e;
+      thr->ts.static_trip = (e0 == n ? -1 : 1);
+      return 0;
+    }
+  else
+    {
+      gomp_ull n, s0, e0, i, c, s, e;
+
+      /* Otherwise, each thread gets exactly chunk_size iterations
+        (if available) each time through the loop.  */
+
+      if (__builtin_expect (ws->mode, 0) == 0)
+       n = (ws->end_ull - ws->next_ull + ws->incr_ull - 1) / ws->incr_ull;
+      else
+       n = (ws->next_ull - ws->end_ull - ws->incr_ull - 1) / -ws->incr_ull;
+      i = thr->ts.team_id;
+      c = ws->chunk_size_ull;
+
+      /* Initial guess is a C sized chunk positioned nthreads iterations
+        in, offset by our thread number.  */
+      s0 = (thr->ts.static_trip * (gomp_ull) nthreads + i) * c;
+      e0 = s0 + c;
+
+      /* Detect overflow.  */
+      if (s0 >= n)
+       return 1;
+      if (e0 > n)
+       e0 = n;
+
+      /* Transform these to the actual start and end numbers.  */
+      s = s0 * ws->incr_ull + ws->next_ull;
+      e = e0 * ws->incr_ull + ws->next_ull;
+
+      *pstart = s;
+      *pend = e;
+
+      if (e0 == n)
+       thr->ts.static_trip = -1;
+      else
+       thr->ts.static_trip++;
+      return 0;
+    }
+}
+
+
+/* This function implements the DYNAMIC scheduling method.  Arguments are
+   as for gomp_iter_ull_static_next.  This function must be called with
+   ws->lock held.  */
+
+bool
+gomp_iter_ull_dynamic_next_locked (gomp_ull *pstart, gomp_ull *pend)
+{
+  struct gomp_thread *thr = gomp_thread ();
+  struct gomp_work_share *ws = thr->ts.work_share;
+  gomp_ull start, end, chunk, left;
+
+  start = ws->next_ull;
+  if (start == ws->end_ull)
+    return false;
+
+  chunk = ws->chunk_size_ull;
+  left = ws->end_ull - start;
+  if (__builtin_expect (ws->mode & 2, 0))
+    {
+      if (chunk < left)
+       chunk = left;
+    }
+  else
+    {
+      if (chunk > left)
+       chunk = left;
+    }
+  end = start + chunk;
+
+  ws->next_ull = end;
+  *pstart = start;
+  *pend = end;
+  return true;
+}
+
+
+#if defined HAVE_SYNC_BUILTINS && defined __LP64__
+/* Similar, but doesn't require the lock held, and uses compare-and-swap
+   instead.  Note that the only memory value that changes is ws->next_ull.  */
+
+bool
+gomp_iter_ull_dynamic_next (gomp_ull *pstart, gomp_ull *pend)
+{
+  struct gomp_thread *thr = gomp_thread ();
+  struct gomp_work_share *ws = thr->ts.work_share;
+  gomp_ull start, end, nend, chunk;
+
+  end = ws->end_ull;
+  chunk = ws->chunk_size_ull;
+
+  if (__builtin_expect (ws->mode & 1, 1))
+    {
+      gomp_ull tmp = __sync_fetch_and_add (&ws->next_ull, chunk);
+      if (__builtin_expect (ws->mode & 2, 0) == 0)
+       {
+         if (tmp >= end)
+           return false;
+         nend = tmp + chunk;
+         if (nend > end)
+           nend = end;
+         *pstart = tmp;
+         *pend = nend;
+         return true;
+       }
+      else
+       {
+         if (tmp <= end)
+           return false;
+         nend = tmp + chunk;
+         if (nend < end)
+           nend = end;
+         *pstart = tmp;
+         *pend = nend;
+         return true;
+       }
+    }
+
+  start = ws->next_ull;
+  while (1)
+    {
+      gomp_ull left = end - start;
+      gomp_ull tmp;
+
+      if (start == end)
+       return false;
+
+      if (__builtin_expect (ws->mode & 2, 0))
+       {
+         if (chunk < left)
+           chunk = left;
+       }
+      else
+       {
+         if (chunk > left)
+           chunk = left;
+       }
+      nend = start + chunk;
+
+      tmp = __sync_val_compare_and_swap (&ws->next_ull, start, nend);
+      if (__builtin_expect (tmp == start, 1))
+       break;
+
+      start = tmp;
+    }
+
+  *pstart = start;
+  *pend = nend;
+  return true;
+}
+#endif /* HAVE_SYNC_BUILTINS */
+
+
+/* This function implements the GUIDED scheduling method.  Arguments are
+   as for gomp_iter_ull_static_next.  This function must be called with the
+   work share lock held.  */
+
+bool
+gomp_iter_ull_guided_next_locked (gomp_ull *pstart, gomp_ull *pend)
+{
+  struct gomp_thread *thr = gomp_thread ();
+  struct gomp_work_share *ws = thr->ts.work_share;
+  struct gomp_team *team = thr->ts.team;
+  gomp_ull nthreads = team ? team->nthreads : 1;
+  gomp_ull n, q;
+  gomp_ull start, end;
+
+  if (ws->next_ull == ws->end_ull)
+    return false;
+
+  start = ws->next_ull;
+  if (__builtin_expect (ws->mode, 0) == 0)
+    n = (ws->end_ull - start) / ws->incr_ull;
+  else
+    n = (start - ws->end_ull) / -ws->incr_ull;
+  q = (n + nthreads - 1) / nthreads;
+
+  if (q < ws->chunk_size_ull)
+    q = ws->chunk_size_ull;
+  if (q <= n)
+    end = start + q * ws->incr_ull;
+  else
+    end = ws->end_ull;
+
+  ws->next_ull = end;
+  *pstart = start;
+  *pend = end;
+  return true;
+}
+
+#if defined HAVE_SYNC_BUILTINS && defined __LP64__
+/* Similar, but doesn't require the lock held, and uses compare-and-swap
+   instead.  Note that the only memory value that changes is ws->next_ull.  */
+
+bool
+gomp_iter_ull_guided_next (gomp_ull *pstart, gomp_ull *pend)
+{
+  struct gomp_thread *thr = gomp_thread ();
+  struct gomp_work_share *ws = thr->ts.work_share;
+  struct gomp_team *team = thr->ts.team;
+  gomp_ull nthreads = team ? team->nthreads : 1;
+  gomp_ull start, end, nend, incr;
+  gomp_ull chunk_size;
+
+  start = ws->next_ull;
+  end = ws->end_ull;
+  incr = ws->incr_ull;
+  chunk_size = ws->chunk_size_ull;
+
+  while (1)
+    {
+      gomp_ull n, q;
+      gomp_ull tmp;
+
+      if (start == end)
+       return false;
+
+      if (__builtin_expect (ws->mode, 0) == 0)
+       n = (end - start) / incr;
+      else
+       n = (start - end) / -incr;
+      q = (n + nthreads - 1) / nthreads;
+
+      if (q < chunk_size)
+       q = chunk_size;
+      if (__builtin_expect (q <= n, 1))
+       nend = start + q * incr;
+      else
+       nend = end;
+
+      tmp = __sync_val_compare_and_swap (&ws->next_ull, start, nend);
+      if (__builtin_expect (tmp == start, 1))
+       break;
+
+      start = tmp;
+    }
+
+  *pstart = start;
+  *pend = nend;
+  return true;
+}
+#endif /* HAVE_SYNC_BUILTINS */
index 7075250a87fc0986c831eb78124ab318a2786268..66180122c1e81ae3b22fdfa1d7d60d1f1ae2f84f 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005, 2007 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2007, 2008 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
@@ -50,6 +50,7 @@
 #include "sem.h"
 #include "mutex.h"
 #include "bar.h"
+#include "ptrlock.h"
 
 
 /* This structure contains the data to control one work-sharing construct,
 
 enum gomp_schedule_type
 {
+  GFS_RUNTIME,
   GFS_STATIC,
   GFS_DYNAMIC,
   GFS_GUIDED,
-  GFS_RUNTIME
+  GFS_AUTO
 };
 
 struct gomp_work_share
@@ -70,56 +72,94 @@ struct gomp_work_share
      If this is a SECTIONS construct, this value will always be DYNAMIC.  */
   enum gomp_schedule_type sched;
 
-  /* This is the chunk_size argument to the SCHEDULE clause.  */
-  long chunk_size;
+  int mode;
 
-  /* This is the iteration end point.  If this is a SECTIONS construct, 
-     this is the number of contained sections.  */
-  long end;
+  union {
+    struct {
+      /* This is the chunk_size argument to the SCHEDULE clause.  */
+      long chunk_size;
+
+      /* This is the iteration end point.  If this is a SECTIONS construct,
+        this is the number of contained sections.  */
+      long end;
+
+      /* This is the iteration step.  If this is a SECTIONS construct, this
+        is always 1.  */
+      long incr;
+    };
+
+    struct {
+      /* The same as above, but for the unsigned long long loop variants.  */
+      unsigned long long chunk_size_ull;
+      unsigned long long end_ull;
+      unsigned long long incr_ull;
+    };
+  };
+
+  /* This is a circular queue that details which threads will be allowed
+     into the ordered region and in which order.  When a thread allocates
+     iterations on which it is going to work, it also registers itself at
+     the end of the array.  When a thread reaches the ordered region, it
+     checks to see if it is the one at the head of the queue.  If not, it
+     blocks on its RELEASE semaphore.  */
+  unsigned *ordered_team_ids;
+
+  /* This is the number of threads that have registered themselves in
+     the circular queue ordered_team_ids.  */
+  unsigned ordered_num_used;
+
+  /* This is the team_id of the currently acknowledged owner of the ordered
+     section, or -1u if the ordered section has not been acknowledged by
+     any thread.  This is distinguished from the thread that is *allowed*
+     to take the section next.  */
+  unsigned ordered_owner;
+
+  /* This is the index into the circular queue ordered_team_ids of the
+     current thread that's allowed into the ordered reason.  */
+  unsigned ordered_cur;
 
-  /* This is the iteration step.  If this is a SECTIONS construct, this
-     is always 1.  */
-  long incr;
+  /* This is a chain of allocated gomp_work_share blocks, valid only
+     in the first gomp_work_share struct in the block.  */
+  struct gomp_work_share *next_alloc;
+
+  /* The above fields are written once during workshare initialization,
+     or related to ordered worksharing.  Make sure the following fields
+     are in a different cache line.  */
 
   /* This lock protects the update of the following members.  */
-  gomp_mutex_t lock;
+  gomp_mutex_t lock __attribute__((aligned (64)));
+
+  /* This is the count of the number of threads that have exited the work
+     share construct.  If the construct was marked nowait, they have moved on
+     to other work; otherwise they're blocked on a barrier.  The last member
+     of the team to exit the work share construct must deallocate it.  */
+  unsigned threads_completed;
 
   union {
     /* This is the next iteration value to be allocated.  In the case of
        GFS_STATIC loops, this the iteration start point and never changes.  */
     long next;
 
+    /* The same, but with unsigned long long type.  */
+    unsigned long long next_ull;
+
     /* This is the returned data structure for SINGLE COPYPRIVATE.  */
     void *copyprivate;
   };
 
-  /* This is the count of the number of threads that have exited the work
-     share construct.  If the construct was marked nowait, they have moved on
-     to other work; otherwise they're blocked on a barrier.  The last member
-     of the team to exit the work share construct must deallocate it.  */
-  unsigned threads_completed;
-
-  /* This is the index into the circular queue ordered_team_ids of the 
-     current thread that's allowed into the ordered reason.  */
-  unsigned ordered_cur;
-
-  /* This is the number of threads that have registered themselves in
-     the circular queue ordered_team_ids.  */
-  unsigned ordered_num_used;
+  union {
+    /* Link to gomp_work_share struct for next work sharing construct
+       encountered after this one.  */
+    gomp_ptrlock_t next_ws;
 
-  /* This is the team_id of the currently acknoledged owner of the ordered
-     section, or -1u if the ordered section has not been acknowledged by
-     any thread.  This is distinguished from the thread that is *allowed*
-     to take the section next.  */
-  unsigned ordered_owner;
+    /* gomp_work_share structs are chained in the free work share cache
+       through this.  */
+    struct gomp_work_share *next_free;
+  };
 
-  /* This is a circular queue that details which threads will be allowed
-     into the ordered region and in which order.  When a thread allocates
-     iterations on which it is going to work, it also registers itself at
-     the end of the array.  When a thread reaches the ordered region, it
-     checks to see if it is the one at the head of the queue.  If not, it
-     blocks on its RELEASE semaphore.  */
-  unsigned ordered_team_ids[];
+  /* If only few threads are in the team, ordered_team_ids can point
+     to this array which fills the padding at the end of this struct.  */
+  unsigned inline_ordered_team_ids[0];
 };
 
 /* This structure contains all of the thread-local data associated with 
@@ -133,21 +173,30 @@ struct gomp_team_state
 
   /* This is the work share construct which this thread is currently
      processing.  Recall that with NOWAIT, not all threads may be 
-     processing the same construct.  This value is NULL when there
-     is no construct being processed.  */
+     processing the same construct.  */
   struct gomp_work_share *work_share;
 
+  /* This is the previous work share construct or NULL if there wasn't any.
+     When all threads are done with the current work sharing construct,
+     the previous one can be freed.  The current one can't, as its
+     next_ws field is used.  */
+  struct gomp_work_share *last_work_share;
+
   /* This is the ID of this thread within the team.  This value is
      guaranteed to be between 0 and N-1, where N is the number of
      threads in the team.  */
   unsigned team_id;
 
-  /* The work share "generation" is a number that increases by one for
-     each work share construct encountered in the dynamic flow of the
-     program.  It is used to find the control data for the work share
-     when encountering it for the first time.  This particular number
-     reflects the generation of the work_share member of this struct.  */
-  unsigned work_share_generation;
+  /* Nesting level.  */
+  unsigned level;
+
+  /* Active nesting level.  Only active parallel regions are counted.  */
+  unsigned active_level;
+
+#ifdef HAVE_SYNC_BUILTINS
+  /* Number of single stmts encountered.  */
+  unsigned long single_count;
+#endif
 
   /* For GFS_RUNTIME loops that resolved to GFS_STATIC, this is the
      trip number through the loop.  So first time a particular loop
@@ -157,48 +206,118 @@ struct gomp_team_state
   unsigned long static_trip;
 };
 
-/* This structure describes a "team" of threads.  These are the threads
-   that are spawned by a PARALLEL constructs, as well as the work sharing
-   constructs that the team encounters.  */
+/* These are the OpenMP 3.0 Internal Control Variables described in
+   section 2.3.1.  Those described as having one copy per task are
+   stored within the structure; those described as having one copy
+   for the whole program are (naturally) global variables.  */
 
-struct gomp_team
+struct gomp_task_icv
 {
-  /* This lock protects access to the following work shares data structures.  */
-  gomp_mutex_t work_share_lock;
+  unsigned long nthreads_var;
+  enum gomp_schedule_type run_sched_var;
+  int run_sched_modifier;
+  bool dyn_var;
+  bool nest_var;
+};
 
-  /* This is a dynamically sized array containing pointers to the control
-     structs for all "live" work share constructs.  Here "live" means that
-     the construct has been encountered by at least one thread, and not
-     completed by all threads.  */
-  struct gomp_work_share **work_shares;
+extern struct gomp_task_icv gomp_global_icv;
+extern unsigned long gomp_thread_limit_var;
+extern unsigned long gomp_remaining_threads_count;
+#ifndef HAVE_SYNC_BUILTINS
+extern gomp_mutex_t gomp_remaining_threads_lock;
+#endif
+extern unsigned long gomp_max_active_levels_var;
+extern unsigned long long gomp_spin_count_var, gomp_throttled_spin_count_var;
+extern unsigned long gomp_available_cpus, gomp_managed_threads;
 
-  /* The work_shares array is indexed by "generation & generation_mask".
-     The mask will be 2**N - 1, where 2**N is the size of the array.  */
-  unsigned generation_mask;
+enum gomp_task_kind
+{
+  GOMP_TASK_IMPLICIT,
+  GOMP_TASK_IFFALSE,
+  GOMP_TASK_WAITING,
+  GOMP_TASK_TIED
+};
 
-  /* These two values define the bounds of the elements of the work_shares
-     array that are currently in use.  */
-  unsigned oldest_live_gen;
-  unsigned num_live_gen;
+/* This structure describes a "task" to be run by a thread.  */
 
+struct gomp_task
+{
+  struct gomp_task *parent;
+  struct gomp_task *children;
+  struct gomp_task *next_child;
+  struct gomp_task *prev_child;
+  struct gomp_task *next_queue;
+  struct gomp_task *prev_queue;
+  struct gomp_task_icv icv;
+  void (*fn) (void *);
+  void *fn_data;
+  enum gomp_task_kind kind;
+  bool in_taskwait;
+  gomp_sem_t taskwait_sem;
+};
+
+/* This structure describes a "team" of threads.  These are the threads
+   that are spawned by a PARALLEL constructs, as well as the work sharing
+   constructs that the team encounters.  */
+
+struct gomp_team
+{
   /* This is the number of threads in the current team.  */
   unsigned nthreads;
 
+  /* This is number of gomp_work_share structs that have been allocated
+     as a block last time.  */
+  unsigned work_share_chunk;
+
   /* This is the saved team state that applied to a master thread before
      the current thread was created.  */
   struct gomp_team_state prev_ts;
 
-  /* This barrier is used for most synchronization of the team.  */
-  gomp_barrier_t barrier;
-
   /* This semaphore should be used by the master thread instead of its
      "native" semaphore in the thread structure.  Required for nested
      parallels, as the master is a member of two teams.  */
   gomp_sem_t master_release;
 
-  /* This array contains pointers to the release semaphore of the threads
-     in the team.  */
-  gomp_sem_t *ordered_release[];
+  /* This points to an array with pointers to the release semaphore
+     of the threads in the team.  */
+  gomp_sem_t **ordered_release;
+
+  /* List of gomp_work_share structs chained through next_free fields.
+     This is populated and taken off only by the first thread in the
+     team encountering a new work sharing construct, in a critical
+     section.  */
+  struct gomp_work_share *work_share_list_alloc;
+
+  /* List of gomp_work_share structs freed by free_work_share.  New
+     entries are atomically added to the start of the list, and
+     alloc_work_share can safely only move all but the first entry
+     to work_share_list alloc, as free_work_share can happen concurrently
+     with alloc_work_share.  */
+  struct gomp_work_share *work_share_list_free;
+
+#ifdef HAVE_SYNC_BUILTINS
+  /* Number of simple single regions encountered by threads in this
+     team.  */
+  unsigned long single_count;
+#else
+  /* Mutex protecting addition of workshares to work_share_list_free.  */
+  gomp_mutex_t work_share_list_free_lock;
+#endif
+
+  /* This barrier is used for most synchronization of the team.  */
+  gomp_barrier_t barrier;
+
+  /* Initial work shares, to avoid allocating any gomp_work_share
+     structs in the common case.  */
+  struct gomp_work_share work_shares[8];
+
+  gomp_mutex_t task_lock;
+  struct gomp_task *task_queue;
+  int task_count;
+  int task_running_count;
+
+  /* This array contains structures for implicit tasks.  */
+  struct gomp_task implicit_task[];
 };
 
 /* This structure contains all data that is private to libgomp and is
@@ -214,8 +333,28 @@ struct gomp_thread
      is NULL only if the thread is idle.  */
   struct gomp_team_state ts;
 
+  /* This is the task that the thread is currently executing.  */
+  struct gomp_task *task;
+
   /* This semaphore is used for ordered loops.  */
   gomp_sem_t release;
+
+  /* user pthread thread pool */
+  struct gomp_thread_pool *thread_pool;
+};
+
+
+struct gomp_thread_pool
+{
+  /* This array manages threads spawned from the top level, which will
+     return to the idle loop once the current PARALLEL construct ends.  */
+  struct gomp_thread **threads;
+  unsigned threads_size;
+  unsigned threads_used;
+  struct gomp_team *last_team;
+
+  /* This barrier holds and releases threads waiting in threads.  */
+  gomp_barrier_t threads_dock;
 };
 
 /* ... and here is that TLS data.  */
@@ -234,14 +373,20 @@ static inline struct gomp_thread *gomp_thread (void)
 }
 #endif
 
-/* These are the OpenMP 2.5 internal control variables described in
-   section 2.3.  At least those that correspond to environment variables.  */
+extern struct gomp_task_icv *gomp_new_icv (void);
+
+/* Here's how to access the current copy of the ICVs.  */
 
-extern unsigned long gomp_nthreads_var;
-extern bool gomp_dyn_var;
-extern bool gomp_nest_var;
-extern enum gomp_schedule_type gomp_run_sched_var;
-extern unsigned long gomp_run_sched_chunk;
+static inline struct gomp_task_icv *gomp_icv (bool write)
+{
+  struct gomp_task *task = gomp_thread ()->task;
+  if (task)
+    return &task->icv;
+  else if (write)
+    return gomp_new_icv ();
+  else
+    return &gomp_global_icv;
+}
 
 /* The attributes to be used during thread creation.  */
 extern pthread_attr_t gomp_thread_attr;
@@ -286,6 +431,22 @@ extern bool gomp_iter_dynamic_next (long *, long *);
 extern bool gomp_iter_guided_next (long *, long *);
 #endif
 
+/* iter_ull.c */
+
+extern int gomp_iter_ull_static_next (unsigned long long *,
+                                     unsigned long long *);
+extern bool gomp_iter_ull_dynamic_next_locked (unsigned long long *,
+                                              unsigned long long *);
+extern bool gomp_iter_ull_guided_next_locked (unsigned long long *,
+                                             unsigned long long *);
+
+#if defined HAVE_SYNC_BUILTINS && defined __LP64__
+extern bool gomp_iter_ull_dynamic_next (unsigned long long *,
+                                       unsigned long long *);
+extern bool gomp_iter_ull_guided_next (unsigned long long *,
+                                      unsigned long long *);
+#endif
+
 /* ordered.c */
 
 extern void gomp_ordered_first (void);
@@ -297,26 +458,49 @@ extern void gomp_ordered_sync (void);
 
 /* parallel.c */
 
-extern unsigned gomp_resolve_num_threads (unsigned);
+extern unsigned gomp_resolve_num_threads (unsigned, unsigned);
 
 /* proc.c (in config/) */
 
 extern void gomp_init_num_threads (void);
 extern unsigned gomp_dynamic_max_threads (void);
 
+/* task.c */
+
+extern void gomp_init_task (struct gomp_task *, struct gomp_task *,
+                           struct gomp_task_icv *);
+extern void gomp_end_task (void);
+extern void gomp_barrier_handle_tasks (gomp_barrier_state_t);
+
+static void inline
+gomp_finish_task (struct gomp_task *task)
+{
+  gomp_sem_destroy (&task->taskwait_sem);
+}
+
 /* team.c */
 
+extern struct gomp_team *gomp_new_team (unsigned);
 extern void gomp_team_start (void (*) (void *), void *, unsigned,
-                            struct gomp_work_share *);
+                            struct gomp_team *);
 extern void gomp_team_end (void);
 
 /* work.c */
 
-extern struct gomp_work_share * gomp_new_work_share (bool, unsigned);
+extern void gomp_init_work_share (struct gomp_work_share *, bool, unsigned);
+extern void gomp_fini_work_share (struct gomp_work_share *);
 extern bool gomp_work_share_start (bool);
 extern void gomp_work_share_end (void);
 extern void gomp_work_share_end_nowait (void);
 
+static inline void
+gomp_work_share_init_done (void)
+{
+  struct gomp_thread *thr = gomp_thread ();
+  if (__builtin_expect (thr->ts.last_work_share != NULL, 1))
+    gomp_ptrlock_set (&thr->ts.last_work_share->next_ws, thr->ts.work_share);
+}
+
 #ifdef HAVE_ATTRIBUTE_VISIBILITY
 # pragma GCC visibility pop
 #endif
@@ -329,6 +513,53 @@ extern void gomp_work_share_end_nowait (void);
 #define _LIBGOMP_OMP_LOCK_DEFINED 1
 #include "omp.h.in"
 
+#if !defined (HAVE_ATTRIBUTE_VISIBILITY) \
+    || !defined (HAVE_ATTRIBUTE_ALIAS) \
+    || !defined (PIC)
+# undef LIBGOMP_GNU_SYMBOL_VERSIONING
+#endif
+
+#ifdef LIBGOMP_GNU_SYMBOL_VERSIONING
+extern void gomp_init_lock_30 (omp_lock_t *) __GOMP_NOTHROW;
+extern void gomp_destroy_lock_30 (omp_lock_t *) __GOMP_NOTHROW;
+extern void gomp_set_lock_30 (omp_lock_t *) __GOMP_NOTHROW;
+extern void gomp_unset_lock_30 (omp_lock_t *) __GOMP_NOTHROW;
+extern int gomp_test_lock_30 (omp_lock_t *) __GOMP_NOTHROW;
+extern void gomp_init_nest_lock_30 (omp_nest_lock_t *) __GOMP_NOTHROW;
+extern void gomp_destroy_nest_lock_30 (omp_nest_lock_t *) __GOMP_NOTHROW;
+extern void gomp_set_nest_lock_30 (omp_nest_lock_t *) __GOMP_NOTHROW;
+extern void gomp_unset_nest_lock_30 (omp_nest_lock_t *) __GOMP_NOTHROW;
+extern int gomp_test_nest_lock_30 (omp_nest_lock_t *) __GOMP_NOTHROW;
+
+extern void gomp_init_lock_25 (omp_lock_25_t *) __GOMP_NOTHROW;
+extern void gomp_destroy_lock_25 (omp_lock_25_t *) __GOMP_NOTHROW;
+extern void gomp_set_lock_25 (omp_lock_25_t *) __GOMP_NOTHROW;
+extern void gomp_unset_lock_25 (omp_lock_25_t *) __GOMP_NOTHROW;
+extern int gomp_test_lock_25 (omp_lock_25_t *) __GOMP_NOTHROW;
+extern void gomp_init_nest_lock_25 (omp_nest_lock_25_t *) __GOMP_NOTHROW;
+extern void gomp_destroy_nest_lock_25 (omp_nest_lock_25_t *) __GOMP_NOTHROW;
+extern void gomp_set_nest_lock_25 (omp_nest_lock_25_t *) __GOMP_NOTHROW;
+extern void gomp_unset_nest_lock_25 (omp_nest_lock_25_t *) __GOMP_NOTHROW;
+extern int gomp_test_nest_lock_25 (omp_nest_lock_25_t *) __GOMP_NOTHROW;
+
+# define strong_alias(fn, al) \
+  extern __typeof (fn) al __attribute__ ((alias (#fn)));
+# define omp_lock_symver(fn) \
+  __asm (".symver g" #fn "_30, " #fn "@@OMP_3.0"); \
+  __asm (".symver g" #fn "_25, " #fn "@OMP_1.0");
+#else
+# define gomp_init_lock_30 omp_init_lock
+# define gomp_destroy_lock_30 omp_destroy_lock
+# define gomp_set_lock_30 omp_set_lock
+# define gomp_unset_lock_30 omp_unset_lock
+# define gomp_test_lock_30 omp_test_lock
+# define gomp_init_nest_lock_30 omp_init_nest_lock
+# define gomp_destroy_nest_lock_30 omp_destroy_nest_lock
+# define gomp_set_nest_lock_30 omp_set_nest_lock
+# define gomp_unset_nest_lock_30 omp_unset_nest_lock
+# define gomp_test_nest_lock_30 omp_test_nest_lock
+#endif
+
 #ifdef HAVE_ATTRIBUTE_VISIBILITY
 # define attribute_hidden __attribute__ ((visibility ("hidden")))
 #else
index 9e13ef8116cf090e1c89a91220850097970e6062..e6c12fa001906074fd6102eb492ca0e573bb93ae 100644 (file)
@@ -55,6 +55,53 @@ OMP_2.0 {
        omp_get_wtime_;
 } OMP_1.0;
 
+OMP_3.0 {
+  global:
+       omp_set_schedule;
+       omp_set_schedule_;
+       omp_set_schedule_8_;
+       omp_get_schedule;
+       omp_get_schedule_;
+       omp_get_schedule_8_;
+       omp_get_thread_limit;
+       omp_get_thread_limit_;
+       omp_set_max_active_levels;
+       omp_set_max_active_levels_;
+       omp_set_max_active_levels_8_;
+       omp_get_max_active_levels;
+       omp_get_max_active_levels_;
+       omp_get_level;
+       omp_get_level_;
+       omp_get_ancestor_thread_num;
+       omp_get_ancestor_thread_num_;
+       omp_get_ancestor_thread_num_8_;
+       omp_get_team_size;
+       omp_get_team_size_;
+       omp_get_team_size_8_;
+       omp_get_active_level;
+       omp_get_active_level_;
+       omp_init_lock;
+       omp_init_nest_lock;
+       omp_destroy_lock;
+       omp_destroy_nest_lock;
+       omp_set_lock;
+       omp_set_nest_lock;
+       omp_unset_lock;
+       omp_unset_nest_lock;
+       omp_test_lock;
+       omp_test_nest_lock;
+       omp_destroy_lock_;
+       omp_destroy_nest_lock_;
+       omp_init_lock_;
+       omp_init_nest_lock_;
+       omp_set_lock_;
+       omp_set_nest_lock_;
+       omp_test_lock_;
+       omp_test_nest_lock_;
+       omp_unset_lock_;
+       omp_unset_nest_lock_;
+} OMP_2.0;
+
 GOMP_1.0 {
   global:
        GOMP_atomic_end;
@@ -70,16 +117,12 @@ GOMP_1.0 {
        GOMP_loop_end_nowait;
        GOMP_loop_guided_next;
        GOMP_loop_guided_start;
-       GOMP_loop_ordered_dynamic_first;
        GOMP_loop_ordered_dynamic_next;
        GOMP_loop_ordered_dynamic_start;
-       GOMP_loop_ordered_guided_first;
        GOMP_loop_ordered_guided_next;
        GOMP_loop_ordered_guided_start;
-       GOMP_loop_ordered_runtime_first;
        GOMP_loop_ordered_runtime_next;
        GOMP_loop_ordered_runtime_start;
-       GOMP_loop_ordered_static_first;
        GOMP_loop_ordered_static_next;
        GOMP_loop_ordered_static_start;
        GOMP_loop_runtime_next;
@@ -103,3 +146,25 @@ GOMP_1.0 {
        GOMP_single_copy_start;
        GOMP_single_start;
 };
+
+GOMP_2.0 {
+  global:
+       GOMP_task;
+       GOMP_taskwait;
+       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_1.0;
index 85543565a1e806542c61b49bded002302601f650..ecd92a8060e6dddeff526ae063afaf478c83710f 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2008 Free Software Foundation, Inc.
    Contributed by Jakub Jelinek <jakub@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
@@ -53,6 +53,26 @@ typedef union { omp_nest_lock_t *lock; uint64_t u; } *omp_nest_lock_arg_t;
 # define omp_nest_lock_arg(arg) ((arg)->lock)
 # endif
 
+#if (@OMP_LOCK_25_SIZE@ == @OMP_LOCK_25_KIND@) \
+    && (@OMP_LOCK_25_ALIGN@ <= @OMP_LOCK_25_SIZE@)
+# define OMP_LOCK_25_DIRECT
+typedef omp_lock_25_t *omp_lock_25_arg_t;
+# define omp_lock_25_arg(arg) (arg)
+#else
+typedef union { omp_lock_25_t *lock; uint64_t u; } *omp_lock_25_arg_t;
+# define omp_lock_25_arg(arg) ((arg)->lock)
+# endif
+
+#if (@OMP_NEST_LOCK_25_SIZE@ == @OMP_NEST_LOCK_25_KIND@) \
+    && (@OMP_NEST_LOCK_25_ALIGN@ <= @OMP_NEST_LOCK_25_SIZE@)
+# define OMP_NEST_LOCK_25_DIRECT
+typedef omp_nest_lock_25_t *omp_nest_lock_25_arg_t;
+# define omp_nest_lock_25_arg(arg) (arg)
+#else
+typedef union { omp_nest_lock_25_t *lock; uint64_t u; } *omp_nest_lock_25_arg_t;
+# define omp_nest_lock_25_arg(arg) ((arg)->lock)
+# endif
+
 static inline void
 omp_check_defines (void)
 {
@@ -63,6 +83,14 @@ omp_check_defines (void)
             || @OMP_LOCK_KIND@ != sizeof (*(omp_lock_arg_t) 0)
             || @OMP_NEST_LOCK_KIND@ != sizeof (*(omp_nest_lock_arg_t) 0))
            ? -1 : 1] __attribute__ ((__unused__));
+  char test2[(@OMP_LOCK_25_SIZE@ != sizeof (omp_lock_25_t)
+            || @OMP_LOCK_25_ALIGN@ != __alignof (omp_lock_25_t)
+            || @OMP_NEST_LOCK_25_SIZE@ != sizeof (omp_nest_lock_25_t)
+            || @OMP_NEST_LOCK_25_ALIGN@ != __alignof (omp_nest_lock_25_t)
+            || @OMP_LOCK_25_KIND@ != sizeof (*(omp_lock_25_arg_t) 0)
+            || @OMP_NEST_LOCK_25_KIND@
+               != sizeof (*(omp_nest_lock_25_arg_t) 0))
+           ? -1 : 1] __attribute__ ((__unused__));
 }
 
 #endif /* LIBGOMP_F_H */
index 52ecafdcf0fdcbe5201a272bb74907de9c234faa..322fd4f23d12e2b12ecff7460c97a8fb8da005e6 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2007, 2008 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
@@ -83,6 +83,74 @@ extern void GOMP_parallel_loop_runtime_start (void (*)(void *), void *,
 extern void GOMP_loop_end (void);
 extern void GOMP_loop_end_nowait (void);
 
+/* loop_ull.c */
+
+extern bool GOMP_loop_ull_static_start (bool, unsigned long long,
+                                       unsigned long long,
+                                       unsigned long long,
+                                       unsigned long long,
+                                       unsigned long long *,
+                                       unsigned long long *);
+extern bool GOMP_loop_ull_dynamic_start (bool, unsigned long long,
+                                        unsigned long long,
+                                        unsigned long long,
+                                        unsigned long long,
+                                        unsigned long long *,
+                                        unsigned long long *);
+extern bool GOMP_loop_ull_guided_start (bool, unsigned long long,
+                                       unsigned long long,
+                                       unsigned long long,
+                                       unsigned long long,
+                                       unsigned long long *,
+                                       unsigned long long *);
+extern bool GOMP_loop_ull_runtime_start (bool, unsigned long long,
+                                        unsigned long long,
+                                        unsigned long long,
+                                        unsigned long long *,
+                                        unsigned long long *);
+
+extern bool GOMP_loop_ull_ordered_static_start (bool, unsigned long long,
+                                               unsigned long long,
+                                               unsigned long long,
+                                               unsigned long long,
+                                               unsigned long long *,
+                                               unsigned long long *);
+extern bool GOMP_loop_ull_ordered_dynamic_start (bool, unsigned long long,
+                                                unsigned long long,
+                                                unsigned long long,
+                                                unsigned long long,
+                                                unsigned long long *,
+                                                unsigned long long *);
+extern bool GOMP_loop_ull_ordered_guided_start (bool, unsigned long long,
+                                               unsigned long long,
+                                               unsigned long long,
+                                               unsigned long long,
+                                               unsigned long long *,
+                                               unsigned long long *);
+extern bool GOMP_loop_ull_ordered_runtime_start (bool, unsigned long long,
+                                                unsigned long long,
+                                                unsigned long long,
+                                                unsigned long long *,
+                                                unsigned long long *);
+
+extern bool GOMP_loop_ull_static_next (unsigned long long *,
+                                      unsigned long long *);
+extern bool GOMP_loop_ull_dynamic_next (unsigned long long *,
+                                       unsigned long long *);
+extern bool GOMP_loop_ull_guided_next (unsigned long long *,
+                                      unsigned long long *);
+extern bool GOMP_loop_ull_runtime_next (unsigned long long *,
+                                       unsigned long long *);
+
+extern bool GOMP_loop_ull_ordered_static_next (unsigned long long *,
+                                              unsigned long long *);
+extern bool GOMP_loop_ull_ordered_dynamic_next (unsigned long long *,
+                                               unsigned long long *);
+extern bool GOMP_loop_ull_ordered_guided_next (unsigned long long *,
+                                              unsigned long long *);
+extern bool GOMP_loop_ull_ordered_runtime_next (unsigned long long *,
+                                               unsigned long long *);
+
 /* ordered.c */
 
 extern void GOMP_ordered_start (void);
@@ -93,6 +161,12 @@ extern void GOMP_ordered_end (void);
 extern void GOMP_parallel_start (void (*) (void *), void *, unsigned);
 extern void GOMP_parallel_end (void);
 
+/* team.c */
+
+extern void GOMP_task (void (*) (void *), void *, void (*) (void *, void *),
+                      long, long, bool, unsigned);
+extern void GOMP_taskwait (void);
+
 /* sections.c */
 
 extern unsigned GOMP_sections_start (unsigned);
index 58fd9a8af2837806b39b1d80cf5b0d8a4fdf1a27..1cea334bcbfca3a13c7194e5717add2014f93855 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2008 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
@@ -27,8 +27,9 @@
 
 /* This file handles the LOOP (FOR/DO) construct.  */
 
-#include "libgomp.h"
+#include <limits.h>
 #include <stdlib.h>
+#include "libgomp.h"
 
 
 /* Initialize the given work share construct from the given arguments.  */
@@ -44,6 +45,39 @@ gomp_loop_init (struct gomp_work_share *ws, long start, long end, long incr,
            ? start : end;
   ws->incr = incr;
   ws->next = start;
+  if (sched == GFS_DYNAMIC)
+    {
+      ws->chunk_size *= incr;
+
+#ifdef HAVE_SYNC_BUILTINS
+      {
+       /* For dynamic scheduling prepare things to make each iteration
+          faster.  */
+       struct gomp_thread *thr = gomp_thread ();
+       struct gomp_team *team = thr->ts.team;
+       long nthreads = team ? team->nthreads : 1;
+
+       if (__builtin_expect (incr > 0, 1))
+         {
+           /* Cheap overflow protection.  */
+           if (__builtin_expect ((nthreads | ws->chunk_size)
+                                 >= 1UL << (sizeof (long)
+                                            * __CHAR_BIT__ / 2 - 1), 0))
+             ws->mode = 0;
+           else
+             ws->mode = ws->end < (LONG_MAX
+                                   - (nthreads + 1) * ws->chunk_size);
+         }
+       /* Cheap overflow protection.  */
+       else if (__builtin_expect ((nthreads | -ws->chunk_size)
+                                  >= 1UL << (sizeof (long)
+                                             * __CHAR_BIT__ / 2 - 1), 0))
+         ws->mode = 0;
+       else
+         ws->mode = ws->end > (nthreads + 1) * -ws->chunk_size - LONG_MAX;
+      }
+#endif
+    }
 }
 
 /* The *_start routines are called when first encountering a loop construct
@@ -68,10 +102,13 @@ gomp_loop_static_start (long start, long end, long incr, long chunk_size,
 {
   struct gomp_thread *thr = gomp_thread ();
 
+  thr->ts.static_trip = 0;
   if (gomp_work_share_start (false))
-    gomp_loop_init (thr->ts.work_share, start, end, incr,
-                   GFS_STATIC, chunk_size);
-  gomp_mutex_unlock (&thr->ts.work_share->lock);
+    {
+      gomp_loop_init (thr->ts.work_share, start, end, incr,
+                     GFS_STATIC, chunk_size);
+      gomp_work_share_init_done ();
+    }
 
   return !gomp_iter_static_next (istart, iend);
 }
@@ -84,13 +121,16 @@ gomp_loop_dynamic_start (long start, long end, long incr, long chunk_size,
   bool ret;
 
   if (gomp_work_share_start (false))
-    gomp_loop_init (thr->ts.work_share, start, end, incr,
-                   GFS_DYNAMIC, chunk_size);
+    {
+      gomp_loop_init (thr->ts.work_share, start, end, incr,
+                     GFS_DYNAMIC, chunk_size);
+      gomp_work_share_init_done ();
+    }
 
 #ifdef HAVE_SYNC_BUILTINS
-  gomp_mutex_unlock (&thr->ts.work_share->lock);
   ret = gomp_iter_dynamic_next (istart, iend);
 #else
+  gomp_mutex_lock (&thr->ts.work_share->lock);
   ret = gomp_iter_dynamic_next_locked (istart, iend);
   gomp_mutex_unlock (&thr->ts.work_share->lock);
 #endif
@@ -106,13 +146,16 @@ gomp_loop_guided_start (long start, long end, long incr, long chunk_size,
   bool ret;
 
   if (gomp_work_share_start (false))
-    gomp_loop_init (thr->ts.work_share, start, end, incr,
-                   GFS_GUIDED, chunk_size);
+    {
+      gomp_loop_init (thr->ts.work_share, start, end, incr,
+                     GFS_GUIDED, chunk_size);
+      gomp_work_share_init_done ();
+    }
 
 #ifdef HAVE_SYNC_BUILTINS
-  gomp_mutex_unlock (&thr->ts.work_share->lock);
   ret = gomp_iter_guided_next (istart, iend);
 #else
+  gomp_mutex_lock (&thr->ts.work_share->lock);
   ret = gomp_iter_guided_next_locked (istart, iend);
   gomp_mutex_unlock (&thr->ts.work_share->lock);
 #endif
@@ -124,17 +167,22 @@ bool
 GOMP_loop_runtime_start (long start, long end, long incr,
                         long *istart, long *iend)
 {
-  switch (gomp_run_sched_var)
+  struct gomp_task_icv *icv = gomp_icv (false);
+  switch (icv->run_sched_var)
     {
     case GFS_STATIC:
-      return gomp_loop_static_start (start, end, incr, gomp_run_sched_chunk,
+      return gomp_loop_static_start (start, end, incr, icv->run_sched_modifier,
                                     istart, iend);
     case GFS_DYNAMIC:
-      return gomp_loop_dynamic_start (start, end, incr, gomp_run_sched_chunk,
+      return gomp_loop_dynamic_start (start, end, incr, icv->run_sched_modifier,
                                      istart, iend);
     case GFS_GUIDED:
-      return gomp_loop_guided_start (start, end, incr, gomp_run_sched_chunk,
+      return gomp_loop_guided_start (start, end, incr, icv->run_sched_modifier,
                                     istart, iend);
+    case GFS_AUTO:
+      /* For now map to schedule(static), later on we could play with feedback
+        driven choice.  */
+      return gomp_loop_static_start (start, end, incr, 0, istart, iend);
     default:
       abort ();
     }
@@ -149,13 +197,14 @@ gomp_loop_ordered_static_start (long start, long end, long incr,
 {
   struct gomp_thread *thr = gomp_thread ();
 
+  thr->ts.static_trip = 0;
   if (gomp_work_share_start (true))
     {
       gomp_loop_init (thr->ts.work_share, start, end, incr,
                      GFS_STATIC, chunk_size);
       gomp_ordered_static_init ();
+      gomp_work_share_init_done ();
     }
-  gomp_mutex_unlock (&thr->ts.work_share->lock);
 
   return !gomp_iter_static_next (istart, iend);
 }
@@ -168,8 +217,14 @@ gomp_loop_ordered_dynamic_start (long start, long end, long incr,
   bool ret;
 
   if (gomp_work_share_start (true))
-    gomp_loop_init (thr->ts.work_share, start, end, incr,
-                   GFS_DYNAMIC, chunk_size);
+    {
+      gomp_loop_init (thr->ts.work_share, start, end, incr,
+                     GFS_DYNAMIC, chunk_size);
+      gomp_mutex_lock (&thr->ts.work_share->lock);
+      gomp_work_share_init_done ();
+    }
+  else
+    gomp_mutex_lock (&thr->ts.work_share->lock);
 
   ret = gomp_iter_dynamic_next_locked (istart, iend);
   if (ret)
@@ -187,8 +242,14 @@ gomp_loop_ordered_guided_start (long start, long end, long incr,
   bool ret;
 
   if (gomp_work_share_start (true))
-    gomp_loop_init (thr->ts.work_share, start, end, incr,
-                   GFS_GUIDED, chunk_size);
+    {
+      gomp_loop_init (thr->ts.work_share, start, end, incr,
+                     GFS_GUIDED, chunk_size);
+      gomp_mutex_lock (&thr->ts.work_share->lock);
+      gomp_work_share_init_done ();
+    }
+  else
+    gomp_mutex_lock (&thr->ts.work_share->lock);
 
   ret = gomp_iter_guided_next_locked (istart, iend);
   if (ret)
@@ -202,20 +263,26 @@ bool
 GOMP_loop_ordered_runtime_start (long start, long end, long incr,
                                 long *istart, long *iend)
 {
-  switch (gomp_run_sched_var)
+  struct gomp_task_icv *icv = gomp_icv (false);
+  switch (icv->run_sched_var)
     {
     case GFS_STATIC:
       return gomp_loop_ordered_static_start (start, end, incr,
-                                            gomp_run_sched_chunk,
+                                            icv->run_sched_modifier,
                                             istart, iend);
     case GFS_DYNAMIC:
       return gomp_loop_ordered_dynamic_start (start, end, incr,
-                                             gomp_run_sched_chunk,
+                                             icv->run_sched_modifier,
                                              istart, iend);
     case GFS_GUIDED:
       return gomp_loop_ordered_guided_start (start, end, incr,
-                                            gomp_run_sched_chunk,
+                                            icv->run_sched_modifier,
                                             istart, iend);
+    case GFS_AUTO:
+      /* For now map to schedule(static), later on we could play with feedback
+        driven choice.  */
+      return gomp_loop_ordered_static_start (start, end, incr,
+                                            0, istart, iend);
     default:
       abort ();
     }
@@ -279,6 +346,7 @@ GOMP_loop_runtime_next (long *istart, long *iend)
   switch (thr->ts.work_share->sched)
     {
     case GFS_STATIC:
+    case GFS_AUTO:
       return gomp_loop_static_next (istart, iend);
     case GFS_DYNAMIC:
       return gomp_loop_dynamic_next (istart, iend);
@@ -356,6 +424,7 @@ GOMP_loop_ordered_runtime_next (long *istart, long *iend)
   switch (thr->ts.work_share->sched)
     {
     case GFS_STATIC:
+    case GFS_AUTO:
       return gomp_loop_ordered_static_next (istart, iend);
     case GFS_DYNAMIC:
       return gomp_loop_ordered_dynamic_next (istart, iend);
@@ -375,12 +444,12 @@ gomp_parallel_loop_start (void (*fn) (void *), void *data,
                          long incr, enum gomp_schedule_type sched,
                          long chunk_size)
 {
-  struct gomp_work_share *ws;
+  struct gomp_team *team;
 
-  num_threads = gomp_resolve_num_threads (num_threads);
-  ws = gomp_new_work_share (false, num_threads);
-  gomp_loop_init (ws, start, end, incr, sched, chunk_size);
-  gomp_team_start (fn, data, num_threads, ws);
+  num_threads = gomp_resolve_num_threads (num_threads, 0);
+  team = gomp_new_team (num_threads);
+  gomp_loop_init (&team->work_shares[0], start, end, incr, sched, chunk_size);
+  gomp_team_start (fn, data, num_threads, team);
 }
 
 void
@@ -415,8 +484,9 @@ GOMP_parallel_loop_runtime_start (void (*fn) (void *), void *data,
                                  unsigned num_threads, long start, long end,
                                  long incr)
 {
+  struct gomp_task_icv *icv = gomp_icv (false);
   gomp_parallel_loop_start (fn, data, num_threads, start, end, incr,
-                           gomp_run_sched_var, gomp_run_sched_chunk);
+                           icv->run_sched_var, icv->run_sched_modifier);
 }
 
 /* The GOMP_loop_end* routines are called after the thread is told that
diff --git a/libgomp/loop_ull.c b/libgomp/loop_ull.c
new file mode 100644 (file)
index 0000000..7dab053
--- /dev/null
@@ -0,0 +1,565 @@
+/* Copyright (C) 2005, 2008 Free Software Foundation, Inc.
+   Contributed by Richard Henderson <rth@redhat.com>.
+
+   This file is part of the GNU OpenMP Library (libgomp).
+
+   Libgomp is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 2.1 of the License, or
+   (at your option) any later version.
+
+   Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+   FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+   more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with libgomp; see the file COPYING.LIB.  If not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+/* As a special exception, if you link this library with other files, some
+   of which are compiled with GCC, to produce an executable, this library
+   does not by itself cause the resulting executable to be covered by the
+   GNU General Public License.  This exception does not however invalidate
+   any other reasons why the executable file might be covered by the GNU
+   General Public License.  */
+
+/* This file handles the LOOP (FOR/DO) construct.  */
+
+#include <limits.h>
+#include <stdlib.h>
+#include "libgomp.h"
+
+typedef unsigned long long gomp_ull;
+
+/* Initialize the given work share construct from the given arguments.  */
+
+static inline void
+gomp_loop_ull_init (struct gomp_work_share *ws, bool up, gomp_ull start,
+                   gomp_ull end, gomp_ull incr, enum gomp_schedule_type sched,
+                   gomp_ull chunk_size)
+{
+  ws->sched = sched;
+  ws->chunk_size_ull = chunk_size;
+  /* Canonicalize loops that have zero iterations to ->next == ->end.  */
+  ws->end_ull = ((up && start > end) || (!up && start < end))
+               ? start : end;
+  ws->incr_ull = incr;
+  ws->next_ull = start;
+  ws->mode = 0;
+  if (sched == GFS_DYNAMIC)
+    {
+      ws->chunk_size_ull *= incr;
+
+#if defined HAVE_SYNC_BUILTINS && defined __LP64__
+      {
+       /* For dynamic scheduling prepare things to make each iteration
+          faster.  */
+       struct gomp_thread *thr = gomp_thread ();
+       struct gomp_team *team = thr->ts.team;
+       long nthreads = team ? team->nthreads : 1;
+
+       if (__builtin_expect (up, 1))
+         {
+           /* Cheap overflow protection.  */
+           if (__builtin_expect ((nthreads | ws->chunk_size_ull)
+                                 < 1ULL << (sizeof (gomp_ull)
+                                            * __CHAR_BIT__ / 2 - 1), 1))
+             ws->mode = ws->end_ull < (__LONG_LONG_MAX__ * 2ULL + 1
+                                       - (nthreads + 1) * ws->chunk_size_ull);
+         }
+       /* Cheap overflow protection.  */
+       else if (__builtin_expect ((nthreads | -ws->chunk_size_ull)
+                                  < 1ULL << (sizeof (gomp_ull)
+                                             * __CHAR_BIT__ / 2 - 1), 1))
+         ws->mode = ws->end_ull > ((nthreads + 1) * -ws->chunk_size_ull
+                                   - (__LONG_LONG_MAX__ * 2ULL + 1));
+      }
+#endif
+    }
+  if (!up)
+    ws->mode |= 2;
+}
+
+/* The *_start routines are called when first encountering a loop construct
+   that is not bound directly to a parallel construct.  The first thread
+   that arrives will create the work-share construct; subsequent threads
+   will see the construct exists and allocate work from it.
+
+   START, END, INCR are the bounds of the loop; due to the restrictions of
+   OpenMP, these values must be the same in every thread.  This is not
+   verified (nor is it entirely verifiable, since START is not necessarily
+   retained intact in the work-share data structure).  CHUNK_SIZE is the
+   scheduling parameter; again this must be identical in all threads.
+
+   Returns true if there's any work for this thread to perform.  If so,
+   *ISTART and *IEND are filled with the bounds of the iteration block
+   allocated to this thread.  Returns false if all work was assigned to
+   other threads prior to this thread's arrival.  */
+
+static bool
+gomp_loop_ull_static_start (bool up, gomp_ull start, gomp_ull end,
+                           gomp_ull incr, gomp_ull chunk_size,
+                           gomp_ull *istart, gomp_ull *iend)
+{
+  struct gomp_thread *thr = gomp_thread ();
+
+  thr->ts.static_trip = 0;
+  if (gomp_work_share_start (false))
+    {
+      gomp_loop_ull_init (thr->ts.work_share, up, start, end, incr,
+                         GFS_STATIC, chunk_size);
+      gomp_work_share_init_done ();
+    }
+
+  return !gomp_iter_ull_static_next (istart, iend);
+}
+
+static bool
+gomp_loop_ull_dynamic_start (bool up, gomp_ull start, gomp_ull end,
+                            gomp_ull incr, gomp_ull chunk_size,
+                            gomp_ull *istart, gomp_ull *iend)
+{
+  struct gomp_thread *thr = gomp_thread ();
+  bool ret;
+
+  if (gomp_work_share_start (false))
+    {
+      gomp_loop_ull_init (thr->ts.work_share, up, start, end, incr,
+                         GFS_DYNAMIC, chunk_size);
+      gomp_work_share_init_done ();
+    }
+
+#if defined HAVE_SYNC_BUILTINS && defined __LP64__
+  ret = gomp_iter_ull_dynamic_next (istart, iend);
+#else
+  gomp_mutex_lock (&thr->ts.work_share->lock);
+  ret = gomp_iter_ull_dynamic_next_locked (istart, iend);
+  gomp_mutex_unlock (&thr->ts.work_share->lock);
+#endif
+
+  return ret;
+}
+
+static bool
+gomp_loop_ull_guided_start (bool up, gomp_ull start, gomp_ull end,
+                           gomp_ull incr, gomp_ull chunk_size,
+                           gomp_ull *istart, gomp_ull *iend)
+{
+  struct gomp_thread *thr = gomp_thread ();
+  bool ret;
+
+  if (gomp_work_share_start (false))
+    {
+      gomp_loop_ull_init (thr->ts.work_share, up, start, end, incr,
+                         GFS_GUIDED, chunk_size);
+      gomp_work_share_init_done ();
+    }
+
+#if defined HAVE_SYNC_BUILTINS && defined __LP64__
+  ret = gomp_iter_ull_guided_next (istart, iend);
+#else
+  gomp_mutex_lock (&thr->ts.work_share->lock);
+  ret = gomp_iter_ull_guided_next_locked (istart, iend);
+  gomp_mutex_unlock (&thr->ts.work_share->lock);
+#endif
+
+  return ret;
+}
+
+bool
+GOMP_loop_ull_runtime_start (bool up, gomp_ull start, gomp_ull end,
+                            gomp_ull incr, gomp_ull *istart, gomp_ull *iend)
+{
+  struct gomp_task_icv *icv = gomp_icv (false);
+  switch (icv->run_sched_var)
+    {
+    case GFS_STATIC:
+      return gomp_loop_ull_static_start (up, start, end, incr,
+                                        icv->run_sched_modifier,
+                                        istart, iend);
+    case GFS_DYNAMIC:
+      return gomp_loop_ull_dynamic_start (up, start, end, incr,
+                                         icv->run_sched_modifier,
+                                         istart, iend);
+    case GFS_GUIDED:
+      return gomp_loop_ull_guided_start (up, start, end, incr,
+                                        icv->run_sched_modifier,
+                                        istart, iend);
+    case GFS_AUTO:
+      /* For now map to schedule(static), later on we could play with feedback
+        driven choice.  */
+      return gomp_loop_ull_static_start (up, start, end, incr,
+                                        0, istart, iend);
+    default:
+      abort ();
+    }
+}
+
+/* The *_ordered_*_start routines are similar.  The only difference is that
+   this work-share construct is initialized to expect an ORDERED section.  */
+
+static bool
+gomp_loop_ull_ordered_static_start (bool up, gomp_ull start, gomp_ull end,
+                                   gomp_ull incr, gomp_ull chunk_size,
+                                   gomp_ull *istart, gomp_ull *iend)
+{
+  struct gomp_thread *thr = gomp_thread ();
+
+  thr->ts.static_trip = 0;
+  if (gomp_work_share_start (true))
+    {
+      gomp_loop_ull_init (thr->ts.work_share, up, start, end, incr,
+                         GFS_STATIC, chunk_size);
+      gomp_ordered_static_init ();
+      gomp_work_share_init_done ();
+    }
+
+  return !gomp_iter_ull_static_next (istart, iend);
+}
+
+static bool
+gomp_loop_ull_ordered_dynamic_start (bool up, gomp_ull start, gomp_ull end,
+                                    gomp_ull incr, gomp_ull chunk_size,
+                                    gomp_ull *istart, gomp_ull *iend)
+{
+  struct gomp_thread *thr = gomp_thread ();
+  bool ret;
+
+  if (gomp_work_share_start (true))
+    {
+      gomp_loop_ull_init (thr->ts.work_share, up, start, end, incr,
+                         GFS_DYNAMIC, chunk_size);
+      gomp_mutex_lock (&thr->ts.work_share->lock);
+      gomp_work_share_init_done ();
+    }
+  else
+    gomp_mutex_lock (&thr->ts.work_share->lock);
+
+  ret = gomp_iter_ull_dynamic_next_locked (istart, iend);
+  if (ret)
+    gomp_ordered_first ();
+  gomp_mutex_unlock (&thr->ts.work_share->lock);
+
+  return ret;
+}
+
+static bool
+gomp_loop_ull_ordered_guided_start (bool up, gomp_ull start, gomp_ull end,
+                                   gomp_ull incr, gomp_ull chunk_size,
+                                   gomp_ull *istart, gomp_ull *iend)
+{
+  struct gomp_thread *thr = gomp_thread ();
+  bool ret;
+
+  if (gomp_work_share_start (true))
+    {
+      gomp_loop_ull_init (thr->ts.work_share, up, start, end, incr,
+                         GFS_GUIDED, chunk_size);
+      gomp_mutex_lock (&thr->ts.work_share->lock);
+      gomp_work_share_init_done ();
+    }
+  else
+    gomp_mutex_lock (&thr->ts.work_share->lock);
+
+  ret = gomp_iter_ull_guided_next_locked (istart, iend);
+  if (ret)
+    gomp_ordered_first ();
+  gomp_mutex_unlock (&thr->ts.work_share->lock);
+
+  return ret;
+}
+
+bool
+GOMP_loop_ull_ordered_runtime_start (bool up, gomp_ull start, gomp_ull end,
+                                    gomp_ull incr, gomp_ull *istart,
+                                    gomp_ull *iend)
+{
+  struct gomp_task_icv *icv = gomp_icv (false);
+  switch (icv->run_sched_var)
+    {
+    case GFS_STATIC:
+      return gomp_loop_ull_ordered_static_start (up, start, end, incr,
+                                                icv->run_sched_modifier,
+                                                istart, iend);
+    case GFS_DYNAMIC:
+      return gomp_loop_ull_ordered_dynamic_start (up, start, end, incr,
+                                                 icv->run_sched_modifier,
+                                                 istart, iend);
+    case GFS_GUIDED:
+      return gomp_loop_ull_ordered_guided_start (up, start, end, incr,
+                                                icv->run_sched_modifier,
+                                                istart, iend);
+    case GFS_AUTO:
+      /* For now map to schedule(static), later on we could play with feedback
+        driven choice.  */
+      return gomp_loop_ull_ordered_static_start (up, start, end, incr,
+                                                0, istart, iend);
+    default:
+      abort ();
+    }
+}
+
+/* The *_next routines are called when the thread completes processing of
+   the iteration block currently assigned to it.  If the work-share
+   construct is bound directly to a parallel construct, then the iteration
+   bounds may have been set up before the parallel.  In which case, this
+   may be the first iteration for the thread.
+
+   Returns true if there is work remaining to be performed; *ISTART and
+   *IEND are filled with a new iteration block.  Returns false if all work
+   has been assigned.  */
+
+static bool
+gomp_loop_ull_static_next (gomp_ull *istart, gomp_ull *iend)
+{
+  return !gomp_iter_ull_static_next (istart, iend);
+}
+
+static bool
+gomp_loop_ull_dynamic_next (gomp_ull *istart, gomp_ull *iend)
+{
+  bool ret;
+
+#if defined HAVE_SYNC_BUILTINS && defined __LP64__
+  ret = gomp_iter_ull_dynamic_next (istart, iend);
+#else
+  struct gomp_thread *thr = gomp_thread ();
+  gomp_mutex_lock (&thr->ts.work_share->lock);
+  ret = gomp_iter_ull_dynamic_next_locked (istart, iend);
+  gomp_mutex_unlock (&thr->ts.work_share->lock);
+#endif
+
+  return ret;
+}
+
+static bool
+gomp_loop_ull_guided_next (gomp_ull *istart, gomp_ull *iend)
+{
+  bool ret;
+
+#if defined HAVE_SYNC_BUILTINS && defined __LP64__
+  ret = gomp_iter_ull_guided_next (istart, iend);
+#else
+  struct gomp_thread *thr = gomp_thread ();
+  gomp_mutex_lock (&thr->ts.work_share->lock);
+  ret = gomp_iter_ull_guided_next_locked (istart, iend);
+  gomp_mutex_unlock (&thr->ts.work_share->lock);
+#endif
+
+  return ret;
+}
+
+bool
+GOMP_loop_ull_runtime_next (gomp_ull *istart, gomp_ull *iend)
+{
+  struct gomp_thread *thr = gomp_thread ();
+
+  switch (thr->ts.work_share->sched)
+    {
+    case GFS_STATIC:
+    case GFS_AUTO:
+      return gomp_loop_ull_static_next (istart, iend);
+    case GFS_DYNAMIC:
+      return gomp_loop_ull_dynamic_next (istart, iend);
+    case GFS_GUIDED:
+      return gomp_loop_ull_guided_next (istart, iend);
+    default:
+      abort ();
+    }
+}
+
+/* The *_ordered_*_next routines are called when the thread completes
+   processing of the iteration block currently assigned to it.
+
+   Returns true if there is work remaining to be performed; *ISTART and
+   *IEND are filled with a new iteration block.  Returns false if all work
+   has been assigned.  */
+
+static bool
+gomp_loop_ull_ordered_static_next (gomp_ull *istart, gomp_ull *iend)
+{
+  struct gomp_thread *thr = gomp_thread ();
+  int test;
+
+  gomp_ordered_sync ();
+  gomp_mutex_lock (&thr->ts.work_share->lock);
+  test = gomp_iter_ull_static_next (istart, iend);
+  if (test >= 0)
+    gomp_ordered_static_next ();
+  gomp_mutex_unlock (&thr->ts.work_share->lock);
+
+  return test == 0;
+}
+
+static bool
+gomp_loop_ull_ordered_dynamic_next (gomp_ull *istart, gomp_ull *iend)
+{
+  struct gomp_thread *thr = gomp_thread ();
+  bool ret;
+
+  gomp_ordered_sync ();
+  gomp_mutex_lock (&thr->ts.work_share->lock);
+  ret = gomp_iter_ull_dynamic_next_locked (istart, iend);
+  if (ret)
+    gomp_ordered_next ();
+  else
+    gomp_ordered_last ();
+  gomp_mutex_unlock (&thr->ts.work_share->lock);
+
+  return ret;
+}
+
+static bool
+gomp_loop_ull_ordered_guided_next (gomp_ull *istart, gomp_ull *iend)
+{
+  struct gomp_thread *thr = gomp_thread ();
+  bool ret;
+
+  gomp_ordered_sync ();
+  gomp_mutex_lock (&thr->ts.work_share->lock);
+  ret = gomp_iter_ull_guided_next_locked (istart, iend);
+  if (ret)
+    gomp_ordered_next ();
+  else
+    gomp_ordered_last ();
+  gomp_mutex_unlock (&thr->ts.work_share->lock);
+
+  return ret;
+}
+
+bool
+GOMP_loop_ull_ordered_runtime_next (gomp_ull *istart, gomp_ull *iend)
+{
+  struct gomp_thread *thr = gomp_thread ();
+
+  switch (thr->ts.work_share->sched)
+    {
+    case GFS_STATIC:
+    case GFS_AUTO:
+      return gomp_loop_ull_ordered_static_next (istart, iend);
+    case GFS_DYNAMIC:
+      return gomp_loop_ull_ordered_dynamic_next (istart, iend);
+    case GFS_GUIDED:
+      return gomp_loop_ull_ordered_guided_next (istart, iend);
+    default:
+      abort ();
+    }
+}
+
+/* We use static functions above so that we're sure that the "runtime"
+   function can defer to the proper routine without interposition.  We
+   export the static function with a strong alias when possible, or with
+   a wrapper function otherwise.  */
+
+#ifdef HAVE_ATTRIBUTE_ALIAS
+extern __typeof(gomp_loop_ull_static_start) GOMP_loop_ull_static_start
+       __attribute__((alias ("gomp_loop_ull_static_start")));
+extern __typeof(gomp_loop_ull_dynamic_start) GOMP_loop_ull_dynamic_start
+       __attribute__((alias ("gomp_loop_ull_dynamic_start")));
+extern __typeof(gomp_loop_ull_guided_start) GOMP_loop_ull_guided_start
+       __attribute__((alias ("gomp_loop_ull_guided_start")));
+
+extern __typeof(gomp_loop_ull_ordered_static_start) GOMP_loop_ull_ordered_static_start
+       __attribute__((alias ("gomp_loop_ull_ordered_static_start")));
+extern __typeof(gomp_loop_ull_ordered_dynamic_start) GOMP_loop_ull_ordered_dynamic_start
+       __attribute__((alias ("gomp_loop_ull_ordered_dynamic_start")));
+extern __typeof(gomp_loop_ull_ordered_guided_start) GOMP_loop_ull_ordered_guided_start
+       __attribute__((alias ("gomp_loop_ull_ordered_guided_start")));
+
+extern __typeof(gomp_loop_ull_static_next) GOMP_loop_ull_static_next
+       __attribute__((alias ("gomp_loop_ull_static_next")));
+extern __typeof(gomp_loop_ull_dynamic_next) GOMP_loop_ull_dynamic_next
+       __attribute__((alias ("gomp_loop_ull_dynamic_next")));
+extern __typeof(gomp_loop_ull_guided_next) GOMP_loop_ull_guided_next
+       __attribute__((alias ("gomp_loop_ull_guided_next")));
+
+extern __typeof(gomp_loop_ull_ordered_static_next) GOMP_loop_ull_ordered_static_next
+       __attribute__((alias ("gomp_loop_ull_ordered_static_next")));
+extern __typeof(gomp_loop_ull_ordered_dynamic_next) GOMP_loop_ull_ordered_dynamic_next
+       __attribute__((alias ("gomp_loop_ull_ordered_dynamic_next")));
+extern __typeof(gomp_loop_ull_ordered_guided_next) GOMP_loop_ull_ordered_guided_next
+       __attribute__((alias ("gomp_loop_ull_ordered_guided_next")));
+#else
+bool
+GOMP_loop_ull_static_start (gomp_ull start, gomp_ull end, gomp_ull incr, gomp_ull chunk_size,
+                       gomp_ull *istart, gomp_ull *iend)
+{
+  return gomp_loop_ull_static_start (start, end, incr, chunk_size, istart, iend);
+}
+
+bool
+GOMP_loop_ull_dynamic_start (gomp_ull start, gomp_ull end, gomp_ull incr, gomp_ull chunk_size,
+                        gomp_ull *istart, gomp_ull *iend)
+{
+  return gomp_loop_ull_dynamic_start (start, end, incr, chunk_size, istart, iend);
+}
+
+bool
+GOMP_loop_ull_guided_start (gomp_ull start, gomp_ull end, gomp_ull incr, gomp_ull chunk_size,
+                       gomp_ull *istart, gomp_ull *iend)
+{
+  return gomp_loop_ull_guided_start (start, end, incr, chunk_size, istart, iend);
+}
+
+bool
+GOMP_loop_ull_ordered_static_start (gomp_ull start, gomp_ull end, gomp_ull incr,
+                               gomp_ull chunk_size, gomp_ull *istart, gomp_ull *iend)
+{
+  return gomp_loop_ull_ordered_static_start (start, end, incr, chunk_size,
+                                        istart, iend);
+}
+
+bool
+GOMP_loop_ull_ordered_dynamic_start (gomp_ull start, gomp_ull end, gomp_ull incr,
+                                gomp_ull chunk_size, gomp_ull *istart, gomp_ull *iend)
+{
+  return gomp_loop_ull_ordered_dynamic_start (start, end, incr, chunk_size,
+                                         istart, iend);
+}
+
+bool
+GOMP_loop_ull_ordered_guided_start (gomp_ull start, gomp_ull end, gomp_ull incr,
+                               gomp_ull chunk_size, gomp_ull *istart, gomp_ull *iend)
+{
+  return gomp_loop_ull_ordered_guided_start (start, end, incr, chunk_size,
+                                        istart, iend);
+}
+
+bool
+GOMP_loop_ull_static_next (gomp_ull *istart, gomp_ull *iend)
+{
+  return gomp_loop_ull_static_next (istart, iend);
+}
+
+bool
+GOMP_loop_ull_dynamic_next (gomp_ull *istart, gomp_ull *iend)
+{
+  return gomp_loop_ull_dynamic_next (istart, iend);
+}
+
+bool
+GOMP_loop_ull_guided_next (gomp_ull *istart, gomp_ull *iend)
+{
+  return gomp_loop_ull_guided_next (istart, iend);
+}
+
+bool
+GOMP_loop_ull_ordered_static_next (gomp_ull *istart, gomp_ull *iend)
+{
+  return gomp_loop_ull_ordered_static_next (istart, iend);
+}
+
+bool
+GOMP_loop_ull_ordered_dynamic_next (gomp_ull *istart, gomp_ull *iend)
+{
+  return gomp_loop_ull_ordered_dynamic_next (istart, iend);
+}
+
+bool
+GOMP_loop_ull_ordered_guided_next (gomp_ull *istart, gomp_ull *iend)
+{
+  return gomp_loop_ull_ordered_guided_next (istart, iend);
+}
+#endif
index 5ebcdbb2735102ece3a4330abbbfbcf6ee3a1343..d4fe94a2ca77b811337bc0320b37e4c43fdfaee7 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005, 2007 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2007, 2008 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
@@ -47,6 +47,14 @@ typedef struct
 } omp_nest_lock_t;
 #endif
 
+typedef enum omp_sched_t
+{
+  omp_sched_static = 1,
+  omp_sched_dynamic = 2,
+  omp_sched_guided = 3,
+  omp_sched_auto = 4
+} omp_sched_t;
+
 #ifdef __cplusplus
 extern "C" {
 # define __GOMP_NOTHROW throw ()
@@ -83,6 +91,16 @@ extern int omp_test_nest_lock (omp_nest_lock_t *) __GOMP_NOTHROW;
 extern double omp_get_wtime (void) __GOMP_NOTHROW;
 extern double omp_get_wtick (void) __GOMP_NOTHROW;
 
+void omp_set_schedule (omp_sched_t, int) __GOMP_NOTHROW;
+void omp_get_schedule (omp_sched_t *, int *) __GOMP_NOTHROW;
+int omp_get_thread_limit (void) __GOMP_NOTHROW;
+void omp_set_max_active_levels (int) __GOMP_NOTHROW;
+int omp_get_max_active_levels (void) __GOMP_NOTHROW;
+int omp_get_level (void) __GOMP_NOTHROW;
+int omp_get_ancestor_thread_num (int) __GOMP_NOTHROW;
+int omp_get_team_size (int) __GOMP_NOTHROW;
+int omp_get_active_level (void) __GOMP_NOTHROW;
+
 #ifdef __cplusplus
 }
 #endif
index 4b8553b3236ce31ac24e84e43455f498c1ac3b3d..a31a94567eae2f2594c11441e486991577174799 100644 (file)
@@ -1,4 +1,4 @@
-!  Copyright (C) 2005 Free Software Foundation, Inc.
+!  Copyright (C) 2005, 2007, 2008 Free Software Foundation, Inc.
 !  Contributed by Jakub Jelinek <jakub@redhat.com>.
 
 !  This file is part of the GNU OpenMP Library (libgomp).
         integer, parameter :: omp_logical_kind = 4
         integer, parameter :: omp_lock_kind = @OMP_LOCK_KIND@
         integer, parameter :: omp_nest_lock_kind = @OMP_NEST_LOCK_KIND@
+        integer, parameter :: omp_sched_kind = 4
       end module
 
       module omp_lib
         use omp_lib_kinds
-        integer, parameter :: openmp_version = 200505
+        integer, parameter :: openmp_version = 200805
+        integer (omp_sched_kind), parameter :: omp_sched_static = 1
+        integer (omp_sched_kind), parameter :: omp_sched_dynamic = 2
+        integer (omp_sched_kind), parameter :: omp_sched_guided = 3
+        integer (omp_sched_kind), parameter :: omp_sched_auto = 4
 
         interface
           subroutine omp_init_lock (lock)
           end function omp_get_wtime
         end interface
 
+        interface omp_set_schedule
+          subroutine omp_set_schedule (kind, modifier)
+            use omp_lib_kinds
+            integer (omp_sched_kind), intent (in) :: kind
+            integer (4), intent (in) :: modifier
+          end subroutine omp_set_schedule
+          subroutine omp_set_schedule_8 (kind, modifier)
+            use omp_lib_kinds
+            integer (omp_sched_kind), intent (in) :: kind
+            integer (8), intent (in) :: modifier
+          end subroutine omp_set_schedule_8
+         end interface
+
+        interface omp_get_schedule
+          subroutine omp_get_schedule (kind, modifier)
+            use omp_lib_kinds
+            integer (omp_sched_kind), intent (out) :: kind
+            integer (4), intent (out) :: modifier
+          end subroutine omp_get_schedule
+          subroutine omp_get_schedule_8 (kind, modifier)
+            use omp_lib_kinds
+            integer (omp_sched_kind), intent (out) :: kind
+            integer (8), intent (out) :: modifier
+          end subroutine omp_get_schedule_8
+         end interface
+
+        interface
+          function omp_get_thread_limit ()
+            use omp_lib_kinds
+            integer (omp_integer_kind) :: omp_get_thread_limit
+          end function omp_get_thread_limit
+        end interface
+
+        interface omp_set_max_active_levels
+          subroutine omp_set_max_active_levels (max_levels)
+            use omp_lib_kinds
+            integer (4), intent (in) :: max_levels
+          end subroutine omp_set_max_active_levels
+          subroutine omp_set_max_active_levels_8 (max_levels)
+            use omp_lib_kinds
+            integer (8), intent (in) :: max_levels
+          end subroutine omp_set_max_active_levels_8
+        end interface
+
+        interface
+          function omp_get_max_active_levels ()
+            use omp_lib_kinds
+            integer (omp_integer_kind) :: omp_get_max_active_levels
+          end function omp_get_max_active_levels
+        end interface
+
+        interface
+          function omp_get_level ()
+            use omp_lib_kinds
+            integer (omp_integer_kind) :: omp_get_level
+          end function omp_get_level
+        end interface
+
+        interface omp_get_ancestor_thread_num
+          function omp_get_ancestor_thread_num (level)
+            use omp_lib_kinds
+            integer (4), intent (in) :: level
+            integer (omp_integer_kind) :: omp_get_ancestor_thread_num
+          end function omp_get_ancestor_thread_num
+          function omp_get_ancestor_thread_num_8 (level)
+            use omp_lib_kinds
+            integer (8), intent (in) :: level
+            integer (omp_integer_kind) :: omp_get_ancestor_thread_num
+          end function omp_get_ancestor_thread_num_8
+        end interface
+
+        interface omp_get_team_size
+          function omp_get_team_size (level)
+            use omp_lib_kinds
+            integer (4), intent (in) :: level
+            integer (omp_integer_kind) :: omp_get_team_size
+          end function omp_get_team_size
+          function omp_get_team_size_8 (level)
+            use omp_lib_kinds
+            integer (8), intent (in) :: level
+            integer (omp_integer_kind) :: omp_get_team_size
+          end function omp_get_team_size_8
+        end interface
+
+        interface
+          function omp_get_active_level ()
+            use omp_lib_kinds
+            integer (omp_integer_kind) :: omp_get_active_level
+          end function omp_get_active_level
+        end interface
+
       end module omp_lib
index 734f2f781fc355fe1e83be06edd094f75019a459..60677f666a167d8c7b5d6c084e40ead890d6c002 100644 (file)
@@ -1,4 +1,4 @@
-!  Copyright (C) 2005 Free Software Foundation, Inc.
+!  Copyright (C) 2005, 2007, 2008 Free Software Foundation, Inc.
 !  Contributed by Jakub Jelinek <jakub@redhat.com>.
 
 !  This file is part of the GNU OpenMP Library (libgomp).
 !  General Public License.
 
       integer omp_lock_kind, omp_nest_lock_kind, openmp_version
+      integer omp_sched_kind, omp_sched_static, omp_sched_dynamic
+      integer omp_sched_guided, omp_sched_auto
       parameter (omp_lock_kind = @OMP_LOCK_KIND@)
       parameter (omp_nest_lock_kind = @OMP_NEST_LOCK_KIND@)
-      parameter (openmp_version = 200505)
+      parameter (omp_sched_kind = 4)
+      parameter (omp_sched_static = 1)
+      parameter (omp_sched_dynamic = 2)
+      parameter (omp_sched_guided = 3)
+      parameter (omp_sched_auto = 4)
+      parameter (openmp_version = 200805)
 
       external omp_init_lock, omp_init_nest_lock
       external omp_destroy_lock, omp_destroy_nest_lock
 
       external omp_get_wtick, omp_get_wtime
       double precision omp_get_wtick, omp_get_wtime
+
+      external omp_set_schedule, omp_get_schedule
+      external omp_get_thread_limit, omp_set_max_active_levels
+      external omp_get_max_active_levels, omp_get_level
+      external omp_get_ancestor_thread_num, omp_get_team_size
+      external omp_get_active_level
+      integer*4 omp_get_thread_limit, omp_get_max_active_levels
+      integer*4 omp_get_level, omp_get_ancestor_thread_num
+      integer*4 omp_get_team_size, omp_get_active_level
index edd344a90a8744422e5825e5709c776f3c990029..3f2a305613893a662e75382713d9ae898855998e 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2007, 2008 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
 /* This file handles the (bare) PARALLEL construct.  */
 
 #include "libgomp.h"
+#include <limits.h>
 
 
 /* Determine the number of threads to be launched for a PARALLEL construct.
-   This algorithm is explicitly described in OpenMP 2.5 section 2.4.1.
+   This algorithm is explicitly described in OpenMP 3.0 section 2.4.1.
    SPECIFIED is a combination of the NUM_THREADS clause and the IF clause.
    If the IF clause is false, SPECIFIED is forced to 1.  When NUM_THREADS
    is not present, SPECIFIED is 0.  */
 
 unsigned
-gomp_resolve_num_threads (unsigned specified)
+gomp_resolve_num_threads (unsigned specified, unsigned count)
 {
-  /* Early exit for false IF condition or degenerate NUM_THREADS.  */
+  struct gomp_thread *thread = gomp_thread();
+  struct gomp_task_icv *icv;
+  unsigned threads_requested, max_num_threads, num_threads;
+  unsigned long remaining;
+
+  icv = gomp_icv (false);
+
   if (specified == 1)
     return 1;
-
-  /* If this is a nested region, and nested regions are disabled, force
-     this team to use only one thread.  */
-  if (gomp_thread()->ts.team && !gomp_nest_var)
+  else if (thread->ts.active_level >= 1 && !icv->nest_var)
+    return 1;
+  else if (thread->ts.active_level >= gomp_max_active_levels_var)
     return 1;
 
   /* If NUM_THREADS not specified, use nthreads_var.  */
   if (specified == 0)
-    specified = gomp_nthreads_var;
+    threads_requested = icv->nthreads_var;
+  else
+    threads_requested = specified;
+
+  max_num_threads = threads_requested;
 
   /* If dynamic threads are enabled, bound the number of threads
      that we launch.  */
-  if (gomp_dyn_var)
+  if (icv->dyn_var)
     {
       unsigned dyn = gomp_dynamic_max_threads ();
-      if (dyn < specified)
-       return dyn;
+      if (dyn < max_num_threads)
+       max_num_threads = dyn;
+
+      /* Optimization for parallel sections.  */
+      if (count && count < max_num_threads)
+       max_num_threads = count;
     }
 
-  return specified;
+  /* ULONG_MAX stands for infinity.  */
+  if (__builtin_expect (gomp_thread_limit_var == ULONG_MAX, 1)
+      || max_num_threads == 1)
+    return max_num_threads;
+
+#ifdef HAVE_SYNC_BUILTINS
+  do
+    {
+      remaining = gomp_remaining_threads_count;
+      num_threads = max_num_threads;
+      if (num_threads > remaining)
+       num_threads = remaining + 1;
+    }
+  while (__sync_val_compare_and_swap (&gomp_remaining_threads_count,
+                                     remaining, remaining - num_threads + 1)
+        != remaining);
+#else
+  gomp_mutex_lock (&gomp_remaining_threads_lock);
+  num_threads = max_num_threads;
+  remaining = gomp_remaining_threads_count;
+  if (num_threads > remaining)
+    num_threads = remaining + 1;
+  gomp_remaining_threads_count -= num_threads - 1;
+  gomp_mutex_unlock (&gomp_remaining_threads_lock);
+#endif
+
+  return num_threads;
 }
 
 void
 GOMP_parallel_start (void (*fn) (void *), void *data, unsigned num_threads)
 {
-  num_threads = gomp_resolve_num_threads (num_threads);
-  gomp_team_start (fn, data, num_threads, NULL);
+  num_threads = gomp_resolve_num_threads (num_threads, 0);
+  gomp_team_start (fn, data, num_threads, gomp_new_team (num_threads));
 }
 
 void
 GOMP_parallel_end (void)
 {
+  if (__builtin_expect (gomp_thread_limit_var != ULONG_MAX, 0))
+    {
+      struct gomp_thread *thr = gomp_thread ();
+      struct gomp_team *team = thr->ts.team;
+      if (team && team->nthreads > 1)
+       {
+#ifdef HAVE_SYNC_BUILTINS
+         __sync_fetch_and_add (&gomp_remaining_threads_count,
+                               1UL - team->nthreads);
+#else
+         gomp_mutex_lock (&gomp_remaining_threads_lock);
+         gomp_remaining_threads_count -= team->nthreads - 1;
+#endif
+       }
+    }
   gomp_team_end ();
 }
 
@@ -87,40 +142,63 @@ omp_get_num_threads (void)
   return team ? team->nthreads : 1;
 }
 
-/* ??? Does this function need to disregard dyn_var?  I don't see
-   how else one could get a useable "maximum".  */
-
 int
-omp_get_max_threads (void)
+omp_get_thread_num (void)
 {
-  return gomp_resolve_num_threads (0);
+  return gomp_thread ()->ts.team_id;
 }
 
+/* This wasn't right for OpenMP 2.5.  Active region used to be non-zero
+   when the IF clause doesn't evaluate to false, starting with OpenMP 3.0
+   it is non-zero with more than one thread in the team.  */
+
 int
-omp_get_thread_num (void)
+omp_in_parallel (void)
 {
-  return gomp_thread ()->ts.team_id;
+  return gomp_thread ()->ts.active_level > 0;
 }
 
-/* ??? This isn't right.  The definition of this function is false if any
-   of the IF clauses for any of the parallels is false.  Which is not the
-   same thing as any outer team having more than one thread.  */
+int
+omp_get_level (void)
+{
+  return gomp_thread ()->ts.level;
+}
 
-int omp_in_parallel (void)
+int
+omp_get_ancestor_thread_num (int level)
 {
-  struct gomp_team *team = gomp_thread ()->ts.team;
+  struct gomp_team_state *ts = &gomp_thread ()->ts;
+  if (level < 0 || level > ts->level)
+    return -1;
+  for (level = ts->level - level; level > 0; --level)
+    ts = &ts->team->prev_ts;
+  return ts->team_id;
+}
 
-  while (team)
-    {
-      if (team->nthreads > 1)
-       return true;
-      team = team->prev_ts.team;
-    }
+int
+omp_get_team_size (int level)
+{
+  struct gomp_team_state *ts = &gomp_thread ()->ts;
+  if (level < 0 || level > ts->level)
+    return -1;
+  for (level = ts->level - level; level > 0; --level)
+    ts = &ts->team->prev_ts;
+  if (ts->team == NULL)
+    return 1;
+  else
+    return ts->team->nthreads;
+}
 
-  return false;
+int
+omp_get_active_level (void)
+{
+  return gomp_thread ()->ts.active_level;
 }
 
 ialias (omp_get_num_threads)
-ialias (omp_get_max_threads)
 ialias (omp_get_thread_num)
 ialias (omp_in_parallel)
+ialias (omp_get_level)
+ialias (omp_get_ancestor_thread_num)
+ialias (omp_get_team_size)
+ialias (omp_get_active_level)
index 9ccc65e4b66fef0e8780d36a8ee6a909ff0f0ae3..27625efec3e837e6e4f22862ebde2fb44e512c9d 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005, 2007 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2007, 2008 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
@@ -59,14 +59,24 @@ GOMP_sections_start (unsigned count)
   long s, e, ret;
 
   if (gomp_work_share_start (false))
-    gomp_sections_init (thr->ts.work_share, count);
+    {
+      gomp_sections_init (thr->ts.work_share, count);
+      gomp_work_share_init_done ();
+    }
 
+#ifdef HAVE_SYNC_BUILTINS
+  if (gomp_iter_dynamic_next (&s, &e))
+    ret = s;
+  else
+    ret = 0;
+#else
+  gomp_mutex_lock (&thr->ts.work_share->lock);
   if (gomp_iter_dynamic_next_locked (&s, &e))
     ret = s;
   else
     ret = 0;
-
   gomp_mutex_unlock (&thr->ts.work_share->lock);
+#endif
 
   return ret;
 }
@@ -83,15 +93,23 @@ GOMP_sections_start (unsigned count)
 unsigned
 GOMP_sections_next (void)
 {
-  struct gomp_thread *thr = gomp_thread ();
   long s, e, ret;
 
+#ifdef HAVE_SYNC_BUILTINS
+  if (gomp_iter_dynamic_next (&s, &e))
+    ret = s;
+  else
+    ret = 0;
+#else
+  struct gomp_thread *thr = gomp_thread ();
+
   gomp_mutex_lock (&thr->ts.work_share->lock);
   if (gomp_iter_dynamic_next_locked (&s, &e))
     ret = s;
   else
     ret = 0;
   gomp_mutex_unlock (&thr->ts.work_share->lock);
+#endif
 
   return ret;
 }
@@ -103,15 +121,12 @@ void
 GOMP_parallel_sections_start (void (*fn) (void *), void *data,
                              unsigned num_threads, unsigned count)
 {
-  struct gomp_work_share *ws;
-
-  num_threads = gomp_resolve_num_threads (num_threads);
-  if (gomp_dyn_var && num_threads > count)
-    num_threads = count;
+  struct gomp_team *team;
 
-  ws = gomp_new_work_share (false, num_threads);
-  gomp_sections_init (ws, count);
-  gomp_team_start (fn, data, num_threads, ws);
+  num_threads = gomp_resolve_num_threads (num_threads, count);
+  team = gomp_new_team (num_threads);
+  gomp_sections_init (&team->work_shares[0], count);
+  gomp_team_start (fn, data, num_threads, team);
 }
 
 /* The GOMP_section_end* routines are called after the thread is told
index dde05d9ceb8d72dc2372b16255ff83f52b8f192c..16c7fa988a154fdf2e878a7c1f699aa7660ed203 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2008 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
 bool
 GOMP_single_start (void)
 {
+#ifdef HAVE_SYNC_BUILTINS
+  struct gomp_thread *thr = gomp_thread ();
+  struct gomp_team *team = thr->ts.team;
+  unsigned long single_count;
+
+  if (__builtin_expect (team == NULL, 0))
+    return true;
+
+  single_count = thr->ts.single_count++;
+  return __sync_bool_compare_and_swap (&team->single_count, single_count,
+                                      single_count + 1L);
+#else
   bool ret = gomp_work_share_start (false);
-  gomp_mutex_unlock (&gomp_thread ()->ts.work_share->lock);
+  if (ret)
+    gomp_work_share_init_done ();
   gomp_work_share_end_nowait ();
   return ret;
+#endif
 }
 
 /* This routine is called when first encountering a SINGLE construct that
@@ -57,13 +71,15 @@ GOMP_single_copy_start (void)
   void *ret;
 
   first = gomp_work_share_start (false);
-  gomp_mutex_unlock (&thr->ts.work_share->lock);
   
   if (first)
-    ret = NULL;
+    {
+      gomp_work_share_init_done ();
+      ret = NULL;
+    }
   else
     {
-      gomp_barrier_wait (&thr->ts.team->barrier);
+      gomp_team_barrier_wait (&thr->ts.team->barrier);
 
       ret = thr->ts.work_share->copyprivate;
       gomp_work_share_end_nowait ();
@@ -84,7 +100,7 @@ GOMP_single_copy_end (void *data)
   if (team != NULL)
     {
       thr->ts.work_share->copyprivate = data;
-      gomp_barrier_wait (&team->barrier);
+      gomp_team_barrier_wait (&team->barrier);
     }
 
   gomp_work_share_end_nowait ();
diff --git a/libgomp/task.c b/libgomp/task.c
new file mode 100644 (file)
index 0000000..903948c
--- /dev/null
@@ -0,0 +1,361 @@
+/* Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+   Contributed by Richard Henderson <rth@redhat.com>.
+
+   This file is part of the GNU OpenMP Library (libgomp).
+
+   Libgomp is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 2.1 of the License, or
+   (at your option) any later version.
+
+   Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+   FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+   more details.
+
+   You should have received a copy of the GNU Lesser General Public License 
+   along with libgomp; see the file COPYING.LIB.  If not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+/* As a special exception, if you link this library with other files, some
+   of which are compiled with GCC, to produce an executable, this library
+   does not by itself cause the resulting executable to be covered by the
+   GNU General Public License.  This exception does not however invalidate
+   any other reasons why the executable file might be covered by the GNU
+   General Public License.  */
+
+/* This file handles the maintainence of tasks in response to task
+   creation and termination.  */
+
+#include "libgomp.h"
+#include <stdlib.h>
+#include <string.h>
+
+
+/* Create a new task data structure.  */
+
+void
+gomp_init_task (struct gomp_task *task, struct gomp_task *parent_task,
+               struct gomp_task_icv *prev_icv)
+{
+  task->parent = parent_task;
+  task->icv = *prev_icv;
+  task->kind = GOMP_TASK_IMPLICIT;
+  task->in_taskwait = false;
+  task->children = NULL;
+  gomp_sem_init (&task->taskwait_sem, 0);
+}
+
+/* Clean up a task, after completing it.  */
+
+void
+gomp_end_task (void)
+{
+  struct gomp_thread *thr = gomp_thread ();
+  struct gomp_task *task = thr->task;
+
+  gomp_finish_task (task);
+  thr->task = task->parent;
+}
+
+static inline void
+gomp_clear_parent (struct gomp_task *children)
+{
+  struct gomp_task *task = children;
+
+  if (task)
+    do
+      {
+       task->parent = NULL;
+       task = task->next_child;
+      }
+    while (task != children);
+}
+
+/* Called when encountering an explicit task directive.  If IF_CLAUSE is
+   false, then we must not delay in executing the task.  If UNTIED is true,
+   then the task may be executed by any member of the team.  */
+
+void
+GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *),
+          long arg_size, long arg_align, bool if_clause,
+          unsigned flags __attribute__((unused)))
+{
+  struct gomp_thread *thr = gomp_thread ();
+  struct gomp_team *team = thr->ts.team;
+
+#ifdef HAVE_BROKEN_POSIX_SEMAPHORES
+  /* If pthread_mutex_* is used for omp_*lock*, then each task must be
+     tied to one thread all the time.  This means UNTIED tasks must be
+     tied and if CPYFN is non-NULL IF(0) must be forced, as CPYFN
+     might be running on different thread than FN.  */
+  if (cpyfn)
+    if_clause = false;
+  if (flags & 1)
+    flags &= ~1;
+#endif
+
+  if (!if_clause || team == NULL
+      || team->task_count > 64 * team->nthreads)
+    {
+      struct gomp_task task;
+
+      gomp_init_task (&task, thr->task, gomp_icv (false));
+      task.kind = GOMP_TASK_IFFALSE;
+      thr->task = &task;
+      if (__builtin_expect (cpyfn != NULL, 0))
+       {
+         char buf[arg_size + arg_align - 1];
+         char *arg = (char *) (((uintptr_t) buf + arg_align - 1)
+                               & ~(uintptr_t) (arg_align - 1));
+         cpyfn (arg, data);
+         fn (arg);
+       }
+      else
+       fn (data);
+      if (task.children)
+       {
+         gomp_mutex_lock (&team->task_lock);
+         gomp_clear_parent (task.children);
+         gomp_mutex_unlock (&team->task_lock);
+       }
+      gomp_end_task ();
+    }
+  else
+    {
+      struct gomp_task *task;
+      struct gomp_task *parent = thr->task;
+      char *arg;
+      bool do_wake;
+
+      task = gomp_malloc (sizeof (*task) + arg_size + arg_align - 1);
+      arg = (char *) (((uintptr_t) (task + 1) + arg_align - 1)
+                     & ~(uintptr_t) (arg_align - 1));
+      gomp_init_task (task, parent, gomp_icv (false));
+      task->kind = GOMP_TASK_IFFALSE;
+      thr->task = task;
+      if (cpyfn)
+       cpyfn (arg, data);
+      else
+       memcpy (arg, data, arg_size);
+      thr->task = parent;
+      task->kind = GOMP_TASK_WAITING;
+      task->fn = fn;
+      task->fn_data = arg;
+      gomp_mutex_lock (&team->task_lock);
+      if (parent->children)
+       {
+         task->next_child = parent->children;
+         task->prev_child = parent->children->prev_child;
+         task->next_child->prev_child = task;
+         task->prev_child->next_child = task;
+       }
+      else
+       {
+         task->next_child = task;
+         task->prev_child = task;
+       }
+      parent->children = task;
+      if (team->task_queue)
+       {
+         task->next_queue = team->task_queue;
+         task->prev_queue = team->task_queue->prev_queue;
+         task->next_queue->prev_queue = task;
+         task->prev_queue->next_queue = task;
+       }
+      else
+       {
+         task->next_queue = task;
+         task->prev_queue = task;
+         team->task_queue = task;
+       }
+      if (team->task_count++ == 0)
+       gomp_team_barrier_set_task_pending (&team->barrier);
+      do_wake = team->task_running_count < team->nthreads;
+      gomp_mutex_unlock (&team->task_lock);
+      if (do_wake)
+       gomp_team_barrier_wake (&team->barrier, 1);
+    }
+}
+
+void
+gomp_barrier_handle_tasks (gomp_barrier_state_t state)
+{
+  struct gomp_thread *thr = gomp_thread ();
+  struct gomp_team *team = thr->ts.team;
+  struct gomp_task *task = thr->task;
+  struct gomp_task *child_task = NULL;
+  struct gomp_task *to_free = NULL;
+
+  gomp_mutex_lock (&team->task_lock);
+  if (gomp_barrier_last_thread (state))
+    {
+      if (team->task_count == 0)
+       {
+         gomp_team_barrier_done (&team->barrier, state);
+         gomp_mutex_unlock (&team->task_lock);
+         gomp_team_barrier_wake (&team->barrier, 0);
+         return;
+       }
+      gomp_team_barrier_set_waiting_for_tasks (&team->barrier);
+    }
+
+  while (1)
+    {
+      if (team->task_queue != NULL)
+       {
+         struct gomp_task *parent;
+
+         child_task = team->task_queue;
+         parent = child_task->parent;
+         if (parent && parent->children == child_task)
+           parent->children = child_task->next_child;
+         child_task->prev_queue->next_queue = child_task->next_queue;
+         child_task->next_queue->prev_queue = child_task->prev_queue;
+         if (child_task->next_queue != child_task)
+           team->task_queue = child_task->next_queue;
+         else
+           team->task_queue = NULL;
+         child_task->kind = GOMP_TASK_TIED;
+         team->task_running_count++;
+         if (team->task_count == team->task_running_count)
+           gomp_team_barrier_clear_task_pending (&team->barrier);
+       }
+      gomp_mutex_unlock (&team->task_lock);
+      if (to_free)
+       {
+         gomp_finish_task (to_free);
+         free (to_free);
+         to_free = NULL;
+       }
+      if (child_task)
+       {
+         thr->task = child_task;
+         child_task->fn (child_task->fn_data);
+         thr->task = task;
+       }
+      else
+       return;
+      gomp_mutex_lock (&team->task_lock);
+      if (child_task)
+       {
+         struct gomp_task *parent = child_task->parent;
+         if (parent)
+           {
+             child_task->prev_child->next_child = child_task->next_child;
+             child_task->next_child->prev_child = child_task->prev_child;
+             if (parent->children == child_task)
+               {
+                 if (child_task->next_child != child_task)
+                   parent->children = child_task->next_child;
+                 else
+                   {
+                     parent->children = NULL;
+                     if (parent->in_taskwait)
+                       gomp_sem_post (&parent->taskwait_sem);
+                   }
+               }
+           }
+         gomp_clear_parent (child_task->children);
+         to_free = child_task;
+         child_task = NULL;
+         team->task_running_count--;
+         if (--team->task_count == 0
+             && gomp_team_barrier_waiting_for_tasks (&team->barrier))
+           {
+             gomp_team_barrier_done (&team->barrier, state);
+             gomp_mutex_unlock (&team->task_lock);
+             gomp_team_barrier_wake (&team->barrier, 0);
+           }
+       }
+    }
+}
+
+/* Called when encountering a taskwait directive.  */
+
+void
+GOMP_taskwait (void)
+{
+  struct gomp_thread *thr = gomp_thread ();
+  struct gomp_team *team = thr->ts.team;
+  struct gomp_task *task = thr->task;
+  struct gomp_task *child_task = NULL;
+  struct gomp_task *to_free = NULL;
+
+  if (task == NULL || task->children == NULL)
+    return;
+  gomp_mutex_lock (&team->task_lock);
+  while (1)
+    {
+      if (task->children == NULL)
+       {
+         gomp_mutex_unlock (&team->task_lock);
+         if (to_free)
+           {
+             gomp_finish_task (to_free);
+             free (to_free);
+           }
+         return;
+       }
+      if (task->children->kind == GOMP_TASK_WAITING)
+       {
+         child_task = task->children;
+         task->children = child_task->next_child;
+         child_task->prev_queue->next_queue = child_task->next_queue;
+         child_task->next_queue->prev_queue = child_task->prev_queue;
+         if (team->task_queue == child_task)
+           {
+             if (child_task->next_queue != child_task)
+               team->task_queue = child_task->next_queue;
+             else
+               team->task_queue = NULL;
+           }
+         child_task->kind = GOMP_TASK_TIED;
+         team->task_running_count++;
+         if (team->task_count == team->task_running_count)
+           gomp_team_barrier_clear_task_pending (&team->barrier);
+       }
+      else
+       /* All tasks we are waiting for are already running
+          in other threads.  Wait for them.  */
+       task->in_taskwait = true;
+      gomp_mutex_unlock (&team->task_lock);
+      if (to_free)
+       {
+         gomp_finish_task (to_free);
+         free (to_free);
+         to_free = NULL;
+       }
+      if (child_task)
+       {
+         thr->task = child_task;
+         child_task->fn (child_task->fn_data);
+         thr->task = task;
+       }
+      else
+       {
+         gomp_sem_wait (&task->taskwait_sem);
+         task->in_taskwait = false;
+         return;
+       }
+      gomp_mutex_lock (&team->task_lock);
+      if (child_task)
+       {
+         child_task->prev_child->next_child = child_task->next_child;
+         child_task->next_child->prev_child = child_task->prev_child;
+         if (task->children == child_task)
+           {
+             if (child_task->next_child != child_task)
+               task->children = child_task->next_child;
+             else
+               task->children = NULL;
+           }
+         gomp_clear_parent (child_task->children);
+         to_free = child_task;
+         child_task = NULL;
+         team->task_count--;
+         team->task_running_count--;
+       }
+    }
+}
index 7d50bfc29af83e3504270fbf7acca1288571926a..18b02e72f902b3104da1f06a5d120dd06ae29998 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
 #include <stdlib.h>
 #include <string.h>
 
-/* This array manages threads spawned from the top level, which will
-   return to the idle loop once the current PARALLEL construct ends.  */
-static struct gomp_thread **gomp_threads;
-static unsigned gomp_threads_size;
-static unsigned gomp_threads_used;
-
 /* This attribute contains PTHREAD_CREATE_DETACHED.  */
 pthread_attr_t gomp_thread_attr;
 
-/* This barrier holds and releases threads waiting in gomp_threads.  */
-static gomp_barrier_t gomp_threads_dock;
+/* This key is for the thread destructor.  */
+pthread_key_t gomp_thread_destructor;
+
 
 /* This is the libgomp per-thread data structure.  */
 #ifdef HAVE_TLS
@@ -56,9 +51,11 @@ pthread_key_t gomp_tls_key;
 
 struct gomp_thread_start_data
 {
-  struct gomp_team_state ts;
   void (*fn) (void *);
   void *fn_data;
+  struct gomp_team_state ts;
+  struct gomp_task *task;
+  struct gomp_thread_pool *thread_pool;
   bool nested;
 };
 
@@ -71,6 +68,7 @@ gomp_thread_start (void *xdata)
 {
   struct gomp_thread_start_data *data = xdata;
   struct gomp_thread *thr;
+  struct gomp_thread_pool *pool;
   void (*local_fn) (void *);
   void *local_data;
 
@@ -86,43 +84,46 @@ gomp_thread_start (void *xdata)
   /* Extract what we need from data.  */
   local_fn = data->fn;
   local_data = data->fn_data;
+  thr->thread_pool = data->thread_pool;
   thr->ts = data->ts;
+  thr->task = data->task;
 
   thr->ts.team->ordered_release[thr->ts.team_id] = &thr->release;
 
+  /* Make thread pool local. */
+  pool = thr->thread_pool;
+
   if (data->nested)
     {
-      gomp_barrier_wait (&thr->ts.team->barrier);
+      struct gomp_team *team = thr->ts.team;
+      struct gomp_task *task = thr->task;
+
+      gomp_barrier_wait (&team->barrier);
+
       local_fn (local_data);
-      gomp_barrier_wait (&thr->ts.team->barrier);
+      gomp_team_barrier_wait (&team->barrier);
+      gomp_finish_task (task);
+      gomp_barrier_wait_last (&team->barrier);
     }
   else
     {
-      gomp_threads[thr->ts.team_id] = thr;
+      pool->threads[thr->ts.team_id] = thr;
 
-      gomp_barrier_wait (&gomp_threads_dock);
+      gomp_barrier_wait (&pool->threads_dock);
       do
        {
-         struct gomp_team *team;
+         struct gomp_team *team = thr->ts.team;
+         struct gomp_task *task = thr->task;
 
          local_fn (local_data);
+         gomp_team_barrier_wait (&team->barrier);
+         gomp_finish_task (task);
 
-         /* Clear out the team and function data.  This is a debugging
-            signal that we're in fact back in the dock.  */
-         team = thr->ts.team;
-         thr->fn = NULL;
-         thr->data = NULL;
-         thr->ts.team = NULL;
-         thr->ts.work_share = NULL;
-         thr->ts.team_id = 0;
-         thr->ts.work_share_generation = 0;
-         thr->ts.static_trip = 0;
-
-         gomp_barrier_wait (&team->barrier);
-         gomp_barrier_wait (&gomp_threads_dock);
+         gomp_barrier_wait (&pool->threads_dock);
 
          local_fn = thr->fn;
          local_data = thr->data;
+         thr->fn = NULL;
        }
       while (local_fn);
     }
@@ -133,28 +134,43 @@ gomp_thread_start (void *xdata)
 
 /* Create a new team data structure.  */
 
-static struct gomp_team *
-new_team (unsigned nthreads, struct gomp_work_share *work_share)
+struct gomp_team *
+gomp_new_team (unsigned nthreads)
 {
   struct gomp_team *team;
   size_t size;
+  int i;
 
-  size = sizeof (*team) + nthreads * sizeof (team->ordered_release[0]);
+  size = sizeof (*team) + nthreads * (sizeof (team->ordered_release[0])
+                                     + sizeof (team->implicit_task[0]));
   team = gomp_malloc (size);
-  gomp_mutex_init (&team->work_share_lock);
 
-  team->work_shares = gomp_malloc (4 * sizeof (struct gomp_work_share *));
-  team->generation_mask = 3;
-  team->oldest_live_gen = work_share == NULL;
-  team->num_live_gen = work_share != NULL;
-  team->work_shares[0] = work_share;
+  team->work_share_chunk = 8;
+#ifdef HAVE_SYNC_BUILTINS
+  team->single_count = 0;
+#else
+  gomp_mutex_init (&team->work_share_list_free_lock);
+#endif
+  gomp_init_work_share (&team->work_shares[0], false, nthreads);
+  team->work_shares[0].next_alloc = NULL;
+  team->work_share_list_free = NULL;
+  team->work_share_list_alloc = &team->work_shares[1];
+  for (i = 1; i < 7; i++)
+    team->work_shares[i].next_free = &team->work_shares[i + 1];
+  team->work_shares[i].next_free = NULL;
 
   team->nthreads = nthreads;
   gomp_barrier_init (&team->barrier, nthreads);
 
   gomp_sem_init (&team->master_release, 0);
+  team->ordered_release = (void *) &team->implicit_task[nthreads];
   team->ordered_release[0] = &team->master_release;
 
+  gomp_mutex_init (&team->task_lock);
+  team->task_queue = NULL;
+  team->task_count = 0;
+  team->task_running_count = 0;
+
   return team;
 }
 
@@ -164,31 +180,98 @@ new_team (unsigned nthreads, struct gomp_work_share *work_share)
 static void
 free_team (struct gomp_team *team)
 {
-  free (team->work_shares);
-  gomp_mutex_destroy (&team->work_share_lock);
   gomp_barrier_destroy (&team->barrier);
-  gomp_sem_destroy (&team->master_release);
+  gomp_mutex_destroy (&team->task_lock);
   free (team);
 }
 
+/* Allocate and initialize a thread pool. */
+
+static struct gomp_thread_pool *gomp_new_thread_pool (void)
+{
+  struct gomp_thread_pool *pool
+    = gomp_malloc (sizeof(struct gomp_thread_pool));
+  pool->threads = NULL;
+  pool->threads_size = 0;
+  pool->threads_used = 0;
+  pool->last_team = NULL;
+  return pool;
+}
+
+static void
+gomp_free_pool_helper (void *thread_pool)
+{
+  struct gomp_thread_pool *pool
+    = (struct gomp_thread_pool *) thread_pool;
+  gomp_barrier_wait_last (&pool->threads_dock);
+  pthread_exit (NULL);
+}
+
+/* Free a thread pool and release its threads. */
+
+static void
+gomp_free_thread (void *arg __attribute__((unused)))
+{
+  struct gomp_thread *thr = gomp_thread ();
+  struct gomp_thread_pool *pool = thr->thread_pool;
+  if (pool)
+    {
+      if (pool->threads_used > 0)
+       {
+         int i;
+         for (i = 1; i < pool->threads_used; i++)
+           {
+             struct gomp_thread *nthr = pool->threads[i];
+             nthr->fn = gomp_free_pool_helper;
+             nthr->data = pool;
+           }
+         /* This barrier undocks threads docked on pool->threads_dock.  */
+         gomp_barrier_wait (&pool->threads_dock);
+         /* And this waits till all threads have called gomp_barrier_wait_last
+            in gomp_free_pool_helper.  */
+         gomp_barrier_wait (&pool->threads_dock);
+         /* Now it is safe to destroy the barrier and free the pool.  */
+         gomp_barrier_destroy (&pool->threads_dock);
+       }
+      free (pool->threads);
+      if (pool->last_team)
+       free_team (pool->last_team);
+      free (pool);
+      thr->thread_pool = NULL;
+    }
+  if (thr->task != NULL)
+    {
+      struct gomp_task *task = thr->task;
+      gomp_end_task ();
+      free (task);
+    }
+}
 
 /* Launch a team.  */
 
 void
 gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
-                struct gomp_work_share *work_share)
+                struct gomp_team *team)
 {
   struct gomp_thread_start_data *start_data;
   struct gomp_thread *thr, *nthr;
-  struct gomp_team *team;
+  struct gomp_task *task;
+  struct gomp_task_icv *icv;
   bool nested;
+  struct gomp_thread_pool *pool;
   unsigned i, n, old_threads_used = 0;
   pthread_attr_t thread_attr, *attr;
 
   thr = gomp_thread ();
   nested = thr->ts.team != NULL;
-
-  team = new_team (nthreads, work_share);
+  if (__builtin_expect (thr->thread_pool == NULL, 0))
+    {
+      thr->thread_pool = gomp_new_thread_pool ();
+      pthread_setspecific (gomp_thread_destructor, thr);
+    }
+  pool = thr->thread_pool;
+  task = thr->task;
+  icv = task ? &task->icv : &gomp_global_icv;
 
   /* Always save the previous state, even if this isn't a nested team.
      In particular, we should save any work share state from an outer
@@ -196,10 +279,18 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
   team->prev_ts = thr->ts;
 
   thr->ts.team = team;
-  thr->ts.work_share = work_share;
   thr->ts.team_id = 0;
-  thr->ts.work_share_generation = 0;
+  ++thr->ts.level;
+  if (nthreads > 1)
+    ++thr->ts.active_level;
+  thr->ts.work_share = &team->work_shares[0];
+  thr->ts.last_work_share = NULL;
+#ifdef HAVE_SYNC_BUILTINS
+  thr->ts.single_count = 0;
+#endif
   thr->ts.static_trip = 0;
+  thr->task = &team->implicit_task[0];
+  gomp_init_task (thr->task, task, icv);
 
   if (nthreads == 1)
     return;
@@ -213,14 +304,14 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
      only the initial program thread will modify gomp_threads.  */
   if (!nested)
     {
-      old_threads_used = gomp_threads_used;
+      old_threads_used = pool->threads_used;
 
       if (nthreads <= old_threads_used)
        n = nthreads;
       else if (old_threads_used == 0)
        {
          n = 0;
-         gomp_barrier_init (&gomp_threads_dock, nthreads);
+         gomp_barrier_init (&pool->threads_dock, nthreads);
        }
       else
        {
@@ -228,23 +319,30 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
 
          /* Increase the barrier threshold to make sure all new
             threads arrive before the team is released.  */
-         gomp_barrier_reinit (&gomp_threads_dock, nthreads);
+         gomp_barrier_reinit (&pool->threads_dock, nthreads);
        }
 
       /* Not true yet, but soon will be.  We're going to release all
-        threads from the dock, and those that aren't part of the 
+        threads from the dock, and those that aren't part of the
         team will exit.  */
-      gomp_threads_used = nthreads;
+      pool->threads_used = nthreads;
 
       /* Release existing idle threads.  */
       for (; i < n; ++i)
        {
-         nthr = gomp_threads[i];
+         nthr = pool->threads[i];
          nthr->ts.team = team;
-         nthr->ts.work_share = work_share;
+         nthr->ts.work_share = &team->work_shares[0];
+         nthr->ts.last_work_share = NULL;
          nthr->ts.team_id = i;
-         nthr->ts.work_share_generation = 0;
+         nthr->ts.level = team->prev_ts.level + 1;
+         nthr->ts.active_level = thr->ts.active_level;
+#ifdef HAVE_SYNC_BUILTINS
+         nthr->ts.single_count = 0;
+#endif
          nthr->ts.static_trip = 0;
+         nthr->task = &team->implicit_task[i];
+         gomp_init_task (nthr->task, task, icv);
          nthr->fn = fn;
          nthr->data = data;
          team->ordered_release[i] = &nthr->release;
@@ -254,20 +352,36 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
        goto do_release;
 
       /* If necessary, expand the size of the gomp_threads array.  It is
-        expected that changes in the number of threads is rare, thus we
+        expected that changes in the number of threads are rare, thus we
         make no effort to expand gomp_threads_size geometrically.  */
-      if (nthreads >= gomp_threads_size)
+      if (nthreads >= pool->threads_size)
        {
-         gomp_threads_size = nthreads + 1;
-         gomp_threads
-           = gomp_realloc (gomp_threads,
-                           gomp_threads_size
+         pool->threads_size = nthreads + 1;
+         pool->threads
+           = gomp_realloc (pool->threads,
+                           pool->threads_size
                            * sizeof (struct gomp_thread_data *));
        }
     }
 
+  if (__builtin_expect (nthreads > old_threads_used, 0))
+    {
+      long diff = (long) nthreads - (long) old_threads_used;
+
+      if (old_threads_used == 0)
+       --diff;
+
+#ifdef HAVE_SYNC_BUILTINS
+      __sync_fetch_and_add (&gomp_managed_threads, diff);
+#else
+      gomp_mutex_lock (&gomp_remaining_threads_lock);
+      gomp_managed_threads += diff;
+      gomp_mutex_unlock (&gomp_remaining_threads_lock);
+#endif
+    }
+
   attr = &gomp_thread_attr;
-  if (gomp_cpu_affinity != NULL)
+  if (__builtin_expect (gomp_cpu_affinity != NULL, 0))
     {
       size_t stacksize;
       pthread_attr_init (&thread_attr);
@@ -286,13 +400,21 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
       pthread_t pt;
       int err;
 
+      start_data->fn = fn;
+      start_data->fn_data = data;
       start_data->ts.team = team;
-      start_data->ts.work_share = work_share;
+      start_data->ts.work_share = &team->work_shares[0];
+      start_data->ts.last_work_share = NULL;
       start_data->ts.team_id = i;
-      start_data->ts.work_share_generation = 0;
+      start_data->ts.level = team->prev_ts.level + 1;
+      start_data->ts.active_level = thr->ts.active_level;
+#ifdef HAVE_SYNC_BUILTINS
+      start_data->ts.single_count = 0;
+#endif
       start_data->ts.static_trip = 0;
-      start_data->fn = fn;
-      start_data->fn_data = data;
+      start_data->task = &team->implicit_task[i];
+      gomp_init_task (start_data->task, task, icv);
+      start_data->thread_pool = pool;
       start_data->nested = nested;
 
       if (gomp_cpu_affinity != NULL)
@@ -303,18 +425,30 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
        gomp_fatal ("Thread creation failed: %s", strerror (err));
     }
 
-  if (gomp_cpu_affinity != NULL)
+  if (__builtin_expect (gomp_cpu_affinity != NULL, 0))
     pthread_attr_destroy (&thread_attr);
 
  do_release:
-  gomp_barrier_wait (nested ? &team->barrier : &gomp_threads_dock);
+  gomp_barrier_wait (nested ? &team->barrier : &pool->threads_dock);
 
   /* Decrease the barrier threshold to match the number of threads
      that should arrive back at the end of this team.  The extra
      threads should be exiting.  Note that we arrange for this test
      to never be true for nested teams.  */
-  if (nthreads < old_threads_used)
-    gomp_barrier_reinit (&gomp_threads_dock, nthreads);
+  if (__builtin_expect (nthreads < old_threads_used, 0))
+    {
+      long diff = (long) nthreads - (long) old_threads_used;
+
+      gomp_barrier_reinit (&pool->threads_dock, nthreads);
+
+#ifdef HAVE_SYNC_BUILTINS
+      __sync_fetch_and_add (&gomp_managed_threads, diff);
+#else
+      gomp_mutex_lock (&gomp_remaining_threads_lock);
+      gomp_managed_threads += diff;
+      gomp_mutex_unlock (&gomp_remaining_threads_lock);
+#endif
+    }
 }
 
 
@@ -327,11 +461,52 @@ gomp_team_end (void)
   struct gomp_thread *thr = gomp_thread ();
   struct gomp_team *team = thr->ts.team;
 
-  gomp_barrier_wait (&team->barrier);
+  /* This barrier handles all pending explicit threads.  */
+  gomp_team_barrier_wait (&team->barrier);
+  gomp_fini_work_share (thr->ts.work_share);
 
+  gomp_end_task ();
   thr->ts = team->prev_ts;
 
-  free_team (team);
+  if (__builtin_expect (thr->ts.team != NULL, 0))
+    {
+#ifdef HAVE_SYNC_BUILTINS
+      __sync_fetch_and_add (&gomp_managed_threads, 1L - team->nthreads);
+#else
+      gomp_mutex_lock (&gomp_remaining_threads_lock);
+      gomp_managed_threads -= team->nthreads - 1L;
+      gomp_mutex_unlock (&gomp_remaining_threads_lock);
+#endif
+      /* This barrier has gomp_barrier_wait_last counterparts
+        and ensures the team can be safely destroyed.  */
+      gomp_barrier_wait (&team->barrier);
+    }
+
+  if (__builtin_expect (team->work_shares[0].next_alloc != NULL, 0))
+    {
+      struct gomp_work_share *ws = team->work_shares[0].next_alloc;
+      do
+       {
+         struct gomp_work_share *next_ws = ws->next_alloc;
+         free (ws);
+         ws = next_ws;
+       }
+      while (ws != NULL);
+    }
+  gomp_sem_destroy (&team->master_release);
+#ifndef HAVE_SYNC_BUILTINS
+  gomp_mutex_destroy (&team->work_share_list_free_lock);
+#endif
+
+  if (__builtin_expect (thr->ts.team != NULL, 0))
+    free_team (team);
+  else
+    {
+      struct gomp_thread_pool *pool = thr->thread_pool;
+      if (pool->last_team)
+       free_team (pool->last_team);
+      pool->last_team = team;
+    }
 }
 
 
@@ -349,6 +524,9 @@ initialize_team (void)
   pthread_setspecific (gomp_tls_key, &initial_thread_tls_data);
 #endif
 
+  if (pthread_key_create (&gomp_thread_destructor, gomp_free_thread) != 0)
+    gomp_fatal ("could not create thread pool destructor.");
+
 #ifdef HAVE_TLS
   thr = &gomp_tls_data;
 #else
@@ -356,3 +534,22 @@ initialize_team (void)
 #endif
   gomp_sem_init (&thr->release, 0);
 }
+
+static void __attribute__((destructor))
+team_destructor (void)
+{
+  /* Without this dlclose on libgomp could lead to subsequent
+     crashes.  */
+  pthread_key_delete (gomp_thread_destructor);
+}
+
+struct gomp_task_icv *
+gomp_new_icv (void)
+{
+  struct gomp_thread *thr = gomp_thread ();
+  struct gomp_task *task = gomp_malloc (sizeof (struct gomp_task));
+  gomp_init_task (task, NULL, &gomp_global_icv);
+  thr->task = task;
+  pthread_setspecific (gomp_thread_destructor, thr);
+  return &task->icv;
+}
index 9c6163ba2bfdbc4349dce3c1d72874d846be34f7..ae1806fb2da277f167346e0054903cd592916b87 100644 (file)
@@ -112,9 +112,15 @@ MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
 MAKEINFO = @MAKEINFO@
 NM = @NM@
 OBJEXT = @OBJEXT@
+OMP_LOCK_25_ALIGN = @OMP_LOCK_25_ALIGN@
+OMP_LOCK_25_KIND = @OMP_LOCK_25_KIND@
+OMP_LOCK_25_SIZE = @OMP_LOCK_25_SIZE@
 OMP_LOCK_ALIGN = @OMP_LOCK_ALIGN@
 OMP_LOCK_KIND = @OMP_LOCK_KIND@
 OMP_LOCK_SIZE = @OMP_LOCK_SIZE@
+OMP_NEST_LOCK_25_ALIGN = @OMP_NEST_LOCK_25_ALIGN@
+OMP_NEST_LOCK_25_KIND = @OMP_NEST_LOCK_25_KIND@
+OMP_NEST_LOCK_25_SIZE = @OMP_NEST_LOCK_25_SIZE@
 OMP_NEST_LOCK_ALIGN = @OMP_NEST_LOCK_ALIGN@
 OMP_NEST_LOCK_KIND = @OMP_NEST_LOCK_KIND@
 OMP_NEST_LOCK_SIZE = @OMP_NEST_LOCK_SIZE@
index f11482c7315ffc86395e8feaf3fb57879ec94e09..f3f42de66193c9ae8aadf40639e5ef9a1b07d4f2 100644 (file)
@@ -31,8 +31,15 @@ if { $lang_test_file_found } {
     set ld_library_path "$always_ld_library_path:${blddir}/${lang_library_path}"
     set_ld_library_path_env_vars
 
+    set flags_file "${blddir}/../libstdc++-v3/scripts/testsuite_flags"
+    if { [file exists $flags_file] } {
+       set libstdcxx_includes [exec sh $flags_file --build-includes]
+    } else {
+       set libstdcxx_includes ""
+    }
+
     # Main loop.
-    gfortran-dg-runtest $tests ""
+    gfortran-dg-runtest $tests $libstdcxx_includes
 }
 
 # All done.
diff --git a/libgomp/testsuite/libgomp.c++/collapse-1.C b/libgomp/testsuite/libgomp.c++/collapse-1.C
new file mode 100644 (file)
index 0000000..132d35c
--- /dev/null
@@ -0,0 +1,29 @@
+// { dg-do run }
+
+#include <string.h>
+#include <stdlib.h>
+
+int
+main ()
+{
+  int i, j, k, l = 0;
+  int a[3][3][3];
+
+  memset (a, '\0', sizeof (a));
+  #pragma omp parallel for collapse(4 - 1) schedule(static, 4)
+    for (i = 0; i < 2; i++)
+      for (j = 0; j < 2; j++)
+       for (k = 0; k < 2; k++)
+         a[i][j][k] = i + j * 4 + k * 16;
+  #pragma omp parallel
+    {
+      #pragma omp for collapse(2) reduction(|:l) private (k)
+       for (i = 0; i < 2; i++)
+         for (j = 0; j < 2; j++)
+           for (k = 0; k < 2; k++)
+             if (a[i][j][k] != i + j * 4 + k * 16)
+               l = 1;
+    }
+  if (l)
+    abort ();
+}
diff --git a/libgomp/testsuite/libgomp.c++/collapse-2.C b/libgomp/testsuite/libgomp.c++/collapse-2.C
new file mode 100644 (file)
index 0000000..a42a1f0
--- /dev/null
@@ -0,0 +1,371 @@
+// { dg-do run }
+
+#include <omp.h>
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+extern "C" void abort ();
+
+template <typename T>
+class I
+{
+public:
+  typedef ptrdiff_t difference_type;
+  I ();
+  ~I ();
+  I (T *);
+  I (const I &);
+  T &operator * ();
+  T *operator -> ();
+  T &operator [] (const difference_type &) const;
+  I &operator = (const I &);
+  I &operator ++ ();
+  I operator ++ (int);
+  I &operator -- ();
+  I operator -- (int);
+  I &operator += (const difference_type &);
+  I &operator -= (const difference_type &);
+  I operator + (const difference_type &) const;
+  I operator - (const difference_type &) const;
+  template <typename S> friend bool operator == (I<S> &, I<S> &);
+  template <typename S> friend bool operator == (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator < (I<S> &, I<S> &);
+  template <typename S> friend bool operator < (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator <= (I<S> &, I<S> &);
+  template <typename S> friend bool operator <= (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator > (I<S> &, I<S> &);
+  template <typename S> friend bool operator > (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator >= (I<S> &, I<S> &);
+  template <typename S> friend bool operator >= (const I<S> &, const I<S> &);
+  template <typename S> friend typename I<S>::difference_type operator - (I<S> &, I<S> &);
+  template <typename S> friend typename I<S>::difference_type operator - (const I<S> &, const I<S> &);
+  template <typename S> friend I<S> operator + (typename I<S>::difference_type , const I<S> &);
+private:
+  T *p;
+};
+template <typename T> I<T>::I () : p (0) {}
+template <typename T> I<T>::~I () { p = (T *) 0; }
+template <typename T> I<T>::I (T *x) : p (x) {}
+template <typename T> I<T>::I (const I &x) : p (x.p) {}
+template <typename T> T &I<T>::operator * () { return *p; }
+template <typename T> T *I<T>::operator -> () { return p; }
+template <typename T> T &I<T>::operator [] (const difference_type &x) const { return p[x]; }
+template <typename T> I<T> &I<T>::operator = (const I &x) { p = x.p; return *this; }
+template <typename T> I<T> &I<T>::operator ++ () { ++p; return *this; }
+template <typename T> I<T> I<T>::operator ++ (int) { return I (p++); }
+template <typename T> I<T> &I<T>::operator -- () { --p; return *this; }
+template <typename T> I<T> I<T>::operator -- (int) { return I (p--); }
+template <typename T> I<T> &I<T>::operator += (const difference_type &x) { p += x; return *this; }
+template <typename T> I<T> &I<T>::operator -= (const difference_type &x) { p -= x; return *this; }
+template <typename T> I<T> I<T>::operator + (const difference_type &x) const { return I (p + x); }
+template <typename T> I<T> I<T>::operator - (const difference_type &x) const { return I (p - x); }
+template <typename T> bool operator == (I<T> &x, I<T> &y) { return x.p == y.p; }
+template <typename T> bool operator == (const I<T> &x, const I<T> &y) { return x.p == y.p; }
+template <typename T> bool operator != (I<T> &x, I<T> &y) { return !(x == y); }
+template <typename T> bool operator != (const I<T> &x, const I<T> &y) { return !(x == y); }
+template <typename T> bool operator < (I<T> &x, I<T> &y) { return x.p < y.p; }
+template <typename T> bool operator < (const I<T> &x, const I<T> &y) { return x.p < y.p; }
+template <typename T> bool operator <= (I<T> &x, I<T> &y) { return x.p <= y.p; }
+template <typename T> bool operator <= (const I<T> &x, const I<T> &y) { return x.p <= y.p; }
+template <typename T> bool operator > (I<T> &x, I<T> &y) { return x.p > y.p; }
+template <typename T> bool operator > (const I<T> &x, const I<T> &y) { return x.p > y.p; }
+template <typename T> bool operator >= (I<T> &x, I<T> &y) { return x.p >= y.p; }
+template <typename T> bool operator >= (const I<T> &x, const I<T> &y) { return x.p >= y.p; }
+template <typename T> typename I<T>::difference_type operator - (I<T> &x, I<T> &y) { return x.p - y.p; }
+template <typename T> typename I<T>::difference_type operator - (const I<T> &x, const I<T> &y) { return x.p - y.p; }
+template <typename T> I<T> operator + (typename I<T>::difference_type x, const I<T> &y) { return I<T> (x + y.p); }
+
+template <typename T>
+class J
+{
+public:
+  J(const I<T> &x, const I<T> &y) : b (x), e (y) {}
+  const I<T> &begin ();
+  const I<T> &end ();
+private:
+  I<T> b, e;
+};
+
+template <typename T> const I<T> &J<T>::begin () { return b; }
+template <typename T> const I<T> &J<T>::end () { return e; }
+
+int results[2000];
+
+void
+f1 (J<int> x, J<int> y, J<int> z)
+{
+  I<int> i, j, k;
+  int l, f = 0, n = 0, m = 0;
+#pragma omp parallel shared (i, j, k, l) firstprivate (f) \
+                    reduction (+:n, m) num_threads (8)
+  {
+  #pragma omp for lastprivate (i, j, k, l) schedule (static, 9) \
+                 collapse (4)
+    for (i = x.begin (); i < x.end (); ++i)
+      for (j = y.begin (); j <= y.end (); j += 1)
+       for (l = 0; l < 1; l++)
+         for (k = z.begin () + 3; k < z.end () - 3; k++)
+           if (omp_get_num_threads () == 8
+               && ((*i + 2) * 12 + (*j + 5) * 4 + (*k - 13)
+                   != (omp_get_thread_num () * 9 + f++)))
+             n++;
+           else
+             m++;
+  }
+  if (n || i != x.end () || j != y.end () + 1 || k != z.end () - 3
+      || m != 72 || l != 1)
+    abort ();
+}
+
+void
+f2 (J<int> x, J<int> y, J<int> z)
+{
+  int f = 0, n = 0, m = 0;
+#pragma omp parallel for firstprivate (f) reduction (+:n, m) \
+                        num_threads (8) schedule (static, 9) \
+                        collapse (6 - 2)
+  for (I<int> i = x.end () - 1; i >= x.begin (); --i)
+    for (int l = -131; l >= -131; l--)
+      for (I<int> j = y.end (); j > y.begin () - 1; j -= 1)
+       {
+         for (I<int> k = z.end () - 4; k >= z.begin () + 3; k--)
+           if (omp_get_num_threads () == 8
+               && ((3 - *i) * 12 + (-3 - *j) * 4 + (16 - *k)
+                   != (omp_get_thread_num () * 9 + f++)))
+             n++;
+           else
+             m++;
+       }
+  if (n || m != 72)
+    abort ();
+}
+
+template <typename T>
+void
+f3 (J<int> x, J<int> y, J<int> z)
+{
+  I<int> i, j, k;
+  int l, f = 0, n = 0, m = 0;
+#pragma omp parallel shared (i, j, k, l) firstprivate (f) \
+                    reduction (+:n, m) num_threads (8)
+  {
+  #pragma omp for lastprivate (i, j, k, l) schedule (static, 9) \
+                 collapse (4)
+    for (i = x.begin (); i < x.end (); ++i)
+      for (j = y.begin (); j <= y.end (); j += 1)
+       for (k = z.begin () + 3; k < z.end () - 3; k++)
+         for (l = 7; l <= 7; l++)
+           if (omp_get_num_threads () == 8
+               && ((*i + 2) * 12 + (*j + 5) * 4 + (*k - 13)
+                   != (omp_get_thread_num () * 9 + f++)))
+             n++;
+           else
+             m++;
+  }
+  if (n || i != x.end () || j != y.end () + 1 || k != z.end () - 3
+      || m != 72 || l != 8)
+    abort ();
+}
+
+template <typename T>
+void
+f4 (J<int> x, J<int> y, J<int> z)
+{
+  int f = 0, n = 0, m = 0;
+#pragma omp parallel for firstprivate (f) reduction (+:n, m) \
+                        num_threads (8) schedule (static, 9) \
+                        collapse (5 - 2)
+  for (I<int> i = x.end () - 1; i >= x.begin (); --i)
+    {
+      for (I<int> j = y.end (); j > y.begin () - 1; j -= 1)
+       {
+         for (I<int> k = z.end () - 4; k >= z.begin () + 3; k--)
+           if (omp_get_num_threads () == 8
+               && ((3 - *i) * 12 + (-3 - *j) * 4 + (16 - *k)
+                   != (omp_get_thread_num () * 9 + f++)))
+             n++;
+           else
+             m++;
+       }
+    }
+  if (n || m != 72)
+    abort ();
+}
+
+template <typename T>
+void
+f5 (J<int> x, J<int> y, J<int> z)
+{
+  I<int> i, j, k;
+  int f = 0, n = 0, m = 0;
+#pragma omp parallel shared (i, j, k) firstprivate (f) \
+                    reduction (+:n, m) num_threads (8)
+  {
+  #pragma omp for lastprivate (i, j, k) schedule (static, 9) \
+                 collapse (3)
+    for (i = x.begin (); i < x.end (); ++i)
+      for (j = y.begin (); j <= y.end (); j += (T) 1)
+       {
+         for (k = z.begin () + 3; k < z.end () - 3; k++)
+           if (omp_get_num_threads () == 8
+               && ((*i + 2) * 12 + (*j + 5) * 4 + (*k - 13)
+                   != (omp_get_thread_num () * 9 + f++)))
+             n++;
+           else
+             m++;
+       }
+  }
+  if (n || i != x.end () || j != y.end () + 1 || k != z.end () - 3
+      || m != 72)
+    abort ();
+}
+
+template <typename T>
+void
+f6 (J<int> x, J<int> y, J<int> z)
+{
+  int f = 0, n = 0, m = 0;
+#pragma omp parallel for firstprivate (f) reduction (+:n, m) \
+                        num_threads (8) schedule (static, 9) \
+                        collapse (5 - 2)
+  for (I<int> i = x.end () - 1; i >= x.begin (); --i)
+    {
+      for (I<int> j = y.end (); j > y.begin () - 1; j -= 1)
+       {
+         for (I<int> k = z.end () - 4; k >= z.begin () + (T) 3; k--)
+           if (omp_get_num_threads () == 8
+               && ((3 - *i) * 12 + (-3 - *j) * 4 + (16 - *k)
+                   != (omp_get_thread_num () * 9 + f++)))
+             n++;
+           else
+             m++;
+       }
+    }
+  if (n || m != 72)
+    abort ();
+}
+
+template <typename T>
+void
+f7 (J<T> x, J<T> y, J<T> z)
+{
+  I<T> i, j, k, o = y.begin ();
+  T l, f = 0, n = 0, m = 0;
+#pragma omp parallel shared (i, j, k, l) firstprivate (f) \
+                    reduction (+:n, m) num_threads (8)
+  {
+  #pragma omp for lastprivate (i, j, k, l) schedule (static, 9) \
+                 collapse (4)
+    for (i = x.begin (); i < x.end (); ++i)
+      for (j = y.begin (); j <= y.end (); j += 1)
+       for (l = *o; l <= *o; l = 1 + l)
+         for (k = z.begin () + 3; k < z.end () - 3; k++)
+           if (omp_get_num_threads () == 8
+               && ((*i + 2) * 12 + (*j + 5) * 4 + (*k - 13)
+                   != (omp_get_thread_num () * 9 + f++)))
+             n++;
+           else
+             m++;
+  }
+  if (n || i != x.end () || j != y.end () + 1 || k != z.end () - 3
+      || m != 72 || l != *o + 1)
+    abort ();
+}
+
+template <typename T>
+void
+f8 (J<T> x, J<T> y, J<T> z)
+{
+  T f = 0, n = 0, m = 0;
+#pragma omp parallel for firstprivate (f) reduction (+:n, m) \
+                        num_threads (8) schedule (static, 9) \
+                        collapse (6 - 2)
+  for (I<T> i = x.end () - 1; i >= x.begin (); --i)
+    for (T l = 0; l < 1; l++)
+      for (I<T> j = y.end (); j > y.begin () - 1; j -= 1)
+       {
+         for (I<T> k = z.end () - 4; k >= z.begin () + 3; k--)
+           if (omp_get_num_threads () == 8
+               && ((3 - *i) * 12 + (-3 - *j) * 4 + (16 - *k)
+                   != (omp_get_thread_num () * 9 + f++)))
+             n++;
+           else
+             m++;
+       }
+  if (n || m != 72)
+    abort ();
+}
+
+template <typename S, typename T>
+void
+f9 (J<T> x, J<T> y, J<T> z)
+{
+  S i, j, k, o = y.begin ();
+  T l, f = 0, n = 0, m = 0;
+#pragma omp parallel shared (i, j, k, l) firstprivate (f) \
+                    reduction (+:n, m) num_threads (8)
+  {
+  #pragma omp for lastprivate (i, j, k, l) schedule (static, 9) \
+                 collapse (4)
+    for (i = x.begin (); i < x.end (); ++i)
+      for (j = y.begin (); j <= y.end (); j += 1)
+       for (l = *o; l <= *o; l = 1 + l)
+         for (k = z.begin () + 3; k < z.end () - 3; k++)
+           if (omp_get_num_threads () == 8
+               && ((*i + 2) * 12 + (*j + 5) * 4 + (*k - 13)
+                   != (omp_get_thread_num () * 9 + f++)))
+             n++;
+           else
+             m++;
+  }
+  if (n || i != x.end () || j != y.end () + 1 || k != z.end () - 3
+      || m != 72 || l != *o + 1)
+    abort ();
+}
+
+template <typename S, typename T>
+void
+f10 (J<T> x, J<T> y, J<T> z)
+{
+  T f = 0, n = 0, m = 0;
+#pragma omp parallel for firstprivate (f) reduction (+:n, m) \
+                        num_threads (8) schedule (static, 9) \
+                        collapse (6 - 2)
+  for (S i = x.end () - 1; i >= x.begin (); --i)
+    for (T l = 0; l < 1; l++)
+      for (S j = y.end (); j > y.begin () - 1; j -= 1)
+       {
+         for (S k = z.end () - 4; k >= z.begin () + 3; k--)
+           if (omp_get_num_threads () == 8
+               && ((3 - *i) * 12 + (-3 - *j) * 4 + (16 - *k)
+                   != (omp_get_thread_num () * 9 + f++)))
+             n++;
+           else
+             m++;
+       }
+  if (n || m != 72)
+    abort ();
+}
+
+int
+main ()
+{
+  int a[2000];
+  long b[2000];
+  for (int i = 0; i < 2000; i++)
+    {
+      a[i] = i - 1000;
+      b[i] = i - 1000;
+    }
+  J<int> x (&a[998], &a[1004]);
+  J<int> y (&a[995], &a[997]);
+  J<int> z (&a[1010], &a[1020]);
+  f1 (x, y, z);
+  f2 (x, y, z);
+  f3 <int> (x, y, z);
+  f4 <int> (x, y, z);
+  f5 <int> (x, y, z);
+  f6 <int> (x, y, z);
+  f7 <int> (x, y, z);
+  f8 <int> (x, y, z);
+  f9 <I<int>, int> (x, y, z);
+  f10 <I<int>, int> (x, y, z);
+}
diff --git a/libgomp/testsuite/libgomp.c++/ctor-10.C b/libgomp/testsuite/libgomp.c++/ctor-10.C
new file mode 100644 (file)
index 0000000..f46e45e
--- /dev/null
@@ -0,0 +1,78 @@
+// { dg-do run }
+// { dg-require-effective-target tls_runtime }
+
+#include <omp.h>
+#include <assert.h>
+
+#define N 10
+#define THR 4
+
+struct B
+{
+  B();
+  B(const B &);
+  ~B();
+  B& operator=(const B &);
+  void doit();
+  static B *base;
+  static B *threadbase;
+#pragma omp threadprivate(threadbase)
+};
+
+B *B::base;
+B *B::threadbase;
+static unsigned cmask[THR];
+static unsigned dmask[THR];
+
+B::B()
+{
+  assert (base == 0);
+}
+
+B::B(const B &b)
+{
+  unsigned index = &b - base;
+  assert (index < N);
+  cmask[omp_get_thread_num()] |= 1u << index;
+}
+
+B::~B()
+{
+  if (threadbase)
+    {
+      unsigned index = this - threadbase;
+      assert (index < N);
+      dmask[omp_get_thread_num()] |= 1u << index;
+    }
+}
+
+void foo()
+{
+  B b[N];
+
+  B::base = b;
+
+  #pragma omp parallel firstprivate(b)
+    {
+      assert (omp_get_num_threads () == THR);
+      B::threadbase = b;
+    }
+
+  B::threadbase = 0;
+}
+
+int main()
+{
+  omp_set_dynamic (0);
+  omp_set_num_threads (THR);
+  foo();
+
+  for (int i = 0; i < THR; ++i)
+    {
+      unsigned xmask = (1u << N) - 1;
+      assert (cmask[i] == xmask);
+      assert (dmask[i] == xmask);
+    }
+
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c++/for-1.C b/libgomp/testsuite/libgomp.c++/for-1.C
new file mode 100644 (file)
index 0000000..1c71346
--- /dev/null
@@ -0,0 +1,291 @@
+// { dg-do run }
+
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+extern "C" void abort ();
+
+template <typename T>
+class I
+{
+public:
+  typedef ptrdiff_t difference_type;
+  I ();
+  ~I ();
+  I (T *);
+  I (const I &);
+  T &operator * ();
+  T *operator -> ();
+  T &operator [] (const difference_type &) const;
+  I &operator = (const I &);
+  I &operator ++ ();
+  I operator ++ (int);
+  I &operator -- ();
+  I operator -- (int);
+  I &operator += (const difference_type &);
+  I &operator -= (const difference_type &);
+  I operator + (const difference_type &) const;
+  I operator - (const difference_type &) const;
+  template <typename S> friend bool operator == (I<S> &, I<S> &);
+  template <typename S> friend bool operator == (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator < (I<S> &, I<S> &);
+  template <typename S> friend bool operator < (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator <= (I<S> &, I<S> &);
+  template <typename S> friend bool operator <= (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator > (I<S> &, I<S> &);
+  template <typename S> friend bool operator > (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator >= (I<S> &, I<S> &);
+  template <typename S> friend bool operator >= (const I<S> &, const I<S> &);
+  template <typename S> friend typename I<S>::difference_type operator - (I<S> &, I<S> &);
+  template <typename S> friend typename I<S>::difference_type operator - (const I<S> &, const I<S> &);
+  template <typename S> friend I<S> operator + (typename I<S>::difference_type , const I<S> &);
+private:
+  T *p;
+};
+template <typename T> I<T>::I () : p (0) {}
+template <typename T> I<T>::~I () {}
+template <typename T> I<T>::I (T *x) : p (x) {}
+template <typename T> I<T>::I (const I &x) : p (x.p) {}
+template <typename T> T &I<T>::operator * () { return *p; }
+template <typename T> T *I<T>::operator -> () { return p; }
+template <typename T> T &I<T>::operator [] (const difference_type &x) const { return p[x]; }
+template <typename T> I<T> &I<T>::operator = (const I &x) { p = x.p; return *this; }
+template <typename T> I<T> &I<T>::operator ++ () { ++p; return *this; }
+template <typename T> I<T> I<T>::operator ++ (int) { return I (p++); }
+template <typename T> I<T> &I<T>::operator -- () { --p; return *this; }
+template <typename T> I<T> I<T>::operator -- (int) { return I (p--); }
+template <typename T> I<T> &I<T>::operator += (const difference_type &x) { p += x; return *this; }
+template <typename T> I<T> &I<T>::operator -= (const difference_type &x) { p -= x; return *this; }
+template <typename T> I<T> I<T>::operator + (const difference_type &x) const { return I (p + x); }
+template <typename T> I<T> I<T>::operator - (const difference_type &x) const { return I (p - x); }
+template <typename T> bool operator == (I<T> &x, I<T> &y) { return x.p == y.p; }
+template <typename T> bool operator == (const I<T> &x, const I<T> &y) { return x.p == y.p; }
+template <typename T> bool operator != (I<T> &x, I<T> &y) { return !(x == y); }
+template <typename T> bool operator != (const I<T> &x, const I<T> &y) { return !(x == y); }
+template <typename T> bool operator < (I<T> &x, I<T> &y) { return x.p < y.p; }
+template <typename T> bool operator < (const I<T> &x, const I<T> &y) { return x.p < y.p; }
+template <typename T> bool operator <= (I<T> &x, I<T> &y) { return x.p <= y.p; }
+template <typename T> bool operator <= (const I<T> &x, const I<T> &y) { return x.p <= y.p; }
+template <typename T> bool operator > (I<T> &x, I<T> &y) { return x.p > y.p; }
+template <typename T> bool operator > (const I<T> &x, const I<T> &y) { return x.p > y.p; }
+template <typename T> bool operator >= (I<T> &x, I<T> &y) { return x.p >= y.p; }
+template <typename T> bool operator >= (const I<T> &x, const I<T> &y) { return x.p >= y.p; }
+template <typename T> typename I<T>::difference_type operator - (I<T> &x, I<T> &y) { return x.p - y.p; }
+template <typename T> typename I<T>::difference_type operator - (const I<T> &x, const I<T> &y) { return x.p - y.p; }
+template <typename T> I<T> operator + (typename I<T>::difference_type x, const I<T> &y) { return I<T> (x + y.p); }
+
+template <typename T>
+class J
+{
+public:
+  J(const I<T> &x, const I<T> &y) : b (x), e (y) {}
+  const I<T> &begin ();
+  const I<T> &end ();
+private:
+  I<T> b, e;
+};
+
+template <typename T> const I<T> &J<T>::begin () { return b; }
+template <typename T> const I<T> &J<T>::end () { return e; }
+
+int results[2000];
+
+template <typename T>
+void
+baz (I<T> &i)
+{
+  if (*i < 0 || *i >= 2000)
+    abort ();
+  results[*i]++;
+}
+
+void
+f1 (const I<int> &x, const I<int> &y)
+{
+#pragma omp parallel for
+  for (I<int> i = x; i <= y; i += 6)
+    baz (i);
+}
+
+void
+f2 (const I<int> &x, const I<int> &y)
+{
+  I<int> i;
+#pragma omp parallel for private(i)
+  for (i = x; i < y - 1; i = 1 - 6 + 7 + i)
+    baz (i);
+}
+
+template <typename T>
+void
+f3 (const I<int> &x, const I<int> &y)
+{
+#pragma omp parallel for
+  for (I<int> i = x; i <= y; i = i + 9 - 8)
+    baz (i);
+}
+
+template <typename T>
+void
+f4 (const I<int> &x, const I<int> &y)
+{
+  I<int> i;
+#pragma omp parallel for lastprivate(i)
+  for (i = x + 2000 - 64; i > y + 10; --i)
+    baz (i);
+}
+
+void
+f5 (const I<int> &x, const I<int> &y)
+{
+#pragma omp parallel for
+  for (I<int> i = x + 2000 - 64; i > y + 10; i -= 10)
+    baz (i);
+}
+
+template <int N>
+void
+f6 (const I<int> &x, const I<int> &y)
+{
+#pragma omp parallel for
+  for (I<int> i = x + 2000 - 64; i > y + 10; i = i - 12 + 2)
+    {
+      I<int> j = i + N;
+      baz (j);
+    }
+}
+
+template <int N>
+void
+f7 (I<int> i, const I<int> &x, const I<int> &y)
+{
+#pragma omp parallel for
+  for (i = x - 10; i <= y + 10; i += N)
+    baz (i);
+}
+
+template <int N>
+void
+f8 (J<int> j)
+{
+  I<int> i;
+#pragma omp parallel for
+  for (i = j.begin (); i <= j.end () + N; i += 2)
+    baz (i);
+}
+
+template <typename T, int N>
+void
+f9 (const I<T> &x, const I<T> &y)
+{
+#pragma omp parallel for
+  for (I<T> i = x; i <= y; i = i + N)
+    baz (i);
+}
+
+template <typename T, int N>
+void
+f10 (const I<T> &x, const I<T> &y)
+{
+  I<T> i;
+#pragma omp parallel for
+  for (i = x; i > y; i = i + N)
+    baz (i);
+}
+
+template <typename T>
+void
+f11 (const T &x, const T &y)
+{
+#pragma omp parallel
+  {
+#pragma omp for nowait
+    for (T i = x; i <= y; i += 3)
+      baz (i);
+#pragma omp single
+    {
+      T j = y + 3;
+      baz (j);
+    }
+  }
+}
+
+template <typename T>
+void
+f12 (const T &x, const T &y)
+{
+  T i;
+#pragma omp parallel for
+  for (i = x; i > y; --i)
+    baz (i);
+}
+
+template <int N>
+struct K
+{
+  template <typename T>
+  static void
+  f13 (const T &x, const T &y)
+  {
+#pragma omp parallel for
+    for (T i = x; i <= y + N; i += N)
+      baz (i);
+  }
+};
+
+#define check(expr) \
+  for (int i = 0; i < 2000; i++)                       \
+    if (expr)                                          \
+      {                                                        \
+       if (results[i] != 1)                            \
+         abort ();                                     \
+       results[i] = 0;                                 \
+      }                                                        \
+    else if (results[i])                               \
+      abort ()
+
+int
+main ()
+{
+  int a[2000];
+  long b[2000];
+  for (int i = 0; i < 2000; i++)
+    {
+      a[i] = i;
+      b[i] = i;
+    }
+  f1 (&a[10], &a[1990]);
+  check (i >= 10 && i <= 1990 && (i - 10) % 6 == 0);
+  f2 (&a[0], &a[1999]);
+  check (i < 1998 && (i & 1) == 0);
+  f3<char> (&a[20], &a[1837]);
+  check (i >= 20 && i <= 1837);
+  f4<int> (&a[0], &a[30]);
+  check (i > 40 && i <= 2000 - 64);
+  f5 (&a[0], &a[100]);
+  check (i >= 116 && i <= 2000 - 64 && (i - 116) % 10 == 0);
+  f6<-10> (&a[10], &a[110]);
+  check (i >= 116 && i <= 2000 - 64 && (i - 116) % 10 == 0);
+  f7<6> (I<int> (), &a[12], &a[1800]);
+  check (i >= 2 && i <= 1808 && (i - 2) % 6 == 0);
+  f8<121> (J<int> (&a[14], &a[1803]));
+  check (i >= 14 && i <= 1924 && (i & 1) == 0);
+  f9<int, 7> (&a[33], &a[1967]);
+  check (i >= 33 && i <= 1967 && (i - 33) % 7 == 0);
+  f10<int, -7> (&a[1939], &a[17]);
+  check (i >= 21 && i <= 1939 && (i - 21) % 7 == 0);
+  f11<I<int> > (&a[16], &a[1981]);
+  check (i >= 16 && i <= 1984 && (i - 16) % 3 == 0);
+  f12<I<int> > (&a[1761], &a[37]);
+  check (i > 37 && i <= 1761);
+  K<5>::f13<I<int> > (&a[1], &a[1935]);
+  check (i >= 1 && i <= 1936 && (i - 1) % 5 == 0);
+  f9<long, 7> (&b[33], &b[1967]);
+  check (i >= 33 && i <= 1967 && (i - 33) % 7 == 0);
+  f10<long, -7> (&b[1939], &b[17]);
+  check (i >= 21 && i <= 1939 && (i - 21) % 7 == 0);
+  f11<I<long> > (&b[16], &b[1981]);
+  check (i >= 16 && i <= 1984 && (i - 16) % 3 == 0);
+  f12<I<long> > (&b[1761], &b[37]);
+  check (i > 37 && i <= 1761);
+  K<5>::f13<I<long> > (&b[1], &b[1935]);
+  check (i >= 1 && i <= 1936 && (i - 1) % 5 == 0);
+}
diff --git a/libgomp/testsuite/libgomp.c++/for-2.C b/libgomp/testsuite/libgomp.c++/for-2.C
new file mode 100644 (file)
index 0000000..98ffa1a
--- /dev/null
@@ -0,0 +1,182 @@
+// { dg-do run }
+
+extern "C" void abort ();
+
+template <typename T>
+class J
+{
+public:
+  J(T x, T y) : b (x), e (y) {}
+  T begin ();
+  T end ();
+private:
+  T b, e;
+};
+
+template <typename T> T J<T>::begin () { return b; }
+template <typename T> T J<T>::end () { return e; }
+
+int results[2000];
+
+void
+baz (int i)
+{
+  if (i < 0 || i >= 2000)
+    abort ();
+  results[i]++;
+}
+
+void
+f1 (int x, int y)
+{
+#pragma omp parallel for
+  for (int i = x; i <= y; i += 6)
+    baz (i);
+}
+
+void
+f2 (int x, int y)
+{
+  int i;
+#pragma omp parallel for private(i)
+  for (i = x; i < y - 1; i = 1 - 6 + 7 + i)
+    baz (i);
+}
+
+template <typename T>
+void
+f3 (int x, int y)
+{
+#pragma omp parallel for
+  for (int i = x; i <= y; i = i + 9 - 8)
+    baz (i);
+}
+
+template <typename T>
+void
+f4 (int x, int y)
+{
+  int i;
+#pragma omp parallel for lastprivate(i)
+  for (i = x + 2000 - 64; i > y + 10; --i)
+    baz (i);
+}
+
+void
+f5 (int x, int y)
+{
+#pragma omp parallel for
+  for (int i = x + 2000 - 64; i > y + 10L; i -= 10L)
+    baz (i);
+}
+
+template <int N>
+void
+f6 (int x, int y)
+{
+#pragma omp parallel for
+  for (int i = x + 2000 - 64; i > y + 10L; i = i - 12 + 2L)
+    baz (i + N);
+}
+
+template <long N>
+void
+f7 (int i, int x, int y)
+{
+#pragma omp parallel for
+  for (i = x - 10; i <= y + 10; i += N)
+    baz (i);
+}
+
+template <long N>
+void
+f8 (J<int> j)
+{
+  int i;
+#pragma omp parallel for
+  for (i = j.begin (); i <= j.end () + N; i += 2)
+    baz (i);
+}
+
+template <typename T, long N>
+void
+f9 (T x, T y)
+{
+#pragma omp parallel for
+  for (T i = x; i <= y; i = i + N)
+    baz (i);
+}
+
+template <typename T, long N>
+void
+f10 (T x, T y)
+{
+  T i;
+#pragma omp parallel for
+  for (i = x; i > y; i = i + N)
+    baz (i);
+}
+
+template <typename T>
+void
+f11 (T x, long y)
+{
+#pragma omp parallel
+  {
+#pragma omp for nowait
+    for (T i = x; i <= y; i += 3L)
+      baz (i);
+#pragma omp single
+    baz (y + 3);
+  }
+}
+
+template <typename T>
+void
+f12 (T x, T y)
+{
+  T i;
+#pragma omp parallel for
+  for (i = x; i > y; --i)
+    baz (i);
+}
+
+#define check(expr) \
+  for (int i = 0; i < 2000; i++)                       \
+    if (expr)                                          \
+      {                                                        \
+       if (results[i] != 1)                            \
+         abort ();                                     \
+       results[i] = 0;                                 \
+      }                                                        \
+    else if (results[i])                               \
+      abort ()
+
+int
+main ()
+{
+  f1 (10, 1990);
+  check (i >= 10 && i <= 1990 && (i - 10) % 6 == 0);
+  f2 (0, 1999);
+  check (i < 1998 && (i & 1) == 0);
+  f3<char> (20, 1837);
+  check (i >= 20 && i <= 1837);
+  f4<int> (0, 30);
+  check (i > 40 && i <= 2000 - 64);
+  f5 (0, 100);
+  check (i >= 116 && i <= 2000 - 64 && (i - 116) % 10 == 0);
+  f6<-10> (10, 110);
+  check (i >= 116 && i <= 2000 - 64 && (i - 116) % 10 == 0);
+  f7<6> (0, 12, 1800);
+  check (i >= 2 && i <= 1808 && (i - 2) % 6 == 0);
+  f8<121> (J<int> (14, 1803));
+  check (i >= 14 && i <= 1924 && (i & 1) == 0);
+  f9<int, 7> (33, 1967);
+  check (i >= 33 && i <= 1967 && (i - 33) % 7 == 0);
+  f10<int, -7> (1939, 17);
+  check (i >= 21 && i <= 1939 && (i - 21) % 7 == 0);
+  f11<int> (16, 1981);
+  check (i >= 16 && i <= 1984 && (i - 16) % 3 == 0);
+  f12<int> (1761, 37);
+  check (i > 37 && i <= 1761);
+}
diff --git a/libgomp/testsuite/libgomp.c++/for-3.C b/libgomp/testsuite/libgomp.c++/for-3.C
new file mode 100644 (file)
index 0000000..235f838
--- /dev/null
@@ -0,0 +1,239 @@
+// { dg-do run }
+
+#include <vector>
+#include <cstdlib>
+
+template <typename T>
+class J
+{
+public:
+  typedef typename std::vector<T>::const_iterator const_iterator;
+  J(const const_iterator &x, const const_iterator &y) : b (x), e (y) {}
+  const const_iterator &begin ();
+  const const_iterator &end ();
+private:
+  const_iterator b, e;
+};
+
+template <typename T>
+const typename std::vector<T>::const_iterator &J<T>::begin () { return b; }
+template <typename T>
+const typename std::vector<T>::const_iterator &J<T>::end () { return e; }
+
+int results[2000];
+
+template <typename T>
+void
+baz (T &i)
+{
+  if (*i < 0 || *i >= 2000)
+    std::abort ();
+  results[*i]++;
+}
+
+void
+f1 (const std::vector<int>::const_iterator &x,
+    const std::vector<int>::const_iterator &y)
+{
+#pragma omp parallel for
+  for (std::vector<int>::const_iterator i = x; i <= y; i += 6)
+    baz (i);
+}
+
+void
+f2 (const std::vector<int>::const_iterator &x,
+    const std::vector<int>::const_iterator &y)
+{
+  std::vector<int>::const_iterator i;
+#pragma omp parallel for private(i)
+  for (i = x; i < y - 1; i = 1 - 6 + 7 + i)
+    baz (i);
+}
+
+template <typename T>
+void
+f3 (const std::vector<int>::const_iterator &x,
+    const std::vector<int>::const_iterator &y)
+{
+#pragma omp parallel for schedule (dynamic, 6)
+  for (std::vector<int>::const_iterator i = x; i <= y; i = i + 9 - 8)
+    baz (i);
+}
+
+template <typename T>
+void
+f4 (const std::vector<int>::const_iterator &x,
+    const std::vector<int>::const_iterator &y)
+{
+  std::vector<int>::const_iterator i;
+#pragma omp parallel for lastprivate(i)
+  for (i = x + 2000 - 64; i > y + 10; --i)
+    baz (i);
+}
+
+void
+f5 (const std::vector<int>::const_iterator &x,
+    const std::vector<int>::const_iterator &y)
+{
+#pragma omp parallel for schedule (static, 10)
+  for (std::vector<int>::const_iterator i = x + 2000 - 64; i > y + 10; i -= 10)
+    baz (i);
+}
+
+template <int N>
+void
+f6 (const std::vector<int>::const_iterator &x,
+    const std::vector<int>::const_iterator &y)
+{
+#pragma omp parallel for schedule (runtime)
+  for (std::vector<int>::const_iterator i = x + 2000 - 64;
+       i > y + 10; i = i - 12 + 2)
+    {
+      std::vector<int>::const_iterator j = i + N;
+      baz (j);
+    }
+}
+
+template <int N>
+void
+f7 (std::vector<int>::const_iterator i,
+    const std::vector<int>::const_iterator &x,
+    const std::vector<int>::const_iterator &y)
+{
+#pragma omp parallel for schedule (dynamic, 6)
+  for (i = x - 10; i <= y + 10; i += N)
+    baz (i);
+}
+
+template <int N>
+void
+f8 (J<int> j)
+{
+  std::vector<int>::const_iterator i;
+#pragma omp parallel for schedule (dynamic, 40)
+  for (i = j.begin (); i <= j.end () + N; i += 2)
+    baz (i);
+}
+
+template <typename T, int N>
+void
+f9 (const typename std::vector<T>::const_iterator &x,
+    const typename std::vector<T>::const_iterator &y)
+{
+#pragma omp parallel for schedule (static, 25)
+  for (typename std::vector<T>::const_iterator i = x; i <= y; i = i + N)
+    baz (i);
+}
+
+template <typename T, int N>
+void
+f10 (const typename std::vector<T>::const_iterator &x,
+     const typename std::vector<T>::const_iterator &y)
+{
+  typename std::vector<T>::const_iterator i;
+#pragma omp parallel for
+  for (i = x; i > y; i = i + N)
+    baz (i);
+}
+
+template <typename T>
+void
+f11 (const T &x, const T &y)
+{
+#pragma omp parallel
+  {
+#pragma omp for nowait schedule (static, 2)
+    for (T i = x; i <= y; i += 3)
+      baz (i);
+#pragma omp single
+    {
+      T j = y + 3;
+      baz (j);
+    }
+  }
+}
+
+template <typename T>
+void
+f12 (const T &x, const T &y)
+{
+  T i;
+#pragma omp parallel for schedule (dynamic, 130)
+  for (i = x; i > y; --i)
+    baz (i);
+}
+
+template <int N>
+struct K
+{
+  template <typename T>
+  static void
+  f13 (const T &x, const T &y)
+  {
+#pragma omp parallel for schedule (runtime)
+    for (T i = x; i <= y + N; i += N)
+      baz (i);
+  }
+};
+
+#define check(expr) \
+  for (int i = 0; i < 2000; i++)                       \
+    if (expr)                                          \
+      {                                                        \
+       if (results[i] != 1)                            \
+         std::abort ();                                \
+       results[i] = 0;                                 \
+      }                                                        \
+    else if (results[i])                               \
+      std::abort ()
+
+int
+main ()
+{
+  std::vector<int> a(2000);
+  std::vector<long> b(2000);
+  for (int i = 0; i < 2000; i++)
+    {
+      a[i] = i;
+      b[i] = i;
+    }
+  f1 (a.begin () + 10, a.begin () + 1990);
+  check (i >= 10 && i <= 1990 && (i - 10) % 6 == 0);
+  f2 (a.begin () + 0, a.begin () + 1999);
+  check (i < 1998 && (i & 1) == 0);
+  f3<char> (a.begin () + 20, a.begin () + 1837);
+  check (i >= 20 && i <= 1837);
+  f4<int> (a.begin () + 0, a.begin () + 30);
+  check (i > 40 && i <= 2000 - 64);
+  f5 (a.begin () + 0, a.begin () + 100);
+  check (i >= 116 && i <= 2000 - 64 && (i - 116) % 10 == 0);
+  f6<-10> (a.begin () + 10, a.begin () + 110);
+  check (i >= 116 && i <= 2000 - 64 && (i - 116) % 10 == 0);
+  f7<6> (std::vector<int>::const_iterator (), a.begin () + 12,
+        a.begin () + 1800);
+  check (i >= 2 && i <= 1808 && (i - 2) % 6 == 0);
+  f8<121> (J<int> (a.begin () + 14, a.begin () + 1803));
+  check (i >= 14 && i <= 1924 && (i & 1) == 0);
+  f9<int, 7> (a.begin () + 33, a.begin () + 1967);
+  check (i >= 33 && i <= 1967 && (i - 33) % 7 == 0);
+  f10<int, -7> (a.begin () + 1939, a.begin () + 17);
+  check (i >= 21 && i <= 1939 && (i - 21) % 7 == 0);
+  f11<std::vector<int>::const_iterator > (a.begin () + 16, a.begin () + 1981);
+  check (i >= 16 && i <= 1984 && (i - 16) % 3 == 0);
+  f12<std::vector<int>::const_iterator > (a.begin () + 1761, a.begin () + 37);
+  check (i > 37 && i <= 1761);
+  K<5>::f13<std::vector<int>::const_iterator > (a.begin () + 1,
+                                               a.begin () + 1935);
+  check (i >= 1 && i <= 1936 && (i - 1) % 5 == 0);
+  f9<long, 7> (b.begin () + 33, b.begin () + 1967);
+  check (i >= 33 && i <= 1967 && (i - 33) % 7 == 0);
+  f10<long, -7> (b.begin () + 1939, b.begin () + 17);
+  check (i >= 21 && i <= 1939 && (i - 21) % 7 == 0);
+  f11<std::vector<long>::const_iterator > (b.begin () + 16, b.begin () + 1981);
+  check (i >= 16 && i <= 1984 && (i - 16) % 3 == 0);
+  f12<std::vector<long>::const_iterator > (b.begin () + 1761, b.begin () + 37);
+  check (i > 37 && i <= 1761);
+  K<5>::f13<std::vector<long>::const_iterator > (b.begin () + 1,
+                                                b.begin () + 1935);
+  check (i >= 1 && i <= 1936 && (i - 1) % 5 == 0);
+}
diff --git a/libgomp/testsuite/libgomp.c++/for-4.C b/libgomp/testsuite/libgomp.c++/for-4.C
new file mode 100644 (file)
index 0000000..c528ef9
--- /dev/null
@@ -0,0 +1,225 @@
+// { dg-do run }
+
+#include <string>
+#include <cstdlib>
+
+template <typename T>
+class J
+{
+public:
+  typedef typename std::basic_string<T>::iterator iterator;
+  J(const iterator &x, const iterator &y) : b (x), e (y) {}
+  const iterator &begin ();
+  const iterator &end ();
+private:
+  iterator b, e;
+};
+
+template <typename T>
+const typename std::basic_string<T>::iterator &J<T>::begin () { return b; }
+template <typename T>
+const typename std::basic_string<T>::iterator &J<T>::end () { return e; }
+
+template <typename T>
+void
+baz (T &i)
+{
+  if (*i < L'a' || *i >= L'a' + 2000)
+    std::abort ();
+  (*i)++;
+}
+
+void
+f1 (const std::basic_string<wchar_t>::iterator &x,
+    const std::basic_string<wchar_t>::iterator &y)
+{
+#pragma omp parallel for
+  for (std::basic_string<wchar_t>::iterator i = x; i <= y; i += 6)
+    baz (i);
+}
+
+void
+f2 (const std::basic_string<wchar_t>::iterator &x,
+    const std::basic_string<wchar_t>::iterator &y)
+{
+  std::basic_string<wchar_t>::iterator i;
+#pragma omp parallel for private(i)
+  for (i = x; i < y - 1; i = 1 - 6 + 7 + i)
+    baz (i);
+}
+
+template <typename T>
+void
+f3 (const std::basic_string<wchar_t>::iterator &x,
+    const std::basic_string<wchar_t>::iterator &y)
+{
+#pragma omp parallel for schedule (dynamic, 6)
+  for (std::basic_string<wchar_t>::iterator i = x; i <= y; i = i + 9 - 8)
+    baz (i);
+}
+
+template <typename T>
+void
+f4 (const std::basic_string<wchar_t>::iterator &x,
+    const std::basic_string<wchar_t>::iterator &y)
+{
+  std::basic_string<wchar_t>::iterator i;
+#pragma omp parallel for lastprivate(i)
+  for (i = x + 2000 - 64; i > y + 10; --i)
+    baz (i);
+}
+
+void
+f5 (const std::basic_string<wchar_t>::iterator &x,
+    const std::basic_string<wchar_t>::iterator &y)
+{
+#pragma omp parallel for schedule (static, 10)
+  for (std::basic_string<wchar_t>::iterator i = x + 2000 - 64;
+       i > y + 10; i -= 10)
+    baz (i);
+}
+
+template <int N>
+void
+f6 (const std::basic_string<wchar_t>::iterator &x,
+    const std::basic_string<wchar_t>::iterator &y)
+{
+#pragma omp parallel for schedule (runtime)
+  for (std::basic_string<wchar_t>::iterator i = x + 2000 - 64;
+       i > y + 10; i = i - 12 + 2)
+    {
+      std::basic_string<wchar_t>::iterator j = i + N;
+      baz (j);
+    }
+}
+
+template <int N>
+void
+f7 (std::basic_string<wchar_t>::iterator i,
+    const std::basic_string<wchar_t>::iterator &x,
+    const std::basic_string<wchar_t>::iterator &y)
+{
+#pragma omp parallel for schedule (dynamic, 6)
+  for (i = x - 10; i <= y + 10; i += N)
+    baz (i);
+}
+
+template <wchar_t N>
+void
+f8 (J<wchar_t> j)
+{
+  std::basic_string<wchar_t>::iterator i;
+#pragma omp parallel for schedule (dynamic, 40)
+  for (i = j.begin (); i <= j.end () + N; i += 2)
+    baz (i);
+}
+
+template <typename T, int N>
+void
+f9 (const typename std::basic_string<T>::iterator &x,
+    const typename std::basic_string<T>::iterator &y)
+{
+#pragma omp parallel for schedule (static, 25)
+  for (typename std::basic_string<T>::iterator i = x; i <= y; i = i + N)
+    baz (i);
+}
+
+template <typename T, int N>
+void
+f10 (const typename std::basic_string<T>::iterator &x,
+     const typename std::basic_string<T>::iterator &y)
+{
+  typename std::basic_string<T>::iterator i;
+#pragma omp parallel for
+  for (i = x; i > y; i = i + N)
+    baz (i);
+}
+
+template <typename T>
+void
+f11 (const T &x, const T &y)
+{
+#pragma omp parallel
+  {
+#pragma omp for nowait schedule (static, 2)
+    for (T i = x; i <= y; i += 3)
+      baz (i);
+#pragma omp single
+    {
+      T j = y + 3;
+      baz (j);
+    }
+  }
+}
+
+template <typename T>
+void
+f12 (const T &x, const T &y)
+{
+  T i;
+#pragma omp parallel for schedule (dynamic, 130)
+  for (i = x; i > y; --i)
+    baz (i);
+}
+
+template <int N>
+struct K
+{
+  template <typename T>
+  static void
+  f13 (const T &x, const T &y)
+  {
+#pragma omp parallel for schedule (runtime)
+    for (T i = x; i <= y + N; i += N)
+      baz (i);
+  }
+};
+
+#define check(expr) \
+  for (int i = 0; i < 2000; i++)                       \
+    if (expr)                                          \
+      {                                                        \
+       if (a[i] != L'a' + i + 1)                       \
+         std::abort ();                                \
+       a[i] = L'a' + i;                                \
+      }                                                        \
+    else if (a[i] != L'a' + i)                         \
+      std::abort ()
+
+int
+main ()
+{
+  std::basic_string<wchar_t> a = L"";
+  for (int i = 0; i < 2000; i++)
+    a += L'a' + i;
+  f1 (a.begin () + 10, a.begin () + 1990);
+  check (i >= 10 && i <= 1990 && (i - 10) % 6 == 0);
+  f2 (a.begin () + 0, a.begin () + 1999);
+  check (i < 1998 && (i & 1) == 0);
+  f3<char> (a.begin () + 20, a.begin () + 1837);
+  check (i >= 20 && i <= 1837);
+  f4<int> (a.begin () + 0, a.begin () + 30);
+  check (i > 40 && i <= 2000 - 64);
+  f5 (a.begin () + 0, a.begin () + 100);
+  check (i >= 116 && i <= 2000 - 64 && (i - 116) % 10 == 0);
+  f6<-10> (a.begin () + 10, a.begin () + 110);
+  check (i >= 116 && i <= 2000 - 64 && (i - 116) % 10 == 0);
+  f7<6> (std::basic_string<wchar_t>::iterator (), a.begin () + 12,
+        a.begin () + 1800);
+  check (i >= 2 && i <= 1808 && (i - 2) % 6 == 0);
+  f8<121> (J<wchar_t> (a.begin () + 14, a.begin () + 1803));
+  check (i >= 14 && i <= 1924 && (i & 1) == 0);
+  f9<wchar_t, 7> (a.begin () + 33, a.begin () + 1967);
+  check (i >= 33 && i <= 1967 && (i - 33) % 7 == 0);
+  f10<wchar_t, -7> (a.begin () + 1939, a.begin () + 17);
+  check (i >= 21 && i <= 1939 && (i - 21) % 7 == 0);
+  f11<std::basic_string<wchar_t>::iterator > (a.begin () + 16,
+                                             a.begin () + 1981);
+  check (i >= 16 && i <= 1984 && (i - 16) % 3 == 0);
+  f12<std::basic_string<wchar_t>::iterator > (a.begin () + 1761,
+                                             a.begin () + 37);
+  check (i > 37 && i <= 1761);
+  K<5>::f13<std::basic_string<wchar_t>::iterator > (a.begin () + 1,
+                                                   a.begin () + 1935);
+  check (i >= 1 && i <= 1936 && (i - 1) % 5 == 0);
+}
diff --git a/libgomp/testsuite/libgomp.c++/for-5.C b/libgomp/testsuite/libgomp.c++/for-5.C
new file mode 100644 (file)
index 0000000..9b75bf3
--- /dev/null
@@ -0,0 +1,303 @@
+// { dg-do run }
+
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+extern "C" void abort ();
+
+template <typename T>
+class I
+{
+public:
+  typedef ptrdiff_t difference_type;
+  I ();
+  ~I ();
+  I (T *);
+  I (const I &);
+  T &operator * ();
+  T *operator -> ();
+  T &operator [] (const difference_type &) const;
+  I &operator = (const I &);
+  I &operator ++ ();
+  I operator ++ (int);
+  I &operator -- ();
+  I operator -- (int);
+  I &operator += (const difference_type &);
+  I &operator -= (const difference_type &);
+  I operator + (const difference_type &) const;
+  I operator - (const difference_type &) const;
+  template <typename S> friend bool operator == (I<S> &, I<S> &);
+  template <typename S> friend bool operator == (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator < (I<S> &, I<S> &);
+  template <typename S> friend bool operator < (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator <= (I<S> &, I<S> &);
+  template <typename S> friend bool operator <= (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator > (I<S> &, I<S> &);
+  template <typename S> friend bool operator > (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator >= (I<S> &, I<S> &);
+  template <typename S> friend bool operator >= (const I<S> &, const I<S> &);
+  template <typename S> friend typename I<S>::difference_type operator - (I<S> &, I<S> &);
+  template <typename S> friend typename I<S>::difference_type operator - (const I<S> &, const I<S> &);
+  template <typename S> friend I<S> operator + (typename I<S>::difference_type , const I<S> &);
+private:
+  T *p;
+};
+template <typename T> I<T>::I () : p (0) {}
+template <typename T> I<T>::~I () { p = (T *) 0; }
+template <typename T> I<T>::I (T *x) : p (x) {}
+template <typename T> I<T>::I (const I &x) : p (x.p) {}
+template <typename T> T &I<T>::operator * () { return *p; }
+template <typename T> T *I<T>::operator -> () { return p; }
+template <typename T> T &I<T>::operator [] (const difference_type &x) const { return p[x]; }
+template <typename T> I<T> &I<T>::operator = (const I &x) { p = x.p; return *this; }
+template <typename T> I<T> &I<T>::operator ++ () { ++p; return *this; }
+template <typename T> I<T> I<T>::operator ++ (int) { return I (p++); }
+template <typename T> I<T> &I<T>::operator -- () { --p; return *this; }
+template <typename T> I<T> I<T>::operator -- (int) { return I (p--); }
+template <typename T> I<T> &I<T>::operator += (const difference_type &x) { p += x; return *this; }
+template <typename T> I<T> &I<T>::operator -= (const difference_type &x) { p -= x; return *this; }
+template <typename T> I<T> I<T>::operator + (const difference_type &x) const { return I (p + x); }
+template <typename T> I<T> I<T>::operator - (const difference_type &x) const { return I (p - x); }
+template <typename T> bool operator == (I<T> &x, I<T> &y) { return x.p == y.p; }
+template <typename T> bool operator == (const I<T> &x, const I<T> &y) { return x.p == y.p; }
+template <typename T> bool operator != (I<T> &x, I<T> &y) { return !(x == y); }
+template <typename T> bool operator != (const I<T> &x, const I<T> &y) { return !(x == y); }
+template <typename T> bool operator < (I<T> &x, I<T> &y) { return x.p < y.p; }
+template <typename T> bool operator < (const I<T> &x, const I<T> &y) { return x.p < y.p; }
+template <typename T> bool operator <= (I<T> &x, I<T> &y) { return x.p <= y.p; }
+template <typename T> bool operator <= (const I<T> &x, const I<T> &y) { return x.p <= y.p; }
+template <typename T> bool operator > (I<T> &x, I<T> &y) { return x.p > y.p; }
+template <typename T> bool operator > (const I<T> &x, const I<T> &y) { return x.p > y.p; }
+template <typename T> bool operator >= (I<T> &x, I<T> &y) { return x.p >= y.p; }
+template <typename T> bool operator >= (const I<T> &x, const I<T> &y) { return x.p >= y.p; }
+template <typename T> typename I<T>::difference_type operator - (I<T> &x, I<T> &y) { return x.p - y.p; }
+template <typename T> typename I<T>::difference_type operator - (const I<T> &x, const I<T> &y) { return x.p - y.p; }
+template <typename T> I<T> operator + (typename I<T>::difference_type x, const I<T> &y) { return I<T> (x + y.p); }
+
+template <typename T>
+class J
+{
+public:
+  J(const I<T> &x, const I<T> &y) : b (x), e (y) {}
+  const I<T> &begin ();
+  const I<T> &end ();
+private:
+  I<T> b, e;
+};
+
+template <typename T> const I<T> &J<T>::begin () { return b; }
+template <typename T> const I<T> &J<T>::end () { return e; }
+
+int results[2000];
+
+template <typename T>
+void
+baz (I<T> &i)
+{
+  if (*i < 0 || *i >= 2000)
+    abort ();
+  results[*i]++;
+}
+
+I<int>
+f1 (const I<int> &x, const I<int> &y)
+{
+  I<int> i;
+#pragma omp parallel shared (i)
+  {
+  #pragma omp for lastprivate (i) schedule(runtime)
+    for (i = x; i < y - 1; ++i)
+      baz (i);
+  #pragma omp single
+    i += 3;
+  }
+  return I<int> (i);
+}
+
+I<int>
+f2 (const I<int> &x, const I<int> &y)
+{
+  I<int> i;
+#pragma omp parallel for lastprivate (i)
+  for (i = x; i < y - 1; i = 1 - 6 + 7 + i)
+    baz (i);
+  return I<int> (i);
+}
+
+template <typename T>
+I<int>
+f3 (const I<int> &x, const I<int> &y)
+{
+  I<int> i;
+#pragma omp parallel
+  #pragma omp for lastprivate (i)
+    for (i = x + 1000 - 64; i <= y - 10; i++)
+      baz (i);
+  return i;
+}
+
+template <typename T>
+I<int>
+f4 (const I<int> &x, const I<int> &y)
+{
+  I<int> i;
+#pragma omp parallel for lastprivate (i)
+  for (i = x + 2000 - 64; i > y + 10; --i)
+    baz (i);
+  return I<int> (i);
+}
+
+template <typename T>
+I<int>
+f5 (const I<int> &x, const I<int> &y)
+{
+  I<int> i;
+#pragma omp parallel for lastprivate (i)
+  for (i = x; i > y + T (6); i--)
+    baz (i);
+  return i;
+}
+
+template <typename T>
+I<int>
+f6 (const I<int> &x, const I<int> &y)
+{
+  I<int> i;
+#pragma omp parallel for lastprivate (i)
+  for (i = x - T (7); i > y; i -= T (2))
+    baz (i);
+  return I<int> (i);
+}
+
+template <int N>
+I<int>
+f7 (I<int> i, const I<int> &x, const I<int> &y)
+{
+#pragma omp parallel for lastprivate (i)
+  for (i = x - 10; i <= y + 10; i += N)
+    baz (i);
+  return I<int> (i);
+}
+
+template <int N>
+I<int>
+f8 (J<int> j)
+{
+  I<int> i;
+#pragma omp parallel shared (i)
+  #pragma omp for lastprivate (i)
+    for (i = j.begin (); i <= j.end () + N; i += 2)
+      baz (i);
+  return i;
+}
+
+I<int> i9;
+
+template <long N>
+I<int> &
+f9 (J<int> j)
+{
+#pragma omp parallel for lastprivate (i9)
+  for (i9 = j.begin () + N; i9 <= j.end () - N; i9 = i9 - N)
+    baz (i9);
+  return i9;
+}
+
+template <typename T, int N>
+I<T>
+f10 (const I<T> &x, const I<T> &y)
+{
+  I<T> i;
+#pragma omp parallel for lastprivate (i)
+  for (i = x; i > y; i = i + N)
+    baz (i);
+  return i;
+}
+
+template <typename T, typename U>
+T
+f11 (T i, const T &x, const T &y)
+{
+#pragma omp parallel
+  #pragma omp for lastprivate (i)
+  for (i = x + U (2); i <= y + U (1); i = U (2) + U (3) + i)
+    baz (i);
+  return T (i);
+}
+
+template <typename T>
+T
+f12 (const T &x, const T &y)
+{
+  T i;
+#pragma omp parallel for lastprivate (i)
+  for (i = x; i > y; --i)
+    baz (i);
+  return i;
+}
+
+#define check(expr) \
+  for (int i = 0; i < 2000; i++)                       \
+    if (expr)                                          \
+      {                                                        \
+       if (results[i] != 1)                            \
+         abort ();                                     \
+       results[i] = 0;                                 \
+      }                                                        \
+    else if (results[i])                               \
+      abort ()
+
+int
+main ()
+{
+  int a[2000];
+  long b[2000];
+  for (int i = 0; i < 2000; i++)
+    {
+      a[i] = i;
+      b[i] = i;
+    }
+  if (*f1 (&a[10], &a[1873]) != 1875)
+    abort ();
+  check (i >= 10 && i < 1872);
+  if (*f2 (&a[0], &a[1998]) != 1998)
+    abort ();
+  check (i < 1997 && (i & 1) == 0);
+  if (*f3<int> (&a[10], &a[1971]) != 1962)
+    abort ();
+  check (i >= 946 && i <= 1961);
+  if (*f4<int> (&a[0], &a[30]) != 40)
+    abort ();
+  check (i > 40 && i <= 2000 - 64);
+  if (*f5<short> (&a[1931], &a[17]) != 23)
+    abort ();
+  check (i > 23 && i <= 1931);
+  if (*f6<long> (&a[1931], &a[17]) != 16)
+    abort ();
+  check (i > 17 && i <= 1924 && (i & 1) == 0);
+  if (*f7<6> (I<int> (), &a[12], &a[1800]) != 1814)
+    abort ();
+  check (i >= 2 && i <= 1808 && (i - 2) % 6 == 0);
+  if (*f8<121> (J<int> (&a[14], &a[1803])) != 1926)
+    abort ();
+  check (i >= 14 && i <= 1924 && (i & 1) == 0);
+  if (*f9<-3L> (J<int> (&a[27], &a[1761])) != 1767)
+    abort ();
+  check (i >= 24 && i <= 1764 && (i % 3) == 0);
+  if (*f10<int, -7> (&a[1939], &a[17]) != 14)
+    abort ();
+  check (i >= 21 && i <= 1939 && i % 7 == 0);
+  if (*f11<I<int>, short> (I<int> (), &a[71], &a[1941]) != 1943)
+    abort ();
+  check (i >= 73 && i <= 1938 && (i - 73) % 5 == 0);
+  if (*f12<I<int> > (&a[1761], &a[37]) != 37)
+    abort ();
+  check (i > 37 && i <= 1761);
+  if (*f10<long, -7> (&b[1939], &b[17]) != 14)
+    abort ();
+  check (i >= 21 && i <= 1939 && i % 7 == 0);
+  if (*f11<I<long>, short> (I<long> (), &b[71], &b[1941]) != 1943)
+    abort ();
+  check (i >= 73 && i <= 1938 && (i - 73) % 5 == 0);
+  if (*f12<I<long> > (&b[1761], &b[37]) != 37)
+    abort ();
+  check (i > 37 && i <= 1761);
+}
diff --git a/libgomp/testsuite/libgomp.c++/loop-10.C b/libgomp/testsuite/libgomp.c++/loop-10.C
new file mode 100644 (file)
index 0000000..9c0de25
--- /dev/null
@@ -0,0 +1,105 @@
+// { dg-do run }
+
+#include <omp.h>
+
+extern "C" void abort (void);
+
+#define LLONG_MAX __LONG_LONG_MAX__
+#define ULLONG_MAX (LLONG_MAX * 2ULL + 1)
+#define INT_MAX __INT_MAX__
+
+int v;
+
+int
+test1 (void)
+{
+  int e = 0, cnt = 0;
+  long long i;
+  unsigned long long j;
+  char buf[6], *p;
+
+  #pragma omp for schedule(dynamic,1) collapse(2) nowait
+  for (i = LLONG_MAX - 30001; i <= LLONG_MAX - 10001; i += 10000)
+    for (j = 20; j <= LLONG_MAX - 70; j += LLONG_MAX + 50ULL)
+      if ((i != LLONG_MAX - 30001
+          && i != LLONG_MAX - 20001
+          && i != LLONG_MAX - 10001)
+         || j != 20)
+       e = 1;
+      else
+       cnt++;
+  if (e || cnt != 3)
+    abort ();
+  else
+    cnt = 0;
+
+  #pragma omp for schedule(guided,1) collapse(2) nowait
+  for (i = -LLONG_MAX + 30000; i >= -LLONG_MAX + 10000; i -= 10000)
+    for (j = ULLONG_MAX - 3; j >= LLONG_MAX + 70ULL; j -= LLONG_MAX + 50ULL)
+      if ((i != -LLONG_MAX + 30000
+          && i != -LLONG_MAX + 20000
+          && i != -LLONG_MAX + 10000)
+         || j != ULLONG_MAX - 3)
+       e = 1;
+      else
+       cnt++;
+  if (e || cnt != 3)
+    abort ();
+  else
+    cnt = 0;
+
+  #pragma omp for schedule(static,1) collapse(2) nowait
+  for (i = LLONG_MAX - 30001; i <= LLONG_MAX - 10001; i += 10000)
+    for (j = 20; j <= LLONG_MAX - 70 + v; j += LLONG_MAX + 50ULL)
+      if ((i != LLONG_MAX - 30001
+          && i != LLONG_MAX - 20001
+          && i != LLONG_MAX - 10001)
+         || j != 20)
+       e = 1;
+      else
+       cnt++;
+  if (e || cnt != 3)
+    abort ();
+  else
+    cnt = 0;
+
+  #pragma omp for schedule(static) collapse(2) nowait
+  for (i = -LLONG_MAX + 30000 + v; i >= -LLONG_MAX + 10000; i -= 10000)
+    for (j = ULLONG_MAX - 3; j >= LLONG_MAX + 70ULL; j -= LLONG_MAX + 50ULL)
+      if ((i != -LLONG_MAX + 30000
+          && i != -LLONG_MAX + 20000
+          && i != -LLONG_MAX + 10000)
+         || j != ULLONG_MAX - 3)
+       e = 1;
+      else
+       cnt++;
+  if (e || cnt != 3)
+    abort ();
+  else
+    cnt = 0;
+
+  #pragma omp for schedule(runtime) collapse(2) nowait
+  for (i = 10; i < 30; i++)
+    for (p = buf; p <= buf + 4; p += 2)
+      if (i < 10 || i >= 30 || (p != buf && p != buf + 2 && p != buf + 4))
+       e = 1;
+      else
+       cnt++;
+  if (e || cnt != 60)
+    abort ();
+  else
+    cnt = 0;
+
+  return 0;
+}
+
+int
+main (void)
+{
+  if (2 * sizeof (int) != sizeof (long long))
+    return 0;
+  asm volatile ("" : "+r" (v));
+  omp_set_schedule (omp_sched_dynamic, 1);
+  test1 ();
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c++/loop-8.C b/libgomp/testsuite/libgomp.c++/loop-8.C
new file mode 100644 (file)
index 0000000..bc20c68
--- /dev/null
@@ -0,0 +1,276 @@
+#include <omp.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+test1 ()
+{
+  short int buf[64], *p;
+  int i;
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for
+  for (p = &buf[10]; p < &buf[54]; p++)
+    *p = 5;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 5 * (i >= 10 && i < 54))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for
+  for (p = &buf[3]; p <= &buf[63]; p += 2)
+    p[-2] = 6;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 6 * ((i & 1) && i <= 61))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for
+  for (p = &buf[16]; p < &buf[51]; p = 4 + p)
+    p[2] = 7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 7 * ((i & 3) == 2 && i >= 18 && i < 53))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for
+  for (p = &buf[16]; p <= &buf[40]; p = p + 4ULL)
+    p[2] = -7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != -7 * ((i & 3) == 2 && i >= 18 && i <= 42))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for
+  for (p = &buf[53]; p > &buf[9]; --p)
+    *p = 5;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 5 * (i >= 10 && i < 54))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for
+  for (p = &buf[63]; p >= &buf[3]; p -= 2)
+    p[-2] = 6;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 6 * ((i & 1) && i <= 61))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for
+  for (p = &buf[48]; p > &buf[15]; p = -4 + p)
+    p[2] = 7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 7 * ((i & 3) == 2 && i >= 18 && i < 53))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for
+  for (p = &buf[40]; p >= &buf[16]; p = p - 4ULL)
+    p[2] = -7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != -7 * ((i & 3) == 2 && i >= 18 && i <= 42))
+      abort ();
+  return 0;
+}
+
+int
+test2 ()
+{
+  int buf[64], *p;
+  int i;
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (static, 3)
+  for (p = &buf[10]; p < &buf[54]; p++)
+    *p = 5;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 5 * (i >= 10 && i < 54))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (static, 3)
+  for (p = &buf[3]; p <= &buf[63]; p += 2)
+    p[-2] = 6;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 6 * ((i & 1) && i <= 61))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (static, 3)
+  for (p = &buf[16]; p < &buf[51]; p = 4 + p)
+    p[2] = 7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 7 * ((i & 3) == 2 && i >= 18 && i < 53))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (static, 3)
+  for (p = &buf[16]; p <= &buf[40]; p = p + 4ULL)
+    p[2] = -7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != -7 * ((i & 3) == 2 && i >= 18 && i <= 42))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (static, 3)
+  for (p = &buf[53]; p > &buf[9]; --p)
+    *p = 5;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 5 * (i >= 10 && i < 54))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (static, 3)
+  for (p = &buf[63]; p >= &buf[3]; p -= 2)
+    p[-2] = 6;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 6 * ((i & 1) && i <= 61))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (static, 3)
+  for (p = &buf[48]; p > &buf[15]; p = -4 + p)
+    p[2] = 7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 7 * ((i & 3) == 2 && i >= 18 && i < 53))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (static, 3)
+  for (p = &buf[40]; p >= &buf[16]; p = p - 4ULL)
+    p[2] = -7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != -7 * ((i & 3) == 2 && i >= 18 && i <= 42))
+      abort ();
+  return 0;
+}
+
+int
+test3 ()
+{
+  int buf[64], *p;
+  int i;
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (dynamic, 3)
+  for (p = &buf[10]; p < &buf[54]; p++)
+    *p = 5;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 5 * (i >= 10 && i < 54))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (dynamic, 3)
+  for (p = &buf[3]; p <= &buf[63]; p += 2)
+    p[-2] = 6;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 6 * ((i & 1) && i <= 61))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (dynamic, 3)
+  for (p = &buf[16]; p < &buf[51]; p = 4 + p)
+    p[2] = 7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 7 * ((i & 3) == 2 && i >= 18 && i < 53))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (dynamic, 3)
+  for (p = &buf[16]; p <= &buf[40]; p = p + 4ULL)
+    p[2] = -7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != -7 * ((i & 3) == 2 && i >= 18 && i <= 42))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (dynamic, 3)
+  for (p = &buf[53]; p > &buf[9]; --p)
+    *p = 5;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 5 * (i >= 10 && i < 54))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (dynamic, 3)
+  for (p = &buf[63]; p >= &buf[3]; p -= 2)
+    p[-2] = 6;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 6 * ((i & 1) && i <= 61))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (dynamic, 3)
+  for (p = &buf[48]; p > &buf[15]; p = -4 + p)
+    p[2] = 7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 7 * ((i & 3) == 2 && i >= 18 && i < 53))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (dynamic, 3)
+  for (p = &buf[40]; p >= &buf[16]; p = p - 4ULL)
+    p[2] = -7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != -7 * ((i & 3) == 2 && i >= 18 && i <= 42))
+      abort ();
+  return 0;
+}
+
+int
+test4 ()
+{
+  int buf[64], *p;
+  int i;
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (runtime)
+  for (p = &buf[10]; p < &buf[54]; p++)
+    *p = 5;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 5 * (i >= 10 && i < 54))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (runtime)
+  for (p = &buf[3]; p <= &buf[63]; p += 2)
+    p[-2] = 6;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 6 * ((i & 1) && i <= 61))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (runtime)
+  for (p = &buf[16]; p < &buf[51]; p = 4 + p)
+    p[2] = 7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 7 * ((i & 3) == 2 && i >= 18 && i < 53))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (runtime)
+  for (p = &buf[16]; p <= &buf[40]; p = p + 4ULL)
+    p[2] = -7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != -7 * ((i & 3) == 2 && i >= 18 && i <= 42))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (runtime)
+  for (p = &buf[53]; p > &buf[9]; --p)
+    *p = 5;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 5 * (i >= 10 && i < 54))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (runtime)
+  for (p = &buf[63]; p >= &buf[3]; p -= 2)
+    p[-2] = 6;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 6 * ((i & 1) && i <= 61))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (runtime)
+  for (p = &buf[48]; p > &buf[15]; p = -4 + p)
+    p[2] = 7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 7 * ((i & 3) == 2 && i >= 18 && i < 53))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (runtime)
+  for (p = &buf[40]; p >= &buf[16]; p = p - 4ULL)
+    p[2] = -7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != -7 * ((i & 3) == 2 && i >= 18 && i <= 42))
+      abort ();
+  return 0;
+}
+
+int
+main ()
+{
+  test1 ();
+  test2 ();
+  test3 ();
+  omp_set_schedule (omp_sched_static, 0);
+  test4 ();
+  omp_set_schedule (omp_sched_static, 3);
+  test4 ();
+  omp_set_schedule (omp_sched_dynamic, 5);
+  test4 ();
+  omp_set_schedule (omp_sched_guided, 2);
+  test4 ();
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c++/loop-9.C b/libgomp/testsuite/libgomp.c++/loop-9.C
new file mode 100644 (file)
index 0000000..35daf22
--- /dev/null
@@ -0,0 +1,387 @@
+// { dg-do run }
+
+#include <omp.h>
+
+extern "C" void abort ();
+
+#define LLONG_MAX __LONG_LONG_MAX__
+#define ULLONG_MAX (LLONG_MAX * 2ULL + 1)
+#define INT_MAX __INT_MAX__
+
+int arr[6 * 5];
+
+void
+set (int loopidx, int idx)
+{
+#pragma omp atomic
+  arr[loopidx * 5 + idx]++;
+}
+
+#define check(var, val, loopidx, idx) \
+  if (var == (val)) set (loopidx, idx); else
+#define test(loopidx, count) \
+  for (idx = 0; idx < 5; idx++) \
+    if (arr[loopidx * 5 + idx] != idx < count) \
+      abort (); \
+    else \
+      arr[loopidx * 5 + idx] = 0
+
+int
+test1 ()
+{
+  int e = 0, idx;
+
+#pragma omp parallel reduction(+:e)
+  {
+    long long i;
+    unsigned long long j;
+    #pragma omp for schedule(dynamic,1) nowait
+    for (i = LLONG_MAX - 30001; i <= LLONG_MAX - 10001; i += 10000)
+      {
+       check (i, LLONG_MAX - 30001, 0, 0)
+       check (i, LLONG_MAX - 20001, 0, 1)
+       check (i, LLONG_MAX - 10001, 0, 2)
+       e = 1;
+      }
+    #pragma omp for schedule(dynamic,1) nowait
+    for (i = -LLONG_MAX + 30000; i >= -LLONG_MAX + 10000; i -= 10000)
+      {
+       check (i, -LLONG_MAX + 30000, 1, 0)
+       check (i, -LLONG_MAX + 20000, 1, 1)
+       check (i, -LLONG_MAX + 10000, 1, 2)
+       e = 1;
+      }
+    #pragma omp for schedule(dynamic,1) nowait
+    for (j = 20; j <= LLONG_MAX - 70; j += LLONG_MAX + 50ULL)
+      {
+       check (j, 20, 2, 0)
+       e = 1;
+      }
+    #pragma omp for schedule(dynamic,1) nowait
+    for (j = ULLONG_MAX - 3; j >= LLONG_MAX + 70ULL; j -= LLONG_MAX + 50ULL)
+      {
+       check (j, ULLONG_MAX - 3, 3, 0)
+       e = 1;
+      }
+    #pragma omp for schedule(dynamic,1) nowait
+    for (j = LLONG_MAX - 20000ULL; j <= LLONG_MAX + 10000ULL; j += 10000ULL)
+      {
+       check (j, LLONG_MAX - 20000ULL, 4, 0)
+       check (j, LLONG_MAX - 10000ULL, 4, 1)
+       check (j, LLONG_MAX, 4, 2)
+       check (j, LLONG_MAX + 10000ULL, 4, 3)
+       e = 1;
+      }
+    #pragma omp for schedule(dynamic,1) nowait
+    for (i = -3LL * INT_MAX - 20000LL; i <= INT_MAX + 10000LL; i += INT_MAX + 200LL)
+      {
+       check (i, -3LL * INT_MAX - 20000LL, 5, 0)
+       check (i, -2LL * INT_MAX - 20000LL + 200LL, 5, 1)
+       check (i, -INT_MAX - 20000LL + 400LL, 5, 2)
+       check (i, -20000LL + 600LL, 5, 3)
+       check (i, INT_MAX - 20000LL + 800LL, 5, 4)
+       e = 1;
+      }
+  }
+  if (e)
+    abort ();
+  test (0, 3);
+  test (1, 3);
+  test (2, 1);
+  test (3, 1);
+  test (4, 4);
+  test (5, 5);
+  return 0;
+}
+
+int
+test2 ()
+{
+  int e = 0, idx;
+
+#pragma omp parallel reduction(+:e)
+  {
+    long long i;
+    unsigned long long j;
+    #pragma omp for schedule(guided,1) nowait
+    for (i = LLONG_MAX - 30001; i <= LLONG_MAX - 10001; i += 10000)
+      {
+       check (i, LLONG_MAX - 30001, 0, 0)
+       check (i, LLONG_MAX - 20001, 0, 1)
+       check (i, LLONG_MAX - 10001, 0, 2)
+       e = 1;
+      }
+    #pragma omp for schedule(guided,1) nowait
+    for (i = -LLONG_MAX + 30000; i >= -LLONG_MAX + 10000; i -= 10000)
+      {
+       check (i, -LLONG_MAX + 30000, 1, 0)
+       check (i, -LLONG_MAX + 20000, 1, 1)
+       check (i, -LLONG_MAX + 10000, 1, 2)
+       e = 1;
+      }
+    #pragma omp for schedule(guided,1) nowait
+    for (j = 20; j <= LLONG_MAX - 70; j += LLONG_MAX + 50ULL)
+      {
+       check (j, 20, 2, 0)
+       e = 1;
+      }
+    #pragma omp for schedule(guided,1) nowait
+    for (j = ULLONG_MAX - 3; j >= LLONG_MAX + 70ULL; j -= LLONG_MAX + 50ULL)
+      {
+       check (j, ULLONG_MAX - 3, 3, 0)
+       e = 1;
+      }
+    #pragma omp for schedule(guided,1) nowait
+    for (j = LLONG_MAX - 20000ULL; j <= LLONG_MAX + 10000ULL; j += 10000ULL)
+      {
+       check (j, LLONG_MAX - 20000ULL, 4, 0)
+       check (j, LLONG_MAX - 10000ULL, 4, 1)
+       check (j, LLONG_MAX, 4, 2)
+       check (j, LLONG_MAX + 10000ULL, 4, 3)
+       e = 1;
+      }
+    #pragma omp for schedule(guided,1) nowait
+    for (i = -3LL * INT_MAX - 20000LL; i <= INT_MAX + 10000LL; i += INT_MAX + 200LL)
+      {
+       check (i, -3LL * INT_MAX - 20000LL, 5, 0)
+       check (i, -2LL * INT_MAX - 20000LL + 200LL, 5, 1)
+       check (i, -INT_MAX - 20000LL + 400LL, 5, 2)
+       check (i, -20000LL + 600LL, 5, 3)
+       check (i, INT_MAX - 20000LL + 800LL, 5, 4)
+       e = 1;
+      }
+  }
+  if (e)
+    abort ();
+  test (0, 3);
+  test (1, 3);
+  test (2, 1);
+  test (3, 1);
+  test (4, 4);
+  test (5, 5);
+  return 0;
+}
+
+int
+test3 ()
+{
+  int e = 0, idx;
+
+#pragma omp parallel reduction(+:e)
+  {
+    long long i;
+    unsigned long long j;
+    #pragma omp for schedule(static) nowait
+    for (i = LLONG_MAX - 30001; i <= LLONG_MAX - 10001; i += 10000)
+      {
+       check (i, LLONG_MAX - 30001, 0, 0)
+       check (i, LLONG_MAX - 20001, 0, 1)
+       check (i, LLONG_MAX - 10001, 0, 2)
+       e = 1;
+      }
+    #pragma omp for schedule(static) nowait
+    for (i = -LLONG_MAX + 30000; i >= -LLONG_MAX + 10000; i -= 10000)
+      {
+       check (i, -LLONG_MAX + 30000, 1, 0)
+       check (i, -LLONG_MAX + 20000, 1, 1)
+       check (i, -LLONG_MAX + 10000, 1, 2)
+       e = 1;
+      }
+    #pragma omp for schedule(static) nowait
+    for (j = 20; j <= LLONG_MAX - 70; j += LLONG_MAX + 50ULL)
+      {
+       check (j, 20, 2, 0)
+       e = 1;
+      }
+    #pragma omp for schedule(static) nowait
+    for (j = ULLONG_MAX - 3; j >= LLONG_MAX + 70ULL; j -= LLONG_MAX + 50ULL)
+      {
+       check (j, ULLONG_MAX - 3, 3, 0)
+       e = 1;
+      }
+    #pragma omp for schedule(static) nowait
+    for (j = LLONG_MAX - 20000ULL; j <= LLONG_MAX + 10000ULL; j += 10000ULL)
+      {
+       check (j, LLONG_MAX - 20000ULL, 4, 0)
+       check (j, LLONG_MAX - 10000ULL, 4, 1)
+       check (j, LLONG_MAX, 4, 2)
+       check (j, LLONG_MAX + 10000ULL, 4, 3)
+       e = 1;
+      }
+    #pragma omp for schedule(static) nowait
+    for (i = -3LL * INT_MAX - 20000LL; i <= INT_MAX + 10000LL; i += INT_MAX + 200LL)
+      {
+       check (i, -3LL * INT_MAX - 20000LL, 5, 0)
+       check (i, -2LL * INT_MAX - 20000LL + 200LL, 5, 1)
+       check (i, -INT_MAX - 20000LL + 400LL, 5, 2)
+       check (i, -20000LL + 600LL, 5, 3)
+       check (i, INT_MAX - 20000LL + 800LL, 5, 4)
+       e = 1;
+      }
+  }
+  if (e)
+    abort ();
+  test (0, 3);
+  test (1, 3);
+  test (2, 1);
+  test (3, 1);
+  test (4, 4);
+  test (5, 5);
+  return 0;
+}
+
+int
+test4 ()
+{
+  int e = 0, idx;
+
+#pragma omp parallel reduction(+:e)
+  {
+    long long i;
+    unsigned long long j;
+    #pragma omp for schedule(static,1) nowait
+    for (i = LLONG_MAX - 30001; i <= LLONG_MAX - 10001; i += 10000)
+      {
+       check (i, LLONG_MAX - 30001, 0, 0)
+       check (i, LLONG_MAX - 20001, 0, 1)
+       check (i, LLONG_MAX - 10001, 0, 2)
+       e = 1;
+      }
+    #pragma omp for schedule(static,1) nowait
+    for (i = -LLONG_MAX + 30000; i >= -LLONG_MAX + 10000; i -= 10000)
+      {
+       check (i, -LLONG_MAX + 30000, 1, 0)
+       check (i, -LLONG_MAX + 20000, 1, 1)
+       check (i, -LLONG_MAX + 10000, 1, 2)
+       e = 1;
+      }
+    #pragma omp for schedule(static,1) nowait
+    for (j = 20; j <= LLONG_MAX - 70; j += LLONG_MAX + 50ULL)
+      {
+       check (j, 20, 2, 0)
+       e = 1;
+      }
+    #pragma omp for schedule(static,1) nowait
+    for (j = ULLONG_MAX - 3; j >= LLONG_MAX + 70ULL; j -= LLONG_MAX + 50ULL)
+      {
+       check (j, ULLONG_MAX - 3, 3, 0)
+       e = 1;
+      }
+    #pragma omp for schedule(static,1) nowait
+    for (j = LLONG_MAX - 20000ULL; j <= LLONG_MAX + 10000ULL; j += 10000ULL)
+      {
+       check (j, LLONG_MAX - 20000ULL, 4, 0)
+       check (j, LLONG_MAX - 10000ULL, 4, 1)
+       check (j, LLONG_MAX, 4, 2)
+       check (j, LLONG_MAX + 10000ULL, 4, 3)
+       e = 1;
+      }
+    #pragma omp for schedule(static,1) nowait
+    for (i = -3LL * INT_MAX - 20000LL; i <= INT_MAX + 10000LL; i += INT_MAX + 200LL)
+      {
+       check (i, -3LL * INT_MAX - 20000LL, 5, 0)
+       check (i, -2LL * INT_MAX - 20000LL + 200LL, 5, 1)
+       check (i, -INT_MAX - 20000LL + 400LL, 5, 2)
+       check (i, -20000LL + 600LL, 5, 3)
+       check (i, INT_MAX - 20000LL + 800LL, 5, 4)
+       e = 1;
+      }
+  }
+  if (e)
+    abort ();
+  test (0, 3);
+  test (1, 3);
+  test (2, 1);
+  test (3, 1);
+  test (4, 4);
+  test (5, 5);
+  return 0;
+}
+
+int
+test5 ()
+{
+  int e = 0, idx;
+
+#pragma omp parallel reduction(+:e)
+  {
+    long long i;
+    unsigned long long j;
+    #pragma omp for schedule(runtime) nowait
+    for (i = LLONG_MAX - 30001; i <= LLONG_MAX - 10001; i += 10000)
+      {
+       check (i, LLONG_MAX - 30001, 0, 0)
+       check (i, LLONG_MAX - 20001, 0, 1)
+       check (i, LLONG_MAX - 10001, 0, 2)
+       e = 1;
+      }
+    #pragma omp for schedule(runtime) nowait
+    for (i = -LLONG_MAX + 30000; i >= -LLONG_MAX + 10000; i -= 10000)
+      {
+       check (i, -LLONG_MAX + 30000, 1, 0)
+       check (i, -LLONG_MAX + 20000, 1, 1)
+       check (i, -LLONG_MAX + 10000, 1, 2)
+       e = 1;
+      }
+    #pragma omp for schedule(runtime) nowait
+    for (j = 20; j <= LLONG_MAX - 70; j += LLONG_MAX + 50ULL)
+      {
+       check (j, 20, 2, 0)
+       e = 1;
+      }
+    #pragma omp for schedule(runtime) nowait
+    for (j = ULLONG_MAX - 3; j >= LLONG_MAX + 70ULL; j -= LLONG_MAX + 50ULL)
+      {
+       check (j, ULLONG_MAX - 3, 3, 0)
+       e = 1;
+      }
+    #pragma omp for schedule(runtime) nowait
+    for (j = LLONG_MAX - 20000ULL; j <= LLONG_MAX + 10000ULL; j += 10000ULL)
+      {
+       check (j, LLONG_MAX - 20000ULL, 4, 0)
+       check (j, LLONG_MAX - 10000ULL, 4, 1)
+       check (j, LLONG_MAX, 4, 2)
+       check (j, LLONG_MAX + 10000ULL, 4, 3)
+       e = 1;
+      }
+    #pragma omp for schedule(runtime) nowait
+    for (i = -3LL * INT_MAX - 20000LL; i <= INT_MAX + 10000LL; i += INT_MAX + 200LL)
+      {
+       check (i, -3LL * INT_MAX - 20000LL, 5, 0)
+       check (i, -2LL * INT_MAX - 20000LL + 200LL, 5, 1)
+       check (i, -INT_MAX - 20000LL + 400LL, 5, 2)
+       check (i, -20000LL + 600LL, 5, 3)
+       check (i, INT_MAX - 20000LL + 800LL, 5, 4)
+       e = 1;
+      }
+  }
+  if (e)
+    abort ();
+  test (0, 3);
+  test (1, 3);
+  test (2, 1);
+  test (3, 1);
+  test (4, 4);
+  test (5, 5);
+  return 0;
+}
+
+int
+main ()
+{
+  if (2 * sizeof (int) != sizeof (long long))
+    return 0;
+  test1 ();
+  test2 ();
+  test3 ();
+  test4 ();
+  omp_set_schedule (omp_sched_static, 0);
+  test5 ();
+  omp_set_schedule (omp_sched_static, 3);
+  test5 ();
+  omp_set_schedule (omp_sched_dynamic, 5);
+  test5 ();
+  omp_set_schedule (omp_sched_guided, 2);
+  test5 ();
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c++/task-1.C b/libgomp/testsuite/libgomp.c++/task-1.C
new file mode 100644 (file)
index 0000000..535a828
--- /dev/null
@@ -0,0 +1,83 @@
+extern "C" void abort ();
+
+int a = 18;
+
+void
+f1 (int i, int j, int k)
+{
+  int l = 6, m = 7, n = 8;
+#pragma omp task private(j, m) shared(k, n)
+  {
+    j = 6;
+    m = 5;
+    if (++a != 19 || ++i != 9 || j != 6 || ++l != 7 || m != 5 || ++n != 9)
+      #pragma omp atomic
+       k++;
+  }
+#pragma omp taskwait
+  if (a != 19 || i != 8 || j != 26 || k != 0 || l != 6 || m != 7 || n != 9)
+    abort ();
+}
+
+int v1 = 1, v2 = 2, v5 = 5;
+int err;
+
+void
+f2 (void)
+{
+  int v3 = 3;
+#pragma omp sections private (v1) firstprivate (v2)
+  {
+  #pragma omp section
+    {
+      int v4 = 4;
+      v1 = 7;
+      #pragma omp task
+       {
+         if (++v1 != 8 || ++v2 != 3 || ++v3 != 4 || ++v4 != 5 || ++v5 != 6)
+           err = 1;
+       }
+      #pragma omp taskwait
+      if (v1 != 7 || v2 != 2 || v3 != 3 || v4 != 4 || v5 != 6)
+       abort ();
+      if (err)
+       abort ();
+    }
+  }
+}
+
+void
+f3 (int i, int j, int k)
+{
+  int l = 6, m = 7, n = 8;
+#pragma omp task private(j, m) shared(k, n) untied
+  {
+    j = 6;
+    m = 5;
+    if (++a != 19 || ++i != 9 || j != 6 || ++l != 7 || m != 5 || ++n != 9)
+      #pragma omp atomic
+       k++;
+  }
+#pragma omp taskwait
+  if (a != 19 || i != 8 || j != 26 || k != 0 || l != 6 || m != 7 || n != 9)
+    abort ();
+}
+
+int
+main ()
+{
+  f1 (8, 26, 0);
+  f2 ();
+  a = 18;
+  f3 (8, 26, 0);
+  a = 18;
+#pragma omp parallel num_threads(4)
+  {
+    #pragma omp master
+      {
+       f1 (8, 26, 0);
+       a = 18;
+       f3 (8, 26, 0);
+      }
+  }
+}
diff --git a/libgomp/testsuite/libgomp.c++/task-2.C b/libgomp/testsuite/libgomp.c++/task-2.C
new file mode 100644 (file)
index 0000000..a198cc7
--- /dev/null
@@ -0,0 +1,70 @@
+// { dg-do run }
+
+#include <omp.h>
+extern "C" void abort ();
+
+int l = 5;
+
+int
+foo (int i)
+{
+  int j = 7;
+  const int k = 8;
+  #pragma omp task firstprivate (i) shared (j, l)
+  {
+    #pragma omp critical
+      {
+       j += i;
+       l += k;
+      }
+  }
+  i++;
+  #pragma omp task firstprivate (i) shared (j, l)
+  {
+    #pragma omp critical
+      {
+       j += i;
+       l += k;
+      }
+  }
+  i++;
+  #pragma omp task firstprivate (i) shared (j, l)
+  {
+    #pragma omp critical
+      {
+       j += i;
+       l += k;
+      }
+  }
+  i++;
+  #pragma omp task firstprivate (i) shared (j, l)
+  {
+    #pragma omp critical
+      {
+       j += i;
+       l += k;
+      }
+  }
+  i++;
+  #pragma omp taskwait
+  return (i != 8 * omp_get_thread_num () + 4
+         || j != 4 * i - 3
+         || k != 8);
+}
+
+int
+main (void)
+{
+  int r = 0;
+  #pragma omp parallel num_threads (4) reduction(+:r)
+    if (omp_get_num_threads () != 4)
+      {
+       #pragma omp master
+         l = 133;
+      }
+    else if (foo (8 * omp_get_thread_num ()))
+      r++;
+  if (r || l != 133)
+    abort ();
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c++/task-3.C b/libgomp/testsuite/libgomp.c++/task-3.C
new file mode 100644 (file)
index 0000000..e1ecb49
--- /dev/null
@@ -0,0 +1,90 @@
+// { dg-do run }
+
+extern "C" void abort ();
+
+struct A
+{
+  A ();
+  ~A ();
+  A (const A &);
+  unsigned long l;
+};
+
+int e;
+
+A::A ()
+{
+  l = 17;
+}
+
+A::~A ()
+{
+  if (l > 30)
+    #pragma omp atomic
+      e++;
+}
+
+A::A (const A &r)
+{
+  l = r.l;
+}
+
+void
+check (int i, A &a, int j, A &b)
+{
+  if (i != 6 || a.l != 21 || j != 0 || b.l != 23)
+    #pragma omp atomic
+      e++;
+}
+
+A b;
+int j;
+
+void
+foo (int i)
+{
+  A a;
+  a.l = 21;
+  #pragma omp task firstprivate (i, a, j, b)
+    check (i, a, j, b);
+}
+
+void
+bar (int i, A a)
+{
+  a.l = 21;
+  #pragma omp task firstprivate (i, a, j, b)
+    check (i, a, j, b);
+}
+
+A
+baz ()
+{
+  A a, c;
+  a.l = 21;
+  c.l = 23;
+  #pragma omp task firstprivate (a, c)
+    check (6, a, 0, c);
+  return a;
+}
+
+int
+main ()
+{
+  b.l = 23;
+  foo (6);
+  bar (6, A ());
+  baz ();
+  #pragma omp parallel num_threads (4)
+    {
+      #pragma omp single
+       for (int i = 0; i < 64; i++)
+         {
+           foo (6);
+           bar (6, A ());
+           baz ();
+         }
+    }
+  if (e)
+    abort ();
+}
diff --git a/libgomp/testsuite/libgomp.c++/task-4.C b/libgomp/testsuite/libgomp.c++/task-4.C
new file mode 100644 (file)
index 0000000..f2e786a
--- /dev/null
@@ -0,0 +1,37 @@
+#include <omp.h>
+extern "C" void *memset (void *, int, __SIZE_TYPE__);
+extern "C" void abort (void);
+
+int e;
+
+void
+baz (int i, int *p, int j, int *q)
+{
+  if (p[0] != 1 || p[i] != 3 || q[0] != 2 || q[j] != 4)
+    #pragma omp atomic
+      e++;
+}
+
+void
+foo (int i, int j)
+{
+  int p[i + 1];
+  int q[j + 1];
+  memset (p, 0, sizeof (p));
+  memset (q, 0, sizeof (q));
+  p[0] = 1;
+  p[i] = 3;
+  q[0] = 2;
+  q[j] = 4;
+  #pragma omp task firstprivate (p, q)
+    baz (i, p, j, q);
+}
+
+int
+main ()
+{
+  #pragma omp parallel num_threads (4)
+    foo (5 + omp_get_thread_num (), 7 + omp_get_thread_num ());
+  if (e)
+    abort ();
+}
diff --git a/libgomp/testsuite/libgomp.c++/task-5.C b/libgomp/testsuite/libgomp.c++/task-5.C
new file mode 100644 (file)
index 0000000..c882bfe
--- /dev/null
@@ -0,0 +1,90 @@
+// { dg-do run }
+
+extern "C" void abort ();
+
+struct A
+{
+  A ();
+  ~A ();
+  A (const A &);
+  unsigned long l;
+};
+
+int e;
+
+A::A ()
+{
+  l = 17;
+}
+
+A::~A ()
+{
+  if (l > 130)
+    #pragma omp atomic
+      e++;
+}
+
+A::A (const A &r)
+{
+  l = r.l + 64;
+}
+
+void
+check (int i, A &a, int j, A &b)
+{
+  if (i != 6 || a.l != 21 + 64 || j != 0 || b.l != 23 + 64)
+    #pragma omp atomic
+      e++;
+}
+
+A b;
+int j;
+
+void
+foo (int i)
+{
+  A a;
+  a.l = 21;
+  #pragma omp task firstprivate (j, b)
+    check (i, a, j, b);
+}
+
+void
+bar (int i, A a)
+{
+  a.l = 21;
+  #pragma omp task firstprivate (j, b)
+    check (i, a, j, b);
+}
+
+A
+baz ()
+{
+  A a, c;
+  a.l = 21;
+  c.l = 23;
+  #pragma omp task firstprivate (a, c)
+    check (6, a, 0, c);
+  return a;
+}
+
+int
+main ()
+{
+  b.l = 23;
+  foo (6);
+  bar (6, A ());
+  baz ();
+  #pragma omp parallel num_threads (4)
+    {
+      #pragma omp single
+       for (int i = 0; i < 64; i++)
+         {
+           foo (6);
+           bar (6, A ());
+           baz ();
+         }
+    }
+  if (e)
+    abort ();
+}
diff --git a/libgomp/testsuite/libgomp.c++/task-6.C b/libgomp/testsuite/libgomp.c++/task-6.C
new file mode 100644 (file)
index 0000000..cc9072b
--- /dev/null
@@ -0,0 +1,86 @@
+extern "C" void abort ();
+
+int a = 18;
+
+template <typename T>
+void
+f1 (T i, T j, T k)
+{
+  T l = 6, m = 7, n = 8;
+#pragma omp task private(j, m) shared(k, n)
+  {
+    j = 6;
+    m = 5;
+    if (++a != 19 || ++i != 9 || j != 6 || ++l != 7 || m != 5 || ++n != 9)
+      #pragma omp atomic
+       k++;
+  }
+#pragma omp taskwait
+  if (a != 19 || i != 8 || j != 26 || k != 0 || l != 6 || m != 7 || n != 9)
+    abort ();
+}
+
+int v1 = 1, v2 = 2, v5 = 5;
+int err;
+
+template <typename T>
+void
+f2 (void)
+{
+  T v3 = 3;
+#pragma omp sections private (v1) firstprivate (v2)
+  {
+  #pragma omp section
+    {
+      T v4 = 4;
+      v1 = 7;
+      #pragma omp task
+       {
+         if (++v1 != 8 || ++v2 != 3 || ++v3 != 4 || ++v4 != 5 || ++v5 != 6)
+           err = 1;
+       }
+      #pragma omp taskwait
+      if (v1 != 7 || v2 != 2 || v3 != 3 || v4 != 4 || v5 != 6)
+       abort ();
+      if (err)
+       abort ();
+    }
+  }
+}
+
+template <typename T>
+void
+f3 (T i, T j, T k)
+{
+  T l = 6, m = 7, n = 8;
+#pragma omp task private(j, m) shared(k, n) untied
+  {
+    j = 6;
+    m = 5;
+    if (++a != 19 || ++i != 9 || j != 6 || ++l != 7 || m != 5 || ++n != 9)
+      #pragma omp atomic
+       k++;
+  }
+#pragma omp taskwait
+  if (a != 19 || i != 8 || j != 26 || k != 0 || l != 6 || m != 7 || n != 9)
+    abort ();
+}
+
+int
+main ()
+{
+  f1 <int> (8, 26, 0);
+  f2 <int> ();
+  a = 18;
+  f3 <int> (8, 26, 0);
+  a = 18;
+#pragma omp parallel num_threads(4)
+  {
+    #pragma omp master
+      {
+       f1 <int> (8, 26, 0);
+       a = 18;
+       f3 <int> (8, 26, 0);
+      }
+  }
+}
diff --git a/libgomp/testsuite/libgomp.c/collapse-1.c b/libgomp/testsuite/libgomp.c/collapse-1.c
new file mode 100644 (file)
index 0000000..82becfa
--- /dev/null
@@ -0,0 +1,30 @@
+/* { dg-do run } */
+
+#include <string.h>
+#include <stdlib.h>
+
+int
+main (void)
+{
+  int i, j, k, l = 0;
+  int a[3][3][3];
+
+  memset (a, '\0', sizeof (a));
+  #pragma omp parallel for collapse(4 - 1) schedule(static, 4)
+    for (i = 0; i < 2; i++)
+      for (j = 0; j < 2; j++)
+       for (k = 0; k < 2; k++)
+         a[i][j][k] = i + j * 4 + k * 16;
+  #pragma omp parallel
+    {
+      #pragma omp for collapse(2) reduction(|:l)
+       for (i = 0; i < 2; i++)
+         for (j = 0; j < 2; j++)
+           for (k = 0; k < 2; k++)
+             if (a[i][j][k] != i + j * 4 + k * 16)
+               l = 1;
+    }
+  if (l)
+    abort ();
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/collapse-2.c b/libgomp/testsuite/libgomp.c/collapse-2.c
new file mode 100644 (file)
index 0000000..b5c77d4
--- /dev/null
@@ -0,0 +1,30 @@
+/* { dg-do run } */
+
+#include <stdlib.h>
+#include <omp.h>
+
+int
+main (void)
+{
+  int i, j, k, l = 0, f = 0;
+  int m1 = 4, m2 = -5, m3 = 17;
+
+  #pragma omp parallel for num_threads (8) collapse(3) \
+                      schedule(static, 9) reduction(+:l) \
+                      firstprivate(f)
+    for (i = -2; i < m1; i++)
+      for (j = m2; j < -2; j++)
+       {
+         for (k = 13; k < m3; k++)
+           {
+             if (omp_get_num_threads () == 8
+                 && ((i + 2) * 12 + (j + 5) * 4 + (k - 13)
+                     != (omp_get_thread_num () * 9
+                         + f++)))
+               l++;
+           }
+       }
+  if (l)
+    abort ();
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/collapse-3.c b/libgomp/testsuite/libgomp.c/collapse-3.c
new file mode 100644 (file)
index 0000000..4674f83
--- /dev/null
@@ -0,0 +1,31 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -std=gnu99" } */
+
+#include <string.h>
+#include <stdlib.h>
+
+int
+main (void)
+{
+  int i2, l = 0;
+  int a[3][3][3];
+
+  memset (a, '\0', sizeof (a));
+  #pragma omp parallel for collapse(4 - 1) schedule(static, 4)
+    for (int i = 0; i < 2; i++)
+      for (int j = 0; j < 2; j++)
+       for (int k = 0; k < 2; k++)
+         a[i][j][k] = i + j * 4 + k * 16;
+  #pragma omp parallel
+    {
+      #pragma omp for collapse(2) reduction(|:l)
+       for (i2 = 0; i2 < 2; i2++)
+         for (int j = 0; j < 2; j++)
+           for (int k = 0; k < 2; k++)
+             if (a[i2][j][k] != i2 + j * 4 + k * 16)
+               l = 1;
+    }
+  if (l)
+    abort ();
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/icv-1.c b/libgomp/testsuite/libgomp.c/icv-1.c
new file mode 100644 (file)
index 0000000..99708f8
--- /dev/null
@@ -0,0 +1,33 @@
+#include <omp.h>
+#include <stdlib.h>
+
+int
+main (void)
+{
+  int err = 0;
+
+  omp_set_num_threads (4);
+  if (omp_get_max_threads () != 4)
+    abort ();
+  #pragma omp parallel reduction(|: err) num_threads(1)
+  {
+    if (omp_get_max_threads () != 4)
+      err |= 1;
+    omp_set_num_threads (6);
+    #pragma omp task if(0) shared(err)
+    {
+      if (omp_get_max_threads () != 6)
+       err |= 2;
+      omp_set_num_threads (5);
+      if (omp_get_max_threads () != 5)
+       err |= 4;
+    }
+    if (omp_get_max_threads () != 6)
+      err |= 8;
+  }
+  if (err)
+    abort ();
+  if (omp_get_max_threads () != 4)
+    abort ();
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/icv-2.c b/libgomp/testsuite/libgomp.c/icv-2.c
new file mode 100644 (file)
index 0000000..326f8eb
--- /dev/null
@@ -0,0 +1,46 @@
+/* { dg-do run { target *-*-linux* } } */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+#include <pthread.h>
+#include <omp.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+pthread_barrier_t bar;
+
+void *tf (void *p)
+{
+  int l;
+  if (p)
+    omp_set_num_threads (3);
+  pthread_barrier_wait (&bar);
+  if (!p)
+    omp_set_num_threads (6);
+  pthread_barrier_wait (&bar);
+  omp_set_dynamic (0);
+  if (omp_get_max_threads () != (p ? 3 : 6))
+    abort ();
+  l = 0;
+  #pragma omp parallel num_threads (6) reduction (|:l)
+    {
+      l |= omp_get_max_threads () != (p ? 3 : 6);
+      omp_set_num_threads ((p ? 3 : 6) + omp_get_thread_num ());
+      l |= omp_get_max_threads () != ((p ? 3 : 6) + omp_get_thread_num ());
+    }
+  if (l)
+    abort ();
+  return NULL;
+}
+
+int
+main (void)
+{
+  pthread_t th;
+  pthread_barrier_init (&bar, NULL, 2);
+  pthread_create (&th, NULL, tf, NULL);
+  tf ("");
+  pthread_join (th, NULL);
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/lib-2.c b/libgomp/testsuite/libgomp.c/lib-2.c
new file mode 100644 (file)
index 0000000..3a3b3f6
--- /dev/null
@@ -0,0 +1,25 @@
+#include <stdlib.h>
+#include <omp.h>
+
+int
+main (void)
+{
+  omp_sched_t kind;
+  int modifier;
+
+  omp_set_schedule (omp_sched_static, 32);
+  omp_get_schedule (&kind, &modifier);
+  if (kind != omp_sched_static || modifier != 32)
+    abort ();
+  omp_set_schedule (omp_sched_guided, 4);
+  omp_get_schedule (&kind, &modifier);
+  if (kind != omp_sched_guided || modifier != 4)
+    abort ();
+  if (omp_get_thread_limit () < 0)
+    abort ();
+  omp_set_max_active_levels (6);
+  if (omp_get_max_active_levels () != 6)
+    abort ();
+
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/lock-1.c b/libgomp/testsuite/libgomp.c/lock-1.c
new file mode 100644 (file)
index 0000000..e09645d
--- /dev/null
@@ -0,0 +1,31 @@
+#include <omp.h>
+#include <stdlib.h>
+
+int
+main (void)
+{
+  int l = 0;
+  omp_nest_lock_t lock;
+  omp_init_nest_lock (&lock);
+  if (omp_test_nest_lock (&lock) != 1)
+    abort ();
+  if (omp_test_nest_lock (&lock) != 2)
+    abort ();
+#pragma omp parallel if (0) reduction (+:l)
+  {
+    /* In OpenMP 2.5 this was supposed to return 3,
+       but in OpenMP 3.0 the parallel region has a different
+       task and omp_*_lock_t are owned by tasks, not by threads.  */
+    if (omp_test_nest_lock (&lock) != 0)
+      l++;
+  }
+  if (l)
+    abort ();
+  if (omp_test_nest_lock (&lock) != 3)
+    abort ();
+  omp_unset_nest_lock (&lock);
+  omp_unset_nest_lock (&lock);
+  omp_unset_nest_lock (&lock);
+  omp_destroy_nest_lock (&lock);
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/lock-2.c b/libgomp/testsuite/libgomp.c/lock-2.c
new file mode 100644 (file)
index 0000000..9009b12
--- /dev/null
@@ -0,0 +1,32 @@
+#include <omp.h>
+#include <stdlib.h>
+
+int
+main (void)
+{
+  int l = 0;
+  omp_nest_lock_t lock;
+  omp_init_nest_lock (&lock);
+#pragma omp parallel reduction (+:l) num_threads (1)
+  {
+    if (omp_test_nest_lock (&lock) != 1)
+      l++;
+    if (omp_test_nest_lock (&lock) != 2)
+      l++;
+  #pragma omp task if (0) shared (lock, l)
+    {
+      if (omp_test_nest_lock (&lock) != 0)
+       l++;
+    }
+  #pragma omp taskwait
+    if (omp_test_nest_lock (&lock) != 3)
+      l++;
+    omp_unset_nest_lock (&lock);
+    omp_unset_nest_lock (&lock);
+    omp_unset_nest_lock (&lock);
+  }
+  if (l)
+    abort ();
+  omp_destroy_nest_lock (&lock);
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/lock-3.c b/libgomp/testsuite/libgomp.c/lock-3.c
new file mode 100644 (file)
index 0000000..1fc8372
--- /dev/null
@@ -0,0 +1,60 @@
+/* { dg-do run { target *-*-linux* } } */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+#include <pthread.h>
+#include <omp.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+pthread_barrier_t bar;
+omp_nest_lock_t lock;
+
+void *tf (void *p)
+{
+  int l;
+  if (p)
+    {
+      if (omp_test_nest_lock (&lock) != 1)
+       abort ();
+      if (omp_test_nest_lock (&lock) != 2)
+       abort ();
+    }
+  pthread_barrier_wait (&bar);
+  if (!p && omp_test_nest_lock (&lock) != 0)
+    abort ();
+  pthread_barrier_wait (&bar);
+  if (p)
+    {
+      if (omp_test_nest_lock (&lock) != 3)
+       abort ();
+      omp_unset_nest_lock (&lock);
+      omp_unset_nest_lock (&lock);
+      omp_unset_nest_lock (&lock);
+    }
+  pthread_barrier_wait (&bar);
+  if (!p)
+    {
+      if (omp_test_nest_lock (&lock) != 1)
+       abort ();
+      if (omp_test_nest_lock (&lock) != 2)
+       abort ();
+      omp_unset_nest_lock (&lock);
+      omp_unset_nest_lock (&lock);
+    }
+  return NULL;
+}
+
+int
+main (void)
+{
+  pthread_t th;
+  omp_init_nest_lock (&lock);
+  pthread_barrier_init (&bar, NULL, 2);
+  pthread_create (&th, NULL, tf, NULL);
+  tf ("");
+  pthread_join (th, NULL);
+  omp_destroy_nest_lock (&lock);
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/loop-4.c b/libgomp/testsuite/libgomp.c/loop-4.c
new file mode 100644 (file)
index 0000000..bc57c04
--- /dev/null
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+
+extern void abort (void);
+
+int
+main (void)
+{
+  int e = 0;
+#pragma omp parallel num_threads (4) reduction(+:e)
+  {
+    long i;
+    #pragma omp for schedule(dynamic,1)
+    for (i = __LONG_MAX__ - 30001; i <= __LONG_MAX__ - 10001; i += 10000)
+      if (i != __LONG_MAX__ - 30001
+         && i != __LONG_MAX__ - 20001
+         && i != __LONG_MAX__ - 10001)
+       e = 1;
+    #pragma omp for schedule(dynamic,1)
+    for (i = -__LONG_MAX__ + 30000; i >= -__LONG_MAX__ + 10000; i -= 10000)
+      if (i != -__LONG_MAX__ + 30000
+         && i != -__LONG_MAX__ + 20000
+         && i != -__LONG_MAX__ + 10000)
+       e = 1;
+  }
+  if (e)
+    abort ();
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/loop-5.c b/libgomp/testsuite/libgomp.c/loop-5.c
new file mode 100644 (file)
index 0000000..3a5c7cf
--- /dev/null
@@ -0,0 +1,276 @@
+#include <omp.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+test1 (void)
+{
+  short int buf[64], *p;
+  int i;
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for
+  for (p = &buf[10]; p < &buf[54]; p++)
+    *p = 5;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 5 * (i >= 10 && i < 54))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for
+  for (p = &buf[3]; p <= &buf[63]; p += 2)
+    p[-2] = 6;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 6 * ((i & 1) && i <= 61))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for
+  for (p = &buf[16]; p < &buf[51]; p = 4 + p)
+    p[2] = 7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 7 * ((i & 3) == 2 && i >= 18 && i < 53))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for
+  for (p = &buf[16]; p <= &buf[40]; p = p + 4ULL)
+    p[2] = -7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != -7 * ((i & 3) == 2 && i >= 18 && i <= 42))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for
+  for (p = &buf[53]; p > &buf[9]; --p)
+    *p = 5;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 5 * (i >= 10 && i < 54))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for
+  for (p = &buf[63]; p >= &buf[3]; p -= 2)
+    p[-2] = 6;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 6 * ((i & 1) && i <= 61))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for
+  for (p = &buf[48]; p > &buf[15]; p = -4 + p)
+    p[2] = 7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 7 * ((i & 3) == 2 && i >= 18 && i < 53))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for
+  for (p = &buf[40]; p >= &buf[16]; p = p - 4ULL)
+    p[2] = -7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != -7 * ((i & 3) == 2 && i >= 18 && i <= 42))
+      abort ();
+  return 0;
+}
+
+int
+test2 (void)
+{
+  int buf[64], *p;
+  int i;
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (static, 3)
+  for (p = &buf[10]; p < &buf[54]; p++)
+    *p = 5;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 5 * (i >= 10 && i < 54))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (static, 3)
+  for (p = &buf[3]; p <= &buf[63]; p += 2)
+    p[-2] = 6;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 6 * ((i & 1) && i <= 61))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (static, 3)
+  for (p = &buf[16]; p < &buf[51]; p = 4 + p)
+    p[2] = 7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 7 * ((i & 3) == 2 && i >= 18 && i < 53))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (static, 3)
+  for (p = &buf[16]; p <= &buf[40]; p = p + 4ULL)
+    p[2] = -7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != -7 * ((i & 3) == 2 && i >= 18 && i <= 42))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (static, 3)
+  for (p = &buf[53]; p > &buf[9]; --p)
+    *p = 5;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 5 * (i >= 10 && i < 54))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (static, 3)
+  for (p = &buf[63]; p >= &buf[3]; p -= 2)
+    p[-2] = 6;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 6 * ((i & 1) && i <= 61))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (static, 3)
+  for (p = &buf[48]; p > &buf[15]; p = -4 + p)
+    p[2] = 7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 7 * ((i & 3) == 2 && i >= 18 && i < 53))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (static, 3)
+  for (p = &buf[40]; p >= &buf[16]; p = p - 4ULL)
+    p[2] = -7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != -7 * ((i & 3) == 2 && i >= 18 && i <= 42))
+      abort ();
+  return 0;
+}
+
+int
+test3 (void)
+{
+  int buf[64], *p;
+  int i;
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (dynamic, 3)
+  for (p = &buf[10]; p < &buf[54]; p++)
+    *p = 5;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 5 * (i >= 10 && i < 54))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (dynamic, 3)
+  for (p = &buf[3]; p <= &buf[63]; p += 2)
+    p[-2] = 6;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 6 * ((i & 1) && i <= 61))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (dynamic, 3)
+  for (p = &buf[16]; p < &buf[51]; p = 4 + p)
+    p[2] = 7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 7 * ((i & 3) == 2 && i >= 18 && i < 53))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (dynamic, 3)
+  for (p = &buf[16]; p <= &buf[40]; p = p + 4ULL)
+    p[2] = -7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != -7 * ((i & 3) == 2 && i >= 18 && i <= 42))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (dynamic, 3)
+  for (p = &buf[53]; p > &buf[9]; --p)
+    *p = 5;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 5 * (i >= 10 && i < 54))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (dynamic, 3)
+  for (p = &buf[63]; p >= &buf[3]; p -= 2)
+    p[-2] = 6;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 6 * ((i & 1) && i <= 61))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (dynamic, 3)
+  for (p = &buf[48]; p > &buf[15]; p = -4 + p)
+    p[2] = 7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 7 * ((i & 3) == 2 && i >= 18 && i < 53))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (dynamic, 3)
+  for (p = &buf[40]; p >= &buf[16]; p = p - 4ULL)
+    p[2] = -7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != -7 * ((i & 3) == 2 && i >= 18 && i <= 42))
+      abort ();
+  return 0;
+}
+
+int
+test4 (void)
+{
+  int buf[64], *p;
+  int i;
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (runtime)
+  for (p = &buf[10]; p < &buf[54]; p++)
+    *p = 5;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 5 * (i >= 10 && i < 54))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (runtime)
+  for (p = &buf[3]; p <= &buf[63]; p += 2)
+    p[-2] = 6;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 6 * ((i & 1) && i <= 61))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (runtime)
+  for (p = &buf[16]; p < &buf[51]; p = 4 + p)
+    p[2] = 7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 7 * ((i & 3) == 2 && i >= 18 && i < 53))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (runtime)
+  for (p = &buf[16]; p <= &buf[40]; p = p + 4ULL)
+    p[2] = -7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != -7 * ((i & 3) == 2 && i >= 18 && i <= 42))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (runtime)
+  for (p = &buf[53]; p > &buf[9]; --p)
+    *p = 5;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 5 * (i >= 10 && i < 54))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (runtime)
+  for (p = &buf[63]; p >= &buf[3]; p -= 2)
+    p[-2] = 6;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 6 * ((i & 1) && i <= 61))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (runtime)
+  for (p = &buf[48]; p > &buf[15]; p = -4 + p)
+    p[2] = 7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != 7 * ((i & 3) == 2 && i >= 18 && i < 53))
+      abort ();
+  memset (buf, '\0', sizeof (buf));
+#pragma omp parallel for schedule (runtime)
+  for (p = &buf[40]; p >= &buf[16]; p = p - 4ULL)
+    p[2] = -7;
+  for (i = 0; i < 64; i++)
+    if (buf[i] != -7 * ((i & 3) == 2 && i >= 18 && i <= 42))
+      abort ();
+  return 0;
+}
+
+int
+main (void)
+{
+  test1 ();
+  test2 ();
+  test3 ();
+  omp_set_schedule (omp_sched_static, 0);
+  test4 ();
+  omp_set_schedule (omp_sched_static, 3);
+  test4 ();
+  omp_set_schedule (omp_sched_dynamic, 5);
+  test4 ();
+  omp_set_schedule (omp_sched_guided, 2);
+  test4 ();
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/loop-6.c b/libgomp/testsuite/libgomp.c/loop-6.c
new file mode 100644 (file)
index 0000000..9029e18
--- /dev/null
@@ -0,0 +1,387 @@
+/* { dg-do run } */
+
+#include <omp.h>
+
+extern void abort (void);
+
+#define LLONG_MAX __LONG_LONG_MAX__
+#define ULLONG_MAX (LLONG_MAX * 2ULL + 1)
+#define INT_MAX __INT_MAX__
+
+int arr[6 * 5];
+
+void
+set (int loopidx, int idx)
+{
+#pragma omp atomic
+  arr[loopidx * 5 + idx]++;
+}
+
+#define check(var, val, loopidx, idx) \
+  if (var == (val)) set (loopidx, idx); else
+#define test(loopidx, count) \
+  for (idx = 0; idx < 5; idx++) \
+    if (arr[loopidx * 5 + idx] != idx < count) \
+      abort (); \
+    else \
+      arr[loopidx * 5 + idx] = 0
+
+int
+test1 (void)
+{
+  int e = 0, idx;
+
+#pragma omp parallel reduction(+:e)
+  {
+    long long i;
+    unsigned long long j;
+    #pragma omp for schedule(dynamic,1) nowait
+    for (i = LLONG_MAX - 30001; i <= LLONG_MAX - 10001; i += 10000)
+      {
+       check (i, LLONG_MAX - 30001, 0, 0)
+       check (i, LLONG_MAX - 20001, 0, 1)
+       check (i, LLONG_MAX - 10001, 0, 2)
+       e = 1;
+      }
+    #pragma omp for schedule(dynamic,1) nowait
+    for (i = -LLONG_MAX + 30000; i >= -LLONG_MAX + 10000; i -= 10000)
+      {
+       check (i, -LLONG_MAX + 30000, 1, 0)
+       check (i, -LLONG_MAX + 20000, 1, 1)
+       check (i, -LLONG_MAX + 10000, 1, 2)
+       e = 1;
+      }
+    #pragma omp for schedule(dynamic,1) nowait
+    for (j = 20; j <= LLONG_MAX - 70; j += LLONG_MAX + 50ULL)
+      {
+       check (j, 20, 2, 0)
+       e = 1;
+      }
+    #pragma omp for schedule(dynamic,1) nowait
+    for (j = ULLONG_MAX - 3; j >= LLONG_MAX + 70ULL; j -= LLONG_MAX + 50ULL)
+      {
+       check (j, ULLONG_MAX - 3, 3, 0)
+       e = 1;
+      }
+    #pragma omp for schedule(dynamic,1) nowait
+    for (j = LLONG_MAX - 20000ULL; j <= LLONG_MAX + 10000ULL; j += 10000ULL)
+      {
+       check (j, LLONG_MAX - 20000ULL, 4, 0)
+       check (j, LLONG_MAX - 10000ULL, 4, 1)
+       check (j, LLONG_MAX, 4, 2)
+       check (j, LLONG_MAX + 10000ULL, 4, 3)
+       e = 1;
+      }
+    #pragma omp for schedule(dynamic,1) nowait
+    for (i = -3LL * INT_MAX - 20000LL; i <= INT_MAX + 10000LL; i += INT_MAX + 200LL)
+      {
+       check (i, -3LL * INT_MAX - 20000LL, 5, 0)
+       check (i, -2LL * INT_MAX - 20000LL + 200LL, 5, 1)
+       check (i, -INT_MAX - 20000LL + 400LL, 5, 2)
+       check (i, -20000LL + 600LL, 5, 3)
+       check (i, INT_MAX - 20000LL + 800LL, 5, 4)
+       e = 1;
+      }
+  }
+  if (e)
+    abort ();
+  test (0, 3);
+  test (1, 3);
+  test (2, 1);
+  test (3, 1);
+  test (4, 4);
+  test (5, 5);
+  return 0;
+}
+
+int
+test2 (void)
+{
+  int e = 0, idx;
+
+#pragma omp parallel reduction(+:e)
+  {
+    long long i;
+    unsigned long long j;
+    #pragma omp for schedule(guided,1) nowait
+    for (i = LLONG_MAX - 30001; i <= LLONG_MAX - 10001; i += 10000)
+      {
+       check (i, LLONG_MAX - 30001, 0, 0)
+       check (i, LLONG_MAX - 20001, 0, 1)
+       check (i, LLONG_MAX - 10001, 0, 2)
+       e = 1;
+      }
+    #pragma omp for schedule(guided,1) nowait
+    for (i = -LLONG_MAX + 30000; i >= -LLONG_MAX + 10000; i -= 10000)
+      {
+       check (i, -LLONG_MAX + 30000, 1, 0)
+       check (i, -LLONG_MAX + 20000, 1, 1)
+       check (i, -LLONG_MAX + 10000, 1, 2)
+       e = 1;
+      }
+    #pragma omp for schedule(guided,1) nowait
+    for (j = 20; j <= LLONG_MAX - 70; j += LLONG_MAX + 50ULL)
+      {
+       check (j, 20, 2, 0)
+       e = 1;
+      }
+    #pragma omp for schedule(guided,1) nowait
+    for (j = ULLONG_MAX - 3; j >= LLONG_MAX + 70ULL; j -= LLONG_MAX + 50ULL)
+      {
+       check (j, ULLONG_MAX - 3, 3, 0)
+       e = 1;
+      }
+    #pragma omp for schedule(guided,1) nowait
+    for (j = LLONG_MAX - 20000ULL; j <= LLONG_MAX + 10000ULL; j += 10000ULL)
+      {
+       check (j, LLONG_MAX - 20000ULL, 4, 0)
+       check (j, LLONG_MAX - 10000ULL, 4, 1)
+       check (j, LLONG_MAX, 4, 2)
+       check (j, LLONG_MAX + 10000ULL, 4, 3)
+       e = 1;
+      }
+    #pragma omp for schedule(guided,1) nowait
+    for (i = -3LL * INT_MAX - 20000LL; i <= INT_MAX + 10000LL; i += INT_MAX + 200LL)
+      {
+       check (i, -3LL * INT_MAX - 20000LL, 5, 0)
+       check (i, -2LL * INT_MAX - 20000LL + 200LL, 5, 1)
+       check (i, -INT_MAX - 20000LL + 400LL, 5, 2)
+       check (i, -20000LL + 600LL, 5, 3)
+       check (i, INT_MAX - 20000LL + 800LL, 5, 4)
+       e = 1;
+      }
+  }
+  if (e)
+    abort ();
+  test (0, 3);
+  test (1, 3);
+  test (2, 1);
+  test (3, 1);
+  test (4, 4);
+  test (5, 5);
+  return 0;
+}
+
+int
+test3 (void)
+{
+  int e = 0, idx;
+
+#pragma omp parallel reduction(+:e)
+  {
+    long long i;
+    unsigned long long j;
+    #pragma omp for schedule(static) nowait
+    for (i = LLONG_MAX - 30001; i <= LLONG_MAX - 10001; i += 10000)
+      {
+       check (i, LLONG_MAX - 30001, 0, 0)
+       check (i, LLONG_MAX - 20001, 0, 1)
+       check (i, LLONG_MAX - 10001, 0, 2)
+       e = 1;
+      }
+    #pragma omp for schedule(static) nowait
+    for (i = -LLONG_MAX + 30000; i >= -LLONG_MAX + 10000; i -= 10000)
+      {
+       check (i, -LLONG_MAX + 30000, 1, 0)
+       check (i, -LLONG_MAX + 20000, 1, 1)
+       check (i, -LLONG_MAX + 10000, 1, 2)
+       e = 1;
+      }
+    #pragma omp for schedule(static) nowait
+    for (j = 20; j <= LLONG_MAX - 70; j += LLONG_MAX + 50ULL)
+      {
+       check (j, 20, 2, 0)
+       e = 1;
+      }
+    #pragma omp for schedule(static) nowait
+    for (j = ULLONG_MAX - 3; j >= LLONG_MAX + 70ULL; j -= LLONG_MAX + 50ULL)
+      {
+       check (j, ULLONG_MAX - 3, 3, 0)
+       e = 1;
+      }
+    #pragma omp for schedule(static) nowait
+    for (j = LLONG_MAX - 20000ULL; j <= LLONG_MAX + 10000ULL; j += 10000ULL)
+      {
+       check (j, LLONG_MAX - 20000ULL, 4, 0)
+       check (j, LLONG_MAX - 10000ULL, 4, 1)
+       check (j, LLONG_MAX, 4, 2)
+       check (j, LLONG_MAX + 10000ULL, 4, 3)
+       e = 1;
+      }
+    #pragma omp for schedule(static) nowait
+    for (i = -3LL * INT_MAX - 20000LL; i <= INT_MAX + 10000LL; i += INT_MAX + 200LL)
+      {
+       check (i, -3LL * INT_MAX - 20000LL, 5, 0)
+       check (i, -2LL * INT_MAX - 20000LL + 200LL, 5, 1)
+       check (i, -INT_MAX - 20000LL + 400LL, 5, 2)
+       check (i, -20000LL + 600LL, 5, 3)
+       check (i, INT_MAX - 20000LL + 800LL, 5, 4)
+       e = 1;
+      }
+  }
+  if (e)
+    abort ();
+  test (0, 3);
+  test (1, 3);
+  test (2, 1);
+  test (3, 1);
+  test (4, 4);
+  test (5, 5);
+  return 0;
+}
+
+int
+test4 (void)
+{
+  int e = 0, idx;
+
+#pragma omp parallel reduction(+:e)
+  {
+    long long i;
+    unsigned long long j;
+    #pragma omp for schedule(static,1) nowait
+    for (i = LLONG_MAX - 30001; i <= LLONG_MAX - 10001; i += 10000)
+      {
+       check (i, LLONG_MAX - 30001, 0, 0)
+       check (i, LLONG_MAX - 20001, 0, 1)
+       check (i, LLONG_MAX - 10001, 0, 2)
+       e = 1;
+      }
+    #pragma omp for schedule(static,1) nowait
+    for (i = -LLONG_MAX + 30000; i >= -LLONG_MAX + 10000; i -= 10000)
+      {
+       check (i, -LLONG_MAX + 30000, 1, 0)
+       check (i, -LLONG_MAX + 20000, 1, 1)
+       check (i, -LLONG_MAX + 10000, 1, 2)
+       e = 1;
+      }
+    #pragma omp for schedule(static,1) nowait
+    for (j = 20; j <= LLONG_MAX - 70; j += LLONG_MAX + 50ULL)
+      {
+       check (j, 20, 2, 0)
+       e = 1;
+      }
+    #pragma omp for schedule(static,1) nowait
+    for (j = ULLONG_MAX - 3; j >= LLONG_MAX + 70ULL; j -= LLONG_MAX + 50ULL)
+      {
+       check (j, ULLONG_MAX - 3, 3, 0)
+       e = 1;
+      }
+    #pragma omp for schedule(static,1) nowait
+    for (j = LLONG_MAX - 20000ULL; j <= LLONG_MAX + 10000ULL; j += 10000ULL)
+      {
+       check (j, LLONG_MAX - 20000ULL, 4, 0)
+       check (j, LLONG_MAX - 10000ULL, 4, 1)
+       check (j, LLONG_MAX, 4, 2)
+       check (j, LLONG_MAX + 10000ULL, 4, 3)
+       e = 1;
+      }
+    #pragma omp for schedule(static,1) nowait
+    for (i = -3LL * INT_MAX - 20000LL; i <= INT_MAX + 10000LL; i += INT_MAX + 200LL)
+      {
+       check (i, -3LL * INT_MAX - 20000LL, 5, 0)
+       check (i, -2LL * INT_MAX - 20000LL + 200LL, 5, 1)
+       check (i, -INT_MAX - 20000LL + 400LL, 5, 2)
+       check (i, -20000LL + 600LL, 5, 3)
+       check (i, INT_MAX - 20000LL + 800LL, 5, 4)
+       e = 1;
+      }
+  }
+  if (e)
+    abort ();
+  test (0, 3);
+  test (1, 3);
+  test (2, 1);
+  test (3, 1);
+  test (4, 4);
+  test (5, 5);
+  return 0;
+}
+
+int
+test5 (void)
+{
+  int e = 0, idx;
+
+#pragma omp parallel reduction(+:e)
+  {
+    long long i;
+    unsigned long long j;
+    #pragma omp for schedule(runtime) nowait
+    for (i = LLONG_MAX - 30001; i <= LLONG_MAX - 10001; i += 10000)
+      {
+       check (i, LLONG_MAX - 30001, 0, 0)
+       check (i, LLONG_MAX - 20001, 0, 1)
+       check (i, LLONG_MAX - 10001, 0, 2)
+       e = 1;
+      }
+    #pragma omp for schedule(runtime) nowait
+    for (i = -LLONG_MAX + 30000; i >= -LLONG_MAX + 10000; i -= 10000)
+      {
+       check (i, -LLONG_MAX + 30000, 1, 0)
+       check (i, -LLONG_MAX + 20000, 1, 1)
+       check (i, -LLONG_MAX + 10000, 1, 2)
+       e = 1;
+      }
+    #pragma omp for schedule(runtime) nowait
+    for (j = 20; j <= LLONG_MAX - 70; j += LLONG_MAX + 50ULL)
+      {
+       check (j, 20, 2, 0)
+       e = 1;
+      }
+    #pragma omp for schedule(runtime) nowait
+    for (j = ULLONG_MAX - 3; j >= LLONG_MAX + 70ULL; j -= LLONG_MAX + 50ULL)
+      {
+       check (j, ULLONG_MAX - 3, 3, 0)
+       e = 1;
+      }
+    #pragma omp for schedule(runtime) nowait
+    for (j = LLONG_MAX - 20000ULL; j <= LLONG_MAX + 10000ULL; j += 10000ULL)
+      {
+       check (j, LLONG_MAX - 20000ULL, 4, 0)
+       check (j, LLONG_MAX - 10000ULL, 4, 1)
+       check (j, LLONG_MAX, 4, 2)
+       check (j, LLONG_MAX + 10000ULL, 4, 3)
+       e = 1;
+      }
+    #pragma omp for schedule(runtime) nowait
+    for (i = -3LL * INT_MAX - 20000LL; i <= INT_MAX + 10000LL; i += INT_MAX + 200LL)
+      {
+       check (i, -3LL * INT_MAX - 20000LL, 5, 0)
+       check (i, -2LL * INT_MAX - 20000LL + 200LL, 5, 1)
+       check (i, -INT_MAX - 20000LL + 400LL, 5, 2)
+       check (i, -20000LL + 600LL, 5, 3)
+       check (i, INT_MAX - 20000LL + 800LL, 5, 4)
+       e = 1;
+      }
+  }
+  if (e)
+    abort ();
+  test (0, 3);
+  test (1, 3);
+  test (2, 1);
+  test (3, 1);
+  test (4, 4);
+  test (5, 5);
+  return 0;
+}
+
+int
+main (void)
+{
+  if (2 * sizeof (int) != sizeof (long long))
+    return 0;
+  test1 ();
+  test2 ();
+  test3 ();
+  test4 ();
+  omp_set_schedule (omp_sched_static, 0);
+  test5 ();
+  omp_set_schedule (omp_sched_static, 3);
+  test5 ();
+  omp_set_schedule (omp_sched_dynamic, 5);
+  test5 ();
+  omp_set_schedule (omp_sched_guided, 2);
+  test5 ();
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/loop-7.c b/libgomp/testsuite/libgomp.c/loop-7.c
new file mode 100644 (file)
index 0000000..fc97f4a
--- /dev/null
@@ -0,0 +1,105 @@
+/* { dg-do run } */
+
+#include <omp.h>
+
+extern void abort (void);
+
+#define LLONG_MAX __LONG_LONG_MAX__
+#define ULLONG_MAX (LLONG_MAX * 2ULL + 1)
+#define INT_MAX __INT_MAX__
+
+int v;
+
+int
+test1 (void)
+{
+  int e = 0, cnt = 0;
+  long long i;
+  unsigned long long j;
+  char buf[6], *p;
+
+  #pragma omp for schedule(dynamic,1) collapse(2) nowait
+  for (i = LLONG_MAX - 30001; i <= LLONG_MAX - 10001; i += 10000)
+    for (j = 20; j <= LLONG_MAX - 70; j += LLONG_MAX + 50ULL)
+      if ((i != LLONG_MAX - 30001
+          && i != LLONG_MAX - 20001
+          && i != LLONG_MAX - 10001)
+         || j != 20)
+       e = 1;
+      else
+       cnt++;
+  if (e || cnt != 3)
+    abort ();
+  else
+    cnt = 0;
+
+  #pragma omp for schedule(guided,1) collapse(2) nowait
+  for (i = -LLONG_MAX + 30000; i >= -LLONG_MAX + 10000; i -= 10000)
+    for (j = ULLONG_MAX - 3; j >= LLONG_MAX + 70ULL; j -= LLONG_MAX + 50ULL)
+      if ((i != -LLONG_MAX + 30000
+          && i != -LLONG_MAX + 20000
+          && i != -LLONG_MAX + 10000)
+         || j != ULLONG_MAX - 3)
+       e = 1;
+      else
+       cnt++;
+  if (e || cnt != 3)
+    abort ();
+  else
+    cnt = 0;
+
+  #pragma omp for schedule(static,1) collapse(2) nowait
+  for (i = LLONG_MAX - 30001; i <= LLONG_MAX - 10001; i += 10000)
+    for (j = 20; j <= LLONG_MAX - 70 + v; j += LLONG_MAX + 50ULL)
+      if ((i != LLONG_MAX - 30001
+          && i != LLONG_MAX - 20001
+          && i != LLONG_MAX - 10001)
+         || j != 20)
+       e = 1;
+      else
+       cnt++;
+  if (e || cnt != 3)
+    abort ();
+  else
+    cnt = 0;
+
+  #pragma omp for schedule(static) collapse(2) nowait
+  for (i = -LLONG_MAX + 30000 + v; i >= -LLONG_MAX + 10000; i -= 10000)
+    for (j = ULLONG_MAX - 3; j >= LLONG_MAX + 70ULL; j -= LLONG_MAX + 50ULL)
+      if ((i != -LLONG_MAX + 30000
+          && i != -LLONG_MAX + 20000
+          && i != -LLONG_MAX + 10000)
+         || j != ULLONG_MAX - 3)
+       e = 1;
+      else
+       cnt++;
+  if (e || cnt != 3)
+    abort ();
+  else
+    cnt = 0;
+
+  #pragma omp for schedule(runtime) collapse(2) nowait
+  for (i = 10; i < 30; i++)
+    for (p = buf; p <= buf + 4; p += 2)
+      if (i < 10 || i >= 30 || (p != buf && p != buf + 2 && p != buf + 4))
+       e = 1;
+      else
+       cnt++;
+  if (e || cnt != 60)
+    abort ();
+  else
+    cnt = 0;
+
+  return 0;
+}
+
+int
+main (void)
+{
+  if (2 * sizeof (int) != sizeof (long long))
+    return 0;
+  asm volatile ("" : "+r" (v));
+  omp_set_schedule (omp_sched_dynamic, 1);
+  test1 ();
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/loop-8.c b/libgomp/testsuite/libgomp.c/loop-8.c
new file mode 100644 (file)
index 0000000..25db25c
--- /dev/null
@@ -0,0 +1,27 @@
+extern void abort (void);
+
+int buf[256];
+
+void __attribute__((noinline))
+foo (void)
+{
+  int i;
+  #pragma omp for schedule (auto)
+    for (i = 0; i < 256; i++)
+      buf[i] += i;
+}
+
+int
+main (void)
+{
+  int i;
+  #pragma omp parallel for schedule (auto)
+    for (i = 0; i < 256; i++)
+      buf[i] = i;
+  #pragma omp parallel num_threads (4)
+    foo ();
+  for (i = 0; i < 256; i++)
+    if (buf[i] != 2 * i)
+      abort ();
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/loop-9.c b/libgomp/testsuite/libgomp.c/loop-9.c
new file mode 100644 (file)
index 0000000..1f789e1
--- /dev/null
@@ -0,0 +1,18 @@
+extern void abort (void);
+
+char buf[8] = "01234567";
+char buf2[8] = "23456789";
+
+int
+main (void)
+{
+  char *p, *q;
+  int sum = 0;
+  #pragma omp parallel for collapse (2) reduction (+:sum) lastprivate (p, q)
+  for (p = buf; p < &buf[8]; p++)
+    for (q = &buf2[0]; q <= buf2 + 7; q++)
+      sum += (*p - '0') + (*q - '0');
+  if (p != &buf[8] || q != buf2 + 8 || sum != 576)
+    abort ();
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/nested-3.c b/libgomp/testsuite/libgomp.c/nested-3.c
new file mode 100644 (file)
index 0000000..6186006
--- /dev/null
@@ -0,0 +1,89 @@
+#include <omp.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+main (void)
+{
+  int e[3];
+
+  memset (e, '\0', sizeof (e));
+  omp_set_nested (1);
+  omp_set_dynamic (0);
+  if (omp_in_parallel ()
+      || omp_get_level () != 0
+      || omp_get_ancestor_thread_num (0) != 0
+      || omp_get_ancestor_thread_num (-1) != -1
+      || omp_get_ancestor_thread_num (1) != -1
+      || omp_get_team_size (0) != 1
+      || omp_get_team_size (-1) != -1
+      || omp_get_team_size (1) != -1
+      || omp_get_active_level () != 0)
+    abort ();
+#pragma omp parallel num_threads (4)
+  {
+    int tn1 = omp_get_thread_num ();
+    if (omp_in_parallel () != 1
+       || omp_get_num_threads () != 4
+       || tn1 >= 4 || tn1 < 0
+       || omp_get_level () != 1
+       || omp_get_ancestor_thread_num (0) != 0
+       || omp_get_ancestor_thread_num (1) != tn1
+       || omp_get_ancestor_thread_num (-1) != -1
+       || omp_get_ancestor_thread_num (2) != -1
+       || omp_get_team_size (0) != 1
+       || omp_get_team_size (1) != omp_get_num_threads ()
+       || omp_get_team_size (-1) != -1
+       || omp_get_team_size (2) != -1
+       || omp_get_active_level () != 1)
+      #pragma omp atomic
+       e[0] += 1;
+    #pragma omp parallel if (0) num_threads(5) firstprivate(tn1)
+    {
+      int tn2 = omp_get_thread_num ();
+      if (omp_in_parallel () != 1
+         || omp_get_num_threads () != 1
+         || tn2 != 0
+         || omp_get_level () != 2
+         || omp_get_ancestor_thread_num (0) != 0
+         || omp_get_ancestor_thread_num (1) != tn1
+         || omp_get_ancestor_thread_num (2) != tn2
+         || omp_get_ancestor_thread_num (-1) != -1
+         || omp_get_ancestor_thread_num (3) != -1
+         || omp_get_team_size (0) != 1
+         || omp_get_team_size (1) != 4
+         || omp_get_team_size (2) != 1
+         || omp_get_team_size (-1) != -1
+         || omp_get_team_size (3) != -1
+         || omp_get_active_level () != 1)
+       #pragma omp atomic
+         e[1] += 1;
+      #pragma omp parallel num_threads(2) firstprivate(tn1, tn2)
+      {
+       int tn3 = omp_get_thread_num ();
+       if (omp_in_parallel () != 1
+           || omp_get_num_threads () != 2
+           || tn3 > 1 || tn3 < 0
+           || omp_get_level () != 3
+           || omp_get_ancestor_thread_num (0) != 0
+           || omp_get_ancestor_thread_num (1) != tn1
+           || omp_get_ancestor_thread_num (2) != tn2
+           || omp_get_ancestor_thread_num (3) != tn3
+           || omp_get_ancestor_thread_num (-1) != -1
+           || omp_get_ancestor_thread_num (4) != -1
+           || omp_get_team_size (0) != 1
+           || omp_get_team_size (1) != 4
+           || omp_get_team_size (2) != 1
+           || omp_get_team_size (3) != 2
+           || omp_get_team_size (-1) != -1
+           || omp_get_team_size (4) != -1
+           || omp_get_active_level () != 2)
+         #pragma omp atomic
+           e[2] += 1;
+      }
+    }
+  }
+  if (e[0] || e[1] || e[2])
+    abort ();
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/nestedfn-6.c b/libgomp/testsuite/libgomp.c/nestedfn-6.c
new file mode 100644 (file)
index 0000000..c0ace6b
--- /dev/null
@@ -0,0 +1,21 @@
+extern void abort (void);
+
+int j;
+
+int
+main (void)
+{
+  int i;
+  void nested (void) { i = 0; }
+#pragma omp parallel for lastprivate (i)
+  for (i = 0; i < 50; i += 3)
+    ;
+  if (i != 51)
+    abort ();
+#pragma omp parallel for lastprivate (j)
+  for (j = -50; j < 70; j += 7)
+    ;
+  if (j != 76)
+    abort ();
+  return 0;
+}
index 778048492f65fa9b9fdd213792783aa2aab14deb..c052e8112885fdeb4a174880081f34cc2ae1662c 100644 (file)
@@ -20,7 +20,7 @@ main (void)
     {
       if (a != 8 || b != 12 || e[0] != 'a' || f[0] != 'b')
        j++;
-#pragma omp barrier
+#pragma omp barrier    /* { dg-warning "may not be closely nested" } */
 #pragma omp atomic
       a += i;
       b += i;
@@ -31,7 +31,7 @@ main (void)
       f[0] += i;
       g[0] = 'g' + i;
       h[0] = 'h' + i;
-#pragma omp barrier
+#pragma omp barrier    /* { dg-warning "may not be closely nested" } */
       if (a != 8 + 6 || b != 12 + i || c != i || d != i)
        j += 8;
       if (e[0] != 'a' + 6 || f[0] != 'b' + i || g[0] != 'g' + i)
index be93cb479d13752c2d2d0dcf12d4b709d59f75d1..dc3d5010da1df1ff0dd1ccccae0f4fd1028007cf 100644 (file)
@@ -26,7 +26,7 @@ main (void)
        {
          if (a != 8 || b != 12 || e[0] != 'a' || f[0] != 'b')
            j++;
-#pragma omp barrier
+#pragma omp barrier    /* { dg-warning "may not be closely nested" } */
 #pragma omp atomic
          a += i;
          b += i;
@@ -37,7 +37,7 @@ main (void)
          f[0] += i;
          g[0] = 'g' + i;
          h[0] = 'h' + i;
-#pragma omp barrier
+#pragma omp barrier    /* { dg-warning "may not be closely nested" } */
          if (a != 8 + 6 || b != 12 + i || c != i || d != i)
            j += 8;
          if (e[0] != 'a' + 6 || f[0] != 'b' + i || g[0] != 'g' + i)
index 33d368583dd8887c66324074af790b152d1091cb..0f1d4197a5f12a7dd6e57ed3cae794bd8365c717 100644 (file)
@@ -27,7 +27,7 @@ main (void)
        {
          if (a != 8 || b != 12 || e[0] != 'a' || f[0] != 'b')
            j++;
-#pragma omp barrier
+#pragma omp barrier    /* { dg-warning "may not be closely nested" } */
 #pragma omp atomic
          a += i;
          b += i;
@@ -38,7 +38,7 @@ main (void)
          f[0] += i;
          g[0] = 'g' + i;
          h[0] = 'h' + i;
-#pragma omp barrier
+#pragma omp barrier    /* { dg-warning "may not be closely nested" } */
          if (a != 8 + 6 || b != 12 + i || c != i || d != i)
            j += 8;
          if (e[0] != 'a' + 6 || f[0] != 'b' + i || g[0] != 'g' + i)
diff --git a/libgomp/testsuite/libgomp.c/sort-1.c b/libgomp/testsuite/libgomp.c/sort-1.c
new file mode 100644 (file)
index 0000000..269d69d
--- /dev/null
@@ -0,0 +1,379 @@
+/* Test and benchmark of a couple of parallel sorting algorithms.
+   Copyright (C) 2008 Free Software Foundation, Inc.
+
+   GCC is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 3, or (at your option) any later
+   version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+   for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <limits.h>
+#include <omp.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int failures;
+
+#define THRESHOLD 100
+
+static void
+verify (const char *name, double stime, int *array, int count)
+{
+  int i;
+  double etime = omp_get_wtime ();
+
+  printf ("%s: %g\n", name, etime - stime);
+  for (i = 1; i < count; i++)
+    if (array[i] < array[i - 1])
+      {
+       printf ("%s: incorrectly sorted\n", name);
+       failures = 1;
+      }
+}
+
+static void
+insertsort (int *array, int s, int e)
+{
+  int i, j, val;
+  for (i = s + 1; i <= e; i++)
+    {
+      val = array[i];
+      j = i;
+      while (j-- > s && val < array[j])
+       array[j + 1] = array[j];
+      array[j + 1] = val;
+    }
+}
+
+struct int_pair
+{
+  int lo;
+  int hi;
+};
+
+struct int_pair_stack
+{
+  struct int_pair *top;
+#define STACK_SIZE 4 * CHAR_BIT * sizeof (int)
+  struct int_pair arr[STACK_SIZE];
+};
+
+static inline void
+init_int_pair_stack (struct int_pair_stack *stack)
+{
+  stack->top = &stack->arr[0];
+}
+
+static inline void
+push_int_pair_stack (struct int_pair_stack *stack, int lo, int hi)
+{
+  stack->top->lo = lo;
+  stack->top->hi = hi;
+  stack->top++;
+}
+
+static inline void
+pop_int_pair_stack (struct int_pair_stack *stack, int *lo, int *hi)
+{
+  stack->top--;
+  *lo = stack->top->lo;
+  *hi = stack->top->hi;
+}
+
+static inline int
+size_int_pair_stack (struct int_pair_stack *stack)
+{
+  return stack->top - &stack->arr[0];
+}
+
+static inline void
+busy_wait (void)
+{
+#if defined __i386__ || defined __x86_64__
+  __asm volatile ("rep; nop" : : : "memory");
+#elif defined __ia64__
+  __asm volatile ("hint @pause" : : : "memory");
+#elif defined __sparc__ && (defined __arch64__ || defined __sparc_v9__)
+  __asm volatile ("membar #LoadLoad" : : : "memory");
+#else
+  __asm volatile ("" : : : "memory");
+#endif
+}
+
+static inline void
+swap (int *array, int a, int b)
+{
+  int val = array[a];
+  array[a] = array[b];
+  array[b] = val;
+}
+
+static inline int
+choose_pivot (int *array, int lo, int hi)
+{
+  int mid = (lo + hi) / 2;
+
+  if (array[mid] < array[lo])
+    swap (array, lo, mid);
+  if (array[hi] < array[mid])
+    {
+      swap (array, mid, hi);
+      if (array[mid] < array[lo])
+       swap (array, lo, mid);
+    }
+  return array[mid];
+}
+
+static inline int
+partition (int *array, int lo, int hi)
+{
+  int pivot = choose_pivot (array, lo, hi);
+  int left = lo;
+  int right = hi;
+
+  for (;;)
+    {
+      while (array[++left] < pivot);
+      while (array[--right] > pivot);
+      if (left >= right)
+       break;
+      swap (array, left, right);
+    }
+  return left;
+}
+
+static void
+sort1 (int *array, int count)
+{
+  omp_lock_t lock;
+  struct int_pair_stack global_stack;
+  int busy = 1;
+  int num_threads;
+
+  omp_init_lock (&lock);
+  init_int_pair_stack (&global_stack);
+  #pragma omp parallel firstprivate (array, count)
+  {
+    int lo = 0, hi = 0, mid, next_lo, next_hi;
+    bool idle = true;
+    struct int_pair_stack local_stack;
+
+    init_int_pair_stack (&local_stack);
+    if (omp_get_thread_num () == 0)
+      {
+       num_threads = omp_get_num_threads ();
+       hi = count - 1;
+       idle = false;
+      }
+
+    for (;;)
+      {
+       if (hi - lo < THRESHOLD)
+         {
+           insertsort (array, lo, hi);
+           lo = hi;
+         }
+       if (lo >= hi)
+         {
+           if (size_int_pair_stack (&local_stack) == 0)
+             {
+             again:
+               omp_set_lock (&lock);
+               if (size_int_pair_stack (&global_stack) == 0)
+                 {
+                   if (!idle)
+                     busy--;
+                   if (busy == 0)
+                     {
+                       omp_unset_lock (&lock);
+                       break;
+                     }
+                   omp_unset_lock (&lock);
+                   idle = true;
+                   while (size_int_pair_stack (&global_stack) == 0
+                          && busy)
+                     busy_wait ();
+                   goto again;
+                 }
+               if (idle)
+                 busy++;
+               pop_int_pair_stack (&global_stack, &lo, &hi);
+               omp_unset_lock (&lock);
+               idle = false;
+             }
+           else
+             pop_int_pair_stack (&local_stack, &lo, &hi);
+         }
+
+       mid = partition (array, lo, hi);
+       if (mid - lo < hi - mid)
+         {
+           next_lo = mid;
+           next_hi = hi;
+           hi = mid - 1;
+         }
+       else
+         {
+           next_lo = lo;
+           next_hi = mid - 1;
+           lo = mid;
+         }
+
+       if (next_hi - next_lo < THRESHOLD)
+         insertsort (array, next_lo, next_hi);
+       else
+         {
+           if (size_int_pair_stack (&global_stack) < num_threads - 1)
+             {
+               int size;
+
+               omp_set_lock (&lock);
+               size = size_int_pair_stack (&global_stack);
+               if (size < num_threads - 1 && size < STACK_SIZE)
+                 push_int_pair_stack (&global_stack, next_lo, next_hi);
+               else
+                 push_int_pair_stack (&local_stack, next_lo, next_hi);
+               omp_unset_lock (&lock);
+             }
+           else
+             push_int_pair_stack (&local_stack, next_lo, next_hi);
+         }
+      }
+    }
+  omp_destroy_lock (&lock);
+}
+
+static void
+sort2_1 (int *array, int lo, int hi, int num_threads, int *busy)
+{
+  int mid;
+
+  if (hi - lo < THRESHOLD)
+    {
+      insertsort (array, lo, hi);
+      return;
+    }
+
+  mid = partition (array, lo, hi);
+
+  if (*busy >= num_threads)
+    {
+      sort2_1 (array, lo, mid - 1, num_threads, busy);
+      sort2_1 (array, mid, hi, num_threads, busy);
+      return;
+    }
+
+  #pragma omp atomic
+    *busy += 1;
+
+  #pragma omp parallel num_threads (2) \
+                      firstprivate (array, lo, hi, mid, num_threads, busy)
+  {
+    if (omp_get_thread_num () == 0)
+      sort2_1 (array, lo, mid - 1, num_threads, busy);
+    else
+      {
+       sort2_1 (array, mid, hi, num_threads, busy);
+       #pragma omp atomic
+         *busy -= 1;
+      }
+  }
+}
+
+static void
+sort2 (int *array, int count)
+{
+  int num_threads;
+  int busy = 1;
+
+  #pragma omp parallel
+    #pragma omp single nowait
+      num_threads = omp_get_num_threads ();
+
+  sort2_1 (array, 0, count - 1, num_threads, &busy);
+}
+
+#if _OPENMP >= 200805
+static void
+sort3_1 (int *array, int lo, int hi)
+{
+  int mid;
+
+  if (hi - lo < THRESHOLD)
+    {
+      insertsort (array, lo, hi);
+      return;
+    }
+
+  mid = partition (array, lo, hi);
+  #pragma omp task
+    sort3_1 (array, lo, mid - 1);
+  sort3_1 (array, mid, hi);
+}
+
+static void
+sort3 (int *array, int count)
+{
+  #pragma omp parallel
+    #pragma omp single
+      sort3_1 (array, 0, count - 1);
+}
+#endif
+
+int
+main (int argc, char **argv)
+{
+  int i, count = 1000000;
+  double stime;
+  int *unsorted, *sorted, num_threads;
+  if (argc >= 2)
+    count = strtoul (argv[1], NULL, 0);
+
+  unsorted = malloc (count * sizeof (int));
+  sorted = malloc (count * sizeof (int));
+  if (unsorted == NULL || sorted == NULL)
+    {
+      puts ("allocation failure");
+      exit (1);
+    }
+
+  srand (0xdeadbeef);
+  for (i = 0; i < count; i++)
+    unsorted[i] = rand ();
+
+  omp_set_nested (1);
+  omp_set_dynamic (0);
+  #pragma omp parallel
+    #pragma omp single nowait
+      num_threads = omp_get_num_threads ();
+  printf ("Threads: %d\n", num_threads);
+
+  memcpy (sorted, unsorted, count * sizeof (int));
+  stime = omp_get_wtime ();
+  sort1 (sorted, count);
+  verify ("sort1", stime, sorted, count);
+
+  memcpy (sorted, unsorted, count * sizeof (int));
+  stime = omp_get_wtime ();
+  sort2 (sorted, count);
+  verify ("sort2", stime, sorted, count);
+
+#if _OPENMP >= 200805
+  memcpy (sorted, unsorted, count * sizeof (int));
+  stime = omp_get_wtime ();
+  sort3 (sorted, count);
+  verify ("sort3", stime, sorted, count);
+#endif
+
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/task-1.c b/libgomp/testsuite/libgomp.c/task-1.c
new file mode 100644 (file)
index 0000000..66f58a2
--- /dev/null
@@ -0,0 +1,84 @@
+extern void abort (void);
+
+int a = 18;
+
+void
+f1 (int i, int j, int k)
+{
+  int l = 6, m = 7, n = 8;
+#pragma omp task private(j, m) shared(k, n)
+  {
+    j = 6;
+    m = 5;
+    if (++a != 19 || ++i != 9 || j != 6 || ++l != 7 || m != 5 || ++n != 9)
+      #pragma omp atomic
+       k++;
+  }
+#pragma omp taskwait
+  if (a != 19 || i != 8 || j != 26 || k != 0 || l != 6 || m != 7 || n != 9)
+    abort ();
+}
+
+int v1 = 1, v2 = 2, v5 = 5;
+int err;
+
+void
+f2 (void)
+{
+  int v3 = 3;
+#pragma omp sections private (v1) firstprivate (v2)
+  {
+  #pragma omp section
+    {
+      int v4 = 4;
+      v1 = 7;
+      #pragma omp task
+       {
+         if (++v1 != 8 || ++v2 != 3 || ++v3 != 4 || ++v4 != 5 || ++v5 != 6)
+           err = 1;
+       }
+      #pragma omp taskwait
+      if (v1 != 7 || v2 != 2 || v3 != 3 || v4 != 4 || v5 != 6)
+       abort ();
+      if (err)
+       abort ();
+    }
+  }
+}
+
+void
+f3 (int i, int j, int k)
+{
+  int l = 6, m = 7, n = 8;
+#pragma omp task private(j, m) shared(k, n) untied
+  {
+    j = 6;
+    m = 5;
+    if (++a != 19 || ++i != 9 || j != 6 || ++l != 7 || m != 5 || ++n != 9)
+      #pragma omp atomic
+       k++;
+  }
+#pragma omp taskwait
+  if (a != 19 || i != 8 || j != 26 || k != 0 || l != 6 || m != 7 || n != 9)
+    abort ();
+}
+
+int
+main (void)
+{
+  f1 (8, 26, 0);
+  f2 ();
+  a = 18;
+  f3 (8, 26, 0);
+  a = 18;
+#pragma omp parallel num_threads(4)
+  {
+    #pragma omp master
+      {
+       f1 (8, 26, 0);
+       a = 18;
+       f3 (8, 26, 0);
+      }
+  }
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/task-2.c b/libgomp/testsuite/libgomp.c/task-2.c
new file mode 100644 (file)
index 0000000..ed6a09c
--- /dev/null
@@ -0,0 +1,53 @@
+extern void abort (void);
+
+int
+f1 (void)
+{
+  int a = 6, e = 0;
+  int nested (int x)
+  {
+    return x + a;
+  }
+  #pragma omp task
+  {
+    int n = nested (5);
+    if (n != 11)
+      #pragma omp atomic
+       e += 1;
+  }
+  #pragma omp taskwait
+  return e;
+}
+
+int
+f2 (void)
+{
+  int a = 6, e = 0;
+  int nested (int x)
+  {
+    return x + a;
+  }
+  a = nested (4);
+  #pragma omp task
+  {
+    if (a != 10)
+      #pragma omp atomic
+       e += 1;
+  }
+  #pragma omp taskwait
+  return e;
+}
+
+int
+main (void)
+{
+  int e = 0;
+  #pragma omp parallel num_threads(4) reduction(+:e)
+  {
+    e += f1 ();
+    e += f2 ();
+  }
+  if (e)
+    abort ();
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/task-3.c b/libgomp/testsuite/libgomp.c/task-3.c
new file mode 100644 (file)
index 0000000..5657346
--- /dev/null
@@ -0,0 +1,70 @@
+/* { dg-do run } */
+
+#include <omp.h>
+extern void abort ();
+
+int l = 5;
+
+int
+foo (int i)
+{
+  int j = 7;
+  const int k = 8;
+  #pragma omp task firstprivate (i) shared (j, l)
+  {
+    #pragma omp critical
+      {
+       j += i;
+       l += k;
+      }
+  }
+  i++;
+  #pragma omp task firstprivate (i) shared (j, l)
+  {
+    #pragma omp critical
+      {
+       j += i;
+       l += k;
+      }
+  }
+  i++;
+  #pragma omp task firstprivate (i) shared (j, l)
+  {
+    #pragma omp critical
+      {
+       j += i;
+       l += k;
+      }
+  }
+  i++;
+  #pragma omp task firstprivate (i) shared (j, l)
+  {
+    #pragma omp critical
+      {
+       j += i;
+       l += k;
+      }
+  }
+  i++;
+  #pragma omp taskwait
+  return (i != 8 * omp_get_thread_num () + 4
+         || j != 4 * i - 3
+         || k != 8);
+}
+
+int
+main (void)
+{
+  int r = 0;
+  #pragma omp parallel num_threads (4) reduction(+:r)
+    if (omp_get_num_threads () != 4)
+      {
+       #pragma omp master
+         l = 133;
+      }
+    else if (foo (8 * omp_get_thread_num ()))
+      r++;
+  if (r || l != 133)
+    abort ();
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/task-4.c b/libgomp/testsuite/libgomp.c/task-4.c
new file mode 100644 (file)
index 0000000..1843593
--- /dev/null
@@ -0,0 +1,40 @@
+/* { dg-do run } */
+
+#include <omp.h>
+#include <stdlib.h>
+#include <string.h>
+
+int e;
+
+void __attribute__((noinline))
+baz (int i, int *p, int j, int *q)
+{
+  if (p[0] != 1 || p[i] != 3 || q[0] != 2 || q[j] != 4)
+    #pragma omp atomic
+      e++;
+}
+
+void __attribute__((noinline))
+foo (int i, int j)
+{
+  int p[i + 1];
+  int q[j + 1];
+  memset (p, 0, sizeof (p));
+  memset (q, 0, sizeof (q));
+  p[0] = 1;
+  p[i] = 3;
+  q[0] = 2;
+  q[j] = 4;
+  #pragma omp task firstprivate (p, q)
+    baz (i, p, j, q);
+}
+
+int
+main (void)
+{
+  #pragma omp parallel num_threads (4)
+    foo (5 + omp_get_thread_num (), 7 + omp_get_thread_num ());
+  if (e)
+    abort ();
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.fortran/allocatable1.f90 b/libgomp/testsuite/libgomp.fortran/allocatable1.f90
new file mode 100644 (file)
index 0000000..1efe2ab
--- /dev/null
@@ -0,0 +1,81 @@
+! { dg-do run }
+!$ use omp_lib
+
+  integer, allocatable :: a(:, :)
+  integer :: b(6, 3)
+  integer :: i, j
+  logical :: k, l
+  b(:, :) = 16
+  l = .false.
+  if (allocated (a)) call abort
+!$omp parallel private (a, b) reduction (.or.:l)
+  l = l.or.allocated (a)
+  allocate (a(3, 6))
+  l = l.or..not.allocated (a)
+  l = l.or.size(a).ne.18.or.size(a,1).ne.3.or.size(a,2).ne.6
+  a(3, 2) = 1
+  b(3, 2) = 1
+  deallocate (a)
+  l = l.or.allocated (a)
+!$omp end parallel
+  if (allocated (a).or.l) call abort
+  allocate (a(6, 3))
+  a(:, :) = 3
+  if (.not.allocated (a)) call abort
+  l = l.or.size(a).ne.18.or.size(a,1).ne.6.or.size(a,2).ne.3
+  if (l) call abort
+!$omp parallel private (a, b) reduction (.or.:l)
+  l = l.or..not.allocated (a)
+  a(3, 2) = 1
+  b(3, 2) = 1
+!$omp end parallel
+  if (l.or..not.allocated (a)) call abort
+!$omp parallel firstprivate (a, b) reduction (.or.:l)
+  l = l.or..not.allocated (a)
+  l = l.or.size(a).ne.18.or.size(a,1).ne.6.or.size(a,2).ne.3
+  do i = 1, 6
+    l = l.or.(a(i, 1).ne.3).or.(a(i, 2).ne.3)
+    l = l.or.(a(i, 3).ne.3).or.(b(i, 1).ne.16)
+    l = l.or.(b(i, 2).ne.16).or.(b(i, 3).ne.16)
+  end do
+  a(:, :) = omp_get_thread_num ()
+  b(:, :) = omp_get_thread_num ()
+!$omp end parallel
+  if (any (a.ne.3).or.any (b.ne.16).or.l) call abort
+  k = .true.
+!$omp parallel do firstprivate (a, b, k) lastprivate (a, b) &
+!$omp & reduction (.or.:l)
+  do i = 1, 36
+    l = l.or..not.allocated (a)
+    l = l.or.size(a).ne.18.or.size(a,1).ne.6.or.size(a,2).ne.3
+    if (k) then
+      do j = 1, 6
+        l = l.or.(a(j, 1).ne.3).or.(a(j, 2).ne.3)
+        l = l.or.(a(j, 3).ne.3).or.(b(j, 1).ne.16)
+       l = l.or.(b(j, 2).ne.16).or.(b(j, 3).ne.16)
+      end do
+      k = .false.
+    end if
+    a(:, :) = i + 2
+    b(:, :) = i
+  end do
+  if (any (a.ne.38).or.any (b.ne.36).or.l) call abort
+  deallocate (a)
+  if (allocated (a)) call abort
+  allocate (a (0:1, 0:3))
+  a(:, :) = 0
+!$omp parallel do reduction (+:a) reduction (.or.:l) &
+!$omp & num_threads(3) schedule(static)
+  do i = 0, 7
+    l = l.or..not.allocated (a)
+    l = l.or.size(a).ne.8.or.size(a,1).ne.2.or.size(a,2).ne.4
+    a(modulo (i, 2), i / 2) = a(modulo (i, 2), i / 2) + i
+    a(i / 4, modulo (i, 4)) = a(i / 4, modulo (i, 4)) + i
+  end do
+  if (l) call abort
+  do i = 0, 1
+    do j = 0, 3
+      if (a(i, j) .ne. (5*i + 3*j)) call abort
+    end do
+  end do
+end
diff --git a/libgomp/testsuite/libgomp.fortran/allocatable2.f90 b/libgomp/testsuite/libgomp.fortran/allocatable2.f90
new file mode 100644 (file)
index 0000000..a37616b
--- /dev/null
@@ -0,0 +1,47 @@
+! { dg-do run }
+! { dg-require-effective-target tls_runtime }
+!$ use omp_lib
+
+  integer, save, allocatable :: a(:, :)
+  integer, allocatable :: b(:, :)
+  integer :: n
+  logical :: l
+!$omp threadprivate (a)
+  if (allocated (a)) call abort
+  call omp_set_dynamic (.false.)
+  l = .false.
+!$omp parallel num_threads (4) reduction(.or.:l)
+  allocate (a(-1:1, 7:10))
+  a(:, :) = omp_get_thread_num () + 6
+  l = l.or..not.allocated (a)
+  l = l.or.size(a).ne.12.or.size(a,1).ne.3.or.size(a,2).ne.4
+!$omp end parallel
+  if (l.or.any(a.ne.6)) call abort ()
+!$omp parallel num_threads (4) copyin (a) reduction(.or.:l) private (b)
+  l = l.or.allocated (b)
+  l = l.or..not.allocated (a)
+  l = l.or.size(a).ne.12.or.size(a,1).ne.3.or.size(a,2).ne.4
+  l = l.or.any(a.ne.6)
+  allocate (b(1, 3))
+  a(:, :) = omp_get_thread_num () + 36
+  b(:, :) = omp_get_thread_num () + 66
+  !$omp single
+    n = omp_get_thread_num ()
+  !$omp end single copyprivate (a, b)
+  l = l.or..not.allocated (a)
+  l = l.or.size(a).ne.12.or.size(a,1).ne.3.or.size(a,2).ne.4
+  l = l.or.any(a.ne.(n + 36))
+  l = l.or..not.allocated (b)
+  l = l.or.size(b).ne.3.or.size(b,1).ne.1.or.size(b,2).ne.3
+  l = l.or.any(b.ne.(n + 66))
+  deallocate (b)
+  l = l.or.allocated (b)
+!$omp end parallel
+  if (n.lt.0 .or. n.ge.4) call abort
+  if (l.or.any(a.ne.(n + 36))) call abort
+!$omp parallel num_threads (4) reduction(.or.:l)
+  deallocate (a)
+  l = l.or.allocated (a)
+!$omp end parallel
+  if (l.or.allocated (a)) call abort
+end
diff --git a/libgomp/testsuite/libgomp.fortran/allocatable3.f90 b/libgomp/testsuite/libgomp.fortran/allocatable3.f90
new file mode 100644 (file)
index 0000000..fe3714a
--- /dev/null
@@ -0,0 +1,21 @@
+! { dg-do run }
+
+  integer, allocatable :: a(:)
+  integer :: i
+  logical :: l
+  l = .false.
+  if (allocated (a)) call abort
+!$omp parallel private (a) reduction (.or.:l)
+  allocate (a (-7:-5))
+  l = l.or..not.allocated (a)
+  l = l.or.size(a).ne.3.or.size(a,1).ne.3
+  a(:) = 0
+  !$omp do private (a)
+  do i = 1, 7
+    a(:) = i
+    l = l.or.any (a.ne.i)
+  end do
+  l = l.or.any (a.ne.0)
+  deallocate (a)
+!$omp end parallel
+end
diff --git a/libgomp/testsuite/libgomp.fortran/allocatable4.f90 b/libgomp/testsuite/libgomp.fortran/allocatable4.f90
new file mode 100644 (file)
index 0000000..996578c
--- /dev/null
@@ -0,0 +1,47 @@
+! { dg-do run }
+
+  integer, allocatable :: a(:, :)
+  integer :: b(6, 3)
+  integer :: i, j
+  logical :: k, l
+  b(:, :) = 16
+  l = .false.
+  if (allocated (a)) call abort
+!$omp task private (a, b) shared (l)
+  l = l.or.allocated (a)
+  allocate (a(3, 6))
+  l = l.or..not.allocated (a)
+  l = l.or.size(a).ne.18.or.size(a,1).ne.3.or.size(a,2).ne.6
+  a(3, 2) = 1
+  b(3, 2) = 1
+  deallocate (a)
+  l = l.or.allocated (a)
+!$omp end task
+!$omp taskwait
+  if (allocated (a).or.l) call abort
+  allocate (a(6, 3))
+  a(:, :) = 3
+  if (.not.allocated (a)) call abort
+  l = l.or.size(a).ne.18.or.size(a,1).ne.6.or.size(a,2).ne.3
+  if (l) call abort
+!$omp task private (a, b) shared (l)
+  l = l.or..not.allocated (a)
+  a(3, 2) = 1
+  b(3, 2) = 1
+!$omp end task
+!$omp taskwait
+  if (l.or..not.allocated (a)) call abort
+!$omp task firstprivate (a, b) shared (l)
+  l = l.or..not.allocated (a)
+  l = l.or.size(a).ne.18.or.size(a,1).ne.6.or.size(a,2).ne.3
+  do i = 1, 6
+    l = l.or.(a(i, 1).ne.3).or.(a(i, 2).ne.3)
+    l = l.or.(a(i, 3).ne.3).or.(b(i, 1).ne.16)
+    l = l.or.(b(i, 2).ne.16).or.(b(i, 3).ne.16)
+  end do
+  a(:, :) = 7
+  b(:, :) = 8
+!$omp end task
+!$omp taskwait
+  if (any (a.ne.3).or.any (b.ne.16).or.l) call abort
+end
diff --git a/libgomp/testsuite/libgomp.fortran/collapse1.f90 b/libgomp/testsuite/libgomp.fortran/collapse1.f90
new file mode 100644 (file)
index 0000000..1ecfa0c
--- /dev/null
@@ -0,0 +1,26 @@
+! { dg-do run }
+
+program collapse1
+  integer :: i, j, k, a(1:3, 4:6, 5:7)
+  logical :: l
+  l = .false.
+  a(:, :, :) = 0
+  !$omp parallel do collapse(4 - 1) schedule(static, 4)
+    do i = 1, 3
+      do j = 4, 6
+        do k = 5, 7
+          a(i, j, k) = i + j + k
+        end do
+      end do
+    end do
+  !$omp parallel do collapse(2) reduction(.or.:l)
+    do i = 1, 3
+      do j = 4, 6
+        do k = 5, 7
+          if (a(i, j, k) .ne. (i + j + k)) l = .true.
+        end do
+      end do
+    end do
+  !$omp end parallel do
+  if (l) call abort
+end program collapse1
diff --git a/libgomp/testsuite/libgomp.fortran/collapse2.f90 b/libgomp/testsuite/libgomp.fortran/collapse2.f90
new file mode 100644 (file)
index 0000000..77e0dee
--- /dev/null
@@ -0,0 +1,53 @@
+! { dg-do run }
+
+program collapse2
+  call test1
+  call test2
+contains
+  subroutine test1
+    integer :: i, j, k, a(1:3, 4:6, 5:7)
+    logical :: l
+    l = .false.
+    a(:, :, :) = 0
+    !$omp parallel do collapse(4 - 1) schedule(static, 4)
+      do 164 i = 1, 3
+        do 164 j = 4, 6
+          do 164 k = 5, 7
+            a(i, j, k) = i + j + k
+164      end do
+    !$omp parallel do collapse(2) reduction(.or.:l)
+firstdo: do i = 1, 3
+        do j = 4, 6
+          do k = 5, 7
+            if (a(i, j, k) .ne. (i + j + k)) l = .true.
+          end do
+        end do
+      end do firstdo
+    !$omp end parallel do
+    if (l) call abort
+  end subroutine test1
+
+  subroutine test2
+    integer :: a(3,3,3), k, kk, kkk, l, ll, lll
+    !$omp do collapse(3)
+      do 115 k=1,3
+  dokk: do kk=1,3
+          do kkk=1,3
+            a(k,kk,kkk) = 1
+          enddo
+        enddo dokk
+115   continue
+    if (any(a(1:3,1:3,1:3).ne.1)) call abort
+
+    !$omp do collapse(3)
+ dol: do 120 l=1,3
+  doll: do ll=1,3
+          do lll=1,3
+            a(l,ll,lll) = 2
+          enddo
+        enddo doll
+120   end do dol
+    if (any(a(1:3,1:3,1:3).ne.2)) call abort
+  end subroutine test2
+
+end program collapse2
diff --git a/libgomp/testsuite/libgomp.fortran/collapse3.f90 b/libgomp/testsuite/libgomp.fortran/collapse3.f90
new file mode 100644 (file)
index 0000000..eac9eac
--- /dev/null
@@ -0,0 +1,204 @@
+! { dg-do run }
+
+program collapse3
+  call test1
+  call test2 (2, 6, -2, 4, 13, 18)
+  call test3 (2, 6, -2, 4, 13, 18, 1, 1, 1)
+  call test4
+  call test5 (2, 6, -2, 4, 13, 18)
+  call test6 (2, 6, -2, 4, 13, 18, 1, 1, 1)
+contains
+  subroutine test1
+    integer :: i, j, k, a(1:7, -3:5, 12:19), m
+    logical :: l
+    l = .false.
+    a(:, :, :) = 0
+    !$omp parallel do collapse (3) lastprivate (i, j, k, m) reduction (.or.:l)
+      do i = 2, 6
+        do j = -2, 4
+          do k = 13, 18
+            l = l.or.i.lt.2.or.i.gt.6.or.j.lt.-2.or.j.gt.4
+            l = l.or.k.lt.13.or.k.gt.18
+            if (.not.l) a(i, j, k) = a(i, j, k) + 1
+            m = i * 100 + j * 10 + k
+          end do
+        end do
+      end do
+    if (i.ne.7.or.j.ne.5.or.k.ne.19) call abort
+    if (m.ne.(600+40+18)) call abort
+    do i = 1, 7
+      do j = -3, 5
+        do k = 12, 19
+          if (i.eq.1.or.i.eq.7.or.j.eq.-3.or.j.eq.5.or.k.eq.12.or.k.eq.19) then
+            if (a(i, j, k).ne.0) print *, i, j, k
+          else
+            if (a(i, j, k).ne.1) print *, 'kk', i, j, k, a(i, j, k)
+          end if
+        end do
+      end do
+    end do
+  end subroutine test1
+
+  subroutine test2(v1, v2, v3, v4, v5, v6)
+    integer :: i, j, k, a(1:7, -3:5, 12:19), m
+    integer :: v1, v2, v3, v4, v5, v6
+    logical :: l
+    l = .false.
+    a(:, :, :) = 0
+    !$omp parallel do collapse (3) lastprivate (i, j, k, m) reduction (.or.:l)
+      do i = v1, v2
+        do j = v3, v4
+          do k = v5, v6
+            l = l.or.i.lt.2.or.i.gt.6.or.j.lt.-2.or.j.gt.4
+            l = l.or.k.lt.13.or.k.gt.18
+            if (.not.l) a(i, j, k) = a(i, j, k) + 1
+            m = i * 100 + j * 10 + k
+          end do
+        end do
+      end do
+    if (i.ne.7.or.j.ne.5.or.k.ne.19) call abort
+    if (m.ne.(600+40+18)) call abort
+    do i = 1, 7
+      do j = -3, 5
+        do k = 12, 19
+          if (i.eq.1.or.i.eq.7.or.j.eq.-3.or.j.eq.5.or.k.eq.12.or.k.eq.19) then
+            if (a(i, j, k).ne.0) print *, i, j, k
+          else
+            if (a(i, j, k).ne.1) print *, 'kk', i, j, k, a(i, j, k)
+          end if
+        end do
+      end do
+    end do
+  end subroutine test2
+
+  subroutine test3(v1, v2, v3, v4, v5, v6, v7, v8, v9)
+    integer :: i, j, k, a(1:7, -3:5, 12:19), m
+    integer :: v1, v2, v3, v4, v5, v6, v7, v8, v9
+    logical :: l
+    l = .false.
+    a(:, :, :) = 0
+    !$omp parallel do collapse (3) lastprivate (i, j, k, m) reduction (.or.:l)
+      do i = v1, v2, v7
+        do j = v3, v4, v8
+          do k = v5, v6, v9
+            l = l.or.i.lt.2.or.i.gt.6.or.j.lt.-2.or.j.gt.4
+            l = l.or.k.lt.13.or.k.gt.18
+            if (.not.l) a(i, j, k) = a(i, j, k) + 1
+            m = i * 100 + j * 10 + k
+          end do
+        end do
+      end do
+    if (i.ne.7.or.j.ne.5.or.k.ne.19) call abort
+    if (m.ne.(600+40+18)) call abort
+    do i = 1, 7
+      do j = -3, 5
+        do k = 12, 19
+          if (i.eq.1.or.i.eq.7.or.j.eq.-3.or.j.eq.5.or.k.eq.12.or.k.eq.19) then
+            if (a(i, j, k).ne.0) print *, i, j, k
+          else
+            if (a(i, j, k).ne.1) print *, 'kk', i, j, k, a(i, j, k)
+          end if
+        end do
+      end do
+    end do
+  end subroutine test3
+
+  subroutine test4
+    integer :: i, j, k, a(1:7, -3:5, 12:19), m
+    logical :: l
+    l = .false.
+    a(:, :, :) = 0
+    !$omp parallel do collapse (3) lastprivate (i, j, k, m) reduction (.or.:l) &
+    !$omp& schedule (dynamic, 5)
+      do i = 2, 6
+        do j = -2, 4
+          do k = 13, 18
+            l = l.or.i.lt.2.or.i.gt.6.or.j.lt.-2.or.j.gt.4
+            l = l.or.k.lt.13.or.k.gt.18
+            if (.not.l) a(i, j, k) = a(i, j, k) + 1
+            m = i * 100 + j * 10 + k
+          end do
+        end do
+      end do
+    if (i.ne.7.or.j.ne.5.or.k.ne.19) call abort
+    if (m.ne.(600+40+18)) call abort
+    do i = 1, 7
+      do j = -3, 5
+        do k = 12, 19
+          if (i.eq.1.or.i.eq.7.or.j.eq.-3.or.j.eq.5.or.k.eq.12.or.k.eq.19) then
+            if (a(i, j, k).ne.0) print *, i, j, k
+          else
+            if (a(i, j, k).ne.1) print *, 'kk', i, j, k, a(i, j, k)
+          end if
+        end do
+      end do
+    end do
+  end subroutine test4
+
+  subroutine test5(v1, v2, v3, v4, v5, v6)
+    integer :: i, j, k, a(1:7, -3:5, 12:19), m
+    integer :: v1, v2, v3, v4, v5, v6
+    logical :: l
+    l = .false.
+    a(:, :, :) = 0
+    !$omp parallel do collapse (3) lastprivate (i, j, k, m) reduction (.or.:l) &
+    !$omp & schedule (guided)
+      do i = v1, v2
+        do j = v3, v4
+          do k = v5, v6
+            l = l.or.i.lt.2.or.i.gt.6.or.j.lt.-2.or.j.gt.4
+            l = l.or.k.lt.13.or.k.gt.18
+            if (.not.l) a(i, j, k) = a(i, j, k) + 1
+            m = i * 100 + j * 10 + k
+          end do
+        end do
+      end do
+    if (i.ne.7.or.j.ne.5.or.k.ne.19) call abort
+    if (m.ne.(600+40+18)) call abort
+    do i = 1, 7
+      do j = -3, 5
+        do k = 12, 19
+          if (i.eq.1.or.i.eq.7.or.j.eq.-3.or.j.eq.5.or.k.eq.12.or.k.eq.19) then
+            if (a(i, j, k).ne.0) print *, i, j, k
+          else
+            if (a(i, j, k).ne.1) print *, 'kk', i, j, k, a(i, j, k)
+          end if
+        end do
+      end do
+    end do
+  end subroutine test5
+
+  subroutine test6(v1, v2, v3, v4, v5, v6, v7, v8, v9)
+    integer :: i, j, k, a(1:7, -3:5, 12:19), m
+    integer :: v1, v2, v3, v4, v5, v6, v7, v8, v9
+    logical :: l
+    l = .false.
+    a(:, :, :) = 0
+    !$omp parallel do collapse (3) lastprivate (i, j, k, m) reduction (.or.:l) &
+    !$omp & schedule (dynamic)
+      do i = v1, v2, v7
+        do j = v3, v4, v8
+          do k = v5, v6, v9
+            l = l.or.i.lt.2.or.i.gt.6.or.j.lt.-2.or.j.gt.4
+            l = l.or.k.lt.13.or.k.gt.18
+            if (.not.l) a(i, j, k) = a(i, j, k) + 1
+            m = i * 100 + j * 10 + k
+          end do
+        end do
+      end do
+    if (i.ne.7.or.j.ne.5.or.k.ne.19) call abort
+    if (m.ne.(600+40+18)) call abort
+    do i = 1, 7
+      do j = -3, 5
+        do k = 12, 19
+          if (i.eq.1.or.i.eq.7.or.j.eq.-3.or.j.eq.5.or.k.eq.12.or.k.eq.19) then
+            if (a(i, j, k).ne.0) print *, i, j, k
+          else
+            if (a(i, j, k).ne.1) print *, 'kk', i, j, k, a(i, j, k)
+          end if
+        end do
+      end do
+    end do
+  end subroutine test6
+
+end program collapse3
diff --git a/libgomp/testsuite/libgomp.fortran/collapse4.f90 b/libgomp/testsuite/libgomp.fortran/collapse4.f90
new file mode 100644 (file)
index 0000000..f19b0f6
--- /dev/null
@@ -0,0 +1,12 @@
+! { dg-do run }
+
+  integer :: i, j, k
+  !$omp parallel do lastprivate (i, j, k) collapse (3)
+    do i = 0, 17
+      do j = 0, 6
+        do k = 0, 5
+        end do
+      end do
+    end do
+  if (i .ne. 18 .or. j .ne. 7 .or. k .ne. 6) call abort
+end
diff --git a/libgomp/testsuite/libgomp.fortran/lastprivate1.f90 b/libgomp/testsuite/libgomp.fortran/lastprivate1.f90
new file mode 100644 (file)
index 0000000..91bb96c
--- /dev/null
@@ -0,0 +1,126 @@
+program lastprivate
+  integer :: i
+  common /c/ i
+  !$omp parallel num_threads (4)
+  call test1
+  !$omp end parallel
+  if (i .ne. 21) call abort
+  !$omp parallel num_threads (4)
+  call test2
+  !$omp end parallel
+  if (i .ne. 64) call abort
+  !$omp parallel num_threads (4)
+  call test3
+  !$omp end parallel
+  if (i .ne. 14) call abort
+  call test4
+  call test5
+  call test6
+  call test7
+  call test8
+  call test9
+  call test10
+  call test11
+  call test12
+contains
+  subroutine test1
+    integer :: i
+    common /c/ i
+    !$omp do lastprivate (i)
+    do i = 1, 20
+    end do
+  end subroutine test1
+  subroutine test2
+    integer :: i
+    common /c/ i
+    !$omp do lastprivate (i)
+    do i = 7, 61, 3
+    end do
+  end subroutine test2
+  function ret3 ()
+    integer :: ret3
+    ret3 = 3
+  end function ret3
+  subroutine test3
+    integer :: i
+    common /c/ i
+    !$omp do lastprivate (i)
+    do i = -10, 11, ret3 ()
+    end do
+  end subroutine test3
+  subroutine test4
+    integer :: j
+    !$omp parallel do lastprivate (j) num_threads (4) default (none)
+    do j = 1, 20
+    end do
+    if (j .ne. 21) call abort
+  end subroutine test4
+  subroutine test5
+    integer :: j
+    !$omp parallel do lastprivate (j) num_threads (4) default (none)
+    do j = 7, 61, 3
+    end do
+    if (j .ne. 64) call abort
+  end subroutine test5
+  subroutine test6
+    integer :: j
+    !$omp parallel do lastprivate (j) num_threads (4) default (none)
+    do j = -10, 11, ret3 ()
+    end do
+    if (j .ne. 14) call abort
+  end subroutine test6
+  subroutine test7
+    integer :: i
+    common /c/ i
+    !$omp parallel do lastprivate (i) num_threads (4) default (none)
+    do i = 1, 20
+    end do
+    if (i .ne. 21) call abort
+  end subroutine test7
+  subroutine test8
+    integer :: i
+    common /c/ i
+    !$omp parallel do lastprivate (i) num_threads (4) default (none)
+    do i = 7, 61, 3
+    end do
+    if (i .ne. 64) call abort
+  end subroutine test8
+  subroutine test9
+    integer :: i
+    common /c/ i
+    !$omp parallel do lastprivate (i) num_threads (4) default (none)
+    do i = -10, 11, ret3 ()
+    end do
+    if (i .ne. 14) call abort
+  end subroutine test9
+  subroutine test10
+    integer :: i
+    common /c/ i
+    !$omp parallel num_threads (4) default (none) shared (i)
+    !$omp do lastprivate (i)
+    do i = 1, 20
+    end do
+    !$omp end parallel
+    if (i .ne. 21) call abort
+  end subroutine test10
+  subroutine test11
+    integer :: i
+    common /c/ i
+    !$omp parallel num_threads (4) default (none) shared (i)
+    !$omp do lastprivate (i)
+    do i = 7, 61, 3
+    end do
+    !$omp end parallel
+    if (i .ne. 64) call abort
+  end subroutine test11
+  subroutine test12
+    integer :: i
+    common /c/ i
+    !$omp parallel num_threads (4) default (none) shared (i)
+    !$omp do lastprivate (i)
+    do i = -10, 11, ret3 ()
+    end do
+    !$omp end parallel
+    if (i .ne. 14) call abort
+  end subroutine test12
+end program lastprivate
diff --git a/libgomp/testsuite/libgomp.fortran/lastprivate2.f90 b/libgomp/testsuite/libgomp.fortran/lastprivate2.f90
new file mode 100644 (file)
index 0000000..6d7e11e
--- /dev/null
@@ -0,0 +1,141 @@
+program lastprivate
+  integer :: i, k
+  common /c/ i, k
+  !$omp parallel num_threads (4)
+  call test1
+  !$omp end parallel
+  if (i .ne. 21 .or. k .ne. 20) call abort
+  !$omp parallel num_threads (4)
+  call test2
+  !$omp end parallel
+  if (i .ne. 64 .or. k .ne. 61) call abort
+  !$omp parallel num_threads (4)
+  call test3
+  !$omp end parallel
+  if (i .ne. 14 .or. k .ne. 11) call abort
+  call test4
+  call test5
+  call test6
+  call test7
+  call test8
+  call test9
+  call test10
+  call test11
+  call test12
+contains
+  subroutine test1
+    integer :: i, k
+    common /c/ i, k
+    !$omp do lastprivate (i, k)
+    do i = 1, 20
+      k = i
+    end do
+  end subroutine test1
+  subroutine test2
+    integer :: i, k
+    common /c/ i, k
+    !$omp do lastprivate (i, k)
+    do i = 7, 61, 3
+      k = i
+    end do
+  end subroutine test2
+  function ret3 ()
+    integer :: ret3
+    ret3 = 3
+  end function ret3
+  subroutine test3
+    integer :: i, k
+    common /c/ i, k
+    !$omp do lastprivate (i, k)
+    do i = -10, 11, ret3 ()
+      k = i
+    end do
+  end subroutine test3
+  subroutine test4
+    integer :: j, l
+    !$omp parallel do lastprivate (j, l) num_threads (4)
+    do j = 1, 20
+      l = j
+    end do
+    if (j .ne. 21 .or. l .ne. 20) call abort
+  end subroutine test4
+  subroutine test5
+    integer :: j, l
+    l = 77
+    !$omp parallel do lastprivate (j, l) num_threads (4) firstprivate (l)
+    do j = 7, 61, 3
+      l = j
+    end do
+    if (j .ne. 64 .or. l .ne. 61) call abort
+  end subroutine test5
+  subroutine test6
+    integer :: j, l
+    !$omp parallel do lastprivate (j, l) num_threads (4)
+    do j = -10, 11, ret3 ()
+      l = j
+    end do
+    if (j .ne. 14 .or. l .ne. 11) call abort
+  end subroutine test6
+  subroutine test7
+    integer :: i, k
+    common /c/ i, k
+    !$omp parallel do lastprivate (i, k) num_threads (4)
+    do i = 1, 20
+      k = i
+    end do
+    if (i .ne. 21 .or. k .ne. 20) call abort
+  end subroutine test7
+  subroutine test8
+    integer :: i, k
+    common /c/ i, k
+    !$omp parallel do lastprivate (i, k) num_threads (4)
+    do i = 7, 61, 3
+      k = i
+    end do
+    if (i .ne. 64 .or. k .ne. 61) call abort
+  end subroutine test8
+  subroutine test9
+    integer :: i, k
+    common /c/ i, k
+    k = 77
+    !$omp parallel do lastprivate (i, k) num_threads (4) firstprivate (k)
+    do i = -10, 11, ret3 ()
+      k = i
+    end do
+    if (i .ne. 14 .or. k .ne. 11) call abort
+  end subroutine test9
+  subroutine test10
+    integer :: i, k
+    common /c/ i, k
+    !$omp parallel num_threads (4)
+    !$omp do lastprivate (i, k)
+    do i = 1, 20
+      k = i
+    end do
+    !$omp end parallel
+    if (i .ne. 21 .or. k .ne. 20) call abort
+  end subroutine test10
+  subroutine test11
+    integer :: i, k
+    common /c/ i, k
+    !$omp parallel num_threads (4)
+    !$omp do lastprivate (i, k)
+    do i = 7, 61, 3
+      k = i
+    end do
+    !$omp end parallel
+    if (i .ne. 64 .or. k .ne. 61) call abort
+  end subroutine test11
+  subroutine test12
+    integer :: i, k
+    common /c/ i, k
+    k = 77
+    !$omp parallel num_threads (4)
+    !$omp do lastprivate (i, k) firstprivate (k)
+    do i = -10, 11, ret3 ()
+      k = i
+    end do
+    !$omp end parallel
+    if (i .ne. 14 .or. k .ne. 11) call abort
+  end subroutine test12
+end program lastprivate
diff --git a/libgomp/testsuite/libgomp.fortran/lib4.f90 b/libgomp/testsuite/libgomp.fortran/lib4.f90
new file mode 100644 (file)
index 0000000..cbb9845
--- /dev/null
@@ -0,0 +1,16 @@
+! { dg-do run }
+
+program lib4
+  use omp_lib
+  integer (omp_sched_kind) :: kind
+  integer :: modifier
+  call omp_set_schedule (omp_sched_static, 32)
+  call omp_get_schedule (kind, modifier)
+  if (kind.ne.omp_sched_static.or.modifier.ne.32) call abort
+  call omp_set_schedule (omp_sched_dynamic, 4)
+  call omp_get_schedule (kind, modifier)
+  if (kind.ne.omp_sched_dynamic.or.modifier.ne.4) call abort
+  if (omp_get_thread_limit ().lt.0) call abort
+  call omp_set_max_active_levels (6)
+  if (omp_get_max_active_levels ().ne.6) call abort
+end program lib4
diff --git a/libgomp/testsuite/libgomp.fortran/lock-1.f90 b/libgomp/testsuite/libgomp.fortran/lock-1.f90
new file mode 100644 (file)
index 0000000..d7d3e3f
--- /dev/null
@@ -0,0 +1,24 @@
+! { dg-do run }
+
+  use omp_lib
+
+  integer (kind = omp_nest_lock_kind) :: lock
+  logical :: l
+
+  l = .false.
+  call omp_init_nest_lock (lock)
+  if (omp_test_nest_lock (lock) .ne. 1) call abort
+  if (omp_test_nest_lock (lock) .ne. 2) call abort
+!$omp parallel if (.false.) reduction (.or.:l)
+  ! In OpenMP 2.5 this was supposed to return 3,
+  ! but in OpenMP 3.0 the parallel region has a different
+  ! task and omp_*_lock_t are owned by tasks, not by threads.
+  if (omp_test_nest_lock (lock) .ne. 0) l = .true.
+!$omp end parallel
+  if (l) call abort
+  if (omp_test_nest_lock (lock) .ne. 3) call abort
+  call omp_unset_nest_lock (lock)
+  call omp_unset_nest_lock (lock)
+  call omp_unset_nest_lock (lock)
+  call omp_destroy_nest_lock (lock)
+end
diff --git a/libgomp/testsuite/libgomp.fortran/lock-2.f90 b/libgomp/testsuite/libgomp.fortran/lock-2.f90
new file mode 100644 (file)
index 0000000..9965139
--- /dev/null
@@ -0,0 +1,24 @@
+! { dg-do run }
+
+  use omp_lib
+
+  integer (kind = omp_nest_lock_kind) :: lock
+  logical :: l
+
+  l = .false.
+  call omp_init_nest_lock (lock)
+!$omp parallel num_threads (1) reduction (.or.:l)
+  if (omp_test_nest_lock (lock) .ne. 1) call abort
+  if (omp_test_nest_lock (lock) .ne. 2) call abort
+!$omp task if (.false.) shared (lock, l)
+  if (omp_test_nest_lock (lock) .ne. 0) l = .true.
+!$omp end task
+!$omp taskwait
+  if (omp_test_nest_lock (lock) .ne. 3) l = .true.
+  call omp_unset_nest_lock (lock)
+  call omp_unset_nest_lock (lock)
+  call omp_unset_nest_lock (lock)
+!$omp end parallel
+  if (l) call abort
+  call omp_destroy_nest_lock (lock)
+end
diff --git a/libgomp/testsuite/libgomp.fortran/nested1.f90 b/libgomp/testsuite/libgomp.fortran/nested1.f90
new file mode 100644 (file)
index 0000000..98c4322
--- /dev/null
@@ -0,0 +1,87 @@
+! { dg-do run }
+program nested1
+  use omp_lib
+  integer :: e1, e2, e3, e
+  integer :: tn1, tn2, tn3
+  e1 = 0
+  e2 = 0
+  e3 = 0
+  call omp_set_nested (.true.)
+  call omp_set_dynamic (.false.)
+  if (omp_in_parallel ()) call abort
+  if (omp_get_num_threads ().ne.1) call abort
+  if (omp_get_level ().ne.0) call abort
+  if (omp_get_ancestor_thread_num (0).ne.0) call abort
+  if (omp_get_ancestor_thread_num (-1).ne.-1) call abort
+  if (omp_get_ancestor_thread_num (1).ne.-1) call abort
+  if (omp_get_team_size (0).ne.1) call abort
+  if (omp_get_team_size (-1).ne.-1) call abort
+  if (omp_get_team_size (1).ne.-1) call abort
+  if (omp_get_active_level ().ne.0) call abort
+!$omp parallel num_threads (4) private (e, tn1)
+  e = 0
+  tn1 = omp_get_thread_num ()
+  if (.not.omp_in_parallel ()) e = e + 1
+  if (omp_get_num_threads ().ne.4) e = e + 1
+  if (tn1.lt.0.or.tn1.ge.4) e = e + 1
+  if (omp_get_level ().ne.1) e = e + 1
+  if (omp_get_ancestor_thread_num (0).ne.0) e = e + 1
+  if (omp_get_ancestor_thread_num (1).ne.tn1) e = e + 1
+  if (omp_get_ancestor_thread_num (-1).ne.-1) e = e + 1
+  if (omp_get_ancestor_thread_num (2).ne.-1) e = e + 1
+  if (omp_get_team_size (0).ne.1) e = e + 1
+  if (omp_get_team_size (1).ne.4) e = e + 1
+  if (omp_get_team_size (-1).ne.-1) e = e + 1
+  if (omp_get_team_size (2).ne.-1) e = e + 1
+  if (omp_get_active_level ().ne.1) e = e + 1
+  !$omp atomic
+    e1 = e1 + e
+!$omp parallel num_threads (5) if (.false.) firstprivate (tn1) &
+!$omp& private (e, tn2)
+  e = 0
+  tn2 = omp_get_thread_num ()
+  if (.not.omp_in_parallel ()) e = e + 1
+  if (omp_get_num_threads ().ne.1) e = e + 1
+  if (tn2.ne.0) e = e + 1
+  if (omp_get_level ().ne.2) e = e + 1
+  if (omp_get_ancestor_thread_num (0).ne.0) e = e + 1
+  if (omp_get_ancestor_thread_num (1).ne.tn1) e = e + 1
+  if (omp_get_ancestor_thread_num (2).ne.tn2) e = e + 1
+  if (omp_get_ancestor_thread_num (-1).ne.-1) e = e + 1
+  if (omp_get_ancestor_thread_num (3).ne.-1) e = e + 1
+  if (omp_get_team_size (0).ne.1) e = e + 1
+  if (omp_get_team_size (1).ne.4) e = e + 1
+  if (omp_get_team_size (2).ne.1) e = e + 1
+  if (omp_get_team_size (-1).ne.-1) e = e + 1
+  if (omp_get_team_size (3).ne.-1) e = e + 1
+  if (omp_get_active_level ().ne.1) e = e + 1
+  !$omp atomic
+    e2 = e2 + e
+!$omp parallel num_threads (2) firstprivate (tn1, tn2) &
+!$omp& private (e, tn3)
+  e = 0
+  tn3 = omp_get_thread_num ()
+  if (.not.omp_in_parallel ()) e = e + 1
+  if (omp_get_num_threads ().ne.2) e = e + 1
+  if (tn3.lt.0.or.tn3.ge.2) e = e + 1
+  if (omp_get_level ().ne.3) e = e + 1
+  if (omp_get_ancestor_thread_num (0).ne.0) e = e + 1
+  if (omp_get_ancestor_thread_num (1).ne.tn1) e = e + 1
+  if (omp_get_ancestor_thread_num (2).ne.tn2) e = e + 1
+  if (omp_get_ancestor_thread_num (3).ne.tn3) e = e + 1
+  if (omp_get_ancestor_thread_num (-1).ne.-1) e = e + 1
+  if (omp_get_ancestor_thread_num (4).ne.-1) e = e + 1
+  if (omp_get_team_size (0).ne.1) e = e + 1
+  if (omp_get_team_size (1).ne.4) e = e + 1
+  if (omp_get_team_size (2).ne.1) e = e + 1
+  if (omp_get_team_size (3).ne.2) e = e + 1
+  if (omp_get_team_size (-1).ne.-1) e = e + 1
+  if (omp_get_team_size (4).ne.-1) e = e + 1
+  if (omp_get_active_level ().ne.2) e = e + 1
+  !$omp atomic
+    e3 = e3 + e
+!$omp end parallel
+!$omp end parallel
+!$omp end parallel
+  if (e1.ne.0.or.e2.ne.0.or.e3.ne.0) call abort
+end program nested1
diff --git a/libgomp/testsuite/libgomp.fortran/nestedfn4.f90 b/libgomp/testsuite/libgomp.fortran/nestedfn4.f90
new file mode 100644 (file)
index 0000000..c987bf4
--- /dev/null
@@ -0,0 +1,41 @@
+program foo
+  integer :: i, j, k
+  integer :: a(10), c(10)
+  k = 2
+  a(:) = 0
+  call test1
+  call test2
+  do i = 1, 10
+    if (a(i) .ne. 10 * i) call abort
+  end do
+  !$omp parallel do reduction (+:c)
+  do i = 1, 10
+    c = c + a
+  end do
+  do i = 1, 10
+    if (c(i) .ne. 10 * a(i)) call abort
+  end do
+  !$omp parallel do lastprivate (j)
+  do j = 1, 10, k
+  end do
+  if (j .ne. 11) call abort
+contains
+  subroutine test1
+    integer :: i
+    integer :: b(10)
+    do i = 1, 10
+      b(i) = i
+    end do
+    c(:) = 0
+    !$omp parallel do reduction (+:a)
+    do i = 1, 10
+      a = a + b
+    end do
+  end subroutine test1
+  subroutine test2
+    !$omp parallel do lastprivate (j)
+    do j = 1, 10, k
+    end do
+    if (j .ne. 11) call abort
+  end subroutine test2
+end program foo
diff --git a/libgomp/testsuite/libgomp.fortran/strassen.f90 b/libgomp/testsuite/libgomp.fortran/strassen.f90
new file mode 100644 (file)
index 0000000..b449826
--- /dev/null
@@ -0,0 +1,75 @@
+! { dg-options "-O2" }
+
+program strassen_matmul
+  use omp_lib
+  integer, parameter :: N = 1024
+  double precision, save :: A(N,N), B(N,N), C(N,N), D(N,N)
+  double precision :: start, end
+
+  call random_seed
+  call random_number (A)
+  call random_number (B)
+  start = omp_get_wtime ()
+  C = matmul (A, B)
+  end = omp_get_wtime ()
+  write(*,'(a, f10.6)') ' Time for matmul      = ', end - start
+  D = 0
+  start = omp_get_wtime ()
+  call strassen (A, B, D, N)
+  end = omp_get_wtime ()
+  write(*,'(a, f10.6)') ' Time for Strassen    = ', end - start
+  if (sqrt (sum ((C - D) ** 2)) / N .gt. 0.1) call abort
+  D = 0
+  start = omp_get_wtime ()
+!$omp parallel
+!$omp single
+  call strassen (A, B, D, N)
+!$omp end single nowait
+!$omp end parallel
+  end = omp_get_wtime ()
+  write(*,'(a, f10.6)') ' Time for Strassen MP = ', end - start
+  if (sqrt (sum ((C - D) ** 2)) / N .gt. 0.1) call abort
+
+contains
+
+  recursive subroutine strassen (A, B, C, N)
+    integer, intent(in) :: N
+    double precision, intent(in) :: A(N,N), B(N,N)
+    double precision, intent(out) :: C(N,N)
+    double precision :: T(N/2,N/2,7)
+    integer :: K, L
+
+    if (iand (N,1) .ne. 0 .or. N < 64) then
+      C = matmul (A, B)
+      return
+    end if
+    K = N / 2
+    L = N / 2 + 1
+!$omp task shared (A, B, T)
+    call strassen (A(:K,:K) + A(L:,L:), B(:K,:K) + B(L:,L:), T(:,:,1), K)
+!$omp end task
+!$omp task shared (A, B, T)
+    call strassen (A(L:,:K) + A(L:,L:), B(:K,:K), T(:,:,2), K)
+!$omp end task
+!$omp task shared (A, B, T)
+    call strassen (A(:K,:K), B(:K,L:) - B(L:,L:), T(:,:,3), K)
+!$omp end task
+!$omp task shared (A, B, T)
+    call strassen (A(L:,L:), B(L:,:K) - B(:K,:K), T(:,:,4), K)
+!$omp end task
+!$omp task shared (A, B, T)
+    call strassen (A(:K,:K) + A(:K,L:), B(L:,L:), T(:,:,5), K)
+!$omp end task
+!$omp task shared (A, B, T)
+    call strassen (A(L:,:K) - A(:K,:K), B(:K,:K) + B(:K,L:), T(:,:,6), K)
+!$omp end task
+!$omp task shared (A, B, T)
+    call strassen (A(:K,L:) - A(L:,L:), B(L:,:K) + B(L:,L:), T(:,:,7), K)
+!$omp end task
+!$omp taskwait
+    C(:K,:K) = T(:,:,1) + T(:,:,4) - T(:,:,5) + T(:,:,7)
+    C(L:,:K) = T(:,:,2) + T(:,:,4)
+    C(:K,L:) = T(:,:,3) + T(:,:,5)
+    C(L:,L:) = T(:,:,1) - T(:,:,2) + T(:,:,3) + T(:,:,6)
+  end subroutine strassen
+end
diff --git a/libgomp/testsuite/libgomp.fortran/tabs1.f90 b/libgomp/testsuite/libgomp.fortran/tabs1.f90
new file mode 100644 (file)
index 0000000..4f3d4f5
--- /dev/null
@@ -0,0 +1,12 @@
+       if (b().ne.2) call abort
+contains
+subroutine a
+!$omp parallel
+       !$omp   end     parallel
+       end subroutine a
+function b()
+       integer :: b
+       b = 1
+       !$      b = 2
+end function b
+       end
diff --git a/libgomp/testsuite/libgomp.fortran/tabs2.f b/libgomp/testsuite/libgomp.fortran/tabs2.f
new file mode 100644 (file)
index 0000000..7aed549
--- /dev/null
@@ -0,0 +1,13 @@
+! { dg-options "-ffixed-form" }
+      if (b().ne.2) call abort
+      contains
+      subroutine a
+!$omp parallel
+!$omp  end     parallel
+       end subroutine a
+      function b()
+      integer :: b
+       b = 1
+!$     b = 2
+      end function b
+      end
diff --git a/libgomp/testsuite/libgomp.fortran/task1.f90 b/libgomp/testsuite/libgomp.fortran/task1.f90
new file mode 100644 (file)
index 0000000..df57cb8
--- /dev/null
@@ -0,0 +1,27 @@
+! { dg-do run }
+
+program tasktest
+  use omp_lib
+  integer :: i, j
+  common /tasktest_j/ j
+  j = 0
+  !$omp parallel private (i)
+    i = omp_get_thread_num ()
+    if (i.lt.2) then
+      !$omp task if (.false.) default(firstprivate)
+        call subr (i + 1)
+      !$omp end task
+    end if
+  !$omp end parallel
+  if (j.gt.0) call abort
+contains
+  subroutine subr (i)
+    use omp_lib
+    integer :: i, j
+    common /tasktest_j/ j
+    if (omp_get_thread_num ().ne.(i - 1)) then
+    !$omp atomic
+      j = j + 1
+    end if
+  end subroutine subr
+end program tasktest
diff --git a/libgomp/testsuite/libgomp.fortran/task2.f90 b/libgomp/testsuite/libgomp.fortran/task2.f90
new file mode 100644 (file)
index 0000000..24ffee5
--- /dev/null
@@ -0,0 +1,142 @@
+  integer :: err
+  err = 0
+!$omp parallel num_threads (4) default (none) shared (err)
+!$omp single
+  call test
+!$omp end single
+!$omp end parallel
+  if (err.ne.0) call abort
+contains
+  subroutine check (x, y, l)
+    integer :: x, y
+    logical :: l
+    l = l .or. x .ne. y
+  end subroutine check
+
+  subroutine foo (c, d, e, f, g, h, i, j, k, n)
+    use omp_lib
+    integer :: n
+    character (len = *) :: c
+    character (len = n) :: d
+    integer, dimension (2, 3:5, n) :: e
+    integer, dimension (2, 3:n, n) :: f
+    character (len = *), dimension (5, 3:n) :: g
+    character (len = n), dimension (5, 3:n) :: h
+    real, dimension (:, :, :) :: i
+    double precision, dimension (3:, 5:, 7:) :: j
+    integer, dimension (:, :, :) :: k
+    logical :: l
+    integer :: p, q, r
+    character (len = n) :: s
+    integer, dimension (2, 3:5, n) :: t
+    integer, dimension (2, 3:n, n) :: u
+    character (len = n), dimension (5, 3:n) :: v
+    character (len = 2 * n + 24) :: w
+    integer :: x, z
+    character (len = 1) :: y
+    s = 'PQRSTUV'
+    forall (p = 1:2, q = 3:5, r = 1:7) t(p, q, r) = -10 + p - q + 2 * r
+    forall (p = 1:2, q = 3:7, r = 1:7) u(p, q, r) = 30 - p + q - 2 * r
+    forall (p = 1:5, q = 3:7, p + q .le. 8) v(p, q) = '_+|/Oo_'
+    forall (p = 1:5, q = 3:7, p + q .gt. 8) v(p, q) = '///|||!'
+!$omp task default (none) firstprivate (c, d, e, f, g, h, i, j, k) &
+!$omp & firstprivate (s, t, u, v) private (l, p, q, r, w, x, y) shared (err)
+    l = .false.
+    l = l .or. c .ne. 'abcdefghijkl'
+    l = l .or. d .ne. 'ABCDEFG'
+    l = l .or. s .ne. 'PQRSTUV'
+    do 100, p = 1, 2
+      do 100, q = 3, 7
+       do 100, r = 1, 7
+         if (q .lt. 6) l = l .or. e(p, q, r) .ne. 5 + p + q + 2 * r
+         l = l .or. f(p, q, r) .ne. 25 + p + q + 2 * r
+         if (r .lt. 6 .and. q + r .le. 8) l = l .or. g(r, q) .ne. '0123456789AB'
+         if (r .lt. 6 .and. q + r .gt. 8) l = l .or. g(r, q) .ne. '9876543210ZY'
+         if (r .lt. 6 .and. q + r .le. 8) l = l .or. h(r, q) .ne. '0123456'
+         if (r .lt. 6 .and. q + r .gt. 8) l = l .or. h(r, q) .ne. '9876543'
+         if (q .lt. 6) l = l .or. t(p, q, r) .ne. -10 + p - q + 2 * r
+         l = l .or. u(p, q, r) .ne. 30 - p + q - 2 * r
+         if (r .lt. 6 .and. q + r .le. 8) l = l .or. v(r, q) .ne. '_+|/Oo_'
+         if (r .lt. 6 .and. q + r .gt. 8) l = l .or. v(r, q) .ne. '///|||!'
+100 continue
+    do 101, p = 3, 5
+      do 101, q = 2, 6
+       do 101, r = 1, 7
+         l = l .or. i(p - 2, q - 1, r) .ne. 7.5 * p * q * r
+         l = l .or. j(p, q + 3, r + 6) .ne. 9.5 * p * q * r
+101 continue
+    do 102, p = 1, 5
+      do 102, q = 4, 6
+       l = l .or. k(p, 1, q - 3) .ne. 19 + p + 7 + 3 * q
+102 continue
+    call check (size (e, 1), 2, l)
+    call check (size (e, 2), 3, l)
+    call check (size (e, 3), 7, l)
+    call check (size (e), 42, l)
+    call check (size (f, 1), 2, l)
+    call check (size (f, 2), 5, l)
+    call check (size (f, 3), 7, l)
+    call check (size (f), 70, l)
+    call check (size (g, 1), 5, l)
+    call check (size (g, 2), 5, l)
+    call check (size (g), 25, l)
+    call check (size (h, 1), 5, l)
+    call check (size (h, 2), 5, l)
+    call check (size (h), 25, l)
+    call check (size (i, 1), 3, l)
+    call check (size (i, 2), 5, l)
+    call check (size (i, 3), 7, l)
+    call check (size (i), 105, l)
+    call check (size (j, 1), 4, l)
+    call check (size (j, 2), 5, l)
+    call check (size (j, 3), 7, l)
+    call check (size (j), 140, l)
+    call check (size (k, 1), 5, l)
+    call check (size (k, 2), 1, l)
+    call check (size (k, 3), 3, l)
+    call check (size (k), 15, l)
+    if (l) then
+!$omp atomic
+      err = err + 1
+    end if
+!$omp end task
+  c = ''
+  d = ''
+  e(:, :, :) = 199
+  f(:, :, :) = 198
+  g(:, :) = ''
+  h(:, :) = ''
+  i(:, :, :) = 7.0
+  j(:, :, :) = 8.0
+  k(:, :, :) = 9
+  s = ''
+  t(:, :, :) = 10
+  u(:, :, :) = 11
+  v(:, :) = ''
+  end subroutine foo
+
+  subroutine test
+    character (len = 12) :: c
+    character (len = 7) :: d
+    integer, dimension (2, 3:5, 7) :: e
+    integer, dimension (2, 3:7, 7) :: f
+    character (len = 12), dimension (5, 3:7) :: g
+    character (len = 7), dimension (5, 3:7) :: h
+    real, dimension (3:5, 2:6, 1:7) :: i
+    double precision, dimension (3:6, 2:6, 1:7) :: j
+    integer, dimension (1:5, 7:7, 4:6) :: k
+    integer :: p, q, r
+    c = 'abcdefghijkl'
+    d = 'ABCDEFG'
+    forall (p = 1:2, q = 3:5, r = 1:7) e(p, q, r) = 5 + p + q + 2 * r
+    forall (p = 1:2, q = 3:7, r = 1:7) f(p, q, r) = 25 + p + q + 2 * r
+    forall (p = 1:5, q = 3:7, p + q .le. 8) g(p, q) = '0123456789AB'
+    forall (p = 1:5, q = 3:7, p + q .gt. 8) g(p, q) = '9876543210ZY'
+    forall (p = 1:5, q = 3:7, p + q .le. 8) h(p, q) = '0123456'
+    forall (p = 1:5, q = 3:7, p + q .gt. 8) h(p, q) = '9876543'
+    forall (p = 3:5, q = 2:6, r = 1:7) i(p, q, r) = 7.5 * p * q * r
+    forall (p = 3:6, q = 2:6, r = 1:7) j(p, q, r) = 9.5 * p * q * r
+    forall (p = 1:5, q = 7:7, r = 4:6) k(p, q, r) = 19 + p + q + 3 * r
+    call foo (c, d, e, f, g, h, i, j, k, 7)
+  end subroutine test
+end
index 58caabc6248263eb07c68eb8fccd7013c0fa13fe..cdd4849b6ad2e46ca162b2b3b8f27a21802d2817 100644 (file)
@@ -94,7 +94,7 @@ contains
     forall (p = 1:2, q = 3:7, r = 1:7) u(p, q, r) = 30 - x - p + q - 2 * r
     forall (p = 1:5, q = 3:7, p + q .le. 8) v(p, q) = w(1:7)
     forall (p = 1:5, q = 3:7, p + q .gt. 8) v(p, q) = w(20:26)
-!$omp barrier
+!$omp barrier          ! { dg-warning "may not be closely nested" }
     y = ''
     if (x .eq. 0) y = '0'
     if (x .eq. 1) y = '1'
index 5c889f9923aa6e2196adf6bc7745c9ddc1c1c646..9b611505219c6ab2b4326bb34cf5d140da3fb74d 100644 (file)
@@ -66,7 +66,7 @@ contains
     forall (p = 1:2, q = 3:7, r = 1:7) u(p, q, r) = 30 - x - p + q - 2 * r
     forall (p = 1:5, q = 3:7, p + q .le. 8) v(p, q) = w(1:7)
     forall (p = 1:5, q = 3:7, p + q .gt. 8) v(p, q) = w(20:26)
-!$omp barrier
+!$omp barrier          ! { dg-warning "may not be closely nested" }
     y = ''
     if (x .eq. 0) y = '0'
     if (x .eq. 1) y = '1'
index cd20c9dbe736800925c6c4a5b0e1be5c3cf35a28..b48a5e3244b35ea1d32d72e3d4acb13a69b8c13e 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2008 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
    of threads.  */
 
 #include "libgomp.h"
+#include <stddef.h>
 #include <stdlib.h>
 #include <string.h>
 
 
-/* Create a new work share structure.  */
+/* Allocate a new work share structure, preferably from current team's
+   free gomp_work_share cache.  */
 
-struct gomp_work_share *
-gomp_new_work_share (bool ordered, unsigned nthreads)
+static struct gomp_work_share *
+alloc_work_share (struct gomp_team *team)
 {
   struct gomp_work_share *ws;
-  size_t size;
+  unsigned int i;
 
-  size = sizeof (*ws);
-  if (ordered)
-    size += nthreads * sizeof (ws->ordered_team_ids[0]);
+  /* This is called in a critical section.  */
+  if (team->work_share_list_alloc != NULL)
+    {
+      ws = team->work_share_list_alloc;
+      team->work_share_list_alloc = ws->next_free;
+      return ws;
+    }
 
-  ws = gomp_malloc_cleared (size);
-  gomp_mutex_init (&ws->lock);
-  ws->ordered_owner = -1;
+#ifdef HAVE_SYNC_BUILTINS
+  ws = team->work_share_list_free;
+  /* We need atomic read from work_share_list_free,
+     as free_work_share can be called concurrently.  */
+  __asm ("" : "+r" (ws));
+
+  if (ws && ws->next_free)
+    {
+      struct gomp_work_share *next = ws->next_free;
+      ws->next_free = NULL;
+      team->work_share_list_alloc = next->next_free;
+      return next;
+    }
+#else
+  gomp_mutex_lock (&team->work_share_list_free_lock);
+  ws = team->work_share_list_free;
+  if (ws)
+    {
+      team->work_share_list_alloc = ws->next_free;
+      team->work_share_list_free = NULL;
+      gomp_mutex_unlock (&team->work_share_list_free_lock);
+      return ws;
+    }
+  gomp_mutex_unlock (&team->work_share_list_free_lock);
+#endif
 
+  team->work_share_chunk *= 2;
+  ws = gomp_malloc (team->work_share_chunk * sizeof (struct gomp_work_share));
+  ws->next_alloc = team->work_shares[0].next_alloc;
+  team->work_shares[0].next_alloc = ws;
+  team->work_share_list_alloc = &ws[1];
+  for (i = 1; i < team->work_share_chunk - 1; i++)
+    ws[i].next_free = &ws[i + 1];
+  ws[i].next_free = NULL;
   return ws;
 }
 
+/* Initialize an already allocated struct gomp_work_share.
+   This shouldn't touch the next_alloc field.  */
+
+void
+gomp_init_work_share (struct gomp_work_share *ws, bool ordered,
+                     unsigned nthreads)
+{
+  gomp_mutex_init (&ws->lock);
+  if (__builtin_expect (ordered, 0))
+    {
+#define INLINE_ORDERED_TEAM_IDS_CNT \
+  ((sizeof (struct gomp_work_share) \
+    - offsetof (struct gomp_work_share, inline_ordered_team_ids)) \
+   / sizeof (((struct gomp_work_share *) 0)->inline_ordered_team_ids[0]))
+
+      if (nthreads > INLINE_ORDERED_TEAM_IDS_CNT)
+       ws->ordered_team_ids
+         = gomp_malloc (nthreads * sizeof (*ws->ordered_team_ids));
+      else
+       ws->ordered_team_ids = ws->inline_ordered_team_ids;
+      memset (ws->ordered_team_ids, '\0',
+             nthreads * sizeof (*ws->ordered_team_ids));
+      ws->ordered_num_used = 0;
+      ws->ordered_owner = -1;
+      ws->ordered_cur = 0;
+    }
+  else
+    ws->ordered_team_ids = NULL;
+  gomp_ptrlock_init (&ws->next_ws, NULL);
+  ws->threads_completed = 0;
+}
 
-/* Free a work share structure.  */
+/* Do any needed destruction of gomp_work_share fields before it
+   is put back into free gomp_work_share cache or freed.  */
 
-static void
-free_work_share (struct gomp_work_share *ws)
+void
+gomp_fini_work_share (struct gomp_work_share *ws)
 {
   gomp_mutex_destroy (&ws->lock);
-  free (ws);
+  if (ws->ordered_team_ids != ws->inline_ordered_team_ids)
+    free (ws->ordered_team_ids);
+  gomp_ptrlock_destroy (&ws->next_ws);
 }
 
+/* Free a work share struct, if not orphaned, put it into current
+   team's free gomp_work_share cache.  */
+
+static inline void
+free_work_share (struct gomp_team *team, struct gomp_work_share *ws)
+{
+  gomp_fini_work_share (ws);
+  if (__builtin_expect (team == NULL, 0))
+    free (ws);
+  else
+    {
+      struct gomp_work_share *next_ws;
+#ifdef HAVE_SYNC_BUILTINS
+      do
+       {
+         next_ws = team->work_share_list_free;
+         ws->next_free = next_ws;
+       }
+      while (!__sync_bool_compare_and_swap (&team->work_share_list_free,
+                                           next_ws, ws));
+#else
+      gomp_mutex_lock (&team->work_share_list_free_lock);
+      next_ws = team->work_share_list_free;
+      ws->next_free = next_ws;
+      team->work_share_list_free = ws;
+      gomp_mutex_unlock (&team->work_share_list_free_lock);
+#endif
+    }
+}
 
 /* The current thread is ready to begin the next work sharing construct.
    In all cases, thr->ts.work_share is updated to point to the new
@@ -74,71 +173,34 @@ gomp_work_share_start (bool ordered)
   struct gomp_thread *thr = gomp_thread ();
   struct gomp_team *team = thr->ts.team;
   struct gomp_work_share *ws;
-  unsigned ws_index, ws_gen;
 
   /* Work sharing constructs can be orphaned.  */
   if (team == NULL)
     {
-      ws = gomp_new_work_share (ordered, 1);
+      ws = gomp_malloc (sizeof (*ws));
+      gomp_init_work_share (ws, ordered, 1);
       thr->ts.work_share = ws;
-      thr->ts.static_trip = 0;
-      gomp_mutex_lock (&ws->lock);
-      return true;
+      return ws;
     }
 
-  gomp_mutex_lock (&team->work_share_lock);
-
-  /* This thread is beginning its next generation.  */
-  ws_gen = ++thr->ts.work_share_generation;
-
-  /* If this next generation is not newer than any other generation in
-     the team, then simply reference the existing construct.  */
-  if (ws_gen - team->oldest_live_gen < team->num_live_gen)
+  ws = thr->ts.work_share;
+  thr->ts.last_work_share = ws;
+  ws = gomp_ptrlock_get (&ws->next_ws);
+  if (ws == NULL)
     {
-      ws_index = ws_gen & team->generation_mask;
-      ws = team->work_shares[ws_index];
+      /* This thread encountered a new ws first.  */
+      struct gomp_work_share *ws = alloc_work_share (team);
+      gomp_init_work_share (ws, ordered, team->nthreads);
       thr->ts.work_share = ws;
-      thr->ts.static_trip = 0;
-
-      gomp_mutex_lock (&ws->lock);
-      gomp_mutex_unlock (&team->work_share_lock);
-
-      return false;
+      return true;
     }
-
-  /* Resize the work shares queue if we've run out of space.  */
-  if (team->num_live_gen++ == team->generation_mask)
+  else
     {
-      team->work_shares = gomp_realloc (team->work_shares,
-                                       2 * team->num_live_gen
-                                       * sizeof (*team->work_shares));
-
-      /* Unless oldest_live_gen is zero, the sequence of live elements
-        wraps around the end of the array.  If we do nothing, we break
-        lookup of the existing elements.  Fix that by unwrapping the
-        data from the front to the end.  */
-      if (team->oldest_live_gen > 0)
-       memcpy (team->work_shares + team->num_live_gen,
-               team->work_shares,
-               (team->oldest_live_gen & team->generation_mask)
-               * sizeof (*team->work_shares));
-
-      team->generation_mask = team->generation_mask * 2 + 1;
+      thr->ts.work_share = ws;
+      return false;
     }
-
-  ws_index = ws_gen & team->generation_mask;
-  ws = gomp_new_work_share (ordered, team->nthreads);
-  thr->ts.work_share = ws;
-  thr->ts.static_trip = 0;
-  team->work_shares[ws_index] = ws;
-
-  gomp_mutex_lock (&ws->lock);
-  gomp_mutex_unlock (&team->work_share_lock);
-
-  return true;
 }
 
-
 /* The current thread is done with its current work sharing construct.
    This version does imply a barrier at the end of the work-share.  */
 
@@ -147,36 +209,28 @@ gomp_work_share_end (void)
 {
   struct gomp_thread *thr = gomp_thread ();
   struct gomp_team *team = thr->ts.team;
-  struct gomp_work_share *ws = thr->ts.work_share;
-  bool last;
-
-  thr->ts.work_share = NULL;
+  gomp_barrier_state_t bstate;
 
   /* Work sharing constructs can be orphaned.  */
   if (team == NULL)
     {
-      free_work_share (ws);
+      free_work_share (NULL, thr->ts.work_share);
+      thr->ts.work_share = NULL;
       return;
     }
 
-  last = gomp_barrier_wait_start (&team->barrier);
+  bstate = gomp_barrier_wait_start (&team->barrier);
 
-  if (last)
+  if (gomp_barrier_last_thread (bstate))
     {
-      unsigned ws_index;
-
-      ws_index = thr->ts.work_share_generation & team->generation_mask;
-      team->work_shares[ws_index] = NULL;
-      team->oldest_live_gen++;
-      team->num_live_gen = 0;
-
-      free_work_share (ws);
+      if (__builtin_expect (thr->ts.last_work_share != NULL, 1))
+       free_work_share (team, thr->ts.last_work_share);
     }
 
-  gomp_barrier_wait_end (&team->barrier, last);
+  gomp_team_barrier_wait_end (&team->barrier, bstate);
+  thr->ts.last_work_share = NULL;
 }
 
-
 /* The current thread is done with its current work sharing construct.
    This version does NOT imply a barrier at the end of the work-share.  */
 
@@ -188,15 +242,17 @@ gomp_work_share_end_nowait (void)
   struct gomp_work_share *ws = thr->ts.work_share;
   unsigned completed;
 
-  thr->ts.work_share = NULL;
-
   /* Work sharing constructs can be orphaned.  */
   if (team == NULL)
     {
-      free_work_share (ws);
+      free_work_share (NULL, ws);
+      thr->ts.work_share = NULL;
       return;
     }
 
+  if (__builtin_expect (thr->ts.last_work_share == NULL, 0))
+    return;
+
 #ifdef HAVE_SYNC_BUILTINS
   completed = __sync_add_and_fetch (&ws->threads_completed, 1);
 #else
@@ -206,18 +262,6 @@ gomp_work_share_end_nowait (void)
 #endif
 
   if (completed == team->nthreads)
-    {
-      unsigned ws_index;
-
-      gomp_mutex_lock (&team->work_share_lock);
-
-      ws_index = thr->ts.work_share_generation & team->generation_mask;
-      team->work_shares[ws_index] = NULL;
-      team->oldest_live_gen++;
-      team->num_live_gen--;
-
-      gomp_mutex_unlock (&team->work_share_lock);
-
-      free_work_share (ws);
-    }
+    free_work_share (team, thr->ts.last_work_share);
+  thr->ts.last_work_share = NULL;
 }