c-cppbuiltin.c (c_cpp_builtins): Change _OPENMP value to 200805.

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

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

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

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

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

From-SVN: r136433
This commit is contained in:
Jakub Jelinek 2008-06-06 15:01:54 +02:00 committed by Jakub Jelinek
parent c4fe74e01a
commit a68ab35173
193 changed files with 18368 additions and 1794 deletions

View 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

View 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;

View 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)

View 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);

View 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);

View 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);
/* 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);
elocus = locus;
if (EXPR_HAS_LOCATION (init))
elocus = EXPR_LOCATION (init);
init = DECL_INITIAL (decl);
if (init == NULL)
/* Validate the iteration variable. */
if (!INTEGRAL_TYPE_P (TREE_TYPE (decl))
&& TREE_CODE (TREE_TYPE (decl)) != POINTER_TYPE)
{
error ("%H%qE is not initialized", &elocus, decl);
init = integer_zero_node;
error ("%Hinvalid type for iteration variable %qE", &elocus, decl);
fail = true;
}
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 (TREE_CODE (cond) == LT_EXPR
|| TREE_CODE (cond) == LE_EXPR
|| TREE_CODE (cond) == GT_EXPR
|| TREE_CODE (cond) == GE_EXPR)
/* 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)
{
tree op0 = TREE_OPERAND (cond, 0);
tree op1 = TREE_OPERAND (cond, 1);
elocus = DECL_SOURCE_LOCATION (decl);
/* 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;
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))
init = DECL_INITIAL (decl);
if (init == NULL)
{
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));
error ("%H%qE is not initialized", &elocus, decl);
init = integer_zero_node;
fail = true;
}
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;
}
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_ok)
if (cond == NULL_TREE)
{
error ("%Hinvalid controlling predicate", &elocus);
error ("%Hmissing controlling predicate", &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 cond_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 (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 t = check_omp_for_incr_expr (TREE_OPERAND (incr, 1), decl);
if (t != error_mark_node)
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.
For example:
long n; int i;
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))
{
incr_ok = true;
t = build2 (PLUS_EXPR, TREE_TYPE (decl), decl, t);
incr = build2 (MODIFY_EXPR, void_type_node, decl, t);
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;
}
}
break;
default:
break;
if (!cond_ok)
{
error ("%Hinvalid controlling predicate", &elocus);
fail = true;
}
}
if (!incr_ok)
if (incr == NULL_TREE)
{
error ("%Hinvalid increment expression", &elocus);
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))
{
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)))
{
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;
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;
}
}
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;

View 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 %<;%>");
/* 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;
}
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_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 ();
}

View 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 }
};

View 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;

View 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

View 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;

View 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

View 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))

View 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;
}

View 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

View 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);

View 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));

View 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 ();
}
/* Helper function, to parse omp for increment expression. */
static tree
cp_parser_omp_for_cond (cp_parser *parser, tree decl)
{
tree lhs = cp_parser_cast_expression (parser, false, false), rhs;
enum tree_code op;
cp_token *token;
if (lhs != decl)
{
cp_parser_skip_to_end_of_statement (parser);
return error_mark_node;
}
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_parser_skip_to_end_of_statement (parser);
return error_mark_node;
}
return build2 (op, boolean_type_node, lhs, rhs);
}
/* 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)
{
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);
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)
cp_parser_omp_for_loop (cp_parser *parser, tree clauses, tree *par_clauses)
{
tree init, cond, incr, body, decl, pre_body;
location_t loc;
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;
if (!cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR))
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++)
{
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;
int bracecount = 0;
bool add_private_clause = false;
location_t loc;
init = decl = NULL;
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))
if (!cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR))
{
tree asm_specification, attributes;
cp_declarator *declarator;
cp_parser_error (parser, "for statement expected");
return NULL;
}
loc = cp_lexer_consume_token (parser->lexer)->location;
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_parser_require (parser, CPP_OPEN_PAREN, "%<(%>"))
return NULL;
cp_parser_require (parser, CPP_EQ, "%<=%>");
if (cp_parser_parse_definitely (parser))
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;
decl = start_decl (declarator, &type_specifiers,
/*initialized_p=*/false, attributes,
/*prefix_attributes=*/NULL_TREE,
&pushed_scope);
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);
init = cp_parser_assignment_expression (parser, false);
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;
if (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE)
init = error_mark_node;
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);
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);
}
if (pushed_scope)
pop_scope (pushed_scope);
}
}
else
cp_parser_abort_tentative_parse (parser);
/* 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);
if (pushed_scope)
pop_scope (pushed_scope);
{
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);
}
}
}
}
else
cp_parser_abort_tentative_parse (parser);
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 parsing as an initialized declaration failed, try again as
a simple expression. */
if (decl == NULL)
init = cp_parser_expression (parser, false);
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;
}
}
}
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, "%<;%>");
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);
}
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;
}
}
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))
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))
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);
/* 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);

View 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

View 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_OPERAND (init, 0);
init = TREE_OPERAND (init, 2);
}
break;
default:
break;
}
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)
{
error ("expected iteration declaration or initialization");
return NULL;
}
}
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_OPERAND (init, 0);
init = TREE_OPERAND (init, 2);
}
break;
default:
break;
}
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 (decl == NULL)
{
error ("%Hexpected iteration declaration or initialization",
&locus);
return NULL;
}
}
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;
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 (EXPR_HAS_LOCATION (init))
if (init && EXPR_HAS_LOCATION (init))
elocus = EXPR_LOCATION (init);
error ("%Hinvalid type for iteration variable %qE", &elocus, decl);
return NULL;
if (!DECL_P (decl))
{
error ("%Hexpected iteration declaration or initialization",
&elocus);
return NULL;
}
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)
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 (pre_body == NULL || IS_EMPTY_STMT (pre_body))
if (IS_EMPTY_STMT (pre_body))
pre_body = NULL;
else if (! processing_template_decl)
{
add_stmt (pre_body);
pre_body = 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);
omp_for = c_finish_omp_for (locus, declv, initv, condv, incrv,
body, pre_body);
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)
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)))
{
tree t = TREE_OPERAND (OMP_FOR_INCR (omp_for), 1);
int n = TREE_SIDE_EFFECTS (TREE_OPERAND (t, 1)) != 0;
if (omp_for == NULL)
return NULL;
if (!processing_template_decl)
TREE_OPERAND (t, n)
= fold_build_cleanup_point_expr (TREE_TYPE (TREE_OPERAND (t, n)),
TREE_OPERAND (t, n));
for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INCR (omp_for)); i++)
{
tree incr = TREE_VEC_ELT (OMP_FOR_INCR (omp_for), i);
if (TREE_CODE (incr) != MODIFY_EXPR)
continue;
if (TREE_SIDE_EFFECTS (TREE_OPERAND (incr, 1))
&& BINARY_CLASS_P (TREE_OPERAND (incr, 1)))
{
tree t = TREE_OPERAND (incr, 1);
int n = TREE_SIDE_EFFECTS (TREE_OPERAND (t, 1)) != 0;
if (!processing_template_decl)
TREE_OPERAND (t, n)
= fold_build_cleanup_point_expr (TREE_TYPE (TREE_OPERAND (t, n)),
TREE_OPERAND (t, n));
}
if (orig_incr)
TREE_VEC_ELT (OMP_FOR_INCR (omp_for), i) = TREE_VEC_ELT (orig_incr, i);
}
if (omp_for != NULL)
OMP_FOR_CLAUSES (omp_for) = clauses;
return omp_for;
}
@ -4039,26 +4370,12 @@ finish_omp_flush (void)
finish_expr_stmt (stmt);
}
/* True if OpenMP sharing attribute of DECL is predetermined. */
enum omp_clause_default_kind
cxx_omp_predetermined_sharing (tree decl)
void
finish_omp_taskwait (void)
{
enum omp_clause_default_kind kind;
kind = c_omp_predetermined_sharing (decl);
if (kind != OMP_CLAUSE_DEFAULT_UNSPECIFIED)
return kind;
/* Static data members are predetermined as shared. */
if (TREE_STATIC (decl))
{
tree ctx = CP_DECL_CONTEXT (decl);
if (TYPE_P (ctx) && MAYBE_CLASS_TYPE_P (ctx))
return OMP_CLAUSE_DEFAULT_SHARED;
}
return OMP_CLAUSE_DEFAULT_UNSPECIFIED;
tree fn = built_in_decls[BUILT_IN_GOMP_TASKWAIT];
tree stmt = finish_call_expr (fn, NULL, false, false, tf_warning_or_error);
finish_expr_stmt (stmt);
}
void

