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:
parent
c4fe74e01a
commit
a68ab35173
262
gcc/ChangeLog
262
gcc/ChangeLog
@ -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
|
||||
|
16
gcc/bitmap.c
16
gcc/bitmap.c
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
319
gcc/c-omp.c
319
gcc/c-omp.c
@ -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;
|
||||
|
395
gcc/c-parser.c
395
gcc/c-parser.c
@ -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 ();
|
||||
}
|
||||
|
@ -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 }
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
686
gcc/cp/parser.c
686
gcc/cp/parser.c
@ -1611,7 +1611,7 @@ static tree cp_parser_delete_expression
|
||||
static tree cp_parser_cast_expression
|
||||
(cp_parser *, bool, bool);
|
||||
static tree cp_parser_binary_expression
|
||||
(cp_parser *, bool);
|
||||
(cp_parser *, bool, enum cp_parser_prec);
|
||||
static tree cp_parser_question_colon_clause
|
||||
(cp_parser *, tree);
|
||||
static tree cp_parser_assignment_expression
|
||||
@ -6008,14 +6008,15 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p)
|
||||
: binops_by_token[token->type].prec)
|
||||
|
||||
static tree
|
||||
cp_parser_binary_expression (cp_parser* parser, bool cast_p)
|
||||
cp_parser_binary_expression (cp_parser* parser, bool cast_p,
|
||||
enum cp_parser_prec prec)
|
||||
{
|
||||
cp_parser_expression_stack stack;
|
||||
cp_parser_expression_stack_entry *sp = &stack[0];
|
||||
tree lhs, rhs;
|
||||
cp_token *token;
|
||||
enum tree_code tree_type, lhs_type, rhs_type;
|
||||
enum cp_parser_prec prec = PREC_NOT_OPERATOR, new_prec, lookahead_prec;
|
||||
enum cp_parser_prec new_prec, lookahead_prec;
|
||||
bool overloaded_p;
|
||||
|
||||
/* Parse the first expression. */
|
||||
@ -6192,7 +6193,7 @@ cp_parser_assignment_expression (cp_parser* parser, bool cast_p)
|
||||
else
|
||||
{
|
||||
/* Parse the binary expressions (logical-or-expression). */
|
||||
expr = cp_parser_binary_expression (parser, cast_p);
|
||||
expr = cp_parser_binary_expression (parser, cast_p, PREC_NOT_OPERATOR);
|
||||
/* If the next token is a `?' then we're actually looking at a
|
||||
conditional-expression. */
|
||||
if (cp_lexer_next_token_is (parser->lexer, CPP_QUERY))
|
||||
@ -19493,7 +19494,9 @@ cp_parser_omp_clause_name (cp_parser *parser)
|
||||
switch (p[0])
|
||||
{
|
||||
case 'c':
|
||||
if (!strcmp ("copyin", p))
|
||||
if (!strcmp ("collapse", p))
|
||||
result = PRAGMA_OMP_CLAUSE_COLLAPSE;
|
||||
else if (!strcmp ("copyin", p))
|
||||
result = PRAGMA_OMP_CLAUSE_COPYIN;
|
||||
else if (!strcmp ("copyprivate", p))
|
||||
result = PRAGMA_OMP_CLAUSE_COPYPRIVATE;
|
||||
@ -19526,6 +19529,10 @@ cp_parser_omp_clause_name (cp_parser *parser)
|
||||
else if (!strcmp ("shared", p))
|
||||
result = PRAGMA_OMP_CLAUSE_SHARED;
|
||||
break;
|
||||
case 'u':
|
||||
if (!strcmp ("untied", p))
|
||||
result = PRAGMA_OMP_CLAUSE_UNTIED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -19628,6 +19635,47 @@ cp_parser_omp_var_list (cp_parser *parser, enum omp_clause_code kind, tree list)
|
||||
return list;
|
||||
}
|
||||
|
||||
/* OpenMP 3.0:
|
||||
collapse ( constant-expression ) */
|
||||
|
||||
static tree
|
||||
cp_parser_omp_clause_collapse (cp_parser *parser, tree list)
|
||||
{
|
||||
tree c, num;
|
||||
location_t loc;
|
||||
HOST_WIDE_INT n;
|
||||
|
||||
loc = cp_lexer_peek_token (parser->lexer)->location;
|
||||
if (!cp_parser_require (parser, CPP_OPEN_PAREN, "%<(%>"))
|
||||
return list;
|
||||
|
||||
num = cp_parser_constant_expression (parser, false, NULL);
|
||||
|
||||
if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "%<)%>"))
|
||||
cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
|
||||
/*or_comma=*/false,
|
||||
/*consume_paren=*/true);
|
||||
|
||||
if (num == error_mark_node)
|
||||
return list;
|
||||
num = fold_non_dependent_expr (num);
|
||||
if (!INTEGRAL_TYPE_P (TREE_TYPE (num))
|
||||
|| !host_integerp (num, 0)
|
||||
|| (n = tree_low_cst (num, 0)) <= 0
|
||||
|| (int) n != n)
|
||||
{
|
||||
error ("%Hcollapse argument needs positive constant integer expression", &loc);
|
||||
return list;
|
||||
}
|
||||
|
||||
check_no_duplicate_clause (list, OMP_CLAUSE_COLLAPSE, "collapse");
|
||||
c = build_omp_clause (OMP_CLAUSE_COLLAPSE);
|
||||
OMP_CLAUSE_CHAIN (c) = list;
|
||||
OMP_CLAUSE_COLLAPSE_EXPR (c) = num;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/* OpenMP 2.5:
|
||||
default ( shared | none ) */
|
||||
|
||||
@ -19839,7 +19887,7 @@ cp_parser_omp_clause_reduction (cp_parser *parser, tree list)
|
||||
schedule ( schedule-kind , expression )
|
||||
|
||||
schedule-kind:
|
||||
static | dynamic | guided | runtime */
|
||||
static | dynamic | guided | runtime | auto */
|
||||
|
||||
static tree
|
||||
cp_parser_omp_clause_schedule (cp_parser *parser, tree list)
|
||||
@ -19882,6 +19930,8 @@ cp_parser_omp_clause_schedule (cp_parser *parser, tree list)
|
||||
}
|
||||
else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_STATIC))
|
||||
OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_STATIC;
|
||||
else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_AUTO))
|
||||
OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_AUTO;
|
||||
else
|
||||
goto invalid_kind;
|
||||
cp_lexer_consume_token (parser->lexer);
|
||||
@ -19897,6 +19947,9 @@ cp_parser_omp_clause_schedule (cp_parser *parser, tree list)
|
||||
else if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_RUNTIME)
|
||||
error ("schedule %<runtime%> does not take "
|
||||
"a %<chunk_size%> parameter");
|
||||
else if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_AUTO)
|
||||
error ("schedule %<auto%> does not take "
|
||||
"a %<chunk_size%> parameter");
|
||||
else
|
||||
OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c) = t;
|
||||
|
||||
@ -19919,6 +19972,21 @@ cp_parser_omp_clause_schedule (cp_parser *parser, tree list)
|
||||
return list;
|
||||
}
|
||||
|
||||
/* OpenMP 3.0:
|
||||
untied */
|
||||
|
||||
static tree
|
||||
cp_parser_omp_clause_untied (cp_parser *parser ATTRIBUTE_UNUSED, tree list)
|
||||
{
|
||||
tree c;
|
||||
|
||||
check_no_duplicate_clause (list, OMP_CLAUSE_UNTIED, "untied");
|
||||
|
||||
c = build_omp_clause (OMP_CLAUSE_UNTIED);
|
||||
OMP_CLAUSE_CHAIN (c) = list;
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Parse all OpenMP clauses. The set clauses allowed by the directive
|
||||
is a bitmask in MASK. Return the list of clauses found; the result
|
||||
of clause default goes in *pdefault. */
|
||||
@ -19944,6 +20012,10 @@ cp_parser_omp_all_clauses (cp_parser *parser, unsigned int mask,
|
||||
|
||||
switch (c_kind)
|
||||
{
|
||||
case PRAGMA_OMP_CLAUSE_COLLAPSE:
|
||||
clauses = cp_parser_omp_clause_collapse (parser, clauses);
|
||||
c_name = "collapse";
|
||||
break;
|
||||
case PRAGMA_OMP_CLAUSE_COPYIN:
|
||||
clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_COPYIN, clauses);
|
||||
c_name = "copyin";
|
||||
@ -20001,6 +20073,10 @@ cp_parser_omp_all_clauses (cp_parser *parser, unsigned int mask,
|
||||
clauses);
|
||||
c_name = "shared";
|
||||
break;
|
||||
case PRAGMA_OMP_CLAUSE_UNTIED:
|
||||
clauses = cp_parser_omp_clause_untied (parser, clauses);
|
||||
c_name = "nowait";
|
||||
break;
|
||||
default:
|
||||
cp_parser_error (parser, "expected %<#pragma omp%> clause");
|
||||
goto saw_error;
|
||||
@ -20210,94 +20286,454 @@ cp_parser_omp_flush (cp_parser *parser, cp_token *pragma_tok)
|
||||
finish_omp_flush ();
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
255
gcc/cp/pt.c
255
gcc/cp/pt.c
@ -10214,16 +10214,26 @@ tsubst_omp_clauses (tree clauses, tree args, tsubst_flags_t complain,
|
||||
|
||||
switch (OMP_CLAUSE_CODE (nc))
|
||||
{
|
||||
case OMP_CLAUSE_LASTPRIVATE:
|
||||
if (OMP_CLAUSE_LASTPRIVATE_STMT (oc))
|
||||
{
|
||||
OMP_CLAUSE_LASTPRIVATE_STMT (nc) = push_stmt_list ();
|
||||
tsubst_expr (OMP_CLAUSE_LASTPRIVATE_STMT (oc), args, complain,
|
||||
in_decl, /*integral_constant_expression_p=*/false);
|
||||
OMP_CLAUSE_LASTPRIVATE_STMT (nc)
|
||||
= pop_stmt_list (OMP_CLAUSE_LASTPRIVATE_STMT (nc));
|
||||
}
|
||||
/* FALLTHRU */
|
||||
case OMP_CLAUSE_PRIVATE:
|
||||
case OMP_CLAUSE_SHARED:
|
||||
case OMP_CLAUSE_FIRSTPRIVATE:
|
||||
case OMP_CLAUSE_LASTPRIVATE:
|
||||
case OMP_CLAUSE_REDUCTION:
|
||||
case OMP_CLAUSE_COPYIN:
|
||||
case OMP_CLAUSE_COPYPRIVATE:
|
||||
case OMP_CLAUSE_IF:
|
||||
case OMP_CLAUSE_NUM_THREADS:
|
||||
case OMP_CLAUSE_SCHEDULE:
|
||||
case OMP_CLAUSE_COLLAPSE:
|
||||
OMP_CLAUSE_OPERAND (nc, 0)
|
||||
= tsubst_expr (OMP_CLAUSE_OPERAND (oc, 0), args, complain,
|
||||
in_decl, /*integral_constant_expression_p=*/false);
|
||||
@ -10231,6 +10241,7 @@ tsubst_omp_clauses (tree clauses, tree args, tsubst_flags_t complain,
|
||||
case OMP_CLAUSE_NOWAIT:
|
||||
case OMP_CLAUSE_ORDERED:
|
||||
case OMP_CLAUSE_DEFAULT:
|
||||
case OMP_CLAUSE_UNTIED:
|
||||
break;
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
@ -10274,6 +10285,137 @@ tsubst_copy_asm_operands (tree t, tree args, tsubst_flags_t complain,
|
||||
#undef RECUR
|
||||
}
|
||||
|
||||
/* Substitute one OMP_FOR iterator. */
|
||||
|
||||
static void
|
||||
tsubst_omp_for_iterator (tree t, int i, tree declv, tree initv,
|
||||
tree condv, tree incrv, tree *clauses,
|
||||
tree args, tsubst_flags_t complain, tree in_decl,
|
||||
bool integral_constant_expression_p)
|
||||
{
|
||||
#define RECUR(NODE) \
|
||||
tsubst_expr ((NODE), args, complain, in_decl, \
|
||||
integral_constant_expression_p)
|
||||
tree decl, init, cond, incr;
|
||||
|
||||
init = TREE_VEC_ELT (OMP_FOR_INIT (t), i);
|
||||
gcc_assert (TREE_CODE (init) == MODIFY_EXPR);
|
||||
decl = RECUR (TREE_OPERAND (init, 0));
|
||||
init = TREE_OPERAND (init, 1);
|
||||
gcc_assert (!type_dependent_expression_p (decl));
|
||||
|
||||
if (!CLASS_TYPE_P (TREE_TYPE (decl)))
|
||||
{
|
||||
cond = RECUR (TREE_VEC_ELT (OMP_FOR_COND (t), i));
|
||||
incr = TREE_VEC_ELT (OMP_FOR_INCR (t), i);
|
||||
if (TREE_CODE (incr) == MODIFY_EXPR)
|
||||
incr = build_x_modify_expr (RECUR (TREE_OPERAND (incr, 0)), NOP_EXPR,
|
||||
RECUR (TREE_OPERAND (incr, 1)),
|
||||
complain);
|
||||
else
|
||||
incr = RECUR (incr);
|
||||
TREE_VEC_ELT (declv, i) = decl;
|
||||
TREE_VEC_ELT (initv, i) = init;
|
||||
TREE_VEC_ELT (condv, i) = cond;
|
||||
TREE_VEC_ELT (incrv, i) = incr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (init && TREE_CODE (init) != DECL_EXPR)
|
||||
{
|
||||
tree c;
|
||||
for (c = *clauses; c ; c = OMP_CLAUSE_CHAIN (c))
|
||||
{
|
||||
if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE
|
||||
|| OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE)
|
||||
&& OMP_CLAUSE_DECL (c) == decl)
|
||||
break;
|
||||
else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
|
||||
&& OMP_CLAUSE_DECL (c) == decl)
|
||||
error ("iteration variable %qD should not be firstprivate", decl);
|
||||
else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
|
||||
&& OMP_CLAUSE_DECL (c) == decl)
|
||||
error ("iteration variable %qD should not be reduction", decl);
|
||||
}
|
||||
if (c == NULL)
|
||||
{
|
||||
c = build_omp_clause (OMP_CLAUSE_PRIVATE);
|
||||
OMP_CLAUSE_DECL (c) = decl;
|
||||
c = finish_omp_clauses (c);
|
||||
if (c)
|
||||
{
|
||||
OMP_CLAUSE_CHAIN (c) = *clauses;
|
||||
*clauses = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
cond = TREE_VEC_ELT (OMP_FOR_COND (t), i);
|
||||
if (COMPARISON_CLASS_P (cond))
|
||||
cond = build2 (TREE_CODE (cond), boolean_type_node,
|
||||
RECUR (TREE_OPERAND (cond, 0)),
|
||||
RECUR (TREE_OPERAND (cond, 1)));
|
||||
else
|
||||
cond = RECUR (cond);
|
||||
incr = TREE_VEC_ELT (OMP_FOR_INCR (t), i);
|
||||
switch (TREE_CODE (incr))
|
||||
{
|
||||
case PREINCREMENT_EXPR:
|
||||
case PREDECREMENT_EXPR:
|
||||
case POSTINCREMENT_EXPR:
|
||||
case POSTDECREMENT_EXPR:
|
||||
incr = build2 (TREE_CODE (incr), TREE_TYPE (decl),
|
||||
RECUR (TREE_OPERAND (incr, 0)), NULL_TREE);
|
||||
break;
|
||||
case MODIFY_EXPR:
|
||||
if (TREE_CODE (TREE_OPERAND (incr, 1)) == PLUS_EXPR
|
||||
|| TREE_CODE (TREE_OPERAND (incr, 1)) == MINUS_EXPR)
|
||||
{
|
||||
tree rhs = TREE_OPERAND (incr, 1);
|
||||
incr = build2 (MODIFY_EXPR, TREE_TYPE (decl),
|
||||
RECUR (TREE_OPERAND (incr, 0)),
|
||||
build2 (TREE_CODE (rhs), TREE_TYPE (decl),
|
||||
RECUR (TREE_OPERAND (rhs, 0)),
|
||||
RECUR (TREE_OPERAND (rhs, 1))));
|
||||
}
|
||||
else
|
||||
incr = RECUR (incr);
|
||||
break;
|
||||
case MODOP_EXPR:
|
||||
if (TREE_CODE (TREE_OPERAND (incr, 1)) == PLUS_EXPR
|
||||
|| TREE_CODE (TREE_OPERAND (incr, 1)) == MINUS_EXPR)
|
||||
{
|
||||
tree lhs = RECUR (TREE_OPERAND (incr, 0));
|
||||
incr = build2 (MODIFY_EXPR, TREE_TYPE (decl), lhs,
|
||||
build2 (TREE_CODE (TREE_OPERAND (incr, 1)),
|
||||
TREE_TYPE (decl), lhs,
|
||||
RECUR (TREE_OPERAND (incr, 2))));
|
||||
}
|
||||
else if (TREE_CODE (TREE_OPERAND (incr, 1)) == NOP_EXPR
|
||||
&& (TREE_CODE (TREE_OPERAND (incr, 2)) == PLUS_EXPR
|
||||
|| (TREE_CODE (TREE_OPERAND (incr, 2)) == MINUS_EXPR)))
|
||||
{
|
||||
tree rhs = TREE_OPERAND (incr, 2);
|
||||
incr = build2 (MODIFY_EXPR, TREE_TYPE (decl),
|
||||
RECUR (TREE_OPERAND (incr, 0)),
|
||||
build2 (TREE_CODE (rhs), TREE_TYPE (decl),
|
||||
RECUR (TREE_OPERAND (rhs, 0)),
|
||||
RECUR (TREE_OPERAND (rhs, 1))));
|
||||
}
|
||||
else
|
||||
incr = RECUR (incr);
|
||||
break;
|
||||
default:
|
||||
incr = RECUR (incr);
|
||||
break;
|
||||
}
|
||||
|
||||
TREE_VEC_ELT (declv, i) = decl;
|
||||
TREE_VEC_ELT (initv, i) = init;
|
||||
TREE_VEC_ELT (condv, i) = cond;
|
||||
TREE_VEC_ELT (incrv, i) = incr;
|
||||
#undef RECUR
|
||||
}
|
||||
|
||||
/* Like tsubst_copy for expressions, etc. but also does semantic
|
||||
processing. */
|
||||
|
||||
@ -10597,21 +10739,55 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
|
||||
= OMP_PARALLEL_COMBINED (t);
|
||||
break;
|
||||
|
||||
case OMP_TASK:
|
||||
tmp = tsubst_omp_clauses (OMP_TASK_CLAUSES (t),
|
||||
args, complain, in_decl);
|
||||
stmt = begin_omp_task ();
|
||||
RECUR (OMP_TASK_BODY (t));
|
||||
finish_omp_task (tmp, stmt);
|
||||
break;
|
||||
|
||||
case OMP_FOR:
|
||||
{
|
||||
tree clauses, decl, init, cond, incr, body, pre_body;
|
||||
tree clauses, body, pre_body;
|
||||
tree declv, initv, condv, incrv;
|
||||
int i;
|
||||
|
||||
clauses = tsubst_omp_clauses (OMP_FOR_CLAUSES (t),
|
||||
args, complain, in_decl);
|
||||
init = OMP_FOR_INIT (t);
|
||||
gcc_assert (TREE_CODE (init) == MODIFY_EXPR);
|
||||
decl = RECUR (TREE_OPERAND (init, 0));
|
||||
init = RECUR (TREE_OPERAND (init, 1));
|
||||
cond = RECUR (OMP_FOR_COND (t));
|
||||
incr = RECUR (OMP_FOR_INCR (t));
|
||||
declv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t)));
|
||||
initv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t)));
|
||||
condv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t)));
|
||||
incrv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t)));
|
||||
|
||||
for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (t)); i++)
|
||||
tsubst_omp_for_iterator (t, i, declv, initv, condv, incrv,
|
||||
&clauses, args, complain, in_decl,
|
||||
integral_constant_expression_p);
|
||||
|
||||
stmt = begin_omp_structured_block ();
|
||||
|
||||
for (i = 0; i < TREE_VEC_LENGTH (initv); i++)
|
||||
if (TREE_VEC_ELT (initv, i) == NULL
|
||||
|| TREE_CODE (TREE_VEC_ELT (initv, i)) != DECL_EXPR)
|
||||
TREE_VEC_ELT (initv, i) = RECUR (TREE_VEC_ELT (initv, i));
|
||||
else if (CLASS_TYPE_P (TREE_TYPE (TREE_VEC_ELT (initv, i))))
|
||||
{
|
||||
tree init = RECUR (TREE_VEC_ELT (initv, i));
|
||||
gcc_assert (init == TREE_VEC_ELT (declv, i));
|
||||
TREE_VEC_ELT (initv, i) = NULL_TREE;
|
||||
}
|
||||
else
|
||||
{
|
||||
tree decl_expr = TREE_VEC_ELT (initv, i);
|
||||
tree init = DECL_INITIAL (DECL_EXPR_DECL (decl_expr));
|
||||
gcc_assert (init != NULL);
|
||||
TREE_VEC_ELT (initv, i) = RECUR (init);
|
||||
DECL_INITIAL (DECL_EXPR_DECL (decl_expr)) = NULL;
|
||||
RECUR (decl_expr);
|
||||
DECL_INITIAL (DECL_EXPR_DECL (decl_expr)) = init;
|
||||
}
|
||||
|
||||
pre_body = push_stmt_list ();
|
||||
RECUR (OMP_FOR_PRE_BODY (t));
|
||||
pre_body = pop_stmt_list (pre_body);
|
||||
@ -10620,10 +10796,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
|
||||
RECUR (OMP_FOR_BODY (t));
|
||||
body = pop_stmt_list (body);
|
||||
|
||||
t = finish_omp_for (EXPR_LOCATION (t), decl, init, cond, incr, body,
|
||||
pre_body);
|
||||
if (t)
|
||||
OMP_FOR_CLAUSES (t) = clauses;
|
||||
t = finish_omp_for (EXPR_LOCATION (t), declv, initv, condv, incrv,
|
||||
body, pre_body, clauses);
|
||||
|
||||
add_stmt (finish_omp_structured_block (stmt));
|
||||
}
|
||||
@ -16195,6 +16369,63 @@ dependent_template_id_p (tree tmpl, tree args)
|
||||
|| any_dependent_template_arguments_p (args));
|
||||
}
|
||||
|
||||
/* Returns TRUE if OMP_FOR with DECLV, INITV, CONDV and INCRV vectors
|
||||
is dependent. */
|
||||
|
||||
bool
|
||||
dependent_omp_for_p (tree declv, tree initv, tree condv, tree incrv)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!processing_template_decl)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < TREE_VEC_LENGTH (declv); i++)
|
||||
{
|
||||
tree decl = TREE_VEC_ELT (declv, i);
|
||||
tree init = TREE_VEC_ELT (initv, i);
|
||||
tree cond = TREE_VEC_ELT (condv, i);
|
||||
tree incr = TREE_VEC_ELT (incrv, i);
|
||||
|
||||
if (type_dependent_expression_p (decl))
|
||||
return true;
|
||||
|
||||
if (init && type_dependent_expression_p (init))
|
||||
return true;
|
||||
|
||||
if (type_dependent_expression_p (cond))
|
||||
return true;
|
||||
|
||||
if (COMPARISON_CLASS_P (cond)
|
||||
&& (type_dependent_expression_p (TREE_OPERAND (cond, 0))
|
||||
|| type_dependent_expression_p (TREE_OPERAND (cond, 1))))
|
||||
return true;
|
||||
|
||||
if (TREE_CODE (incr) == MODOP_EXPR)
|
||||
{
|
||||
if (type_dependent_expression_p (TREE_OPERAND (incr, 0))
|
||||
|| type_dependent_expression_p (TREE_OPERAND (incr, 2)))
|
||||
return true;
|
||||
}
|
||||
else if (type_dependent_expression_p (incr))
|
||||
return true;
|
||||
else if (TREE_CODE (incr) == MODIFY_EXPR)
|
||||
{
|
||||
if (type_dependent_expression_p (TREE_OPERAND (incr, 0)))
|
||||
return true;
|
||||
else if (BINARY_CLASS_P (TREE_OPERAND (incr, 1)))
|
||||
{
|
||||
tree t = TREE_OPERAND (incr, 1);
|
||||
if (type_dependent_expression_p (TREE_OPERAND (t, 0))
|
||||
|| type_dependent_expression_p (TREE_OPERAND (t, 1)))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* TYPE is a TYPENAME_TYPE. Returns the ordinary TYPE to which the
|
||||
TYPENAME_TYPE corresponds. Returns the original TYPENAME_TYPE if
|
||||
no such TYPE can be found. Note that this function peers inside
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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] = ' ';
|
||||
|
@ -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:
|
||||
|
@ -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, ¶llel_clauses,
|
||||
code->loc);
|
||||
}
|
||||
@ -1118,7 +1416,7 @@ gfc_trans_omp_parallel_do (gfc_code *code)
|
||||
pblock = █
|
||||
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:
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
354
gcc/gimplify.c
354
gcc/gimplify.c
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
|
@ -3727,6 +3727,7 @@ do_reorg_1 (void)
|
||||
}
|
||||
|
||||
set_cfun (NULL);
|
||||
bitmap_obstack_release (NULL);
|
||||
}
|
||||
|
||||
/* This function creates new global struct variables.
|
||||
|
@ -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. */
|
||||
|
@ -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. */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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",
|
||||
|
1929
gcc/omp-low.c
1929
gcc/omp-low.c
File diff suppressed because it is too large
Load Diff
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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" }
|
||||
;
|
||||
}
|
||||
|
33
gcc/testsuite/g++.dg/gomp/predetermined-1.C
Normal file
33
gcc/testsuite/g++.dg/gomp/predetermined-1.C
Normal 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;
|
||||
}
|
17
gcc/testsuite/g++.dg/gomp/task-1.C
Normal file
17
gcc/testsuite/g++.dg/gomp/task-1.C
Normal 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);
|
||||
}
|
@ -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 ()
|
||||
{
|
||||
|
16
gcc/testsuite/g++.dg/gomp/tls-4.C
Normal file
16
gcc/testsuite/g++.dg/gomp/tls-4.C
Normal 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" }
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
92
gcc/testsuite/gcc.dg/gomp/collapse-1.c
Normal file
92
gcc/testsuite/gcc.dg/gomp/collapse-1.c
Normal 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 ();
|
||||
}
|
198
gcc/testsuite/gcc.dg/gomp/nesting-1.c
Normal file
198
gcc/testsuite/gcc.dg/gomp/nesting-1.c
Normal 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" } */
|
||||
;
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
57
gcc/testsuite/gfortran.dg/gomp/collapse1.f90
Normal file
57
gcc/testsuite/gfortran.dg/gomp/collapse1.f90
Normal 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 }
|
@ -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" } }
|
||||
|
@ -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
|
||||
|
37
gcc/testsuite/gfortran.dg/gomp/sharing-3.f90
Normal file
37
gcc/testsuite/gfortran.dg/gomp/sharing-3.f90
Normal 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
|
@ -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);
|
||||
|
@ -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. */
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
25
gcc/tree.c
25
gcc/tree.c
@ -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;
|
||||
|
17
gcc/tree.def
17
gcc/tree.def
@ -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.
|
||||
|
47
gcc/tree.h
47
gcc/tree.h
@ -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) \
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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@
|
||||
|
@ -40,5 +40,5 @@ GOMP_barrier (void)
|
||||
if (team == NULL)
|
||||
return;
|
||||
|
||||
gomp_barrier_wait (&team->barrier);
|
||||
gomp_team_barrier_wait (&team->barrier);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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 ();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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
|
||||
|
70
libgomp/config/linux/ptrlock.c
Normal file
70
libgomp/config/linux/ptrlock.c
Normal 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);
|
||||
}
|
65
libgomp/config/linux/ptrlock.h
Normal file
65
libgomp/config/linux/ptrlock.h
Normal 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 */
|
@ -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 ();
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
68
libgomp/config/linux/wait.h
Normal file
68
libgomp/config/linux/wait.h
Normal 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 */
|
@ -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 ();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user