View 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

View 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;

View 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

View 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 */

View 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);

View 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;
}
}
}

View 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;

View 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);

View 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] = ' ';

View 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:

View 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;
/* Allocatable arrays in PRIVATE clauses need to be set to
"not currently allocated" allocation status. */
gfc_init_block (&block);
gcc_assert (outer != NULL);
gcc_assert (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_PRIVATE
|| OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_LASTPRIVATE);
gfc_conv_descriptor_data_set_tuples (&block, decl, null_pointer_node);
/* Allocatable arrays in PRIVATE clauses need to be set to
"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));
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)
for (i = 0; i < collapse; i++)
{
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;
}
int simple = 0;
int dovar_found = 0;
/* 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)
{
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)
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));
}
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");
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);
gfc_add_modify_stmt (&body, dovar, tmp);
/* 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);
}
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:

View 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;

View 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);

View 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)

View 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;

View 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 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_task (tree *expr_p, tree *pre_p)
{
tree expr = *expr_p;
gimplify_scan_omp_clauses (&OMP_TASK_CLAUSES (expr), pre_p, ORT_TASK);
push_gimplify_context ();
gimplify_stmt (&OMP_TASK_BODY (expr));
if (TREE_CODE (OMP_TASK_BODY (expr)) == BIND_EXPR)
pop_gimplify_context (OMP_TASK_BODY (expr));
else
pop_gimplify_context (NULL_TREE);
gimplify_adjust_omp_clauses (&OMP_TASK_CLAUSES (expr));
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;
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, false, false);
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)));
/* 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;
init_decl = build_gimple_modify_stmt (decl, var);
omp_add_variable (gimplify_omp_ctxp, var, GOVD_PRIVATE | GOVD_SEEN);
}
else
var = decl;
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 ();
tree_to_gimple_tuple (&OMP_FOR_INIT (for_stmt));
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);
tree_to_gimple_tuple (&OMP_FOR_INCR (for_stmt));
t = OMP_FOR_INCR (for_stmt);
switch (TREE_CODE (t))
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++)
{
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_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)));
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;
/* 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);
t = GIMPLE_STMT_OPERAND (t, 1);
/* 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;
init_decl = build_gimple_modify_stmt (decl, var);
omp_add_variable (gimplify_omp_ctxp, var, GOVD_PRIVATE | GOVD_SEEN);
}
else
var = decl;
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));
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;
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_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;

View 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)

View 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);

View File

@ -3727,6 +3727,7 @@ do_reorg_1 (void)
}
set_cfun (NULL);
bitmap_obstack_release (NULL);
}
/* This function creates new global struct variables.

View 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. */

View 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. */

View 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);

View 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",

File diff suppressed because it is too large Load Diff

View 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.

View 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

View 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);
}

View 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" }
;
}

View File

@ -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;
}

View File

@ -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);
}

View 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 ()
{

View File

@ -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" }

View 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);
}
}

View 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);
}
}

View File

@ -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 ();
}

View File

@ -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" } */
;
}

View 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);
}

View 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)

View 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

View 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

View File

@ -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 }

View 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" } }

View 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

View File

@ -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

View 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);

View 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. */

View 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:

View 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);
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 = 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 = 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 = 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);
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;

View 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;

View 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;

View 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)

View 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"
};
/* 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;

View 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.

View 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
};
/* 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) \

View 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

View 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

View 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@

View File

@ -40,5 +40,5 @@ GOMP_barrier (void)
if (team == NULL)
return;
gomp_barrier_wait (&team->barrier);
gomp_team_barrier_wait (&team->barrier);
}

View 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

View 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);

View 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");
}

View 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,36 +29,97 @@
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);
}
if (__sync_add_and_fetch (&bar->arrived, -1) == 0)
gomp_mutex_unlock (&bar->mutex);
}
void
gomp_barrier_wait (gomp_barrier_t *barrier)
gomp_barrier_wait (gomp_barrier_t *bar)
{
gomp_barrier_wait_end (barrier, gomp_barrier_wait_start (barrier));
gomp_barrier_wait_end (bar, gomp_barrier_wait_start (bar));
}
/* 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_team_barrier_wait (gomp_barrier_t *bar)
{
gomp_team_barrier_wait_end (bar, gomp_barrier_wait_start (bar));
}

View 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).
@ -36,40 +36,86 @@
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 */

View 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,23 +29,24 @@
#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 ();
}

View 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,47 +29,109 @@
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

View 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,9 +29,10 @@
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));
}

View 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;

View 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).
@ -28,10 +28,8 @@
/* 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");
}

View 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

View File

@ -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);
}

View File

@ -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 */

View 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).
@ -28,10 +28,8 @@
/* 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 ();
}

View 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);
}
}

View 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).
@ -28,10 +28,8 @@
/* 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
}

View File

@ -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 */

View 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
@ -38,14 +35,26 @@
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 ();
}

View 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

View 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);
}

View 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 */

View 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).
@ -42,39 +42,209 @@
#include "libgomp.h"
#ifdef HAVE_BROKEN_POSIX_SEMAPHORES
void
omp_init_lock (omp_lock_t *lock)
gomp_init_lock_30 (omp_lock_t *lock)
{
pthread_mutex_init (lock, NULL);
}
void
omp_destroy_lock (omp_lock_t *lock)
gomp_destroy_lock_30 (omp_lock_t *lock)
{
pthread_mutex_destroy (lock);
}
void
omp_set_lock (omp_lock_t *lock)
gomp_set_lock_30 (omp_lock_t *lock)
{
pthread_mutex_lock (lock);
}
void
omp_unset_lock (omp_lock_t *lock)
gomp_unset_lock_30 (omp_lock_t *lock)
{
pthread_mutex_unlock (lock);
}
int
omp_test_lock (omp_lock_t *lock)
gomp_test_lock_30 (omp_lock_t *lock)
{
return pthread_mutex_trylock (lock) == 0;
}
void
omp_init_nest_lock (omp_nest_lock_t *lock)
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
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
gomp_destroy_lock_25 (omp_lock_25_t *lock)
{
pthread_mutex_destroy (lock);
}
void
gomp_set_lock_25 (omp_lock_25_t *lock)
{
pthread_mutex_lock (lock);
}
void
gomp_unset_lock_25 (omp_lock_25_t *lock)
{
pthread_mutex_unlock (lock);
}
int
gomp_test_lock_25 (omp_lock_25_t *lock)
{
return pthread_mutex_trylock (lock) == 0;
}
void
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

Some files were not shown because too many files have changed in this diff Show More