From d9a6bd32adc40a7e1e5c72692a330f14453ad7f0 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 13 Oct 2015 21:06:23 +0200 Subject: [PATCH] builtin-types.def (BT_FN_BOOL_UINT_LONGPTR_LONGPTR_LONGPTR, [...]): New. gcc/ 2015-10-13 Jakub Jelinek Aldy Hernandez Ilya Verbin * builtin-types.def (BT_FN_BOOL_UINT_LONGPTR_LONGPTR_LONGPTR, BT_FN_BOOL_UINT_ULLPTR_ULLPTR_ULLPTR, BT_FN_BOOL_UINT_LONGPTR_LONG_LONGPTR_LONGPTR, BT_FN_BOOL_UINT_ULLPTR_ULL_ULLPTR_ULLPTR, BT_FN_VOID_INT_SIZE_PTR_PTR_PTR_UINT_PTR, BT_FN_VOID_INT_OMPFN_SIZE_PTR_PTR_PTR_UINT_PTR, BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR_INT, BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_UINT_LONG_INT_LONG_LONG_LONG, BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_UINT_LONG_INT_ULL_ULL_ULL, BT_FN_VOID_LONG_VAR, BT_FN_VOID_ULL_VAR): New. (BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR, BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR, BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR): Remove. * cgraph.h (enum cgraph_simd_clone_arg_type): Add SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP, SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP and SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP. (struct cgraph_simd_clone_arg): Adjust comment. * coretypes.h (struct gomp_ordered): New forward decl. * gimple.c (gimple_build_omp_critical): Add CLAUSES argument, set critical clauses to it. (gimple_build_omp_ordered): Return gomp_ordered * instead of gimple *. Add CLAUSES argument, set ordered clauses to it. (gimple_copy): Unshare clauses on GIMPLE_OMP_CRITICAL and GIMPLE_OMP_ORDERED. * gimple.def (GIMPLE_OMP_ORDERED): Change from GSS_OMP to GSS_OMP_SINGLE_LAYOUT, move it after GIMPLE_OMP_TEAMS. * gimple.h (enum gf_mask): Add GF_OMP_TASK_TASKLOOP. Add another bit to GF_OMP_FOR_KIND_MASK mask. Add GF_OMP_FOR_KIND_TASKLOOP, renumber GF_OMP_FOR_KIND_CILKFOR and GF_OMP_FOR_KIND_OACC_LOOP. Adjust GF_OMP_FOR_SIMD, GF_OMP_FOR_COMBINED and GF_OMP_FOR_COMBINED_INTO. Add another bit to GF_OMP_TARGET_KIND_MASK mask. Add GF_OMP_TARGET_KIND_ENTER_DATA and GF_OMP_TARGET_KIND_EXIT_DATA, renumber GF_OMP_TARGET_KIND_OACC_{PARALLEL,KERNELS,DATA,UPDATE,ENTER_EXIT_DATA}. (gomp_critical): Add clauses field. (gomp_ordered): New struct. (is_a_helper ::test): New inline. (gimple_build_omp_critical): Add CLAUSES argument. (gimple_build_omp_ordered): Likewise. Return gomp_ordered * instead of gimple *. (gimple_omp_critical_clauses, gimple_omp_critical_clauses_ptr, gimple_omp_critical_set_clauses, gimple_omp_ordered_clauses, gimple_omp_ordered_clauses_ptr, gimple_omp_ordered_set_clauses, gimple_omp_task_taskloop_p, gimple_omp_task_set_taskloop_p): New inline functions. * gimple-pretty-print.c (dump_gimple_omp_for): Handle taskloop. (dump_gimple_omp_target): Handle enter data and exit data. (dump_gimple_omp_block): Don't handle GIMPLE_OMP_ORDERED here. (dump_gimple_omp_critical): Print clauses. (dump_gimple_omp_ordered): New function. (dump_gimple_omp_task): Handle taskloop. (pp_gimple_stmt_1): Use dump_gimple_omp_ordered for GIMPLE_OMP_ORDERED. * gimple-walk.c (walk_gimple_op): Walk clauses on GIMPLE_OMP_CRITICAL and GIMPLE_OMP_ORDERED. * gimplify.c (enum gimplify_omp_var_data): Add GOVD_MAP_0LEN_ARRAY. (enum omp_region_type): Add ORT_COMBINED_TARGET and ORT_NONE. (struct gimplify_omp_ctx): Add loop_iter_var, target_map_scalars_firstprivate, target_map_pointers_as_0len_arrays and target_firstprivatize_array_bases fields. (delete_omp_context): Release loop_iter_var. (gimplify_bind_expr): Handle ORT_NONE. (maybe_fold_stmt): Adjust check for ORT_TARGET for the addition of ORT_COMBINED_TARGET. (is_gimple_stmt): Return true for OMP_TASKLOOP, OMP_TEAMS and OMP_TARGET{,_DATA,_UPDATE,_ENTER_DATA,_EXIT_DATA}. (omp_firstprivatize_variable): Handle ORT_NONE. Adjust check for ORT_TARGET for the addition of ORT_COMBINED_TARGET. Handle ctx->target_map_scalars_firstprivate. (omp_add_variable): Handle ORT_NONE. Allow map clause together with data sharing clauses. For data sharing clause with VLA decl on omp target/target data don't add firstprivate for the pointer. Call omp_notice_variable on TYPE_SIZE_UNIT only if it is a DECL_P. (omp_notice_threadprivate_variable): Adjust check for ORT_TARGET for the addition of ORT_COMBINED_TARGET. (omp_notice_variable): Handle ORT_NONE. Adjust check for ORT_TARGET for the addition of ORT_COMBINED_TARGET. Handle implicit mapping of pointers as zero length array sections and ctx->target_map_scalars_firstprivate mapping of scalars as firstprivate data sharing. (omp_check_private): Handle omp_member_access_dummy_var vars. (find_decl_expr): New function. (gimplify_scan_omp_clauses): Add CODE argument. For OMP_CLAUSE_IF complain if OMP_CLAUSE_IF_MODIFIER is present and does not match code. Handle OMP_CLAUSE_GANG separately. Handle OMP_CLAUSE_{PRIORITY,GRAINSIZE,NUM_TASKS,NOGROUP,THREADS,SIMD,SIMDLEN} clauses. Diagnose linear clause on combined distribute {, parallel for} simd construct, unless it is the loop iterator. Handle struct element GOMP_MAP_FIRSTPRIVATE_POINTER. Handle map clauses with COMPONENT_REF. Initialize ctx->target_map_scalars_firstprivate, ctx->target_firstprivatize_array_bases and ctx->target_map_pointers_as_0len_arrays. Add firstprivate for linear clause even to target region if combined. Remove map clauses with GOMP_MAP_FIRSTPRIVATE_POINTER kind from OMP_TARGET_{,ENTER_,EXIT_}DATA. For GOMP_MAP_FIRSTPRIVATE_POINTER map kind with non-INTEGER_CST OMP_CLAUSE_SIZE firstprivatize the bias. Handle OMP_CLAUSE_DEPEND_{SINK,SOURCE}. Handle OMP_CLAUSE_{{USE,IS}_DEVICE_PTR,DEFAULTMAP,HINT}. For linear clause on worksharing loop combined with parallel add shared clause on the parallel. Handle OMP_CLAUSE_REDUCTION with MEM_REF OMP_CLAUSE_DECL. Set DECL_NAME on omp_member_access_dummy_var vars. Add lastprivate clause to outer taskloop if needed. (gimplify_adjust_omp_clauses_1): Handle GOVD_MAP_0LEN_ARRAY. If gimplify_omp_ctxp->target_firstprivatize_array_bases, use GOMP_MAP_FIRSTPRIVATE_POINTER map kind instead of GOMP_MAP_POINTER. (gimplify_adjust_omp_clauses): Add CODE argument. Handle removal of GOMP_MAP_FIRSTPRIVATE_POINTER struct elements for struct not seen in target body. Handle removal of struct mapping if struct is not seen in target body. Remove GOMP_MAP_STRUCT map clause on OMP_TARGET_EXIT_DATA. Adjust check for ORT_TARGET for the addition of ORT_COMBINED_TARGET. Use GOMP_MAP_FIRSTPRIVATE_POINTER instead of GOMP_MAP_POINTER if ctx->target_firstprivatize_array_bases for VLAs. Set OMP_CLAUSE_MAP_PRIVATE if both data sharing and map clause appear together. Handle OMP_CLAUSE_{{USE,IS}_DEVICE_PTR,DEFAULTMAP,HINT}. Don't remove map clause if it has map-type-modifier always. Handle OMP_CLAUSE_{PRIORITY,GRAINSIZE,NUM_TASKS,NOGROUP,THREADS,SIMD,SIMDLEN} clauses. (gimplify_oacc_cache, gimplify_omp_parallel, gimplify_omp_task): Adjust gimplify_scan_omp_clauses and gimplify_adjust_omp_clauses callers. (gimplify_omp_for): Likewise. Handle OMP_TASKLOOP. Initialize loop_iter_var. Use OMP_FOR_ORIG_DECLS. Fix handling of lastprivate iterators in doacross loops. (gimplify_omp_workshare): Adjust gimplify_scan_omp_clauses and gimplify_adjust_omp_clauses callers. Use ORT_COMBINED_TARGET for OMP_TARGET_COMBINED. Adjust check for ORT_TARGET for the addition of ORT_COMBINED_TARGET. (gimplify_omp_target_update): Adjust gimplify_scan_omp_clauses and gimplify_adjust_omp_clauses callers. Handle OMP_TARGET_ENTER_DATA and OMP_TARGET_EXIT_DATA. (gimplify_omp_ordered): New function. (gimplify_expr): Handle OMP_TASKLOOP, OMP_TARGET_ENTER_DATA and OMP_TARGET_EXIT_DATA. Use gimplify_omp_ordered for OMP_ORDERED. Gimplify clauses on OMP_CRITICAL. * internal-fn.c (expand_GOMP_SIMD_ORDERED_START, expand_GOMP_SIMD_ORDERED_END): New functions. * internal-fn.def (GOMP_SIMD_ORDERED_START, GOMP_SIMD_ORDERED_END): New internal functions. * omp-builtins.def (BUILT_IN_GOMP_LOOP_DOACROSS_STATIC_START, BUILT_IN_GOMP_LOOP_DOACROSS_DYNAMIC_START, BUILT_IN_GOMP_LOOP_DOACROSS_GUIDED_START, BUILT_IN_GOMP_LOOP_DOACROSS_RUNTIME_START, BUILT_IN_GOMP_LOOP_ULL_DOACROSS_STATIC_START, BUILT_IN_GOMP_LOOP_ULL_DOACROSS_DYNAMIC_START, BUILT_IN_GOMP_LOOP_ULL_DOACROSS_GUIDED_START, BUILT_IN_GOMP_LOOP_ULL_DOACROSS_RUNTIME_START, BUILT_IN_GOMP_DOACROSS_POST, BUILT_IN_GOMP_DOACROSS_WAIT, BUILT_IN_GOMP_DOACROSS_ULL_POST, BUILT_IN_GOMP_DOACROSS_ULL_WAIT, BUILT_IN_GOMP_TARGET_ENTER_EXIT_DATA, BUILT_IN_GOMP_TASKLOOP, BUILT_IN_GOMP_TASKLOOP_ULL): New built-ins. (BUILT_IN_GOMP_TASK): Add INT argument to the end. (BUILT_IN_GOMP_TARGET): Rename from GOMP_target to GOMP_target_41, adjust type. (BUILT_IN_GOMP_TARGET_DATA): Rename from GOMP_target_data to GOMP_target_data_41, adjust type. (BUILT_IN_GOMP_TARGET_UPDATE): Rename from GOMP_target_update to GOMP_target_update_41, adjust type. * omp-low.c (struct omp_region): Adjust comments, add ord_stmt field. (struct omp_for_data): Add ordered and simd_schedule fields. (omp_member_access_dummy_var, unshare_and_remap_1, unshare_and_remap, is_taskloop_ctx): New functions. (is_taskreg_ctx): Use is_parallel_ctx and is_task_ctx. (extract_omp_for_data): Handle taskloops and doacross loops and simd schedule modifier. (omp_adjust_chunk_size): New function. (get_ws_args_for): Use it. (lookup_sfield): Change first argument to splay_tree_key, add overload with first argument tree. (maybe_lookup_field): Likewise. (use_pointer_for_field): Handle omp_member_access_dummy_var. (omp_copy_decl_2): If var is TREE_ADDRESSABLE listed in task_shared_vars, clear TREE_ADDRESSABLE on the copy. (build_outer_var_ref): Add LASTPRIVATE argument, handle taskloops and omp_member_access_dummy_var vars. (build_sender_ref): Change first argument to splay_tree_key, add overload with first argument tree. (install_var_field): For mask & 8 use &DECL_UID as key instead of the tree itself. (fixup_child_record_type): Const qualify *.omp_data_i. (scan_sharing_clauses): Handle OMP_CLAUSE_SHARED_FIRSTPRIVATE, C/C++ array reductions, OMP_CLAUSE_{IS,USE}_DEVICE_PTR clauses, OMP_CLAUSE_{PRIORITY,GRAINSIZE,NUM_TASKS,SIMDLEN,THREADS,SIMD} and OMP_CLAUSE_{NOGROUP,DEFAULTMAP} clauses, OMP_CLAUSE__LOOPTEMP_ clause on taskloop, GOMP_MAP_FIRSTPRIVATE_POINTER, OMP_CLAUSE_MAP_PRIVATE. (create_omp_child_function): Set TREE_READONLY on .omp_data_i. (find_combined_for): Allow searching for different GIMPLE_OMP_FOR kinds. (add_taskreg_looptemp_clauses): New function. (scan_omp_parallel): Use it. (scan_omp_task): Likewise. (finish_taskreg_scan): Handle OMP_CLAUSE_SHARED_FIRSTPRIVATE. For taskloop, move fields for the first two _LOOPTEMP_ clauses first. (check_omp_nesting_restrictions): Handle GF_OMP_TARGET_KIND_ENTER_DATA and GF_OMP_TARGET_KIND_EXIT_DATA. Formatting fixes. Allow the sandwiched taskloop constructs. Type check OMP_CLAUSE_DEPEND_{KIND,SOURCE}. Allow ordered simd inside of simd region. Diagnose depend(source) or depend(sink:...) on target constructs or task/taskloop. (handle_simd_reference): Use get_name. (lower_rec_input_clauses): Likewise. Ignore all OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE clauses on taskloop construct. Allow _LOOPTEMP_ clause on GOMP_TASK. Unshare new_var before passing it to omp_clause_{default,copy}_ctor. Handle OMP_CLAUSE_REDUCTION with MEM_REF OMP_CLAUSE_DECL. Set lastprivate_firstprivate flag for linear that needs copyin and copyout. Use BUILT_IN_ALLOCA_WITH_ALIGN instead of BUILT_IN_ALLOCA. (lower_lastprivate_clauses): For OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE on taskloop lookup decl in outer context. Pass true to build_outer_var_ref lastprivate argument. Handle OMP_CLAUSE_LASTPRIVATE_TASKLOOP_IV lastprivate if the decl is global outside of outer taskloop for. (lower_reduction_clauses): Handle OMP_CLAUSE_REDUCTION with MEM_REF OMP_CLAUSE_DECL. (lower_send_clauses): Ignore first two _LOOPTEMP_ clauses in taskloop GOMP_TASK. Handle OMP_CLAUSE_SHARED_FIRSTPRIVATE. Handle omp_member_access_dummy_var vars. Handle OMP_CLAUSE_REDUCTION with MEM_REF OMP_CLAUSE_DECL. Use new lookup_sfield overload. (lower_send_shared_vars): Ignore fields with NULL or FIELD_DECL abstract origin. Handle omp_member_access_dummy_var vars. (expand_parallel_call): Use expand_omp_build_assign. (expand_task_call): Handle taskloop construct expansion. Add REGION argument. Use GOMP_TASK_* defines instead of hardcoded integers. Add priority argument to GOMP_task* calls. Or in GOMP_TASK_FLAG_PRIORITY into flags if priority is present for GOMP_task call. (expand_omp_build_assign): Add prototype. Add AFTER argument, if true emit statements after *GSI_P and continue linking. (expand_omp_taskreg): Adjust expand_task_call caller. (expand_omp_for_init_counts): Rename zero_iter_bb argument to zero_iter1_bb and first_zero_iter to first_zero_iter1, add zero_iter2_bb and first_zero_iter2 arguments, handle computation of counts even for ordered loops. (expand_omp_for_init_vars): Handle GOMP_TASK inner_stmt. (expand_omp_ordered_source, expand_omp_ordered_sink, expand_omp_ordered_source_sink, expand_omp_for_ordered_loops): New functions. (expand_omp_for_generic): Use omp_adjust_chunk_size. Handle linear clauses on worksharing loop. Handle DOACROSS loop expansion. (expand_omp_for_static_nochunk): Handle linear clauses on worksharing loop. Adjust expand_omp_for_init_counts callers. (expand_omp_for_static_chunk): Likewise. Use omp_adjust_chunk_size. (expand_omp_simd): Handle addressable fd->loop.v. Adjust expand_omp_for_init_counts callers. (expand_omp_taskloop_for_outer, expand_omp_taskloop_for_inner): New functions. (expand_omp_for): Call expand_omp_taskloop_for_* for taskloop. Handle doacross loops. (expand_omp_target): Handle GF_OMP_TARGET_KIND_ENTER_DATA and GF_OMP_TARGET_KIND_EXIT_DATA. Pass flags and depend arguments to GOMP_target_{41,update_41,enter_exit_data} libcalls. (expand_omp): Don't expand ordered depend constructs here, record ord_stmt instead for later expand_omp_for_generic. (build_omp_regions_1): Handle GF_OMP_TARGET_KIND_ENTER_DATA and GF_OMP_TARGET_KIND_EXIT_DATA. Treat GIMPLE_OMP_ORDERED with depend clause as stand-alone directive. (lower_omp_ordered_clauses): New function. (lower_omp_ordered): Handle OMP_CLAUSE_SIMD, for OMP_CLAUSE_DEPEND don't lower anything. (lower_omp_for_lastprivate): Use last _looptemp_ clause on taskloop for comparison. (lower_omp_for): Handle taskloop constructs. Adjust OMP_CLAUSE_DECL and OMP_CLAUSE_LINEAR_STEP so that expand_omp_for_* can use it during expansion for linear adjustments. (create_task_copyfn): Handle OMP_CLAUSE_SHARED_FIRSTPRIVATE. (lower_depend_clauses): Assert not seeing sink/source depend kinds. Set TREE_ADDRESSABLE on array. Change first argument from gimple * to tree * pointing to the stmt's clauses. (lower_omp_taskreg): Adjust lower_depend_clauses caller. (lower_omp_target): Handle GF_OMP_TARGET_KIND_ENTER_DATA and GF_OMP_TARGET_KIND_EXIT_DATA, depend clauses, GOMP_MAP_{RELEASE,ALWAYS_{TO,FROM,TOFROM},FIRSTPRIVATE_POINTER,STRUCT} map kinds, OMP_CLAUSE_{FIRSTPRIVATE,PRIVATE,{IS,USE}_DEVICE_PTR clauses. Always use short kind and 8-bit align shift. (lower_omp_regimplify_p): Use IS_TYPE_OR_DECL_P macro. (struct lower_omp_regimplify_operands_data): New type. (lower_omp_regimplify_operands_p, lower_omp_regimplify_operands): New functions. (lower_omp_1): Use lower_omp_regimplify_operands instead of gimple_regimplify_operands. (make_gimple_omp_edges): Handle GF_OMP_TARGET_KIND_ENTER_DATA and GF_OMP_TARGET_KIND_EXIT_DATA. Treat GIMPLE_OMP_ORDERED with depend clause as stand-alone directive. (simd_clone_clauses_extract): Honor OMP_CLAUSE_LINEAR_KIND. (simd_clone_mangle): Mangle the various linear kinds per the new ABI. (simd_clone_adjust_argument_types): Handle SIMD_CLONE_ARG_TYPE_LINEAR_*_CONSTANT_STEP. (simd_clone_init_simd_arrays): Don't do anything for uval. (simd_clone_adjust): Handle SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP like SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP. Handle SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP. * omp-low.h (omp_member_access_dummy_var): New prototype. * passes.def (pass_simduid_cleanup): Schedule another copy of the pass after all optimizations. * tree.c (omp_clause_code_name): Add entries for OMP_CLAUSE_{TO_DECLARE,LINK,{USE,IS}_DEVICE_PTR,DEFAULTMAP,HINT} and OMP_CLAUSE_{PRIORITY,GRAINSIZE,NUM_TASKS,NOGROUP,THREADS,SIMD}. (omp_clause_num_ops): Likewise. Bump number of OMP_CLAUSE_REDUCTION arguments to 5 and for OMP_CLAUSE_ORDERED to 1. (walk_tree_1): Adjust for OMP_CLAUSE_ORDERED having 1 argument and OMP_CLAUSE_REDUCTION 5 arguments. Handle OMP_CLAUSE_{TO_DECLARE,LINK,{USE,IS}_DEVICE_PTR,DEFAULTMAP,HINT} and OMP_CLAUSE_{PRIORITY,GRAINSIZE,NUM_TASKS,NOGROUP,THREADS,SIMD} clauses. * tree-core.h (enum omp_clause_linear_kind): New. (struct tree_omp_clause): Change type of map_kind from unsigned char to unsigned int. Add subcode.if_modifier and subcode.linear_kind fields. (enum omp_clause_code): Add OMP_CLAUSE_{TO_DECLARE,LINK,{USE,IS}_DEVICE_PTR,DEFAULTMAP,HINT} and OMP_CLAUSE_{PRIORITY,GRAINSIZE,NUM_TASKS,NOGROUP,THREADS,SIMD}. (OMP_CLAUSE_REDUCTION): Document OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER. (enum omp_clause_depend_kind): Add OMP_CLAUSE_DEPEND_{SOURCE,SINK}. * tree.def (OMP_FOR): Add OMP_FOR_ORIG_DECLS operand. (OMP_CRITICAL): Move before OMP_SINGLE. Add OMP_CRITICAL_CLAUSES operand. (OMP_ORDERED): Move before OMP_SINGLE. Add OMP_ORDERED_CLAUSES operand. (OMP_TASKLOOP, OMP_TARGET_ENTER_DATA, OMP_TARGET_EXIT_DATA): New tree codes. * tree.h (OMP_BODY): Replace OMP_CRITICAL with OMP_TASKGROUP. (OMP_CLAUSE_SET_MAP_KIND): Cast to unsigned int rather than unsigned char. (OMP_CRITICAL_NAME): Adjust to be 3rd operand instead of 2nd. (OMP_CLAUSE_NUM_TASKS_EXPR): Formatting fix. (OMP_STANDALONE_CLAUSES): Adjust to cover OMP_TARGET_{ENTER,EXIT}_DATA. (OMP_CLAUSE_DEPEND_SINK_NEGATIVE, OMP_TARGET_COMBINED, OMP_CLAUSE_MAP_PRIVATE, OMP_FOR_ORIG_DECLS, OMP_CLAUSE_IF_MODIFIER, OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION, OMP_CRITICAL_CLAUSES, OMP_CLAUSE_PRIVATE_TASKLOOP_IV, OMP_CLAUSE_LASTPRIVATE_TASKLOOP_IV, OMP_CLAUSE_HINT_EXPR, OMP_CLAUSE_SCHEDULE_SIMD, OMP_CLAUSE_LINEAR_KIND, OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER, OMP_CLAUSE_SHARED_FIRSTPRIVATE, OMP_ORDERED_CLAUSES, OMP_TARGET_ENTER_DATA_CLAUSES, OMP_TARGET_EXIT_DATA_CLAUSES, OMP_CLAUSE_NUM_TASKS_EXPR, OMP_CLAUSE_GRAINSIZE_EXPR, OMP_CLAUSE_PRIORITY_EXPR, OMP_CLAUSE_ORDERED_EXPR): Define. * tree-inline.c (remap_gimple_stmt): Handle clauses on GIMPLE_OMP_ORDERED and GIMPLE_OMP_CRITICAL. For IFN_GOMP_SIMD_ORDERED_{START,END} set has_simduid_loops. * tree-nested.c (convert_nonlocal_omp_clauses): Handle OMP_CLAUSE_{TO_DECLARE,LINK,{USE,IS}_DEVICE_PTR,SIMDLEN,PRIORITY,SIMD} and OMP_CLAUSE_{GRAINSIZE,NUM_TASKS,HINT,NOGROUP,THREADS,DEFAULTMAP} clauses. Handle OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER. (convert_local_omp_clauses): Likewise. * tree-pretty-print.c (dump_omp_clause): Handle OMP_CLAUSE_{TO_DECLARE,LINK,{USE,IS}_DEVICE_PTR,SIMDLEN,PRIORITY,SIMD} and OMP_CLAUSE_{GRAINSIZE,NUM_TASKS,HINT,NOGROUP,THREADS,DEFAULTMAP} clauses. Handle OMP_CLAUSE_IF_MODIFIER, OMP_CLAUSE_ORDERED_EXPR, OMP_CLAUSE_SCHEDULE_SIMD, OMP_CLAUSE_LINEAR_KIND, OMP_CLAUSE_DEPEND_{SOURCE,SINK}. Use "delete" for GOMP_MAP_FORCE_DEALLOC. Handle GOMP_MAP_{ALWAYS_{TO,FROM,TOFROM},RELEASE,FIRSTPRIVATE_POINTER,STRUCT}. (dump_generic_node): Handle OMP_TASKLOOP, OMP_TARGET_{ENTER,EXIT}_DATA and clauses on OMP_ORDERED and OMP_CRITICAL. * tree-vectorizer.c (adjust_simduid_builtins): Adjust comment. Remove IFN_GOMP_SIMD_ORDERED_{START,END}. (vectorize_loops): Adjust comments. (pass_simduid_cleanup::execute): Likewise. * tree-vect-stmts.c (vectorizable_simd_clone_call): Handle SIMD_CLONE_ARG_TYPE_LINEAR_{REF,VAL,UVAL}_CONSTANT_STEP. * wide-int.h (wi::gcd): New. gcc/c-family/ 2015-10-13 Jakub Jelinek Aldy Hernandez * c-common.c (enum c_builtin_type): Define DEF_FUNCTION_TYPE_9, DEF_FUNCTION_TYPE_10 and DEF_FUNCTION_TYPE_11. (c_define_builtins): Likewise. * c-common.h (enum c_omp_clause_split): Add C_OMP_CLAUSE_SPLIT_TASKLOOP. (c_finish_omp_critical, c_finish_omp_ordered): Add CLAUSES argument. (c_finish_omp_for): Add ORIG_DECLV argument. * c-cppbuiltin.c (c_cpp_builtins): Predefine _OPENMP as 201511 instead of 201307. * c-omp.c (c_finish_omp_critical): Add CLAUSES argument, set OMP_CRITICAL_CLAUSES to it. (c_finish_omp_ordered): Add CLAUSES argument, set OMP_ORDERED_CLAUSES to it. (c_finish_omp_for): Add ORIG_DECLV argument, set OMP_FOR_ORIG_DECLS to it if OMP_FOR. Clear DECL_INITIAL on the IVs. (c_omp_split_clauses): Handle OpenMP 4.5 combined/composite constructs and new OpenMP 4.5 clauses. Clear OMP_CLAUSE_SCHEDULE_SIMD if not combined with OMP_SIMD. Add verification code. * c-pragma.c (omp_pragmas_simd): Add taskloop. * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_TASKLOOP. (enum pragma_omp_clause): Add PRAGMA_OMP_CLAUSE_{DEFAULTMAP,GRAINSIZE,HINT,{IS,USE}_DEVICE_PTR} and PRAGMA_OMP_CLAUSE_{LINK,NOGROUP,NUM_TASKS,PRIORITY,SIMD,THREADS}. gcc/c/ 2015-10-13 Jakub Jelinek Aldy Hernandez * c-parser.c (c_parser_pragma): Handle PRAGMA_OMP_ORDERED here. (c_parser_omp_clause_name): Handle OpenMP 4.5 clauses. (c_parser_omp_variable_list): Handle structure elements for map, to and from clauses. Handle array sections in reduction clause. Formatting fixes. (c_parser_omp_clause_if): Add IS_OMP argument, handle parsing of if clause modifiers. (c_parser_omp_clause_num_tasks, c_parser_omp_clause_grainsize, c_parser_omp_clause_priority, c_parser_omp_clause_hint, c_parser_omp_clause_defaultmap, c_parser_omp_clause_use_device_ptr, c_parser_omp_clause_is_device_ptr): New functions. (c_parser_omp_clause_ordered): Parse optional parameter. (c_parser_omp_clause_reduction): Handle array reductions. (c_parser_omp_clause_schedule): Parse optional simd modifier. (c_parser_omp_clause_nogroup, c_parser_omp_clause_orderedkind): New functions. (c_parser_omp_clause_linear): Parse linear clause modifiers. (c_parser_omp_clause_depend_sink): New function. (c_parser_omp_clause_depend): Parse source/sink depend kinds. (c_parser_omp_clause_map): Parse release/delete map kinds and optional always modifier. (c_parser_oacc_all_clauses): Adjust c_parser_omp_clause_if and c_finish_omp_clauses callers. (c_parser_omp_all_clauses): Likewise. Parse OpenMP 4.5 clauses. Parse "to" as OMP_CLAUSE_TO_DECLARE if on declare target directive. (c_parser_oacc_cache): Adjust c_finish_omp_clauses caller. (OMP_CRITICAL_CLAUSE_MASK): Define. (c_parser_omp_critical): Parse critical clauses. (c_parser_omp_for_loop): Handle doacross loops, adjust c_finish_omp_for and c_finish_omp_clauses callers. (OMP_SIMD_CLAUSE_MASK): Add simdlen clause. (c_parser_omp_simd): Allow ordered clause if it has no parameter. (OMP_FOR_CLAUSE_MASK): Add linear clause. (c_parser_omp_for): Disallow ordered clause when combined with distribute. Disallow linear clause when combined with distribute and not combined with simd. (OMP_ORDERED_CLAUSE_MASK, OMP_ORDERED_DEPEND_CLAUSE_MASK): Define. (c_parser_omp_ordered): Add CONTEXT argument, remove LOC argument, parse clauses and if depend clause is found, don't parse a body. (c_parser_omp_parallel): Disallow copyin clause on target parallel. Allow target parallel without for after it. (OMP_TASK_CLAUSE_MASK): Add priority clause. (OMP_TARGET_DATA_CLAUSE_MASK): Add use_device_ptr clause. (c_parser_omp_target_data): Diagnose no map clauses or clauses with invalid kinds. (OMP_TARGET_UPDATE_CLAUSE_MASK): Add depend and nowait clauses. (OMP_TARGET_ENTER_DATA_CLAUSE_MASK, OMP_TARGET_EXIT_DATA_CLAUSE_MASK): Define. (c_parser_omp_target_enter_data, c_parser_omp_target_exit_data): New functions. (OMP_TARGET_CLAUSE_MASK): Add depend, nowait, private, firstprivate, defaultmap and is_device_ptr clauses. (c_parser_omp_target): Parse target parallel and target simd. Set OMP_TARGET_COMBINED on combined constructs. Parse target enter data and target exit data. Diagnose invalid map kinds. (OMP_DECLARE_TARGET_CLAUSE_MASK): Define. (c_parser_omp_declare_target): Parse OpenMP 4.5 forms of this construct. (c_parser_omp_declare_reduction): Use STRIP_NOPS when checking for &omp_priv. (OMP_TASKLOOP_CLAUSE_MASK): Define. (c_parser_omp_taskloop): New function. (c_parser_omp_construct): Don't handle PRAGMA_OMP_ORDERED here, handle PRAGMA_OMP_TASKLOOP. (c_parser_cilk_for): Adjust c_finish_omp_clauses callers. * c-tree.h (c_finish_omp_clauses): Add two new arguments. * c-typeck.c (handle_omp_array_sections_1): Fix comment typo. Add IS_OMP argument, handle structure element bases, diagnose bitfields, pass IS_OMP recursively, diagnose known zero length array sections in depend clauses, handle array sections in reduction clause, diagnose negative length even for pointers. (handle_omp_array_sections): Add IS_OMP argument, use auto_vec for types, pass IS_OMP down to handle_omp_array_sections_1, handle array sections in reduction clause, set OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION if map could be zero length array section, use GOMP_MAP_FIRSTPRIVATE_POINTER for IS_OMP. (c_finish_omp_clauses): Add IS_OMP and DECLARE_SIMD arguments. Handle new OpenMP 4.5 clauses and new restrictions for the old ones. gcc/cp/ 2015-10-13 Jakub Jelinek Aldy Hernandez * class.c (finish_struct_1): Call finish_omp_declare_simd_methods. * cp-gimplify.c (cp_gimplify_expr): Handle OMP_TASKLOOP. (cp_genericize_r): Likewise. (cxx_omp_finish_clause): Don't diagnose references. (cxx_omp_disregard_value_expr): New function. * cp-objcp-common.h (LANG_HOOKS_OMP_DISREGARD_VALUE_EXPR): Redefine. * cp-tree.h (OMP_FOR_GIMPLIFYING_P): Document for OMP_TASKLOOP. (DECL_OMP_PRIVATIZED_MEMBER): Define. (finish_omp_declare_simd_methods, push_omp_privatization_clauses, pop_omp_privatization_clauses, save_omp_privatization_clauses, restore_omp_privatization_clauses, omp_privatize_field, cxx_omp_disregard_value_expr): New prototypes. (finish_omp_clauses): Add two new arguments. (finish_omp_for): Add ORIG_DECLV argument. * parser.c (cp_parser_lambda_body): Call save_omp_privatization_clauses and restore_omp_privatization_clauses. (cp_parser_omp_clause_name): Handle OpenMP 4.5 clauses. (cp_parser_omp_var_list_no_open): Handle structure elements for map, to and from clauses. Handle array sections in reduction clause. Parse this keyword. Formatting fixes. (cp_parser_omp_clause_if): Add IS_OMP argument, handle parsing of if clause modifiers. (cp_parser_omp_clause_num_tasks, cp_parser_omp_clause_grainsize, cp_parser_omp_clause_priority, cp_parser_omp_clause_hint, cp_parser_omp_clause_defaultmap): New functions. (cp_parser_omp_clause_ordered): Parse optional parameter. (cp_parser_omp_clause_reduction): Handle array reductions. (cp_parser_omp_clause_schedule): Parse optional simd modifier. (cp_parser_omp_clause_nogroup, cp_parser_omp_clause_orderedkind): New functions. (cp_parser_omp_clause_linear): Parse linear clause modifiers. (cp_parser_omp_clause_depend_sink): New function. (cp_parser_omp_clause_depend): Parse source/sink depend kinds. (cp_parser_omp_clause_map): Parse release/delete map kinds and optional always modifier. (cp_parser_oacc_all_clauses): Adjust cp_parser_omp_clause_if and finish_omp_clauses callers. (cp_parser_omp_all_clauses): Likewise. Parse OpenMP 4.5 clauses. Parse "to" as OMP_CLAUSE_TO_DECLARE if on declare target directive. (OMP_CRITICAL_CLAUSE_MASK): Define. (cp_parser_omp_critical): Parse critical clauses. (cp_parser_omp_for_incr): Use cp_tree_equal if processing_template_decl. (cp_parser_omp_for_loop_init): Return tree instead of bool. Handle non-static data member iterators. (cp_parser_omp_for_loop): Handle doacross loops, adjust finish_omp_for and finish_omp_clauses callers. (cp_omp_split_clauses): Adjust finish_omp_clauses caller. (OMP_SIMD_CLAUSE_MASK): Add simdlen clause. (cp_parser_omp_simd): Allow ordered clause if it has no parameter. (OMP_FOR_CLAUSE_MASK): Add linear clause. (cp_parser_omp_for): Disallow ordered clause when combined with distribute. Disallow linear clause when combined with distribute and not combined with simd. (OMP_ORDERED_CLAUSE_MASK, OMP_ORDERED_DEPEND_CLAUSE_MASK): Define. (cp_parser_omp_ordered): Add CONTEXT argument, return bool instead of tree, parse clauses and if depend clause is found, don't parse a body. (cp_parser_omp_parallel): Disallow copyin clause on target parallel. Allow target parallel without for after it. (OMP_TASK_CLAUSE_MASK): Add priority clause. (OMP_TARGET_DATA_CLAUSE_MASK): Add use_device_ptr clause. (cp_parser_omp_target_data): Diagnose no map clauses or clauses with invalid kinds. (OMP_TARGET_UPDATE_CLAUSE_MASK): Add depend and nowait clauses. (OMP_TARGET_ENTER_DATA_CLAUSE_MASK, OMP_TARGET_EXIT_DATA_CLAUSE_MASK): Define. (cp_parser_omp_target_enter_data, cp_parser_omp_target_exit_data): New functions. (OMP_TARGET_CLAUSE_MASK): Add depend, nowait, private, firstprivate, defaultmap and is_device_ptr clauses. (cp_parser_omp_target): Parse target parallel and target simd. Set OMP_TARGET_COMBINED on combined constructs. Parse target enter data and target exit data. Diagnose invalid map kinds. (cp_parser_oacc_cache): Adjust finish_omp_clauses caller. (OMP_DECLARE_TARGET_CLAUSE_MASK): Define. (cp_parser_omp_declare_target): Parse OpenMP 4.5 forms of this construct. (OMP_TASKLOOP_CLAUSE_MASK): Define. (cp_parser_omp_taskloop): New function. (cp_parser_omp_construct): Don't handle PRAGMA_OMP_ORDERED here, handle PRAGMA_OMP_TASKLOOP. (cp_parser_pragma): Handle PRAGMA_OMP_ORDERED here directly, handle PRAGMA_OMP_TASKLOOP, call push_omp_privatization_clauses and pop_omp_privatization_clauses around parsing calls. (cp_parser_cilk_for): Adjust finish_omp_clauses caller. * pt.c (apply_late_template_attributes): Adjust tsubst_omp_clauses and finish_omp_clauses callers. (tsubst_omp_clause_decl): Return NULL if decl is NULL. For TREE_LIST, copy over OMP_CLAUSE_DEPEND_SINK_NEGATIVE bit. Use tsubst_expr instead of tsubst_copy, undo convert_from_reference effects. (tsubst_omp_clauses): Add ALLOW_FIELDS argument. Handle new OpenMP 4.5 clauses. Use tsubst_omp_clause_decl for more clauses. If ALLOW_FIELDS, handle non-static data members in the clauses. Clear OMP_CLAUSE_LINEAR_STEP if it has been cleared before. (omp_parallel_combined_clauses): New variable. (tsubst_omp_for_iterator): Add ORIG_DECLV argument, recur on OMP_FOR_ORIG_DECLS, handle non-static data member iterators. Improve handling of clauses on combined constructs. (tsubst_expr): Call push_omp_privatization_clauses and pop_omp_privatization_clauses around instantiation of certain OpenMP constructs, improve handling of clauses on combined constructs, handle OMP_TASKLOOP, adjust tsubst_omp_for_iterator, tsubst_omp_clauses and finish_omp_for callers, handle clauses on critical and ordered, handle OMP_TARGET_{ENTER,EXIT}_DATA. (instantiate_decl): Call save_omp_privatization_clauses and restore_omp_privatization_clauses around instantiation. (dependent_omp_for_p): Fix up comment typo. Handle SCOPE_REF. * semantics.c (omp_private_member_map, omp_private_member_vec, omp_private_member_ignore_next): New variables. (finish_non_static_data_member): Return dummy decl for privatized non-static data members. (omp_clause_decl_field, omp_clause_printable_decl, omp_note_field_privatization, omp_privatize_field): New functions. (handle_omp_array_sections_1): Fix comment typo. Add IS_OMP argument, handle structure element bases, diagnose bitfields, pass IS_OMP recursively, diagnose known zero length array sections in depend clauses, handle array sections in reduction clause, diagnose negative length even for pointers. (handle_omp_array_sections): Add IS_OMP argument, use auto_vec for types, pass IS_OMP down to handle_omp_array_sections_1, handle array sections in reduction clause, set OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION if map could be zero length array section, use GOMP_MAP_FIRSTPRIVATE_POINTER for IS_OMP. (finish_omp_reduction_clause): Handle array sections and arrays. Use omp_clause_printable_decl. (finish_omp_declare_simd_methods, cp_finish_omp_clause_depend_sink): New functions. (finish_omp_clauses): Add ALLOW_FIELDS and DECLARE_SIMD arguments. Handle new OpenMP 4.5 clauses and new restrictions for the old ones, handle non-static data members, reject this keyword when not allowed. (push_omp_privatization_clauses, pop_omp_privatization_clauses, save_omp_privatization_clauses, restore_omp_privatization_clauses): New functions. (handle_omp_for_class_iterator): Handle OMP_TASKLOOP class iterators. Add collapse and ordered arguments. Fix handling of lastprivate iterators in doacross loops. (finish_omp_for): Add ORIG_DECLV argument, handle doacross loops, adjust c_finish_omp_for, handle_omp_for_class_iterator and finish_omp_clauses callers. Fill in OMP_CLAUSE_LINEAR_STEP on simd loops with non-static data member iterators. gcc/fortran/ 2015-10-13 Jakub Jelinek Ilya Verbin * f95-lang.c (DEF_FUNCTION_TYPE_9, DEF_FUNCTION_TYPE_10, DEF_FUNCTION_TYPE_11, DEF_FUNCTION_TYPE_VAR_1): Define. * trans-openmp.c (gfc_trans_omp_clauses): Set OMP_CLAUSE_IF_MODIFIER to ERROR_MARK, OMP_CLAUSE_ORDERED_EXPR to NULL. (gfc_trans_omp_critical): Adjust for addition of clauses. (gfc_trans_omp_ordered): Likewise. * types.def (BT_FN_BOOL_UINT_LONGPTR_LONGPTR_LONGPTR, BT_FN_BOOL_UINT_ULLPTR_ULLPTR_ULLPTR, BT_FN_BOOL_UINT_LONGPTR_LONG_LONGPTR_LONGPTR, BT_FN_BOOL_UINT_ULLPTR_ULL_ULLPTR_ULLPTR, BT_FN_VOID_INT_SIZE_PTR_PTR_PTR_UINT_PTR, BT_FN_VOID_INT_OMPFN_SIZE_PTR_PTR_PTR_UINT_PTR, BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR_INT, BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_UINT_LONG_INT_LONG_LONG_LONG, BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_UINT_LONG_INT_ULL_ULL_ULL, BT_FN_VOID_LONG_VAR, BT_FN_VOID_ULL_VAR): New. (BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR, BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR, BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR): Remove. gcc/lto/ 2015-10-13 Jakub Jelinek * lto-lang.c (DEF_FUNCTION_TYPE_9, DEF_FUNCTION_TYPE_10, DEF_FUNCTION_TYPE_11): Define. gcc/jit/ 2015-10-13 Jakub Jelinek * jit-builtins.c (DEF_FUNCTION_TYPE_9, DEF_FUNCTION_TYPE_10, DEF_FUNCTION_TYPE_11): Define. * jit-builtins.h (DEF_FUNCTION_TYPE_9, DEF_FUNCTION_TYPE_10, DEF_FUNCTION_TYPE_11): Define. gcc/ada/ 2015-10-13 Jakub Jelinek * gcc-interface/utils.c (DEF_FUNCTION_TYPE_9, DEF_FUNCTION_TYPE_10, DEF_FUNCTION_TYPE_11): Define. gcc/testsuite/ 2015-10-13 Jakub Jelinek Aldy Hernandez * c-c++-common/gomp/cancel-1.c (f2): Add map clause to target data. * c-c++-common/gomp/clauses-1.c: New test. * c-c++-common/gomp/clauses-2.c: New test. * c-c++-common/gomp/clauses-3.c: New test. * c-c++-common/gomp/clauses-4.c: New test. * c-c++-common/gomp/declare-target-1.c: New test. * c-c++-common/gomp/declare-target-2.c: New test. * c-c++-common/gomp/depend-3.c: New test. * c-c++-common/gomp/depend-4.c: New test. * c-c++-common/gomp/doacross-1.c: New test. * c-c++-common/gomp/if-1.c: New test. * c-c++-common/gomp/if-2.c: New test. * c-c++-common/gomp/linear-1.c: New test. * c-c++-common/gomp/map-2.c: New test. * c-c++-common/gomp/map-3.c: New test. * c-c++-common/gomp/nesting-1.c (f_omp_parallel, f_omp_target_data): Add map clause to target data. * c-c++-common/gomp/nesting-warn-1.c (f_omp_target): Likewise. * c-c++-common/gomp/ordered-1.c: New test. * c-c++-common/gomp/ordered-2.c: New test. * c-c++-common/gomp/ordered-3.c: New test. * c-c++-common/gomp/pr61486-1.c (foo): Remove linear clause on non-iterator. * c-c++-common/gomp/pr61486-2.c (test, test2): Remove ordered clause and ordered construct where no longer allowed. * c-c++-common/gomp/priority-1.c: New test. * c-c++-common/gomp/reduction-1.c: New test. * c-c++-common/gomp/schedule-simd-1.c: New test. * c-c++-common/gomp/sink-1.c: New test. * c-c++-common/gomp/sink-2.c: New test. * c-c++-common/gomp/sink-3.c: New test. * c-c++-common/gomp/sink-4.c: New test. * c-c++-common/gomp/udr-1.c: New test. * c-c++-common/taskloop-1.c: New test. * c-c++-common/cpp/openmp-define-3.c: Adjust for the new value of _OPENMP macro. * c-c++-common/cilk-plus/PS/body.c (foo): Adjust expected diagnostics. * c-c++-common/goacc-gomp/nesting-fail-1.c (f_acc_parallel, f_acc_kernels, f_acc_data, f_acc_loop): Add map clause to target data. * gcc.dg/gomp/clause-1.c: * gcc.dg/gomp/reduction-1.c: New test. * gcc.dg/gomp/sink-fold-1.c: New test. * gcc.dg/gomp/sink-fold-2.c: New test. * gcc.dg/gomp/sink-fold-3.c: New test. * gcc.dg/vect/vect-simd-clone-15.c: New test. * g++.dg/gomp/clause-1.C (T::test): Remove dg-error on privatization of non-static data members. * g++.dg/gomp/clause-3.C (foo): Remove one dg-error directive. Add some linear clause tests. * g++.dg/gomp/declare-simd-3.C: New test. * g++.dg/gomp/linear-1.C: New test. * g++.dg/gomp/member-1.C: New test. * g++.dg/gomp/member-2.C: New test. * g++.dg/gomp/pr66571-2.C: New test. * g++.dg/gomp/pr67504.C (foo): Add test for ordered clause with dependent argument. * g++.dg/gomp/pr67522.C (foo): Add test for invalid array section in reduction clause. * g++.dg/gomp/reference-1.C: New test. * g++.dg/gomp/sink-1.C: New test. * g++.dg/gomp/sink-2.C: New test. * g++.dg/gomp/sink-3.C: New test. * g++.dg/gomp/task-1.C: Remove both dg-error directives. * g++.dg/gomp/this-1.C: New test. * g++.dg/gomp/this-2.C: New test. * g++.dg/vect/simd-clone-2.cc: New test. * g++.dg/vect/simd-clone-2.h: New test. * g++.dg/vect/simd-clone-3.cc: New test. * g++.dg/vect/simd-clone-4.cc: New test. * g++.dg/vect/simd-clone-4.h: New test. * g++.dg/vect/simd-clone-5.cc: New test. include/ 2015-10-13 Jakub Jelinek Ilya Verbin * gomp-constants.h (GOMP_MAP_FLAG_ALWAYS): Define. (enum gomp_map_kind): Add GOMP_MAP_FIRSTPRIVATE, GOMP_MAP_FIRSTPRIVATE_INT, GOMP_MAP_USE_DEVICE_PTR, GOMP_MAP_ZERO_LEN_ARRAY_SECTION, GOMP_MAP_ALWAYS_TO, GOMP_MAP_ALWAYS_FROM, GOMP_MAP_ALWAYS_TOFROM, GOMP_MAP_STRUCT, GOMP_MAP_DELETE_ZERO_LEN_ARRAY_SECTION, GOMP_MAP_DELETE, GOMP_MAP_RELEASE, GOMP_MAP_FIRSTPRIVATE_POINTER. (GOMP_MAP_ALWAYS_TO_P, GOMP_MAP_ALWAYS_FROM_P): Define. (GOMP_TASK_FLAG_UNTIED, GOMP_TASK_FLAG_FINAL, GOMP_TASK_FLAG_MERGEABLE, GOMP_TASK_FLAG_DEPEND, GOMP_TASK_FLAG_PRIORITY, GOMP_TASK_FLAG_UP, GOMP_TASK_FLAG_GRAINSIZE, GOMP_TASK_FLAG_IF, GOMP_TASK_FLAG_NOGROUP, GOMP_TARGET_FLAG_NOWAIT, GOMP_TARGET_FLAG_EXIT_DATA, GOMP_TARGET_FLAG_UPDATE): Define. libgomp/ 2015-10-13 Jakub Jelinek Aldy Hernandez Ilya Verbin * config/linux/affinity.c (omp_get_place_num_procs, omp_get_place_proc_ids, gomp_get_place_proc_ids_8): New functions. * config/linux/doacross.h: New file. * config/posix/affinity.c (omp_get_place_num_procs, omp_get_place_proc_ids, gomp_get_place_proc_ids_8): New functions. * config/posix/doacross.h: New file. * env.c: Include gomp-constants.h. (struct gomp_task_icv): Rename run_sched_modifier to run_sched_chunk_size. (gomp_max_task_priority_var): New variable. (parse_schedule): Rename run_sched_modifier to run_sched_chunk_size. (handle_omp_display_env): Change _OPENMP value from 201307 to 201511. Print OMP_MAX_TASK_PRIORITY. (initialize_env): Parse OMP_MAX_TASK_PRIORITY. (omp_set_schedule, omp_get_schedule): Rename modifier argument to chunk_size and run_sched_modifier to run_sched_chunk_size. (omp_get_max_task_priority, omp_get_initial_device, omp_get_num_places, omp_get_place_num, omp_get_partition_num_places, omp_get_partition_place_nums): New functions. * fortran.c (omp_set_schedule_, omp_set_schedule_8_, omp_get_schedule_, omp_get_schedule_8_): Rename modifier argument to chunk_size. (omp_get_num_places_, omp_get_place_num_procs_, omp_get_place_num_procs_8_, omp_get_place_proc_ids_, omp_get_place_proc_ids_8_, omp_get_place_num_, omp_get_partition_num_places_, omp_get_partition_place_nums_, omp_get_partition_place_nums_8_, omp_get_initial_device_, omp_get_max_task_priority_): New functions. * libgomp_g.h (GOMP_loop_doacross_static_start, GOMP_loop_doacross_dynamic_start, GOMP_loop_doacross_guided_start, GOMP_loop_doacross_runtime_start, GOMP_loop_ull_doacross_static_start, GOMP_loop_ull_doacross_dynamic_start, GOMP_loop_ull_doacross_guided_start, GOMP_loop_ull_doacross_runtime_start, GOMP_doacross_post, GOMP_doacross_wait, GOMP_doacross_ull_post, GOMP_doacross_wait, GOMP_taskloop, GOMP_taskloop_ull, GOMP_target_41, GOMP_target_data_41, GOMP_target_update_41, GOMP_target_enter_exit_data): New prototypes. (GOMP_task): Add prototype argument. * libgomp.h (_LIBGOMP_CHECKING_): Define to 0 if not yet defined. (struct gomp_doacross_work_share): New type. (struct gomp_work_share): Add doacross field. (struct gomp_task_icv): Rename run_sched_modifier to run_sched_chunk_size. (enum gomp_task_kind): Rename GOMP_TASK_IFFALSE to GOMP_TASK_UNDEFERRED. Add comments. (struct gomp_task_depend_entry): Add comments. (struct gomp_task): Likewise. (struct gomp_taskgroup): Likewise. (struct gomp_target_task): New type. (struct gomp_team): Add comment. (gomp_get_place_proc_ids_8, gomp_doacross_init, gomp_doacross_ull_init, gomp_task_maybe_wait_for_dependencies, gomp_create_target_task, gomp_target_task_fn): New prototypes. (struct target_var_desc): New type. (struct target_mem_desc): Adjust comment. Use struct target_var_desc instead of splay_tree_key for list. (REFCOUNT_INFINITY): Define. (struct splay_tree_key_s): Remove copy_from field. (struct gomp_device_descr): Add dev2dev_func field. (enum gomp_map_vars_kind): New enum. (gomp_map_vars): Add one argument. * libgomp.map (OMP_4.5): Export omp_get_max_task_priority, omp_get_max_task_priority_, omp_get_num_places, omp_get_num_places_, omp_get_place_num_procs, omp_get_place_num_procs_, omp_get_place_num_procs_8_, omp_get_place_proc_ids, omp_get_place_proc_ids_, omp_get_place_proc_ids_8_, omp_get_place_num, omp_get_place_num_, omp_get_partition_num_places, omp_get_partition_num_places_, omp_get_partition_place_nums, omp_get_partition_place_nums_, omp_get_partition_place_nums_8_, omp_get_initial_device, omp_get_initial_device_, omp_target_alloc, omp_target_free, omp_target_is_present, omp_target_memcpy, omp_target_memcpy_rect, omp_target_associate_ptr and omp_target_disassociate_ptr. (GOMP_4.0.2): Renamed to ... (GOMP_4.5): ... this. Export GOMP_target_41, GOMP_target_data_41, GOMP_target_update_41, GOMP_target_enter_exit_data, GOMP_taskloop, GOMP_taskloop_ull, GOMP_loop_doacross_dynamic_start, GOMP_loop_doacross_guided_start, GOMP_loop_doacross_runtime_start, GOMP_loop_doacross_static_start, GOMP_doacross_post, GOMP_doacross_wait, GOMP_loop_ull_doacross_dynamic_start, GOMP_loop_ull_doacross_guided_start, GOMP_loop_ull_doacross_runtime_start, GOMP_loop_ull_doacross_static_start, GOMP_doacross_ull_post and GOMP_doacross_ull_wait. * libgomp.texi: Document omp_get_max_task_priority. Rename modifier argument to chunk_size for omp_set_schedule and omp_get_schedule. Document OMP_MAX_TASK_PRIORITY env var. * loop.c (GOMP_loop_runtime_start): Adjust for run_sched_modifier to run_sched_chunk_size renaming. (GOMP_loop_ordered_runtime_start): Likewise. (gomp_loop_doacross_static_start, gomp_loop_doacross_dynamic_start, gomp_loop_doacross_guided_start, GOMP_loop_doacross_runtime_start, GOMP_parallel_loop_runtime_start): New functions. (GOMP_parallel_loop_runtime): Adjust for run_sched_modifier to run_sched_chunk_size renaming. (GOMP_loop_doacross_static_start, GOMP_loop_doacross_dynamic_start, GOMP_loop_doacross_guided_start): New functions or aliases. * loop_ull.c (GOMP_loop_ull_runtime_start): Adjust for run_sched_modifier to run_sched_chunk_size renaming. (GOMP_loop_ull_ordered_runtime_start): Likewise. (gomp_loop_ull_doacross_static_start, gomp_loop_ull_doacross_dynamic_start, gomp_loop_ull_doacross_guided_start, GOMP_loop_ull_doacross_runtime_start): New functions. (GOMP_loop_ull_doacross_static_start, GOMP_loop_ull_doacross_dynamic_start, GOMP_loop_ull_doacross_guided_start): New functions or aliases. * oacc-mem.c (acc_map_data, present_create_copy, gomp_acc_insert_pointer): Pass GOMP_MAP_VARS_OPENACC instead of false to gomp_map_vars. (gomp_acc_remove_pointer): Use copy_from from target_var_desc. * oacc-parallel.c (GOACC_data_start): Pass GOMP_MAP_VARS_OPENACC instead of false to gomp_map_vars. (GOACC_parallel_keyed): Likewise. Use copy_from from target_var_desc. * omp.h.in (omp_lock_hint_t): New type. (omp_init_lock_with_hint, omp_init_nest_lock_with_hint, omp_get_num_places, omp_get_place_num_procs, omp_get_place_proc_ids, omp_get_place_num, omp_get_partition_num_places, omp_get_partition_place_nums, omp_get_initial_device, omp_get_max_task_priority, omp_target_alloc, omp_target_free, omp_target_is_present, omp_target_memcpy, omp_target_memcpy_rect, omp_target_associate_ptr, omp_target_disassociate_ptr): New prototypes. * omp_lib.f90.in (omp_lock_hint_kind): New parameter. (omp_lock_hint_none, omp_lock_hint_uncontended, omp_lock_hint_contended, omp_lock_hint_nonspeculative, omp_lock_hint_speculative): New parameters. (omp_init_lock_with_hint, omp_init_nest_lock_with_hint, omp_get_num_places, omp_get_place_num_procs, omp_get_place_proc_ids, omp_get_place_num, omp_get_partition_num_places, omp_get_partition_place_nums, omp_get_initial_device, omp_get_max_task_priority): New interfaces. (omp_set_schedule, omp_get_schedule): Rename modifier argument to chunk_size. * omp_lib.h.in (omp_lock_hint_kind): New parameter. (omp_lock_hint_none, omp_lock_hint_uncontended, omp_lock_hint_contended, omp_lock_hint_nonspeculative, omp_lock_hint_speculative): New parameters. (omp_init_lock_with_hint, omp_init_nest_lock_with_hint, omp_get_num_places, omp_get_place_num_procs, omp_get_place_proc_ids, omp_get_place_num, omp_get_partition_num_places, omp_get_partition_place_nums, omp_get_initial_device, omp_get_max_task_priority): New functions and subroutines. * ordered.c: Include stdarg.h and string.h. (MAX_COLLAPSED_BITS): Define. (gomp_doacross_init, GOMP_doacross_post, GOMP_doacross_wait, gomp_doacross_ull_init, GOMP_doacross_ull_post, GOMP_doacross_ull_wait): New functions. * target.c: Include errno.h. (resolve_device): If device is not initialized, call gomp_init_device on it. (gomp_map_lookup): New function. (gomp_map_vars_existing): Add tgt_var argument, fill it in. Don't bump refcount if REFCOUNT_INFINITY. Handle GOMP_MAP_ALWAYS_TO_P. (get_kind): Rename is_openacc argument to short_mapkind. (gomp_map_pointer): Use gomp_map_lookup. (gomp_map_fields_existing): New function. (gomp_map_vars): Rename is_openacc argument to short_mapkind and is_target to pragma_kind. Handle GOMP_MAP_VARS_ENTER_DATA, handle GOMP_MAP_FIRSTPRIVATE_INT, GOMP_MAP_STRUCT, GOMP_MAP_USE_DEVICE_PTR, GOMP_MAP_ZERO_LEN_ARRAY_SECTION. Adjust for tgt->list changed type and copy_from living in there. (gomp_copy_from_async): Adjust for tgt->list changed type and copy_from living in there. (gomp_unmap_vars): Likewise. (gomp_update): Likewise. Rename is_openacc argument to short_mapkind. Don't fail if object is not mapped. (gomp_load_image_to_device): Initialize refcount to REFCOUNT_INFINITY. (gomp_target_fallback): New function. (gomp_get_target_fn_addr): Likewise. (GOMP_target): Adjust gomp_map_vars caller, use gomp_get_target_fn_addr and gomp_target_fallback. (GOMP_target_41): New function. (gomp_target_data_fallback): New function. (GOMP_target_data): Use it, adjust gomp_map_vars caller. (GOMP_target_data_41): New function. (GOMP_target_update): Adjust gomp_update caller. (GOMP_target_update_41): New function. (gomp_exit_data, GOMP_target_enter_exit_data, gomp_target_task_fn, omp_target_alloc, omp_target_free, omp_target_is_present, omp_target_memcpy, omp_target_memcpy_rect_worker, omp_target_memcpy_rect, omp_target_associate_ptr, omp_target_disassociate_ptr, gomp_load_plugin_for_device): New functions. * task.c: Include gomp-constants.h. Include taskloop.c twice to get GOMP_taskloop and GOMP_taskloop_ull definitions. (gomp_task_handle_depend): New function. (GOMP_task): Use it. Add priority argument. Use gomp-constant.h constants instead of hardcoded numbers. Rename GOMP_TASK_IFFALSE to GOMP_TASK_UNDEFERRED. (gomp_create_target_task): New function. (verify_children_queue, verify_taskgroup_queue, verify_task_queue): New functions. (gomp_task_run_pre): Call verify_*_queue functions. If an upcoming tied task is about to leave the sibling or taskgroup queues in an invalid state, adjust appropriately. Remove taskgroup argument. Add comments. (gomp_task_run_post_handle_dependers): Add comments. (gomp_task_run_post_remove_parent): Likewise. (gomp_barrier_handle_tasks): Adjust gomp_task_run_pre caller. (GOMP_taskwait): Likewise. Add comments. (gomp_task_maybe_wait_for_dependencies): Fix scheduling problem such that the first non parent_depends_on task does not end up at the end of the children queue. (GOMP_taskgroup_start): Rename GOMP_TASK_IFFALSE to GOMP_TASK_UNDEFERRED. (GOMP_taskgroup_end): Adjust gomp_task_run_pre caller. * taskloop.c: New file. * testsuite/lib/libgomp.exp (check_effective_target_offload_device_nonshared_as): New proc. * testsuite/libgomp.c/affinity-2.c: New test. * testsuite/libgomp.c/doacross-1.c: New test. * testsuite/libgomp.c/doacross-2.c: New test. * testsuite/libgomp.c/examples-4/declare_target-1.c (fib_wrapper): Add map clause to target. * testsuite/libgomp.c/examples-4/declare_target-4.c (accum): Likewise. * testsuite/libgomp.c/examples-4/declare_target-5.c (accum): Likewise. * testsuite/libgomp.c/examples-4/device-1.c (main): Likewise. * testsuite/libgomp.c/examples-4/device-3.c (main): Likewise. * testsuite/libgomp.c/examples-4/target_data-3.c (gramSchmidt): Likewise. * testsuite/libgomp.c/examples-4/teams-2.c (dotprod): Likewise. * testsuite/libgomp.c/examples-4/teams-3.c (dotprod): Likewise. * testsuite/libgomp.c/examples-4/teams-4.c (dotprod): Likewise. * testsuite/libgomp.c/for-2.h (OMPTGT, OMPTO, OMPFROM): Define if not defined. Use those where needed. * testsuite/libgomp.c/for-4.c: New test. * testsuite/libgomp.c/for-5.c: New test. * testsuite/libgomp.c/for-6.c: New test. * testsuite/libgomp.c/linear-1.c: New test. * testsuite/libgomp.c/ordered-4.c: New test. * testsuite/libgomp.c/pr66199-2.c (f2): Adjust for linear clause only allowed on the loop iterator. * testsuite/libgomp.c/pr66199-3.c: New test. * testsuite/libgomp.c/pr66199-4.c: New test. * testsuite/libgomp.c/reduction-7.c: New test. * testsuite/libgomp.c/reduction-8.c: New test. * testsuite/libgomp.c/reduction-9.c: New test. * testsuite/libgomp.c/reduction-10.c: New test. * testsuite/libgomp.c/target-1.c (fn2, fn3, fn4): Add map(tofrom:s). * testsuite/libgomp.c/target-2.c (fn2, fn3, fn4): Likewise. * testsuite/libgomp.c/target-7.c (foo): Add map(h) where needed. * testsuite/libgomp.c/target-11.c: New test. * testsuite/libgomp.c/target-12.c: New test. * testsuite/libgomp.c/target-13.c: New test. * testsuite/libgomp.c/target-14.c: New test. * testsuite/libgomp.c/target-15.c: New test. * testsuite/libgomp.c/target-16.c: New test. * testsuite/libgomp.c/target-17.c: New test. * testsuite/libgomp.c/target-18.c: New test. * testsuite/libgomp.c/target-19.c: New test. * testsuite/libgomp.c/target-20.c: New test. * testsuite/libgomp.c/target-21.c: New test. * testsuite/libgomp.c/target-22.c: New test. * testsuite/libgomp.c/target-23.c: New test. * testsuite/libgomp.c/target-24.c: New test. * testsuite/libgomp.c/target-25.c: New test. * testsuite/libgomp.c/target-26.c: New test. * testsuite/libgomp.c/target-27.c: New test. * testsuite/libgomp.c/taskloop-1.c: New test. * testsuite/libgomp.c/taskloop-2.c: New test. * testsuite/libgomp.c/taskloop-3.c: New test. * testsuite/libgomp.c/taskloop-4.c: New test. * testsuite/libgomp.c++/ctor-13.C: New test. * testsuite/libgomp.c++/doacross-1.C: New test. * testsuite/libgomp.c++/examples-4/declare_target-2.C: Replace offload_device with offload_device_nonshared_as. * testsuite/libgomp.c++/for-12.C: New test. * testsuite/libgomp.c++/for-13.C: New test. * testsuite/libgomp.c++/for-14.C: New test. * testsuite/libgomp.c++/linear-1.C: New test. * testsuite/libgomp.c++/member-1.C: New test. * testsuite/libgomp.c++/member-2.C: New test. * testsuite/libgomp.c++/member-3.C: New test. * testsuite/libgomp.c++/member-4.C: New test. * testsuite/libgomp.c++/member-5.C: New test. * testsuite/libgomp.c++/ordered-1.C: New test. * testsuite/libgomp.c++/reduction-5.C: New test. * testsuite/libgomp.c++/reduction-6.C: New test. * testsuite/libgomp.c++/reduction-7.C: New test. * testsuite/libgomp.c++/reduction-8.C: New test. * testsuite/libgomp.c++/reduction-9.C: New test. * testsuite/libgomp.c++/reduction-10.C: New test. * testsuite/libgomp.c++/reference-1.C: New test. * testsuite/libgomp.c++/simd14.C: New test. * testsuite/libgomp.c++/target-2.C (fn2): Add map(tofrom: s) clause. * testsuite/libgomp.c++/target-5.C: New test. * testsuite/libgomp.c++/target-6.C: New test. * testsuite/libgomp.c++/target-7.C: New test. * testsuite/libgomp.c++/target-8.C: New test. * testsuite/libgomp.c++/target-9.C: New test. * testsuite/libgomp.c++/target-10.C: New test. * testsuite/libgomp.c++/target-11.C: New test. * testsuite/libgomp.c++/target-12.C: New test. * testsuite/libgomp.c++/taskloop-1.C: New test. * testsuite/libgomp.c++/taskloop-2.C: New test. * testsuite/libgomp.c++/taskloop-3.C: New test. * testsuite/libgomp.c++/taskloop-4.C: New test. * testsuite/libgomp.c++/taskloop-5.C: New test. * testsuite/libgomp.c++/taskloop-6.C: New test. * testsuite/libgomp.c++/taskloop-7.C: New test. * testsuite/libgomp.c++/taskloop-8.C: New test. * testsuite/libgomp.c++/taskloop-9.C: New test. * testsuite/libgomp.fortran/affinity1.f90: New test. * testsuite/libgomp.fortran/affinity2.f90: New test. liboffloadmic/ 2015-10-13 Ilya Verbin * plugin/libgomp-plugin-intelmic.cpp (GOMP_OFFLOAD_dev2dev): New function. * plugin/offload_target_main.cpp (__offload_target_tgt2tgt): New static function, register it in liboffloadmic. From-SVN: r228777 --- gcc/ChangeLog | 375 ++ gcc/ada/ChangeLog | 5 + gcc/ada/gcc-interface/utils.c | 24 + gcc/builtin-types.def | 41 +- gcc/c-family/ChangeLog | 28 + gcc/c-family/c-common.c | 24 + gcc/c-family/c-common.h | 9 +- gcc/c-family/c-cppbuiltin.c | 2 +- gcc/c-family/c-omp.c | 245 +- gcc/c-family/c-pragma.c | 1 + gcc/c-family/c-pragma.h | 17 +- gcc/c/ChangeLog | 82 + gcc/c/c-parser.c | 1513 +++++- gcc/c/c-tree.h | 2 +- gcc/c/c-typeck.c | 532 +- gcc/cgraph.h | 8 +- gcc/coretypes.h | 1 + gcc/cp/ChangeLog | 147 + gcc/cp/class.c | 2 + gcc/cp/cp-gimplify.c | 31 +- gcc/cp/cp-objcp-common.h | 2 + gcc/cp/cp-tree.h | 20 +- gcc/cp/parser.c | 1655 ++++++- gcc/cp/pt.c | 319 +- gcc/cp/semantics.c | 1330 ++++- gcc/fortran/ChangeLog | 24 + gcc/fortran/f95-lang.c | 63 + gcc/fortran/trans-openmp.c | 9 +- gcc/fortran/types.def | 42 +- gcc/gimple-pretty-print.c | 52 +- gcc/gimple-walk.c | 14 + gcc/gimple.c | 31 +- gcc/gimple.def | 9 +- gcc/gimple.h | 151 +- gcc/gimplify.c | 1208 ++++- gcc/internal-fn.c | 16 + gcc/internal-fn.def | 2 + gcc/jit/ChangeLog | 7 + gcc/jit/jit-builtins.c | 17 + gcc/jit/jit-builtins.h | 9 + gcc/lto/ChangeLog | 5 + gcc/lto/lto-lang.c | 24 + gcc/omp-builtins.def | 64 +- gcc/omp-low.c | 4277 +++++++++++++++-- gcc/omp-low.h | 1 + gcc/passes.def | 1 + gcc/testsuite/ChangeLog | 75 + .../c-c++-common/cilk-plus/PS/body.c | 2 +- .../c-c++-common/cpp/openmp-define-3.c | 2 +- .../c-c++-common/goacc-gomp/nesting-fail-1.c | 8 +- gcc/testsuite/c-c++-common/gomp/cancel-1.c | 14 +- gcc/testsuite/c-c++-common/gomp/clauses-1.c | 162 + gcc/testsuite/c-c++-common/gomp/clauses-2.c | 53 + gcc/testsuite/c-c++-common/gomp/clauses-3.c | 23 + gcc/testsuite/c-c++-common/gomp/clauses-4.c | 96 + .../c-c++-common/gomp/declare-target-1.c | 13 + .../c-c++-common/gomp/declare-target-2.c | 27 + gcc/testsuite/c-c++-common/gomp/depend-3.c | 21 + gcc/testsuite/c-c++-common/gomp/depend-4.c | 44 + gcc/testsuite/c-c++-common/gomp/doacross-1.c | 48 + gcc/testsuite/c-c++-common/gomp/if-1.c | 48 + gcc/testsuite/c-c++-common/gomp/if-2.c | 43 + gcc/testsuite/c-c++-common/gomp/linear-1.c | 42 + gcc/testsuite/c-c++-common/gomp/map-2.c | 44 + gcc/testsuite/c-c++-common/gomp/map-3.c | 21 + gcc/testsuite/c-c++-common/gomp/nesting-1.c | 14 +- .../c-c++-common/gomp/nesting-warn-1.c | 4 +- gcc/testsuite/c-c++-common/gomp/ordered-1.c | 91 + gcc/testsuite/c-c++-common/gomp/ordered-2.c | 4 + gcc/testsuite/c-c++-common/gomp/ordered-3.c | 91 + gcc/testsuite/c-c++-common/gomp/pr61486-1.c | 6 +- gcc/testsuite/c-c++-common/gomp/pr61486-2.c | 40 +- gcc/testsuite/c-c++-common/gomp/priority-1.c | 26 + gcc/testsuite/c-c++-common/gomp/reduction-1.c | 51 + .../c-c++-common/gomp/schedule-simd-1.c | 51 + gcc/testsuite/c-c++-common/gomp/sink-1.c | 96 + gcc/testsuite/c-c++-common/gomp/sink-2.c | 16 + gcc/testsuite/c-c++-common/gomp/sink-3.c | 20 + gcc/testsuite/c-c++-common/gomp/sink-4.c | 25 + gcc/testsuite/c-c++-common/gomp/udr-1.c | 16 + gcc/testsuite/c-c++-common/taskloop-1.c | 15 + gcc/testsuite/g++.dg/gomp/clause-1.C | 10 +- gcc/testsuite/g++.dg/gomp/clause-3.C | 11 +- gcc/testsuite/g++.dg/gomp/declare-simd-3.C | 49 + gcc/testsuite/g++.dg/gomp/linear-1.C | 48 + gcc/testsuite/g++.dg/gomp/member-1.C | 252 + gcc/testsuite/g++.dg/gomp/member-2.C | 168 + gcc/testsuite/g++.dg/gomp/pr66571-2.C | 36 + gcc/testsuite/g++.dg/gomp/pr67504.C | 4 + gcc/testsuite/g++.dg/gomp/pr67522.C | 4 + gcc/testsuite/g++.dg/gomp/reference-1.C | 26 + gcc/testsuite/g++.dg/gomp/sink-1.C | 22 + gcc/testsuite/g++.dg/gomp/sink-2.C | 64 + gcc/testsuite/g++.dg/gomp/sink-3.C | 33 + gcc/testsuite/g++.dg/gomp/task-1.C | 4 +- gcc/testsuite/g++.dg/gomp/this-1.C | 68 + gcc/testsuite/g++.dg/gomp/this-2.C | 42 + gcc/testsuite/g++.dg/vect/simd-clone-2.cc | 55 + gcc/testsuite/g++.dg/vect/simd-clone-2.h | 17 + gcc/testsuite/g++.dg/vect/simd-clone-3.cc | 34 + gcc/testsuite/g++.dg/vect/simd-clone-4.cc | 55 + gcc/testsuite/g++.dg/vect/simd-clone-4.h | 19 + gcc/testsuite/g++.dg/vect/simd-clone-5.cc | 41 + gcc/testsuite/gcc.dg/gomp/clause-1.c | 11 +- gcc/testsuite/gcc.dg/gomp/reduction-1.c | 20 + gcc/testsuite/gcc.dg/gomp/sink-fold-1.c | 31 + gcc/testsuite/gcc.dg/gomp/sink-fold-2.c | 19 + gcc/testsuite/gcc.dg/gomp/sink-fold-3.c | 25 + .../gcc.dg/vect/vect-simd-clone-15.c | 39 + gcc/tree-core.h | 58 +- gcc/tree-inline.c | 15 +- gcc/tree-nested.c | 38 + gcc/tree-pretty-print.c | 161 +- gcc/tree-vect-stmts.c | 3 + gcc/tree-vectorizer.c | 23 +- gcc/tree.c | 44 +- gcc/tree.def | 49 +- gcc/tree.h | 77 +- gcc/wide-int.h | 22 + include/ChangeLog | 17 + include/gomp-constants.h | 70 +- libgomp/ChangeLog | 314 ++ libgomp/config/linux/affinity.c | 39 + libgomp/config/linux/doacross.h | 57 + libgomp/config/posix/affinity.c | 24 + libgomp/config/posix/doacross.h | 62 + libgomp/env.c | 96 +- libgomp/fortran.c | 107 +- libgomp/libgomp.h | 157 +- libgomp/libgomp.map | 50 +- libgomp/libgomp.texi | 61 +- libgomp/libgomp_g.h | 52 +- libgomp/loop.c | 155 +- libgomp/loop_ull.c | 154 +- libgomp/oacc-mem.c | 11 +- libgomp/oacc-parallel.c | 11 +- libgomp/omp.h.in | 37 + libgomp/omp_lib.f90.in | 122 +- libgomp/omp_lib.h.in | 30 + libgomp/ordered.c | 521 ++ libgomp/target.c | 1274 ++++- libgomp/task.c | 681 ++- libgomp/taskloop.c | 363 ++ libgomp/testsuite/lib/libgomp.exp | 13 + libgomp/testsuite/libgomp.c++/ctor-13.C | 242 + libgomp/testsuite/libgomp.c++/doacross-1.C | 294 ++ .../libgomp.c++/examples-4/declare_target-2.C | 2 +- libgomp/testsuite/libgomp.c++/for-12.C | 42 + libgomp/testsuite/libgomp.c++/for-13.C | 151 + libgomp/testsuite/libgomp.c++/for-14.C | 120 + libgomp/testsuite/libgomp.c++/linear-1.C | 268 ++ libgomp/testsuite/libgomp.c++/member-1.C | 206 + libgomp/testsuite/libgomp.c++/member-2.C | 211 + libgomp/testsuite/libgomp.c++/member-3.C | 105 + libgomp/testsuite/libgomp.c++/member-4.C | 108 + libgomp/testsuite/libgomp.c++/member-5.C | 183 + libgomp/testsuite/libgomp.c++/ordered-1.C | 1 + libgomp/testsuite/libgomp.c++/reduction-10.C | 201 + libgomp/testsuite/libgomp.c++/reduction-5.C | 127 + libgomp/testsuite/libgomp.c++/reduction-6.C | 195 + libgomp/testsuite/libgomp.c++/reduction-7.C | 134 + libgomp/testsuite/libgomp.c++/reduction-8.C | 198 + libgomp/testsuite/libgomp.c++/reduction-9.C | 130 + libgomp/testsuite/libgomp.c++/reference-1.C | 57 + libgomp/testsuite/libgomp.c++/simd14.C | 43 + libgomp/testsuite/libgomp.c++/target-10.C | 154 + libgomp/testsuite/libgomp.c++/target-11.C | 121 + libgomp/testsuite/libgomp.c++/target-12.C | 93 + libgomp/testsuite/libgomp.c++/target-2.C | 3 +- libgomp/testsuite/libgomp.c++/target-5.C | 1 + libgomp/testsuite/libgomp.c++/target-6.C | 64 + libgomp/testsuite/libgomp.c++/target-7.C | 90 + libgomp/testsuite/libgomp.c++/target-8.C | 58 + libgomp/testsuite/libgomp.c++/target-9.C | 73 + libgomp/testsuite/libgomp.c++/taskloop-1.C | 4 + libgomp/testsuite/libgomp.c++/taskloop-2.C | 6 + libgomp/testsuite/libgomp.c++/taskloop-3.C | 4 + libgomp/testsuite/libgomp.c++/taskloop-4.C | 4 + libgomp/testsuite/libgomp.c++/taskloop-5.C | 73 + libgomp/testsuite/libgomp.c++/taskloop-6.C | 442 ++ libgomp/testsuite/libgomp.c++/taskloop-7.C | 400 ++ libgomp/testsuite/libgomp.c++/taskloop-8.C | 250 + libgomp/testsuite/libgomp.c++/taskloop-9.C | 323 ++ libgomp/testsuite/libgomp.c/affinity-2.c | 89 + libgomp/testsuite/libgomp.c/doacross-1.c | 181 + libgomp/testsuite/libgomp.c/doacross-2.c | 225 + .../libgomp.c/examples-4/declare_target-1.c | 2 +- .../libgomp.c/examples-4/declare_target-4.c | 2 +- .../libgomp.c/examples-4/declare_target-5.c | 2 +- .../testsuite/libgomp.c/examples-4/device-1.c | 12 +- .../testsuite/libgomp.c/examples-4/device-3.c | 4 +- .../libgomp.c/examples-4/target_data-3.c | 2 +- .../testsuite/libgomp.c/examples-4/teams-2.c | 2 +- .../testsuite/libgomp.c/examples-4/teams-3.c | 2 +- .../testsuite/libgomp.c/examples-4/teams-4.c | 2 +- libgomp/testsuite/libgomp.c/for-2.h | 41 + libgomp/testsuite/libgomp.c/for-4.c | 42 + libgomp/testsuite/libgomp.c/for-5.c | 154 + libgomp/testsuite/libgomp.c/for-6.c | 123 + libgomp/testsuite/libgomp.c/linear-1.c | 250 + libgomp/testsuite/libgomp.c/ordered-4.c | 83 + libgomp/testsuite/libgomp.c/pr66199-2.c | 5 +- libgomp/testsuite/libgomp.c/pr66199-3.c | 50 + libgomp/testsuite/libgomp.c/pr66199-4.c | 58 + libgomp/testsuite/libgomp.c/reduction-10.c | 105 + libgomp/testsuite/libgomp.c/reduction-7.c | 64 + libgomp/testsuite/libgomp.c/reduction-8.c | 98 + libgomp/testsuite/libgomp.c/reduction-9.c | 71 + libgomp/testsuite/libgomp.c/target-1.c | 7 +- libgomp/testsuite/libgomp.c/target-11.c | 86 + libgomp/testsuite/libgomp.c/target-12.c | 130 + libgomp/testsuite/libgomp.c/target-13.c | 45 + libgomp/testsuite/libgomp.c/target-14.c | 38 + libgomp/testsuite/libgomp.c/target-15.c | 74 + libgomp/testsuite/libgomp.c/target-16.c | 45 + libgomp/testsuite/libgomp.c/target-17.c | 99 + libgomp/testsuite/libgomp.c/target-18.c | 52 + libgomp/testsuite/libgomp.c/target-19.c | 127 + libgomp/testsuite/libgomp.c/target-2.c | 6 +- libgomp/testsuite/libgomp.c/target-20.c | 120 + libgomp/testsuite/libgomp.c/target-21.c | 79 + libgomp/testsuite/libgomp.c/target-22.c | 51 + libgomp/testsuite/libgomp.c/target-23.c | 48 + libgomp/testsuite/libgomp.c/target-24.c | 43 + libgomp/testsuite/libgomp.c/target-25.c | 84 + libgomp/testsuite/libgomp.c/target-26.c | 36 + libgomp/testsuite/libgomp.c/target-27.c | 67 + libgomp/testsuite/libgomp.c/target-7.c | 18 +- libgomp/testsuite/libgomp.c/taskloop-1.c | 46 + libgomp/testsuite/libgomp.c/taskloop-2.c | 147 + libgomp/testsuite/libgomp.c/taskloop-3.c | 84 + libgomp/testsuite/libgomp.c/taskloop-4.c | 97 + .../testsuite/libgomp.fortran/affinity1.f90 | 49 + .../testsuite/libgomp.fortran/affinity2.f90 | 8 + liboffloadmic/ChangeLog | 7 + .../plugin/libgomp-plugin-intelmic.cpp | 23 + liboffloadmic/plugin/offload_target_main.cpp | 24 + 237 files changed, 26878 insertions(+), 1680 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/gomp/clauses-1.c create mode 100644 gcc/testsuite/c-c++-common/gomp/clauses-2.c create mode 100644 gcc/testsuite/c-c++-common/gomp/clauses-3.c create mode 100644 gcc/testsuite/c-c++-common/gomp/clauses-4.c create mode 100644 gcc/testsuite/c-c++-common/gomp/declare-target-1.c create mode 100644 gcc/testsuite/c-c++-common/gomp/declare-target-2.c create mode 100644 gcc/testsuite/c-c++-common/gomp/depend-3.c create mode 100644 gcc/testsuite/c-c++-common/gomp/depend-4.c create mode 100644 gcc/testsuite/c-c++-common/gomp/doacross-1.c create mode 100644 gcc/testsuite/c-c++-common/gomp/if-1.c create mode 100644 gcc/testsuite/c-c++-common/gomp/if-2.c create mode 100644 gcc/testsuite/c-c++-common/gomp/linear-1.c create mode 100644 gcc/testsuite/c-c++-common/gomp/map-2.c create mode 100644 gcc/testsuite/c-c++-common/gomp/map-3.c create mode 100644 gcc/testsuite/c-c++-common/gomp/ordered-1.c create mode 100644 gcc/testsuite/c-c++-common/gomp/ordered-2.c create mode 100644 gcc/testsuite/c-c++-common/gomp/ordered-3.c create mode 100644 gcc/testsuite/c-c++-common/gomp/priority-1.c create mode 100644 gcc/testsuite/c-c++-common/gomp/reduction-1.c create mode 100644 gcc/testsuite/c-c++-common/gomp/schedule-simd-1.c create mode 100644 gcc/testsuite/c-c++-common/gomp/sink-1.c create mode 100644 gcc/testsuite/c-c++-common/gomp/sink-2.c create mode 100644 gcc/testsuite/c-c++-common/gomp/sink-3.c create mode 100644 gcc/testsuite/c-c++-common/gomp/sink-4.c create mode 100644 gcc/testsuite/c-c++-common/gomp/udr-1.c create mode 100644 gcc/testsuite/c-c++-common/taskloop-1.c create mode 100644 gcc/testsuite/g++.dg/gomp/declare-simd-3.C create mode 100644 gcc/testsuite/g++.dg/gomp/linear-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/member-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/member-2.C create mode 100644 gcc/testsuite/g++.dg/gomp/pr66571-2.C create mode 100644 gcc/testsuite/g++.dg/gomp/reference-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/sink-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/sink-2.C create mode 100644 gcc/testsuite/g++.dg/gomp/sink-3.C create mode 100644 gcc/testsuite/g++.dg/gomp/this-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/this-2.C create mode 100644 gcc/testsuite/g++.dg/vect/simd-clone-2.cc create mode 100644 gcc/testsuite/g++.dg/vect/simd-clone-2.h create mode 100644 gcc/testsuite/g++.dg/vect/simd-clone-3.cc create mode 100644 gcc/testsuite/g++.dg/vect/simd-clone-4.cc create mode 100644 gcc/testsuite/g++.dg/vect/simd-clone-4.h create mode 100644 gcc/testsuite/g++.dg/vect/simd-clone-5.cc create mode 100644 gcc/testsuite/gcc.dg/gomp/reduction-1.c create mode 100644 gcc/testsuite/gcc.dg/gomp/sink-fold-1.c create mode 100644 gcc/testsuite/gcc.dg/gomp/sink-fold-2.c create mode 100644 gcc/testsuite/gcc.dg/gomp/sink-fold-3.c create mode 100644 gcc/testsuite/gcc.dg/vect/vect-simd-clone-15.c create mode 100644 libgomp/config/linux/doacross.h create mode 100644 libgomp/config/posix/doacross.h create mode 100644 libgomp/taskloop.c create mode 100644 libgomp/testsuite/libgomp.c++/ctor-13.C create mode 100644 libgomp/testsuite/libgomp.c++/doacross-1.C create mode 100644 libgomp/testsuite/libgomp.c++/for-12.C create mode 100644 libgomp/testsuite/libgomp.c++/for-13.C create mode 100644 libgomp/testsuite/libgomp.c++/for-14.C create mode 100644 libgomp/testsuite/libgomp.c++/linear-1.C create mode 100644 libgomp/testsuite/libgomp.c++/member-1.C create mode 100644 libgomp/testsuite/libgomp.c++/member-2.C create mode 100644 libgomp/testsuite/libgomp.c++/member-3.C create mode 100644 libgomp/testsuite/libgomp.c++/member-4.C create mode 100644 libgomp/testsuite/libgomp.c++/member-5.C create mode 100644 libgomp/testsuite/libgomp.c++/ordered-1.C create mode 100644 libgomp/testsuite/libgomp.c++/reduction-10.C create mode 100644 libgomp/testsuite/libgomp.c++/reduction-5.C create mode 100644 libgomp/testsuite/libgomp.c++/reduction-6.C create mode 100644 libgomp/testsuite/libgomp.c++/reduction-7.C create mode 100644 libgomp/testsuite/libgomp.c++/reduction-8.C create mode 100644 libgomp/testsuite/libgomp.c++/reduction-9.C create mode 100644 libgomp/testsuite/libgomp.c++/reference-1.C create mode 100644 libgomp/testsuite/libgomp.c++/simd14.C create mode 100644 libgomp/testsuite/libgomp.c++/target-10.C create mode 100644 libgomp/testsuite/libgomp.c++/target-11.C create mode 100644 libgomp/testsuite/libgomp.c++/target-12.C create mode 100644 libgomp/testsuite/libgomp.c++/target-5.C create mode 100644 libgomp/testsuite/libgomp.c++/target-6.C create mode 100644 libgomp/testsuite/libgomp.c++/target-7.C create mode 100644 libgomp/testsuite/libgomp.c++/target-8.C create mode 100644 libgomp/testsuite/libgomp.c++/target-9.C create mode 100644 libgomp/testsuite/libgomp.c++/taskloop-1.C create mode 100644 libgomp/testsuite/libgomp.c++/taskloop-2.C create mode 100644 libgomp/testsuite/libgomp.c++/taskloop-3.C create mode 100644 libgomp/testsuite/libgomp.c++/taskloop-4.C create mode 100644 libgomp/testsuite/libgomp.c++/taskloop-5.C create mode 100644 libgomp/testsuite/libgomp.c++/taskloop-6.C create mode 100644 libgomp/testsuite/libgomp.c++/taskloop-7.C create mode 100644 libgomp/testsuite/libgomp.c++/taskloop-8.C create mode 100644 libgomp/testsuite/libgomp.c++/taskloop-9.C create mode 100644 libgomp/testsuite/libgomp.c/affinity-2.c create mode 100644 libgomp/testsuite/libgomp.c/doacross-1.c create mode 100644 libgomp/testsuite/libgomp.c/doacross-2.c create mode 100644 libgomp/testsuite/libgomp.c/for-4.c create mode 100644 libgomp/testsuite/libgomp.c/for-5.c create mode 100644 libgomp/testsuite/libgomp.c/for-6.c create mode 100644 libgomp/testsuite/libgomp.c/linear-1.c create mode 100644 libgomp/testsuite/libgomp.c/ordered-4.c create mode 100644 libgomp/testsuite/libgomp.c/pr66199-3.c create mode 100644 libgomp/testsuite/libgomp.c/pr66199-4.c create mode 100644 libgomp/testsuite/libgomp.c/reduction-10.c create mode 100644 libgomp/testsuite/libgomp.c/reduction-7.c create mode 100644 libgomp/testsuite/libgomp.c/reduction-8.c create mode 100644 libgomp/testsuite/libgomp.c/reduction-9.c create mode 100644 libgomp/testsuite/libgomp.c/target-11.c create mode 100644 libgomp/testsuite/libgomp.c/target-12.c create mode 100644 libgomp/testsuite/libgomp.c/target-13.c create mode 100644 libgomp/testsuite/libgomp.c/target-14.c create mode 100644 libgomp/testsuite/libgomp.c/target-15.c create mode 100644 libgomp/testsuite/libgomp.c/target-16.c create mode 100644 libgomp/testsuite/libgomp.c/target-17.c create mode 100644 libgomp/testsuite/libgomp.c/target-18.c create mode 100644 libgomp/testsuite/libgomp.c/target-19.c create mode 100644 libgomp/testsuite/libgomp.c/target-20.c create mode 100644 libgomp/testsuite/libgomp.c/target-21.c create mode 100644 libgomp/testsuite/libgomp.c/target-22.c create mode 100644 libgomp/testsuite/libgomp.c/target-23.c create mode 100644 libgomp/testsuite/libgomp.c/target-24.c create mode 100644 libgomp/testsuite/libgomp.c/target-25.c create mode 100644 libgomp/testsuite/libgomp.c/target-26.c create mode 100644 libgomp/testsuite/libgomp.c/target-27.c create mode 100644 libgomp/testsuite/libgomp.c/taskloop-1.c create mode 100644 libgomp/testsuite/libgomp.c/taskloop-2.c create mode 100644 libgomp/testsuite/libgomp.c/taskloop-3.c create mode 100644 libgomp/testsuite/libgomp.c/taskloop-4.c create mode 100644 libgomp/testsuite/libgomp.fortran/affinity1.f90 create mode 100644 libgomp/testsuite/libgomp.fortran/affinity2.f90 diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 47119471d84..750c73aad08 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,378 @@ +2015-10-13 Jakub Jelinek + Aldy Hernandez + Ilya Verbin + + * builtin-types.def (BT_FN_BOOL_UINT_LONGPTR_LONGPTR_LONGPTR, + BT_FN_BOOL_UINT_ULLPTR_ULLPTR_ULLPTR, + BT_FN_BOOL_UINT_LONGPTR_LONG_LONGPTR_LONGPTR, + BT_FN_BOOL_UINT_ULLPTR_ULL_ULLPTR_ULLPTR, + BT_FN_VOID_INT_SIZE_PTR_PTR_PTR_UINT_PTR, + BT_FN_VOID_INT_OMPFN_SIZE_PTR_PTR_PTR_UINT_PTR, + BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR_INT, + BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_UINT_LONG_INT_LONG_LONG_LONG, + BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_UINT_LONG_INT_ULL_ULL_ULL, + BT_FN_VOID_LONG_VAR, BT_FN_VOID_ULL_VAR): New. + (BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR, + BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR, + BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR): Remove. + * cgraph.h (enum cgraph_simd_clone_arg_type): Add + SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP, + SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP and + SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP. + (struct cgraph_simd_clone_arg): Adjust comment. + * coretypes.h (struct gomp_ordered): New forward decl. + * gimple.c (gimple_build_omp_critical): Add CLAUSES argument, + set critical clauses to it. + (gimple_build_omp_ordered): Return gomp_ordered * instead of + gimple *. Add CLAUSES argument, set ordered clauses to it. + (gimple_copy): Unshare clauses on GIMPLE_OMP_CRITICAL and + GIMPLE_OMP_ORDERED. + * gimple.def (GIMPLE_OMP_ORDERED): Change from GSS_OMP to + GSS_OMP_SINGLE_LAYOUT, move it after GIMPLE_OMP_TEAMS. + * gimple.h (enum gf_mask): Add GF_OMP_TASK_TASKLOOP. Add another bit + to GF_OMP_FOR_KIND_MASK mask. Add GF_OMP_FOR_KIND_TASKLOOP, renumber + GF_OMP_FOR_KIND_CILKFOR and GF_OMP_FOR_KIND_OACC_LOOP. Adjust + GF_OMP_FOR_SIMD, GF_OMP_FOR_COMBINED and GF_OMP_FOR_COMBINED_INTO. + Add another bit to GF_OMP_TARGET_KIND_MASK mask. Add + GF_OMP_TARGET_KIND_ENTER_DATA and GF_OMP_TARGET_KIND_EXIT_DATA, + renumber + GF_OMP_TARGET_KIND_OACC_{PARALLEL,KERNELS,DATA,UPDATE,ENTER_EXIT_DATA}. + (gomp_critical): Add clauses field. + (gomp_ordered): New struct. + (is_a_helper ::test): New inline. + (gimple_build_omp_critical): Add CLAUSES argument. + (gimple_build_omp_ordered): Likewise. Return gomp_ordered * + instead of gimple *. + (gimple_omp_critical_clauses, gimple_omp_critical_clauses_ptr, + gimple_omp_critical_set_clauses, gimple_omp_ordered_clauses, + gimple_omp_ordered_clauses_ptr, gimple_omp_ordered_set_clauses, + gimple_omp_task_taskloop_p, gimple_omp_task_set_taskloop_p): New + inline functions. + * gimple-pretty-print.c (dump_gimple_omp_for): Handle taskloop. + (dump_gimple_omp_target): Handle enter data and exit data. + (dump_gimple_omp_block): Don't handle GIMPLE_OMP_ORDERED here. + (dump_gimple_omp_critical): Print clauses. + (dump_gimple_omp_ordered): New function. + (dump_gimple_omp_task): Handle taskloop. + (pp_gimple_stmt_1): Use dump_gimple_omp_ordered for + GIMPLE_OMP_ORDERED. + * gimple-walk.c (walk_gimple_op): Walk clauses on + GIMPLE_OMP_CRITICAL and GIMPLE_OMP_ORDERED. + * gimplify.c (enum gimplify_omp_var_data): Add GOVD_MAP_0LEN_ARRAY. + (enum omp_region_type): Add ORT_COMBINED_TARGET and ORT_NONE. + (struct gimplify_omp_ctx): Add loop_iter_var, + target_map_scalars_firstprivate, target_map_pointers_as_0len_arrays + and target_firstprivatize_array_bases fields. + (delete_omp_context): Release loop_iter_var. + (gimplify_bind_expr): Handle ORT_NONE. + (maybe_fold_stmt): Adjust check for ORT_TARGET for the addition of + ORT_COMBINED_TARGET. + (is_gimple_stmt): Return true for OMP_TASKLOOP, OMP_TEAMS and + OMP_TARGET{,_DATA,_UPDATE,_ENTER_DATA,_EXIT_DATA}. + (omp_firstprivatize_variable): Handle ORT_NONE. Adjust check for + ORT_TARGET for the addition of ORT_COMBINED_TARGET. Handle + ctx->target_map_scalars_firstprivate. + (omp_add_variable): Handle ORT_NONE. Allow map clause together with + data sharing clauses. For data sharing clause with VLA decl + on omp target/target data don't add firstprivate for the pointer. + Call omp_notice_variable on TYPE_SIZE_UNIT only if it is a DECL_P. + (omp_notice_threadprivate_variable): Adjust check for ORT_TARGET for + the addition of ORT_COMBINED_TARGET. + (omp_notice_variable): Handle ORT_NONE. Adjust check for ORT_TARGET + for the addition of ORT_COMBINED_TARGET. Handle implicit mapping of + pointers as zero length array sections and + ctx->target_map_scalars_firstprivate mapping of scalars as firstprivate + data sharing. + (omp_check_private): Handle omp_member_access_dummy_var vars. + (find_decl_expr): New function. + (gimplify_scan_omp_clauses): Add CODE argument. For OMP_CLAUSE_IF + complain if OMP_CLAUSE_IF_MODIFIER is present and does not match code. + Handle OMP_CLAUSE_GANG separately. Handle + OMP_CLAUSE_{PRIORITY,GRAINSIZE,NUM_TASKS,NOGROUP,THREADS,SIMD,SIMDLEN} + clauses. Diagnose linear clause on combined + distribute {, parallel for} simd construct, unless it is the loop + iterator. Handle struct element GOMP_MAP_FIRSTPRIVATE_POINTER. + Handle map clauses with COMPONENT_REF. Initialize + ctx->target_map_scalars_firstprivate, + ctx->target_firstprivatize_array_bases and + ctx->target_map_pointers_as_0len_arrays. Add firstprivate for + linear clause even to target region if combined. Remove + map clauses with GOMP_MAP_FIRSTPRIVATE_POINTER kind from + OMP_TARGET_{,ENTER_,EXIT_}DATA. For GOMP_MAP_FIRSTPRIVATE_POINTER + map kind with non-INTEGER_CST OMP_CLAUSE_SIZE firstprivatize the bias. + Handle OMP_CLAUSE_DEPEND_{SINK,SOURCE}. Handle + OMP_CLAUSE_{{USE,IS}_DEVICE_PTR,DEFAULTMAP,HINT}. + For linear clause on worksharing loop combined with parallel add + shared clause on the parallel. Handle OMP_CLAUSE_REDUCTION + with MEM_REF OMP_CLAUSE_DECL. Set DECL_NAME on + omp_member_access_dummy_var vars. Add lastprivate clause to outer + taskloop if needed. + (gimplify_adjust_omp_clauses_1): Handle GOVD_MAP_0LEN_ARRAY. + If gimplify_omp_ctxp->target_firstprivatize_array_bases, use + GOMP_MAP_FIRSTPRIVATE_POINTER map kind instead of + GOMP_MAP_POINTER. + (gimplify_adjust_omp_clauses): Add CODE argument. Handle removal + of GOMP_MAP_FIRSTPRIVATE_POINTER struct elements for struct not seen + in target body. Handle removal of struct mapping if struct is not + seen in target body. Remove GOMP_MAP_STRUCT map clause on + OMP_TARGET_EXIT_DATA. Adjust check for ORT_TARGET for the + addition of ORT_COMBINED_TARGET. Use GOMP_MAP_FIRSTPRIVATE_POINTER + instead of GOMP_MAP_POINTER if ctx->target_firstprivatize_array_bases + for VLAs. Set OMP_CLAUSE_MAP_PRIVATE if both data sharing and map + clause appear together. Handle + OMP_CLAUSE_{{USE,IS}_DEVICE_PTR,DEFAULTMAP,HINT}. Don't remove map + clause if it has map-type-modifier always. Handle + OMP_CLAUSE_{PRIORITY,GRAINSIZE,NUM_TASKS,NOGROUP,THREADS,SIMD,SIMDLEN} + clauses. + (gimplify_oacc_cache, gimplify_omp_parallel, gimplify_omp_task): + Adjust gimplify_scan_omp_clauses and gimplify_adjust_omp_clauses + callers. + (gimplify_omp_for): Likewise. Handle OMP_TASKLOOP. Initialize + loop_iter_var. Use OMP_FOR_ORIG_DECLS. Fix handling of lastprivate + iterators in doacross loops. + (gimplify_omp_workshare): Adjust gimplify_scan_omp_clauses and + gimplify_adjust_omp_clauses callers. Use ORT_COMBINED_TARGET + for OMP_TARGET_COMBINED. Adjust check for ORT_TARGET + for the addition of ORT_COMBINED_TARGET. + (gimplify_omp_target_update): Adjust gimplify_scan_omp_clauses and + gimplify_adjust_omp_clauses callers. Handle OMP_TARGET_ENTER_DATA + and OMP_TARGET_EXIT_DATA. + (gimplify_omp_ordered): New function. + (gimplify_expr): Handle OMP_TASKLOOP, OMP_TARGET_ENTER_DATA and + OMP_TARGET_EXIT_DATA. Use gimplify_omp_ordered for OMP_ORDERED. + Gimplify clauses on OMP_CRITICAL. + * internal-fn.c (expand_GOMP_SIMD_ORDERED_START, + expand_GOMP_SIMD_ORDERED_END): New functions. + * internal-fn.def (GOMP_SIMD_ORDERED_START, + GOMP_SIMD_ORDERED_END): New internal functions. + * omp-builtins.def (BUILT_IN_GOMP_LOOP_DOACROSS_STATIC_START, + BUILT_IN_GOMP_LOOP_DOACROSS_DYNAMIC_START, + BUILT_IN_GOMP_LOOP_DOACROSS_GUIDED_START, + BUILT_IN_GOMP_LOOP_DOACROSS_RUNTIME_START, + BUILT_IN_GOMP_LOOP_ULL_DOACROSS_STATIC_START, + BUILT_IN_GOMP_LOOP_ULL_DOACROSS_DYNAMIC_START, + BUILT_IN_GOMP_LOOP_ULL_DOACROSS_GUIDED_START, + BUILT_IN_GOMP_LOOP_ULL_DOACROSS_RUNTIME_START, + BUILT_IN_GOMP_DOACROSS_POST, BUILT_IN_GOMP_DOACROSS_WAIT, + BUILT_IN_GOMP_DOACROSS_ULL_POST, BUILT_IN_GOMP_DOACROSS_ULL_WAIT, + BUILT_IN_GOMP_TARGET_ENTER_EXIT_DATA, BUILT_IN_GOMP_TASKLOOP, + BUILT_IN_GOMP_TASKLOOP_ULL): New built-ins. + (BUILT_IN_GOMP_TASK): Add INT argument to the end. + (BUILT_IN_GOMP_TARGET): Rename from GOMP_target to GOMP_target_41, + adjust type. + (BUILT_IN_GOMP_TARGET_DATA): Rename from GOMP_target_data to + GOMP_target_data_41, adjust type. + (BUILT_IN_GOMP_TARGET_UPDATE): Rename from GOMP_target_update to + GOMP_target_update_41, adjust type. + * omp-low.c (struct omp_region): Adjust comments, add ord_stmt + field. + (struct omp_for_data): Add ordered and simd_schedule fields. + (omp_member_access_dummy_var, unshare_and_remap_1, + unshare_and_remap, is_taskloop_ctx): New functions. + (is_taskreg_ctx): Use is_parallel_ctx and is_task_ctx. + (extract_omp_for_data): Handle taskloops and doacross loops + and simd schedule modifier. + (omp_adjust_chunk_size): New function. + (get_ws_args_for): Use it. + (lookup_sfield): Change first argument to splay_tree_key, + add overload with first argument tree. + (maybe_lookup_field): Likewise. + (use_pointer_for_field): Handle omp_member_access_dummy_var. + (omp_copy_decl_2): If var is TREE_ADDRESSABLE listed in + task_shared_vars, clear TREE_ADDRESSABLE on the copy. + (build_outer_var_ref): Add LASTPRIVATE argument, handle + taskloops and omp_member_access_dummy_var vars. + (build_sender_ref): Change first argument to splay_tree_key, + add overload with first argument tree. + (install_var_field): For mask & 8 use &DECL_UID as key instead + of the tree itself. + (fixup_child_record_type): Const qualify *.omp_data_i. + (scan_sharing_clauses): Handle OMP_CLAUSE_SHARED_FIRSTPRIVATE, + C/C++ array reductions, OMP_CLAUSE_{IS,USE}_DEVICE_PTR clauses, + OMP_CLAUSE_{PRIORITY,GRAINSIZE,NUM_TASKS,SIMDLEN,THREADS,SIMD} and + OMP_CLAUSE_{NOGROUP,DEFAULTMAP} clauses, OMP_CLAUSE__LOOPTEMP_ clause + on taskloop, GOMP_MAP_FIRSTPRIVATE_POINTER, OMP_CLAUSE_MAP_PRIVATE. + (create_omp_child_function): Set TREE_READONLY on .omp_data_i. + (find_combined_for): Allow searching for different GIMPLE_OMP_FOR + kinds. + (add_taskreg_looptemp_clauses): New function. + (scan_omp_parallel): Use it. + (scan_omp_task): Likewise. + (finish_taskreg_scan): Handle OMP_CLAUSE_SHARED_FIRSTPRIVATE. + For taskloop, move fields for the first two _LOOPTEMP_ clauses first. + (check_omp_nesting_restrictions): Handle GF_OMP_TARGET_KIND_ENTER_DATA + and GF_OMP_TARGET_KIND_EXIT_DATA. Formatting fixes. Allow the + sandwiched taskloop constructs. Type check + OMP_CLAUSE_DEPEND_{KIND,SOURCE}. Allow ordered simd inside of simd + region. Diagnose depend(source) or depend(sink:...) on + target constructs or task/taskloop. + (handle_simd_reference): Use get_name. + (lower_rec_input_clauses): Likewise. Ignore all + OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE clauses on taskloop construct. + Allow _LOOPTEMP_ clause on GOMP_TASK. Unshare new_var + before passing it to omp_clause_{default,copy}_ctor. Handle + OMP_CLAUSE_REDUCTION with MEM_REF OMP_CLAUSE_DECL. Set + lastprivate_firstprivate flag for linear that needs copyin and + copyout. Use BUILT_IN_ALLOCA_WITH_ALIGN instead of BUILT_IN_ALLOCA. + (lower_lastprivate_clauses): For OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE + on taskloop lookup decl in outer context. Pass true to + build_outer_var_ref lastprivate argument. Handle + OMP_CLAUSE_LASTPRIVATE_TASKLOOP_IV lastprivate if the decl is global + outside of outer taskloop for. + (lower_reduction_clauses): Handle OMP_CLAUSE_REDUCTION with MEM_REF + OMP_CLAUSE_DECL. + (lower_send_clauses): Ignore first two _LOOPTEMP_ clauses in taskloop + GOMP_TASK. Handle OMP_CLAUSE_SHARED_FIRSTPRIVATE. Handle + omp_member_access_dummy_var vars. Handle OMP_CLAUSE_REDUCTION + with MEM_REF OMP_CLAUSE_DECL. Use new lookup_sfield overload. + (lower_send_shared_vars): Ignore fields with NULL or FIELD_DECL + abstract origin. Handle omp_member_access_dummy_var vars. + (expand_parallel_call): Use expand_omp_build_assign. + (expand_task_call): Handle taskloop construct expansion. Add + REGION argument. Use GOMP_TASK_* defines instead of hardcoded + integers. Add priority argument to GOMP_task* calls. Or in + GOMP_TASK_FLAG_PRIORITY into flags if priority is present for + GOMP_task call. + (expand_omp_build_assign): Add prototype. Add AFTER + argument, if true emit statements after *GSI_P and continue linking. + (expand_omp_taskreg): Adjust expand_task_call caller. + (expand_omp_for_init_counts): Rename zero_iter_bb argument to + zero_iter1_bb and first_zero_iter to first_zero_iter1, add + zero_iter2_bb and first_zero_iter2 arguments, handle computation + of counts even for ordered loops. + (expand_omp_for_init_vars): Handle GOMP_TASK inner_stmt. + (expand_omp_ordered_source, expand_omp_ordered_sink, + expand_omp_ordered_source_sink, expand_omp_for_ordered_loops): New + functions. + (expand_omp_for_generic): Use omp_adjust_chunk_size. Handle linear + clauses on worksharing loop. Handle DOACROSS loop expansion. + (expand_omp_for_static_nochunk): Handle linear clauses on + worksharing loop. Adjust expand_omp_for_init_counts + callers. + (expand_omp_for_static_chunk): Likewise. Use omp_adjust_chunk_size. + (expand_omp_simd): Handle addressable fd->loop.v. Adjust + expand_omp_for_init_counts callers. + (expand_omp_taskloop_for_outer, expand_omp_taskloop_for_inner): New + functions. + (expand_omp_for): Call expand_omp_taskloop_for_* for taskloop. + Handle doacross loops. + (expand_omp_target): Handle GF_OMP_TARGET_KIND_ENTER_DATA and + GF_OMP_TARGET_KIND_EXIT_DATA. Pass flags and depend arguments to + GOMP_target_{41,update_41,enter_exit_data} libcalls. + (expand_omp): Don't expand ordered depend constructs here, record + ord_stmt instead for later expand_omp_for_generic. + (build_omp_regions_1): Handle GF_OMP_TARGET_KIND_ENTER_DATA and + GF_OMP_TARGET_KIND_EXIT_DATA. Treat GIMPLE_OMP_ORDERED with depend + clause as stand-alone directive. + (lower_omp_ordered_clauses): New function. + (lower_omp_ordered): Handle OMP_CLAUSE_SIMD, for OMP_CLAUSE_DEPEND + don't lower anything. + (lower_omp_for_lastprivate): Use last _looptemp_ clause + on taskloop for comparison. + (lower_omp_for): Handle taskloop constructs. Adjust OMP_CLAUSE_DECL + and OMP_CLAUSE_LINEAR_STEP so that expand_omp_for_* can use it during + expansion for linear adjustments. + (create_task_copyfn): Handle OMP_CLAUSE_SHARED_FIRSTPRIVATE. + (lower_depend_clauses): Assert not seeing sink/source depend kinds. + Set TREE_ADDRESSABLE on array. Change first argument from gimple * + to tree * pointing to the stmt's clauses. + (lower_omp_taskreg): Adjust lower_depend_clauses caller. + (lower_omp_target): Handle GF_OMP_TARGET_KIND_ENTER_DATA + and GF_OMP_TARGET_KIND_EXIT_DATA, depend clauses, + GOMP_MAP_{RELEASE,ALWAYS_{TO,FROM,TOFROM},FIRSTPRIVATE_POINTER,STRUCT} + map kinds, OMP_CLAUSE_{FIRSTPRIVATE,PRIVATE,{IS,USE}_DEVICE_PTR + clauses. Always use short kind and 8-bit align shift. + (lower_omp_regimplify_p): Use IS_TYPE_OR_DECL_P macro. + (struct lower_omp_regimplify_operands_data): New type. + (lower_omp_regimplify_operands_p, lower_omp_regimplify_operands): + New functions. + (lower_omp_1): Use lower_omp_regimplify_operands instead of + gimple_regimplify_operands. + (make_gimple_omp_edges): Handle GF_OMP_TARGET_KIND_ENTER_DATA and + GF_OMP_TARGET_KIND_EXIT_DATA. Treat GIMPLE_OMP_ORDERED with depend + clause as stand-alone directive. + (simd_clone_clauses_extract): Honor OMP_CLAUSE_LINEAR_KIND. + (simd_clone_mangle): Mangle the various linear kinds + per the new ABI. + (simd_clone_adjust_argument_types): Handle + SIMD_CLONE_ARG_TYPE_LINEAR_*_CONSTANT_STEP. + (simd_clone_init_simd_arrays): Don't do anything for uval. + (simd_clone_adjust): Handle + SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP like + SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP. + Handle SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP. + * omp-low.h (omp_member_access_dummy_var): New prototype. + * passes.def (pass_simduid_cleanup): Schedule another copy of the + pass after all optimizations. + * tree.c (omp_clause_code_name): Add entries for + OMP_CLAUSE_{TO_DECLARE,LINK,{USE,IS}_DEVICE_PTR,DEFAULTMAP,HINT} + and OMP_CLAUSE_{PRIORITY,GRAINSIZE,NUM_TASKS,NOGROUP,THREADS,SIMD}. + (omp_clause_num_ops): Likewise. Bump number of OMP_CLAUSE_REDUCTION + arguments to 5 and for OMP_CLAUSE_ORDERED to 1. + (walk_tree_1): Adjust for OMP_CLAUSE_ORDERED having 1 argument and + OMP_CLAUSE_REDUCTION 5 arguments. Handle + OMP_CLAUSE_{TO_DECLARE,LINK,{USE,IS}_DEVICE_PTR,DEFAULTMAP,HINT} + and OMP_CLAUSE_{PRIORITY,GRAINSIZE,NUM_TASKS,NOGROUP,THREADS,SIMD} + clauses. + * tree-core.h (enum omp_clause_linear_kind): New. + (struct tree_omp_clause): Change type of map_kind + from unsigned char to unsigned int. Add subcode.if_modifier + and subcode.linear_kind fields. + (enum omp_clause_code): Add + OMP_CLAUSE_{TO_DECLARE,LINK,{USE,IS}_DEVICE_PTR,DEFAULTMAP,HINT} + and OMP_CLAUSE_{PRIORITY,GRAINSIZE,NUM_TASKS,NOGROUP,THREADS,SIMD}. + (OMP_CLAUSE_REDUCTION): Document + OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER. + (enum omp_clause_depend_kind): Add OMP_CLAUSE_DEPEND_{SOURCE,SINK}. + * tree.def (OMP_FOR): Add OMP_FOR_ORIG_DECLS operand. + (OMP_CRITICAL): Move before OMP_SINGLE. Add OMP_CRITICAL_CLAUSES + operand. + (OMP_ORDERED): Move before OMP_SINGLE. Add OMP_ORDERED_CLAUSES + operand. + (OMP_TASKLOOP, OMP_TARGET_ENTER_DATA, OMP_TARGET_EXIT_DATA): New tree + codes. + * tree.h (OMP_BODY): Replace OMP_CRITICAL with OMP_TASKGROUP. + (OMP_CLAUSE_SET_MAP_KIND): Cast to unsigned int rather than unsigned + char. + (OMP_CRITICAL_NAME): Adjust to be 3rd operand instead of 2nd. + (OMP_CLAUSE_NUM_TASKS_EXPR): Formatting fix. + (OMP_STANDALONE_CLAUSES): Adjust to cover OMP_TARGET_{ENTER,EXIT}_DATA. + (OMP_CLAUSE_DEPEND_SINK_NEGATIVE, OMP_TARGET_COMBINED, + OMP_CLAUSE_MAP_PRIVATE, OMP_FOR_ORIG_DECLS, OMP_CLAUSE_IF_MODIFIER, + OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION, OMP_CRITICAL_CLAUSES, + OMP_CLAUSE_PRIVATE_TASKLOOP_IV, OMP_CLAUSE_LASTPRIVATE_TASKLOOP_IV, + OMP_CLAUSE_HINT_EXPR, OMP_CLAUSE_SCHEDULE_SIMD, + OMP_CLAUSE_LINEAR_KIND, OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER, + OMP_CLAUSE_SHARED_FIRSTPRIVATE, OMP_ORDERED_CLAUSES, + OMP_TARGET_ENTER_DATA_CLAUSES, OMP_TARGET_EXIT_DATA_CLAUSES, + OMP_CLAUSE_NUM_TASKS_EXPR, OMP_CLAUSE_GRAINSIZE_EXPR, + OMP_CLAUSE_PRIORITY_EXPR, OMP_CLAUSE_ORDERED_EXPR): Define. + * tree-inline.c (remap_gimple_stmt): Handle clauses on + GIMPLE_OMP_ORDERED and GIMPLE_OMP_CRITICAL. For + IFN_GOMP_SIMD_ORDERED_{START,END} set has_simduid_loops. + * tree-nested.c (convert_nonlocal_omp_clauses): Handle + OMP_CLAUSE_{TO_DECLARE,LINK,{USE,IS}_DEVICE_PTR,SIMDLEN,PRIORITY,SIMD} + and OMP_CLAUSE_{GRAINSIZE,NUM_TASKS,HINT,NOGROUP,THREADS,DEFAULTMAP} + clauses. Handle OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER. + (convert_local_omp_clauses): Likewise. + * tree-pretty-print.c (dump_omp_clause): Handle + OMP_CLAUSE_{TO_DECLARE,LINK,{USE,IS}_DEVICE_PTR,SIMDLEN,PRIORITY,SIMD} + and OMP_CLAUSE_{GRAINSIZE,NUM_TASKS,HINT,NOGROUP,THREADS,DEFAULTMAP} + clauses. Handle OMP_CLAUSE_IF_MODIFIER, OMP_CLAUSE_ORDERED_EXPR, + OMP_CLAUSE_SCHEDULE_SIMD, OMP_CLAUSE_LINEAR_KIND, + OMP_CLAUSE_DEPEND_{SOURCE,SINK}. Use "delete" for + GOMP_MAP_FORCE_DEALLOC. Handle + GOMP_MAP_{ALWAYS_{TO,FROM,TOFROM},RELEASE,FIRSTPRIVATE_POINTER,STRUCT}. + (dump_generic_node): Handle OMP_TASKLOOP, OMP_TARGET_{ENTER,EXIT}_DATA + and clauses on OMP_ORDERED and OMP_CRITICAL. + * tree-vectorizer.c (adjust_simduid_builtins): Adjust comment. + Remove IFN_GOMP_SIMD_ORDERED_{START,END}. + (vectorize_loops): Adjust comments. + (pass_simduid_cleanup::execute): Likewise. + * tree-vect-stmts.c (vectorizable_simd_clone_call): Handle + SIMD_CLONE_ARG_TYPE_LINEAR_{REF,VAL,UVAL}_CONSTANT_STEP. + * wide-int.h (wi::gcd): New. + 2015-10-13 Uros Bizjak * config/i386/i386.c (classify_argument): Use CEIL where applicable. diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 137cdfe782f..9effe45f230 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,8 @@ +2015-10-13 Jakub Jelinek + + * gcc-interface/utils.c (DEF_FUNCTION_TYPE_9, DEF_FUNCTION_TYPE_10, + DEF_FUNCTION_TYPE_11): Define. + 2015-10-09 Eric Botcazou * gcc-interface/Make-lang.in: Make sure that GNAT1_OBJS and not just diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c index 0f3087d3dbf..917c2803f0d 100644 --- a/gcc/ada/gcc-interface/utils.c +++ b/gcc/ada/gcc-interface/utils.c @@ -5369,6 +5369,12 @@ enum c_builtin_type ARG6, ARG7) NAME, #define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7, ARG8) NAME, +#define DEF_FUNCTION_TYPE_9(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9) NAME, +#define DEF_FUNCTION_TYPE_10(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9, ARG10) NAME, +#define DEF_FUNCTION_TYPE_11(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) NAME, #define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME, #define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME, #define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME, @@ -5392,6 +5398,9 @@ enum c_builtin_type #undef DEF_FUNCTION_TYPE_6 #undef DEF_FUNCTION_TYPE_7 #undef DEF_FUNCTION_TYPE_8 +#undef DEF_FUNCTION_TYPE_9 +#undef DEF_FUNCTION_TYPE_10 +#undef DEF_FUNCTION_TYPE_11 #undef DEF_FUNCTION_TYPE_VAR_0 #undef DEF_FUNCTION_TYPE_VAR_1 #undef DEF_FUNCTION_TYPE_VAR_2 @@ -5493,6 +5502,18 @@ install_builtin_function_types (void) ARG6, ARG7, ARG8) \ def_fn_type (ENUM, RETURN, 0, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ ARG7, ARG8); +#define DEF_FUNCTION_TYPE_9(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9) \ + def_fn_type (ENUM, RETURN, 0, 9, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ + ARG7, ARG8, ARG9); +#define DEF_FUNCTION_TYPE_10(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5,\ + ARG6, ARG7, ARG8, ARG9, ARG10) \ + def_fn_type (ENUM, RETURN, 0, 10, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ + ARG7, ARG8, ARG9, ARG10); +#define DEF_FUNCTION_TYPE_11(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5,\ + ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) \ + def_fn_type (ENUM, RETURN, 0, 11, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ + ARG7, ARG8, ARG9, ARG10, ARG11); #define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \ def_fn_type (ENUM, RETURN, 1, 0); #define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \ @@ -5526,6 +5547,9 @@ install_builtin_function_types (void) #undef DEF_FUNCTION_TYPE_6 #undef DEF_FUNCTION_TYPE_7 #undef DEF_FUNCTION_TYPE_8 +#undef DEF_FUNCTION_TYPE_9 +#undef DEF_FUNCTION_TYPE_10 +#undef DEF_FUNCTION_TYPE_11 #undef DEF_FUNCTION_TYPE_VAR_0 #undef DEF_FUNCTION_TYPE_VAR_1 #undef DEF_FUNCTION_TYPE_VAR_2 diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def index 9d20dcc3d82..b561436f55c 100644 --- a/gcc/builtin-types.def +++ b/gcc/builtin-types.def @@ -473,6 +473,11 @@ DEF_FUNCTION_TYPE_4 (BT_FN_VOID_SIZE_VPTR_PTR_INT, BT_VOID, BT_SIZE, BT_VOLATILE_PTR, BT_PTR, BT_INT) DEF_FUNCTION_TYPE_4 (BT_FN_VOID_SIZE_CONST_VPTR_PTR_INT, BT_VOID, BT_SIZE, BT_CONST_VOLATILE_PTR, BT_PTR, BT_INT) +DEF_FUNCTION_TYPE_4 (BT_FN_BOOL_UINT_LONGPTR_LONGPTR_LONGPTR, + BT_BOOL, BT_UINT, BT_PTR_LONG, BT_PTR_LONG, BT_PTR_LONG) +DEF_FUNCTION_TYPE_4 (BT_FN_BOOL_UINT_ULLPTR_ULLPTR_ULLPTR, + BT_BOOL, BT_UINT, BT_PTR_ULONGLONG, BT_PTR_ULONGLONG, + BT_PTR_ULONGLONG) DEF_FUNCTION_TYPE_5 (BT_FN_INT_STRING_INT_SIZE_CONST_STRING_VALIST_ARG, BT_INT, BT_STRING, BT_INT, BT_SIZE, BT_CONST_STRING, @@ -497,6 +502,12 @@ DEF_FUNCTION_TYPE_5 (BT_FN_VOID_INT_SIZE_PTR_PTR_PTR, DEF_FUNCTION_TYPE_5 (BT_FN_VOID_OMPFN_PTR_UINT_UINT_UINT, BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, BT_UINT, BT_UINT) +DEF_FUNCTION_TYPE_5 (BT_FN_BOOL_UINT_LONGPTR_LONG_LONGPTR_LONGPTR, + BT_BOOL, BT_UINT, BT_PTR_LONG, BT_LONG, BT_PTR_LONG, + BT_PTR_LONG) +DEF_FUNCTION_TYPE_5 (BT_FN_BOOL_UINT_ULLPTR_ULL_ULLPTR_ULLPTR, + BT_BOOL, BT_UINT, BT_PTR_ULONGLONG, BT_ULONGLONG, + BT_PTR_ULONGLONG, BT_PTR_ULONGLONG) DEF_FUNCTION_TYPE_6 (BT_FN_INT_STRING_SIZE_INT_SIZE_CONST_STRING_VALIST_ARG, BT_INT, BT_STRING, BT_SIZE, BT_INT, BT_SIZE, @@ -524,8 +535,6 @@ DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_VPTR_PTR_I16_BOOL_INT_INT, BT_INT) DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_SIZE_VPTR_PTR_PTR_INT_INT, BT_BOOL, BT_SIZE, BT_VOLATILE_PTR, BT_PTR, BT_PTR, BT_INT, BT_INT) -DEF_FUNCTION_TYPE_6 (BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR, - BT_VOID, BT_INT, BT_PTR, BT_SIZE, BT_PTR, BT_PTR, BT_PTR) DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_UINT, BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, @@ -534,17 +543,31 @@ 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_7 (BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR, - BT_VOID, BT_INT, BT_PTR_FN_VOID_PTR, BT_PTR, BT_SIZE, - BT_PTR, BT_PTR, BT_PTR) +DEF_FUNCTION_TYPE_7 (BT_FN_VOID_INT_SIZE_PTR_PTR_PTR_UINT_PTR, + BT_VOID, BT_INT, BT_SIZE, BT_PTR, BT_PTR, BT_PTR, BT_UINT, + BT_PTR) +DEF_FUNCTION_TYPE_8 (BT_FN_VOID_INT_OMPFN_SIZE_PTR_PTR_PTR_UINT_PTR, + BT_VOID, BT_INT, BT_PTR_FN_VOID_PTR, BT_SIZE, BT_PTR, + BT_PTR, BT_PTR, BT_UINT, BT_PTR) DEF_FUNCTION_TYPE_8 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT, BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, BT_LONG, BT_LONG, BT_LONG, BT_LONG, BT_UINT) -DEF_FUNCTION_TYPE_8 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR, + +DEF_FUNCTION_TYPE_9 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR_INT, BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_PTR_FN_VOID_PTR_PTR, BT_LONG, BT_LONG, - BT_BOOL, BT_UINT, BT_PTR) + BT_BOOL, BT_UINT, BT_PTR, BT_INT) + +DEF_FUNCTION_TYPE_11 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_UINT_LONG_INT_LONG_LONG_LONG, + BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, + BT_PTR_FN_VOID_PTR_PTR, BT_LONG, BT_LONG, + BT_UINT, BT_LONG, BT_INT, BT_LONG, BT_LONG, BT_LONG) +DEF_FUNCTION_TYPE_11 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_UINT_LONG_INT_ULL_ULL_ULL, + BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, + BT_PTR_FN_VOID_PTR_PTR, BT_LONG, BT_LONG, + BT_UINT, BT_LONG, BT_INT, + BT_ULONGLONG, BT_ULONGLONG, BT_ULONGLONG) DEF_FUNCTION_TYPE_VAR_0 (BT_FN_VOID_VAR, BT_VOID) DEF_FUNCTION_TYPE_VAR_0 (BT_FN_INT_VAR, BT_INT) @@ -559,6 +582,10 @@ DEF_FUNCTION_TYPE_VAR_1 (BT_FN_INT_CONST_STRING_VAR, BT_INT, BT_CONST_STRING) DEF_FUNCTION_TYPE_VAR_1 (BT_FN_UINT32_UINT32_VAR, BT_UINT32, BT_UINT32) +DEF_FUNCTION_TYPE_VAR_1 (BT_FN_VOID_LONG_VAR, + BT_VOID, BT_LONG) +DEF_FUNCTION_TYPE_VAR_1 (BT_FN_VOID_ULL_VAR, + BT_VOID, BT_ULONGLONG) DEF_FUNCTION_TYPE_VAR_2 (BT_FN_INT_FILEPTR_CONST_STRING_VAR, BT_INT, BT_FILEPTR, BT_CONST_STRING) diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 5af62aa5a34..4521a275b36 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,31 @@ +2015-10-13 Jakub Jelinek + Aldy Hernandez + + * c-common.c (enum c_builtin_type): Define DEF_FUNCTION_TYPE_9, + DEF_FUNCTION_TYPE_10 and DEF_FUNCTION_TYPE_11. + (c_define_builtins): Likewise. + * c-common.h (enum c_omp_clause_split): Add + C_OMP_CLAUSE_SPLIT_TASKLOOP. + (c_finish_omp_critical, c_finish_omp_ordered): Add CLAUSES argument. + (c_finish_omp_for): Add ORIG_DECLV argument. + * c-cppbuiltin.c (c_cpp_builtins): Predefine _OPENMP as + 201511 instead of 201307. + * c-omp.c (c_finish_omp_critical): Add CLAUSES argument, set + OMP_CRITICAL_CLAUSES to it. + (c_finish_omp_ordered): Add CLAUSES argument, set + OMP_ORDERED_CLAUSES to it. + (c_finish_omp_for): Add ORIG_DECLV argument, set OMP_FOR_ORIG_DECLS + to it if OMP_FOR. Clear DECL_INITIAL on the IVs. + (c_omp_split_clauses): Handle OpenMP 4.5 combined/composite + constructs and new OpenMP 4.5 clauses. Clear + OMP_CLAUSE_SCHEDULE_SIMD if not combined with OMP_SIMD. Add + verification code. + * c-pragma.c (omp_pragmas_simd): Add taskloop. + * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_TASKLOOP. + (enum pragma_omp_clause): Add + PRAGMA_OMP_CLAUSE_{DEFAULTMAP,GRAINSIZE,HINT,{IS,USE}_DEVICE_PTR} + and PRAGMA_OMP_CLAUSE_{LINK,NOGROUP,NUM_TASKS,PRIORITY,SIMD,THREADS}. + 2015-10-05 Richard Sandiford * c-lex.c (interpret_float): Use real_equal instead of diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 4b64a448a88..1c75921d542 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -5548,6 +5548,12 @@ enum c_builtin_type ARG6, ARG7) NAME, #define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7, ARG8) NAME, +#define DEF_FUNCTION_TYPE_9(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9) NAME, +#define DEF_FUNCTION_TYPE_10(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9, ARG10) NAME, +#define DEF_FUNCTION_TYPE_11(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) NAME, #define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME, #define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME, #define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME, @@ -5571,6 +5577,9 @@ enum c_builtin_type #undef DEF_FUNCTION_TYPE_6 #undef DEF_FUNCTION_TYPE_7 #undef DEF_FUNCTION_TYPE_8 +#undef DEF_FUNCTION_TYPE_9 +#undef DEF_FUNCTION_TYPE_10 +#undef DEF_FUNCTION_TYPE_11 #undef DEF_FUNCTION_TYPE_VAR_0 #undef DEF_FUNCTION_TYPE_VAR_1 #undef DEF_FUNCTION_TYPE_VAR_2 @@ -5659,6 +5668,18 @@ c_define_builtins (tree va_list_ref_type_node, tree va_list_arg_type_node) ARG6, ARG7, ARG8) \ def_fn_type (ENUM, RETURN, 0, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ ARG7, ARG8); +#define DEF_FUNCTION_TYPE_9(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9) \ + def_fn_type (ENUM, RETURN, 0, 9, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ + ARG7, ARG8, ARG9); +#define DEF_FUNCTION_TYPE_10(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9, ARG10) \ + def_fn_type (ENUM, RETURN, 0, 10, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ + ARG7, ARG8, ARG9, ARG10); +#define DEF_FUNCTION_TYPE_11(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) \ + def_fn_type (ENUM, RETURN, 0, 11, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ + ARG7, ARG8, ARG9, ARG10, ARG11); #define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \ def_fn_type (ENUM, RETURN, 1, 0); #define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \ @@ -5692,6 +5713,9 @@ c_define_builtins (tree va_list_ref_type_node, tree va_list_arg_type_node) #undef DEF_FUNCTION_TYPE_6 #undef DEF_FUNCTION_TYPE_7 #undef DEF_FUNCTION_TYPE_8 +#undef DEF_FUNCTION_TYPE_9 +#undef DEF_FUNCTION_TYPE_10 +#undef DEF_FUNCTION_TYPE_11 #undef DEF_FUNCTION_TYPE_VAR_0 #undef DEF_FUNCTION_TYPE_VAR_1 #undef DEF_FUNCTION_TYPE_VAR_2 diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index d5fb4998268..cf4448230d9 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1252,13 +1252,14 @@ enum c_omp_clause_split C_OMP_CLAUSE_SPLIT_FOR, C_OMP_CLAUSE_SPLIT_SIMD, C_OMP_CLAUSE_SPLIT_COUNT, - C_OMP_CLAUSE_SPLIT_SECTIONS = C_OMP_CLAUSE_SPLIT_FOR + C_OMP_CLAUSE_SPLIT_SECTIONS = C_OMP_CLAUSE_SPLIT_FOR, + C_OMP_CLAUSE_SPLIT_TASKLOOP = C_OMP_CLAUSE_SPLIT_FOR }; extern tree c_finish_omp_master (location_t, tree); extern tree c_finish_omp_taskgroup (location_t, tree); -extern tree c_finish_omp_critical (location_t, tree, tree); -extern tree c_finish_omp_ordered (location_t, tree); +extern tree c_finish_omp_critical (location_t, tree, tree, tree); +extern tree c_finish_omp_ordered (location_t, tree, tree); extern void c_finish_omp_barrier (location_t); extern tree c_finish_omp_atomic (location_t, enum tree_code, enum tree_code, tree, tree, tree, tree, tree, bool, bool); @@ -1266,7 +1267,7 @@ extern void c_finish_omp_flush (location_t); extern void c_finish_omp_taskwait (location_t); extern void c_finish_omp_taskyield (location_t); extern tree c_finish_omp_for (location_t, enum tree_code, tree, tree, tree, - tree, tree, tree); + tree, tree, tree, tree); extern tree c_finish_oacc_wait (location_t, tree, tree); extern void c_omp_split_clauses (location_t, enum tree_code, omp_clause_mask, tree, tree *); diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c index e109e820eea..35d246bb7b1 100644 --- a/gcc/c-family/c-cppbuiltin.c +++ b/gcc/c-family/c-cppbuiltin.c @@ -1223,7 +1223,7 @@ c_cpp_builtins (cpp_reader *pfile) cpp_define (pfile, "_OPENACC=201306"); if (flag_openmp) - cpp_define (pfile, "_OPENMP=201307"); + cpp_define (pfile, "_OPENMP=201511"); for (i = 0; i < NUM_INT_N_ENTS; i ++) if (int_n_enabled_p[i]) diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c index cdd2ee83d76..36f9b6627e5 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -100,12 +100,13 @@ c_finish_omp_taskgroup (location_t loc, tree stmt) if it was omitted. LOC is the location of the #pragma. */ tree -c_finish_omp_critical (location_t loc, tree body, tree name) +c_finish_omp_critical (location_t loc, tree body, tree name, tree clauses) { tree stmt = make_node (OMP_CRITICAL); TREE_TYPE (stmt) = void_type_node; OMP_CRITICAL_BODY (stmt) = body; OMP_CRITICAL_NAME (stmt) = name; + OMP_CRITICAL_CLAUSES (stmt) = clauses; SET_EXPR_LOCATION (stmt, loc); return add_stmt (stmt); } @@ -114,9 +115,12 @@ c_finish_omp_critical (location_t loc, tree body, tree name) that follows the pragma. LOC is the location of the #pragma. */ tree -c_finish_omp_ordered (location_t loc, tree stmt) +c_finish_omp_ordered (location_t loc, tree clauses, tree stmt) { - tree t = build1 (OMP_ORDERED, void_type_node, stmt); + tree t = make_node (OMP_ORDERED); + TREE_TYPE (t) = void_type_node; + OMP_ORDERED_BODY (t) = stmt; + OMP_ORDERED_CLAUSES (t) = clauses; SET_EXPR_LOCATION (t, loc); return add_stmt (t); } @@ -428,6 +432,10 @@ c_omp_for_incr_canonicalize_ptr (location_t loc, tree decl, tree incr) /* Validate and generate OMP_FOR. DECLV is a vector of iteration variables, for each collapsed loop. + + ORIG_DECLV, if non-NULL, is a vector with the original iteration + variables (prior to any transformations, by say, C++ iterators). + 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 @@ -435,7 +443,8 @@ c_omp_for_incr_canonicalize_ptr (location_t loc, tree decl, tree incr) tree c_finish_omp_for (location_t locus, enum tree_code code, tree declv, - tree initv, tree condv, tree incrv, tree body, tree pre_body) + tree orig_declv, tree initv, tree condv, tree incrv, + tree body, tree pre_body) { location_t elocus; bool fail = false; @@ -480,6 +489,7 @@ c_finish_omp_for (location_t locus, enum tree_code code, tree declv, init = integer_zero_node; fail = true; } + DECL_INITIAL (decl) = NULL_TREE; init = build_modify_expr (elocus, decl, NULL_TREE, NOP_EXPR, /* FIXME diagnostics: This should @@ -673,33 +683,42 @@ c_finish_omp_for (location_t locus, enum tree_code code, tree declv, OMP_FOR_INCR (t) = incrv; OMP_FOR_BODY (t) = body; OMP_FOR_PRE_BODY (t) = pre_body; + if (code == OMP_FOR) + OMP_FOR_ORIG_DECLS (t) = orig_declv; SET_EXPR_LOCATION (t, locus); return add_stmt (t); } } -/* Right now we have 14 different combined constructs, this +/* Right now we have 21 different combined/composite constructs, this function attempts to split or duplicate clauses for combined constructs. CODE is the innermost construct in the combined construct, and MASK allows to determine which constructs are combined together, as every construct has at least one clause that no other construct has (except for OMP_SECTIONS, but that can be only combined with parallel). - Combined constructs are: - #pragma omp parallel for - #pragma omp parallel sections - #pragma omp parallel for simd - #pragma omp for simd - #pragma omp distribute simd + Combined/composite constructs are: #pragma omp distribute parallel for #pragma omp distribute parallel for simd - #pragma omp teams distribute - #pragma omp teams distribute parallel for - #pragma omp teams distribute parallel for simd + #pragma omp distribute simd + #pragma omp for simd + #pragma omp parallel for + #pragma omp parallel for simd + #pragma omp parallel sections + #pragma omp target parallel + #pragma omp target parallel for + #pragma omp target parallel for simd #pragma omp target teams #pragma omp target teams distribute #pragma omp target teams distribute parallel for - #pragma omp target teams distribute parallel for simd */ + #pragma omp target teams distribute parallel for simd + #pragma omp target teams distribute simd + #pragma omp target simd + #pragma omp taskloop simd + #pragma omp teams distribute + #pragma omp teams distribute parallel for + #pragma omp teams distribute parallel for simd + #pragma omp teams distribute simd */ void c_omp_split_clauses (location_t loc, enum tree_code code, @@ -738,6 +757,8 @@ c_omp_split_clauses (location_t loc, enum tree_code code, /* First the clauses that are unique to some constructs. */ case OMP_CLAUSE_DEVICE: case OMP_CLAUSE_MAP: + case OMP_CLAUSE_IS_DEVICE_PTR: + case OMP_CLAUSE_DEFAULTMAP: s = C_OMP_CLAUSE_SPLIT_TARGET; break; case OMP_CLAUSE_NUM_TEAMS: @@ -753,25 +774,51 @@ c_omp_split_clauses (location_t loc, enum tree_code code, s = C_OMP_CLAUSE_SPLIT_PARALLEL; break; case OMP_CLAUSE_ORDERED: - case OMP_CLAUSE_SCHEDULE: case OMP_CLAUSE_NOWAIT: s = C_OMP_CLAUSE_SPLIT_FOR; break; + case OMP_CLAUSE_SCHEDULE: + s = C_OMP_CLAUSE_SPLIT_FOR; + if (code != OMP_SIMD) + OMP_CLAUSE_SCHEDULE_SIMD (clauses) = 0; + break; case OMP_CLAUSE_SAFELEN: - case OMP_CLAUSE_LINEAR: + case OMP_CLAUSE_SIMDLEN: case OMP_CLAUSE_ALIGNED: s = C_OMP_CLAUSE_SPLIT_SIMD; break; - /* Duplicate this to all of distribute, for and simd. */ + case OMP_CLAUSE_GRAINSIZE: + case OMP_CLAUSE_NUM_TASKS: + case OMP_CLAUSE_FINAL: + case OMP_CLAUSE_UNTIED: + case OMP_CLAUSE_MERGEABLE: + case OMP_CLAUSE_NOGROUP: + case OMP_CLAUSE_PRIORITY: + s = C_OMP_CLAUSE_SPLIT_TASKLOOP; + break; + /* Duplicate this to all of taskloop, distribute, for and simd. */ case OMP_CLAUSE_COLLAPSE: if (code == OMP_SIMD) { - c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses), - OMP_CLAUSE_COLLAPSE); - OMP_CLAUSE_COLLAPSE_EXPR (c) - = OMP_CLAUSE_COLLAPSE_EXPR (clauses); - OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_SIMD]; - cclauses[C_OMP_CLAUSE_SPLIT_SIMD] = c; + if ((mask & ((OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE) + | (OMP_CLAUSE_MASK_1 + << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE) + | (OMP_CLAUSE_MASK_1 + << PRAGMA_OMP_CLAUSE_NOGROUP))) != 0) + { + c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses), + OMP_CLAUSE_COLLAPSE); + OMP_CLAUSE_COLLAPSE_EXPR (c) + = OMP_CLAUSE_COLLAPSE_EXPR (clauses); + OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_SIMD]; + cclauses[C_OMP_CLAUSE_SPLIT_SIMD] = c; + } + else + { + /* This must be #pragma omp target simd */ + s = C_OMP_CLAUSE_SPLIT_SIMD; + break; + } } if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE)) != 0) { @@ -789,10 +836,13 @@ c_omp_split_clauses (location_t loc, enum tree_code code, else s = C_OMP_CLAUSE_SPLIT_FOR; } + else if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOGROUP)) + != 0) + s = C_OMP_CLAUSE_SPLIT_TASKLOOP; else s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE; break; - /* Private clause is supported on all constructs but target, + /* Private clause is supported on all constructs, it is enough to put it on the innermost one. For #pragma omp {for,sections} put it on parallel though, as that's what we did for OpenMP 3.1. */ @@ -808,9 +858,28 @@ c_omp_split_clauses (location_t loc, enum tree_code code, } break; /* Firstprivate clause is supported on all constructs but - target and simd. Put it on the outermost of those and - duplicate on parallel. */ + simd. Put it on the outermost of those and duplicate on teams + and parallel. */ case OMP_CLAUSE_FIRSTPRIVATE: + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)) + != 0) + { + if (code == OMP_SIMD + && (mask & ((OMP_CLAUSE_MASK_1 + << PRAGMA_OMP_CLAUSE_NUM_THREADS) + | (OMP_CLAUSE_MASK_1 + << PRAGMA_OMP_CLAUSE_NUM_TEAMS))) == 0) + { + /* This must be #pragma omp target simd. */ + s = C_OMP_CLAUSE_SPLIT_TARGET; + break; + } + c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses), + OMP_CLAUSE_FIRSTPRIVATE); + OMP_CLAUSE_DECL (c) = OMP_CLAUSE_DECL (clauses); + OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET]; + cclauses[C_OMP_CLAUSE_SPLIT_TARGET] = c; + } if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)) != 0) { @@ -831,7 +900,9 @@ c_omp_split_clauses (location_t loc, enum tree_code code, } else /* This must be - #pragma omp parallel{, for{, simd}, sections}. */ + #pragma omp parallel{, for{, simd}, sections} + or + #pragma omp target parallel. */ s = C_OMP_CLAUSE_SPLIT_PARALLEL; } else if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS)) @@ -851,7 +922,14 @@ c_omp_split_clauses (location_t loc, enum tree_code code, { /* This must be #pragma omp distribute simd. */ gcc_assert (code == OMP_SIMD); - s = C_OMP_CLAUSE_SPLIT_TEAMS; + s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE; + } + else if ((mask & (OMP_CLAUSE_MASK_1 + << PRAGMA_OMP_CLAUSE_NOGROUP)) != 0) + { + /* This must be #pragma omp taskloop simd. */ + gcc_assert (code == OMP_SIMD); + s = C_OMP_CLAUSE_SPLIT_TASKLOOP; } else { @@ -889,17 +967,25 @@ c_omp_split_clauses (location_t loc, enum tree_code code, } s = C_OMP_CLAUSE_SPLIT_SIMD; break; - /* Shared and default clauses are allowed on private and teams. */ + /* Shared and default clauses are allowed on parallel, teams and + taskloop. */ case OMP_CLAUSE_SHARED: case OMP_CLAUSE_DEFAULT: - if (code == OMP_TEAMS) + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOGROUP)) + != 0) { - s = C_OMP_CLAUSE_SPLIT_TEAMS; + s = C_OMP_CLAUSE_SPLIT_TASKLOOP; break; } if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS)) != 0) { + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)) + == 0) + { + s = C_OMP_CLAUSE_SPLIT_TEAMS; + break; + } c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses), OMP_CLAUSE_CODE (clauses)); if (OMP_CLAUSE_CODE (clauses) == OMP_CLAUSE_SHARED) @@ -909,7 +995,6 @@ c_omp_split_clauses (location_t loc, enum tree_code code, = OMP_CLAUSE_DEFAULT_KIND (clauses); OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; cclauses[C_OMP_CLAUSE_SPLIT_TEAMS] = c; - } s = C_OMP_CLAUSE_SPLIT_PARALLEL; break; @@ -917,20 +1002,22 @@ c_omp_split_clauses (location_t loc, enum tree_code code, Duplicate it on all of them, but omit on for or sections if parallel is present. */ case OMP_CLAUSE_REDUCTION: - if (code == OMP_SIMD) - { - c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses), - OMP_CLAUSE_REDUCTION); - OMP_CLAUSE_DECL (c) = OMP_CLAUSE_DECL (clauses); - OMP_CLAUSE_REDUCTION_CODE (c) - = OMP_CLAUSE_REDUCTION_CODE (clauses); - OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) - = OMP_CLAUSE_REDUCTION_PLACEHOLDER (clauses); - OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_SIMD]; - cclauses[C_OMP_CLAUSE_SPLIT_SIMD] = c; - } if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE)) != 0) { + if (code == OMP_SIMD) + { + c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses), + OMP_CLAUSE_REDUCTION); + OMP_CLAUSE_DECL (c) = OMP_CLAUSE_DECL (clauses); + OMP_CLAUSE_REDUCTION_CODE (c) + = OMP_CLAUSE_REDUCTION_CODE (clauses); + OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) + = OMP_CLAUSE_REDUCTION_PLACEHOLDER (clauses); + OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c) + = OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clauses); + OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_SIMD]; + cclauses[C_OMP_CLAUSE_SPLIT_SIMD] = c; + } if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS)) != 0) { @@ -941,6 +1028,8 @@ c_omp_split_clauses (location_t loc, enum tree_code code, = OMP_CLAUSE_REDUCTION_CODE (clauses); OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = OMP_CLAUSE_REDUCTION_PLACEHOLDER (clauses); + OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c) + = OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clauses); OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] = c; s = C_OMP_CLAUSE_SPLIT_TEAMS; @@ -951,25 +1040,83 @@ c_omp_split_clauses (location_t loc, enum tree_code code, else s = C_OMP_CLAUSE_SPLIT_FOR; } - else if (code == OMP_SECTIONS) + else if (code == OMP_SECTIONS || code == OMP_PARALLEL) s = C_OMP_CLAUSE_SPLIT_PARALLEL; + else if (code == OMP_SIMD) + s = C_OMP_CLAUSE_SPLIT_SIMD; else s = C_OMP_CLAUSE_SPLIT_TEAMS; break; case OMP_CLAUSE_IF: - /* FIXME: This is currently being discussed. */ - if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)) + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOGROUP)) != 0) - s = C_OMP_CLAUSE_SPLIT_PARALLEL; + s = C_OMP_CLAUSE_SPLIT_TASKLOOP; + else if ((mask & (OMP_CLAUSE_MASK_1 + << PRAGMA_OMP_CLAUSE_NUM_THREADS)) != 0) + { + if ((mask & (OMP_CLAUSE_MASK_1 + << PRAGMA_OMP_CLAUSE_MAP)) != 0) + { + if (OMP_CLAUSE_IF_MODIFIER (clauses) == OMP_PARALLEL) + s = C_OMP_CLAUSE_SPLIT_PARALLEL; + else if (OMP_CLAUSE_IF_MODIFIER (clauses) == OMP_TARGET) + s = C_OMP_CLAUSE_SPLIT_TARGET; + else if (OMP_CLAUSE_IF_MODIFIER (clauses) == ERROR_MARK) + { + c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses), + OMP_CLAUSE_IF); + OMP_CLAUSE_IF_MODIFIER (c) + = OMP_CLAUSE_IF_MODIFIER (clauses); + OMP_CLAUSE_IF_EXPR (c) = OMP_CLAUSE_IF_EXPR (clauses); + OMP_CLAUSE_CHAIN (c) + = cclauses[C_OMP_CLAUSE_SPLIT_TARGET]; + cclauses[C_OMP_CLAUSE_SPLIT_TARGET] = c; + s = C_OMP_CLAUSE_SPLIT_PARALLEL; + } + else + { + error_at (OMP_CLAUSE_LOCATION (clauses), + "expected % or % % " + "clause modifier"); + continue; + } + } + else + s = C_OMP_CLAUSE_SPLIT_PARALLEL; + } else s = C_OMP_CLAUSE_SPLIT_TARGET; break; + case OMP_CLAUSE_LINEAR: + /* Linear clause is allowed on simd and for. Put it on the + innermost construct. */ + if (code == OMP_SIMD) + s = C_OMP_CLAUSE_SPLIT_SIMD; + else + s = C_OMP_CLAUSE_SPLIT_FOR; + break; default: gcc_unreachable (); } OMP_CLAUSE_CHAIN (clauses) = cclauses[s]; cclauses[s] = clauses; } +#ifdef ENABLE_CHECKING + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)) == 0) + gcc_assert (cclauses[C_OMP_CLAUSE_SPLIT_TARGET] == NULL_TREE); + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS)) == 0) + gcc_assert (cclauses[C_OMP_CLAUSE_SPLIT_TEAMS] == NULL_TREE); + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) == 0) + gcc_assert (cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE] == NULL_TREE); + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)) == 0) + gcc_assert (cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] == NULL_TREE); + if ((mask & ((OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE) + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOGROUP))) == 0 + && code != OMP_SECTIONS) + gcc_assert (cclauses[C_OMP_CLAUSE_SPLIT_FOR] == NULL_TREE); + if (code != OMP_SIMD) + gcc_assert (cclauses[C_OMP_CLAUSE_SPLIT_SIMD] == NULL_TREE); +#endif } diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c index 3c348009cea..834a916fcb5 100644 --- a/gcc/c-family/c-pragma.c +++ b/gcc/c-family/c-pragma.c @@ -1246,6 +1246,7 @@ static const struct omp_pragma_def omp_pragmas_simd[] = { { "parallel", PRAGMA_OMP_PARALLEL }, { "simd", PRAGMA_OMP_SIMD }, { "target", PRAGMA_OMP_TARGET }, + { "taskloop", PRAGMA_OMP_TASKLOOP }, { "teams", PRAGMA_OMP_TEAMS }, }; diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h index f6e10900a63..cec920f6f3a 100644 --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -36,6 +36,7 @@ enum pragma_kind { PRAGMA_OACC_PARALLEL, PRAGMA_OACC_UPDATE, PRAGMA_OACC_WAIT, + PRAGMA_OMP_ATOMIC, PRAGMA_OMP_BARRIER, PRAGMA_OMP_CANCEL, @@ -56,6 +57,7 @@ enum pragma_kind { PRAGMA_OMP_TARGET, PRAGMA_OMP_TASK, PRAGMA_OMP_TASKGROUP, + PRAGMA_OMP_TASKLOOP, PRAGMA_OMP_TASKWAIT, PRAGMA_OMP_TASKYIELD, PRAGMA_OMP_THREADPRIVATE, @@ -74,7 +76,7 @@ enum pragma_kind { }; -/* All clauses defined by OpenACC 2.0, and OpenMP 2.5, 3.0, 3.1, and 4.0. +/* All clauses defined by OpenACC 2.0, and OpenMP 2.5, 3.0, 3.1, 4.0 and 4.5. Used internally by both C and C++ parsers. */ enum pragma_omp_clause { PRAGMA_OMP_CLAUSE_NONE = 0, @@ -84,6 +86,7 @@ enum pragma_omp_clause { PRAGMA_OMP_CLAUSE_COPYIN, PRAGMA_OMP_CLAUSE_COPYPRIVATE, PRAGMA_OMP_CLAUSE_DEFAULT, + PRAGMA_OMP_CLAUSE_DEFAULTMAP, PRAGMA_OMP_CLAUSE_DEPEND, PRAGMA_OMP_CLAUSE_DEVICE, PRAGMA_OMP_CLAUSE_DIST_SCHEDULE, @@ -91,18 +94,25 @@ enum pragma_omp_clause { PRAGMA_OMP_CLAUSE_FIRSTPRIVATE, PRAGMA_OMP_CLAUSE_FOR, PRAGMA_OMP_CLAUSE_FROM, + PRAGMA_OMP_CLAUSE_GRAINSIZE, + PRAGMA_OMP_CLAUSE_HINT, PRAGMA_OMP_CLAUSE_IF, PRAGMA_OMP_CLAUSE_INBRANCH, + PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR, PRAGMA_OMP_CLAUSE_LASTPRIVATE, PRAGMA_OMP_CLAUSE_LINEAR, + PRAGMA_OMP_CLAUSE_LINK, PRAGMA_OMP_CLAUSE_MAP, PRAGMA_OMP_CLAUSE_MERGEABLE, + PRAGMA_OMP_CLAUSE_NOGROUP, PRAGMA_OMP_CLAUSE_NOTINBRANCH, PRAGMA_OMP_CLAUSE_NOWAIT, + PRAGMA_OMP_CLAUSE_NUM_TASKS, PRAGMA_OMP_CLAUSE_NUM_TEAMS, PRAGMA_OMP_CLAUSE_NUM_THREADS, PRAGMA_OMP_CLAUSE_ORDERED, PRAGMA_OMP_CLAUSE_PARALLEL, + PRAGMA_OMP_CLAUSE_PRIORITY, PRAGMA_OMP_CLAUSE_PRIVATE, PRAGMA_OMP_CLAUSE_PROC_BIND, PRAGMA_OMP_CLAUSE_REDUCTION, @@ -110,13 +120,16 @@ enum pragma_omp_clause { PRAGMA_OMP_CLAUSE_SCHEDULE, PRAGMA_OMP_CLAUSE_SECTIONS, PRAGMA_OMP_CLAUSE_SHARED, + PRAGMA_OMP_CLAUSE_SIMD, PRAGMA_OMP_CLAUSE_SIMDLEN, PRAGMA_OMP_CLAUSE_TASKGROUP, PRAGMA_OMP_CLAUSE_THREAD_LIMIT, + PRAGMA_OMP_CLAUSE_THREADS, PRAGMA_OMP_CLAUSE_TO, PRAGMA_OMP_CLAUSE_UNIFORM, PRAGMA_OMP_CLAUSE_UNTIED, - + PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR, + /* Clauses for Cilk Plus SIMD-enabled function. */ PRAGMA_CILK_CLAUSE_NOMASK, PRAGMA_CILK_CLAUSE_MASK, diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index f87a29a07d1..a54921a145f 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,85 @@ +2015-10-13 Jakub Jelinek + Aldy Hernandez + + * c-parser.c (c_parser_pragma): Handle PRAGMA_OMP_ORDERED here. + (c_parser_omp_clause_name): Handle OpenMP 4.5 clauses. + (c_parser_omp_variable_list): Handle structure elements for + map, to and from clauses. Handle array sections in reduction + clause. Formatting fixes. + (c_parser_omp_clause_if): Add IS_OMP argument, handle parsing of + if clause modifiers. + (c_parser_omp_clause_num_tasks, c_parser_omp_clause_grainsize, + c_parser_omp_clause_priority, c_parser_omp_clause_hint, + c_parser_omp_clause_defaultmap, c_parser_omp_clause_use_device_ptr, + c_parser_omp_clause_is_device_ptr): New functions. + (c_parser_omp_clause_ordered): Parse optional parameter. + (c_parser_omp_clause_reduction): Handle array reductions. + (c_parser_omp_clause_schedule): Parse optional simd modifier. + (c_parser_omp_clause_nogroup, c_parser_omp_clause_orderedkind): New + functions. + (c_parser_omp_clause_linear): Parse linear clause modifiers. + (c_parser_omp_clause_depend_sink): New function. + (c_parser_omp_clause_depend): Parse source/sink depend kinds. + (c_parser_omp_clause_map): Parse release/delete map kinds and + optional always modifier. + (c_parser_oacc_all_clauses): Adjust c_parser_omp_clause_if + and c_finish_omp_clauses callers. + (c_parser_omp_all_clauses): Likewise. Parse OpenMP 4.5 clauses. + Parse "to" as OMP_CLAUSE_TO_DECLARE if on declare target directive. + (c_parser_oacc_cache): Adjust c_finish_omp_clauses caller. + (OMP_CRITICAL_CLAUSE_MASK): Define. + (c_parser_omp_critical): Parse critical clauses. + (c_parser_omp_for_loop): Handle doacross loops, adjust + c_finish_omp_for and c_finish_omp_clauses callers. + (OMP_SIMD_CLAUSE_MASK): Add simdlen clause. + (c_parser_omp_simd): Allow ordered clause if it has no parameter. + (OMP_FOR_CLAUSE_MASK): Add linear clause. + (c_parser_omp_for): Disallow ordered clause when combined with + distribute. Disallow linear clause when combined with distribute + and not combined with simd. + (OMP_ORDERED_CLAUSE_MASK, OMP_ORDERED_DEPEND_CLAUSE_MASK): Define. + (c_parser_omp_ordered): Add CONTEXT argument, remove LOC argument, + parse clauses and if depend clause is found, don't parse a body. + (c_parser_omp_parallel): Disallow copyin clause on target parallel. + Allow target parallel without for after it. + (OMP_TASK_CLAUSE_MASK): Add priority clause. + (OMP_TARGET_DATA_CLAUSE_MASK): Add use_device_ptr clause. + (c_parser_omp_target_data): Diagnose no map clauses or clauses with + invalid kinds. + (OMP_TARGET_UPDATE_CLAUSE_MASK): Add depend and nowait clauses. + (OMP_TARGET_ENTER_DATA_CLAUSE_MASK, + OMP_TARGET_EXIT_DATA_CLAUSE_MASK): Define. + (c_parser_omp_target_enter_data, c_parser_omp_target_exit_data): New + functions. + (OMP_TARGET_CLAUSE_MASK): Add depend, nowait, private, firstprivate, + defaultmap and is_device_ptr clauses. + (c_parser_omp_target): Parse target parallel and target simd. Set + OMP_TARGET_COMBINED on combined constructs. Parse target enter data + and target exit data. Diagnose invalid map kinds. + (OMP_DECLARE_TARGET_CLAUSE_MASK): Define. + (c_parser_omp_declare_target): Parse OpenMP 4.5 forms of this + construct. + (c_parser_omp_declare_reduction): Use STRIP_NOPS when checking for + &omp_priv. + (OMP_TASKLOOP_CLAUSE_MASK): Define. + (c_parser_omp_taskloop): New function. + (c_parser_omp_construct): Don't handle PRAGMA_OMP_ORDERED here, + handle PRAGMA_OMP_TASKLOOP. + (c_parser_cilk_for): Adjust c_finish_omp_clauses callers. + * c-tree.h (c_finish_omp_clauses): Add two new arguments. + * c-typeck.c (handle_omp_array_sections_1): Fix comment typo. + Add IS_OMP argument, handle structure element bases, diagnose + bitfields, pass IS_OMP recursively, diagnose known zero length + array sections in depend clauses, handle array sections in reduction + clause, diagnose negative length even for pointers. + (handle_omp_array_sections): Add IS_OMP argument, use auto_vec for + types, pass IS_OMP down to handle_omp_array_sections_1, handle + array sections in reduction clause, set + OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION if map could be zero + length array section, use GOMP_MAP_FIRSTPRIVATE_POINTER for IS_OMP. + (c_finish_omp_clauses): Add IS_OMP and DECLARE_SIMD arguments. + Handle new OpenMP 4.5 clauses and new restrictions for the old ones. + 2015-10-06 Marek Polacek * c-parser.c (c_parser_statement_after_labels): Use diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 2d24c212937..704ebc6bdc6 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1255,6 +1255,7 @@ static bool c_parser_pragma (c_parser *, enum pragma_context); static bool c_parser_omp_target (c_parser *, enum pragma_context); static void c_parser_omp_end_declare_target (c_parser *); static void c_parser_omp_declare (c_parser *, enum pragma_context); +static bool c_parser_omp_ordered (c_parser *, enum pragma_context); /* These Objective-C parser functions are only ever called when compiling Objective-C. */ @@ -9804,6 +9805,10 @@ c_parser_pragma (c_parser *parser, enum pragma_context context) case PRAGMA_OMP_DECLARE_REDUCTION: c_parser_omp_declare (parser, context); return false; + + case PRAGMA_OMP_ORDERED: + return c_parser_omp_ordered (parser, context); + case PRAGMA_IVDEP: c_parser_consume_pragma (parser); c_parser_skip_to_pragma_eol (parser); @@ -9969,7 +9974,9 @@ c_parser_omp_clause_name (c_parser *parser) result = PRAGMA_OACC_CLAUSE_CREATE; break; case 'd': - if (!strcmp ("delete", p)) + if (!strcmp ("defaultmap", p)) + result = PRAGMA_OMP_CLAUSE_DEFAULTMAP; + else if (!strcmp ("delete", p)) result = PRAGMA_OACC_CLAUSE_DELETE; else if (!strcmp ("depend", p)) result = PRAGMA_OMP_CLAUSE_DEPEND; @@ -9991,20 +9998,28 @@ c_parser_omp_clause_name (c_parser *parser) case 'g': if (!strcmp ("gang", p)) result = PRAGMA_OACC_CLAUSE_GANG; + else if (!strcmp ("grainsize", p)) + result = PRAGMA_OMP_CLAUSE_GRAINSIZE; break; case 'h': - if (!strcmp ("host", p)) + if (!strcmp ("hint", p)) + result = PRAGMA_OMP_CLAUSE_HINT; + else if (!strcmp ("host", p)) result = PRAGMA_OACC_CLAUSE_HOST; break; case 'i': if (!strcmp ("inbranch", p)) result = PRAGMA_OMP_CLAUSE_INBRANCH; + else if (!strcmp ("is_device_ptr", p)) + result = PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR; break; case 'l': if (!strcmp ("lastprivate", p)) result = PRAGMA_OMP_CLAUSE_LASTPRIVATE; else if (!strcmp ("linear", p)) result = PRAGMA_OMP_CLAUSE_LINEAR; + else if (!strcmp ("link", p)) + result = PRAGMA_OMP_CLAUSE_LINK; break; case 'm': if (!strcmp ("map", p)) @@ -10015,12 +10030,16 @@ c_parser_omp_clause_name (c_parser *parser) result = PRAGMA_CILK_CLAUSE_MASK; break; case 'n': - if (!strcmp ("notinbranch", p)) + if (!strcmp ("nogroup", p)) + result = PRAGMA_OMP_CLAUSE_NOGROUP; + else if (!strcmp ("notinbranch", p)) result = PRAGMA_OMP_CLAUSE_NOTINBRANCH; else if (!strcmp ("nowait", p)) result = PRAGMA_OMP_CLAUSE_NOWAIT; else if (!strcmp ("num_gangs", p)) result = PRAGMA_OACC_CLAUSE_NUM_GANGS; + else if (!strcmp ("num_tasks", p)) + result = PRAGMA_OMP_CLAUSE_NUM_TASKS; else if (!strcmp ("num_teams", p)) result = PRAGMA_OMP_CLAUSE_NUM_TEAMS; else if (!strcmp ("num_threads", p)) @@ -10051,6 +10070,8 @@ c_parser_omp_clause_name (c_parser *parser) else if (!strcmp ("present_or_create", p) || !strcmp ("pcreate", p)) result = PRAGMA_OACC_CLAUSE_PRESENT_OR_CREATE; + else if (!strcmp ("priority", p)) + result = PRAGMA_OMP_CLAUSE_PRIORITY; else if (!strcmp ("private", p)) result = PRAGMA_OMP_CLAUSE_PRIVATE; else if (!strcmp ("proc_bind", p)) @@ -10071,6 +10092,8 @@ c_parser_omp_clause_name (c_parser *parser) result = PRAGMA_OACC_CLAUSE_SEQ; else if (!strcmp ("shared", p)) result = PRAGMA_OMP_CLAUSE_SHARED; + else if (!strcmp ("simd", p)) + result = PRAGMA_OMP_CLAUSE_SIMD; else if (!strcmp ("simdlen", p)) result = PRAGMA_OMP_CLAUSE_SIMDLEN; else if (!strcmp ("self", p)) @@ -10081,6 +10104,8 @@ c_parser_omp_clause_name (c_parser *parser) result = PRAGMA_OMP_CLAUSE_TASKGROUP; else if (!strcmp ("thread_limit", p)) result = PRAGMA_OMP_CLAUSE_THREAD_LIMIT; + else if (!strcmp ("threads", p)) + result = PRAGMA_OMP_CLAUSE_THREADS; else if (!strcmp ("to", p)) result = PRAGMA_OMP_CLAUSE_TO; break; @@ -10089,6 +10114,8 @@ c_parser_omp_clause_name (c_parser *parser) result = PRAGMA_OMP_CLAUSE_UNIFORM; else if (!strcmp ("untied", p)) result = PRAGMA_OMP_CLAUSE_UNTIED; + else if (!strcmp ("use_device_ptr", p)) + result = PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR; break; case 'v': if (!strcmp ("vector", p)) @@ -10228,11 +10255,27 @@ c_parser_omp_variable_list (c_parser *parser, t = error_mark_node; break; } - /* FALL THROUGH. */ + /* FALLTHROUGH */ case OMP_CLAUSE_MAP: case OMP_CLAUSE_FROM: case OMP_CLAUSE_TO: + while (c_parser_next_token_is (parser, CPP_DOT)) + { + location_t op_loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + if (!c_parser_next_token_is (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + t = error_mark_node; + break; + } + tree ident = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + t = build_component_ref (op_loc, t, ident); + } + /* FALLTHROUGH */ case OMP_CLAUSE_DEPEND: + case OMP_CLAUSE_REDUCTION: while (c_parser_next_token_is (parser, CPP_OPEN_SQUARE)) { tree low_bound = NULL_TREE, length = NULL_TREE; @@ -10274,7 +10317,7 @@ c_parser_omp_variable_list (c_parser *parser, && !TREE_READONLY (low_bound)) { error_at (clause_loc, - "%qD is not a constant", low_bound); + "%qD is not a constant", low_bound); t = error_mark_node; } @@ -10282,7 +10325,7 @@ c_parser_omp_variable_list (c_parser *parser, && !TREE_READONLY (length)) { error_at (clause_loc, - "%qD is not a constant", length); + "%qD is not a constant", length); t = error_mark_node; } } @@ -10588,28 +10631,149 @@ c_parser_omp_clause_final (c_parser *parser, tree list) } /* OpenACC, OpenMP 2.5: - if ( expression ) */ + if ( expression ) + + OpenMP 4.5: + if ( directive-name-modifier : expression ) + + directive-name-modifier: + parallel | task | taskloop | target data | target | target update + | target enter data | target exit data */ static tree -c_parser_omp_clause_if (c_parser *parser, tree list) +c_parser_omp_clause_if (c_parser *parser, tree list, bool is_omp) { - location_t loc = c_parser_peek_token (parser)->location; - if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) - { - tree t = c_parser_paren_condition (parser); - tree c; + location_t location = c_parser_peek_token (parser)->location; + enum tree_code if_modifier = ERROR_MARK; - check_no_duplicate_clause (list, OMP_CLAUSE_IF, "if"); + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; - c = build_omp_clause (loc, OMP_CLAUSE_IF); - OMP_CLAUSE_IF_EXPR (c) = t; - OMP_CLAUSE_CHAIN (c) = list; - list = c; + if (is_omp && c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + int n = 2; + if (strcmp (p, "parallel") == 0) + if_modifier = OMP_PARALLEL; + else if (strcmp (p, "task") == 0) + if_modifier = OMP_TASK; + else if (strcmp (p, "taskloop") == 0) + if_modifier = OMP_TASKLOOP; + else if (strcmp (p, "target") == 0) + { + if_modifier = OMP_TARGET; + if (c_parser_peek_2nd_token (parser)->type == CPP_NAME) + { + p = IDENTIFIER_POINTER (c_parser_peek_2nd_token (parser)->value); + if (strcmp ("data", p) == 0) + if_modifier = OMP_TARGET_DATA; + else if (strcmp ("update", p) == 0) + if_modifier = OMP_TARGET_UPDATE; + else if (strcmp ("enter", p) == 0) + if_modifier = OMP_TARGET_ENTER_DATA; + else if (strcmp ("exit", p) == 0) + if_modifier = OMP_TARGET_EXIT_DATA; + if (if_modifier != OMP_TARGET) + { + n = 3; + c_parser_consume_token (parser); + } + else + { + location_t loc = c_parser_peek_2nd_token (parser)->location; + error_at (loc, "expected %, %, % " + "or %"); + if_modifier = ERROR_MARK; + } + if (if_modifier == OMP_TARGET_ENTER_DATA + || if_modifier == OMP_TARGET_EXIT_DATA) + { + if (c_parser_peek_2nd_token (parser)->type == CPP_NAME) + { + p = IDENTIFIER_POINTER + (c_parser_peek_2nd_token (parser)->value); + if (strcmp ("data", p) == 0) + n = 4; + } + if (n == 4) + c_parser_consume_token (parser); + else + { + location_t loc + = c_parser_peek_2nd_token (parser)->location; + error_at (loc, "expected %"); + if_modifier = ERROR_MARK; + } + } + } + } + if (if_modifier != ERROR_MARK) + { + if (c_parser_peek_2nd_token (parser)->type == CPP_COLON) + { + c_parser_consume_token (parser); + c_parser_consume_token (parser); + } + else + { + if (n > 2) + { + location_t loc = c_parser_peek_2nd_token (parser)->location; + error_at (loc, "expected %<:%>"); + } + if_modifier = ERROR_MARK; + } + } } - else - c_parser_error (parser, "expected %<(%>"); - return list; + tree t = c_parser_condition (parser), c; + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + for (c = list; c ; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IF) + { + if (if_modifier != ERROR_MARK + && OMP_CLAUSE_IF_MODIFIER (c) == if_modifier) + { + const char *p = NULL; + switch (if_modifier) + { + case OMP_PARALLEL: p = "parallel"; break; + case OMP_TASK: p = "task"; break; + case OMP_TASKLOOP: p = "taskloop"; break; + case OMP_TARGET_DATA: p = "target data"; break; + case OMP_TARGET: p = "target"; break; + case OMP_TARGET_UPDATE: p = "target update"; break; + case OMP_TARGET_ENTER_DATA: p = "enter data"; break; + case OMP_TARGET_EXIT_DATA: p = "exit data"; break; + default: gcc_unreachable (); + } + error_at (location, "too many % clauses with %qs modifier", + p); + return list; + } + else if (OMP_CLAUSE_IF_MODIFIER (c) == if_modifier) + { + if (!is_omp) + error_at (location, "too many % clauses"); + else + error_at (location, "too many % clauses without modifier"); + return list; + } + else if (if_modifier == ERROR_MARK + || OMP_CLAUSE_IF_MODIFIER (c) == ERROR_MARK) + { + error_at (location, "if any % clause has modifier, then all " + "% clauses have to use modifier"); + return list; + } + } + + c = build_omp_clause (location, OMP_CLAUSE_IF); + OMP_CLAUSE_IF_MODIFIER (c) = if_modifier; + OMP_CLAUSE_IF_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + return c; } /* OpenMP 2.5: @@ -10743,6 +10907,239 @@ c_parser_omp_clause_num_threads (c_parser *parser, tree list) return list; } +/* OpenMP 4.5: + num_tasks ( expression ) */ + +static tree +c_parser_omp_clause_num_tasks (c_parser *parser, tree list) +{ + location_t num_tasks_loc = c_parser_peek_token (parser)->location; + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + location_t expr_loc = c_parser_peek_token (parser)->location; + tree c, t = c_parser_expression (parser).value; + mark_exp_read (t); + t = c_fully_fold (t, false, NULL); + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + c_parser_error (parser, "expected integer expression"); + return list; + } + + /* Attempt to statically determine when the number isn't positive. */ + c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, + build_int_cst (TREE_TYPE (t), 0)); + if (CAN_HAVE_LOCATION_P (c)) + SET_EXPR_LOCATION (c, expr_loc); + if (c == boolean_true_node) + { + warning_at (expr_loc, 0, "% value must be positive"); + t = integer_one_node; + } + + check_no_duplicate_clause (list, OMP_CLAUSE_NUM_TASKS, "num_tasks"); + + c = build_omp_clause (num_tasks_loc, OMP_CLAUSE_NUM_TASKS); + OMP_CLAUSE_NUM_TASKS_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + +/* OpenMP 4.5: + grainsize ( expression ) */ + +static tree +c_parser_omp_clause_grainsize (c_parser *parser, tree list) +{ + location_t grainsize_loc = c_parser_peek_token (parser)->location; + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + location_t expr_loc = c_parser_peek_token (parser)->location; + tree c, t = c_parser_expression (parser).value; + mark_exp_read (t); + t = c_fully_fold (t, false, NULL); + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + c_parser_error (parser, "expected integer expression"); + return list; + } + + /* Attempt to statically determine when the number isn't positive. */ + c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, + build_int_cst (TREE_TYPE (t), 0)); + if (CAN_HAVE_LOCATION_P (c)) + SET_EXPR_LOCATION (c, expr_loc); + if (c == boolean_true_node) + { + warning_at (expr_loc, 0, "% value must be positive"); + t = integer_one_node; + } + + check_no_duplicate_clause (list, OMP_CLAUSE_GRAINSIZE, "grainsize"); + + c = build_omp_clause (grainsize_loc, OMP_CLAUSE_GRAINSIZE); + OMP_CLAUSE_GRAINSIZE_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + +/* OpenMP 4.5: + priority ( expression ) */ + +static tree +c_parser_omp_clause_priority (c_parser *parser, tree list) +{ + location_t priority_loc = c_parser_peek_token (parser)->location; + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + location_t expr_loc = c_parser_peek_token (parser)->location; + tree c, t = c_parser_expression (parser).value; + mark_exp_read (t); + t = c_fully_fold (t, false, NULL); + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + c_parser_error (parser, "expected integer expression"); + return list; + } + + /* Attempt to statically determine when the number isn't + non-negative. */ + c = fold_build2_loc (expr_loc, LT_EXPR, boolean_type_node, t, + build_int_cst (TREE_TYPE (t), 0)); + if (CAN_HAVE_LOCATION_P (c)) + SET_EXPR_LOCATION (c, expr_loc); + if (c == boolean_true_node) + { + warning_at (expr_loc, 0, "% value must be non-negative"); + t = integer_one_node; + } + + check_no_duplicate_clause (list, OMP_CLAUSE_PRIORITY, "priority"); + + c = build_omp_clause (priority_loc, OMP_CLAUSE_PRIORITY); + OMP_CLAUSE_PRIORITY_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + +/* OpenMP 4.5: + hint ( expression ) */ + +static tree +c_parser_omp_clause_hint (c_parser *parser, tree list) +{ + location_t hint_loc = c_parser_peek_token (parser)->location; + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + tree c, t = c_parser_expression (parser).value; + mark_exp_read (t); + t = c_fully_fold (t, false, NULL); + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + c_parser_error (parser, "expected integer expression"); + return list; + } + + check_no_duplicate_clause (list, OMP_CLAUSE_HINT, "hint"); + + c = build_omp_clause (hint_loc, OMP_CLAUSE_HINT); + OMP_CLAUSE_HINT_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + +/* OpenMP 4.5: + defaultmap ( tofrom : scalar ) */ + +static tree +c_parser_omp_clause_defaultmap (c_parser *parser, tree list) +{ + location_t loc = c_parser_peek_token (parser)->location; + tree c; + const char *p; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + if (!c_parser_next_token_is (parser, CPP_NAME)) + { + c_parser_error (parser, "expected %"); + goto out_err; + } + p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "tofrom") != 0) + { + c_parser_error (parser, "expected %"); + goto out_err; + } + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + goto out_err; + if (!c_parser_next_token_is (parser, CPP_NAME)) + { + c_parser_error (parser, "expected %"); + goto out_err; + } + p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "scalar") != 0) + { + c_parser_error (parser, "expected %"); + goto out_err; + } + c_parser_consume_token (parser); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + check_no_duplicate_clause (list, OMP_CLAUSE_DEFAULTMAP, "defaultmap"); + c = build_omp_clause (loc, OMP_CLAUSE_DEFAULTMAP); + OMP_CLAUSE_CHAIN (c) = list; + return c; + + out_err: + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return list; +} + +/* OpenMP 4.5: + use_device_ptr ( variable-list ) */ + +static tree +c_parser_omp_clause_use_device_ptr (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_USE_DEVICE_PTR, + list); +} + +/* OpenMP 4.5: + is_device_ptr ( variable-list ) */ + +static tree +c_parser_omp_clause_is_device_ptr (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_IS_DEVICE_PTR, list); +} + /* OpenACC: num_workers ( expression ) */ @@ -10837,19 +11234,44 @@ c_parser_oacc_clause_wait (c_parser *parser, tree list) } /* OpenMP 2.5: - ordered */ + ordered + + OpenMP 4.5: + ordered ( constant-expression ) */ static tree c_parser_omp_clause_ordered (c_parser *parser, tree list) { - tree c; - check_no_duplicate_clause (list, OMP_CLAUSE_ORDERED, "ordered"); - c = build_omp_clause (c_parser_peek_token (parser)->location, - OMP_CLAUSE_ORDERED); + tree c, num = NULL_TREE; + HOST_WIDE_INT n; + location_t loc = c_parser_peek_token (parser)->location; + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + c_parser_consume_token (parser); + 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 (num) + { + mark_exp_read (num); + num = c_fully_fold (num, false, NULL); + if (!INTEGRAL_TYPE_P (TREE_TYPE (num)) + || !tree_fits_shwi_p (num) + || (n = tree_to_shwi (num)) <= 0 + || (int) n != n) + { + error_at (loc, "ordered argument needs positive " + "constant integer expression"); + return list; + } + } + c = build_omp_clause (loc, OMP_CLAUSE_ORDERED); + OMP_CLAUSE_ORDERED_EXPR (c) = num; OMP_CLAUSE_CHAIN (c) = list; - return c; } @@ -10948,7 +11370,27 @@ c_parser_omp_clause_reduction (c_parser *parser, tree list) OMP_CLAUSE_REDUCTION, list); for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) { - tree type = TREE_TYPE (OMP_CLAUSE_DECL (c)); + tree d = OMP_CLAUSE_DECL (c), type; + if (TREE_CODE (d) != TREE_LIST) + type = TREE_TYPE (d); + else + { + int cnt = 0; + tree t; + for (t = d; TREE_CODE (t) == TREE_LIST; t = TREE_CHAIN (t)) + cnt++; + type = TREE_TYPE (t); + while (cnt > 0) + { + if (TREE_CODE (type) != POINTER_TYPE + && TREE_CODE (type) != ARRAY_TYPE) + break; + type = TREE_TYPE (type); + cnt--; + } + } + while (TREE_CODE (type) == ARRAY_TYPE) + type = TREE_TYPE (type); OMP_CLAUSE_REDUCTION_CODE (c) = code; if (code == ERROR_MARK || !(INTEGRAL_TYPE_P (type) @@ -10972,7 +11414,13 @@ c_parser_omp_clause_reduction (c_parser *parser, tree list) schedule-kind: static | dynamic | guided | runtime | auto -*/ + + OpenMP 4.5: + schedule ( schedule-modifier : schedule-kind ) + schedule ( schedule-modifier : schedule-kind , expression ) + + schedule-modifier: + simd */ static tree c_parser_omp_clause_schedule (c_parser *parser, tree list) @@ -10985,6 +11433,19 @@ c_parser_omp_clause_schedule (c_parser *parser, tree list) c = build_omp_clause (loc, OMP_CLAUSE_SCHEDULE); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + tree kind = c_parser_peek_token (parser)->value; + const char *p = IDENTIFIER_POINTER (kind); + if (strcmp ("simd", p) == 0 + && c_parser_peek_2nd_token (parser)->type == CPP_COLON) + { + OMP_CLAUSE_SCHEDULE_SIMD (c) = 1; + c_parser_consume_token (parser); + c_parser_consume_token (parser); + } + } + if (c_parser_next_token_is (parser, CPP_NAME)) { tree kind = c_parser_peek_token (parser)->value; @@ -11163,6 +11624,33 @@ c_parser_omp_clause_cancelkind (c_parser *parser ATTRIBUTE_UNUSED, return c; } +/* OpenMP 4.5: + nogroup */ + +static tree +c_parser_omp_clause_nogroup (c_parser *parser ATTRIBUTE_UNUSED, tree list) +{ + check_no_duplicate_clause (list, OMP_CLAUSE_NOGROUP, "nogroup"); + tree c = build_omp_clause (c_parser_peek_token (parser)->location, + OMP_CLAUSE_NOGROUP); + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 4.5: + simd + threads */ + +static tree +c_parser_omp_clause_orderedkind (c_parser *parser ATTRIBUTE_UNUSED, + enum omp_clause_code code, tree list) +{ + check_no_duplicate_clause (list, code, omp_clause_code_name[code]); + tree c = build_omp_clause (c_parser_peek_token (parser)->location, code); + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + /* OpenMP 4.0: num_teams ( expression ) */ @@ -11291,20 +11779,44 @@ c_parser_omp_clause_aligned (c_parser *parser, tree list) /* OpenMP 4.0: linear ( variable-list ) - linear ( variable-list : expression ) */ + linear ( variable-list : expression ) + + OpenMP 4.5: + linear ( modifier ( variable-list ) ) + linear ( modifier ( variable-list ) : expression ) */ static tree c_parser_omp_clause_linear (c_parser *parser, tree list, bool is_cilk_simd_fn) { location_t clause_loc = c_parser_peek_token (parser)->location; tree nl, c, step; + enum omp_clause_linear_kind kind = OMP_CLAUSE_LINEAR_DEFAULT; if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) return list; + if (!is_cilk_simd_fn + && c_parser_next_token_is (parser, CPP_NAME)) + { + c_token *tok = c_parser_peek_token (parser); + const char *p = IDENTIFIER_POINTER (tok->value); + if (strcmp ("val", p) == 0) + kind = OMP_CLAUSE_LINEAR_VAL; + if (c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN) + kind = OMP_CLAUSE_LINEAR_DEFAULT; + if (kind != OMP_CLAUSE_LINEAR_DEFAULT) + { + c_parser_consume_token (parser); + c_parser_consume_token (parser); + } + } + nl = c_parser_omp_variable_list (parser, clause_loc, OMP_CLAUSE_LINEAR, list); + if (kind != OMP_CLAUSE_LINEAR_DEFAULT) + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + if (c_parser_next_token_is (parser, CPP_COLON)) { c_parser_consume_token (parser); @@ -11330,6 +11842,7 @@ c_parser_omp_clause_linear (c_parser *parser, tree list, bool is_cilk_simd_fn) for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) { OMP_CLAUSE_LINEAR_STEP (c) = step; + OMP_CLAUSE_LINEAR_KIND (c) = kind; } c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); @@ -11408,11 +11921,98 @@ c_parser_omp_clause_simdlen (c_parser *parser, tree list) return c; } +/* OpenMP 4.5: + vec: + identifier [+/- integer] + vec , identifier [+/- integer] +*/ + +static tree +c_parser_omp_clause_depend_sink (c_parser *parser, location_t clause_loc, + tree list) +{ + tree vec = NULL; + if (c_parser_next_token_is_not (parser, CPP_NAME) + || c_parser_peek_token (parser)->id_kind != C_ID_ID) + { + c_parser_error (parser, "expected identifier"); + return list; + } + + while (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_token (parser)->id_kind == C_ID_ID) + { + tree t = lookup_name (c_parser_peek_token (parser)->value); + tree addend = NULL; + + if (t == NULL_TREE) + { + undeclared_variable (c_parser_peek_token (parser)->location, + c_parser_peek_token (parser)->value); + t = error_mark_node; + } + + c_parser_consume_token (parser); + + bool neg = false; + if (c_parser_next_token_is (parser, CPP_MINUS)) + neg = true; + else if (!c_parser_next_token_is (parser, CPP_PLUS)) + { + addend = integer_zero_node; + neg = false; + goto add_to_vector; + } + c_parser_consume_token (parser); + + if (c_parser_next_token_is_not (parser, CPP_NUMBER)) + { + c_parser_error (parser, "expected integer"); + return list; + } + + addend = c_parser_peek_token (parser)->value; + if (TREE_CODE (addend) != INTEGER_CST) + { + c_parser_error (parser, "expected integer"); + return list; + } + c_parser_consume_token (parser); + + add_to_vector: + if (t != error_mark_node) + { + vec = tree_cons (addend, t, vec); + if (neg) + OMP_CLAUSE_DEPEND_SINK_NEGATIVE (vec) = 1; + } + + if (c_parser_next_token_is_not (parser, CPP_COMMA)) + break; + + c_parser_consume_token (parser); + } + + if (vec == NULL_TREE) + return list; + + tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DEPEND); + OMP_CLAUSE_DEPEND_KIND (u) = OMP_CLAUSE_DEPEND_SINK; + OMP_CLAUSE_DECL (u) = nreverse (vec); + OMP_CLAUSE_CHAIN (u) = list; + return u; +} + /* OpenMP 4.0: depend ( depend-kind: variable-list ) depend-kind: - in | out | inout */ + in | out | inout + + OpenMP 4.5: + depend ( source ) + + depend ( sink : vec ) */ static tree c_parser_omp_clause_depend (c_parser *parser, tree list) @@ -11433,6 +12033,10 @@ c_parser_omp_clause_depend (c_parser *parser, tree list) kind = OMP_CLAUSE_DEPEND_INOUT; else if (strcmp ("out", p) == 0) kind = OMP_CLAUSE_DEPEND_OUT; + else if (strcmp ("source", p) == 0) + kind = OMP_CLAUSE_DEPEND_SOURCE; + else if (strcmp ("sink", p) == 0) + kind = OMP_CLAUSE_DEPEND_SINK; else goto invalid_kind; } @@ -11440,14 +12044,30 @@ c_parser_omp_clause_depend (c_parser *parser, tree list) goto invalid_kind; c_parser_consume_token (parser); + + if (kind == OMP_CLAUSE_DEPEND_SOURCE) + { + c = build_omp_clause (clause_loc, OMP_CLAUSE_DEPEND); + OMP_CLAUSE_DEPEND_KIND (c) = kind; + OMP_CLAUSE_DECL (c) = NULL_TREE; + OMP_CLAUSE_CHAIN (c) = list; + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return c; + } + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) goto resync_fail; - nl = c_parser_omp_variable_list (parser, clause_loc, - OMP_CLAUSE_DEPEND, list); + if (kind == OMP_CLAUSE_DEPEND_SINK) + nl = c_parser_omp_clause_depend_sink (parser, clause_loc, list); + else + { + nl = c_parser_omp_variable_list (parser, clause_loc, + OMP_CLAUSE_DEPEND, list); - for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) - OMP_CLAUSE_DEPEND_KIND (c) = kind; + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_DEPEND_KIND (c) = kind; + } c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); return nl; @@ -11464,18 +12084,61 @@ c_parser_omp_clause_depend (c_parser *parser, tree list) map ( variable-list ) map-kind: - alloc | to | from | tofrom */ + alloc | to | from | tofrom + + OpenMP 4.5: + map-kind: + alloc | to | from | tofrom | release | delete + + map ( always [,] map-kind: variable-list ) */ static tree c_parser_omp_clause_map (c_parser *parser, tree list) { location_t clause_loc = c_parser_peek_token (parser)->location; enum gomp_map_kind kind = GOMP_MAP_TOFROM; + int always = 0; + enum c_id_kind always_id_kind = C_ID_NONE; + location_t always_loc = UNKNOWN_LOCATION; + tree always_id = NULL_TREE; tree nl, c; if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) return list; + if (c_parser_next_token_is (parser, CPP_NAME)) + { + c_token *tok = c_parser_peek_token (parser); + const char *p = IDENTIFIER_POINTER (tok->value); + always_id_kind = tok->id_kind; + always_loc = tok->location; + always_id = tok->value; + if (strcmp ("always", p) == 0) + { + c_token *sectok = c_parser_peek_2nd_token (parser); + if (sectok->type == CPP_COMMA) + { + c_parser_consume_token (parser); + c_parser_consume_token (parser); + always = 2; + } + else if (sectok->type == CPP_NAME) + { + p = IDENTIFIER_POINTER (sectok->value); + if (strcmp ("alloc", p) == 0 + || strcmp ("to", p) == 0 + || strcmp ("from", p) == 0 + || strcmp ("tofrom", p) == 0 + || strcmp ("release", p) == 0 + || strcmp ("delete", p) == 0) + { + c_parser_consume_token (parser); + always = 1; + } + } + } + } + if (c_parser_next_token_is (parser, CPP_NAME) && c_parser_peek_2nd_token (parser)->type == CPP_COLON) { @@ -11483,11 +12146,15 @@ c_parser_omp_clause_map (c_parser *parser, tree list) if (strcmp ("alloc", p) == 0) kind = GOMP_MAP_ALLOC; else if (strcmp ("to", p) == 0) - kind = GOMP_MAP_TO; + kind = always ? GOMP_MAP_ALWAYS_TO : GOMP_MAP_TO; else if (strcmp ("from", p) == 0) - kind = GOMP_MAP_FROM; + kind = always ? GOMP_MAP_ALWAYS_FROM : GOMP_MAP_FROM; else if (strcmp ("tofrom", p) == 0) - kind = GOMP_MAP_TOFROM; + kind = always ? GOMP_MAP_ALWAYS_TOFROM : GOMP_MAP_TOFROM; + else if (strcmp ("release", p) == 0) + kind = GOMP_MAP_RELEASE; + else if (strcmp ("delete", p) == 0) + kind = GOMP_MAP_DELETE; else { c_parser_error (parser, "invalid map kind"); @@ -11498,6 +12165,35 @@ c_parser_omp_clause_map (c_parser *parser, tree list) c_parser_consume_token (parser); c_parser_consume_token (parser); } + else if (always) + { + if (always_id_kind != C_ID_ID) + { + c_parser_error (parser, "expected identifier"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return list; + } + + tree t = lookup_name (always_id); + if (t == NULL_TREE) + { + undeclared_variable (always_loc, always_id); + t = error_mark_node; + } + if (t != error_mark_node) + { + tree u = build_omp_clause (clause_loc, OMP_CLAUSE_MAP); + OMP_CLAUSE_DECL (u) = t; + OMP_CLAUSE_CHAIN (u) = list; + OMP_CLAUSE_SET_MAP_KIND (u, kind); + list = u; + } + if (always == 1) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return list; + } + } nl = c_parser_omp_variable_list (parser, clause_loc, OMP_CLAUSE_MAP, list); @@ -11735,7 +12431,7 @@ c_parser_oacc_all_clauses (c_parser *parser, omp_clause_mask mask, c_name = "host"; break; case PRAGMA_OACC_CLAUSE_IF: - clauses = c_parser_omp_clause_if (parser, clauses); + clauses = c_parser_omp_clause_if (parser, clauses, false); c_name = "if"; break; case PRAGMA_OACC_CLAUSE_NUM_GANGS: @@ -11806,7 +12502,7 @@ c_parser_oacc_all_clauses (c_parser *parser, omp_clause_mask mask, c_parser_skip_to_pragma_eol (parser); if (finish_p) - return c_finish_omp_clauses (clauses); + return c_finish_omp_clauses (clauses, false); return clauses; } @@ -11860,8 +12556,20 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, clauses = c_parser_omp_clause_final (parser, clauses); c_name = "final"; break; + case PRAGMA_OMP_CLAUSE_GRAINSIZE: + clauses = c_parser_omp_clause_grainsize (parser, clauses); + c_name = "grainsize"; + break; + case PRAGMA_OMP_CLAUSE_HINT: + clauses = c_parser_omp_clause_hint (parser, clauses); + c_name = "hint"; + break; + case PRAGMA_OMP_CLAUSE_DEFAULTMAP: + clauses = c_parser_omp_clause_defaultmap (parser, clauses); + c_name = "defaultmap"; + break; case PRAGMA_OMP_CLAUSE_IF: - clauses = c_parser_omp_clause_if (parser, clauses); + clauses = c_parser_omp_clause_if (parser, clauses, true); c_name = "if"; break; case PRAGMA_OMP_CLAUSE_LASTPRIVATE: @@ -11876,6 +12584,10 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, clauses = c_parser_omp_clause_nowait (parser, clauses); c_name = "nowait"; break; + case PRAGMA_OMP_CLAUSE_NUM_TASKS: + clauses = c_parser_omp_clause_num_tasks (parser, clauses); + c_name = "num_tasks"; + break; case PRAGMA_OMP_CLAUSE_NUM_THREADS: clauses = c_parser_omp_clause_num_threads (parser, clauses); c_name = "num_threads"; @@ -11884,6 +12596,10 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, clauses = c_parser_omp_clause_ordered (parser, clauses); c_name = "ordered"; break; + case PRAGMA_OMP_CLAUSE_PRIORITY: + clauses = c_parser_omp_clause_priority (parser, clauses); + c_name = "priority"; + break; case PRAGMA_OMP_CLAUSE_PRIVATE: clauses = c_parser_omp_clause_private (parser, clauses); c_name = "private"; @@ -11953,8 +12669,18 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, if (!first) goto clause_not_first; break; + case PRAGMA_OMP_CLAUSE_LINK: + clauses + = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_LINK, clauses); + c_name = "link"; + break; case PRAGMA_OMP_CLAUSE_TO: - clauses = c_parser_omp_clause_to (parser, clauses); + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINK)) != 0) + clauses + = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO_DECLARE, + clauses); + else + clauses = c_parser_omp_clause_to (parser, clauses); c_name = "to"; break; case PRAGMA_OMP_CLAUSE_FROM: @@ -11991,6 +12717,14 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, clauses = c_parser_omp_clause_map (parser, clauses); c_name = "map"; break; + case PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR: + clauses = c_parser_omp_clause_use_device_ptr (parser, clauses); + c_name = "use_device_ptr"; + break; + case PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR: + clauses = c_parser_omp_clause_is_device_ptr (parser, clauses); + c_name = "is_device_ptr"; + break; case PRAGMA_OMP_CLAUSE_DEVICE: clauses = c_parser_omp_clause_device (parser, clauses); c_name = "device"; @@ -12015,6 +12749,22 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, clauses = c_parser_omp_clause_simdlen (parser, clauses); c_name = "simdlen"; break; + case PRAGMA_OMP_CLAUSE_NOGROUP: + clauses = c_parser_omp_clause_nogroup (parser, clauses); + c_name = "nogroup"; + break; + case PRAGMA_OMP_CLAUSE_THREADS: + clauses + = c_parser_omp_clause_orderedkind (parser, OMP_CLAUSE_THREADS, + clauses); + c_name = "threads"; + break; + case PRAGMA_OMP_CLAUSE_SIMD: + clauses + = c_parser_omp_clause_orderedkind (parser, OMP_CLAUSE_SIMD, + clauses); + c_name = "simd"; + break; default: c_parser_error (parser, "expected %<#pragma omp%> clause"); goto saw_error; @@ -12035,7 +12785,11 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, c_parser_skip_to_pragma_eol (parser); if (finish_p) - return c_finish_omp_clauses (clauses); + { + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNIFORM)) != 0) + return c_finish_omp_clauses (clauses, true, true); + return c_finish_omp_clauses (clauses, true); + } return clauses; } @@ -12068,7 +12822,7 @@ c_parser_oacc_cache (location_t loc, c_parser *parser) tree stmt, clauses; clauses = c_parser_omp_var_list_parens (parser, OMP_CLAUSE__CACHE_, NULL); - clauses = c_finish_omp_clauses (clauses); + clauses = c_finish_omp_clauses (clauses, false); c_parser_skip_to_pragma_eol (parser); @@ -12852,12 +13606,18 @@ c_parser_omp_barrier (c_parser *parser) # pragma omp critical [(name)] new-line structured-block + OpenMP 4.5: + # pragma omp critical [(name) [hint(expression)]] new-line + LOC is the location of the #pragma itself. */ +#define OMP_CRITICAL_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_HINT) ) + static tree c_parser_omp_critical (location_t loc, c_parser *parser) { - tree stmt, name = NULL; + tree stmt, name = NULL_TREE, clauses = NULL_TREE; if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) { @@ -12870,13 +13630,20 @@ c_parser_omp_critical (location_t loc, c_parser *parser) } else c_parser_error (parser, "expected identifier"); + + clauses = c_parser_omp_all_clauses (parser, + OMP_CRITICAL_CLAUSE_MASK, + "#pragma omp critical"); + } + else + { + if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + c_parser_error (parser, "expected %<(%> or end of line"); + c_parser_skip_to_pragma_eol (parser); } - else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) - c_parser_error (parser, "expected %<(%> or end of line"); - c_parser_skip_to_pragma_eol (parser); stmt = c_parser_omp_structured_block (parser); - return c_finish_omp_critical (loc, stmt, name); + return c_finish_omp_critical (loc, stmt, name, clauses); } /* OpenMP 2.5: @@ -12912,21 +13679,51 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, tree decl, cond, incr, save_break, save_cont, body, init, stmt, cl; tree declv, condv, incrv, initv, ret = NULL_TREE; tree pre_body = NULL_TREE, this_pre_body; + tree ordered_cl = NULL_TREE; bool fail = false, open_brace_parsed = false; - int i, collapse = 1, nbraces = 0; + int i, collapse = 1, ordered = 0, count, nbraces = 0; location_t for_loc; vec *for_block = make_tree_vector (); for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl)) if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_COLLAPSE) collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (cl)); + else if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_ORDERED + && OMP_CLAUSE_ORDERED_EXPR (cl)) + { + ordered_cl = cl; + ordered = tree_to_shwi (OMP_CLAUSE_ORDERED_EXPR (cl)); + } + + if (ordered && ordered < collapse) + { + error_at (OMP_CLAUSE_LOCATION (ordered_cl), + "% clause parameter is less than %"); + OMP_CLAUSE_ORDERED_EXPR (ordered_cl) + = build_int_cst (NULL_TREE, collapse); + ordered = collapse; + } + if (ordered) + { + for (tree *pc = &clauses; *pc; ) + if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_LINEAR) + { + error_at (OMP_CLAUSE_LOCATION (*pc), + "% clause may not be specified together " + "with % clause with a parameter"); + *pc = OMP_CLAUSE_CHAIN (*pc); + } + else + pc = &OMP_CLAUSE_CHAIN (*pc); + } - gcc_assert (collapse >= 1); + gcc_assert (collapse >= 1 && ordered >= 0); + count = ordered ? ordered : collapse; - declv = make_tree_vec (collapse); - initv = make_tree_vec (collapse); - condv = make_tree_vec (collapse); - incrv = make_tree_vec (collapse); + declv = make_tree_vec (count); + initv = make_tree_vec (count); + condv = make_tree_vec (count); + incrv = make_tree_vec (count); if (code != CILK_FOR && !c_parser_next_token_is_keyword (parser, RID_FOR)) @@ -12943,7 +13740,7 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, for_loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); - for (i = 0; i < collapse; i++) + for (i = 0; i < count; i++) { int bracecount = 0; @@ -13067,7 +13864,7 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, } parse_next: - if (i == collapse - 1) + if (i == count - 1) break; /* FIXME: OpenMP 3.0 draft isn't very clear on what exactly is allowed @@ -13098,7 +13895,7 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, bracecount--; } fail = true; - collapse = 0; + count = 0; break; } } @@ -13165,7 +13962,7 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, an error from the initialization parsing. */ if (!fail) { - stmt = c_finish_omp_for (loc, code, declv, initv, condv, + stmt = c_finish_omp_for (loc, code, declv, NULL, initv, condv, incrv, body, pre_body); if (stmt) { @@ -13179,10 +13976,10 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, c = &OMP_CLAUSE_CHAIN (*c); else { - for (i = 0; i < collapse; i++) + for (i = 0; i < count; i++) if (TREE_VEC_ELT (declv, i) == OMP_CLAUSE_DECL (*c)) break; - if (i == collapse) + if (i == count) c = &OMP_CLAUSE_CHAIN (*c); else if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_FIRSTPRIVATE) { @@ -13238,7 +14035,7 @@ omp_split_clauses (location_t loc, enum tree_code code, c_omp_split_clauses (loc, code, mask, clauses, cclauses); for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++) if (cclauses[i]) - cclauses[i] = c_finish_omp_clauses (cclauses[i]); + cclauses[i] = c_finish_omp_clauses (cclauses[i], true); } /* OpenMP 4.0: @@ -13250,6 +14047,7 @@ omp_split_clauses (location_t loc, enum tree_code code, #define OMP_SIMD_CLAUSE_MASK \ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SAFELEN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMDLEN) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ @@ -13265,13 +14063,21 @@ c_parser_omp_simd (location_t loc, c_parser *parser, strcat (p_name, " simd"); mask |= OMP_SIMD_CLAUSE_MASK; - mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED); clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); if (cclauses) { omp_split_clauses (loc, OMP_SIMD, mask, clauses, cclauses); clauses = cclauses[C_OMP_CLAUSE_SPLIT_SIMD]; + tree c = find_omp_clause (cclauses[C_OMP_CLAUSE_SPLIT_FOR], + OMP_CLAUSE_ORDERED); + if (c && OMP_CLAUSE_ORDERED_EXPR (c)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% clause with parameter may not be specified " + "on %qs construct", p_name); + OMP_CLAUSE_ORDERED_EXPR (c) = NULL_TREE; + } } block = c_begin_compound_stmt (true); @@ -13297,6 +14103,7 @@ c_parser_omp_simd (location_t loc, c_parser *parser, ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE) \ @@ -13313,6 +14120,9 @@ c_parser_omp_for (location_t loc, c_parser *parser, mask |= OMP_FOR_CLAUSE_MASK; if (cclauses) mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); + /* Composite distribute parallel for{, simd} disallows ordered clause. */ + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) != 0) + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED); if (c_parser_next_token_is (parser, CPP_NAME)) { @@ -13347,6 +14157,10 @@ c_parser_omp_for (location_t loc, c_parser *parser, return NULL_TREE; } + /* Composite distribute parallel for disallows linear clause. */ + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) != 0) + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR); + clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); if (cclauses) { @@ -13380,14 +14194,61 @@ c_parser_omp_master (location_t loc, c_parser *parser) # pragma omp ordered new-line structured-block - LOC is the location of the #pragma itself. -*/ + OpenMP 4.5: + # pragma omp ordered ordered-clauses new-line + structured-block + + # pragma omp ordered depend-clauses new-line */ + +#define OMP_ORDERED_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREADS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMD)) + +#define OMP_ORDERED_DEPEND_CLAUSE_MASK \ + (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) + +static bool +c_parser_omp_ordered (c_parser *parser, enum pragma_context context) +{ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_pragma (parser); + + if (context != pragma_stmt && context != pragma_compound) + { + c_parser_error (parser, "expected declaration specifiers"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + } + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + if (!strcmp ("depend", p)) + { + if (context == pragma_stmt) + { + error_at (loc, + "%<#pragma omp ordered%> with % clause may " + "only be used in compound statements"); + c_parser_skip_to_pragma_eol (parser); + return false; + } + + tree clauses + = c_parser_omp_all_clauses (parser, + OMP_ORDERED_DEPEND_CLAUSE_MASK, + "#pragma omp ordered"); + c_finish_omp_ordered (loc, clauses, NULL_TREE); + return false; + } + } -static tree -c_parser_omp_ordered (location_t loc, c_parser *parser) -{ - c_parser_skip_to_pragma_eol (parser); - return c_finish_omp_ordered (loc, c_parser_omp_structured_block (parser)); + tree clauses = c_parser_omp_all_clauses (parser, OMP_ORDERED_CLAUSE_MASK, + "#pragma omp ordered"); + c_finish_omp_ordered (loc, clauses, + c_parser_omp_structured_block (parser)); + return true; } /* OpenMP 2.5: @@ -13540,6 +14401,10 @@ c_parser_omp_parallel (location_t loc, c_parser *parser, strcat (p_name, " parallel"); mask |= OMP_PARALLEL_CLAUSE_MASK; + /* #pragma omp target parallel{, for, for simd} disallow copyin clause. */ + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)) != 0 + && (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) == 0) + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYIN); if (c_parser_next_token_is_keyword (parser, RID_FOR)) { @@ -13560,7 +14425,11 @@ c_parser_omp_parallel (location_t loc, c_parser *parser, OMP_PARALLEL_COMBINED (stmt) = 1; return stmt; } - else if (cclauses) + /* When combined with distribute, parallel has to be followed by for. + #pragma omp target parallel is allowed though. */ + else if (cclauses + && (mask & (OMP_CLAUSE_MASK_1 + << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) != 0) { error_at (loc, "expected % after %qs", p_name); c_parser_skip_to_pragma_eol (parser); @@ -13571,7 +14440,7 @@ c_parser_omp_parallel (location_t loc, c_parser *parser, c_parser_skip_to_pragma_eol (parser, false); return NULL_TREE; } - else if (c_parser_next_token_is (parser, CPP_NAME)) + else if (cclauses == NULL && c_parser_next_token_is (parser, CPP_NAME)) { const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); if (strcmp (p, "sections") == 0) @@ -13592,6 +14461,11 @@ c_parser_omp_parallel (location_t loc, c_parser *parser, } clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); + if (cclauses) + { + omp_split_clauses (loc, OMP_PARALLEL, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; + } block = c_begin_omp_parallel (); c_parser_statement (parser); @@ -13643,7 +14517,8 @@ c_parser_omp_single (location_t loc, c_parser *parser) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FINAL) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)) + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY)) static tree c_parser_omp_task (location_t loc, c_parser *parser) @@ -13923,17 +14798,56 @@ c_parser_omp_teams (location_t loc, c_parser *parser, #define OMP_TARGET_DATA_CLAUSE_MASK \ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)) + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR)) static tree c_parser_omp_target_data (location_t loc, c_parser *parser) { - tree stmt = make_node (OMP_TARGET_DATA); - TREE_TYPE (stmt) = void_type_node; - - OMP_TARGET_DATA_CLAUSES (stmt) + tree clauses = c_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK, "#pragma omp target data"); + int map_seen = 0; + for (tree *pc = &clauses; *pc;) + { + if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP) + switch (OMP_CLAUSE_MAP_KIND (*pc)) + { + case GOMP_MAP_TO: + case GOMP_MAP_ALWAYS_TO: + case GOMP_MAP_FROM: + case GOMP_MAP_ALWAYS_FROM: + case GOMP_MAP_TOFROM: + case GOMP_MAP_ALWAYS_TOFROM: + case GOMP_MAP_ALLOC: + map_seen = 3; + break; + case GOMP_MAP_FIRSTPRIVATE_POINTER: + break; + default: + map_seen |= 1; + error_at (OMP_CLAUSE_LOCATION (*pc), + "%<#pragma omp target data%> with map-type other " + "than %, %, % or % " + "on % clause"); + *pc = OMP_CLAUSE_CHAIN (*pc); + continue; + } + pc = &OMP_CLAUSE_CHAIN (*pc); + } + + if (map_seen != 3) + { + if (map_seen == 0) + error_at (loc, + "%<#pragma omp target data%> must contain at least " + "one % clause"); + return NULL_TREE; + } + + tree stmt = make_node (OMP_TARGET_DATA); + TREE_TYPE (stmt) = void_type_node; + OMP_TARGET_DATA_CLAUSES (stmt) = clauses; keep_next_level (); tree block = c_begin_compound_stmt (true); add_stmt (c_parser_omp_structured_block (parser)); @@ -13950,7 +14864,9 @@ c_parser_omp_target_data (location_t loc, c_parser *parser) ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FROM) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TO) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)) + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) static bool c_parser_omp_target_update (location_t loc, c_parser *parser, @@ -13985,6 +14901,177 @@ c_parser_omp_target_update (location_t loc, c_parser *parser, return false; } +/* OpenMP 4.5: + # pragma omp target enter data target-data-clause[optseq] new-line */ + +#define OMP_TARGET_ENTER_DATA_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) + +static tree +c_parser_omp_target_enter_data (location_t loc, c_parser *parser, + enum pragma_context context) +{ + bool data_seen = false; + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "data") == 0) + { + c_parser_consume_token (parser); + data_seen = true; + } + } + if (!data_seen) + { + c_parser_error (parser, "expected %"); + c_parser_skip_to_pragma_eol (parser); + return NULL_TREE; + } + + if (context == pragma_stmt) + { + error_at (loc, + "%<#pragma omp target enter data%> may only be " + "used in compound statements"); + c_parser_skip_to_pragma_eol (parser); + return NULL_TREE; + } + + tree clauses + = c_parser_omp_all_clauses (parser, OMP_TARGET_ENTER_DATA_CLAUSE_MASK, + "#pragma omp target enter data"); + int map_seen = 0; + for (tree *pc = &clauses; *pc;) + { + if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP) + switch (OMP_CLAUSE_MAP_KIND (*pc)) + { + case GOMP_MAP_TO: + case GOMP_MAP_ALWAYS_TO: + case GOMP_MAP_ALLOC: + map_seen = 3; + break; + case GOMP_MAP_FIRSTPRIVATE_POINTER: + break; + default: + map_seen |= 1; + error_at (OMP_CLAUSE_LOCATION (*pc), + "%<#pragma omp target enter data%> with map-type other " + "than % or % on % clause"); + *pc = OMP_CLAUSE_CHAIN (*pc); + continue; + } + pc = &OMP_CLAUSE_CHAIN (*pc); + } + + if (map_seen != 3) + { + if (map_seen == 0) + error_at (loc, + "%<#pragma omp target enter data%> must contain at least " + "one % clause"); + return NULL_TREE; + } + + tree stmt = make_node (OMP_TARGET_ENTER_DATA); + TREE_TYPE (stmt) = void_type_node; + OMP_TARGET_ENTER_DATA_CLAUSES (stmt) = clauses; + SET_EXPR_LOCATION (stmt, loc); + add_stmt (stmt); + return stmt; +} + +/* OpenMP 4.5: + # pragma omp target exit data target-data-clause[optseq] new-line */ + +#define OMP_TARGET_EXIT_DATA_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) + +static tree +c_parser_omp_target_exit_data (location_t loc, c_parser *parser, + enum pragma_context context) +{ + bool data_seen = false; + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "data") == 0) + { + c_parser_consume_token (parser); + data_seen = true; + } + } + if (!data_seen) + { + c_parser_error (parser, "expected %"); + c_parser_skip_to_pragma_eol (parser); + return NULL_TREE; + } + + if (context == pragma_stmt) + { + error_at (loc, + "%<#pragma omp target exit data%> may only be " + "used in compound statements"); + c_parser_skip_to_pragma_eol (parser); + return NULL_TREE; + } + + tree clauses + = c_parser_omp_all_clauses (parser, OMP_TARGET_EXIT_DATA_CLAUSE_MASK, + "#pragma omp target exit data"); + + int map_seen = 0; + for (tree *pc = &clauses; *pc;) + { + if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP) + switch (OMP_CLAUSE_MAP_KIND (*pc)) + { + case GOMP_MAP_FROM: + case GOMP_MAP_ALWAYS_FROM: + case GOMP_MAP_RELEASE: + case GOMP_MAP_DELETE: + map_seen = 3; + break; + case GOMP_MAP_FIRSTPRIVATE_POINTER: + break; + default: + map_seen |= 1; + error_at (OMP_CLAUSE_LOCATION (*pc), + "%<#pragma omp target exit data%> with map-type other " + "than %, % or % on %" + " clause"); + *pc = OMP_CLAUSE_CHAIN (*pc); + continue; + } + pc = &OMP_CLAUSE_CHAIN (*pc); + } + + if (map_seen != 3) + { + if (map_seen == 0) + error_at (loc, + "%<#pragma omp target exit data%> must contain at least one " + "% clause"); + return NULL_TREE; + } + + tree stmt = make_node (OMP_TARGET_EXIT_DATA); + TREE_TYPE (stmt) = void_type_node; + OMP_TARGET_EXIT_DATA_CLAUSES (stmt) = clauses; + SET_EXPR_LOCATION (stmt, loc); + add_stmt (stmt); + return stmt; +} + /* OpenMP 4.0: # pragma omp target target-clause[optseq] new-line structured-block */ @@ -13992,13 +15079,20 @@ c_parser_omp_target_update (location_t loc, c_parser *parser, #define OMP_TARGET_CLAUSE_MASK \ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)) + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULTMAP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR)) static bool c_parser_omp_target (c_parser *parser, enum pragma_context context) { location_t loc = c_parser_peek_token (parser)->location; c_parser_consume_pragma (parser); + tree *pc = NULL, stmt, block; if (context != pragma_stmt && context != pragma_compound) { @@ -14010,8 +15104,15 @@ c_parser_omp_target (c_parser *parser, enum pragma_context context) if (c_parser_next_token_is (parser, CPP_NAME)) { const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + enum tree_code ccode = ERROR_MARK; if (strcmp (p, "teams") == 0) + ccode = OMP_TEAMS; + else if (strcmp (p, "parallel") == 0) + ccode = OMP_PARALLEL; + else if (strcmp (p, "simd") == 0) + ccode = OMP_SIMD; + if (ccode != ERROR_MARK) { tree cclauses[C_OMP_CLAUSE_SPLIT_COUNT]; char p_name[sizeof ("#pragma omp target teams distribute " @@ -14021,15 +15122,48 @@ c_parser_omp_target (c_parser *parser, enum pragma_context context) strcpy (p_name, "#pragma omp target"); if (!flag_openmp) /* flag_openmp_simd */ { - tree stmt = c_parser_omp_teams (loc, parser, p_name, - OMP_TARGET_CLAUSE_MASK, - cclauses); + tree stmt; + switch (ccode) + { + case OMP_TEAMS: + stmt = c_parser_omp_teams (loc, parser, p_name, + OMP_TARGET_CLAUSE_MASK, + cclauses); + break; + case OMP_PARALLEL: + stmt = c_parser_omp_parallel (loc, parser, p_name, + OMP_TARGET_CLAUSE_MASK, + cclauses); + break; + case OMP_SIMD: + stmt = c_parser_omp_simd (loc, parser, p_name, + OMP_TARGET_CLAUSE_MASK, + cclauses); + break; + default: + gcc_unreachable (); + } return stmt != NULL_TREE; } keep_next_level (); - tree block = c_begin_compound_stmt (true); - tree ret = c_parser_omp_teams (loc, parser, p_name, - OMP_TARGET_CLAUSE_MASK, cclauses); + tree block = c_begin_compound_stmt (true), ret; + switch (ccode) + { + case OMP_TEAMS: + ret = c_parser_omp_teams (loc, parser, p_name, + OMP_TARGET_CLAUSE_MASK, cclauses); + break; + case OMP_PARALLEL: + ret = c_parser_omp_parallel (loc, parser, p_name, + OMP_TARGET_CLAUSE_MASK, cclauses); + break; + case OMP_SIMD: + ret = c_parser_omp_simd (loc, parser, p_name, + OMP_TARGET_CLAUSE_MASK, cclauses); + break; + default: + gcc_unreachable (); + } block = c_end_compound_stmt (loc, block, true); if (ret == NULL_TREE) return false; @@ -14037,8 +15171,10 @@ c_parser_omp_target (c_parser *parser, enum pragma_context context) TREE_TYPE (stmt) = void_type_node; OMP_TARGET_CLAUSES (stmt) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET]; OMP_TARGET_BODY (stmt) = block; + OMP_TARGET_COMBINED (stmt) = 1; add_stmt (stmt); - return true; + pc = &OMP_TARGET_CLAUSES (stmt); + goto check_clauses; } else if (!flag_openmp) /* flag_openmp_simd */ { @@ -14051,6 +15187,18 @@ c_parser_omp_target (c_parser *parser, enum pragma_context context) c_parser_omp_target_data (loc, parser); return true; } + else if (strcmp (p, "enter") == 0) + { + c_parser_consume_token (parser); + c_parser_omp_target_enter_data (loc, parser, context); + return false; + } + else if (strcmp (p, "exit") == 0) + { + c_parser_consume_token (parser); + c_parser_omp_target_exit_data (loc, parser, context); + return false; + } else if (strcmp (p, "update") == 0) { c_parser_consume_token (parser); @@ -14058,19 +15206,46 @@ c_parser_omp_target (c_parser *parser, enum pragma_context context) } } - tree stmt = make_node (OMP_TARGET); + stmt = make_node (OMP_TARGET); TREE_TYPE (stmt) = void_type_node; OMP_TARGET_CLAUSES (stmt) = c_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK, "#pragma omp target"); + pc = &OMP_TARGET_CLAUSES (stmt); keep_next_level (); - tree block = c_begin_compound_stmt (true); + block = c_begin_compound_stmt (true); add_stmt (c_parser_omp_structured_block (parser)); OMP_TARGET_BODY (stmt) = c_end_compound_stmt (loc, block, true); SET_EXPR_LOCATION (stmt, loc); add_stmt (stmt); + +check_clauses: + while (*pc) + { + if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP) + switch (OMP_CLAUSE_MAP_KIND (*pc)) + { + case GOMP_MAP_TO: + case GOMP_MAP_ALWAYS_TO: + case GOMP_MAP_FROM: + case GOMP_MAP_ALWAYS_FROM: + case GOMP_MAP_TOFROM: + case GOMP_MAP_ALWAYS_TOFROM: + case GOMP_MAP_ALLOC: + case GOMP_MAP_FIRSTPRIVATE_POINTER: + break; + default: + error_at (OMP_CLAUSE_LOCATION (*pc), + "%<#pragma omp target%> with map-type other " + "than %, %, % or % " + "on % clause"); + *pc = OMP_CLAUSE_CHAIN (*pc); + continue; + } + pc = &OMP_CLAUSE_CHAIN (*pc); + } return true; } @@ -14306,13 +15481,64 @@ c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms, /* OpenMP 4.0: # pragma omp declare target new-line declarations and definitions - # pragma omp end declare target new-line */ + # pragma omp end declare target new-line + + OpenMP 4.5: + # pragma omp declare target ( extended-list ) new-line + + # pragma omp declare target declare-target-clauses[seq] new-line */ + +#define OMP_DECLARE_TARGET_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TO) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINK)) static void c_parser_omp_declare_target (c_parser *parser) { - c_parser_skip_to_pragma_eol (parser); - current_omp_declare_target_attribute++; + location_t loc = c_parser_peek_token (parser)->location; + tree clauses = NULL_TREE; + if (c_parser_next_token_is (parser, CPP_NAME)) + clauses = c_parser_omp_all_clauses (parser, OMP_DECLARE_TARGET_CLAUSE_MASK, + "#pragma omp declare target"); + else if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + clauses = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO_DECLARE, + clauses); + c_parser_skip_to_pragma_eol (parser); + } + else + { + c_parser_skip_to_pragma_eol (parser); + current_omp_declare_target_attribute++; + return; + } + if (current_omp_declare_target_attribute) + error_at (loc, "%<#pragma omp declare target%> with clauses in between " + "%<#pragma omp declare target%> without clauses and " + "%<#pragma omp end declare target%>"); + for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) + { + tree t = OMP_CLAUSE_DECL (c), id; + tree at1 = lookup_attribute ("omp declare target", DECL_ATTRIBUTES (t)); + tree at2 = lookup_attribute ("omp declare target link", + DECL_ATTRIBUTES (t)); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINK) + { + id = get_identifier ("omp declare target link"); + std::swap (at1, at2); + } + else + id = get_identifier ("omp declare target"); + if (at2) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD specified both in declare target % and %" + " clauses", t); + continue; + } + if (!at1) + DECL_ATTRIBUTES (t) = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (t)); + } } static void @@ -14612,9 +15838,13 @@ c_parser_omp_declare_reduction (c_parser *parser, enum pragma_context context) int j; tree c = initializer.value; for (j = 0; j < call_expr_nargs (c); j++) - if (TREE_CODE (CALL_EXPR_ARG (c, j)) == ADDR_EXPR - && TREE_OPERAND (CALL_EXPR_ARG (c, j), 0) == omp_priv) - break; + { + tree a = CALL_EXPR_ARG (c, j); + STRIP_NOPS (a); + if (TREE_CODE (a) == ADDR_EXPR + && TREE_OPERAND (a, 0) == omp_priv) + break; + } if (j == call_expr_nargs (c)) error ("one of the initializer call arguments should be " "%<&omp_priv%>"); @@ -14741,6 +15971,86 @@ c_parser_omp_declare (c_parser *parser, enum pragma_context context) c_parser_skip_to_pragma_eol (parser); } +/* OpenMP 4.5: + #pragma omp taskloop taskloop-clause[optseq] new-line + for-loop + + #pragma omp taskloop simd taskloop-simd-clause[optseq] new-line + for-loop */ + +#define OMP_TASKLOOP_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_GRAINSIZE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TASKS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNTIED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FINAL) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOGROUP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY)) + +static tree +c_parser_omp_taskloop (location_t loc, c_parser *parser, + char *p_name, omp_clause_mask mask, tree *cclauses) +{ + tree clauses, block, ret; + + strcat (p_name, " taskloop"); + mask |= OMP_TASKLOOP_CLAUSE_MASK; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + if (strcmp (p, "simd") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION); + c_parser_consume_token (parser); + if (!flag_openmp) /* flag_openmp_simd */ + return c_parser_omp_simd (loc, parser, p_name, mask, cclauses); + block = c_begin_compound_stmt (true); + ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses); + block = c_end_compound_stmt (loc, block, true); + if (ret == NULL) + return ret; + ret = make_node (OMP_TASKLOOP); + TREE_TYPE (ret) = void_type_node; + OMP_FOR_BODY (ret) = block; + OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_TASKLOOP]; + SET_EXPR_LOCATION (ret, loc); + add_stmt (ret); + return ret; + } + } + if (!flag_openmp) /* flag_openmp_simd */ + { + c_parser_skip_to_pragma_eol (parser, false); + return NULL_TREE; + } + + clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); + if (cclauses) + { + omp_split_clauses (loc, OMP_TASKLOOP, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_TASKLOOP]; + } + + block = c_begin_compound_stmt (true); + ret = c_parser_omp_for_loop (loc, parser, OMP_TASKLOOP, clauses, NULL); + block = c_end_compound_stmt (loc, block, true); + add_stmt (block); + + return ret; +} + /* Main entry point to parsing most OpenMP pragmas. */ static void @@ -14798,9 +16108,6 @@ c_parser_omp_construct (c_parser *parser) case PRAGMA_OMP_MASTER: stmt = c_parser_omp_master (loc, parser); break; - case PRAGMA_OMP_ORDERED: - stmt = c_parser_omp_ordered (loc, parser); - break; case PRAGMA_OMP_PARALLEL: strcpy (p_name, "#pragma omp"); stmt = c_parser_omp_parallel (loc, parser, p_name, mask, NULL); @@ -14822,6 +16129,10 @@ c_parser_omp_construct (c_parser *parser) case PRAGMA_OMP_TASKGROUP: stmt = c_parser_omp_taskgroup (parser); break; + case PRAGMA_OMP_TASKLOOP: + strcpy (p_name, "#pragma omp"); + stmt = c_parser_omp_taskloop (loc, parser, p_name, mask, NULL); + break; case PRAGMA_OMP_TEAMS: strcpy (p_name, "#pragma omp"); stmt = c_parser_omp_teams (loc, parser, p_name, mask, NULL); @@ -15224,7 +16535,7 @@ c_parser_cilk_for (c_parser *parser, tree grain) tree clauses = build_omp_clause (EXPR_LOCATION (grain), OMP_CLAUSE_SCHEDULE); OMP_CLAUSE_SCHEDULE_KIND (clauses) = OMP_CLAUSE_SCHEDULE_CILKFOR; OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clauses) = grain; - clauses = c_finish_omp_clauses (clauses); + clauses = c_finish_omp_clauses (clauses, false); tree block = c_begin_compound_stmt (true); tree sb = push_stmt_list (); @@ -15289,7 +16600,7 @@ c_parser_cilk_for (c_parser *parser, tree grain) OMP_CLAUSE_OPERAND (c, 0) = cilk_for_number_of_iterations (omp_for); OMP_CLAUSE_CHAIN (c) = clauses; - OMP_PARALLEL_CLAUSES (omp_par) = c_finish_omp_clauses (c); + OMP_PARALLEL_CLAUSES (omp_par) = c_finish_omp_clauses (c, true); add_stmt (omp_par); } diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 667529a68c6..bee03d3dc45 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -649,7 +649,7 @@ extern tree c_begin_omp_task (void); extern tree c_finish_omp_task (location_t, tree, tree); extern void c_finish_omp_cancel (location_t, tree); extern void c_finish_omp_cancellation_point (location_t, tree); -extern tree c_finish_omp_clauses (tree); +extern tree c_finish_omp_clauses (tree, bool, bool = false); extern tree c_build_va_arg (location_t, tree, tree); extern tree c_finish_transaction (location_t, tree, int); extern bool c_tree_equal (tree, tree); diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index df3245a49b5..bc436029093 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -11654,7 +11654,7 @@ c_finish_omp_cancellation_point (location_t loc, tree clauses) map(a[:b][2:1][:c][:2][:d][e:f][2:5]) FIRST_NON_ONE will be 3, array-section-subscript [:b], [2:1] and [:c] all are or may have length of 1, array-section-subscript [:2] is the - first one knonwn not to have length 1. For array-section-subscript + first one known not to have length 1. For array-section-subscript <= FIRST_NON_ONE we diagnose non-contiguous arrays if low bound isn't 0 or length isn't the array domain max + 1, for > FIRST_NON_ONE we can if MAYBE_ZERO_LEN is false. MAYBE_ZERO_LEN will be true in the above @@ -11662,13 +11662,39 @@ c_finish_omp_cancellation_point (location_t loc, tree clauses) static tree handle_omp_array_sections_1 (tree c, tree t, vec &types, - bool &maybe_zero_len, unsigned int &first_non_one) + bool &maybe_zero_len, unsigned int &first_non_one, + bool is_omp) { tree ret, low_bound, length, type; if (TREE_CODE (t) != TREE_LIST) { if (error_operand_p (t)) return error_mark_node; + ret = t; + if (TREE_CODE (t) == COMPONENT_REF + && is_omp + && (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TO + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FROM)) + { + if (DECL_BIT_FIELD (TREE_OPERAND (t, 1))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "bit-field %qE in %qs clause", + t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + while (TREE_CODE (t) == COMPONENT_REF) + { + if (TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == UNION_TYPE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is a member of a union", t); + return error_mark_node; + } + t = TREE_OPERAND (t, 0); + } + } if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) { if (DECL_P (t)) @@ -11689,11 +11715,11 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); return error_mark_node; } - return t; + return ret; } ret = handle_omp_array_sections_1 (c, TREE_CHAIN (t), types, - maybe_zero_len, first_non_one); + maybe_zero_len, first_non_one, is_omp); if (ret == error_mark_node || ret == NULL_TREE) return ret; @@ -11734,11 +11760,32 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, if (length != NULL_TREE) { if (!integer_nonzerop (length)) - maybe_zero_len = true; + { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + { + if (integer_zerop (length)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "zero length array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + } + else + maybe_zero_len = true; + } if (first_non_one == types.length () && (TREE_CODE (length) != INTEGER_CST || integer_onep (length))) first_non_one++; } + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + && !integer_zerop (low_bound)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% array section has to be zero-based"); + return error_mark_node; + } if (TREE_CODE (type) == ARRAY_TYPE) { if (length == NULL_TREE @@ -11786,7 +11833,17 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, return error_mark_node; } if (tree_int_cst_equal (size, low_bound)) - maybe_zero_len = true; + { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + { + error_at (OMP_CLAUSE_LOCATION (c), + "zero length array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + maybe_zero_len = true; + } else if (length == NULL_TREE && first_non_one == types.length () && tree_int_cst_equal @@ -11796,7 +11853,9 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, } else if (length == NULL_TREE) { - maybe_zero_len = true; + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION) + maybe_zero_len = true; if (first_non_one == types.length ()) first_non_one++; } @@ -11830,7 +11889,9 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, } else if (length == NULL_TREE) { - maybe_zero_len = true; + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION) + maybe_zero_len = true; if (first_non_one == types.length ()) first_non_one++; } @@ -11854,6 +11915,15 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, "for pointer type length expression must be specified"); return error_mark_node; } + if (length != NULL_TREE + && TREE_CODE (length) == INTEGER_CST + && tree_int_cst_sgn (length) == -1) + { + error_at (OMP_CLAUSE_LOCATION (c), + "negative length in array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } /* If there is a pointer type anywhere but in the very first array-section-subscript, the array section can't be contiguous. */ if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND @@ -11887,28 +11957,22 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, /* Handle array sections for clause C. */ static bool -handle_omp_array_sections (tree c) +handle_omp_array_sections (tree c, bool is_omp) { bool maybe_zero_len = false; unsigned int first_non_one = 0; - vec types = vNULL; + auto_vec types; tree first = handle_omp_array_sections_1 (c, OMP_CLAUSE_DECL (c), types, - maybe_zero_len, first_non_one); + maybe_zero_len, first_non_one, + is_omp); if (first == error_mark_node) - { - types.release (); - return true; - } + return true; if (first == NULL_TREE) - { - types.release (); - return false; - } + return false; if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND) { tree t = OMP_CLAUSE_DECL (c); tree tem = NULL_TREE; - types.release (); /* Need to evaluate side effects in the length expressions if any. */ while (TREE_CODE (t) == TREE_LIST) @@ -11978,7 +12042,6 @@ handle_omp_array_sections (tree c) "array section is not contiguous in %qs " "clause", omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - types.release (); return true; } } @@ -11997,7 +12060,9 @@ handle_omp_array_sections (tree c) { tree l; - if (i > first_non_one && length && integer_nonzerop (length)) + if (i > first_non_one + && ((length && integer_nonzerop (length)) + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)) continue; if (length) l = fold_convert (sizetype, length); @@ -12022,6 +12087,22 @@ handle_omp_array_sections (tree c) else if (size == NULL_TREE) { size = size_in_bytes (TREE_TYPE (types[i])); + tree eltype = TREE_TYPE (types[num - 1]); + while (TREE_CODE (eltype) == ARRAY_TYPE) + eltype = TREE_TYPE (eltype); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + { + if (integer_zerop (size) + || integer_zerop (size_in_bytes (eltype))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "zero length array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + size = size_binop (EXACT_DIV_EXPR, size, + size_in_bytes (eltype)); + } size = size_binop (MULT_EXPR, size, l); if (condition) size = fold_build3 (COND_EXPR, sizetype, condition, @@ -12031,20 +12112,56 @@ handle_omp_array_sections (tree c) size = size_binop (MULT_EXPR, size, l); } } - types.release (); if (side_effects) size = build2 (COMPOUND_EXPR, sizetype, side_effects, size); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + { + size = size_binop (MINUS_EXPR, size, size_one_node); + size = c_fully_fold (size, false, NULL); + tree index_type = build_index_type (size); + tree eltype = TREE_TYPE (first); + while (TREE_CODE (eltype) == ARRAY_TYPE) + eltype = TREE_TYPE (eltype); + tree type = build_array_type (eltype, index_type); + tree ptype = build_pointer_type (eltype); + if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) + t = build_fold_addr_expr (t); + t = build2 (MEM_REF, type, t, build_int_cst (ptype, 0)); + OMP_CLAUSE_DECL (c) = t; + return false; + } first = c_fully_fold (first, false, NULL); OMP_CLAUSE_DECL (c) = first; if (size) size = c_fully_fold (size, false, NULL); OMP_CLAUSE_SIZE (c) = size; - if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP + || (TREE_CODE (t) == COMPONENT_REF + && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)) return false; gcc_assert (OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_FORCE_DEVICEPTR); + if (is_omp) + switch (OMP_CLAUSE_MAP_KIND (c)) + { + case GOMP_MAP_ALLOC: + case GOMP_MAP_TO: + case GOMP_MAP_FROM: + case GOMP_MAP_TOFROM: + case GOMP_MAP_ALWAYS_TO: + case GOMP_MAP_ALWAYS_FROM: + case GOMP_MAP_ALWAYS_TOFROM: + case GOMP_MAP_RELEASE: + case GOMP_MAP_DELETE: + OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION (c) = 1; + break; + default: + break; + } tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); - OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_POINTER); - if (!c_mark_addressable (t)) + OMP_CLAUSE_SET_MAP_KIND (c2, is_omp + ? GOMP_MAP_FIRSTPRIVATE_POINTER + : GOMP_MAP_POINTER); + if (!is_omp && !c_mark_addressable (t)) return false; OMP_CLAUSE_DECL (c2) = t; t = build_fold_addr_expr (first); @@ -12109,11 +12226,12 @@ c_find_omp_placeholder_r (tree *tp, int *, void *data) Remove any elements from the list that are invalid. */ tree -c_finish_omp_clauses (tree clauses) +c_finish_omp_clauses (tree clauses, bool is_omp, bool declare_simd) { bitmap_head generic_head, firstprivate_head, lastprivate_head; - bitmap_head aligned_head; - tree c, t, *pc; + bitmap_head aligned_head, map_head, map_field_head, generic_field_head; + tree c, t, type, *pc; + tree simdlen = NULL_TREE, safelen = NULL_TREE; bool branch_seen = false; bool copyprivate_seen = false; tree *nowait_clause = NULL; @@ -12123,6 +12241,9 @@ c_finish_omp_clauses (tree clauses) bitmap_initialize (&firstprivate_head, &bitmap_default_obstack); bitmap_initialize (&lastprivate_head, &bitmap_default_obstack); bitmap_initialize (&aligned_head, &bitmap_default_obstack); + bitmap_initialize (&map_head, &bitmap_default_obstack); + bitmap_initialize (&map_field_head, &bitmap_default_obstack); + bitmap_initialize (&generic_field_head, &bitmap_default_obstack); for (pc = &clauses, c = clauses; c ; c = *pc) { @@ -12144,9 +12265,61 @@ c_finish_omp_clauses (tree clauses) case OMP_CLAUSE_REDUCTION: need_implicitly_determined = true; t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) == TREE_LIST) + { + if (handle_omp_array_sections (c, is_omp)) + { + remove = true; + break; + } + + t = OMP_CLAUSE_DECL (c); + } + t = require_complete_type (t); + if (t == error_mark_node) + { + remove = true; + break; + } + type = TREE_TYPE (t); + if (TREE_CODE (t) == MEM_REF) + type = TREE_TYPE (type); + if (TREE_CODE (type) == ARRAY_TYPE) + { + tree oatype = type; + gcc_assert (TREE_CODE (t) != MEM_REF); + while (TREE_CODE (type) == ARRAY_TYPE) + type = TREE_TYPE (type); + if (integer_zerop (TYPE_SIZE_UNIT (type))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD in % clause is a zero size array", + t); + remove = true; + break; + } + tree size = size_binop (EXACT_DIV_EXPR, TYPE_SIZE_UNIT (oatype), + TYPE_SIZE_UNIT (type)); + if (integer_zerop (size)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD in % clause is a zero size array", + t); + remove = true; + break; + } + size = size_binop (MINUS_EXPR, size, size_one_node); + tree index_type = build_index_type (size); + tree atype = build_array_type (type, index_type); + tree ptype = build_pointer_type (type); + if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) + t = build_fold_addr_expr (t); + t = build2 (MEM_REF, atype, t, build_int_cst (ptype, 0)); + OMP_CLAUSE_DECL (c) = t; + } if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) == NULL_TREE - && (FLOAT_TYPE_P (TREE_TYPE (t)) - || TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE)) + && (FLOAT_TYPE_P (type) + || TREE_CODE (type) == COMPLEX_TYPE)) { enum tree_code r_code = OMP_CLAUSE_REDUCTION_CODE (c); const char *r_name = NULL; @@ -12158,11 +12331,11 @@ c_finish_omp_clauses (tree clauses) case MINUS_EXPR: break; case MIN_EXPR: - if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE) + if (TREE_CODE (type) == COMPLEX_TYPE) r_name = "min"; break; case MAX_EXPR: - if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE) + if (TREE_CODE (type) == COMPLEX_TYPE) r_name = "max"; break; case BIT_AND_EXPR: @@ -12175,11 +12348,11 @@ c_finish_omp_clauses (tree clauses) r_name = "|"; break; case TRUTH_ANDIF_EXPR: - if (FLOAT_TYPE_P (TREE_TYPE (t))) + if (FLOAT_TYPE_P (type)) r_name = "&&"; break; case TRUTH_ORIF_EXPR: - if (FLOAT_TYPE_P (TREE_TYPE (t))) + if (FLOAT_TYPE_P (type)) r_name = "||"; break; default: @@ -12197,37 +12370,49 @@ c_finish_omp_clauses (tree clauses) else if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) == error_mark_node) { error_at (OMP_CLAUSE_LOCATION (c), - "user defined reduction not found for %qD", t); + "user defined reduction not found for %qE", t); remove = true; break; } else if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)) { tree list = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c); - tree type = TYPE_MAIN_VARIANT (TREE_TYPE (t)); + type = TYPE_MAIN_VARIANT (type); tree placeholder = build_decl (OMP_CLAUSE_LOCATION (c), VAR_DECL, NULL_TREE, type); + tree decl_placeholder = NULL_TREE; OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = placeholder; DECL_ARTIFICIAL (placeholder) = 1; DECL_IGNORED_P (placeholder) = 1; + if (TREE_CODE (t) == MEM_REF) + { + decl_placeholder = build_decl (OMP_CLAUSE_LOCATION (c), + VAR_DECL, NULL_TREE, type); + OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c) = decl_placeholder; + DECL_ARTIFICIAL (decl_placeholder) = 1; + DECL_IGNORED_P (decl_placeholder) = 1; + } if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 0))) c_mark_addressable (placeholder); if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 1))) - c_mark_addressable (OMP_CLAUSE_DECL (c)); + c_mark_addressable (decl_placeholder ? decl_placeholder + : OMP_CLAUSE_DECL (c)); OMP_CLAUSE_REDUCTION_MERGE (c) = c_clone_omp_udr (TREE_VEC_ELT (list, 2), TREE_VEC_ELT (list, 0), TREE_VEC_ELT (list, 1), - OMP_CLAUSE_DECL (c), placeholder); + decl_placeholder ? decl_placeholder + : OMP_CLAUSE_DECL (c), placeholder); OMP_CLAUSE_REDUCTION_MERGE (c) = build3_loc (OMP_CLAUSE_LOCATION (c), BIND_EXPR, void_type_node, NULL_TREE, - OMP_CLAUSE_REDUCTION_MERGE (c), NULL_TREE); + OMP_CLAUSE_REDUCTION_MERGE (c), NULL_TREE); TREE_SIDE_EFFECTS (OMP_CLAUSE_REDUCTION_MERGE (c)) = 1; if (TREE_VEC_LENGTH (list) == 6) { if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 3))) - c_mark_addressable (OMP_CLAUSE_DECL (c)); + c_mark_addressable (decl_placeholder ? decl_placeholder + : OMP_CLAUSE_DECL (c)); if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 4))) c_mark_addressable (placeholder); tree init = TREE_VEC_ELT (list, 5); @@ -12236,11 +12421,15 @@ c_finish_omp_clauses (tree clauses) OMP_CLAUSE_REDUCTION_INIT (c) = c_clone_omp_udr (init, TREE_VEC_ELT (list, 4), TREE_VEC_ELT (list, 3), - OMP_CLAUSE_DECL (c), placeholder); + decl_placeholder ? decl_placeholder + : OMP_CLAUSE_DECL (c), placeholder); if (TREE_VEC_ELT (list, 5) == error_mark_node) - OMP_CLAUSE_REDUCTION_INIT (c) - = build2 (INIT_EXPR, TREE_TYPE (t), t, - OMP_CLAUSE_REDUCTION_INIT (c)); + { + tree v = decl_placeholder ? decl_placeholder : t; + OMP_CLAUSE_REDUCTION_INIT (c) + = build2 (INIT_EXPR, TREE_TYPE (v), v, + OMP_CLAUSE_REDUCTION_INIT (c)); + } if (walk_tree (&OMP_CLAUSE_REDUCTION_INIT (c), c_find_omp_placeholder_r, placeholder, NULL)) @@ -12249,12 +12438,13 @@ c_finish_omp_clauses (tree clauses) else { tree init; - if (AGGREGATE_TYPE_P (TREE_TYPE (t))) - init = build_constructor (TREE_TYPE (t), NULL); + tree v = decl_placeholder ? decl_placeholder : t; + if (AGGREGATE_TYPE_P (TREE_TYPE (v))) + init = build_constructor (TREE_TYPE (v), NULL); else - init = fold_convert (TREE_TYPE (t), integer_zero_node); + init = fold_convert (TREE_TYPE (v), integer_zero_node); OMP_CLAUSE_REDUCTION_INIT (c) - = build2 (INIT_EXPR, TREE_TYPE (t), t, init); + = build2 (INIT_EXPR, TREE_TYPE (v), v, init); } OMP_CLAUSE_REDUCTION_INIT (c) = build3_loc (OMP_CLAUSE_LOCATION (c), BIND_EXPR, @@ -12262,7 +12452,22 @@ c_finish_omp_clauses (tree clauses) OMP_CLAUSE_REDUCTION_INIT (c), NULL_TREE); TREE_SIDE_EFFECTS (OMP_CLAUSE_REDUCTION_INIT (c)) = 1; } - goto check_dup_generic; + if (TREE_CODE (t) == MEM_REF) + { + if (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (t))) == NULL_TREE + || TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (t)))) + != INTEGER_CST) + { + sorry ("variable length element type in array " + "% clause"); + remove = true; + break; + } + t = TREE_OPERAND (t, 0); + if (TREE_CODE (t) == ADDR_EXPR) + t = TREE_OPERAND (t, 0); + } + goto check_dup_generic_t; case OMP_CLAUSE_COPYPRIVATE: copyprivate_seen = true; @@ -12288,7 +12493,17 @@ c_finish_omp_clauses (tree clauses) goto check_dup_generic; case OMP_CLAUSE_LINEAR: + if (!declare_simd) + need_implicitly_determined = true; t = OMP_CLAUSE_DECL (c); + if (!declare_simd + && OMP_CLAUSE_LINEAR_KIND (c) != OMP_CLAUSE_LINEAR_DEFAULT) + { + error_at (OMP_CLAUSE_LOCATION (c), + "modifier should not be specified in % " + "clause on % or % constructs"); + OMP_CLAUSE_LINEAR_KIND (c) = OMP_CLAUSE_LINEAR_DEFAULT; + } if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) && TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE) { @@ -12316,6 +12531,7 @@ c_finish_omp_clauses (tree clauses) check_dup_generic: t = OMP_CLAUSE_DECL (c); + check_dup_generic_t: if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) { error_at (OMP_CLAUSE_LOCATION (c), @@ -12406,9 +12622,41 @@ c_finish_omp_clauses (tree clauses) case OMP_CLAUSE_DEPEND: t = OMP_CLAUSE_DECL (c); + if (t == NULL_TREE) + { + gcc_assert (OMP_CLAUSE_DEPEND_KIND (c) + == OMP_CLAUSE_DEPEND_SOURCE); + break; + } + if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK) + { + gcc_assert (TREE_CODE (t) == TREE_LIST); + for (; t; t = TREE_CHAIN (t)) + { + tree decl = TREE_VALUE (t); + if (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE) + { + tree offset = TREE_PURPOSE (t); + bool neg = wi::neg_p ((wide_int) offset); + offset = fold_unary (ABS_EXPR, TREE_TYPE (offset), offset); + tree t2 = pointer_int_sum (OMP_CLAUSE_LOCATION (c), + neg ? MINUS_EXPR : PLUS_EXPR, + decl, offset); + t2 = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR, + sizetype, t2, decl); + if (t2 == error_mark_node) + { + remove = true; + break; + } + TREE_PURPOSE (t) = t2; + } + } + break; + } if (TREE_CODE (t) == TREE_LIST) { - if (handle_omp_array_sections (c)) + if (handle_omp_array_sections (c, is_omp)) remove = true; break; } @@ -12431,7 +12679,7 @@ c_finish_omp_clauses (tree clauses) t = OMP_CLAUSE_DECL (c); if (TREE_CODE (t) == TREE_LIST) { - if (handle_omp_array_sections (c)) + if (handle_omp_array_sections (c, is_omp)) remove = true; else { @@ -12444,12 +12692,85 @@ c_finish_omp_clauses (tree clauses) omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; } + while (TREE_CODE (t) == ARRAY_REF) + t = TREE_OPERAND (t, 0); + if (TREE_CODE (t) == COMPONENT_REF + && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) + { + while (TREE_CODE (t) == COMPONENT_REF) + t = TREE_OPERAND (t, 0); + if (bitmap_bit_p (&map_field_head, DECL_UID (t))) + break; + if (bitmap_bit_p (&map_head, DECL_UID (t))) + { + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) + error ("%qD appears more than once in motion" + " clauses", t); + else + error ("%qD appears more than once in map" + " clauses", t); + remove = true; + } + else + { + bitmap_set_bit (&map_head, DECL_UID (t)); + bitmap_set_bit (&map_field_head, DECL_UID (t)); + } + } } break; } if (t == error_mark_node) - remove = true; - else if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) + { + remove = true; + break; + } + if (TREE_CODE (t) == COMPONENT_REF + && is_omp + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE__CACHE_) + { + if (DECL_BIT_FIELD (TREE_OPERAND (t, 1))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "bit-field %qE in %qs clause", + t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (!lang_hooks.types.omp_mappable_type (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE does not have a mappable type in %qs clause", + t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + while (TREE_CODE (t) == COMPONENT_REF) + { + if (TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) + == UNION_TYPE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is a member of a union", t); + remove = true; + break; + } + t = TREE_OPERAND (t, 0); + } + if (remove) + break; + if (VAR_P (t) || TREE_CODE (t) == PARM_DECL) + { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && (OMP_CLAUSE_MAP_KIND (c) + == GOMP_MAP_FIRSTPRIVATE_POINTER)) + { + if (bitmap_bit_p (&generic_field_head, DECL_UID (t))) + break; + } + else if (bitmap_bit_p (&map_field_head, DECL_UID (t))) + break; + } + } + if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) { error_at (OMP_CLAUSE_LOCATION (c), "%qE is not a variable in %qs clause", t, @@ -12467,8 +12788,11 @@ c_finish_omp_clauses (tree clauses) remove = true; else if (!(OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER + || (OMP_CLAUSE_MAP_KIND (c) + == GOMP_MAP_FIRSTPRIVATE_POINTER) || (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FORCE_DEVICEPTR))) + && t == OMP_CLAUSE_DECL (c) && !lang_hooks.types.omp_mappable_type (TREE_TYPE (t))) { error_at (OMP_CLAUSE_LOCATION (c), @@ -12476,7 +12800,24 @@ c_finish_omp_clauses (tree clauses) omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; } - else if (bitmap_bit_p (&generic_head, DECL_UID (t))) + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER) + { + if (bitmap_bit_p (&generic_head, DECL_UID (t)) + || bitmap_bit_p (&firstprivate_head, DECL_UID (t))) + { + error ("%qD appears more than once in data clauses", t); + remove = true; + } + else + { + bitmap_set_bit (&generic_head, DECL_UID (t)); + if (t != OMP_CLAUSE_DECL (c) + && TREE_CODE (OMP_CLAUSE_DECL (c)) == COMPONENT_REF) + bitmap_set_bit (&generic_field_head, DECL_UID (t)); + } + } + else if (bitmap_bit_p (&map_head, DECL_UID (t))) { if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) error ("%qD appears more than once in motion clauses", t); @@ -12485,7 +12826,42 @@ c_finish_omp_clauses (tree clauses) remove = true; } else - bitmap_set_bit (&generic_head, DECL_UID (t)); + { + bitmap_set_bit (&map_head, DECL_UID (t)); + if (t != OMP_CLAUSE_DECL (c) + && TREE_CODE (OMP_CLAUSE_DECL (c)) == COMPONENT_REF) + bitmap_set_bit (&map_field_head, DECL_UID (t)); + } + break; + + case OMP_CLAUSE_TO_DECLARE: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) == FUNCTION_DECL) + break; + /* FALLTHRU */ + case OMP_CLAUSE_LINK: + t = OMP_CLAUSE_DECL (c); + if (!VAR_P (t)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in clause %qs", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (DECL_THREAD_LOCAL_P (t)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD is threadprivate variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (!lang_hooks.types.omp_mappable_type (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD does not have a mappable type in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } break; case OMP_CLAUSE_UNIFORM: @@ -12503,6 +12879,19 @@ c_finish_omp_clauses (tree clauses) } goto check_dup_generic; + case OMP_CLAUSE_IS_DEVICE_PTR: + case OMP_CLAUSE_USE_DEVICE_PTR: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE + && TREE_CODE (TREE_TYPE (t)) != ARRAY_TYPE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qs variable is neither a pointer nor an array", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + goto check_dup_generic; + case OMP_CLAUSE_NOWAIT: if (copyprivate_seen) { @@ -12527,8 +12916,6 @@ c_finish_omp_clauses (tree clauses) case OMP_CLAUSE_COLLAPSE: case OMP_CLAUSE_FINAL: case OMP_CLAUSE_MERGEABLE: - case OMP_CLAUSE_SAFELEN: - case OMP_CLAUSE_SIMDLEN: case OMP_CLAUSE_DEVICE: case OMP_CLAUSE_DIST_SCHEDULE: case OMP_CLAUSE_PARALLEL: @@ -12536,6 +12923,14 @@ c_finish_omp_clauses (tree clauses) case OMP_CLAUSE_SECTIONS: case OMP_CLAUSE_TASKGROUP: case OMP_CLAUSE_PROC_BIND: + case OMP_CLAUSE_PRIORITY: + case OMP_CLAUSE_GRAINSIZE: + case OMP_CLAUSE_NUM_TASKS: + case OMP_CLAUSE_NOGROUP: + case OMP_CLAUSE_THREADS: + case OMP_CLAUSE_SIMD: + case OMP_CLAUSE_HINT: + case OMP_CLAUSE_DEFAULTMAP: case OMP_CLAUSE__CILK_FOR_COUNT_: case OMP_CLAUSE_NUM_GANGS: case OMP_CLAUSE_NUM_WORKERS: @@ -12550,6 +12945,15 @@ c_finish_omp_clauses (tree clauses) pc = &OMP_CLAUSE_CHAIN (c); continue; + case OMP_CLAUSE_SAFELEN: + safelen = c; + pc = &OMP_CLAUSE_CHAIN (c); + continue; + case OMP_CLAUSE_SIMDLEN: + simdlen = c; + pc = &OMP_CLAUSE_CHAIN (c); + continue; + case OMP_CLAUSE_INBRANCH: case OMP_CLAUSE_NOTINBRANCH: if (branch_seen) @@ -12619,6 +13023,18 @@ c_finish_omp_clauses (tree clauses) pc = &OMP_CLAUSE_CHAIN (c); } + if (simdlen + && safelen + && tree_int_cst_lt (OMP_CLAUSE_SAFELEN_EXPR (safelen), + OMP_CLAUSE_SIMDLEN_EXPR (simdlen))) + { + error_at (OMP_CLAUSE_LOCATION (simdlen), + "% clause value is bigger than " + "% clause value"); + OMP_CLAUSE_SIMDLEN_EXPR (simdlen) + = OMP_CLAUSE_SAFELEN_EXPR (safelen); + } + bitmap_obstack_release (NULL); return clauses; } diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 607aef7c0ed..7c54f24cc7e 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -643,8 +643,14 @@ enum cgraph_simd_clone_arg_type { SIMD_CLONE_ARG_TYPE_VECTOR, SIMD_CLONE_ARG_TYPE_UNIFORM, + /* These are only for integer/pointer arguments passed by value. */ SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP, SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP, + /* These 3 are only for reference type arguments or arguments passed + by reference. */ + SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP, + SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP, + SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP, SIMD_CLONE_ARG_TYPE_MASK }; @@ -684,7 +690,7 @@ struct GTY(()) cgraph_simd_clone_arg { variable), uniform, or vector. */ enum cgraph_simd_clone_arg_type arg_type; - /* For arg_type SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP this is + /* For arg_type SIMD_CLONE_ARG_TYPE_LINEAR_*CONSTANT_STEP this is the constant linear step, if arg_type is SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP, this is index of the uniform argument holding the step, otherwise 0. */ diff --git a/gcc/coretypes.h b/gcc/coretypes.h index 7b3df54ca3f..3439c382cab 100644 --- a/gcc/coretypes.h +++ b/gcc/coretypes.h @@ -112,6 +112,7 @@ struct gomp_atomic_load; struct gomp_atomic_store; struct gomp_continue; struct gomp_critical; +struct gomp_ordered; struct gomp_for; struct gomp_parallel; struct gomp_task; diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 517ce522960..b5951afbee4 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,150 @@ +2015-10-13 Jakub Jelinek + Aldy Hernandez + + * class.c (finish_struct_1): Call finish_omp_declare_simd_methods. + * cp-gimplify.c (cp_gimplify_expr): Handle OMP_TASKLOOP. + (cp_genericize_r): Likewise. + (cxx_omp_finish_clause): Don't diagnose references. + (cxx_omp_disregard_value_expr): New function. + * cp-objcp-common.h (LANG_HOOKS_OMP_DISREGARD_VALUE_EXPR): Redefine. + * cp-tree.h (OMP_FOR_GIMPLIFYING_P): Document for OMP_TASKLOOP. + (DECL_OMP_PRIVATIZED_MEMBER): Define. + (finish_omp_declare_simd_methods, push_omp_privatization_clauses, + pop_omp_privatization_clauses, save_omp_privatization_clauses, + restore_omp_privatization_clauses, omp_privatize_field, + cxx_omp_disregard_value_expr): New prototypes. + (finish_omp_clauses): Add two new arguments. + (finish_omp_for): Add ORIG_DECLV argument. + * parser.c (cp_parser_lambda_body): Call + save_omp_privatization_clauses and restore_omp_privatization_clauses. + (cp_parser_omp_clause_name): Handle OpenMP 4.5 clauses. + (cp_parser_omp_var_list_no_open): Handle structure elements for + map, to and from clauses. Handle array sections in reduction + clause. Parse this keyword. Formatting fixes. + (cp_parser_omp_clause_if): Add IS_OMP argument, handle parsing of + if clause modifiers. + (cp_parser_omp_clause_num_tasks, cp_parser_omp_clause_grainsize, + cp_parser_omp_clause_priority, cp_parser_omp_clause_hint, + cp_parser_omp_clause_defaultmap): New functions. + (cp_parser_omp_clause_ordered): Parse optional parameter. + (cp_parser_omp_clause_reduction): Handle array reductions. + (cp_parser_omp_clause_schedule): Parse optional simd modifier. + (cp_parser_omp_clause_nogroup, cp_parser_omp_clause_orderedkind): + New functions. + (cp_parser_omp_clause_linear): Parse linear clause modifiers. + (cp_parser_omp_clause_depend_sink): New function. + (cp_parser_omp_clause_depend): Parse source/sink depend kinds. + (cp_parser_omp_clause_map): Parse release/delete map kinds and + optional always modifier. + (cp_parser_oacc_all_clauses): Adjust cp_parser_omp_clause_if + and finish_omp_clauses callers. + (cp_parser_omp_all_clauses): Likewise. Parse OpenMP 4.5 clauses. + Parse "to" as OMP_CLAUSE_TO_DECLARE if on declare target directive. + (OMP_CRITICAL_CLAUSE_MASK): Define. + (cp_parser_omp_critical): Parse critical clauses. + (cp_parser_omp_for_incr): Use cp_tree_equal if + processing_template_decl. + (cp_parser_omp_for_loop_init): Return tree instead of bool. Handle + non-static data member iterators. + (cp_parser_omp_for_loop): Handle doacross loops, adjust + finish_omp_for and finish_omp_clauses callers. + (cp_omp_split_clauses): Adjust finish_omp_clauses caller. + (OMP_SIMD_CLAUSE_MASK): Add simdlen clause. + (cp_parser_omp_simd): Allow ordered clause if it has no parameter. + (OMP_FOR_CLAUSE_MASK): Add linear clause. + (cp_parser_omp_for): Disallow ordered clause when combined with + distribute. Disallow linear clause when combined with distribute + and not combined with simd. + (OMP_ORDERED_CLAUSE_MASK, OMP_ORDERED_DEPEND_CLAUSE_MASK): Define. + (cp_parser_omp_ordered): Add CONTEXT argument, return bool instead + of tree, parse clauses and if depend clause is found, don't parse + a body. + (cp_parser_omp_parallel): Disallow copyin clause on target parallel. + Allow target parallel without for after it. + (OMP_TASK_CLAUSE_MASK): Add priority clause. + (OMP_TARGET_DATA_CLAUSE_MASK): Add use_device_ptr clause. + (cp_parser_omp_target_data): Diagnose no map clauses or clauses with + invalid kinds. + (OMP_TARGET_UPDATE_CLAUSE_MASK): Add depend and nowait clauses. + (OMP_TARGET_ENTER_DATA_CLAUSE_MASK, + OMP_TARGET_EXIT_DATA_CLAUSE_MASK): Define. + (cp_parser_omp_target_enter_data, cp_parser_omp_target_exit_data): New + functions. + (OMP_TARGET_CLAUSE_MASK): Add depend, nowait, private, firstprivate, + defaultmap and is_device_ptr clauses. + (cp_parser_omp_target): Parse target parallel and target simd. Set + OMP_TARGET_COMBINED on combined constructs. Parse target enter data + and target exit data. Diagnose invalid map kinds. + (cp_parser_oacc_cache): Adjust finish_omp_clauses caller. + (OMP_DECLARE_TARGET_CLAUSE_MASK): Define. + (cp_parser_omp_declare_target): Parse OpenMP 4.5 forms of this + construct. + (OMP_TASKLOOP_CLAUSE_MASK): Define. + (cp_parser_omp_taskloop): New function. + (cp_parser_omp_construct): Don't handle PRAGMA_OMP_ORDERED here, + handle PRAGMA_OMP_TASKLOOP. + (cp_parser_pragma): Handle PRAGMA_OMP_ORDERED here directly, + handle PRAGMA_OMP_TASKLOOP, call push_omp_privatization_clauses + and pop_omp_privatization_clauses around parsing calls. + (cp_parser_cilk_for): Adjust finish_omp_clauses caller. + * pt.c (apply_late_template_attributes): Adjust tsubst_omp_clauses + and finish_omp_clauses callers. + (tsubst_omp_clause_decl): Return NULL if decl is NULL. + For TREE_LIST, copy over OMP_CLAUSE_DEPEND_SINK_NEGATIVE bit. + Use tsubst_expr instead of tsubst_copy, undo convert_from_reference + effects. + (tsubst_omp_clauses): Add ALLOW_FIELDS argument. Handle new + OpenMP 4.5 clauses. Use tsubst_omp_clause_decl for more clauses. + If ALLOW_FIELDS, handle non-static data members in the clauses. + Clear OMP_CLAUSE_LINEAR_STEP if it has been cleared before. + (omp_parallel_combined_clauses): New variable. + (tsubst_omp_for_iterator): Add ORIG_DECLV argument, recur on + OMP_FOR_ORIG_DECLS, handle non-static data member iterators. + Improve handling of clauses on combined constructs. + (tsubst_expr): Call push_omp_privatization_clauses and + pop_omp_privatization_clauses around instantiation of certain + OpenMP constructs, improve handling of clauses on combined + constructs, handle OMP_TASKLOOP, adjust tsubst_omp_for_iterator, + tsubst_omp_clauses and finish_omp_for callers, handle clauses on + critical and ordered, handle OMP_TARGET_{ENTER,EXIT}_DATA. + (instantiate_decl): Call save_omp_privatization_clauses and + restore_omp_privatization_clauses around instantiation. + (dependent_omp_for_p): Fix up comment typo. Handle SCOPE_REF. + * semantics.c (omp_private_member_map, omp_private_member_vec, + omp_private_member_ignore_next): New variables. + (finish_non_static_data_member): Return dummy decl for privatized + non-static data members. + (omp_clause_decl_field, omp_clause_printable_decl, + omp_note_field_privatization, omp_privatize_field): New functions. + (handle_omp_array_sections_1): Fix comment typo. + Add IS_OMP argument, handle structure element bases, diagnose + bitfields, pass IS_OMP recursively, diagnose known zero length + array sections in depend clauses, handle array sections in reduction + clause, diagnose negative length even for pointers. + (handle_omp_array_sections): Add IS_OMP argument, use auto_vec for + types, pass IS_OMP down to handle_omp_array_sections_1, handle + array sections in reduction clause, set + OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION if map could be zero + length array section, use GOMP_MAP_FIRSTPRIVATE_POINTER for IS_OMP. + (finish_omp_reduction_clause): Handle array sections and arrays. + Use omp_clause_printable_decl. + (finish_omp_declare_simd_methods, cp_finish_omp_clause_depend_sink): + New functions. + (finish_omp_clauses): Add ALLOW_FIELDS and DECLARE_SIMD arguments. + Handle new OpenMP 4.5 clauses and new restrictions for the old + ones, handle non-static data members, reject this keyword when not + allowed. + (push_omp_privatization_clauses, pop_omp_privatization_clauses, + save_omp_privatization_clauses, restore_omp_privatization_clauses): + New functions. + (handle_omp_for_class_iterator): Handle OMP_TASKLOOP class iterators. + Add collapse and ordered arguments. Fix handling of lastprivate + iterators in doacross loops. + (finish_omp_for): Add ORIG_DECLV argument, handle doacross loops, + adjust c_finish_omp_for, handle_omp_for_class_iterator and + finish_omp_clauses callers. Fill in OMP_CLAUSE_LINEAR_STEP on simd + loops with non-static data member iterators. + 2015-10-12 Ville Voutilainen PR c++/58566 diff --git a/gcc/cp/class.c b/gcc/cp/class.c index ef537be5c30..685b7b3fc18 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -6697,6 +6697,8 @@ finish_struct_1 (tree t) finish_struct_bits (t); set_method_tm_attributes (t); + if (flag_openmp || flag_openmp_simd) + finish_omp_declare_simd_methods (t); /* Complete the rtl for any static member objects of the type we're working on. */ diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index 9b6ac89d1a1..e37cbc7cd99 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -713,6 +713,7 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) case OMP_FOR: case OMP_SIMD: case OMP_DISTRIBUTE: + case OMP_TASKLOOP: ret = cp_gimplify_omp_for (expr_p, pre_p); break; @@ -1294,7 +1295,8 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) genericize_break_stmt (stmt_p); else if (TREE_CODE (stmt) == OMP_FOR || TREE_CODE (stmt) == OMP_SIMD - || TREE_CODE (stmt) == OMP_DISTRIBUTE) + || TREE_CODE (stmt) == OMP_DISTRIBUTE + || TREE_CODE (stmt) == OMP_TASKLOOP) genericize_omp_for_stmt (stmt_p, walk_subtrees, data); else if (TREE_CODE (stmt) == SIZEOF_EXPR) { @@ -1752,16 +1754,7 @@ cxx_omp_finish_clause (tree c, gimple_seq *) 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 % has reference type", - decl); - make_shared = true; - } - } + inner_type = TREE_TYPE (inner_type); /* We're interested in the base element, not arrays. */ while (TREE_CODE (inner_type) == ARRAY_TYPE) @@ -1778,3 +1771,19 @@ cxx_omp_finish_clause (tree c, gimple_seq *) if (make_shared) OMP_CLAUSE_CODE (c) = OMP_CLAUSE_SHARED; } + +/* Return true if DECL's DECL_VALUE_EXPR (if any) should be + disregarded in OpenMP construct, because it is going to be + remapped during OpenMP lowering. SHARED is true if DECL + is going to be shared, false if it is going to be privatized. */ + +bool +cxx_omp_disregard_value_expr (tree decl, bool shared) +{ + return !shared + && VAR_P (decl) + && DECL_HAS_VALUE_EXPR_P (decl) + && DECL_ARTIFICIAL (decl) + && DECL_LANG_SPECIFIC (decl) + && DECL_OMP_PRIVATIZED_MEMBER (decl); +} diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h index c8572a7f471..199c3f1bc0e 100644 --- a/gcc/cp/cp-objcp-common.h +++ b/gcc/cp/cp-objcp-common.h @@ -150,6 +150,8 @@ extern void cp_common_init_ts (void); #define LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE cxx_omp_privatize_by_reference #undef LANG_HOOKS_OMP_MAPPABLE_TYPE #define LANG_HOOKS_OMP_MAPPABLE_TYPE cp_omp_mappable_type +#undef LANG_HOOKS_OMP_DISREGARD_VALUE_EXPR +#define LANG_HOOKS_OMP_DISREGARD_VALUE_EXPR cxx_omp_disregard_value_expr #undef LANG_HOOKS_EH_USE_CXA_END_CLEANUP #define LANG_HOOKS_EH_USE_CXA_END_CLEANUP true diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f650c76c902..16db41f79e9 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -58,7 +58,8 @@ c-common.h, not after. STMT_EXPR_NO_SCOPE (in STMT_EXPR) BIND_EXPR_TRY_BLOCK (in BIND_EXPR) TYPENAME_IS_ENUM_P (in TYPENAME_TYPE) - OMP_FOR_GIMPLIFYING_P (in OMP_FOR, OMP_SIMD and OMP_DISTRIBUTE) + OMP_FOR_GIMPLIFYING_P (in OMP_FOR, OMP_SIMD, OMP_DISTRIBUTE, + and OMP_TASKLOOP) BASELINK_QUALIFIED_P (in BASELINK) TARGET_EXPR_IMPLICIT_P (in TARGET_EXPR) TEMPLATE_PARM_PARAMETER_PACK (in TEMPLATE_PARM_INDEX) @@ -2172,6 +2173,7 @@ struct GTY(()) lang_decl_base { unsigned repo_available_p : 1; /* var or fn */ unsigned threadprivate_or_deleted_p : 1; /* var or fn */ unsigned anticipated_p : 1; /* fn, type or template */ + /* anticipated_p reused as DECL_OMP_PRIVATIZED_MEMBER in var */ unsigned friend_or_tls : 1; /* var, fn, type or template */ unsigned template_conv_p : 1; /* var or template */ unsigned odr_used : 1; /* var or fn */ @@ -3512,6 +3514,11 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) (DECL_LANG_SPECIFIC (TYPE_FUNCTION_OR_TEMPLATE_DECL_CHECK (NODE)) \ ->u.base.anticipated_p) +/* True for artificial decls added for OpenMP privatized non-static + data members. */ +#define DECL_OMP_PRIVATIZED_MEMBER(NODE) \ + (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))->u.base.anticipated_p) + /* Nonzero if NODE is a FUNCTION_DECL which was declared as a friend within a class but has not been declared in the surrounding scope. The function is invisible except via argument dependent lookup. */ @@ -6301,7 +6308,12 @@ extern void finalize_nrv (tree *, tree, tree); extern tree omp_reduction_id (enum tree_code, tree, tree); extern tree cp_remove_omp_priv_cleanup_stmt (tree *, int *, void *); extern void cp_check_omp_declare_reduction (tree); -extern tree finish_omp_clauses (tree); +extern void finish_omp_declare_simd_methods (tree); +extern tree finish_omp_clauses (tree, bool, bool = false); +extern tree push_omp_privatization_clauses (bool); +extern void pop_omp_privatization_clauses (tree); +extern void save_omp_privatization_clauses (vec &); +extern void restore_omp_privatization_clauses (vec &); extern void finish_omp_threadprivate (tree); extern tree begin_omp_structured_block (void); extern tree finish_omp_structured_block (tree); @@ -6314,7 +6326,7 @@ extern tree begin_omp_task (void); extern tree finish_omp_task (tree, tree); extern tree finish_omp_for (location_t, enum tree_code, tree, tree, tree, tree, tree, - tree, tree); + tree, tree, tree); extern void finish_omp_atomic (enum tree_code, enum tree_code, tree, tree, tree, tree, tree, bool); @@ -6324,6 +6336,7 @@ extern void finish_omp_taskwait (void); extern void finish_omp_taskyield (void); extern void finish_omp_cancel (tree); extern void finish_omp_cancellation_point (tree); +extern tree omp_privatize_field (tree); extern tree begin_transaction_stmt (location_t, tree *, int); extern void finish_transaction_stmt (tree, tree, int, tree); extern tree build_transaction_expr (location_t, tree, int, tree); @@ -6693,6 +6706,7 @@ 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, gimple_seq *); extern bool cxx_omp_privatize_by_reference (const_tree); +extern bool cxx_omp_disregard_value_expr (tree, bool); /* in name-lookup.c */ extern void suggest_alternatives_for (location_t, tree); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index d4ef7f9d864..435757d3fa1 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -9820,6 +9820,8 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr) /* Still increment function_depth so that we don't GC in the middle of an expression. */ ++function_depth; + vec omp_privatization_save; + save_omp_privatization_clauses (omp_privatization_save); /* Clear this in case we're in the middle of a default argument. */ parser->local_variables_forbidden_p = false; @@ -9921,6 +9923,7 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr) expand_or_defer_fn (fn); } + restore_omp_privatization_clauses (omp_privatization_save); parser->local_variables_forbidden_p = local_variables_forbidden_p; if (nested) pop_function_context(); @@ -29093,7 +29096,9 @@ cp_parser_omp_clause_name (cp_parser *parser) result = PRAGMA_OACC_CLAUSE_CREATE; break; case 'd': - if (!strcmp ("depend", p)) + if (!strcmp ("defaultmap", p)) + result = PRAGMA_OMP_CLAUSE_DEFAULTMAP; + else if (!strcmp ("depend", p)) result = PRAGMA_OMP_CLAUSE_DEPEND; else if (!strcmp ("device", p)) result = PRAGMA_OMP_CLAUSE_DEVICE; @@ -29110,19 +29115,29 @@ cp_parser_omp_clause_name (cp_parser *parser) else if (!strcmp ("from", p)) result = PRAGMA_OMP_CLAUSE_FROM; break; + case 'g': + if (!strcmp ("grainsize", p)) + result = PRAGMA_OMP_CLAUSE_GRAINSIZE; + break; case 'h': - if (!strcmp ("host", p)) + if (!strcmp ("hint", p)) + result = PRAGMA_OMP_CLAUSE_HINT; + else if (!strcmp ("host", p)) result = PRAGMA_OACC_CLAUSE_HOST; break; case 'i': if (!strcmp ("inbranch", p)) result = PRAGMA_OMP_CLAUSE_INBRANCH; + else if (!strcmp ("is_device_ptr", p)) + result = PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR; break; case 'l': if (!strcmp ("lastprivate", p)) result = PRAGMA_OMP_CLAUSE_LASTPRIVATE; else if (!strcmp ("linear", p)) result = PRAGMA_OMP_CLAUSE_LINEAR; + else if (!strcmp ("link", p)) + result = PRAGMA_OMP_CLAUSE_LINK; break; case 'm': if (!strcmp ("map", p)) @@ -29133,7 +29148,9 @@ cp_parser_omp_clause_name (cp_parser *parser) result = PRAGMA_CILK_CLAUSE_MASK; break; case 'n': - if (!strcmp ("notinbranch", p)) + if (!strcmp ("nogroup", p)) + result = PRAGMA_OMP_CLAUSE_NOGROUP; + else if (!strcmp ("notinbranch", p)) result = PRAGMA_OMP_CLAUSE_NOTINBRANCH; else if (!strcmp ("nowait", p)) result = PRAGMA_OMP_CLAUSE_NOWAIT; @@ -29141,6 +29158,8 @@ cp_parser_omp_clause_name (cp_parser *parser) result = PRAGMA_CILK_CLAUSE_NOMASK; else if (!strcmp ("num_gangs", p)) result = PRAGMA_OACC_CLAUSE_NUM_GANGS; + else if (!strcmp ("num_tasks", p)) + result = PRAGMA_OMP_CLAUSE_NUM_TASKS; else if (!strcmp ("num_teams", p)) result = PRAGMA_OMP_CLAUSE_NUM_TEAMS; else if (!strcmp ("num_threads", p)) @@ -29169,6 +29188,8 @@ cp_parser_omp_clause_name (cp_parser *parser) else if (!strcmp ("present_or_create", p) || !strcmp ("pcreate", p)) result = PRAGMA_OACC_CLAUSE_PRESENT_OR_CREATE; + else if (!strcmp ("priority", p)) + result = PRAGMA_OMP_CLAUSE_PRIORITY; else if (!strcmp ("proc_bind", p)) result = PRAGMA_OMP_CLAUSE_PROC_BIND; break; @@ -29187,6 +29208,8 @@ cp_parser_omp_clause_name (cp_parser *parser) result = PRAGMA_OACC_CLAUSE_SELF; else if (!strcmp ("shared", p)) result = PRAGMA_OMP_CLAUSE_SHARED; + else if (!strcmp ("simd", p)) + result = PRAGMA_OMP_CLAUSE_SIMD; else if (!strcmp ("simdlen", p)) result = PRAGMA_OMP_CLAUSE_SIMDLEN; break; @@ -29195,6 +29218,8 @@ cp_parser_omp_clause_name (cp_parser *parser) result = PRAGMA_OMP_CLAUSE_TASKGROUP; else if (!strcmp ("thread_limit", p)) result = PRAGMA_OMP_CLAUSE_THREAD_LIMIT; + else if (!strcmp ("threads", p)) + result = PRAGMA_OMP_CLAUSE_THREADS; else if (!strcmp ("to", p)) result = PRAGMA_OMP_CLAUSE_TO; break; @@ -29203,6 +29228,8 @@ cp_parser_omp_clause_name (cp_parser *parser) result = PRAGMA_OMP_CLAUSE_UNIFORM; else if (!strcmp ("untied", p)) result = PRAGMA_OMP_CLAUSE_UNTIED; + else if (!strcmp ("use_device_ptr", p)) + result = PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR; break; case 'v': if (!strcmp ("vector_length", p)) @@ -29273,18 +29300,33 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, tree name, decl; token = cp_lexer_peek_token (parser->lexer); - name = cp_parser_id_expression (parser, /*template_p=*/false, - /*check_dependency_p=*/true, - /*template_p=*/NULL, - /*declarator_p=*/false, - /*optional_p=*/false); - if (name == error_mark_node) - goto skip_comma; + if (kind != 0 + && current_class_ptr + && cp_parser_is_keyword (token, RID_THIS)) + { + decl = finish_this_expr (); + if (TREE_CODE (decl) == NON_LVALUE_EXPR + || CONVERT_EXPR_P (decl)) + decl = TREE_OPERAND (decl, 0); + cp_lexer_consume_token (parser->lexer); + } + else + { + name = cp_parser_id_expression (parser, /*template_p=*/false, + /*check_dependency_p=*/true, + /*template_p=*/NULL, + /*declarator_p=*/false, + /*optional_p=*/false); + if (name == error_mark_node) + goto skip_comma; - decl = cp_parser_lookup_name_simple (parser, name, token->location); + decl = cp_parser_lookup_name_simple (parser, name, token->location); + if (decl == error_mark_node) + cp_parser_name_lookup_error (parser, name, decl, NLE_NULL, + token->location); + } if (decl == error_mark_node) - cp_parser_name_lookup_error (parser, name, decl, NLE_NULL, - token->location); + ; else if (kind != 0) { switch (kind) @@ -29296,11 +29338,24 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, decl = error_mark_node; break; } - /* FALL THROUGH. */ + /* FALLTHROUGH. */ case OMP_CLAUSE_MAP: case OMP_CLAUSE_FROM: case OMP_CLAUSE_TO: + while (cp_lexer_next_token_is (parser->lexer, CPP_DOT)) + { + location_t loc + = cp_lexer_peek_token (parser->lexer)->location; + cp_id_kind idk = CP_ID_KIND_NONE; + cp_lexer_consume_token (parser->lexer); + decl + = cp_parser_postfix_dot_deref_expression (parser, CPP_DOT, + decl, false, + &idk, loc); + } + /* FALLTHROUGH. */ case OMP_CLAUSE_DEPEND: + case OMP_CLAUSE_REDUCTION: while (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE)) { tree low_bound = NULL_TREE, length = NULL_TREE; @@ -29334,7 +29389,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, && !TREE_READONLY (low_bound)) { error_at (token->location, - "%qD is not a constant", low_bound); + "%qD is not a constant", low_bound); decl = error_mark_node; } @@ -29342,7 +29397,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, && !TREE_READONLY (length)) { error_at (token->location, - "%qD is not a constant", length); + "%qD is not a constant", length); decl = error_mark_node; } } @@ -29753,16 +29808,102 @@ cp_parser_omp_clause_final (cp_parser *parser, tree list, location_t location) } /* OpenMP 2.5: - if ( expression ) */ + if ( expression ) + + OpenMP 4.5: + if ( directive-name-modifier : expression ) + + directive-name-modifier: + parallel | task | taskloop | target data | target | target update + | target enter data | target exit data */ static tree -cp_parser_omp_clause_if (cp_parser *parser, tree list, location_t location) +cp_parser_omp_clause_if (cp_parser *parser, tree list, location_t location, + bool is_omp) { tree t, c; + enum tree_code if_modifier = ERROR_MARK; if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) return list; + if (is_omp && cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + int n = 2; + + if (strcmp ("parallel", p) == 0) + if_modifier = OMP_PARALLEL; + else if (strcmp ("task", p) == 0) + if_modifier = OMP_TASK; + else if (strcmp ("taskloop", p) == 0) + if_modifier = OMP_TASKLOOP; + else if (strcmp ("target", p) == 0) + { + if_modifier = OMP_TARGET; + if (cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) + { + id = cp_lexer_peek_nth_token (parser->lexer, 2)->u.value; + p = IDENTIFIER_POINTER (id); + if (strcmp ("data", p) == 0) + if_modifier = OMP_TARGET_DATA; + else if (strcmp ("update", p) == 0) + if_modifier = OMP_TARGET_UPDATE; + else if (strcmp ("enter", p) == 0) + if_modifier = OMP_TARGET_ENTER_DATA; + else if (strcmp ("exit", p) == 0) + if_modifier = OMP_TARGET_EXIT_DATA; + if (if_modifier != OMP_TARGET) + n = 3; + else + { + location_t loc + = cp_lexer_peek_nth_token (parser->lexer, 2)->location; + error_at (loc, "expected %, %, % " + "or %"); + if_modifier = ERROR_MARK; + } + if (if_modifier == OMP_TARGET_ENTER_DATA + || if_modifier == OMP_TARGET_EXIT_DATA) + { + if (cp_lexer_nth_token_is (parser->lexer, 3, CPP_NAME)) + { + id = cp_lexer_peek_nth_token (parser->lexer, 3)->u.value; + p = IDENTIFIER_POINTER (id); + if (strcmp ("data", p) == 0) + n = 4; + } + if (n != 4) + { + location_t loc + = cp_lexer_peek_nth_token (parser->lexer, 3)->location; + error_at (loc, "expected %"); + if_modifier = ERROR_MARK; + } + } + } + } + if (if_modifier != ERROR_MARK) + { + if (cp_lexer_nth_token_is (parser->lexer, n, CPP_COLON)) + { + while (n-- > 0) + cp_lexer_consume_token (parser->lexer); + } + else + { + if (n > 2) + { + location_t loc + = cp_lexer_peek_nth_token (parser->lexer, n)->location; + error_at (loc, "expected %<:%>"); + } + if_modifier = ERROR_MARK; + } + } + } + t = cp_parser_condition (parser); if (t == error_mark_node @@ -29771,9 +29912,48 @@ cp_parser_omp_clause_if (cp_parser *parser, tree list, location_t location) /*or_comma=*/false, /*consume_paren=*/true); - check_no_duplicate_clause (list, OMP_CLAUSE_IF, "if", location); + for (c = list; c ; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IF) + { + if (if_modifier != ERROR_MARK + && OMP_CLAUSE_IF_MODIFIER (c) == if_modifier) + { + const char *p = NULL; + switch (if_modifier) + { + case OMP_PARALLEL: p = "parallel"; break; + case OMP_TASK: p = "task"; break; + case OMP_TASKLOOP: p = "taskloop"; break; + case OMP_TARGET_DATA: p = "target data"; break; + case OMP_TARGET: p = "target"; break; + case OMP_TARGET_UPDATE: p = "target update"; break; + case OMP_TARGET_ENTER_DATA: p = "enter data"; break; + case OMP_TARGET_EXIT_DATA: p = "exit data"; break; + default: gcc_unreachable (); + } + error_at (location, "too many % clauses with %qs modifier", + p); + return list; + } + else if (OMP_CLAUSE_IF_MODIFIER (c) == if_modifier) + { + if (!is_omp) + error_at (location, "too many % clauses"); + else + error_at (location, "too many % clauses without modifier"); + return list; + } + else if (if_modifier == ERROR_MARK + || OMP_CLAUSE_IF_MODIFIER (c) == ERROR_MARK) + { + error_at (location, "if any % clause has modifier, then all " + "% clauses have to use modifier"); + return list; + } + } c = build_omp_clause (location, OMP_CLAUSE_IF); + OMP_CLAUSE_IF_MODIFIER (c) = if_modifier; OMP_CLAUSE_IF_EXPR (c) = t; OMP_CLAUSE_CHAIN (c) = list; @@ -29879,6 +30059,184 @@ cp_parser_omp_clause_num_threads (cp_parser *parser, tree list, return c; } +/* OpenMP 4.5: + num_tasks ( expression ) */ + +static tree +cp_parser_omp_clause_num_tasks (cp_parser *parser, tree list, + location_t location) +{ + tree t, c; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + t = cp_parser_expression (parser); + + if (t == error_mark_node + || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + check_no_duplicate_clause (list, OMP_CLAUSE_NUM_TASKS, + "num_tasks", location); + + c = build_omp_clause (location, OMP_CLAUSE_NUM_TASKS); + OMP_CLAUSE_NUM_TASKS_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 4.5: + grainsize ( expression ) */ + +static tree +cp_parser_omp_clause_grainsize (cp_parser *parser, tree list, + location_t location) +{ + tree t, c; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + t = cp_parser_expression (parser); + + if (t == error_mark_node + || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + check_no_duplicate_clause (list, OMP_CLAUSE_GRAINSIZE, + "grainsize", location); + + c = build_omp_clause (location, OMP_CLAUSE_GRAINSIZE); + OMP_CLAUSE_GRAINSIZE_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 4.5: + priority ( expression ) */ + +static tree +cp_parser_omp_clause_priority (cp_parser *parser, tree list, + location_t location) +{ + tree t, c; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + t = cp_parser_expression (parser); + + if (t == error_mark_node + || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + check_no_duplicate_clause (list, OMP_CLAUSE_PRIORITY, + "priority", location); + + c = build_omp_clause (location, OMP_CLAUSE_PRIORITY); + OMP_CLAUSE_PRIORITY_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 4.5: + hint ( expression ) */ + +static tree +cp_parser_omp_clause_hint (cp_parser *parser, tree list, + location_t location) +{ + tree t, c; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + t = cp_parser_expression (parser); + + if (t == error_mark_node + || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + check_no_duplicate_clause (list, OMP_CLAUSE_HINT, "hint", location); + + c = build_omp_clause (location, OMP_CLAUSE_HINT); + OMP_CLAUSE_HINT_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 4.5: + defaultmap ( tofrom : scalar ) */ + +static tree +cp_parser_omp_clause_defaultmap (cp_parser *parser, tree list, + location_t location) +{ + tree c, id; + const char *p; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + if (!cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + cp_parser_error (parser, "expected %"); + goto out_err; + } + id = cp_lexer_peek_token (parser->lexer)->u.value; + p = IDENTIFIER_POINTER (id); + if (strcmp (p, "tofrom") != 0) + { + cp_parser_error (parser, "expected %"); + goto out_err; + } + cp_lexer_consume_token (parser->lexer); + if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) + goto out_err; + + if (!cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + cp_parser_error (parser, "expected %"); + goto out_err; + } + id = cp_lexer_peek_token (parser->lexer)->u.value; + p = IDENTIFIER_POINTER (id); + if (strcmp (p, "scalar") != 0) + { + cp_parser_error (parser, "expected %"); + goto out_err; + } + cp_lexer_consume_token (parser->lexer); + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + goto out_err; + + check_no_duplicate_clause (list, OMP_CLAUSE_DEFAULTMAP, "defaultmap", + location); + + c = build_omp_clause (location, OMP_CLAUSE_DEFAULTMAP); + OMP_CLAUSE_CHAIN (c) = list; + return c; + + out_err: + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; +} + /* OpenACC: num_workers ( expression ) */ @@ -29917,18 +30275,49 @@ cp_parser_omp_clause_num_workers (cp_parser *parser, tree list) } /* OpenMP 2.5: - ordered */ + ordered + + OpenMP 4.5: + ordered ( constant-expression ) */ static tree -cp_parser_omp_clause_ordered (cp_parser * /*parser*/, +cp_parser_omp_clause_ordered (cp_parser *parser, tree list, location_t location) { - tree c; + tree c, num = NULL_TREE; + HOST_WIDE_INT n; check_no_duplicate_clause (list, OMP_CLAUSE_ORDERED, "ordered", location); + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) + { + cp_lexer_consume_token (parser->lexer); + + num = cp_parser_constant_expression (parser); + + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_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 (!tree_fits_shwi_p (num) + || !INTEGRAL_TYPE_P (TREE_TYPE (num)) + || (n = tree_to_shwi (num)) <= 0 + || (int) n != n) + { + error_at (location, + "ordered argument needs positive constant integer " + "expression"); + return list; + } + } + c = build_omp_clause (location, OMP_CLAUSE_ORDERED); + OMP_CLAUSE_ORDERED_EXPR (c) = num; OMP_CLAUSE_CHAIN (c) = list; return c; } @@ -30047,7 +30436,14 @@ cp_parser_omp_clause_reduction (cp_parser *parser, tree list) schedule ( schedule-kind , expression ) schedule-kind: - static | dynamic | guided | runtime | auto */ + static | dynamic | guided | runtime | auto + + OpenMP 4.5: + schedule ( schedule-modifier : schedule-kind ) + schedule ( schedule-modifier : schedule-kind , expression ) + + schedule-modifier: + simd */ static tree cp_parser_omp_clause_schedule (cp_parser *parser, tree list, location_t location) @@ -30059,6 +30455,19 @@ cp_parser_omp_clause_schedule (cp_parser *parser, tree list, location_t location c = build_omp_clause (location, OMP_CLAUSE_SCHEDULE); + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + if (strcmp ("simd", p) == 0 + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON)) + { + OMP_CLAUSE_SCHEDULE_SIMD (c) = 1; + cp_lexer_consume_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); + } + } + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { tree id = cp_lexer_peek_token (parser->lexer)->u.value; @@ -30180,6 +30589,34 @@ cp_parser_omp_clause_cancelkind (cp_parser * /*parser*/, return c; } +/* OpenMP 4.5: + nogroup */ + +static tree +cp_parser_omp_clause_nogroup (cp_parser * /*parser*/, + tree list, location_t location) +{ + check_no_duplicate_clause (list, OMP_CLAUSE_NOGROUP, "nogroup", location); + tree c = build_omp_clause (location, OMP_CLAUSE_NOGROUP); + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 4.5: + simd + threads */ + +static tree +cp_parser_omp_clause_orderedkind (cp_parser * /*parser*/, + enum omp_clause_code code, + tree list, location_t location) +{ + check_no_duplicate_clause (list, code, omp_clause_code_name[code], location); + tree c = build_omp_clause (location, code); + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + /* OpenMP 4.0: num_teams ( expression ) */ @@ -30277,7 +30714,11 @@ cp_parser_omp_clause_aligned (cp_parser *parser, tree list) /* OpenMP 4.0: linear ( variable-list ) - linear ( variable-list : expression ) */ + linear ( variable-list : expression ) + + OpenMP 4.5: + linear ( modifier ( variable-list ) ) + linear ( modifier ( variable-list ) : expression ) */ static tree cp_parser_omp_clause_linear (cp_parser *parser, tree list, @@ -30285,12 +30726,43 @@ cp_parser_omp_clause_linear (cp_parser *parser, tree list, { tree nlist, c, step = integer_one_node; bool colon; + enum omp_clause_linear_kind kind = OMP_CLAUSE_LINEAR_DEFAULT; if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) return list; - nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_LINEAR, list, - &colon); + if (!is_cilk_simd_fn + && cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + + if (strcmp ("ref", p) == 0) + kind = OMP_CLAUSE_LINEAR_REF; + else if (strcmp ("val", p) == 0) + kind = OMP_CLAUSE_LINEAR_VAL; + else if (strcmp ("uval", p) == 0) + kind = OMP_CLAUSE_LINEAR_UVAL; + if (cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_PAREN)) + cp_lexer_consume_token (parser->lexer); + else + kind = OMP_CLAUSE_LINEAR_DEFAULT; + } + + if (kind == OMP_CLAUSE_LINEAR_DEFAULT) + nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_LINEAR, list, + &colon); + else + { + nlist = cp_parser_omp_var_list (parser, OMP_CLAUSE_LINEAR, list); + colon = cp_lexer_next_token_is (parser->lexer, CPP_COLON); + if (colon) + cp_parser_require (parser, CPP_COLON, RT_COLON); + else if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + } if (colon) { @@ -30311,7 +30783,10 @@ cp_parser_omp_clause_linear (cp_parser *parser, tree list, } for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) - OMP_CLAUSE_LINEAR_STEP (c) = step; + { + OMP_CLAUSE_LINEAR_STEP (c) = step; + OMP_CLAUSE_LINEAR_KIND (c) = kind; + } return nlist; } @@ -30365,23 +30840,113 @@ cp_parser_omp_clause_simdlen (cp_parser *parser, tree list, /*or_comma=*/false, /*consume_paren=*/true); - check_no_duplicate_clause (list, OMP_CLAUSE_SIMDLEN, "simdlen", location); + check_no_duplicate_clause (list, OMP_CLAUSE_SIMDLEN, "simdlen", location); + + c = build_omp_clause (location, OMP_CLAUSE_SIMDLEN); + OMP_CLAUSE_SIMDLEN_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 4.5: + vec: + identifier [+/- integer] + vec , identifier [+/- integer] +*/ + +static tree +cp_parser_omp_clause_depend_sink (cp_parser *parser, location_t clause_loc, + tree list) +{ + tree vec = NULL; + + if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME)) + { + cp_parser_error (parser, "expected identifier"); + return list; + } + + while (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + location_t id_loc = cp_lexer_peek_token (parser->lexer)->location; + tree t, identifier = cp_parser_identifier (parser); + tree addend = NULL; + + if (identifier == error_mark_node) + t = error_mark_node; + else + { + t = cp_parser_lookup_name_simple + (parser, identifier, + cp_lexer_peek_token (parser->lexer)->location); + if (t == error_mark_node) + cp_parser_name_lookup_error (parser, identifier, t, NLE_NULL, + id_loc); + } + + bool neg = false; + if (cp_lexer_next_token_is (parser->lexer, CPP_MINUS)) + neg = true; + else if (!cp_lexer_next_token_is (parser->lexer, CPP_PLUS)) + { + addend = integer_zero_node; + goto add_to_vector; + } + cp_lexer_consume_token (parser->lexer); + + if (cp_lexer_next_token_is_not (parser->lexer, CPP_NUMBER)) + { + cp_parser_error (parser, "expected integer"); + return list; + } + + addend = cp_lexer_peek_token (parser->lexer)->u.value; + if (TREE_CODE (addend) != INTEGER_CST) + { + cp_parser_error (parser, "expected integer"); + return list; + } + cp_lexer_consume_token (parser->lexer); + + add_to_vector: + if (t != error_mark_node) + { + vec = tree_cons (addend, t, vec); + if (neg) + OMP_CLAUSE_DEPEND_SINK_NEGATIVE (vec) = 1; + } - c = build_omp_clause (location, OMP_CLAUSE_SIMDLEN); - OMP_CLAUSE_SIMDLEN_EXPR (c) = t; - OMP_CLAUSE_CHAIN (c) = list; + if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)) + break; - return c; + cp_lexer_consume_token (parser->lexer); + } + + if (cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN) && vec) + { + tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DEPEND); + OMP_CLAUSE_DEPEND_KIND (u) = OMP_CLAUSE_DEPEND_SINK; + OMP_CLAUSE_DECL (u) = nreverse (vec); + OMP_CLAUSE_CHAIN (u) = list; + return u; + } + return list; } /* OpenMP 4.0: depend ( depend-kind : variable-list ) depend-kind: - in | out | inout */ + in | out | inout + + OpenMP 4.5: + depend ( source ) + + depend ( sink : vec ) */ static tree -cp_parser_omp_clause_depend (cp_parser *parser, tree list) +cp_parser_omp_clause_depend (cp_parser *parser, tree list, location_t loc) { tree nlist, c; enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_INOUT; @@ -30400,6 +30965,10 @@ cp_parser_omp_clause_depend (cp_parser *parser, tree list) kind = OMP_CLAUSE_DEPEND_INOUT; else if (strcmp ("out", p) == 0) kind = OMP_CLAUSE_DEPEND_OUT; + else if (strcmp ("source", p) == 0) + kind = OMP_CLAUSE_DEPEND_SOURCE; + else if (strcmp ("sink", p) == 0) + kind = OMP_CLAUSE_DEPEND_SINK; else goto invalid_kind; } @@ -30407,15 +30976,33 @@ cp_parser_omp_clause_depend (cp_parser *parser, tree list) goto invalid_kind; cp_lexer_consume_token (parser->lexer); + + if (kind == OMP_CLAUSE_DEPEND_SOURCE) + { + c = build_omp_clause (loc, OMP_CLAUSE_DEPEND); + OMP_CLAUSE_DEPEND_KIND (c) = kind; + OMP_CLAUSE_DECL (c) = NULL_TREE; + OMP_CLAUSE_CHAIN (c) = list; + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return c; + } + if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) goto resync_fail; - nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_DEPEND, list, - NULL); - - for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) - OMP_CLAUSE_DEPEND_KIND (c) = kind; + if (kind == OMP_CLAUSE_DEPEND_SINK) + nlist = cp_parser_omp_clause_depend_sink (parser, loc, list); + else + { + nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_DEPEND, + list, NULL); + for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_DEPEND_KIND (c) = kind; + } return nlist; invalid_kind: @@ -30432,17 +31019,48 @@ cp_parser_omp_clause_depend (cp_parser *parser, tree list) map ( variable-list ) map-kind: - alloc | to | from | tofrom */ + alloc | to | from | tofrom + + OpenMP 4.5: + map-kind: + alloc | to | from | tofrom | release | delete + + map ( always [,] map-kind: variable-list ) */ static tree cp_parser_omp_clause_map (cp_parser *parser, tree list) { tree nlist, c; enum gomp_map_kind kind = GOMP_MAP_TOFROM; + bool always = false; if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) return list; + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + + if (strcmp ("always", p) == 0) + { + int nth = 2; + if (cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_COMMA) + nth++; + if ((cp_lexer_peek_nth_token (parser->lexer, nth)->type == CPP_NAME + || (cp_lexer_peek_nth_token (parser->lexer, nth)->keyword + == RID_DELETE)) + && (cp_lexer_peek_nth_token (parser->lexer, nth + 1)->type + == CPP_COLON)) + { + always = true; + cp_lexer_consume_token (parser->lexer); + if (nth == 3) + cp_lexer_consume_token (parser->lexer); + } + } + } + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME) && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_COLON) { @@ -30452,11 +31070,13 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list) if (strcmp ("alloc", p) == 0) kind = GOMP_MAP_ALLOC; else if (strcmp ("to", p) == 0) - kind = GOMP_MAP_TO; + kind = always ? GOMP_MAP_ALWAYS_TO : GOMP_MAP_TO; else if (strcmp ("from", p) == 0) - kind = GOMP_MAP_FROM; + kind = always ? GOMP_MAP_ALWAYS_FROM : GOMP_MAP_FROM; else if (strcmp ("tofrom", p) == 0) - kind = GOMP_MAP_TOFROM; + kind = always ? GOMP_MAP_ALWAYS_TOFROM : GOMP_MAP_TOFROM; + else if (strcmp ("release", p) == 0) + kind = GOMP_MAP_RELEASE; else { cp_parser_error (parser, "invalid map kind"); @@ -30468,6 +31088,13 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list) cp_lexer_consume_token (parser->lexer); cp_lexer_consume_token (parser->lexer); } + else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_DELETE) + && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_COLON) + { + kind = GOMP_MAP_DELETE; + cp_lexer_consume_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); + } nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_MAP, list, NULL); @@ -30710,7 +31337,7 @@ cp_parser_oacc_all_clauses (cp_parser *parser, omp_clause_mask mask, c_name = "host"; break; case PRAGMA_OACC_CLAUSE_IF: - clauses = cp_parser_omp_clause_if (parser, clauses, here); + clauses = cp_parser_omp_clause_if (parser, clauses, here, false); c_name = "if"; break; case PRAGMA_OACC_CLAUSE_NUM_GANGS: @@ -30777,7 +31404,7 @@ cp_parser_oacc_all_clauses (cp_parser *parser, omp_clause_mask mask, cp_parser_skip_to_pragma_eol (parser, pragma_tok); if (finish_p) - return finish_omp_clauses (clauses); + return finish_omp_clauses (clauses, false); return clauses; } @@ -30838,8 +31465,34 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, clauses); c_name = "firstprivate"; break; + case PRAGMA_OMP_CLAUSE_GRAINSIZE: + clauses = cp_parser_omp_clause_grainsize (parser, clauses, + token->location); + c_name = "grainsize"; + break; + case PRAGMA_OMP_CLAUSE_HINT: + clauses = cp_parser_omp_clause_hint (parser, clauses, + token->location); + c_name = "hint"; + break; + case PRAGMA_OMP_CLAUSE_DEFAULTMAP: + clauses = cp_parser_omp_clause_defaultmap (parser, clauses, + token->location); + c_name = "defaultmap"; + break; + case PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR: + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_USE_DEVICE_PTR, + clauses); + c_name = "use_device_ptr"; + break; + case PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR: + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_IS_DEVICE_PTR, + clauses); + c_name = "is_device_ptr"; + break; case PRAGMA_OMP_CLAUSE_IF: - clauses = cp_parser_omp_clause_if (parser, clauses, token->location); + clauses = cp_parser_omp_clause_if (parser, clauses, token->location, + true); c_name = "if"; break; case PRAGMA_OMP_CLAUSE_LASTPRIVATE: @@ -30856,6 +31509,11 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, clauses = cp_parser_omp_clause_nowait (parser, clauses, token->location); c_name = "nowait"; break; + case PRAGMA_OMP_CLAUSE_NUM_TASKS: + clauses = cp_parser_omp_clause_num_tasks (parser, clauses, + token->location); + c_name = "num_tasks"; + break; case PRAGMA_OMP_CLAUSE_NUM_THREADS: clauses = cp_parser_omp_clause_num_threads (parser, clauses, token->location); @@ -30866,6 +31524,11 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, token->location); c_name = "ordered"; break; + case PRAGMA_OMP_CLAUSE_PRIORITY: + clauses = cp_parser_omp_clause_priority (parser, clauses, + token->location); + c_name = "priority"; + break; case PRAGMA_OMP_CLAUSE_PRIVATE: clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_PRIVATE, clauses); @@ -30936,14 +31599,20 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, if (!first) goto clause_not_first; break; + case PRAGMA_OMP_CLAUSE_LINK: + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_LINK, clauses); + c_name = "to"; + break; case PRAGMA_OMP_CLAUSE_TO: - clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_TO, - clauses); + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINK)) != 0) + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_TO_DECLARE, + clauses); + else + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_TO, clauses); c_name = "to"; break; case PRAGMA_OMP_CLAUSE_FROM: - clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FROM, - clauses); + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FROM, clauses); c_name = "from"; break; case PRAGMA_OMP_CLAUSE_UNIFORM: @@ -30972,7 +31641,8 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, c_name = "linear"; break; case PRAGMA_OMP_CLAUSE_DEPEND: - clauses = cp_parser_omp_clause_depend (parser, clauses); + clauses = cp_parser_omp_clause_depend (parser, clauses, + token->location); c_name = "depend"; break; case PRAGMA_OMP_CLAUSE_MAP: @@ -31004,6 +31674,23 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, token->location); c_name = "simdlen"; break; + case PRAGMA_OMP_CLAUSE_NOGROUP: + clauses = cp_parser_omp_clause_nogroup (parser, clauses, + token->location); + c_name = "nogroup"; + break; + case PRAGMA_OMP_CLAUSE_THREADS: + clauses + = cp_parser_omp_clause_orderedkind (parser, OMP_CLAUSE_THREADS, + clauses, token->location); + c_name = "threads"; + break; + case PRAGMA_OMP_CLAUSE_SIMD: + clauses + = cp_parser_omp_clause_orderedkind (parser, OMP_CLAUSE_SIMD, + clauses, token->location); + c_name = "simd"; + break; case PRAGMA_CILK_CLAUSE_VECTORLENGTH: clauses = cp_parser_cilk_simd_vectorlength (parser, clauses, true); c_name = "simdlen"; @@ -31029,7 +31716,12 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, if (!(flag_cilkplus && pragma_tok == NULL)) cp_parser_skip_to_pragma_eol (parser, pragma_tok); if (finish_p) - return finish_omp_clauses (clauses); + { + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNIFORM)) != 0) + return finish_omp_clauses (clauses, false, true); + else + return finish_omp_clauses (clauses, true); + } return clauses; } @@ -31522,12 +32214,19 @@ cp_parser_omp_barrier (cp_parser *parser, cp_token *pragma_tok) /* OpenMP 2.5: # pragma omp critical [(name)] new-line + structured-block + + OpenMP 4.5: + # pragma omp critical [(name) [hint(expression)]] new-line structured-block */ +#define OMP_CRITICAL_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_HINT) ) + static tree cp_parser_omp_critical (cp_parser *parser, cp_token *pragma_tok) { - tree stmt, name = NULL; + tree stmt, name = NULL_TREE, clauses = NULL_TREE; if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) { @@ -31542,11 +32241,16 @@ cp_parser_omp_critical (cp_parser *parser, cp_token *pragma_tok) /*consume_paren=*/true); if (name == error_mark_node) name = NULL; + + clauses = cp_parser_omp_all_clauses (parser, + OMP_CRITICAL_CLAUSE_MASK, + "#pragma omp critical", pragma_tok); } - cp_parser_require_pragma_eol (parser, pragma_tok); + else + cp_parser_require_pragma_eol (parser, pragma_tok); stmt = cp_parser_omp_structured_block (parser); - return c_finish_omp_critical (input_location, stmt, name); + return c_finish_omp_critical (input_location, stmt, name, clauses); } /* OpenMP 2.5: @@ -31624,13 +32328,15 @@ cp_parser_omp_for_incr (cp_parser *parser, tree decl) ? PREINCREMENT_EXPR : PREDECREMENT_EXPR); cp_lexer_consume_token (parser->lexer); lhs = cp_parser_simple_cast_expression (parser); - if (lhs != decl) + if (lhs != decl + && (!processing_template_decl || !cp_tree_equal (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) + if (lhs != decl + && (!processing_template_decl || !cp_tree_equal (lhs, decl))) return error_mark_node; token = cp_lexer_peek_token (parser->lexer); @@ -31656,7 +32362,8 @@ cp_parser_omp_for_incr (cp_parser *parser, tree decl) lhs = cp_parser_binary_expression (parser, false, false, PREC_ADDITIVE_EXPRESSION, NULL); token = cp_lexer_peek_token (parser->lexer); - decl_first = lhs == decl; + decl_first = (lhs == decl + || (processing_template_decl && cp_tree_equal (lhs, decl))); if (decl_first) lhs = NULL_TREE; if (token->type != CPP_PLUS @@ -31689,7 +32396,9 @@ cp_parser_omp_for_incr (cp_parser *parser, tree decl) if (!decl_first) { - if (rhs != decl || op == MINUS_EXPR) + if ((rhs != decl + && (!processing_template_decl || !cp_tree_equal (rhs, decl))) + || op == MINUS_EXPR) return error_mark_node; rhs = build2 (op, TREE_TYPE (decl), lhs, decl); } @@ -31705,7 +32414,7 @@ cp_parser_omp_for_incr (cp_parser *parser, tree decl) Return true if the resulting construct should have an OMP_CLAUSE_PRIVATE added to it. */ -static bool +static tree cp_parser_omp_for_loop_init (cp_parser *parser, enum tree_code code, tree &this_pre_body, @@ -31715,9 +32424,9 @@ cp_parser_omp_for_loop_init (cp_parser *parser, tree &real_decl) { if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) - return false; + return NULL_TREE; - bool add_private_clause = false; + tree add_private_clause = NULL_TREE; /* See 2.5.1 (in OpenMP 3.0, similar wording is in 2.5 standard too): @@ -31848,6 +32557,33 @@ cp_parser_omp_for_loop_init (cp_parser *parser, cp_parser_parse_tentatively (parser); decl = cp_parser_primary_expression (parser, false, false, false, &idk); + cp_token *last_tok = cp_lexer_peek_token (parser->lexer); + if (!cp_parser_error_occurred (parser) + && decl + && (TREE_CODE (decl) == COMPONENT_REF + || (TREE_CODE (decl) == SCOPE_REF && TREE_TYPE (decl)))) + { + cp_parser_abort_tentative_parse (parser); + cp_parser_parse_tentatively (parser); + cp_token *token = cp_lexer_peek_token (parser->lexer); + tree name = cp_parser_id_expression (parser, /*template_p=*/false, + /*check_dependency_p=*/true, + /*template_p=*/NULL, + /*declarator_p=*/false, + /*optional_p=*/false); + if (name != error_mark_node + && last_tok == cp_lexer_peek_token (parser->lexer)) + { + decl = cp_parser_lookup_name_simple (parser, name, + token->location); + if (TREE_CODE (decl) == FIELD_DECL) + add_private_clause = omp_privatize_field (decl); + } + cp_parser_abort_tentative_parse (parser); + 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) @@ -31862,7 +32598,8 @@ cp_parser_omp_for_loop_init (cp_parser *parser, decl, NOP_EXPR, rhs, tf_warning_or_error)); - add_private_clause = true; + if (!add_private_clause) + add_private_clause = decl; } else { @@ -31888,29 +32625,58 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, { tree init, cond, incr, body, decl, pre_body = NULL_TREE, ret; tree real_decl, initv, condv, incrv, declv; - tree this_pre_body, cl; + tree this_pre_body, cl, ordered_cl = NULL_TREE; location_t loc_first; bool collapse_err = false; - int i, collapse = 1, nbraces = 0; + int i, collapse = 1, ordered = 0, count, nbraces = 0; vec *for_block = make_tree_vector (); for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl)) if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_COLLAPSE) collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (cl)); + else if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_ORDERED + && OMP_CLAUSE_ORDERED_EXPR (cl)) + { + ordered_cl = cl; + ordered = tree_to_shwi (OMP_CLAUSE_ORDERED_EXPR (cl)); + } + + if (ordered && ordered < collapse) + { + error_at (OMP_CLAUSE_LOCATION (ordered_cl), + "% clause parameter is less than %"); + OMP_CLAUSE_ORDERED_EXPR (ordered_cl) + = build_int_cst (NULL_TREE, collapse); + ordered = collapse; + } + if (ordered) + { + for (tree *pc = &clauses; *pc; ) + if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_LINEAR) + { + error_at (OMP_CLAUSE_LOCATION (*pc), + "% clause may not be specified together " + "with % clause with a parameter"); + *pc = OMP_CLAUSE_CHAIN (*pc); + } + else + pc = &OMP_CLAUSE_CHAIN (*pc); + } - gcc_assert (collapse >= 1); + gcc_assert (collapse >= 1 && ordered >= 0); + count = ordered ? ordered : collapse; - declv = make_tree_vec (collapse); - initv = make_tree_vec (collapse); - condv = make_tree_vec (collapse); - incrv = make_tree_vec (collapse); + declv = make_tree_vec (count); + initv = make_tree_vec (count); + condv = make_tree_vec (count); + incrv = make_tree_vec (count); loc_first = cp_lexer_peek_token (parser->lexer)->location; - for (i = 0; i < collapse; i++) + for (i = 0; i < count; i++) { int bracecount = 0; - bool add_private_clause = false; + tree add_private_clause = NULL_TREE; location_t loc; if (code != CILK_FOR @@ -31934,9 +32700,9 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, this_pre_body = push_stmt_list (); add_private_clause - |= cp_parser_omp_for_loop_init (parser, code, - this_pre_body, for_block, - init, decl, real_decl); + = cp_parser_omp_for_loop_init (parser, code, + this_pre_body, for_block, + init, decl, real_decl); cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); if (this_pre_body) @@ -31985,13 +32751,13 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, OMP_CLAUSE_CHAIN (l) = clauses; clauses = l; } - add_private_clause = false; + add_private_clause = NULL_TREE; } else { if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_PRIVATE && OMP_CLAUSE_DECL (*c) == real_decl) - add_private_clause = false; + add_private_clause = NULL_TREE; c = &OMP_CLAUSE_CHAIN (*c); } } @@ -32017,13 +32783,22 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, } if (c == NULL) { - c = build_omp_clause (loc, OMP_CLAUSE_PRIVATE); - OMP_CLAUSE_DECL (c) = decl; - c = finish_omp_clauses (c); + if (code != OMP_SIMD) + c = build_omp_clause (loc, OMP_CLAUSE_PRIVATE); + else if (collapse == 1) + c = build_omp_clause (loc, OMP_CLAUSE_LINEAR); + else + c = build_omp_clause (loc, OMP_CLAUSE_LASTPRIVATE); + OMP_CLAUSE_DECL (c) = add_private_clause; + c = finish_omp_clauses (c, true); if (c) { OMP_CLAUSE_CHAIN (c) = clauses; clauses = c; + /* For linear, signal that we need to fill up + the so far unknown linear step. */ + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR) + OMP_CLAUSE_LINEAR_STEP (c) = NULL_TREE; } } } @@ -32040,7 +32815,8 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, until finish_omp_for. */ if (real_decl && ((processing_template_decl - && !POINTER_TYPE_P (TREE_TYPE (real_decl))) + && (TREE_TYPE (real_decl) == NULL_TREE + || !POINTER_TYPE_P (TREE_TYPE (real_decl)))) || CLASS_TYPE_P (TREE_TYPE (real_decl)))) incr = cp_parser_omp_for_incr (parser, real_decl); else @@ -32059,7 +32835,7 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, TREE_VEC_ELT (condv, i) = cond; TREE_VEC_ELT (incrv, i) = incr; - if (i == collapse - 1) + if (i == count - 1) break; /* FIXME: OpenMP 3.0 draft isn't very clear on what exactly is allowed @@ -32114,8 +32890,8 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, if (declv == NULL_TREE) ret = NULL_TREE; else - ret = finish_omp_for (loc_first, code, declv, initv, condv, incrv, body, - pre_body, clauses); + ret = finish_omp_for (loc_first, code, declv, NULL, initv, condv, incrv, + body, pre_body, clauses); while (nbraces) { @@ -32158,7 +32934,7 @@ cp_omp_split_clauses (location_t loc, enum tree_code code, c_omp_split_clauses (loc, code, mask, clauses, cclauses); for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++) if (cclauses[i]) - cclauses[i] = finish_omp_clauses (cclauses[i]); + cclauses[i] = finish_omp_clauses (cclauses[i], true); } /* OpenMP 4.0: @@ -32167,6 +32943,7 @@ cp_omp_split_clauses (location_t loc, enum tree_code code, #define OMP_SIMD_CLAUSE_MASK \ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SAFELEN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMDLEN) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ @@ -32184,7 +32961,6 @@ cp_parser_omp_simd (cp_parser *parser, cp_token *pragma_tok, strcat (p_name, " simd"); mask |= OMP_SIMD_CLAUSE_MASK; - mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED); clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok, cclauses == NULL); @@ -32192,6 +32968,15 @@ cp_parser_omp_simd (cp_parser *parser, cp_token *pragma_tok, { cp_omp_split_clauses (loc, OMP_SIMD, mask, clauses, cclauses); clauses = cclauses[C_OMP_CLAUSE_SPLIT_SIMD]; + tree c = find_omp_clause (cclauses[C_OMP_CLAUSE_SPLIT_FOR], + OMP_CLAUSE_ORDERED); + if (c && OMP_CLAUSE_ORDERED_EXPR (c)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% clause with parameter may not be specified " + "on %qs construct", p_name); + OMP_CLAUSE_ORDERED_EXPR (c) = NULL_TREE; + } } sb = begin_omp_structured_block (); @@ -32217,6 +33002,7 @@ cp_parser_omp_simd (cp_parser *parser, cp_token *pragma_tok, ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE) \ @@ -32235,6 +33021,9 @@ cp_parser_omp_for (cp_parser *parser, cp_token *pragma_tok, mask |= OMP_FOR_CLAUSE_MASK; if (cclauses) mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); + /* Composite distribute parallel for{, simd} disallows ordered clause. */ + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) != 0) + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED); if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { @@ -32274,6 +33063,10 @@ cp_parser_omp_for (cp_parser *parser, cp_token *pragma_tok, return NULL_TREE; } + /* Composite distribute parallel for disallows linear clause. */ + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) != 0) + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR); + clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok, cclauses == NULL); if (cclauses) @@ -32307,14 +33100,62 @@ cp_parser_omp_master (cp_parser *parser, cp_token *pragma_tok) /* OpenMP 2.5: # pragma omp ordered new-line + structured-block + + OpenMP 4.5: + # pragma omp ordered ordered-clauses new-line structured-block */ -static tree -cp_parser_omp_ordered (cp_parser *parser, cp_token *pragma_tok) +#define OMP_ORDERED_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREADS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMD)) + +#define OMP_ORDERED_DEPEND_CLAUSE_MASK \ + (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) + +static bool +cp_parser_omp_ordered (cp_parser *parser, cp_token *pragma_tok, + enum pragma_context context) { - location_t loc = cp_lexer_peek_token (parser->lexer)->location; - cp_parser_require_pragma_eol (parser, pragma_tok); - return c_finish_omp_ordered (loc, cp_parser_omp_structured_block (parser)); + location_t loc = pragma_tok->location; + + if (context != pragma_stmt && context != pragma_compound) + { + cp_parser_error (parser, "expected declaration specifiers"); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return false; + } + + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + + if (strcmp (p, "depend") == 0) + { + if (context == pragma_stmt) + { + error_at (pragma_tok->location, "%<#pragma omp ordered%> with " + "% clause may only be used in compound " + "statements"); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return false; + } + tree clauses + = cp_parser_omp_all_clauses (parser, + OMP_ORDERED_DEPEND_CLAUSE_MASK, + "#pragma omp ordered", pragma_tok); + c_finish_omp_ordered (loc, clauses, NULL_TREE); + return false; + } + } + + tree clauses + = cp_parser_omp_all_clauses (parser, OMP_ORDERED_CLAUSE_MASK, + "#pragma omp ordered", pragma_tok); + c_finish_omp_ordered (loc, clauses, + cp_parser_omp_structured_block (parser)); + return true; } /* OpenMP 2.5: @@ -32452,6 +33293,10 @@ cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok, strcat (p_name, " parallel"); mask |= OMP_PARALLEL_CLAUSE_MASK; + /* #pragma omp target parallel{, for, for simd} disallow copyin clause. */ + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)) != 0 + && (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) == 0) + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYIN); if (cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR)) { @@ -32473,7 +33318,11 @@ cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok, OMP_PARALLEL_COMBINED (stmt) = 1; return stmt; } - else if (cclauses) + /* When combined with distribute, parallel has to be followed by for. + #pragma omp target parallel is allowed though. */ + else if (cclauses + && (mask & (OMP_CLAUSE_MASK_1 + << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) != 0) { error_at (loc, "expected % after %qs", p_name); cp_parser_skip_to_pragma_eol (parser, pragma_tok); @@ -32484,7 +33333,7 @@ cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok, cp_parser_skip_to_pragma_eol (parser, pragma_tok); return NULL_TREE; } - else if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + else if (cclauses == NULL && cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { tree id = cp_lexer_peek_token (parser->lexer)->u.value; const char *p = IDENTIFIER_POINTER (id); @@ -32506,6 +33355,11 @@ cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok, } clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok); + if (cclauses) + { + cp_omp_split_clauses (loc, OMP_PARALLEL, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; + } block = begin_omp_parallel (); save = cp_parser_begin_omp_structured_block (parser); @@ -32552,7 +33406,8 @@ cp_parser_omp_single (cp_parser *parser, cp_token *pragma_tok) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FINAL) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)) + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY)) static tree cp_parser_omp_task (cp_parser *parser, cp_token *pragma_tok) @@ -32780,91 +33635,305 @@ cp_parser_omp_distribute (cp_parser *parser, cp_token *pragma_tok, | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT)) -static tree -cp_parser_omp_teams (cp_parser *parser, cp_token *pragma_tok, - char *p_name, omp_clause_mask mask, tree *cclauses) -{ - tree clauses, sb, ret; - unsigned int save; - location_t loc = cp_lexer_peek_token (parser->lexer)->location; +static tree +cp_parser_omp_teams (cp_parser *parser, cp_token *pragma_tok, + char *p_name, omp_clause_mask mask, tree *cclauses) +{ + tree clauses, sb, ret; + unsigned int save; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + + strcat (p_name, " teams"); + mask |= OMP_TEAMS_CLAUSE_MASK; + + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + if (strcmp (p, "distribute") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + + cp_lexer_consume_token (parser->lexer); + if (!flag_openmp) /* flag_openmp_simd */ + return cp_parser_omp_distribute (parser, pragma_tok, p_name, mask, + cclauses); + sb = begin_omp_structured_block (); + save = cp_parser_begin_omp_structured_block (parser); + ret = cp_parser_omp_distribute (parser, pragma_tok, p_name, mask, + cclauses); + cp_parser_end_omp_structured_block (parser, save); + tree body = finish_omp_structured_block (sb); + if (ret == NULL) + return ret; + clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; + ret = make_node (OMP_TEAMS); + TREE_TYPE (ret) = void_type_node; + OMP_TEAMS_CLAUSES (ret) = clauses; + OMP_TEAMS_BODY (ret) = body; + OMP_TEAMS_COMBINED (ret) = 1; + return add_stmt (ret); + } + } + if (!flag_openmp) /* flag_openmp_simd */ + { + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return NULL_TREE; + } + + clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok, + cclauses == NULL); + if (cclauses) + { + cp_omp_split_clauses (loc, OMP_TEAMS, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; + } + + tree stmt = make_node (OMP_TEAMS); + TREE_TYPE (stmt) = void_type_node; + OMP_TEAMS_CLAUSES (stmt) = clauses; + OMP_TEAMS_BODY (stmt) = cp_parser_omp_structured_block (parser); + + return add_stmt (stmt); +} + +/* OpenMP 4.0: + # pragma omp target data target-data-clause[optseq] new-line + structured-block */ + +#define OMP_TARGET_DATA_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR)) + +static tree +cp_parser_omp_target_data (cp_parser *parser, cp_token *pragma_tok) +{ + tree clauses + = cp_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK, + "#pragma omp target data", pragma_tok); + int map_seen = 0; + for (tree *pc = &clauses; *pc;) + { + if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP) + switch (OMP_CLAUSE_MAP_KIND (*pc)) + { + case GOMP_MAP_TO: + case GOMP_MAP_ALWAYS_TO: + case GOMP_MAP_FROM: + case GOMP_MAP_ALWAYS_FROM: + case GOMP_MAP_TOFROM: + case GOMP_MAP_ALWAYS_TOFROM: + case GOMP_MAP_ALLOC: + map_seen = 3; + break; + case GOMP_MAP_FIRSTPRIVATE_POINTER: + break; + default: + map_seen |= 1; + error_at (OMP_CLAUSE_LOCATION (*pc), + "%<#pragma omp target data%> with map-type other " + "than %, %, % or % " + "on % clause"); + *pc = OMP_CLAUSE_CHAIN (*pc); + continue; + } + pc = &OMP_CLAUSE_CHAIN (*pc); + } + + if (map_seen != 3) + { + if (map_seen == 0) + error_at (pragma_tok->location, + "%<#pragma omp target data%> must contain at least " + "one % clause"); + return NULL_TREE; + } + + tree stmt = make_node (OMP_TARGET_DATA); + TREE_TYPE (stmt) = void_type_node; + OMP_TARGET_DATA_CLAUSES (stmt) = clauses; + + keep_next_level (true); + OMP_TARGET_DATA_BODY (stmt) = cp_parser_omp_structured_block (parser); + + SET_EXPR_LOCATION (stmt, pragma_tok->location); + return add_stmt (stmt); +} + +/* OpenMP 4.5: + # pragma omp target enter data target-enter-data-clause[optseq] new-line + structured-block */ - strcat (p_name, " teams"); - mask |= OMP_TEAMS_CLAUSE_MASK; +#define OMP_TARGET_ENTER_DATA_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) +static tree +cp_parser_omp_target_enter_data (cp_parser *parser, cp_token *pragma_tok, + enum pragma_context context) +{ + bool data_seen = false; if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { tree id = cp_lexer_peek_token (parser->lexer)->u.value; const char *p = IDENTIFIER_POINTER (id); - if (strcmp (p, "distribute") == 0) - { - tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; - if (cclauses == NULL) - cclauses = cclauses_buf; + if (strcmp (p, "data") == 0) + { cp_lexer_consume_token (parser->lexer); - if (!flag_openmp) /* flag_openmp_simd */ - return cp_parser_omp_distribute (parser, pragma_tok, p_name, mask, - cclauses); - sb = begin_omp_structured_block (); - save = cp_parser_begin_omp_structured_block (parser); - ret = cp_parser_omp_distribute (parser, pragma_tok, p_name, mask, - cclauses); - cp_parser_end_omp_structured_block (parser, save); - tree body = finish_omp_structured_block (sb); - if (ret == NULL) - return ret; - clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; - ret = make_node (OMP_TEAMS); - TREE_TYPE (ret) = void_type_node; - OMP_TEAMS_CLAUSES (ret) = clauses; - OMP_TEAMS_BODY (ret) = body; - OMP_TEAMS_COMBINED (ret) = 1; - return add_stmt (ret); + data_seen = true; } } - if (!flag_openmp) /* flag_openmp_simd */ + if (!data_seen) { + cp_parser_error (parser, "expected %"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); return NULL_TREE; } - clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok, - cclauses == NULL); - if (cclauses) + if (context == pragma_stmt) { - cp_omp_split_clauses (loc, OMP_TEAMS, mask, clauses, cclauses); - clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; + error_at (pragma_tok->location, + "%<#pragma omp target enter data%> may only be " + "used in compound statements"); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return NULL_TREE; } - tree stmt = make_node (OMP_TEAMS); - TREE_TYPE (stmt) = void_type_node; - OMP_TEAMS_CLAUSES (stmt) = clauses; - OMP_TEAMS_BODY (stmt) = cp_parser_omp_structured_block (parser); + tree clauses + = cp_parser_omp_all_clauses (parser, OMP_TARGET_ENTER_DATA_CLAUSE_MASK, + "#pragma omp target enter data", pragma_tok); + int map_seen = 0; + for (tree *pc = &clauses; *pc;) + { + if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP) + switch (OMP_CLAUSE_MAP_KIND (*pc)) + { + case GOMP_MAP_TO: + case GOMP_MAP_ALWAYS_TO: + case GOMP_MAP_ALLOC: + map_seen = 3; + break; + case GOMP_MAP_FIRSTPRIVATE_POINTER: + break; + default: + map_seen |= 1; + error_at (OMP_CLAUSE_LOCATION (*pc), + "%<#pragma omp target enter data%> with map-type other " + "than % or % on % clause"); + *pc = OMP_CLAUSE_CHAIN (*pc); + continue; + } + pc = &OMP_CLAUSE_CHAIN (*pc); + } + + if (map_seen != 3) + { + if (map_seen == 0) + error_at (pragma_tok->location, + "%<#pragma omp target enter data%> must contain at least " + "one % clause"); + return NULL_TREE; + } + tree stmt = make_node (OMP_TARGET_ENTER_DATA); + TREE_TYPE (stmt) = void_type_node; + OMP_TARGET_ENTER_DATA_CLAUSES (stmt) = clauses; + SET_EXPR_LOCATION (stmt, pragma_tok->location); return add_stmt (stmt); } -/* OpenMP 4.0: - # pragma omp target data target-data-clause[optseq] new-line +/* OpenMP 4.5: + # pragma omp target exit data target-enter-data-clause[optseq] new-line structured-block */ -#define OMP_TARGET_DATA_CLAUSE_MASK \ +#define OMP_TARGET_EXIT_DATA_CLAUSE_MASK \ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)) + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) static tree -cp_parser_omp_target_data (cp_parser *parser, cp_token *pragma_tok) +cp_parser_omp_target_exit_data (cp_parser *parser, cp_token *pragma_tok, + enum pragma_context context) { - tree stmt = make_node (OMP_TARGET_DATA); - TREE_TYPE (stmt) = void_type_node; + bool data_seen = false; + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); - OMP_TARGET_DATA_CLAUSES (stmt) - = cp_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK, - "#pragma omp target data", pragma_tok); - keep_next_level (true); - OMP_TARGET_DATA_BODY (stmt) = cp_parser_omp_structured_block (parser); + if (strcmp (p, "data") == 0) + { + cp_lexer_consume_token (parser->lexer); + data_seen = true; + } + } + if (!data_seen) + { + cp_parser_error (parser, "expected %"); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return NULL_TREE; + } + + if (context == pragma_stmt) + { + error_at (pragma_tok->location, + "%<#pragma omp target exit data%> may only be " + "used in compound statements"); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return NULL_TREE; + } + + tree clauses + = cp_parser_omp_all_clauses (parser, OMP_TARGET_EXIT_DATA_CLAUSE_MASK, + "#pragma omp target exit data", pragma_tok); + int map_seen = 0; + for (tree *pc = &clauses; *pc;) + { + if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP) + switch (OMP_CLAUSE_MAP_KIND (*pc)) + { + case GOMP_MAP_FROM: + case GOMP_MAP_ALWAYS_FROM: + case GOMP_MAP_RELEASE: + case GOMP_MAP_DELETE: + map_seen = 3; + break; + case GOMP_MAP_FIRSTPRIVATE_POINTER: + break; + default: + map_seen |= 1; + error_at (OMP_CLAUSE_LOCATION (*pc), + "%<#pragma omp target exit data%> with map-type other " + "than %, % or % on %" + " clause"); + *pc = OMP_CLAUSE_CHAIN (*pc); + continue; + } + pc = &OMP_CLAUSE_CHAIN (*pc); + } + + if (map_seen != 3) + { + if (map_seen == 0) + error_at (pragma_tok->location, + "%<#pragma omp target exit data%> must contain at least " + "one % clause"); + return NULL_TREE; + } + tree stmt = make_node (OMP_TARGET_EXIT_DATA); + TREE_TYPE (stmt) = void_type_node; + OMP_TARGET_EXIT_DATA_CLAUSES (stmt) = clauses; SET_EXPR_LOCATION (stmt, pragma_tok->location); return add_stmt (stmt); } @@ -32876,7 +33945,9 @@ cp_parser_omp_target_data (cp_parser *parser, cp_token *pragma_tok) ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FROM) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TO) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)) + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) static bool cp_parser_omp_target_update (cp_parser *parser, cp_token *pragma_tok, @@ -32918,12 +33989,20 @@ cp_parser_omp_target_update (cp_parser *parser, cp_token *pragma_tok, #define OMP_TARGET_CLAUSE_MASK \ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)) + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULTMAP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR)) static bool cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok, enum pragma_context context) { + tree *pc = NULL, stmt; + if (context != pragma_stmt && context != pragma_compound) { cp_parser_error (parser, "expected declaration specifiers"); @@ -32935,8 +34014,15 @@ cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok, { tree id = cp_lexer_peek_token (parser->lexer)->u.value; const char *p = IDENTIFIER_POINTER (id); + enum tree_code ccode = ERROR_MARK; if (strcmp (p, "teams") == 0) + ccode = OMP_TEAMS; + else if (strcmp (p, "parallel") == 0) + ccode = OMP_PARALLEL; + else if (strcmp (p, "simd") == 0) + ccode = OMP_SIMD; + if (ccode != ERROR_MARK) { tree cclauses[C_OMP_CLAUSE_SPLIT_COUNT]; char p_name[sizeof ("#pragma omp target teams distribute " @@ -32946,16 +34032,49 @@ cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok, strcpy (p_name, "#pragma omp target"); if (!flag_openmp) /* flag_openmp_simd */ { - tree stmt = cp_parser_omp_teams (parser, pragma_tok, p_name, - OMP_TARGET_CLAUSE_MASK, - cclauses); + tree stmt; + switch (ccode) + { + case OMP_TEAMS: + stmt = cp_parser_omp_teams (parser, pragma_tok, p_name, + OMP_TARGET_CLAUSE_MASK, + cclauses); + break; + case OMP_PARALLEL: + stmt = cp_parser_omp_parallel (parser, pragma_tok, p_name, + OMP_TARGET_CLAUSE_MASK, + cclauses); + break; + case OMP_SIMD: + stmt = cp_parser_omp_simd (parser, pragma_tok, p_name, + OMP_TARGET_CLAUSE_MASK, + cclauses); + break; + default: + gcc_unreachable (); + } return stmt != NULL_TREE; } keep_next_level (true); - tree sb = begin_omp_structured_block (); + tree sb = begin_omp_structured_block (), ret; unsigned save = cp_parser_begin_omp_structured_block (parser); - tree ret = cp_parser_omp_teams (parser, pragma_tok, p_name, - OMP_TARGET_CLAUSE_MASK, cclauses); + switch (ccode) + { + case OMP_TEAMS: + ret = cp_parser_omp_teams (parser, pragma_tok, p_name, + OMP_TARGET_CLAUSE_MASK, cclauses); + break; + case OMP_PARALLEL: + ret = cp_parser_omp_parallel (parser, pragma_tok, p_name, + OMP_TARGET_CLAUSE_MASK, cclauses); + break; + case OMP_SIMD: + ret = cp_parser_omp_simd (parser, pragma_tok, p_name, + OMP_TARGET_CLAUSE_MASK, cclauses); + break; + default: + gcc_unreachable (); + } cp_parser_end_omp_structured_block (parser, save); tree body = finish_omp_structured_block (sb); if (ret == NULL_TREE) @@ -32964,8 +34083,10 @@ cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok, TREE_TYPE (stmt) = void_type_node; OMP_TARGET_CLAUSES (stmt) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET]; OMP_TARGET_BODY (stmt) = body; + OMP_TARGET_COMBINED (stmt) = 1; add_stmt (stmt); - return true; + pc = &OMP_TARGET_CLAUSES (stmt); + goto check_clauses; } else if (!flag_openmp) /* flag_openmp_simd */ { @@ -32978,6 +34099,18 @@ cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok, cp_parser_omp_target_data (parser, pragma_tok); return true; } + else if (strcmp (p, "enter") == 0) + { + cp_lexer_consume_token (parser->lexer); + cp_parser_omp_target_enter_data (parser, pragma_tok, context); + return false; + } + else if (strcmp (p, "exit") == 0) + { + cp_lexer_consume_token (parser->lexer); + cp_parser_omp_target_exit_data (parser, pragma_tok, context); + return false; + } else if (strcmp (p, "update") == 0) { cp_lexer_consume_token (parser->lexer); @@ -32985,17 +34118,44 @@ cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok, } } - tree stmt = make_node (OMP_TARGET); + stmt = make_node (OMP_TARGET); TREE_TYPE (stmt) = void_type_node; OMP_TARGET_CLAUSES (stmt) = cp_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK, "#pragma omp target", pragma_tok); + pc = &OMP_TARGET_CLAUSES (stmt); keep_next_level (true); OMP_TARGET_BODY (stmt) = cp_parser_omp_structured_block (parser); SET_EXPR_LOCATION (stmt, pragma_tok->location); add_stmt (stmt); + +check_clauses: + while (*pc) + { + if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP) + switch (OMP_CLAUSE_MAP_KIND (*pc)) + { + case GOMP_MAP_TO: + case GOMP_MAP_ALWAYS_TO: + case GOMP_MAP_FROM: + case GOMP_MAP_ALWAYS_FROM: + case GOMP_MAP_TOFROM: + case GOMP_MAP_ALWAYS_TOFROM: + case GOMP_MAP_ALLOC: + case GOMP_MAP_FIRSTPRIVATE_POINTER: + break; + default: + error_at (OMP_CLAUSE_LOCATION (*pc), + "%<#pragma omp target%> with map-type other " + "than %, %, % or % " + "on % clause"); + *pc = OMP_CLAUSE_CHAIN (*pc); + continue; + } + pc = &OMP_CLAUSE_CHAIN (*pc); + } return true; } @@ -33009,7 +34169,7 @@ cp_parser_oacc_cache (cp_parser *parser, cp_token *pragma_tok) tree stmt, clauses; clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE__CACHE_, NULL_TREE); - clauses = finish_omp_clauses (clauses); + clauses = finish_omp_clauses (clauses, false); cp_parser_require_pragma_eol (parser, cp_lexer_peek_token (parser->lexer)); @@ -33463,13 +34623,65 @@ cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs) /* OpenMP 4.0: # pragma omp declare target new-line declarations and definitions - # pragma omp end declare target new-line */ + # pragma omp end declare target new-line + + OpenMP 4.5: + # pragma omp declare target ( extended-list ) new-line + + # pragma omp declare target declare-target-clauses[seq] new-line */ + +#define OMP_DECLARE_TARGET_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TO) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINK)) static void cp_parser_omp_declare_target (cp_parser *parser, cp_token *pragma_tok) { - cp_parser_skip_to_pragma_eol (parser, pragma_tok); - scope_chain->omp_declare_target_attribute++; + tree clauses = NULL_TREE; + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + clauses + = cp_parser_omp_all_clauses (parser, OMP_DECLARE_TARGET_CLAUSE_MASK, + "#pragma omp declare target", pragma_tok); + else if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) + { + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_TO_DECLARE, + clauses); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + } + else + { + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + scope_chain->omp_declare_target_attribute++; + return; + } + if (scope_chain->omp_declare_target_attribute) + error_at (pragma_tok->location, + "%<#pragma omp declare target%> with clauses in between " + "%<#pragma omp declare target%> without clauses and " + "%<#pragma omp end declare target%>"); + for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) + { + tree t = OMP_CLAUSE_DECL (c), id; + tree at1 = lookup_attribute ("omp declare target", DECL_ATTRIBUTES (t)); + tree at2 = lookup_attribute ("omp declare target link", + DECL_ATTRIBUTES (t)); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINK) + { + id = get_identifier ("omp declare target link"); + std::swap (at1, at2); + } + else + id = get_identifier ("omp declare target"); + if (at2) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD specified both in declare target % and %" + " clauses", t); + continue; + } + if (!at1) + DECL_ATTRIBUTES (t) = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (t)); + } } static void @@ -33957,6 +35169,97 @@ cp_parser_omp_declare (cp_parser *parser, cp_token *pragma_tok, cp_parser_require_pragma_eol (parser, pragma_tok); } +/* OpenMP 4.5: + #pragma omp taskloop taskloop-clause[optseq] new-line + for-loop + + #pragma omp taskloop simd taskloop-simd-clause[optseq] new-line + for-loop */ + +#define OMP_TASKLOOP_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_GRAINSIZE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TASKS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNTIED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FINAL) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOGROUP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY)) + +static tree +cp_parser_omp_taskloop (cp_parser *parser, cp_token *pragma_tok, + char *p_name, omp_clause_mask mask, tree *cclauses) +{ + tree clauses, sb, ret; + unsigned int save; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + + strcat (p_name, " taskloop"); + mask |= OMP_TASKLOOP_CLAUSE_MASK; + + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + + if (strcmp (p, "simd") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + + cp_lexer_consume_token (parser->lexer); + if (!flag_openmp) /* flag_openmp_simd */ + return cp_parser_omp_simd (parser, pragma_tok, p_name, mask, + cclauses); + sb = begin_omp_structured_block (); + save = cp_parser_begin_omp_structured_block (parser); + ret = cp_parser_omp_simd (parser, pragma_tok, p_name, mask, + cclauses); + cp_parser_end_omp_structured_block (parser, save); + tree body = finish_omp_structured_block (sb); + if (ret == NULL) + return ret; + ret = make_node (OMP_TASKLOOP); + TREE_TYPE (ret) = void_type_node; + OMP_FOR_BODY (ret) = body; + OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_TASKLOOP]; + SET_EXPR_LOCATION (ret, loc); + add_stmt (ret); + return ret; + } + } + if (!flag_openmp) /* flag_openmp_simd */ + { + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return NULL_TREE; + } + + clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok, + cclauses == NULL); + if (cclauses) + { + cp_omp_split_clauses (loc, OMP_TASKLOOP, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_TASKLOOP]; + } + + sb = begin_omp_structured_block (); + save = cp_parser_begin_omp_structured_block (parser); + + ret = cp_parser_omp_for_loop (parser, OMP_TASKLOOP, clauses, cclauses); + + cp_parser_end_omp_structured_block (parser, save); + add_stmt (finish_omp_structured_block (sb)); + + return ret; +} + /* Main entry point to OpenMP statement pragmas. */ static void @@ -34012,9 +35315,6 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok) case PRAGMA_OMP_MASTER: stmt = cp_parser_omp_master (parser, pragma_tok); break; - case PRAGMA_OMP_ORDERED: - stmt = cp_parser_omp_ordered (parser, pragma_tok); - break; case PRAGMA_OMP_PARALLEL: strcpy (p_name, "#pragma omp"); stmt = cp_parser_omp_parallel (parser, pragma_tok, p_name, mask, NULL); @@ -34036,6 +35336,10 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok) case PRAGMA_OMP_TASKGROUP: stmt = cp_parser_omp_taskgroup (parser, pragma_tok); break; + case PRAGMA_OMP_TASKLOOP: + strcpy (p_name, "#pragma omp"); + stmt = cp_parser_omp_taskloop (parser, pragma_tok, p_name, mask, NULL); + break; case PRAGMA_OMP_TEAMS: strcpy (p_name, "#pragma omp"); stmt = cp_parser_omp_teams (parser, pragma_tok, p_name, mask, NULL); @@ -34424,6 +35728,8 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context) { cp_token *pragma_tok; unsigned int id; + tree stmt; + bool ret; pragma_tok = cp_lexer_consume_token (parser->lexer); gcc_assert (pragma_tok->type == CPP_PRAGMA); @@ -34555,21 +35861,32 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context) case PRAGMA_OMP_DISTRIBUTE: case PRAGMA_OMP_FOR: case PRAGMA_OMP_MASTER: - case PRAGMA_OMP_ORDERED: case PRAGMA_OMP_PARALLEL: case PRAGMA_OMP_SECTIONS: case PRAGMA_OMP_SIMD: case PRAGMA_OMP_SINGLE: case PRAGMA_OMP_TASK: case PRAGMA_OMP_TASKGROUP: + case PRAGMA_OMP_TASKLOOP: case PRAGMA_OMP_TEAMS: if (context != pragma_stmt && context != pragma_compound) goto bad_stmt; + stmt = push_omp_privatization_clauses (false); cp_parser_omp_construct (parser, pragma_tok); + pop_omp_privatization_clauses (stmt); return true; + case PRAGMA_OMP_ORDERED: + stmt = push_omp_privatization_clauses (false); + ret = cp_parser_omp_ordered (parser, pragma_tok, context); + pop_omp_privatization_clauses (stmt); + return ret; + case PRAGMA_OMP_TARGET: - return cp_parser_omp_target (parser, pragma_tok, context); + stmt = push_omp_privatization_clauses (false); + ret = cp_parser_omp_target (parser, pragma_tok, context); + pop_omp_privatization_clauses (stmt); + return ret; case PRAGMA_OMP_END_DECLARE_TARGET: cp_parser_omp_end_declare_target (parser, pragma_tok); @@ -34610,7 +35927,9 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context) "%<#pragma simd%> must be inside a function"); break; } + stmt = push_omp_privatization_clauses (false); cp_parser_cilk_simd (parser, pragma_tok); + pop_omp_privatization_clauses (stmt); return true; case PRAGMA_CILK_GRAINSIZE: @@ -34990,7 +36309,7 @@ cp_parser_cilk_for (cp_parser *parser, tree grain) tree clauses = build_omp_clause (EXPR_LOCATION (grain), OMP_CLAUSE_SCHEDULE); OMP_CLAUSE_SCHEDULE_KIND (clauses) = OMP_CLAUSE_SCHEDULE_CILKFOR; OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clauses) = grain; - clauses = finish_omp_clauses (clauses); + clauses = finish_omp_clauses (clauses, false); tree ret = cp_parser_omp_for_loop (parser, CILK_FOR, clauses, NULL); if (ret) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 6926557dfc6..14a5ddd9bb3 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -9519,7 +9519,7 @@ can_complete_type_without_circularity (tree type) return 1; } -static tree tsubst_omp_clauses (tree, bool, tree, tsubst_flags_t, tree); +static tree tsubst_omp_clauses (tree, bool, bool, tree, tsubst_flags_t, tree); /* Apply any attributes which had to be deferred until instantiation time. DECL_P, ATTRIBUTES and ATTR_FLAGS are as cplus_decl_attributes; @@ -9568,10 +9568,10 @@ apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags, && TREE_VALUE (t)) { tree clauses = TREE_VALUE (TREE_VALUE (t)); - clauses = tsubst_omp_clauses (clauses, true, args, + clauses = tsubst_omp_clauses (clauses, true, false, args, complain, in_decl); c_omp_declare_simd_clauses_to_decls (*decl_p, clauses); - clauses = finish_omp_clauses (clauses); + clauses = finish_omp_clauses (clauses, false, true); tree parms = DECL_ARGUMENTS (*decl_p); clauses = c_omp_declare_simd_clauses_to_numbers (parms, clauses); @@ -14290,13 +14290,21 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) } /* Helper function for tsubst_omp_clauses, used for instantiation of - OMP_CLAUSE_DECL of clauses that handles also OpenMP array sections - represented with TREE_LIST. */ + OMP_CLAUSE_DECL of clauses. */ static tree tsubst_omp_clause_decl (tree decl, tree args, tsubst_flags_t complain, tree in_decl) { + if (decl == NULL_TREE) + return NULL_TREE; + + /* Handle an OpenMP array section represented as a TREE_LIST (or + OMP_CLAUSE_DEPEND_KIND). An OMP_CLAUSE_DEPEND (with a depend + kind of OMP_CLAUSE_DEPEND_SINK) can also be represented as a + TREE_LIST. We can handle it exactly the same as an array section + (purpose, value, and a chain), even though the nomenclature + (low_bound, length, etc) is different. */ if (TREE_CODE (decl) == TREE_LIST) { tree low_bound @@ -14310,18 +14318,29 @@ tsubst_omp_clause_decl (tree decl, tree args, tsubst_flags_t complain, && TREE_VALUE (decl) == length && TREE_CHAIN (decl) == chain) return decl; - return tree_cons (low_bound, length, chain); - } - return tsubst_copy (decl, args, complain, in_decl); + tree ret = tree_cons (low_bound, length, chain); + OMP_CLAUSE_DEPEND_SINK_NEGATIVE (ret) + = OMP_CLAUSE_DEPEND_SINK_NEGATIVE (decl); + return ret; + } + tree ret = tsubst_expr (decl, args, complain, in_decl, + /*integral_constant_expression_p=*/false); + /* Undo convert_from_reference tsubst_expr could have called. */ + if (decl + && REFERENCE_REF_P (ret) + && !REFERENCE_REF_P (decl)) + ret = TREE_OPERAND (ret, 0); + return ret; } /* Like tsubst_copy, but specifically for OpenMP clauses. */ static tree -tsubst_omp_clauses (tree clauses, bool declare_simd, +tsubst_omp_clauses (tree clauses, bool declare_simd, bool allow_fields, tree args, tsubst_flags_t complain, tree in_decl) { - tree new_clauses = NULL, nc, oc; + tree new_clauses = NULL_TREE, nc, oc; + tree linear_no_step = NULL_TREE; for (oc = clauses; oc ; oc = OMP_CLAUSE_CHAIN (oc)) { @@ -14347,13 +14366,12 @@ tsubst_omp_clauses (tree clauses, bool declare_simd, case OMP_CLAUSE_COPYIN: case OMP_CLAUSE_COPYPRIVATE: case OMP_CLAUSE_UNIFORM: - OMP_CLAUSE_DECL (nc) = tsubst_copy (OMP_CLAUSE_DECL (oc), args, - complain, in_decl); - break; case OMP_CLAUSE_DEPEND: case OMP_CLAUSE_FROM: case OMP_CLAUSE_TO: case OMP_CLAUSE_MAP: + case OMP_CLAUSE_USE_DEVICE_PTR: + case OMP_CLAUSE_IS_DEVICE_PTR: OMP_CLAUSE_DECL (nc) = tsubst_omp_clause_decl (OMP_CLAUSE_DECL (oc), args, complain, in_decl); @@ -14369,6 +14387,11 @@ tsubst_omp_clauses (tree clauses, bool declare_simd, case OMP_CLAUSE_THREAD_LIMIT: case OMP_CLAUSE_SAFELEN: case OMP_CLAUSE_SIMDLEN: + case OMP_CLAUSE_NUM_TASKS: + case OMP_CLAUSE_GRAINSIZE: + case OMP_CLAUSE_PRIORITY: + case OMP_CLAUSE_ORDERED: + case OMP_CLAUSE_HINT: OMP_CLAUSE_OPERAND (nc, 0) = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 0), args, complain, in_decl, /*integral_constant_expression_p=*/false); @@ -14389,19 +14412,26 @@ tsubst_omp_clauses (tree clauses, bool declare_simd, else gcc_assert (identifier_p (placeholder)); } - OMP_CLAUSE_DECL (nc) = tsubst_copy (OMP_CLAUSE_DECL (oc), args, - complain, in_decl); + OMP_CLAUSE_DECL (nc) + = tsubst_omp_clause_decl (OMP_CLAUSE_DECL (oc), args, complain, + in_decl); break; case OMP_CLAUSE_LINEAR: case OMP_CLAUSE_ALIGNED: - OMP_CLAUSE_DECL (nc) = tsubst_copy (OMP_CLAUSE_DECL (oc), args, - complain, in_decl); + OMP_CLAUSE_DECL (nc) + = tsubst_omp_clause_decl (OMP_CLAUSE_DECL (oc), args, complain, + in_decl); OMP_CLAUSE_OPERAND (nc, 1) = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 1), args, complain, in_decl, /*integral_constant_expression_p=*/false); + if (OMP_CLAUSE_CODE (oc) == OMP_CLAUSE_LINEAR + && OMP_CLAUSE_LINEAR_STEP (oc) == NULL_TREE) + { + gcc_assert (!linear_no_step); + linear_no_step = nc; + } break; case OMP_CLAUSE_NOWAIT: - case OMP_CLAUSE_ORDERED: case OMP_CLAUSE_DEFAULT: case OMP_CLAUSE_UNTIED: case OMP_CLAUSE_MERGEABLE: @@ -14412,15 +14442,86 @@ tsubst_omp_clauses (tree clauses, bool declare_simd, case OMP_CLAUSE_PARALLEL: case OMP_CLAUSE_SECTIONS: case OMP_CLAUSE_TASKGROUP: + case OMP_CLAUSE_NOGROUP: + case OMP_CLAUSE_THREADS: + case OMP_CLAUSE_SIMD: + case OMP_CLAUSE_DEFAULTMAP: break; default: gcc_unreachable (); } + if (allow_fields) + switch (OMP_CLAUSE_CODE (nc)) + { + case OMP_CLAUSE_PRIVATE: + case OMP_CLAUSE_FIRSTPRIVATE: + case OMP_CLAUSE_LASTPRIVATE: + case OMP_CLAUSE_COPYPRIVATE: + case OMP_CLAUSE_LINEAR: + case OMP_CLAUSE_REDUCTION: + case OMP_CLAUSE_USE_DEVICE_PTR: + case OMP_CLAUSE_IS_DEVICE_PTR: + /* tsubst_expr on SCOPE_REF results in returning + finish_non_static_data_member result. Undo that here. */ + if (TREE_CODE (OMP_CLAUSE_DECL (oc)) == SCOPE_REF + && (TREE_CODE (TREE_OPERAND (OMP_CLAUSE_DECL (oc), 1)) + == IDENTIFIER_NODE)) + { + tree t = OMP_CLAUSE_DECL (nc); + tree v = t; + while (v) + switch (TREE_CODE (v)) + { + case COMPONENT_REF: + case MEM_REF: + case INDIRECT_REF: + CASE_CONVERT: + case POINTER_PLUS_EXPR: + v = TREE_OPERAND (v, 0); + continue; + case PARM_DECL: + if (DECL_CONTEXT (v) == current_function_decl + && DECL_ARTIFICIAL (v) + && DECL_NAME (v) == this_identifier) + OMP_CLAUSE_DECL (nc) = TREE_OPERAND (t, 1); + /* FALLTHRU */ + default: + v = NULL_TREE; + break; + } + } + else if (VAR_P (OMP_CLAUSE_DECL (oc)) + && DECL_HAS_VALUE_EXPR_P (OMP_CLAUSE_DECL (oc)) + && DECL_ARTIFICIAL (OMP_CLAUSE_DECL (oc)) + && DECL_LANG_SPECIFIC (OMP_CLAUSE_DECL (oc)) + && DECL_OMP_PRIVATIZED_MEMBER (OMP_CLAUSE_DECL (oc))) + { + tree decl = OMP_CLAUSE_DECL (nc); + if (VAR_P (decl)) + { + if (!DECL_LANG_SPECIFIC (decl)) + retrofit_lang_decl (decl); + DECL_OMP_PRIVATIZED_MEMBER (decl) = 1; + } + } + break; + default: + break; + } } new_clauses = nreverse (new_clauses); if (!declare_simd) - new_clauses = finish_omp_clauses (new_clauses); + { + new_clauses = finish_omp_clauses (new_clauses, allow_fields); + if (linear_no_step) + for (nc = new_clauses; nc; nc = OMP_CLAUSE_CHAIN (nc)) + if (nc == linear_no_step) + { + OMP_CLAUSE_LINEAR_STEP (nc) = NULL_TREE; + break; + } + } return new_clauses; } @@ -14467,11 +14568,17 @@ tsubst_copy_asm_operands (tree t, tree args, tsubst_flags_t complain, #undef RECUR } +/* Used to temporarily communicate the list of #pragma omp parallel + clauses to #pragma omp for instantiation if they are combined + together. */ + +static tree *omp_parallel_combined_clauses; + /* 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, +tsubst_omp_for_iterator (tree t, int i, tree declv, tree orig_declv, + tree initv, tree condv, tree incrv, tree *clauses, tree args, tsubst_flags_t complain, tree in_decl, bool integral_constant_expression_p) { @@ -14482,6 +14589,13 @@ tsubst_omp_for_iterator (tree t, int i, tree declv, tree initv, init = TREE_VEC_ELT (OMP_FOR_INIT (t), i); gcc_assert (TREE_CODE (init) == MODIFY_EXPR); + + if (orig_declv && OMP_FOR_ORIG_DECLS (t)) + { + tree o = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (t), i); + TREE_VEC_ELT (orig_declv, i) = RECUR (o); + } + decl = TREE_OPERAND (init, 0); init = TREE_OPERAND (init, 1); tree decl_expr = NULL_TREE; @@ -14495,7 +14609,41 @@ tsubst_omp_for_iterator (tree t, int i, tree declv, tree initv, decl = tsubst_decl (decl, args, complain); } else - decl = RECUR (decl); + { + if (TREE_CODE (decl) == SCOPE_REF) + { + decl = RECUR (decl); + if (TREE_CODE (decl) == COMPONENT_REF) + { + tree v = decl; + while (v) + switch (TREE_CODE (v)) + { + case COMPONENT_REF: + case MEM_REF: + case INDIRECT_REF: + CASE_CONVERT: + case POINTER_PLUS_EXPR: + v = TREE_OPERAND (v, 0); + continue; + case PARM_DECL: + if (DECL_CONTEXT (v) == current_function_decl + && DECL_ARTIFICIAL (v) + && DECL_NAME (v) == this_identifier) + { + decl = TREE_OPERAND (decl, 1); + decl = omp_privatize_field (decl); + } + /* FALLTHRU */ + default: + v = NULL_TREE; + break; + } + } + } + else + decl = RECUR (decl); + } init = RECUR (init); tree auto_node = type_uses_auto (TREE_TYPE (decl)); @@ -14542,25 +14690,51 @@ tsubst_omp_for_iterator (tree t, int i, tree declv, tree initv, } else if (init) { - tree c; - for (c = *clauses; c ; c = OMP_CLAUSE_CHAIN (c)) + tree *pc; + int j; + for (j = (omp_parallel_combined_clauses == NULL ? 1 : 0); j < 2; j++) { - if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE) - && OMP_CLAUSE_DECL (c) == decl) + for (pc = j ? clauses : omp_parallel_combined_clauses; *pc; ) + { + if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_PRIVATE + && OMP_CLAUSE_DECL (*pc) == decl) + break; + else if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_LASTPRIVATE + && OMP_CLAUSE_DECL (*pc) == decl) + { + if (j) + break; + /* Move lastprivate (decl) clause to OMP_FOR_CLAUSES. */ + tree c = *pc; + *pc = OMP_CLAUSE_CHAIN (c); + OMP_CLAUSE_CHAIN (c) = *clauses; + *clauses = c; + } + else if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_FIRSTPRIVATE + && OMP_CLAUSE_DECL (*pc) == decl) + { + error ("iteration variable %qD should not be firstprivate", + decl); + *pc = OMP_CLAUSE_CHAIN (*pc); + } + else if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_REDUCTION + && OMP_CLAUSE_DECL (*pc) == decl) + { + error ("iteration variable %qD should not be reduction", + decl); + *pc = OMP_CLAUSE_CHAIN (*pc); + } + else + pc = &OMP_CLAUSE_CHAIN (*pc); + } + if (*pc) 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) + if (*pc == NULL_TREE) { - c = build_omp_clause (input_location, OMP_CLAUSE_PRIVATE); + tree c = build_omp_clause (input_location, OMP_CLAUSE_PRIVATE); OMP_CLAUSE_DECL (c) = decl; - c = finish_omp_clauses (c); + c = finish_omp_clauses (c, true); if (c) { OMP_CLAUSE_CHAIN (c) = *clauses; @@ -15021,20 +15195,27 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, break; case OMP_PARALLEL: - tmp = tsubst_omp_clauses (OMP_PARALLEL_CLAUSES (t), false, + r = push_omp_privatization_clauses (OMP_PARALLEL_COMBINED (t)); + tmp = tsubst_omp_clauses (OMP_PARALLEL_CLAUSES (t), false, true, args, complain, in_decl); + if (OMP_PARALLEL_COMBINED (t)) + omp_parallel_combined_clauses = &tmp; stmt = begin_omp_parallel (); RECUR (OMP_PARALLEL_BODY (t)); + gcc_assert (omp_parallel_combined_clauses == NULL); OMP_PARALLEL_COMBINED (finish_omp_parallel (tmp, stmt)) = OMP_PARALLEL_COMBINED (t); + pop_omp_privatization_clauses (r); break; case OMP_TASK: - tmp = tsubst_omp_clauses (OMP_TASK_CLAUSES (t), false, + r = push_omp_privatization_clauses (false); + tmp = tsubst_omp_clauses (OMP_TASK_CLAUSES (t), false, true, args, complain, in_decl); stmt = begin_omp_task (); RECUR (OMP_TASK_BODY (t)); finish_omp_task (tmp, stmt); + pop_omp_privatization_clauses (r); break; case OMP_FOR: @@ -15042,17 +15223,22 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, case CILK_SIMD: case CILK_FOR: case OMP_DISTRIBUTE: + case OMP_TASKLOOP: { tree clauses, body, pre_body; tree declv = NULL_TREE, initv = NULL_TREE, condv = NULL_TREE; + tree orig_declv = NULL_TREE; tree incrv = NULL_TREE; int i; - clauses = tsubst_omp_clauses (OMP_FOR_CLAUSES (t), false, + r = push_omp_privatization_clauses (OMP_FOR_INIT (t) == NULL_TREE); + clauses = tsubst_omp_clauses (OMP_FOR_CLAUSES (t), false, true, args, complain, in_decl); if (OMP_FOR_INIT (t) != NULL_TREE) { declv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t))); + if (TREE_CODE (t) == OMP_FOR && OMP_FOR_ORIG_DECLS (t)) + orig_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))); @@ -15066,17 +15252,19 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, if (OMP_FOR_INIT (t) != NULL_TREE) 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, + tsubst_omp_for_iterator (t, i, declv, orig_declv, initv, condv, + incrv, &clauses, args, complain, in_decl, integral_constant_expression_p); + omp_parallel_combined_clauses = NULL; body = push_stmt_list (); RECUR (OMP_FOR_BODY (t)); body = pop_stmt_list (body); if (OMP_FOR_INIT (t) != NULL_TREE) - t = finish_omp_for (EXPR_LOCATION (t), TREE_CODE (t), declv, initv, - condv, incrv, body, pre_body, clauses); + t = finish_omp_for (EXPR_LOCATION (t), TREE_CODE (t), declv, + orig_declv, initv, condv, incrv, body, pre_body, + clauses); else { t = make_node (TREE_CODE (t)); @@ -15089,13 +15277,19 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, } add_stmt (finish_omp_structured_block (stmt)); + pop_omp_privatization_clauses (r); } break; case OMP_SECTIONS: + omp_parallel_combined_clauses = NULL; + /* FALLTHRU */ case OMP_SINGLE: case OMP_TEAMS: - tmp = tsubst_omp_clauses (OMP_CLAUSES (t), false, + case OMP_CRITICAL: + r = push_omp_privatization_clauses (TREE_CODE (t) == OMP_TEAMS + && OMP_TEAMS_COMBINED (t)); + tmp = tsubst_omp_clauses (OMP_CLAUSES (t), false, true, args, complain, in_decl); stmt = push_stmt_list (); RECUR (OMP_BODY (t)); @@ -15105,11 +15299,12 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, OMP_BODY (t) = stmt; OMP_CLAUSES (t) = tmp; add_stmt (t); + pop_omp_privatization_clauses (r); break; case OMP_TARGET_DATA: case OMP_TARGET: - tmp = tsubst_omp_clauses (OMP_CLAUSES (t), false, + tmp = tsubst_omp_clauses (OMP_CLAUSES (t), false, true, args, complain, in_decl); keep_next_level (true); stmt = begin_omp_structured_block (); @@ -15124,18 +15319,31 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, break; case OMP_TARGET_UPDATE: - tmp = tsubst_omp_clauses (OMP_TARGET_UPDATE_CLAUSES (t), false, + case OMP_TARGET_ENTER_DATA: + case OMP_TARGET_EXIT_DATA: + tmp = tsubst_omp_clauses (OMP_STANDALONE_CLAUSES (t), false, true, + args, complain, in_decl); + t = copy_node (t); + OMP_STANDALONE_CLAUSES (t) = tmp; + add_stmt (t); + break; + + case OMP_ORDERED: + tmp = tsubst_omp_clauses (OMP_ORDERED_CLAUSES (t), false, true, args, complain, in_decl); + stmt = push_stmt_list (); + RECUR (OMP_BODY (t)); + stmt = pop_stmt_list (stmt); + t = copy_node (t); - OMP_TARGET_UPDATE_CLAUSES (t) = tmp; + OMP_BODY (t) = stmt; + OMP_ORDERED_CLAUSES (t) = tmp; add_stmt (t); break; case OMP_SECTION: - case OMP_CRITICAL: case OMP_MASTER: case OMP_TASKGROUP: - case OMP_ORDERED: stmt = push_stmt_list (); RECUR (OMP_BODY (t)); stmt = pop_stmt_list (stmt); @@ -21053,7 +21261,7 @@ instantiate_decl (tree d, int defer_ok, bool external_p; bool deleted_p; tree fn_context; - bool nested; + bool nested = false; /* This function should only be used to instantiate templates for functions and static member variables. */ @@ -21278,6 +21486,10 @@ instantiate_decl (tree d, int defer_ok, fn_context = decl_function_context (d); nested = (current_function_decl != NULL_TREE); + vec omp_privatization_save; + if (nested) + save_omp_privatization_clauses (omp_privatization_save); + if (!fn_context) push_to_top_level (); else @@ -21447,6 +21659,8 @@ out: c_inhibit_evaluation_warnings = saved_inhibit_evaluation_warnings; pop_deferring_access_checks (); pop_tinst_level (); + if (nested) + restore_omp_privatization_clauses (omp_privatization_save); timevar_pop (TV_TEMPLATE_INST); @@ -22811,7 +23025,7 @@ dependent_template_id_p (tree tmpl, tree args) } /* Returns TRUE if OMP_FOR with DECLV, INITV, CONDV and INCRV vectors - is dependent. */ + are dependent. */ bool dependent_omp_for_p (tree declv, tree initv, tree condv, tree incrv) @@ -22828,7 +23042,8 @@ dependent_omp_for_p (tree declv, tree initv, tree condv, tree incrv) tree cond = TREE_VEC_ELT (condv, i); tree incr = TREE_VEC_ELT (incrv, i); - if (type_dependent_expression_p (decl)) + if (type_dependent_expression_p (decl) + || TREE_CODE (decl) == SCOPE_REF) return true; if (init && type_dependent_expression_p (init)) diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index c1f43301b00..8796b176c15 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -63,6 +63,12 @@ static tree maybe_convert_cond (tree); static tree finalize_nrv_r (tree *, int *, void *); static tree capture_decltype (tree); +/* Used for OpenMP non-static data member privatization. */ + +static hash_map *omp_private_member_map; +static vec omp_private_member_vec; +static bool omp_private_member_ignore_next; + /* Deferred Access Checking Overview --------------------------------- @@ -1704,6 +1710,8 @@ tree finish_non_static_data_member (tree decl, tree object, tree qualifying_scope) { gcc_assert (TREE_CODE (decl) == FIELD_DECL); + bool try_omp_private = !object && omp_private_member_map; + tree ret; if (!object) { @@ -1755,17 +1763,17 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope) type = cp_build_qualified_type (type, quals); } - return (convert_from_reference + ret = (convert_from_reference (build_min (COMPONENT_REF, type, object, decl, NULL_TREE))); } /* If PROCESSING_TEMPLATE_DECL is nonzero here, then QUALIFYING_SCOPE is also non-null. Wrap this in a SCOPE_REF for now. */ else if (processing_template_decl) - return build_qualified_name (TREE_TYPE (decl), - qualifying_scope, - decl, - /*template_p=*/false); + ret = build_qualified_name (TREE_TYPE (decl), + qualifying_scope, + decl, + /*template_p=*/false); else { tree access_type = TREE_TYPE (object); @@ -1782,11 +1790,18 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope) &binfo); } - return build_class_member_access_expr (object, decl, - /*access_path=*/NULL_TREE, - /*preserve_reference=*/false, - tf_warning_or_error); + ret = build_class_member_access_expr (object, decl, + /*access_path=*/NULL_TREE, + /*preserve_reference=*/false, + tf_warning_or_error); } + if (try_omp_private) + { + tree *v = omp_private_member_map->get (decl); + if (v) + ret = convert_from_reference (*v); + } + return ret; } /* If we are currently parsing a template and we encountered a typedef @@ -4252,6 +4267,91 @@ cxx_omp_create_clause_info (tree c, tree type, bool need_default_ctor, return errorcount != save_errorcount; } +/* If DECL is DECL_OMP_PRIVATIZED_MEMBER, return corresponding + FIELD_DECL, otherwise return DECL itself. */ + +static tree +omp_clause_decl_field (tree decl) +{ + if (VAR_P (decl) + && DECL_HAS_VALUE_EXPR_P (decl) + && DECL_ARTIFICIAL (decl) + && DECL_LANG_SPECIFIC (decl) + && DECL_OMP_PRIVATIZED_MEMBER (decl)) + { + tree f = DECL_VALUE_EXPR (decl); + if (TREE_CODE (f) == INDIRECT_REF) + f = TREE_OPERAND (f, 0); + if (TREE_CODE (f) == COMPONENT_REF) + { + f = TREE_OPERAND (f, 1); + gcc_assert (TREE_CODE (f) == FIELD_DECL); + return f; + } + } + return NULL_TREE; +} + +/* Adjust DECL if needed for printing using %qE. */ + +static tree +omp_clause_printable_decl (tree decl) +{ + tree t = omp_clause_decl_field (decl); + if (t) + return t; + return decl; +} + +/* For a FIELD_DECL F and corresponding DECL_OMP_PRIVATIZED_MEMBER + VAR_DECL T that doesn't need a DECL_EXPR added, record it for + privatization. */ + +static void +omp_note_field_privatization (tree f, tree t) +{ + if (!omp_private_member_map) + omp_private_member_map = new hash_map; + tree &v = omp_private_member_map->get_or_insert (f); + if (v == NULL_TREE) + { + v = t; + omp_private_member_vec.safe_push (f); + /* Signal that we don't want to create DECL_EXPR for this dummy var. */ + omp_private_member_vec.safe_push (integer_zero_node); + } +} + +/* Privatize FIELD_DECL T, return corresponding DECL_OMP_PRIVATIZED_MEMBER + dummy VAR_DECL. */ + +tree +omp_privatize_field (tree t) +{ + tree m = finish_non_static_data_member (t, NULL_TREE, NULL_TREE); + if (m == error_mark_node) + return error_mark_node; + if (!omp_private_member_map) + omp_private_member_map = new hash_map; + if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE) + { + gcc_assert (TREE_CODE (m) == INDIRECT_REF); + m = TREE_OPERAND (m, 0); + } + tree &v = omp_private_member_map->get_or_insert (t); + if (v == NULL_TREE) + { + v = create_temporary_var (TREE_TYPE (m)); + if (!DECL_LANG_SPECIFIC (v)) + retrofit_lang_decl (v); + DECL_OMP_PRIVATIZED_MEMBER (v) = 1; + SET_DECL_VALUE_EXPR (v, m); + DECL_HAS_VALUE_EXPR_P (v) = 1; + omp_private_member_vec.safe_push (t); + } + return v; +} + /* Helper function for handle_omp_array_sections. Called recursively to handle multiple array-section-subscripts. C is the clause, T current expression (initially OMP_CLAUSE_DECL), which is either @@ -4266,7 +4366,7 @@ cxx_omp_create_clause_info (tree c, tree type, bool need_default_ctor, map(a[:b][2:1][:c][:2][:d][e:f][2:5]) FIRST_NON_ONE will be 3, array-section-subscript [:b], [2:1] and [:c] all are or may have length of 1, array-section-subscript [:2] is the - first one knonwn not to have length 1. For array-section-subscript + first one known not to have length 1. For array-section-subscript <= FIRST_NON_ONE we diagnose non-contiguous arrays if low bound isn't 0 or length isn't the array domain max + 1, for > FIRST_NON_ONE we can if MAYBE_ZERO_LEN is false. MAYBE_ZERO_LEN will be true in the above @@ -4274,13 +4374,43 @@ cxx_omp_create_clause_info (tree c, tree type, bool need_default_ctor, static tree handle_omp_array_sections_1 (tree c, tree t, vec &types, - bool &maybe_zero_len, unsigned int &first_non_one) + bool &maybe_zero_len, unsigned int &first_non_one, + bool is_omp) { tree ret, low_bound, length, type; if (TREE_CODE (t) != TREE_LIST) { if (error_operand_p (t)) return error_mark_node; + if (REFERENCE_REF_P (t) + && TREE_CODE (TREE_OPERAND (t, 0)) == COMPONENT_REF) + t = TREE_OPERAND (t, 0); + ret = t; + if (TREE_CODE (t) == COMPONENT_REF + && is_omp + && (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TO + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FROM) + && !type_dependent_expression_p (t)) + { + if (DECL_BIT_FIELD (TREE_OPERAND (t, 1))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "bit-field %qE in %qs clause", + t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + while (TREE_CODE (t) == COMPONENT_REF) + { + if (TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == UNION_TYPE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is a member of a union", t); + return error_mark_node; + } + t = TREE_OPERAND (t, 0); + } + } if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) { if (processing_template_decl) @@ -4295,6 +4425,15 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); return error_mark_node; } + else if (TREE_CODE (t) == PARM_DECL + && DECL_ARTIFICIAL (t) + && DECL_NAME (t) == this_identifier) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% allowed in OpenMP only in %" + " clauses"); + return error_mark_node; + } else if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND && VAR_P (t) && CP_DECL_THREAD_LOCAL_P (t)) { @@ -4303,14 +4442,17 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); return error_mark_node; } - if (type_dependent_expression_p (t)) + if (type_dependent_expression_p (ret)) return NULL_TREE; - t = convert_from_reference (t); - return t; + ret = convert_from_reference (ret); + return ret; } + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + && TREE_CODE (TREE_CHAIN (t)) == FIELD_DECL) + TREE_CHAIN (t) = omp_privatize_field (TREE_CHAIN (t)); ret = handle_omp_array_sections_1 (c, TREE_CHAIN (t), types, - maybe_zero_len, first_non_one); + maybe_zero_len, first_non_one, is_omp); if (ret == error_mark_node || ret == NULL_TREE) return ret; @@ -4358,11 +4500,32 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, if (length != NULL_TREE) { if (!integer_nonzerop (length)) - maybe_zero_len = true; + { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + { + if (integer_zerop (length)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "zero length array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + } + else + maybe_zero_len = true; + } if (first_non_one == types.length () && (TREE_CODE (length) != INTEGER_CST || integer_onep (length))) first_non_one++; } + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + && !integer_zerop (low_bound)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% array section has to be zero-based"); + return error_mark_node; + } if (TREE_CODE (type) == ARRAY_TYPE) { if (length == NULL_TREE @@ -4410,7 +4573,17 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, return error_mark_node; } if (tree_int_cst_equal (size, low_bound)) - maybe_zero_len = true; + { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + { + error_at (OMP_CLAUSE_LOCATION (c), + "zero length array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + maybe_zero_len = true; + } else if (length == NULL_TREE && first_non_one == types.length () && tree_int_cst_equal @@ -4420,7 +4593,9 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, } else if (length == NULL_TREE) { - maybe_zero_len = true; + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION) + maybe_zero_len = true; if (first_non_one == types.length ()) first_non_one++; } @@ -4454,7 +4629,9 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, } else if (length == NULL_TREE) { - maybe_zero_len = true; + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION) + maybe_zero_len = true; if (first_non_one == types.length ()) first_non_one++; } @@ -4478,6 +4655,15 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, "for pointer type length expression must be specified"); return error_mark_node; } + if (length != NULL_TREE + && TREE_CODE (length) == INTEGER_CST + && tree_int_cst_sgn (length) == -1) + { + error_at (OMP_CLAUSE_LOCATION (c), + "negative length in array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } /* If there is a pointer type anywhere but in the very first array-section-subscript, the array section can't be contiguous. */ if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND @@ -4511,13 +4697,14 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, /* Handle array sections for clause C. */ static bool -handle_omp_array_sections (tree c) +handle_omp_array_sections (tree c, bool is_omp) { bool maybe_zero_len = false; unsigned int first_non_one = 0; - auto_vec types; + auto_vec types; tree first = handle_omp_array_sections_1 (c, OMP_CLAUSE_DECL (c), types, - maybe_zero_len, first_non_one); + maybe_zero_len, first_non_one, + is_omp); if (first == error_mark_node) return true; if (first == NULL_TREE) @@ -4619,7 +4806,9 @@ handle_omp_array_sections (tree c) { tree l; - if (i > first_non_one && length && integer_nonzerop (length)) + if (i > first_non_one + && ((length && integer_nonzerop (length)) + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)) continue; if (length) l = fold_convert (sizetype, length); @@ -4644,6 +4833,12 @@ handle_omp_array_sections (tree c) else if (size == NULL_TREE) { size = size_in_bytes (TREE_TYPE (types[i])); + tree eltype = TREE_TYPE (types[num - 1]); + while (TREE_CODE (eltype) == ARRAY_TYPE) + eltype = TREE_TYPE (eltype); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + size = size_binop (EXACT_DIV_EXPR, size, + size_in_bytes (eltype)); size = size_binop (MULT_EXPR, size, l); if (condition) size = fold_build3 (COND_EXPR, sizetype, condition, @@ -4657,14 +4852,52 @@ handle_omp_array_sections (tree c) { if (side_effects) size = build2 (COMPOUND_EXPR, sizetype, side_effects, size); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + { + size = size_binop (MINUS_EXPR, size, size_one_node); + tree index_type = build_index_type (size); + tree eltype = TREE_TYPE (first); + while (TREE_CODE (eltype) == ARRAY_TYPE) + eltype = TREE_TYPE (eltype); + tree type = build_array_type (eltype, index_type); + tree ptype = build_pointer_type (eltype); + if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE + && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (t)))) + t = convert_from_reference (t); + else if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) + t = build_fold_addr_expr (t); + t = build2 (MEM_REF, type, t, build_int_cst (ptype, 0)); + OMP_CLAUSE_DECL (c) = t; + return false; + } OMP_CLAUSE_DECL (c) = first; OMP_CLAUSE_SIZE (c) = size; - if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP + || (TREE_CODE (t) == COMPONENT_REF + && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)) return false; + if (is_omp) + switch (OMP_CLAUSE_MAP_KIND (c)) + { + case GOMP_MAP_ALLOC: + case GOMP_MAP_TO: + case GOMP_MAP_FROM: + case GOMP_MAP_TOFROM: + case GOMP_MAP_ALWAYS_TO: + case GOMP_MAP_ALWAYS_FROM: + case GOMP_MAP_ALWAYS_TOFROM: + case GOMP_MAP_RELEASE: + case GOMP_MAP_DELETE: + OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION (c) = 1; + break; + default: + break; + } tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); - OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_POINTER); - if (!cxx_mark_addressable (t)) + OMP_CLAUSE_SET_MAP_KIND (c2, is_omp ? GOMP_MAP_FIRSTPRIVATE_POINTER + : GOMP_MAP_POINTER); + if (!is_omp && !cxx_mark_addressable (t)) return false; OMP_CLAUSE_DECL (c2) = t; t = build_fold_addr_expr (first); @@ -4682,7 +4915,8 @@ handle_omp_array_sections (tree c) OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c); OMP_CLAUSE_CHAIN (c) = c2; ptr = OMP_CLAUSE_DECL (c2); - if (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE + if (!is_omp + && TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (ptr)))) { tree c3 = build_omp_clause (OMP_CLAUSE_LOCATION (c), @@ -5091,9 +5325,45 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor) { tree t = OMP_CLAUSE_DECL (c); bool predefined = false; + if (TREE_CODE (t) == TREE_LIST) + { + gcc_assert (processing_template_decl); + return false; + } tree type = TREE_TYPE (t); + if (TREE_CODE (t) == MEM_REF) + type = TREE_TYPE (type); if (TREE_CODE (type) == REFERENCE_TYPE) type = TREE_TYPE (type); + if (TREE_CODE (type) == ARRAY_TYPE) + { + tree oatype = type; + gcc_assert (TREE_CODE (t) != MEM_REF); + while (TREE_CODE (type) == ARRAY_TYPE) + type = TREE_TYPE (type); + if (!processing_template_decl) + { + t = require_complete_type (t); + if (t == error_mark_node) + return true; + tree size = size_binop (EXACT_DIV_EXPR, TYPE_SIZE_UNIT (oatype), + TYPE_SIZE_UNIT (type)); + if (integer_zerop (size)) + { + error ("%qE in % clause is a zero size array", + omp_clause_printable_decl (t)); + return true; + } + size = size_binop (MINUS_EXPR, size, size_one_node); + tree index_type = build_index_type (size); + tree atype = build_array_type (type, index_type); + tree ptype = build_pointer_type (type); + if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) + t = build_fold_addr_expr (t); + t = build2 (MEM_REF, atype, t, build_int_cst (ptype, 0)); + OMP_CLAUSE_DECL (c) = t; + } + } if (type == error_mark_node) return true; else if (ARITHMETIC_TYPE_P (type)) @@ -5126,9 +5396,10 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor) default: break; } - else if (TREE_CODE (type) == ARRAY_TYPE || TYPE_READONLY (type)) + else if (TYPE_READONLY (type)) { - error ("%qE has invalid type for %", t); + error ("%qE has const type for %", + omp_clause_printable_decl (t)); return true; } else if (!processing_template_decl) @@ -5149,9 +5420,7 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor) tree id = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c); - type = TYPE_MAIN_VARIANT (TREE_TYPE (t)); - if (TREE_CODE (type) == REFERENCE_TYPE) - type = TREE_TYPE (type); + type = TYPE_MAIN_VARIANT (type); OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = NULL_TREE; if (id == NULL_TREE) id = omp_reduction_id (OMP_CLAUSE_REDUCTION_CODE (c), @@ -5169,7 +5438,7 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor) if (TREE_CODE (body) == STATEMENT_LIST) { tree_stmt_iterator tsi; - tree placeholder = NULL_TREE; + tree placeholder = NULL_TREE, decl_placeholder = NULL_TREE; int i; tree stmts[7]; tree atype = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (id))); @@ -5190,14 +5459,24 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor) DECL_ARTIFICIAL (placeholder) = 1; DECL_IGNORED_P (placeholder) = 1; OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = placeholder; + if (TREE_CODE (t) == MEM_REF) + { + decl_placeholder = build_lang_decl (VAR_DECL, NULL_TREE, + type); + DECL_ARTIFICIAL (decl_placeholder) = 1; + DECL_IGNORED_P (decl_placeholder) = 1; + OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c) = decl_placeholder; + } if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[0]))) cxx_mark_addressable (placeholder); if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[1])) && TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c))) != REFERENCE_TYPE) - cxx_mark_addressable (OMP_CLAUSE_DECL (c)); + cxx_mark_addressable (decl_placeholder ? decl_placeholder + : OMP_CLAUSE_DECL (c)); tree omp_out = placeholder; - tree omp_in = convert_from_reference (OMP_CLAUSE_DECL (c)); + tree omp_in = decl_placeholder ? decl_placeholder + : convert_from_reference (OMP_CLAUSE_DECL (c)); if (need_static_cast) { tree rtype = build_reference_type (atype); @@ -5219,10 +5498,12 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor) gcc_assert (TREE_CODE (stmts[3]) == DECL_EXPR && TREE_CODE (stmts[4]) == DECL_EXPR); if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[3]))) - cxx_mark_addressable (OMP_CLAUSE_DECL (c)); + cxx_mark_addressable (decl_placeholder ? decl_placeholder + : OMP_CLAUSE_DECL (c)); if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[4]))) cxx_mark_addressable (placeholder); - tree omp_priv = convert_from_reference (OMP_CLAUSE_DECL (c)); + tree omp_priv = decl_placeholder ? decl_placeholder + : convert_from_reference (OMP_CLAUSE_DECL (c)); tree omp_orig = placeholder; if (need_static_cast) { @@ -5261,7 +5542,8 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor) else { tree init; - tree v = convert_from_reference (t); + tree v = decl_placeholder ? decl_placeholder + : convert_from_reference (t); if (AGGREGATE_TYPE_P (TREE_TYPE (v))) init = build_constructor (TREE_TYPE (v), NULL); else @@ -5276,9 +5558,85 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor) *need_dtor = true; else { - error ("user defined reduction not found for %qD", t); + error ("user defined reduction not found for %qE", + omp_clause_printable_decl (t)); return true; } + if (TREE_CODE (OMP_CLAUSE_DECL (c)) == MEM_REF) + gcc_assert (TYPE_SIZE_UNIT (type) + && TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST); + return false; +} + +/* Called from finish_struct_1. linear(this) or linear(this:step) + clauses might not be finalized yet because the class has been incomplete + when parsing #pragma omp declare simd methods. Fix those up now. */ + +void +finish_omp_declare_simd_methods (tree t) +{ + if (processing_template_decl) + return; + + for (tree x = TYPE_METHODS (t); x; x = DECL_CHAIN (x)) + { + if (TREE_CODE (TREE_TYPE (x)) != METHOD_TYPE) + continue; + tree ods = lookup_attribute ("omp declare simd", DECL_ATTRIBUTES (x)); + if (!ods || !TREE_VALUE (ods)) + continue; + for (tree c = TREE_VALUE (TREE_VALUE (ods)); c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR + && integer_zerop (OMP_CLAUSE_DECL (c)) + && OMP_CLAUSE_LINEAR_STEP (c) + && TREE_CODE (TREE_TYPE (OMP_CLAUSE_LINEAR_STEP (c))) + == POINTER_TYPE) + { + tree s = OMP_CLAUSE_LINEAR_STEP (c); + s = fold_convert_loc (OMP_CLAUSE_LOCATION (c), sizetype, s); + s = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MULT_EXPR, + sizetype, s, TYPE_SIZE_UNIT (t)); + OMP_CLAUSE_LINEAR_STEP (c) = s; + } + } +} + +/* Adjust sink depend clause to take into account pointer offsets. + + Return TRUE if there was a problem processing the offset, and the + whole clause should be removed. */ + +static bool +cp_finish_omp_clause_depend_sink (tree sink_clause) +{ + tree t = OMP_CLAUSE_DECL (sink_clause); + gcc_assert (TREE_CODE (t) == TREE_LIST); + + /* Make sure we don't adjust things twice for templates. */ + if (processing_template_decl) + return false; + + for (; t; t = TREE_CHAIN (t)) + { + tree decl = TREE_VALUE (t); + if (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE) + { + tree offset = TREE_PURPOSE (t); + bool neg = wi::neg_p ((wide_int) offset); + offset = fold_unary (ABS_EXPR, TREE_TYPE (offset), offset); + decl = mark_rvalue_use (decl); + decl = convert_from_reference (decl); + tree t2 = pointer_int_sum (OMP_CLAUSE_LOCATION (sink_clause), + neg ? MINUS_EXPR : PLUS_EXPR, + decl, offset); + t2 = fold_build2_loc (OMP_CLAUSE_LOCATION (sink_clause), + MINUS_EXPR, sizetype, t2, + decl); + if (t2 == error_mark_node) + return true; + TREE_PURPOSE (t) = t2; + } + } return false; } @@ -5286,11 +5644,12 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor) Remove any elements from the list that are invalid. */ tree -finish_omp_clauses (tree clauses) +finish_omp_clauses (tree clauses, bool allow_fields, bool declare_simd) { bitmap_head generic_head, firstprivate_head, lastprivate_head; - bitmap_head aligned_head; + bitmap_head aligned_head, map_head, map_field_head, generic_field_head; tree c, t, *pc; + tree safelen = NULL_TREE; bool branch_seen = false; bool copyprivate_seen = false; @@ -5299,35 +5658,93 @@ finish_omp_clauses (tree clauses) bitmap_initialize (&firstprivate_head, &bitmap_default_obstack); bitmap_initialize (&lastprivate_head, &bitmap_default_obstack); bitmap_initialize (&aligned_head, &bitmap_default_obstack); + bitmap_initialize (&map_head, &bitmap_default_obstack); + bitmap_initialize (&map_field_head, &bitmap_default_obstack); + bitmap_initialize (&generic_field_head, &bitmap_default_obstack); for (pc = &clauses, c = clauses; c ; c = *pc) { bool remove = false; + bool field_ok = false; switch (OMP_CLAUSE_CODE (c)) { case OMP_CLAUSE_SHARED: goto check_dup_generic; case OMP_CLAUSE_PRIVATE: + field_ok = allow_fields; goto check_dup_generic; case OMP_CLAUSE_REDUCTION: + field_ok = allow_fields; + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) == TREE_LIST) + { + if (handle_omp_array_sections (c, allow_fields)) + { + remove = true; + break; + } + if (TREE_CODE (t) == TREE_LIST) + { + while (TREE_CODE (t) == TREE_LIST) + t = TREE_CHAIN (t); + } + else + { + gcc_assert (TREE_CODE (t) == MEM_REF); + t = TREE_OPERAND (t, 0); + if (TREE_CODE (t) == ADDR_EXPR + || TREE_CODE (t) == INDIRECT_REF) + t = TREE_OPERAND (t, 0); + } + tree n = omp_clause_decl_field (t); + if (n) + t = n; + goto check_dup_generic_t; + } goto check_dup_generic; case OMP_CLAUSE_COPYPRIVATE: copyprivate_seen = true; + field_ok = allow_fields; goto check_dup_generic; case OMP_CLAUSE_COPYIN: goto check_dup_generic; case OMP_CLAUSE_LINEAR: + field_ok = allow_fields; t = OMP_CLAUSE_DECL (c); + if (!declare_simd + && OMP_CLAUSE_LINEAR_KIND (c) != OMP_CLAUSE_LINEAR_DEFAULT) + { + error_at (OMP_CLAUSE_LOCATION (c), + "modifier should not be specified in % " + "clause on % or % constructs"); + OMP_CLAUSE_LINEAR_KIND (c) = OMP_CLAUSE_LINEAR_DEFAULT; + } if ((VAR_P (t) || TREE_CODE (t) == PARM_DECL) - && !type_dependent_expression_p (t) - && !INTEGRAL_TYPE_P (TREE_TYPE (t)) - && TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE) + && !type_dependent_expression_p (t)) { - error ("linear clause applied to non-integral non-pointer " - "variable with %qT type", TREE_TYPE (t)); - remove = true; - break; + tree type = TREE_TYPE (t); + if ((OMP_CLAUSE_LINEAR_KIND (c) == OMP_CLAUSE_LINEAR_REF + || OMP_CLAUSE_LINEAR_KIND (c) == OMP_CLAUSE_LINEAR_UVAL) + && TREE_CODE (type) != REFERENCE_TYPE) + { + error ("linear clause with %qs modifier applied to " + "non-reference variable with %qT type", + OMP_CLAUSE_LINEAR_KIND (c) == OMP_CLAUSE_LINEAR_REF + ? "ref" : "uval", TREE_TYPE (t)); + remove = true; + break; + } + if (TREE_CODE (type) == REFERENCE_TYPE) + type = TREE_TYPE (type); + if (!INTEGRAL_TYPE_P (type) + && TREE_CODE (type) != POINTER_TYPE) + { + error ("linear clause applied to non-integral non-pointer " + "variable with %qT type", TREE_TYPE (t)); + remove = true; + break; + } } t = OMP_CLAUSE_LINEAR_STEP (c); if (t == NULL_TREE) @@ -5354,14 +5771,38 @@ finish_omp_clauses (tree clauses) if (TREE_CODE (OMP_CLAUSE_DECL (c)) == PARM_DECL) t = maybe_constant_value (t); t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); - if (TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c))) - == POINTER_TYPE) + tree type = TREE_TYPE (OMP_CLAUSE_DECL (c)); + if (TREE_CODE (type) == REFERENCE_TYPE) + type = TREE_TYPE (type); + if (OMP_CLAUSE_LINEAR_KIND (c) == OMP_CLAUSE_LINEAR_REF) + { + type = build_pointer_type (type); + tree d = fold_convert (type, OMP_CLAUSE_DECL (c)); + t = pointer_int_sum (OMP_CLAUSE_LOCATION (c), PLUS_EXPR, + d, t); + t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), + MINUS_EXPR, sizetype, t, d); + if (t == error_mark_node) + { + remove = true; + break; + } + } + else if (TREE_CODE (type) == POINTER_TYPE + /* Can't multiply the step yet if *this + is still incomplete type. */ + && (!declare_simd + || TREE_CODE (OMP_CLAUSE_DECL (c)) != PARM_DECL + || !DECL_ARTIFICIAL (OMP_CLAUSE_DECL (c)) + || DECL_NAME (OMP_CLAUSE_DECL (c)) + != this_identifier + || !TYPE_BEING_DEFINED (TREE_TYPE (type)))) { + tree d = convert_from_reference (OMP_CLAUSE_DECL (c)); t = pointer_int_sum (OMP_CLAUSE_LOCATION (c), PLUS_EXPR, - OMP_CLAUSE_DECL (c), t); + d, t); t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), - MINUS_EXPR, sizetype, t, - OMP_CLAUSE_DECL (c)); + MINUS_EXPR, sizetype, t, d); if (t == error_mark_node) { remove = true; @@ -5369,14 +5810,33 @@ finish_omp_clauses (tree clauses) } } else - t = fold_convert (TREE_TYPE (OMP_CLAUSE_DECL (c)), t); + t = fold_convert (type, t); } OMP_CLAUSE_LINEAR_STEP (c) = t; } goto check_dup_generic; check_dup_generic: - t = OMP_CLAUSE_DECL (c); - if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) + t = omp_clause_decl_field (OMP_CLAUSE_DECL (c)); + if (t) + { + if (!remove) + omp_note_field_privatization (t, OMP_CLAUSE_DECL (c)); + } + else + t = OMP_CLAUSE_DECL (c); + check_dup_generic_t: + if (t == current_class_ptr + && (!declare_simd + || (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_LINEAR + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_UNIFORM))) + { + error ("% allowed in OpenMP only in %" + " clauses"); + remove = true; + break; + } + if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL + && (!field_ok || TREE_CODE (t) != FIELD_DECL)) { if (processing_template_decl) break; @@ -5397,11 +5857,34 @@ finish_omp_clauses (tree clauses) } else bitmap_set_bit (&generic_head, DECL_UID (t)); + if (!field_ok) + break; + handle_field_decl: + if (!remove + && TREE_CODE (t) == FIELD_DECL + && t == OMP_CLAUSE_DECL (c)) + { + OMP_CLAUSE_DECL (c) = omp_privatize_field (t); + if (OMP_CLAUSE_DECL (c) == error_mark_node) + remove = true; + } break; case OMP_CLAUSE_FIRSTPRIVATE: - t = OMP_CLAUSE_DECL (c); - if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) + t = omp_clause_decl_field (OMP_CLAUSE_DECL (c)); + if (t) + omp_note_field_privatization (t, OMP_CLAUSE_DECL (c)); + else + t = OMP_CLAUSE_DECL (c); + if (t == current_class_ptr) + { + error ("% allowed in OpenMP only in %" + " clauses"); + remove = true; + break; + } + if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL + && (!allow_fields || TREE_CODE (t) != FIELD_DECL)) { if (processing_template_decl) break; @@ -5419,11 +5902,23 @@ finish_omp_clauses (tree clauses) } else bitmap_set_bit (&firstprivate_head, DECL_UID (t)); - break; + goto handle_field_decl; case OMP_CLAUSE_LASTPRIVATE: - t = OMP_CLAUSE_DECL (c); - if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) + t = omp_clause_decl_field (OMP_CLAUSE_DECL (c)); + if (t) + omp_note_field_privatization (t, OMP_CLAUSE_DECL (c)); + else + t = OMP_CLAUSE_DECL (c); + if (t == current_class_ptr) + { + error ("% allowed in OpenMP only in %" + " clauses"); + remove = true; + break; + } + if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL + && (!allow_fields || TREE_CODE (t) != FIELD_DECL)) { if (processing_template_decl) break; @@ -5441,7 +5936,7 @@ finish_omp_clauses (tree clauses) } else bitmap_set_bit (&lastprivate_head, DECL_UID (t)); - break; + goto handle_field_decl; case OMP_CLAUSE_IF: t = OMP_CLAUSE_IF_EXPR (c); @@ -5477,7 +5972,17 @@ finish_omp_clauses (tree clauses) { t = mark_rvalue_use (t); if (!processing_template_decl) - t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + { + t = maybe_constant_value (t); + if (TREE_CODE (t) == INTEGER_CST + && tree_int_cst_sgn (t) != 1) + { + warning_at (OMP_CLAUSE_LOCATION (c), 0, + "% value must be positive"); + t = integer_one_node; + } + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + } OMP_CLAUSE_NUM_THREADS_EXPR (c) = t; } break; @@ -5545,6 +6050,8 @@ finish_omp_clauses (tree clauses) } } OMP_CLAUSE_OPERAND (c, 0) = t; + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SAFELEN) + safelen = c; } break; @@ -5562,7 +6069,17 @@ finish_omp_clauses (tree clauses) { t = mark_rvalue_use (t); if (!processing_template_decl) - t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + { + t = maybe_constant_value (t); + if (TREE_CODE (t) == INTEGER_CST + && tree_int_cst_sgn (t) != 1) + { + warning_at (OMP_CLAUSE_LOCATION (c), 0, + "% value must be positive"); + t = integer_one_node; + } + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + } OMP_CLAUSE_NUM_TEAMS_EXPR (c) = t; } break; @@ -5619,7 +6136,17 @@ finish_omp_clauses (tree clauses) { t = mark_rvalue_use (t); if (!processing_template_decl) - t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + { + t = maybe_constant_value (t); + if (TREE_CODE (t) == INTEGER_CST + && tree_int_cst_sgn (t) != 1) + { + warning_at (OMP_CLAUSE_LOCATION (c), 0, + "% value must be positive"); + t = integer_one_node; + } + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + } OMP_CLAUSE_THREAD_LIMIT_EXPR (c) = t; } break; @@ -5667,6 +6194,13 @@ finish_omp_clauses (tree clauses) case OMP_CLAUSE_ALIGNED: t = OMP_CLAUSE_DECL (c); + if (t == current_class_ptr && !declare_simd) + { + error ("% allowed in OpenMP only in %" + " clauses"); + remove = true; + break; + } if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) { if (processing_template_decl) @@ -5729,9 +6263,21 @@ finish_omp_clauses (tree clauses) case OMP_CLAUSE_DEPEND: t = OMP_CLAUSE_DECL (c); + if (t == NULL_TREE) + { + gcc_assert (OMP_CLAUSE_DEPEND_KIND (c) + == OMP_CLAUSE_DEPEND_SOURCE); + break; + } + if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK) + { + if (cp_finish_omp_clause_depend_sink (c)) + remove = true; + break; + } if (TREE_CODE (t) == TREE_LIST) { - if (handle_omp_array_sections (c)) + if (handle_omp_array_sections (c, allow_fields)) remove = true; break; } @@ -5747,6 +6293,12 @@ finish_omp_clauses (tree clauses) error ("%qE is not a variable in % clause", t); remove = true; } + else if (t == current_class_ptr) + { + error ("% allowed in OpenMP only in %" + " clauses"); + remove = true; + } else if (!processing_template_decl && !cxx_mark_addressable (t)) remove = true; @@ -5759,7 +6311,7 @@ finish_omp_clauses (tree clauses) t = OMP_CLAUSE_DECL (c); if (TREE_CODE (t) == TREE_LIST) { - if (handle_omp_array_sections (c)) + if (handle_omp_array_sections (c, allow_fields)) remove = true; else { @@ -5774,12 +6326,90 @@ finish_omp_clauses (tree clauses) omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; } + while (TREE_CODE (t) == ARRAY_REF) + t = TREE_OPERAND (t, 0); + if (TREE_CODE (t) == COMPONENT_REF + && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) + { + while (TREE_CODE (t) == COMPONENT_REF) + t = TREE_OPERAND (t, 0); + if (bitmap_bit_p (&map_field_head, DECL_UID (t))) + break; + if (bitmap_bit_p (&map_head, DECL_UID (t))) + { + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) + error ("%qD appears more than once in motion" + " clauses", t); + else + error ("%qD appears more than once in map" + " clauses", t); + remove = true; + } + else + { + bitmap_set_bit (&map_head, DECL_UID (t)); + bitmap_set_bit (&map_field_head, DECL_UID (t)); + } + } } break; } if (t == error_mark_node) - remove = true; - else if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) + { + remove = true; + break; + } + if (REFERENCE_REF_P (t) + && TREE_CODE (TREE_OPERAND (t, 0)) == COMPONENT_REF) + t = TREE_OPERAND (t, 0); + if (TREE_CODE (t) == COMPONENT_REF + && allow_fields + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE__CACHE_) + { + if (type_dependent_expression_p (t)) + break; + if (DECL_BIT_FIELD (TREE_OPERAND (t, 1))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "bit-field %qE in %qs clause", + t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (!cp_omp_mappable_type (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE does not have a mappable type in %qs clause", + t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + while (TREE_CODE (t) == COMPONENT_REF) + { + if (TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) + == UNION_TYPE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is a member of a union", t); + remove = true; + break; + } + t = TREE_OPERAND (t, 0); + } + if (remove) + break; + if (VAR_P (t) || TREE_CODE (t) == PARM_DECL) + { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && (OMP_CLAUSE_MAP_KIND (c) + == GOMP_MAP_FIRSTPRIVATE_POINTER)) + { + if (bitmap_bit_p (&generic_field_head, DECL_UID (t))) + break; + } + else if (bitmap_bit_p (&map_field_head, DECL_UID (t))) + break; + } + } + if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) { if (processing_template_decl) break; @@ -5800,12 +6430,22 @@ finish_omp_clauses (tree clauses) omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; } + else if (t == current_class_ptr) + { + error ("% allowed in OpenMP only in %" + " clauses"); + remove = true; + break; + } else if (!processing_template_decl && TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE && !cxx_mark_addressable (t)) remove = true; else if (!(OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP - && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER) + && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER + || (OMP_CLAUSE_MAP_KIND (c) + == GOMP_MAP_FIRSTPRIVATE_POINTER))) + && t == OMP_CLAUSE_DECL (c) && !type_dependent_expression_p (t) && !cp_omp_mappable_type ((TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE) @@ -5817,7 +6457,28 @@ finish_omp_clauses (tree clauses) omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; } - else if (bitmap_bit_p (&generic_head, DECL_UID (t))) + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER) + { + if (bitmap_bit_p (&generic_head, DECL_UID (t)) + || bitmap_bit_p (&firstprivate_head, DECL_UID (t))) + { + error ("%qD appears more than once in data clauses", t); + remove = true; + } + else + { + bitmap_set_bit (&generic_head, DECL_UID (t)); + if (t != OMP_CLAUSE_DECL (c) + && (TREE_CODE (OMP_CLAUSE_DECL (c)) == COMPONENT_REF + || (REFERENCE_REF_P (OMP_CLAUSE_DECL (c)) + && (TREE_CODE (TREE_OPERAND (OMP_CLAUSE_DECL (c), + 0)) + == COMPONENT_REF)))) + bitmap_set_bit (&generic_field_head, DECL_UID (t)); + } + } + else if (bitmap_bit_p (&map_head, DECL_UID (t))) { if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) error ("%qD appears more than once in motion clauses", t); @@ -5826,7 +6487,42 @@ finish_omp_clauses (tree clauses) remove = true; } else - bitmap_set_bit (&generic_head, DECL_UID (t)); + { + bitmap_set_bit (&map_head, DECL_UID (t)); + if (t != OMP_CLAUSE_DECL (c) + && TREE_CODE (OMP_CLAUSE_DECL (c)) == COMPONENT_REF) + bitmap_set_bit (&map_field_head, DECL_UID (t)); + } + break; + + case OMP_CLAUSE_TO_DECLARE: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) == FUNCTION_DECL) + break; + /* FALLTHRU */ + case OMP_CLAUSE_LINK: + t = OMP_CLAUSE_DECL (c); + if (!VAR_P (t)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in clause %qs", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (DECL_THREAD_LOCAL_P (t)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD is threadprivate variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (!cp_omp_mappable_type (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD does not have a mappable type in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } break; case OMP_CLAUSE_UNIFORM: @@ -5844,6 +6540,137 @@ finish_omp_clauses (tree clauses) } goto check_dup_generic; + case OMP_CLAUSE_NUM_TASKS: + t = OMP_CLAUSE_NUM_TASKS_EXPR (c); + if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("% expression must be integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + { + t = maybe_constant_value (t); + if (TREE_CODE (t) == INTEGER_CST + && tree_int_cst_sgn (t) != 1) + { + warning_at (OMP_CLAUSE_LOCATION (c), 0, + "% value must be positive"); + t = integer_one_node; + } + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + } + OMP_CLAUSE_NUM_TASKS_EXPR (c) = t; + } + break; + + case OMP_CLAUSE_GRAINSIZE: + t = OMP_CLAUSE_GRAINSIZE_EXPR (c); + if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("% expression must be integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + { + t = maybe_constant_value (t); + if (TREE_CODE (t) == INTEGER_CST + && tree_int_cst_sgn (t) != 1) + { + warning_at (OMP_CLAUSE_LOCATION (c), 0, + "% value must be positive"); + t = integer_one_node; + } + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + } + OMP_CLAUSE_GRAINSIZE_EXPR (c) = t; + } + break; + + case OMP_CLAUSE_PRIORITY: + t = OMP_CLAUSE_PRIORITY_EXPR (c); + if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("% expression must be integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + { + t = maybe_constant_value (t); + if (TREE_CODE (t) == INTEGER_CST + && tree_int_cst_sgn (t) == -1) + { + warning_at (OMP_CLAUSE_LOCATION (c), 0, + "% value must be non-negative"); + t = integer_one_node; + } + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + } + OMP_CLAUSE_PRIORITY_EXPR (c) = t; + } + break; + + case OMP_CLAUSE_HINT: + t = OMP_CLAUSE_HINT_EXPR (c); + if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("% expression must be integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + { + t = maybe_constant_value (t); + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + } + OMP_CLAUSE_HINT_EXPR (c) = t; + } + break; + + case OMP_CLAUSE_IS_DEVICE_PTR: + case OMP_CLAUSE_USE_DEVICE_PTR: + field_ok = allow_fields; + t = OMP_CLAUSE_DECL (c); + if (!type_dependent_expression_p (t)) + { + tree type = TREE_TYPE (t); + if (TREE_CODE (type) != POINTER_TYPE + && TREE_CODE (type) != ARRAY_TYPE + && (TREE_CODE (type) != REFERENCE_TYPE + || (TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE + && TREE_CODE (TREE_TYPE (type)) != ARRAY_TYPE))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qs variable is neither a pointer, nor an array" + "nor reference to pointer or array", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + } + goto check_dup_generic; + case OMP_CLAUSE_NOWAIT: case OMP_CLAUSE_ORDERED: case OMP_CLAUSE_DEFAULT: @@ -5855,6 +6682,10 @@ finish_omp_clauses (tree clauses) case OMP_CLAUSE_SECTIONS: case OMP_CLAUSE_TASKGROUP: case OMP_CLAUSE_PROC_BIND: + case OMP_CLAUSE_NOGROUP: + case OMP_CLAUSE_THREADS: + case OMP_CLAUSE_SIMD: + case OMP_CLAUSE_DEFAULTMAP: case OMP_CLAUSE__CILK_FOR_COUNT_: break; @@ -5883,7 +6714,7 @@ finish_omp_clauses (tree clauses) { enum omp_clause_code c_kind = OMP_CLAUSE_CODE (c); bool remove = false; - bool need_complete_non_reference = false; + bool need_complete_type = false; bool need_default_ctor = false; bool need_copy_ctor = false; bool need_copy_assignment = false; @@ -5897,31 +6728,49 @@ finish_omp_clauses (tree clauses) need_implicitly_determined = true; break; case OMP_CLAUSE_PRIVATE: - need_complete_non_reference = true; + need_complete_type = true; need_default_ctor = true; need_dtor = true; need_implicitly_determined = true; break; case OMP_CLAUSE_FIRSTPRIVATE: - need_complete_non_reference = true; + need_complete_type = true; need_copy_ctor = true; need_dtor = true; need_implicitly_determined = true; break; case OMP_CLAUSE_LASTPRIVATE: - need_complete_non_reference = true; + need_complete_type = true; need_copy_assignment = true; need_implicitly_determined = true; break; case OMP_CLAUSE_REDUCTION: need_implicitly_determined = true; break; + case OMP_CLAUSE_LINEAR: + if (!declare_simd) + need_implicitly_determined = true; + break; case OMP_CLAUSE_COPYPRIVATE: need_copy_assignment = true; break; case OMP_CLAUSE_COPYIN: need_copy_assignment = true; break; + case OMP_CLAUSE_SIMDLEN: + if (safelen + && !processing_template_decl + && tree_int_cst_lt (OMP_CLAUSE_SAFELEN_EXPR (safelen), + OMP_CLAUSE_SIMDLEN_EXPR (c))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% clause value is bigger than " + "% clause value"); + OMP_CLAUSE_SIMDLEN_EXPR (c) + = OMP_CLAUSE_SAFELEN_EXPR (safelen); + } + pc = &OMP_CLAUSE_CHAIN (c); + continue; case OMP_CLAUSE_NOWAIT: if (copyprivate_seen) { @@ -5975,18 +6824,14 @@ finish_omp_clauses (tree clauses) break; } - if (need_complete_non_reference || need_copy_assignment) + if (need_complete_type || need_copy_assignment) { t = require_complete_type (t); if (t == error_mark_node) remove = true; else if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE - && need_complete_non_reference) - { - error ("%qE has reference type for %qs", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - remove = true; - } + && !complete_type_or_else (TREE_TYPE (TREE_TYPE (t)), t)) + remove = true; } if (need_implicitly_determined) { @@ -6014,19 +6859,21 @@ finish_omp_clauses (tree clauses) if (share_name) { error ("%qE is predetermined %qs for %qs", - t, share_name, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + omp_clause_printable_decl (t), share_name, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; } } /* We're interested in the base element, not arrays. */ inner_type = type = TREE_TYPE (t); - while (TREE_CODE (inner_type) == ARRAY_TYPE) - inner_type = TREE_TYPE (inner_type); - - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + if ((need_complete_type + || need_copy_assignment + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) && TREE_CODE (inner_type) == REFERENCE_TYPE) inner_type = TREE_TYPE (inner_type); + 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 @@ -6051,6 +6898,134 @@ finish_omp_clauses (tree clauses) return clauses; } +/* Start processing OpenMP clauses that can include any + privatization clauses for non-static data members. */ + +tree +push_omp_privatization_clauses (bool ignore_next) +{ + if (omp_private_member_ignore_next) + { + omp_private_member_ignore_next = ignore_next; + return NULL_TREE; + } + omp_private_member_ignore_next = ignore_next; + if (omp_private_member_map) + omp_private_member_vec.safe_push (error_mark_node); + return push_stmt_list (); +} + +/* Revert remapping of any non-static data members since + the last push_omp_privatization_clauses () call. */ + +void +pop_omp_privatization_clauses (tree stmt) +{ + if (stmt == NULL_TREE) + return; + stmt = pop_stmt_list (stmt); + if (omp_private_member_map) + { + while (!omp_private_member_vec.is_empty ()) + { + tree t = omp_private_member_vec.pop (); + if (t == error_mark_node) + { + add_stmt (stmt); + return; + } + bool no_decl_expr = t == integer_zero_node; + if (no_decl_expr) + t = omp_private_member_vec.pop (); + tree *v = omp_private_member_map->get (t); + gcc_assert (v); + if (!no_decl_expr) + add_decl_expr (*v); + omp_private_member_map->remove (t); + } + delete omp_private_member_map; + omp_private_member_map = NULL; + } + add_stmt (stmt); +} + +/* Remember OpenMP privatization clauses mapping and clear it. + Used for lambdas. */ + +void +save_omp_privatization_clauses (vec &save) +{ + save = vNULL; + if (omp_private_member_ignore_next) + save.safe_push (integer_one_node); + omp_private_member_ignore_next = false; + if (!omp_private_member_map) + return; + + while (!omp_private_member_vec.is_empty ()) + { + tree t = omp_private_member_vec.pop (); + if (t == error_mark_node) + { + save.safe_push (t); + continue; + } + tree n = t; + if (t == integer_zero_node) + t = omp_private_member_vec.pop (); + tree *v = omp_private_member_map->get (t); + gcc_assert (v); + save.safe_push (*v); + save.safe_push (t); + if (n != t) + save.safe_push (n); + } + delete omp_private_member_map; + omp_private_member_map = NULL; +} + +/* Restore OpenMP privatization clauses mapping saved by the + above function. */ + +void +restore_omp_privatization_clauses (vec &save) +{ + gcc_assert (omp_private_member_vec.is_empty ()); + omp_private_member_ignore_next = false; + if (save.is_empty ()) + return; + if (save.length () == 1 && save[0] == integer_one_node) + { + omp_private_member_ignore_next = true; + save.release (); + return; + } + + omp_private_member_map = new hash_map ; + while (!save.is_empty ()) + { + tree t = save.pop (); + tree n = t; + if (t != error_mark_node) + { + if (t == integer_one_node) + { + omp_private_member_ignore_next = true; + gcc_assert (save.is_empty ()); + break; + } + if (t == integer_zero_node) + t = save.pop (); + tree &v = omp_private_member_map->get_or_insert (t); + v = save.pop (); + } + omp_private_member_vec.safe_push (t); + if (n != t) + omp_private_member_vec.safe_push (n); + } + save.release (); +} + /* For all variables in the tree_list VARS, mark them as thread local. */ void @@ -6228,9 +7203,10 @@ finish_omp_task (tree clauses, tree body) 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 *lastp) +handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code, + tree declv, tree initv, tree condv, tree incrv, + tree *body, tree *pre_body, tree &clauses, + tree *lastp, int collapse, int ordered) { tree diff, iter_init, iter_incr = NULL, last; tree incr_var = NULL, orig_pre_body, orig_body, c; @@ -6388,10 +7364,25 @@ handle_omp_for_class_iterator (int i, location_t locus, tree declv, tree initv, } incr = cp_convert (TREE_TYPE (diff), incr, tf_warning_or_error); + bool taskloop_iv_seen = false; for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c)) if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE && OMP_CLAUSE_DECL (c) == iter) - break; + { + if (code == OMP_TASKLOOP) + { + taskloop_iv_seen = true; + OMP_CLAUSE_LASTPRIVATE_TASKLOOP_IV (c) = 1; + } + break; + } + else if (code == OMP_TASKLOOP + && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE + && OMP_CLAUSE_DECL (c) == iter) + { + taskloop_iv_seen = true; + OMP_CLAUSE_PRIVATE_TASKLOOP_IV (c) = 1; + } decl = create_temporary_var (TREE_TYPE (diff)); pushdecl (decl); @@ -6399,13 +7390,33 @@ handle_omp_for_class_iterator (int i, location_t locus, tree declv, tree initv, last = create_temporary_var (TREE_TYPE (diff)); pushdecl (last); add_decl_expr (last); - if (c && iter_incr == NULL) + if (c && iter_incr == NULL && TREE_CODE (incr) != INTEGER_CST + && (!ordered || (i < collapse && collapse > 1))) { incr_var = create_temporary_var (TREE_TYPE (diff)); pushdecl (incr_var); add_decl_expr (incr_var); } gcc_assert (stmts_are_full_exprs_p ()); + tree diffvar = NULL_TREE; + if (code == OMP_TASKLOOP) + { + if (!taskloop_iv_seen) + { + tree ivc = build_omp_clause (locus, OMP_CLAUSE_FIRSTPRIVATE); + OMP_CLAUSE_DECL (ivc) = iter; + cxx_omp_finish_clause (ivc, NULL); + OMP_CLAUSE_CHAIN (ivc) = clauses; + clauses = ivc; + } + tree lvc = build_omp_clause (locus, OMP_CLAUSE_FIRSTPRIVATE); + OMP_CLAUSE_DECL (lvc) = last; + OMP_CLAUSE_CHAIN (lvc) = clauses; + clauses = lvc; + diffvar = create_temporary_var (TREE_TYPE (diff)); + pushdecl (diffvar); + add_decl_expr (diffvar); + } orig_pre_body = *pre_body; *pre_body = push_stmt_list (); @@ -6416,19 +7427,32 @@ handle_omp_for_class_iterator (int i, location_t locus, tree declv, tree initv, iter, NOP_EXPR, init, tf_warning_or_error)); init = build_int_cst (TREE_TYPE (diff), 0); - if (c && iter_incr == NULL) + if (c && iter_incr == NULL + && (!ordered || (i < collapse && collapse > 1))) { - finish_expr_stmt (build_x_modify_expr (elocus, - incr_var, NOP_EXPR, - incr, tf_warning_or_error)); - incr = incr_var; + if (incr_var) + { + finish_expr_stmt (build_x_modify_expr (elocus, + incr_var, NOP_EXPR, + incr, tf_warning_or_error)); + incr = incr_var; + } iter_incr = build_x_modify_expr (elocus, iter, PLUS_EXPR, incr, tf_warning_or_error); } + if (c && ordered && i < collapse && collapse > 1) + iter_incr = incr; finish_expr_stmt (build_x_modify_expr (elocus, last, NOP_EXPR, init, tf_warning_or_error)); + if (diffvar) + { + finish_expr_stmt (build_x_modify_expr (elocus, + diffvar, NOP_EXPR, + diff, tf_warning_or_error)); + diff = diffvar; + } *pre_body = pop_stmt_list (*pre_body); cond = cp_build_binary_op (elocus, @@ -6455,7 +7479,22 @@ handle_omp_for_class_iterator (int i, location_t locus, tree declv, tree initv, if (c) { OMP_CLAUSE_LASTPRIVATE_STMT (c) = push_stmt_list (); - finish_expr_stmt (iter_incr); + if (!ordered) + finish_expr_stmt (iter_incr); + else + { + iter_init = decl; + if (i < collapse && collapse > 1 && !error_operand_p (iter_incr)) + iter_init = build2 (PLUS_EXPR, TREE_TYPE (diff), + iter_init, iter_incr); + iter_init = build2 (MINUS_EXPR, TREE_TYPE (diff), iter_init, last); + iter_init = build_x_modify_expr (elocus, + iter, PLUS_EXPR, iter_init, + tf_warning_or_error); + if (iter_init != error_mark_node) + iter_init = build1 (NOP_EXPR, void_type_node, iter_init); + finish_expr_stmt (iter_init); + } OMP_CLAUSE_LASTPRIVATE_STMT (c) = pop_stmt_list (OMP_CLAUSE_LASTPRIVATE_STMT (c)); } @@ -6477,18 +7516,29 @@ handle_omp_for_class_iterator (int i, location_t locus, tree declv, tree initv, sk_omp scope. */ tree -finish_omp_for (location_t locus, enum tree_code code, tree declv, tree initv, - tree condv, tree incrv, tree body, tree pre_body, tree clauses) +finish_omp_for (location_t locus, enum tree_code code, tree declv, + tree orig_declv, tree initv, tree condv, tree incrv, + tree body, tree pre_body, tree clauses) { tree omp_for = NULL, orig_incr = NULL; tree decl = NULL, init, cond, incr, orig_decl = NULL_TREE, block = NULL_TREE; tree last = NULL_TREE; location_t elocus; int i; + int collapse = 1; + int ordered = 0; 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)); + if (TREE_VEC_LENGTH (declv) > 1) + { + tree c = find_omp_clause (clauses, OMP_CLAUSE_COLLAPSE); + if (c) + collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (c)); + if (collapse != TREE_VEC_LENGTH (declv)) + ordered = TREE_VEC_LENGTH (declv); + } for (i = 0; i < TREE_VEC_LENGTH (declv); i++) { decl = TREE_VEC_ELT (declv, i); @@ -6572,6 +7622,9 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv, tree initv, return add_stmt (stmt); } + if (!orig_declv) + orig_declv = copy_node (declv); + if (processing_template_decl) orig_incr = make_tree_vec (TREE_VEC_LENGTH (incrv)); @@ -6614,9 +7667,10 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv, tree initv, } if (code == CILK_FOR && i == 0) orig_decl = decl; - if (handle_omp_for_class_iterator (i, locus, declv, initv, condv, - incrv, &body, &pre_body, - clauses, &last)) + if (handle_omp_for_class_iterator (i, locus, code, declv, initv, + condv, incrv, &body, &pre_body, + clauses, &last, collapse, + ordered)) return NULL; continue; } @@ -6672,8 +7726,8 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv, tree initv, if (code == CILK_FOR && !processing_template_decl) block = push_stmt_list (); - omp_for = c_finish_omp_for (locus, code, declv, initv, condv, incrv, - body, pre_body); + omp_for = c_finish_omp_for (locus, code, declv, orig_declv, initv, condv, + incrv, body, pre_body); if (omp_for == NULL) { @@ -6716,6 +7770,68 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv, tree initv, } OMP_FOR_CLAUSES (omp_for) = clauses; + /* For simd loops with non-static data member iterators, we could have added + OMP_CLAUSE_LINEAR clauses without OMP_CLAUSE_LINEAR_STEP. As we know the + step at this point, fill it in. */ + if (code == OMP_SIMD && !processing_template_decl + && TREE_VEC_LENGTH (OMP_FOR_INCR (omp_for)) == 1) + for (tree c = find_omp_clause (clauses, OMP_CLAUSE_LINEAR); c; + c = find_omp_clause (OMP_CLAUSE_CHAIN (c), OMP_CLAUSE_LINEAR)) + if (OMP_CLAUSE_LINEAR_STEP (c) == NULL_TREE) + { + decl = TREE_OPERAND (TREE_VEC_ELT (OMP_FOR_INIT (omp_for), 0), 0); + gcc_assert (decl == OMP_CLAUSE_DECL (c)); + incr = TREE_VEC_ELT (OMP_FOR_INCR (omp_for), 0); + tree step, stept; + switch (TREE_CODE (incr)) + { + case PREINCREMENT_EXPR: + case POSTINCREMENT_EXPR: + /* c_omp_for_incr_canonicalize_ptr() should have been + called to massage things appropriately. */ + gcc_assert (!POINTER_TYPE_P (TREE_TYPE (decl))); + OMP_CLAUSE_LINEAR_STEP (c) = build_int_cst (TREE_TYPE (decl), 1); + break; + case PREDECREMENT_EXPR: + case POSTDECREMENT_EXPR: + /* c_omp_for_incr_canonicalize_ptr() should have been + called to massage things appropriately. */ + gcc_assert (!POINTER_TYPE_P (TREE_TYPE (decl))); + OMP_CLAUSE_LINEAR_STEP (c) + = build_int_cst (TREE_TYPE (decl), -1); + break; + case MODIFY_EXPR: + gcc_assert (TREE_OPERAND (incr, 0) == decl); + incr = TREE_OPERAND (incr, 1); + switch (TREE_CODE (incr)) + { + case PLUS_EXPR: + if (TREE_OPERAND (incr, 1) == decl) + step = TREE_OPERAND (incr, 0); + else + step = TREE_OPERAND (incr, 1); + break; + case MINUS_EXPR: + case POINTER_PLUS_EXPR: + gcc_assert (TREE_OPERAND (incr, 0) == decl); + step = TREE_OPERAND (incr, 1); + break; + default: + gcc_unreachable (); + } + stept = TREE_TYPE (decl); + if (POINTER_TYPE_P (stept)) + stept = sizetype; + step = fold_convert (stept, step); + if (TREE_CODE (incr) == MINUS_EXPR) + step = fold_build1 (NEGATE_EXPR, stept, step); + OMP_CLAUSE_LINEAR_STEP (c) = step; + break; + default: + gcc_unreachable (); + } + } + if (block) { tree omp_par = make_node (OMP_PARALLEL); @@ -6802,7 +7918,7 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv, tree initv, OMP_CLAUSE_OPERAND (c, 0) = cilk_for_number_of_iterations (omp_for); OMP_CLAUSE_CHAIN (c) = clauses; - OMP_PARALLEL_CLAUSES (omp_par) = finish_omp_clauses (c); + OMP_PARALLEL_CLAUSES (omp_par) = finish_omp_clauses (c, false); add_stmt (omp_par); return omp_par; } diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 8d21be5b64e..4bd35774cf9 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,27 @@ +2015-10-13 Jakub Jelinek + Ilya Verbin + + * f95-lang.c (DEF_FUNCTION_TYPE_9, DEF_FUNCTION_TYPE_10, + DEF_FUNCTION_TYPE_11, DEF_FUNCTION_TYPE_VAR_1): Define. + * trans-openmp.c (gfc_trans_omp_clauses): Set + OMP_CLAUSE_IF_MODIFIER to ERROR_MARK, OMP_CLAUSE_ORDERED_EXPR + to NULL. + (gfc_trans_omp_critical): Adjust for addition of clauses. + (gfc_trans_omp_ordered): Likewise. + * types.def (BT_FN_BOOL_UINT_LONGPTR_LONGPTR_LONGPTR, + BT_FN_BOOL_UINT_ULLPTR_ULLPTR_ULLPTR, + BT_FN_BOOL_UINT_LONGPTR_LONG_LONGPTR_LONGPTR, + BT_FN_BOOL_UINT_ULLPTR_ULL_ULLPTR_ULLPTR, + BT_FN_VOID_INT_SIZE_PTR_PTR_PTR_UINT_PTR, + BT_FN_VOID_INT_OMPFN_SIZE_PTR_PTR_PTR_UINT_PTR, + BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR_INT, + BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_UINT_LONG_INT_LONG_LONG_LONG, + BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_UINT_LONG_INT_ULL_ULL_ULL, + BT_FN_VOID_LONG_VAR, BT_FN_VOID_ULL_VAR): New. + (BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR, + BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR, + BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR): Remove. + 2015-10-07 Andre Vehreschild PR fortran/65889 diff --git a/gcc/fortran/f95-lang.c b/gcc/fortran/f95-lang.c index 0bcfb3f61f6..67b0bac6e61 100644 --- a/gcc/fortran/f95-lang.c +++ b/gcc/fortran/f95-lang.c @@ -633,7 +633,14 @@ gfc_init_builtin_functions (void) ARG6, ARG7) NAME, #define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7, ARG8) NAME, +#define DEF_FUNCTION_TYPE_9(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9) NAME, +#define DEF_FUNCTION_TYPE_10(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9, ARG10) NAME, +#define DEF_FUNCTION_TYPE_11(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) NAME, #define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME, +#define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME, #define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME, #define DEF_FUNCTION_TYPE_VAR_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6) NAME, @@ -651,7 +658,11 @@ gfc_init_builtin_functions (void) #undef DEF_FUNCTION_TYPE_6 #undef DEF_FUNCTION_TYPE_7 #undef DEF_FUNCTION_TYPE_8 +#undef DEF_FUNCTION_TYPE_9 +#undef DEF_FUNCTION_TYPE_10 +#undef DEF_FUNCTION_TYPE_11 #undef DEF_FUNCTION_TYPE_VAR_0 +#undef DEF_FUNCTION_TYPE_VAR_1 #undef DEF_FUNCTION_TYPE_VAR_2 #undef DEF_FUNCTION_TYPE_VAR_6 #undef DEF_FUNCTION_TYPE_VAR_7 @@ -1086,10 +1097,60 @@ gfc_init_builtin_functions (void) builtin_types[(int) ARG7], \ builtin_types[(int) ARG8], \ NULL_TREE); +#define DEF_FUNCTION_TYPE_9(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9) \ + builtin_types[(int) ENUM] \ + = build_function_type_list (builtin_types[(int) RETURN], \ + builtin_types[(int) ARG1], \ + builtin_types[(int) ARG2], \ + builtin_types[(int) ARG3], \ + builtin_types[(int) ARG4], \ + builtin_types[(int) ARG5], \ + builtin_types[(int) ARG6], \ + builtin_types[(int) ARG7], \ + builtin_types[(int) ARG8], \ + builtin_types[(int) ARG9], \ + NULL_TREE); +#define DEF_FUNCTION_TYPE_10(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, \ + ARG5, ARG6, ARG7, ARG8, ARG9, ARG10) \ + builtin_types[(int) ENUM] \ + = build_function_type_list (builtin_types[(int) RETURN], \ + builtin_types[(int) ARG1], \ + builtin_types[(int) ARG2], \ + builtin_types[(int) ARG3], \ + builtin_types[(int) ARG4], \ + builtin_types[(int) ARG5], \ + builtin_types[(int) ARG6], \ + builtin_types[(int) ARG7], \ + builtin_types[(int) ARG8], \ + builtin_types[(int) ARG9], \ + builtin_types[(int) ARG10], \ + NULL_TREE); +#define DEF_FUNCTION_TYPE_11(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, \ + ARG5, ARG6, ARG7, ARG8, ARG9, ARG10, ARG11)\ + builtin_types[(int) ENUM] \ + = build_function_type_list (builtin_types[(int) RETURN], \ + builtin_types[(int) ARG1], \ + builtin_types[(int) ARG2], \ + builtin_types[(int) ARG3], \ + builtin_types[(int) ARG4], \ + builtin_types[(int) ARG5], \ + builtin_types[(int) ARG6], \ + builtin_types[(int) ARG7], \ + builtin_types[(int) ARG8], \ + builtin_types[(int) ARG9], \ + builtin_types[(int) ARG10], \ + builtin_types[(int) ARG11], \ + NULL_TREE); #define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \ builtin_types[(int) ENUM] \ = build_varargs_function_type_list (builtin_types[(int) RETURN], \ NULL_TREE); +#define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \ + builtin_types[(int) ENUM] \ + = build_varargs_function_type_list (builtin_types[(int) RETURN], \ + builtin_types[(int) ARG1], \ + NULL_TREE); #define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, ARG1, ARG2) \ builtin_types[(int) ENUM] \ = build_varargs_function_type_list (builtin_types[(int) RETURN], \ @@ -1133,7 +1194,9 @@ gfc_init_builtin_functions (void) #undef DEF_FUNCTION_TYPE_6 #undef DEF_FUNCTION_TYPE_7 #undef DEF_FUNCTION_TYPE_8 +#undef DEF_FUNCTION_TYPE_10 #undef DEF_FUNCTION_TYPE_VAR_0 +#undef DEF_FUNCTION_TYPE_VAR_1 #undef DEF_FUNCTION_TYPE_VAR_2 #undef DEF_FUNCTION_TYPE_VAR_6 #undef DEF_FUNCTION_TYPE_VAR_7 diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c index 294b6ef731d..b6284c9c957 100644 --- a/gcc/fortran/trans-openmp.c +++ b/gcc/fortran/trans-openmp.c @@ -2245,6 +2245,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, gfc_add_block_to_block (block, &se.post); c = build_omp_clause (where.lb->location, OMP_CLAUSE_IF); + OMP_CLAUSE_IF_MODIFIER (c) = ERROR_MARK; OMP_CLAUSE_IF_EXPR (c) = if_var; omp_clauses = gfc_trans_add_clause (c, omp_clauses); } @@ -2348,6 +2349,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, if (clauses->ordered) { c = build_omp_clause (where.lb->location, OMP_CLAUSE_ORDERED); + OMP_CLAUSE_ORDERED_EXPR (c) = NULL_TREE; omp_clauses = gfc_trans_add_clause (c, omp_clauses); } @@ -2523,6 +2525,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, if (clauses->seq) { c = build_omp_clause (where.lb->location, OMP_CLAUSE_ORDERED); + OMP_CLAUSE_ORDERED_EXPR (c) = NULL_TREE; omp_clauses = gfc_trans_add_clause (c, omp_clauses); } if (clauses->independent) @@ -3095,7 +3098,8 @@ gfc_trans_omp_critical (gfc_code *code) if (code->ext.omp_name != NULL) name = get_identifier (code->ext.omp_name); stmt = gfc_trans_code (code->block->next); - return build2_loc (input_location, OMP_CRITICAL, void_type_node, stmt, name); + return build3_loc (input_location, OMP_CRITICAL, void_type_node, stmt, + NULL_TREE, name); } typedef struct dovar_init_d { @@ -3486,7 +3490,8 @@ gfc_trans_omp_master (gfc_code *code) static tree gfc_trans_omp_ordered (gfc_code *code) { - return build1_v (OMP_ORDERED, gfc_trans_code (code->block->next)); + return build2_loc (input_location, OMP_ORDERED, void_type_node, + gfc_trans_code (code->block->next), NULL_TREE); } static tree diff --git a/gcc/fortran/types.def b/gcc/fortran/types.def index c460b59400d..ca7565482aa 100644 --- a/gcc/fortran/types.def +++ b/gcc/fortran/types.def @@ -154,6 +154,11 @@ DEF_FUNCTION_TYPE_4 (BT_FN_VOID_SIZE_VPTR_PTR_INT, BT_VOID, BT_SIZE, BT_VOLATILE_PTR, BT_PTR, BT_INT) DEF_FUNCTION_TYPE_4 (BT_FN_VOID_SIZE_CONST_VPTR_PTR_INT, BT_VOID, BT_SIZE, BT_CONST_VOLATILE_PTR, BT_PTR, BT_INT) +DEF_FUNCTION_TYPE_4 (BT_FN_BOOL_UINT_LONGPTR_LONGPTR_LONGPTR, + BT_BOOL, BT_UINT, BT_PTR_LONG, BT_PTR_LONG, BT_PTR_LONG) +DEF_FUNCTION_TYPE_4 (BT_FN_BOOL_UINT_ULLPTR_ULLPTR_ULLPTR, + BT_BOOL, BT_UINT, BT_PTR_ULONGLONG, BT_PTR_ULONGLONG, + BT_PTR_ULONGLONG) DEF_FUNCTION_TYPE_5 (BT_FN_VOID_OMPFN_PTR_UINT_UINT_UINT, BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, BT_UINT, @@ -165,6 +170,12 @@ DEF_FUNCTION_TYPE_5 (BT_FN_VOID_SIZE_VPTR_PTR_PTR_INT, BT_VOID, BT_SIZE, BT_VOLATILE_PTR, BT_PTR, BT_PTR, BT_INT) DEF_FUNCTION_TYPE_5 (BT_FN_VOID_INT_SIZE_PTR_PTR_PTR, BT_VOID, BT_INT, BT_SIZE, BT_PTR, BT_PTR, BT_PTR) +DEF_FUNCTION_TYPE_5 (BT_FN_BOOL_UINT_LONGPTR_LONG_LONGPTR_LONGPTR, + BT_BOOL, BT_UINT, BT_PTR_LONG, BT_LONG, BT_PTR_LONG, + BT_PTR_LONG) +DEF_FUNCTION_TYPE_5 (BT_FN_BOOL_UINT_ULLPTR_ULL_ULLPTR_ULLPTR, + BT_BOOL, BT_UINT, BT_PTR_ULONGLONG, BT_ULONGLONG, + BT_PTR_ULONGLONG, BT_PTR_ULONGLONG) DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_LONG_LONG_LONG_LONG_LONGPTR_LONGPTR, BT_BOOL, BT_LONG, BT_LONG, BT_LONG, BT_LONG, @@ -189,8 +200,6 @@ DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_VPTR_PTR_I16_BOOL_INT_INT, BT_INT) DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_SIZE_VPTR_PTR_PTR_INT_INT, BT_BOOL, BT_SIZE, BT_VOLATILE_PTR, BT_PTR, BT_PTR, BT_INT, BT_INT) -DEF_FUNCTION_TYPE_6 (BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR, - BT_VOID, BT_INT, BT_PTR, BT_SIZE, BT_PTR, BT_PTR, BT_PTR) DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_UINT, BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, @@ -199,20 +208,39 @@ 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_7 (BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR, - BT_VOID, BT_INT, BT_PTR_FN_VOID_PTR, BT_PTR, BT_SIZE, - BT_PTR, BT_PTR, BT_PTR) +DEF_FUNCTION_TYPE_7 (BT_FN_VOID_INT_SIZE_PTR_PTR_PTR_UINT_PTR, + BT_VOID, BT_INT, BT_SIZE, BT_PTR, BT_PTR, BT_PTR, BT_UINT, + BT_PTR) DEF_FUNCTION_TYPE_8 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT, BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, BT_LONG, BT_LONG, BT_LONG, BT_LONG, BT_UINT) -DEF_FUNCTION_TYPE_8 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR, +DEF_FUNCTION_TYPE_8 (BT_FN_VOID_INT_OMPFN_SIZE_PTR_PTR_PTR_UINT_PTR, + BT_VOID, BT_INT, BT_PTR_FN_VOID_PTR, BT_SIZE, BT_PTR, + BT_PTR, BT_PTR, BT_UINT, BT_PTR) + +DEF_FUNCTION_TYPE_9 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR_INT, BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_PTR_FN_VOID_PTR_PTR, BT_LONG, BT_LONG, - BT_BOOL, BT_UINT, BT_PTR) + BT_BOOL, BT_UINT, BT_PTR, BT_INT) + +DEF_FUNCTION_TYPE_11 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_UINT_LONG_INT_LONG_LONG_LONG, + BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, + BT_PTR_FN_VOID_PTR_PTR, BT_LONG, BT_LONG, + BT_UINT, BT_LONG, BT_INT, BT_LONG, BT_LONG, BT_LONG) +DEF_FUNCTION_TYPE_11 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_UINT_LONG_INT_ULL_ULL_ULL, + BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, + BT_PTR_FN_VOID_PTR_PTR, BT_LONG, BT_LONG, + BT_UINT, BT_LONG, BT_INT, + BT_ULONGLONG, BT_ULONGLONG, BT_ULONGLONG) DEF_FUNCTION_TYPE_VAR_0 (BT_FN_VOID_VAR, BT_VOID) +DEF_FUNCTION_TYPE_VAR_1 (BT_FN_VOID_LONG_VAR, + BT_VOID, BT_LONG) +DEF_FUNCTION_TYPE_VAR_1 (BT_FN_VOID_ULL_VAR, + BT_VOID, BT_ULONGLONG) + DEF_FUNCTION_TYPE_VAR_2 (BT_FN_VOID_INT_INT_VAR, BT_VOID, BT_INT, BT_INT) DEF_FUNCTION_TYPE_VAR_7 (BT_FN_VOID_INT_SIZE_PTR_PTR_PTR_INT_INT_VAR, diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c index f1a7e791e7c..9780220c47d 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -1134,6 +1134,9 @@ dump_gimple_omp_for (pretty_printer *buffer, gomp_for *gs, int spc, int flags) case GF_OMP_FOR_KIND_DISTRIBUTE: kind = " distribute"; break; + case GF_OMP_FOR_KIND_TASKLOOP: + kind = " taskloop"; + break; case GF_OMP_FOR_KIND_CILKFOR: kind = " _Cilk_for"; break; @@ -1174,6 +1177,9 @@ dump_gimple_omp_for (pretty_printer *buffer, gomp_for *gs, int spc, int flags) case GF_OMP_FOR_KIND_DISTRIBUTE: pp_string (buffer, "#pragma omp distribute"); break; + case GF_OMP_FOR_KIND_TASKLOOP: + pp_string (buffer, "#pragma omp taskloop"); + break; case GF_OMP_FOR_KIND_CILKFOR: break; case GF_OMP_FOR_KIND_OACC_LOOP: @@ -1330,6 +1336,12 @@ dump_gimple_omp_target (pretty_printer *buffer, gomp_target *gs, case GF_OMP_TARGET_KIND_UPDATE: kind = " update"; break; + case GF_OMP_TARGET_KIND_ENTER_DATA: + kind = " enter data"; + break; + case GF_OMP_TARGET_KIND_EXIT_DATA: + kind = " exit data"; + break; case GF_OMP_TARGET_KIND_OACC_KERNELS: kind = " oacc_kernels"; break; @@ -1477,9 +1489,6 @@ dump_gimple_omp_block (pretty_printer *buffer, gimple *gs, int spc, int flags) case GIMPLE_OMP_TASKGROUP: pp_string (buffer, "#pragma omp taskgroup"); break; - case GIMPLE_OMP_ORDERED: - pp_string (buffer, "#pragma omp ordered"); - break; case GIMPLE_OMP_SECTION: pp_string (buffer, "#pragma omp section"); break; @@ -1517,6 +1526,32 @@ dump_gimple_omp_critical (pretty_printer *buffer, gomp_critical *gs, flags, false); pp_right_paren (buffer); } + dump_omp_clauses (buffer, gimple_omp_critical_clauses (gs), spc, flags); + if (!gimple_seq_empty_p (gimple_omp_body (gs))) + { + newline_and_indent (buffer, spc + 2); + pp_left_brace (buffer); + pp_newline (buffer); + dump_gimple_seq (buffer, gimple_omp_body (gs), spc + 4, flags); + newline_and_indent (buffer, spc + 2); + pp_right_brace (buffer); + } + } +} + +/* Dump a GIMPLE_OMP_ORDERED tuple on the pretty_printer BUFFER. */ + +static void +dump_gimple_omp_ordered (pretty_printer *buffer, gomp_ordered *gs, + int spc, int flags) +{ + if (flags & TDF_RAW) + dump_gimple_fmt (buffer, spc, flags, "%G <%+BODY <%S> >", gs, + gimple_omp_body (gs)); + else + { + pp_string (buffer, "#pragma omp ordered"); + dump_omp_clauses (buffer, gimple_omp_ordered_clauses (gs), spc, flags); if (!gimple_seq_empty_p (gimple_omp_body (gs))) { newline_and_indent (buffer, spc + 2); @@ -1969,7 +2004,10 @@ dump_gimple_omp_task (pretty_printer *buffer, gomp_task *gs, int spc, else { gimple_seq body; - pp_string (buffer, "#pragma omp task"); + if (gimple_omp_task_taskloop_p (gs)) + pp_string (buffer, "#pragma omp taskloop"); + else + pp_string (buffer, "#pragma omp task"); dump_omp_clauses (buffer, gimple_omp_task_clauses (gs), spc, flags); if (gimple_omp_task_child_fn (gs)) { @@ -2235,11 +2273,15 @@ pp_gimple_stmt_1 (pretty_printer *buffer, gimple *gs, int spc, int flags) case GIMPLE_OMP_MASTER: case GIMPLE_OMP_TASKGROUP: - case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_SECTION: dump_gimple_omp_block (buffer, gs, spc, flags); break; + case GIMPLE_OMP_ORDERED: + dump_gimple_omp_ordered (buffer, as_a (gs), spc, + flags); + break; + case GIMPLE_OMP_CRITICAL: dump_gimple_omp_critical (buffer, as_a (gs), spc, flags); diff --git a/gcc/gimple-walk.c b/gcc/gimple-walk.c index e62cf62be12..b045c67d357 100644 --- a/gcc/gimple-walk.c +++ b/gcc/gimple-walk.c @@ -320,6 +320,20 @@ walk_gimple_op (gimple *stmt, walk_tree_fn callback_op, callback_op, wi, pset); if (ret) return ret; + ret = walk_tree (gimple_omp_critical_clauses_ptr (omp_stmt), + callback_op, wi, pset); + if (ret) + return ret; + } + break; + + case GIMPLE_OMP_ORDERED: + { + gomp_ordered *omp_stmt = as_a (stmt); + ret = walk_tree (gimple_omp_ordered_clauses_ptr (omp_stmt), + callback_op, wi, pset); + if (ret) + return ret; } break; diff --git a/gcc/gimple.c b/gcc/gimple.c index c3762e19993..5312d6e055d 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -838,14 +838,16 @@ gimple_build_debug_source_bind_stat (tree var, tree value, /* Build a GIMPLE_OMP_CRITICAL statement. BODY is the sequence of statements for which only one thread can execute. - NAME is optional identifier for this critical block. */ + NAME is optional identifier for this critical block. + CLAUSES are clauses for this critical block. */ gomp_critical * -gimple_build_omp_critical (gimple_seq body, tree name) +gimple_build_omp_critical (gimple_seq body, tree name, tree clauses) { gomp_critical *p = as_a (gimple_alloc (GIMPLE_OMP_CRITICAL, 0)); gimple_omp_critical_set_name (p, name); + gimple_omp_critical_set_clauses (p, clauses); if (body) gimple_omp_set_body (p, body); @@ -994,12 +996,15 @@ gimple_build_omp_continue (tree control_def, tree control_use) /* Build a GIMPLE_OMP_ORDERED statement. BODY is the sequence of statements inside a loop that will executed in - sequence. */ + sequence. + CLAUSES are clauses for this statement. */ -gimple * -gimple_build_omp_ordered (gimple_seq body) +gomp_ordered * +gimple_build_omp_ordered (gimple_seq body, tree clauses) { - gimple *p = gimple_alloc (GIMPLE_OMP_ORDERED, 0); + gomp_ordered *p + = as_a (gimple_alloc (GIMPLE_OMP_ORDERED, 0)); + gimple_omp_ordered_set_clauses (p, clauses); if (body) gimple_omp_set_body (p, body); @@ -1779,9 +1784,18 @@ gimple_copy (gimple *stmt) goto copy_omp_body; case GIMPLE_OMP_CRITICAL: - t = unshare_expr (gimple_omp_critical_name ( - as_a (stmt))); + t = unshare_expr (gimple_omp_critical_name + (as_a (stmt))); gimple_omp_critical_set_name (as_a (copy), t); + t = unshare_expr (gimple_omp_critical_clauses + (as_a (stmt))); + gimple_omp_critical_set_clauses (as_a (copy), t); + goto copy_omp_body; + + case GIMPLE_OMP_ORDERED: + t = unshare_expr (gimple_omp_ordered_clauses + (as_a (stmt))); + gimple_omp_ordered_set_clauses (as_a (copy), t); goto copy_omp_body; case GIMPLE_OMP_SECTIONS: @@ -1797,7 +1811,6 @@ gimple_copy (gimple *stmt) case GIMPLE_OMP_SECTION: case GIMPLE_OMP_MASTER: case GIMPLE_OMP_TASKGROUP: - case GIMPLE_OMP_ORDERED: copy_omp_body: new_seq = gimple_seq_copy (gimple_omp_body (stmt)); gimple_omp_set_body (copy, new_seq); diff --git a/gcc/gimple.def b/gcc/gimple.def index 96602df91fc..d3ca402aea7 100644 --- a/gcc/gimple.def +++ b/gcc/gimple.def @@ -283,10 +283,6 @@ DEFGSCODE(GIMPLE_OMP_MASTER, "gimple_omp_master", GSS_OMP) BODY is the sequence of statements to execute in the taskgroup section. */ DEFGSCODE(GIMPLE_OMP_TASKGROUP, "gimple_omp_taskgroup", GSS_OMP) -/* GIMPLE_OMP_ORDERED represents #pragma omp ordered. - BODY is the sequence of statements to execute in the ordered section. */ -DEFGSCODE(GIMPLE_OMP_ORDERED, "gimple_omp_ordered", GSS_OMP) - /* GIMPLE_OMP_PARALLEL represents #pragma omp parallel [CLAUSES] @@ -375,6 +371,11 @@ DEFGSCODE(GIMPLE_OMP_TARGET, "gimple_omp_target", GSS_OMP_PARALLEL_LAYOUT) CLAUSES is an OMP_CLAUSE chain holding the associated clauses. */ DEFGSCODE(GIMPLE_OMP_TEAMS, "gimple_omp_teams", GSS_OMP_SINGLE_LAYOUT) +/* GIMPLE_OMP_ORDERED represents #pragma omp ordered. + BODY is the sequence of statements to execute in the ordered section. + CLAUSES is an OMP_CLAUSE chain holding the associated clauses. */ +DEFGSCODE(GIMPLE_OMP_ORDERED, "gimple_omp_ordered", GSS_OMP_SINGLE_LAYOUT) + /* GIMPLE_PREDICT specifies a hint for branch prediction. PREDICT is one of the predictors from predict.def. diff --git a/gcc/gimple.h b/gcc/gimple.h index a456f54ed39..02d0db59752 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -146,26 +146,30 @@ enum gf_mask { GF_CALL_CTRL_ALTERING = 1 << 7, GF_CALL_WITH_BOUNDS = 1 << 8, GF_OMP_PARALLEL_COMBINED = 1 << 0, - GF_OMP_FOR_KIND_MASK = (1 << 3) - 1, + GF_OMP_TASK_TASKLOOP = 1 << 0, + GF_OMP_FOR_KIND_MASK = (1 << 4) - 1, GF_OMP_FOR_KIND_FOR = 0, GF_OMP_FOR_KIND_DISTRIBUTE = 1, - GF_OMP_FOR_KIND_CILKFOR = 2, - GF_OMP_FOR_KIND_OACC_LOOP = 3, + GF_OMP_FOR_KIND_TASKLOOP = 2, + GF_OMP_FOR_KIND_CILKFOR = 3, + GF_OMP_FOR_KIND_OACC_LOOP = 4, /* Flag for SIMD variants of OMP_FOR kinds. */ - GF_OMP_FOR_SIMD = 1 << 2, + GF_OMP_FOR_SIMD = 1 << 3, GF_OMP_FOR_KIND_SIMD = GF_OMP_FOR_SIMD | 0, GF_OMP_FOR_KIND_CILKSIMD = GF_OMP_FOR_SIMD | 1, - GF_OMP_FOR_COMBINED = 1 << 3, - GF_OMP_FOR_COMBINED_INTO = 1 << 4, - GF_OMP_TARGET_KIND_MASK = (1 << 3) - 1, + GF_OMP_FOR_COMBINED = 1 << 4, + GF_OMP_FOR_COMBINED_INTO = 1 << 5, + GF_OMP_TARGET_KIND_MASK = (1 << 4) - 1, GF_OMP_TARGET_KIND_REGION = 0, GF_OMP_TARGET_KIND_DATA = 1, GF_OMP_TARGET_KIND_UPDATE = 2, - GF_OMP_TARGET_KIND_OACC_PARALLEL = 3, - GF_OMP_TARGET_KIND_OACC_KERNELS = 4, - GF_OMP_TARGET_KIND_OACC_DATA = 5, - GF_OMP_TARGET_KIND_OACC_UPDATE = 6, - GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA = 7, + GF_OMP_TARGET_KIND_ENTER_DATA = 3, + GF_OMP_TARGET_KIND_EXIT_DATA = 4, + GF_OMP_TARGET_KIND_OACC_PARALLEL = 5, + GF_OMP_TARGET_KIND_OACC_KERNELS = 6, + GF_OMP_TARGET_KIND_OACC_DATA = 7, + GF_OMP_TARGET_KIND_OACC_UPDATE = 8, + GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA = 9, /* True on an GIMPLE_OMP_RETURN statement if the return does not require a thread synchronization via some sort of barrier. The exact barrier @@ -571,7 +575,10 @@ struct GTY((tag("GSS_OMP_CRITICAL"))) { /* [ WORD 1-7 ] : base class */ - /* [ WORD 8 ] + /* [ WORD 8 ] */ + tree clauses; + + /* [ WORD 9 ] Critical section name. */ tree name; }; @@ -717,7 +724,7 @@ struct GTY((tag("GSS_OMP_CONTINUE"))) tree control_use; }; -/* GIMPLE_OMP_SINGLE, GIMPLE_OMP_TEAMS */ +/* GIMPLE_OMP_SINGLE, GIMPLE_OMP_TEAMS, GIMPLE_OMP_ORDERED */ struct GTY((tag("GSS_OMP_SINGLE_LAYOUT"))) gimple_statement_omp_single_layout : public gimple_statement_omp @@ -742,6 +749,13 @@ struct GTY((tag("GSS_OMP_SINGLE_LAYOUT"))) stmt->code == GIMPLE_OMP_TEAMS. */ }; +struct GTY((tag("GSS_OMP_SINGLE_LAYOUT"))) + gomp_ordered : public gimple_statement_omp_single_layout +{ + /* No extra fields; adds invariant: + stmt->code == GIMPLE_OMP_ORDERED. */ +}; + /* GIMPLE_OMP_ATOMIC_LOAD. Note: This is based on gimple, not g_s_omp, because g_s_omp @@ -1071,6 +1085,14 @@ is_a_helper ::test (gimple *gs) return gs->code == GIMPLE_OMP_CRITICAL; } +template <> +template <> +inline bool +is_a_helper ::test (gimple *gs) +{ + return gs->code == GIMPLE_OMP_ORDERED; +} + template <> template <> inline bool @@ -1279,6 +1301,14 @@ is_a_helper ::test (const gimple *gs) return gs->code == GIMPLE_OMP_CRITICAL; } +template <> +template <> +inline bool +is_a_helper ::test (const gimple *gs) +{ + return gs->code == GIMPLE_OMP_ORDERED; +} + template <> template <> inline bool @@ -1413,7 +1443,7 @@ gdebug *gimple_build_debug_bind_stat (tree, tree, gimple * MEM_STAT_DECL); gdebug *gimple_build_debug_source_bind_stat (tree, tree, gimple * MEM_STAT_DECL); #define gimple_build_debug_source_bind(var,val,stmt) \ gimple_build_debug_source_bind_stat ((var), (val), (stmt) MEM_STAT_INFO) -gomp_critical *gimple_build_omp_critical (gimple_seq, tree); +gomp_critical *gimple_build_omp_critical (gimple_seq, tree, tree); gomp_for *gimple_build_omp_for (gimple_seq, int, tree, size_t, gimple_seq); gomp_parallel *gimple_build_omp_parallel (gimple_seq, tree, tree, tree); gomp_task *gimple_build_omp_task (gimple_seq, tree, tree, tree, tree, @@ -1422,7 +1452,7 @@ gimple *gimple_build_omp_section (gimple_seq); gimple *gimple_build_omp_master (gimple_seq); gimple *gimple_build_omp_taskgroup (gimple_seq); gomp_continue *gimple_build_omp_continue (tree, tree); -gimple *gimple_build_omp_ordered (gimple_seq); +gomp_ordered *gimple_build_omp_ordered (gimple_seq, tree); gimple *gimple_build_omp_return (bool); gomp_sections *gimple_build_omp_sections (gimple_seq, tree); gimple *gimple_build_omp_sections_switch (void); @@ -4658,7 +4688,8 @@ gimple_omp_critical_name (const gomp_critical *crit_stmt) } -/* Return a pointer to the name associated with OMP critical statement GS. */ +/* Return a pointer to the name associated with OMP critical statement + CRIT_STMT. */ static inline tree * gimple_omp_critical_name_ptr (gomp_critical *crit_stmt) @@ -4667,7 +4698,8 @@ gimple_omp_critical_name_ptr (gomp_critical *crit_stmt) } -/* Set NAME to be the name associated with OMP critical statement GS. */ +/* Set NAME to be the name associated with OMP critical statement + CRIT_STMT. */ static inline void gimple_omp_critical_set_name (gomp_critical *crit_stmt, tree name) @@ -4676,6 +4708,64 @@ gimple_omp_critical_set_name (gomp_critical *crit_stmt, tree name) } +/* Return the clauses associated with OMP_CRITICAL statement CRIT_STMT. */ + +static inline tree +gimple_omp_critical_clauses (const gomp_critical *crit_stmt) +{ + return crit_stmt->clauses; +} + + +/* Return a pointer to the clauses associated with OMP critical statement + CRIT_STMT. */ + +static inline tree * +gimple_omp_critical_clauses_ptr (gomp_critical *crit_stmt) +{ + return &crit_stmt->clauses; +} + + +/* Set CLAUSES to be the clauses associated with OMP critical statement + CRIT_STMT. */ + +static inline void +gimple_omp_critical_set_clauses (gomp_critical *crit_stmt, tree clauses) +{ + crit_stmt->clauses = clauses; +} + + +/* Return the clauses associated with OMP_ORDERED statement ORD_STMT. */ + +static inline tree +gimple_omp_ordered_clauses (const gomp_ordered *ord_stmt) +{ + return ord_stmt->clauses; +} + + +/* Return a pointer to the clauses associated with OMP ordered statement + ORD_STMT. */ + +static inline tree * +gimple_omp_ordered_clauses_ptr (gomp_ordered *ord_stmt) +{ + return &ord_stmt->clauses; +} + + +/* Set CLAUSES to be the clauses associated with OMP ordered statement + ORD_STMT. */ + +static inline void +gimple_omp_ordered_set_clauses (gomp_ordered *ord_stmt, tree clauses) +{ + ord_stmt->clauses = clauses; +} + + /* Return the kind of the OMP_FOR statemement G. */ static inline int @@ -5090,6 +5180,31 @@ gimple_omp_task_set_clauses (gimple *gs, tree clauses) } +/* Return true if OMP task statement G has the + GF_OMP_TASK_TASKLOOP flag set. */ + +static inline bool +gimple_omp_task_taskloop_p (const gimple *g) +{ + GIMPLE_CHECK (g, GIMPLE_OMP_TASK); + return (gimple_omp_subcode (g) & GF_OMP_TASK_TASKLOOP) != 0; +} + + +/* Set the GF_OMP_TASK_TASKLOOP field in G depending on the boolean + value of TASKLOOP_P. */ + +static inline void +gimple_omp_task_set_taskloop_p (gimple *g, bool taskloop_p) +{ + GIMPLE_CHECK (g, GIMPLE_OMP_TASK); + if (taskloop_p) + g->subcode |= GF_OMP_TASK_TASKLOOP; + else + g->subcode &= ~GF_OMP_TASK_TASKLOOP; +} + + /* Return the child function used to hold the body of OMP_TASK GS. */ static inline tree diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 25a81f681a9..4a9f7fd6cbf 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -91,6 +91,8 @@ enum gimplify_omp_var_data /* Flag for GOVD_LINEAR or GOVD_LASTPRIVATE: no outer reference. */ GOVD_LINEAR_LASTPRIVATE_NO_OUTER = 16384, + GOVD_MAP_0LEN_ARRAY = 32768, + GOVD_DATA_SHARE_CLASS = (GOVD_SHARED | GOVD_PRIVATE | GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE | GOVD_REDUCTION | GOVD_LINEAR | GOVD_LOCAL) @@ -110,7 +112,11 @@ enum omp_region_type /* Data region. */ ORT_TARGET_DATA = 16, /* Data region with offloading. */ - ORT_TARGET = 32 + ORT_TARGET = 32, + ORT_COMBINED_TARGET = 33, + /* Dummy OpenMP region, used to disable expansion of + DECL_VALUE_EXPRs in taskloop pre body. */ + ORT_NONE = 64 }; /* Gimplify hashtable helper. */ @@ -147,11 +153,16 @@ struct gimplify_omp_ctx struct gimplify_omp_ctx *outer_context; splay_tree variables; hash_set *privatized_types; + /* Iteration variables in an OMP_FOR. */ + vec loop_iter_var; location_t location; enum omp_clause_default_kind default_kind; enum omp_region_type region_type; bool combined_loop; bool distribute; + bool target_map_scalars_firstprivate; + bool target_map_pointers_as_0len_arrays; + bool target_firstprivatize_array_bases; }; static struct gimplify_ctx *gimplify_ctxp; @@ -382,6 +393,7 @@ delete_omp_context (struct gimplify_omp_ctx *c) { splay_tree_delete (c->variables); delete c->privatized_types; + c->loop_iter_var.release (); XDELETE (c); } @@ -1070,7 +1082,7 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p) struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp; /* Mark variable as local. */ - if (ctx && !DECL_EXTERNAL (t) + if (ctx && ctx->region_type != ORT_NONE && !DECL_EXTERNAL (t) && (! DECL_SEEN_IN_BIND_EXPR_P (t) || splay_tree_lookup (ctx->variables, (splay_tree_key) t) == NULL)) @@ -2255,8 +2267,7 @@ maybe_fold_stmt (gimple_stmt_iterator *gsi) { struct gimplify_omp_ctx *ctx; for (ctx = gimplify_omp_ctxp; ctx; ctx = ctx->outer_context) - if (ctx->region_type == ORT_TARGET - || (ctx->region_type & (ORT_PARALLEL | ORT_TASK)) != 0) + if ((ctx->region_type & (ORT_TARGET | ORT_PARALLEL | ORT_TASK)) != 0) return false; return fold_stmt (gsi); } @@ -4467,6 +4478,13 @@ is_gimple_stmt (tree t) case OMP_ORDERED: case OMP_CRITICAL: case OMP_TASK: + case OMP_TARGET: + case OMP_TARGET_DATA: + case OMP_TARGET_UPDATE: + case OMP_TARGET_ENTER_DATA: + case OMP_TARGET_EXIT_DATA: + case OMP_TASKLOOP: + case OMP_TEAMS: /* These are always void. */ return true; @@ -5536,7 +5554,7 @@ omp_firstprivatize_variable (struct gimplify_omp_ctx *ctx, tree decl) { splay_tree_node n; - if (decl == NULL || !DECL_P (decl)) + if (decl == NULL || !DECL_P (decl) || ctx->region_type == ORT_NONE) return; do @@ -5551,8 +5569,13 @@ omp_firstprivatize_variable (struct gimplify_omp_ctx *ctx, tree decl) else return; } - else if (ctx->region_type == ORT_TARGET) - omp_add_variable (ctx, decl, GOVD_MAP | GOVD_MAP_TO_ONLY); + else if ((ctx->region_type & ORT_TARGET) != 0) + { + if (ctx->target_map_scalars_firstprivate) + omp_add_variable (ctx, decl, GOVD_FIRSTPRIVATE); + else + omp_add_variable (ctx, decl, GOVD_MAP | GOVD_MAP_TO_ONLY); + } else if (ctx->region_type != ORT_WORKSHARE && ctx->region_type != ORT_SIMD && ctx->region_type != ORT_TARGET_DATA) @@ -5628,7 +5651,7 @@ omp_add_variable (struct gimplify_omp_ctx *ctx, tree decl, unsigned int flags) unsigned int nflags; tree t; - if (error_operand_p (decl)) + if (error_operand_p (decl) || ctx->region_type == ORT_NONE) return; /* Never elide decls whose type has TREE_ADDRESSABLE set. This means @@ -5638,7 +5661,7 @@ omp_add_variable (struct gimplify_omp_ctx *ctx, tree decl, unsigned int flags) flags |= GOVD_SEEN; n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl); - if (n != NULL && n->value != GOVD_ALIGNED) + if (n != NULL && (n->value & GOVD_DATA_SHARE_CLASS) != 0) { /* We shouldn't be re-adding the decl with the same data sharing class. */ @@ -5668,6 +5691,9 @@ omp_add_variable (struct gimplify_omp_ctx *ctx, tree decl, unsigned int flags) nflags = GOVD_MAP | GOVD_MAP_TO_ONLY | GOVD_EXPLICIT; else if (flags & GOVD_PRIVATE) nflags = GOVD_PRIVATE; + else if ((ctx->region_type & (ORT_TARGET | ORT_TARGET_DATA)) != 0 + && (flags & GOVD_FIRSTPRIVATE)) + nflags = GOVD_PRIVATE | GOVD_EXPLICIT; else nflags = GOVD_FIRSTPRIVATE; nflags |= flags & GOVD_SEEN; @@ -5712,7 +5738,7 @@ omp_add_variable (struct gimplify_omp_ctx *ctx, tree decl, unsigned int flags) if ((flags & GOVD_SHARED) == 0) { t = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (decl))); - if (TREE_CODE (t) != INTEGER_CST) + if (DECL_P (t)) omp_notice_variable (ctx, t, true); } } @@ -5736,7 +5762,7 @@ omp_notice_threadprivate_variable (struct gimplify_omp_ctx *ctx, tree decl, struct gimplify_omp_ctx *octx; for (octx = ctx; octx; octx = octx->outer_context) - if (octx->region_type == ORT_TARGET) + if ((octx->region_type & ORT_TARGET) != 0) { n = splay_tree_lookup (octx->variables, (splay_tree_key)decl); if (n == NULL) @@ -5871,6 +5897,9 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code) if (error_operand_p (decl)) return false; + if (ctx->region_type == ORT_NONE) + return lang_hooks.decls.omp_disregard_value_expr (decl, false); + /* Threadprivate variables are predetermined. */ if (is_global_var (decl)) { @@ -5887,19 +5916,66 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code) } n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl); - if (ctx->region_type == ORT_TARGET) + if ((ctx->region_type & ORT_TARGET) != 0) { ret = lang_hooks.decls.omp_disregard_value_expr (decl, true); if (n == NULL) { - if (!lang_hooks.types.omp_mappable_type (TREE_TYPE (decl))) + unsigned nflags = flags; + if (ctx->target_map_pointers_as_0len_arrays + || ctx->target_map_scalars_firstprivate) + { + bool is_declare_target = false; + bool is_scalar = false; + if (is_global_var (decl) + && varpool_node::get_create (decl)->offloadable) + { + struct gimplify_omp_ctx *octx; + for (octx = ctx->outer_context; + octx; octx = octx->outer_context) + { + n = splay_tree_lookup (octx->variables, + (splay_tree_key)decl); + if (n + && (n->value & GOVD_DATA_SHARE_CLASS) != GOVD_SHARED + && (n->value & GOVD_DATA_SHARE_CLASS) != 0) + break; + } + is_declare_target = octx == NULL; + } + if (!is_declare_target && ctx->target_map_scalars_firstprivate) + { + tree type = TREE_TYPE (decl); + if (TREE_CODE (type) == REFERENCE_TYPE) + type = TREE_TYPE (type); + if (TREE_CODE (type) == COMPLEX_TYPE) + type = TREE_TYPE (type); + if (INTEGRAL_TYPE_P (type) + || SCALAR_FLOAT_TYPE_P (type) + || TREE_CODE (type) == POINTER_TYPE) + is_scalar = true; + } + if (is_declare_target) + ; + else if (ctx->target_map_pointers_as_0len_arrays + && (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE + || (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE + && TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) + == POINTER_TYPE))) + nflags |= GOVD_MAP | GOVD_MAP_0LEN_ARRAY; + else if (is_scalar) + nflags |= GOVD_FIRSTPRIVATE; + } + if (nflags == flags + && !lang_hooks.types.omp_mappable_type (TREE_TYPE (decl))) { error ("%qD referenced in target region does not have " "a mappable type", decl); - omp_add_variable (ctx, decl, GOVD_MAP | GOVD_EXPLICIT | flags); + nflags |= GOVD_MAP | GOVD_EXPLICIT; } - else - omp_add_variable (ctx, decl, GOVD_MAP | flags); + else if (nflags == flags) + nflags |= GOVD_MAP; + omp_add_variable (ctx, decl, nflags); } else { @@ -6046,19 +6122,38 @@ omp_check_private (struct gimplify_omp_ctx *ctx, tree decl, bool copyprivate) { ctx = ctx->outer_context; if (ctx == NULL) - return !(is_global_var (decl) - /* References might be private, but might be shared too, - when checking for copyprivate, assume they might be - private, otherwise assume they might be shared. */ - || (!copyprivate - && lang_hooks.decls.omp_privatize_by_reference (decl))); + { + if (is_global_var (decl)) + return false; + + /* References might be private, but might be shared too, + when checking for copyprivate, assume they might be + private, otherwise assume they might be shared. */ + if (copyprivate) + return true; + + if (lang_hooks.decls.omp_privatize_by_reference (decl)) + return false; + + /* Treat C++ privatized non-static data members outside + of the privatization the same. */ + if (omp_member_access_dummy_var (decl)) + return false; + + return true; + } if ((ctx->region_type & (ORT_TARGET | ORT_TARGET_DATA)) != 0) continue; n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); if (n != NULL) - return (n->value & GOVD_SHARED) == 0; + { + if ((n->value & GOVD_LOCAL) != 0 + && omp_member_access_dummy_var (decl)) + return false; + return (n->value & GOVD_SHARED) == 0; + } } while (ctx->region_type == ORT_WORKSHARE || ctx->region_type == ORT_SIMD); @@ -6095,18 +6190,55 @@ omp_no_lastprivate (struct gimplify_omp_ctx *ctx) while (1); } +/* Callback for walk_tree to find a DECL_EXPR for the given DECL. */ + +static tree +find_decl_expr (tree *tp, int *walk_subtrees, void *data) +{ + tree t = *tp; + + /* If this node has been visited, unmark it and keep looking. */ + if (TREE_CODE (t) == DECL_EXPR && DECL_EXPR_DECL (t) == (tree) data) + return t; + + if (IS_TYPE_OR_DECL_P (t)) + *walk_subtrees = 0; + return NULL_TREE; +} + /* Scan the OMP clauses in *LIST_P, installing mappings into a new and previous omp contexts. */ static void gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, - enum omp_region_type region_type) + enum omp_region_type region_type, + enum tree_code code) { struct gimplify_omp_ctx *ctx, *outer_ctx; tree c; + hash_map *struct_map_to_clause = NULL; + tree *orig_list_p = list_p; ctx = new_omp_context (region_type); outer_ctx = ctx->outer_context; + if (code == OMP_TARGET && !lang_GNU_Fortran ()) + { + ctx->target_map_pointers_as_0len_arrays = true; + /* FIXME: For Fortran we want to set this too, when + the Fortran FE is updated to OpenMP 4.5. */ + ctx->target_map_scalars_firstprivate = true; + } + if (!lang_GNU_Fortran ()) + switch (code) + { + case OMP_TARGET: + case OMP_TARGET_DATA: + case OMP_TARGET_ENTER_DATA: + case OMP_TARGET_EXIT_DATA: + ctx->target_firstprivatize_array_bases = true; + default: + break; + } while ((c = *list_p) != NULL) { @@ -6151,6 +6283,12 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, && splay_tree_lookup (outer_ctx->variables, (splay_tree_key) decl) == NULL) omp_add_variable (outer_ctx, decl, GOVD_SHARED | GOVD_SEEN); + else if (outer_ctx + && (outer_ctx->region_type & ORT_TASK) != 0 + && outer_ctx->combined_loop + && splay_tree_lookup (outer_ctx->variables, + (splay_tree_key) decl) == NULL) + omp_add_variable (outer_ctx, decl, GOVD_LASTPRIVATE | GOVD_SEEN); else if (outer_ctx && outer_ctx->region_type == ORT_WORKSHARE && outer_ctx->combined_loop @@ -6171,7 +6309,28 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, case OMP_CLAUSE_REDUCTION: flags = GOVD_REDUCTION | GOVD_SEEN | GOVD_EXPLICIT; check_non_private = "reduction"; - goto do_add; + decl = OMP_CLAUSE_DECL (c); + if (TREE_CODE (decl) == MEM_REF) + { + tree type = TREE_TYPE (decl); + if (gimplify_expr (&TYPE_MAX_VALUE (TYPE_DOMAIN (type)), pre_p, + NULL, is_gimple_val, fb_rvalue) == GS_ERROR) + { + remove = true; + break; + } + tree v = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); + if (DECL_P (v)) + { + omp_firstprivatize_variable (ctx, v); + omp_notice_variable (ctx, v, true); + } + decl = TREE_OPERAND (decl, 0); + if (TREE_CODE (decl) == ADDR_EXPR + || TREE_CODE (decl) == INDIRECT_REF) + decl = TREE_OPERAND (decl, 0); + } + goto do_add_decl; case OMP_CLAUSE_LINEAR: if (gimplify_expr (&OMP_CLAUSE_LINEAR_STEP (c), pre_p, NULL, is_gimple_val, fb_rvalue) == GS_ERROR) @@ -6181,6 +6340,36 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, } else { + if (code == OMP_SIMD + && !OMP_CLAUSE_LINEAR_NO_COPYIN (c)) + { + struct gimplify_omp_ctx *octx = outer_ctx; + if (octx + && octx->region_type == ORT_WORKSHARE + && octx->combined_loop + && !octx->distribute) + { + if (octx->outer_context + && (octx->outer_context->region_type + == ORT_COMBINED_PARALLEL)) + octx = octx->outer_context->outer_context; + else + octx = octx->outer_context; + } + if (octx + && octx->region_type == ORT_WORKSHARE + && octx->combined_loop + && octx->distribute + && !lang_GNU_Fortran ()) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% clause for variable other than " + "loop iterator specified on construct " + "combined with %"); + remove = true; + break; + } + } /* For combined #pragma omp parallel for simd, need to put lastprivate and perhaps firstprivate too on the parallel. Similarly for #pragma omp for simd. */ @@ -6199,6 +6388,11 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, decl = NULL_TREE; break; } + flags = GOVD_SEEN; + if (!OMP_CLAUSE_LINEAR_NO_COPYIN (c)) + flags |= GOVD_FIRSTPRIVATE; + if (!OMP_CLAUSE_LINEAR_NO_COPYOUT (c)) + flags |= GOVD_LASTPRIVATE; if (octx && octx->region_type == ORT_WORKSHARE && octx->combined_loop) @@ -6212,19 +6406,28 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, else if (omp_check_private (octx, decl, false)) break; } + else if (octx + && (octx->region_type & ORT_TASK) != 0 + && octx->combined_loop) + ; + else if (octx + && octx->region_type == ORT_COMBINED_PARALLEL + && ctx->region_type == ORT_WORKSHARE + && octx == outer_ctx) + flags = GOVD_SEEN | GOVD_SHARED; + else if (octx + && octx->region_type == ORT_COMBINED_TARGET) + flags &= ~GOVD_LASTPRIVATE; else break; - if (splay_tree_lookup (octx->variables, - (splay_tree_key) decl) != NULL) + splay_tree_node on + = splay_tree_lookup (octx->variables, + (splay_tree_key) decl); + if (on && (on->value & GOVD_DATA_SHARE_CLASS) != 0) { octx = NULL; break; } - flags = GOVD_SEEN; - if (!OMP_CLAUSE_LINEAR_NO_COPYIN (c)) - flags |= GOVD_FIRSTPRIVATE; - if (!OMP_CLAUSE_LINEAR_NO_COPYOUT (c)) - flags |= GOVD_LASTPRIVATE; omp_add_variable (octx, decl, flags); if (octx->outer_context == NULL) break; @@ -6249,10 +6452,24 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, case OMP_CLAUSE_MAP: decl = OMP_CLAUSE_DECL (c); if (error_operand_p (decl)) + remove = true; + switch (code) { - remove = true; + case OMP_TARGET: + break; + case OMP_TARGET_DATA: + case OMP_TARGET_ENTER_DATA: + case OMP_TARGET_EXIT_DATA: + if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER) + /* For target {,enter ,exit }data only the array slice is + mapped, but not the pointer to it. */ + remove = true; + break; + default: break; } + if (remove) + break; if (OMP_CLAUSE_SIZE (c) == NULL_TREE) OMP_CLAUSE_SIZE (c) = DECL_P (decl) ? DECL_SIZE_UNIT (decl) : TYPE_SIZE_UNIT (TREE_TYPE (decl)); @@ -6262,21 +6479,254 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, remove = true; break; } + else if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER + && TREE_CODE (OMP_CLAUSE_SIZE (c)) != INTEGER_CST) + { + OMP_CLAUSE_SIZE (c) + = get_initialized_tmp_var (OMP_CLAUSE_SIZE (c), pre_p, NULL); + omp_add_variable (ctx, OMP_CLAUSE_SIZE (c), + GOVD_FIRSTPRIVATE | GOVD_SEEN); + } if (!DECL_P (decl)) { - if (gimplify_expr (&OMP_CLAUSE_DECL (c), pre_p, - NULL, is_gimple_lvalue, fb_lvalue) + tree d = decl, *pd; + if (TREE_CODE (d) == ARRAY_REF) + { + while (TREE_CODE (d) == ARRAY_REF) + d = TREE_OPERAND (d, 0); + if (TREE_CODE (d) == COMPONENT_REF + && TREE_CODE (TREE_TYPE (d)) == ARRAY_TYPE) + decl = d; + } + pd = &OMP_CLAUSE_DECL (c); + if (d == decl + && TREE_CODE (decl) == INDIRECT_REF + && TREE_CODE (TREE_OPERAND (decl, 0)) == COMPONENT_REF + && (TREE_CODE (TREE_TYPE (TREE_OPERAND (decl, 0))) + == REFERENCE_TYPE)) + { + pd = &TREE_OPERAND (decl, 0); + decl = TREE_OPERAND (decl, 0); + } + if (TREE_CODE (decl) == COMPONENT_REF) + { + while (TREE_CODE (decl) == COMPONENT_REF) + decl = TREE_OPERAND (decl, 0); + } + if (gimplify_expr (pd, pre_p, NULL, is_gimple_lvalue, fb_lvalue) == GS_ERROR) { remove = true; break; } + if (DECL_P (decl)) + { + if (error_operand_p (decl)) + { + remove = true; + break; + } + + if (TYPE_SIZE_UNIT (TREE_TYPE (decl)) == NULL + || (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (decl))) + != INTEGER_CST)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "mapping field %qE of variable length " + "structure", OMP_CLAUSE_DECL (c)); + remove = true; + break; + } + + tree offset; + HOST_WIDE_INT bitsize, bitpos; + machine_mode mode; + int unsignedp, volatilep = 0; + tree base = OMP_CLAUSE_DECL (c); + while (TREE_CODE (base) == ARRAY_REF) + base = TREE_OPERAND (base, 0); + if (TREE_CODE (base) == INDIRECT_REF) + base = TREE_OPERAND (base, 0); + base = get_inner_reference (base, &bitsize, &bitpos, &offset, + &mode, &unsignedp, + &volatilep, false); + gcc_assert (base == decl + && (offset == NULL_TREE + || TREE_CODE (offset) == INTEGER_CST)); + + splay_tree_node n + = splay_tree_lookup (ctx->variables, (splay_tree_key)decl); + bool ptr = (OMP_CLAUSE_MAP_KIND (c) + == GOMP_MAP_FIRSTPRIVATE_POINTER); + if (n == NULL || (n->value & (ptr ? GOVD_PRIVATE + : GOVD_MAP)) == 0) + { + if (ptr) + { + tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), + OMP_CLAUSE_PRIVATE); + OMP_CLAUSE_DECL (c2) = decl; + OMP_CLAUSE_CHAIN (c2) = *orig_list_p; + *orig_list_p = c2; + if (struct_map_to_clause == NULL) + struct_map_to_clause = new hash_map; + tree *osc; + if (n == NULL || (n->value & GOVD_MAP) == 0) + osc = NULL; + else + osc = struct_map_to_clause->get (decl); + if (osc == NULL) + struct_map_to_clause->put (decl, + tree_cons (NULL_TREE, + c, + NULL_TREE)); + else + *osc = tree_cons (*osc, c, NULL_TREE); + flags = GOVD_PRIVATE | GOVD_EXPLICIT; + goto do_add_decl; + } + *list_p = build_omp_clause (OMP_CLAUSE_LOCATION (c), + OMP_CLAUSE_MAP); + OMP_CLAUSE_SET_MAP_KIND (*list_p, GOMP_MAP_STRUCT); + OMP_CLAUSE_DECL (*list_p) = decl; + OMP_CLAUSE_SIZE (*list_p) = size_int (1); + OMP_CLAUSE_CHAIN (*list_p) = c; + if (struct_map_to_clause == NULL) + struct_map_to_clause = new hash_map; + struct_map_to_clause->put (decl, *list_p); + list_p = &OMP_CLAUSE_CHAIN (*list_p); + flags = GOVD_MAP | GOVD_EXPLICIT; + if (OMP_CLAUSE_MAP_KIND (c) & GOMP_MAP_FLAG_ALWAYS) + flags |= GOVD_SEEN; + goto do_add_decl; + } + else + { + tree *osc = struct_map_to_clause->get (decl); + tree *sc = NULL, *pt = NULL; + if (!ptr && TREE_CODE (*osc) == TREE_LIST) + osc = &TREE_PURPOSE (*osc); + if (OMP_CLAUSE_MAP_KIND (c) & GOMP_MAP_FLAG_ALWAYS) + n->value |= GOVD_SEEN; + offset_int o1, o2; + if (offset) + o1 = wi::to_offset (offset); + else + o1 = 0; + if (bitpos) + o1 = o1 + bitpos / BITS_PER_UNIT; + if (ptr) + pt = osc; + else + sc = &OMP_CLAUSE_CHAIN (*osc); + for (; ptr ? (*pt && (sc = &TREE_VALUE (*pt))) + : *sc != c; + ptr ? (pt = &TREE_CHAIN (*pt)) + : (sc = &OMP_CLAUSE_CHAIN (*sc))) + if (TREE_CODE (OMP_CLAUSE_DECL (*sc)) != COMPONENT_REF + && (TREE_CODE (OMP_CLAUSE_DECL (*sc)) + != INDIRECT_REF) + && TREE_CODE (OMP_CLAUSE_DECL (*sc)) != ARRAY_REF) + break; + else + { + tree offset2; + HOST_WIDE_INT bitsize2, bitpos2; + base = OMP_CLAUSE_DECL (*sc); + if (TREE_CODE (base) == ARRAY_REF) + { + while (TREE_CODE (base) == ARRAY_REF) + base = TREE_OPERAND (base, 0); + if (TREE_CODE (base) != COMPONENT_REF + || (TREE_CODE (TREE_TYPE (base)) + != ARRAY_TYPE)) + break; + } + else if (TREE_CODE (base) == INDIRECT_REF + && (TREE_CODE (TREE_OPERAND (base, 0)) + == COMPONENT_REF) + && (TREE_CODE (TREE_TYPE + (TREE_OPERAND (base, 0))) + == REFERENCE_TYPE)) + base = TREE_OPERAND (base, 0); + base = get_inner_reference (base, &bitsize2, + &bitpos2, &offset2, + &mode, &unsignedp, + &volatilep, false); + if (base != decl) + break; + gcc_assert (offset == NULL_TREE + || TREE_CODE (offset) == INTEGER_CST); + tree d1 = OMP_CLAUSE_DECL (*sc); + tree d2 = OMP_CLAUSE_DECL (c); + while (TREE_CODE (d1) == ARRAY_REF) + d1 = TREE_OPERAND (d1, 0); + while (TREE_CODE (d2) == ARRAY_REF) + d2 = TREE_OPERAND (d2, 0); + if (TREE_CODE (d1) == INDIRECT_REF) + d1 = TREE_OPERAND (d1, 0); + if (TREE_CODE (d2) == INDIRECT_REF) + d2 = TREE_OPERAND (d2, 0); + while (TREE_CODE (d1) == COMPONENT_REF) + if (TREE_CODE (d2) == COMPONENT_REF + && TREE_OPERAND (d1, 1) + == TREE_OPERAND (d2, 1)) + { + d1 = TREE_OPERAND (d1, 0); + d2 = TREE_OPERAND (d2, 0); + } + else + break; + if (d1 == d2) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE appears more than once in map " + "clauses", OMP_CLAUSE_DECL (c)); + remove = true; + break; + } + if (offset2) + o2 = wi::to_offset (offset2); + else + o2 = 0; + if (bitpos2) + o2 = o2 + bitpos2 / BITS_PER_UNIT; + if (wi::ltu_p (o1, o2) + || (wi::eq_p (o1, o2) && bitpos < bitpos2)) + break; + } + if (ptr) + { + if (!remove) + *pt = tree_cons (TREE_PURPOSE (*osc), c, *pt); + break; + } + if (!remove) + OMP_CLAUSE_SIZE (*osc) + = size_binop (PLUS_EXPR, OMP_CLAUSE_SIZE (*osc), + size_one_node); + if (!remove && *sc != c) + { + *list_p = OMP_CLAUSE_CHAIN (c); + OMP_CLAUSE_CHAIN (c) = *sc; + *sc = c; + continue; + } + } + } break; } flags = GOVD_MAP | GOVD_EXPLICIT; goto do_add; case OMP_CLAUSE_DEPEND: + if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK + || OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SOURCE) + { + /* Nothing to do. OMP_CLAUSE_DECL will be lowered in + omp-low.c. */ + break; + } if (TREE_CODE (OMP_CLAUSE_DECL (c)) == COMPOUND_EXPR) { gimplify_expr (&TREE_OPERAND (OMP_CLAUSE_DECL (c), 0), pre_p, @@ -6328,19 +6778,46 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, } goto do_notice; + case OMP_CLAUSE_USE_DEVICE_PTR: + flags = GOVD_FIRSTPRIVATE | GOVD_EXPLICIT; + goto do_add; + case OMP_CLAUSE_IS_DEVICE_PTR: + flags = GOVD_FIRSTPRIVATE | GOVD_EXPLICIT; + goto do_add; + do_add: decl = OMP_CLAUSE_DECL (c); + do_add_decl: if (error_operand_p (decl)) { remove = true; break; } + if (DECL_NAME (decl) == NULL_TREE && (flags & GOVD_SHARED) == 0) + { + tree t = omp_member_access_dummy_var (decl); + if (t) + { + tree v = DECL_VALUE_EXPR (decl); + DECL_NAME (decl) = DECL_NAME (TREE_OPERAND (v, 1)); + if (outer_ctx) + omp_notice_variable (outer_ctx, t, true); + } + } omp_add_variable (ctx, decl, flags); if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION && OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)) { omp_add_variable (ctx, OMP_CLAUSE_REDUCTION_PLACEHOLDER (c), GOVD_LOCAL | GOVD_SEEN); + if (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c) + && walk_tree (&OMP_CLAUSE_REDUCTION_INIT (c), + find_decl_expr, + OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c), + NULL) == NULL_TREE) + omp_add_variable (ctx, + OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c), + GOVD_LOCAL | GOVD_SEEN); gimplify_omp_ctxp = ctx; push_gimplify_context (); @@ -6444,6 +6921,11 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, omp_notice_variable (outer_ctx, decl, true); if (check_non_private && region_type == ORT_WORKSHARE + && (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION + || decl == OMP_CLAUSE_DECL (c) + || (TREE_CODE (OMP_CLAUSE_DECL (c)) == MEM_REF + && (TREE_CODE (TREE_OPERAND (OMP_CLAUSE_DECL (c), 0)) + == ADDR_EXPR))) && omp_check_private (ctx, decl, false)) { error ("%s variable %qE is private in outer context", @@ -6452,8 +6934,33 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, } break; - case OMP_CLAUSE_FINAL: case OMP_CLAUSE_IF: + if (OMP_CLAUSE_IF_MODIFIER (c) != ERROR_MARK + && OMP_CLAUSE_IF_MODIFIER (c) != code) + { + const char *p[2]; + for (int i = 0; i < 2; i++) + switch (i ? OMP_CLAUSE_IF_MODIFIER (c) : code) + { + case OMP_PARALLEL: p[i] = "parallel"; break; + case OMP_TASK: p[i] = "task"; break; + case OMP_TASKLOOP: p[i] = "taskloop"; break; + case OMP_TARGET_DATA: p[i] = "target data"; break; + case OMP_TARGET: p[i] = "target"; break; + case OMP_TARGET_UPDATE: p[i] = "target update"; break; + case OMP_TARGET_ENTER_DATA: + p[i] = "target enter data"; break; + case OMP_TARGET_EXIT_DATA: p[i] = "target exit data"; break; + default: gcc_unreachable (); + } + error_at (OMP_CLAUSE_LOCATION (c), + "expected %qs % clause modifier rather than %qs", + p[0], p[1]); + remove = true; + } + /* Fall through. */ + + case OMP_CLAUSE_FINAL: OMP_CLAUSE_OPERAND (c, 0) = gimple_boolify (OMP_CLAUSE_OPERAND (c, 0)); /* Fall through. */ @@ -6464,21 +6971,29 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, case OMP_CLAUSE_THREAD_LIMIT: case OMP_CLAUSE_DIST_SCHEDULE: case OMP_CLAUSE_DEVICE: + case OMP_CLAUSE_PRIORITY: + case OMP_CLAUSE_GRAINSIZE: + case OMP_CLAUSE_NUM_TASKS: + case OMP_CLAUSE_HINT: case OMP_CLAUSE__CILK_FOR_COUNT_: case OMP_CLAUSE_ASYNC: case OMP_CLAUSE_WAIT: case OMP_CLAUSE_NUM_GANGS: case OMP_CLAUSE_NUM_WORKERS: case OMP_CLAUSE_VECTOR_LENGTH: - case OMP_CLAUSE_GANG: case OMP_CLAUSE_WORKER: case OMP_CLAUSE_VECTOR: if (gimplify_expr (&OMP_CLAUSE_OPERAND (c, 0), pre_p, NULL, is_gimple_val, fb_rvalue) == GS_ERROR) remove = true; - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_GANG - && gimplify_expr (&OMP_CLAUSE_OPERAND (c, 1), pre_p, NULL, - is_gimple_val, fb_rvalue) == GS_ERROR) + break; + + case OMP_CLAUSE_GANG: + if (gimplify_expr (&OMP_CLAUSE_OPERAND (c, 0), pre_p, NULL, + is_gimple_val, fb_rvalue) == GS_ERROR) + remove = true; + if (gimplify_expr (&OMP_CLAUSE_OPERAND (c, 1), pre_p, NULL, + is_gimple_val, fb_rvalue) == GS_ERROR) remove = true; break; @@ -6497,6 +7012,14 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, case OMP_CLAUSE_MERGEABLE: case OMP_CLAUSE_PROC_BIND: case OMP_CLAUSE_SAFELEN: + case OMP_CLAUSE_SIMDLEN: + case OMP_CLAUSE_NOGROUP: + case OMP_CLAUSE_THREADS: + case OMP_CLAUSE_SIMD: + break; + + case OMP_CLAUSE_DEFAULTMAP: + ctx->target_map_scalars_firstprivate = false; break; case OMP_CLAUSE_ALIGNED: @@ -6532,6 +7055,8 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, } gimplify_omp_ctxp = ctx; + if (struct_map_to_clause) + delete struct_map_to_clause; } struct gimplify_adjust_omp_clauses_data @@ -6612,6 +7137,30 @@ gimplify_adjust_omp_clauses_1 (splay_tree_node n, void *data) OMP_CLAUSE_PRIVATE_DEBUG (clause) = 1; else if (code == OMP_CLAUSE_PRIVATE && (flags & GOVD_PRIVATE_OUTER_REF)) OMP_CLAUSE_PRIVATE_OUTER_REF (clause) = 1; + else if (code == OMP_CLAUSE_MAP && (flags & GOVD_MAP_0LEN_ARRAY) != 0) + { + tree nc = build_omp_clause (input_location, OMP_CLAUSE_MAP); + OMP_CLAUSE_DECL (nc) = decl; + if (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE + && TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) == POINTER_TYPE) + OMP_CLAUSE_DECL (clause) + = build_simple_mem_ref_loc (input_location, decl); + OMP_CLAUSE_DECL (clause) + = build2 (MEM_REF, char_type_node, OMP_CLAUSE_DECL (clause), + build_int_cst (build_pointer_type (char_type_node), 0)); + OMP_CLAUSE_SIZE (clause) = size_zero_node; + OMP_CLAUSE_SIZE (nc) = size_zero_node; + OMP_CLAUSE_SET_MAP_KIND (clause, GOMP_MAP_ALLOC); + OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION (clause) = 1; + OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_FIRSTPRIVATE_POINTER); + OMP_CLAUSE_CHAIN (nc) = *list_p; + OMP_CLAUSE_CHAIN (clause) = nc; + struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp; + gimplify_omp_ctxp = ctx->outer_context; + gimplify_expr (&TREE_OPERAND (OMP_CLAUSE_DECL (clause), 0), + pre_p, NULL, is_gimple_val, fb_rvalue); + gimplify_omp_ctxp = ctx; + } else if (code == OMP_CLAUSE_MAP) { OMP_CLAUSE_SET_MAP_KIND (clause, @@ -6638,7 +7187,10 @@ gimplify_adjust_omp_clauses_1 (splay_tree_node n, void *data) OMP_CLAUSE_MAP); OMP_CLAUSE_DECL (nc) = decl; OMP_CLAUSE_SIZE (nc) = size_zero_node; - OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_POINTER); + if (gimplify_omp_ctxp->target_firstprivatize_array_bases) + OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_FIRSTPRIVATE_POINTER); + else + OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_POINTER); OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (clause); OMP_CLAUSE_CHAIN (clause) = nc; } @@ -6666,7 +7218,8 @@ gimplify_adjust_omp_clauses_1 (splay_tree_node n, void *data) } static void -gimplify_adjust_omp_clauses (gimple_seq *pre_p, tree *list_p) +gimplify_adjust_omp_clauses (gimple_seq *pre_p, tree *list_p, + enum tree_code code) { struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp; tree c, decl; @@ -6761,13 +7314,56 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, tree *list_p) case OMP_CLAUSE_MAP: decl = OMP_CLAUSE_DECL (c); if (!DECL_P (decl)) - break; + { + if ((ctx->region_type & ORT_TARGET) != 0 + && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER) + { + if (TREE_CODE (decl) == INDIRECT_REF + && TREE_CODE (TREE_OPERAND (decl, 0)) == COMPONENT_REF + && (TREE_CODE (TREE_TYPE (TREE_OPERAND (decl, 0))) + == REFERENCE_TYPE)) + decl = TREE_OPERAND (decl, 0); + if (TREE_CODE (decl) == COMPONENT_REF) + { + while (TREE_CODE (decl) == COMPONENT_REF) + decl = TREE_OPERAND (decl, 0); + if (DECL_P (decl)) + { + n = splay_tree_lookup (ctx->variables, + (splay_tree_key) decl); + if (!(n->value & GOVD_SEEN)) + remove = true; + } + } + } + break; + } n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); - if (ctx->region_type == ORT_TARGET && !(n->value & GOVD_SEEN)) + if ((ctx->region_type & ORT_TARGET) != 0 + && !(n->value & GOVD_SEEN) + && ((OMP_CLAUSE_MAP_KIND (c) & GOMP_MAP_FLAG_ALWAYS) == 0 + || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_STRUCT)) + { + remove = true; + /* For struct element mapping, if struct is never referenced + in target block and none of the mapping has always modifier, + remove all the struct element mappings, which immediately + follow the GOMP_MAP_STRUCT map clause. */ + if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_STRUCT) + { + HOST_WIDE_INT cnt = tree_to_shwi (OMP_CLAUSE_SIZE (c)); + while (cnt--) + OMP_CLAUSE_CHAIN (c) + = OMP_CLAUSE_CHAIN (OMP_CLAUSE_CHAIN (c)); + } + } + else if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_STRUCT + && code == OMP_TARGET_EXIT_DATA) remove = true; else if (DECL_SIZE (decl) && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST - && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_POINTER) + && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_POINTER + && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_FIRSTPRIVATE_POINTER) { /* For GOMP_MAP_FORCE_DEVICEPTR, we'll never enter here, because for these, TREE_CODE (DECL_SIZE (decl)) will always be @@ -6787,17 +7383,33 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, tree *list_p) omp_notice_variable (ctx->outer_context, OMP_CLAUSE_SIZE (c), true); } - tree nc = build_omp_clause (OMP_CLAUSE_LOCATION (c), - OMP_CLAUSE_MAP); - OMP_CLAUSE_DECL (nc) = decl; - OMP_CLAUSE_SIZE (nc) = size_zero_node; - OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_POINTER); - OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (c); - OMP_CLAUSE_CHAIN (c) = nc; - c = nc; + if (((ctx->region_type & ORT_TARGET) != 0 + || !ctx->target_firstprivatize_array_bases) + && ((n->value & GOVD_SEEN) == 0 + || (n->value & (GOVD_PRIVATE | GOVD_FIRSTPRIVATE)) == 0)) + { + tree nc = build_omp_clause (OMP_CLAUSE_LOCATION (c), + OMP_CLAUSE_MAP); + OMP_CLAUSE_DECL (nc) = decl; + OMP_CLAUSE_SIZE (nc) = size_zero_node; + if (ctx->target_firstprivatize_array_bases) + OMP_CLAUSE_SET_MAP_KIND (nc, + GOMP_MAP_FIRSTPRIVATE_POINTER); + else + OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_POINTER); + OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (c); + OMP_CLAUSE_CHAIN (c) = nc; + c = nc; + } + } + else + { + if (OMP_CLAUSE_SIZE (c) == NULL_TREE) + OMP_CLAUSE_SIZE (c) = DECL_SIZE_UNIT (decl); + if ((n->value & GOVD_SEEN) + && (n->value & (GOVD_PRIVATE | GOVD_FIRSTPRIVATE))) + OMP_CLAUSE_MAP_PRIVATE (c) = 1; } - else if (OMP_CLAUSE_SIZE (c) == NULL_TREE) - OMP_CLAUSE_SIZE (c) = DECL_SIZE_UNIT (decl); break; case OMP_CLAUSE_TO: @@ -6846,7 +7458,18 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, tree *list_p) case OMP_CLAUSE_MERGEABLE: case OMP_CLAUSE_PROC_BIND: case OMP_CLAUSE_SAFELEN: + case OMP_CLAUSE_SIMDLEN: case OMP_CLAUSE_DEPEND: + case OMP_CLAUSE_PRIORITY: + case OMP_CLAUSE_GRAINSIZE: + case OMP_CLAUSE_NUM_TASKS: + case OMP_CLAUSE_NOGROUP: + case OMP_CLAUSE_THREADS: + case OMP_CLAUSE_SIMD: + case OMP_CLAUSE_HINT: + case OMP_CLAUSE_DEFAULTMAP: + case OMP_CLAUSE_USE_DEVICE_PTR: + case OMP_CLAUSE_IS_DEVICE_PTR: case OMP_CLAUSE__CILK_FOR_COUNT_: case OMP_CLAUSE_ASYNC: case OMP_CLAUSE_WAIT: @@ -6890,8 +7513,9 @@ gimplify_oacc_cache (tree *expr_p, gimple_seq *pre_p) { tree expr = *expr_p; - gimplify_scan_omp_clauses (&OACC_CACHE_CLAUSES (expr), pre_p, ORT_WORKSHARE); - gimplify_adjust_omp_clauses (pre_p, &OACC_CACHE_CLAUSES (expr)); + gimplify_scan_omp_clauses (&OACC_CACHE_CLAUSES (expr), pre_p, ORT_WORKSHARE, + OACC_CACHE); + gimplify_adjust_omp_clauses (pre_p, &OACC_CACHE_CLAUSES (expr), OACC_CACHE); /* TODO: Do something sensible with this information. */ @@ -6913,7 +7537,7 @@ gimplify_omp_parallel (tree *expr_p, gimple_seq *pre_p) gimplify_scan_omp_clauses (&OMP_PARALLEL_CLAUSES (expr), pre_p, OMP_PARALLEL_COMBINED (expr) ? ORT_COMBINED_PARALLEL - : ORT_PARALLEL); + : ORT_PARALLEL, OMP_PARALLEL); push_gimplify_context (); @@ -6923,7 +7547,8 @@ gimplify_omp_parallel (tree *expr_p, gimple_seq *pre_p) else pop_gimplify_context (NULL); - gimplify_adjust_omp_clauses (pre_p, &OMP_PARALLEL_CLAUSES (expr)); + gimplify_adjust_omp_clauses (pre_p, &OMP_PARALLEL_CLAUSES (expr), + OMP_PARALLEL); g = gimple_build_omp_parallel (body, OMP_PARALLEL_CLAUSES (expr), @@ -6949,7 +7574,7 @@ gimplify_omp_task (tree *expr_p, gimple_seq *pre_p) gimplify_scan_omp_clauses (&OMP_TASK_CLAUSES (expr), pre_p, find_omp_clause (OMP_TASK_CLAUSES (expr), OMP_CLAUSE_UNTIED) - ? ORT_UNTIED_TASK : ORT_TASK); + ? ORT_UNTIED_TASK : ORT_TASK, OMP_TASK); push_gimplify_context (); @@ -6959,7 +7584,7 @@ gimplify_omp_task (tree *expr_p, gimple_seq *pre_p) else pop_gimplify_context (NULL); - gimplify_adjust_omp_clauses (pre_p, &OMP_TASK_CLAUSES (expr)); + gimplify_adjust_omp_clauses (pre_p, &OMP_TASK_CLAUSES (expr), OMP_TASK); g = gimple_build_omp_task (body, OMP_TASK_CLAUSES (expr), @@ -7007,8 +7632,8 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) gomp_for *gfor; gimple_seq for_body, for_pre_body; int i; - bool simd; bitmap has_decl_expr = NULL; + enum omp_region_type ort = ORT_WORKSHARE; orig_for_stmt = for_stmt = *expr_p; @@ -7018,11 +7643,16 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) case CILK_FOR: case OMP_DISTRIBUTE: case OACC_LOOP: - simd = false; + break; + case OMP_TASKLOOP: + if (find_omp_clause (OMP_FOR_CLAUSES (for_stmt), OMP_CLAUSE_UNTIED)) + ort = ORT_UNTIED_TASK; + else + ort = ORT_TASK; break; case OMP_SIMD: case CILK_SIMD: - simd = true; + ort = ORT_SIMD; break; default: gcc_unreachable (); @@ -7030,7 +7660,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) /* Set OMP_CLAUSE_LINEAR_NO_COPYIN flag on explicit linear clause for the IV. */ - if (simd && TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) == 1) + if (ort == ORT_SIMD && TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) == 1) { t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), 0); gcc_assert (TREE_CODE (t) == MODIFY_EXPR); @@ -7057,14 +7687,16 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) } } - gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p, - simd ? ORT_SIMD : ORT_WORKSHARE); + if (TREE_CODE (for_stmt) != OMP_TASKLOOP) + gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p, ort, + TREE_CODE (for_stmt)); + if (TREE_CODE (for_stmt) == OMP_DISTRIBUTE) gimplify_omp_ctxp->distribute = true; /* Handle OMP_FOR_INIT. */ for_pre_body = NULL; - if (simd && OMP_FOR_PRE_BODY (for_stmt)) + if (ort == ORT_SIMD && OMP_FOR_PRE_BODY (for_stmt)) { has_decl_expr = BITMAP_ALLOC (NULL); if (TREE_CODE (OMP_FOR_PRE_BODY (for_stmt)) == DECL_EXPR @@ -7087,20 +7719,109 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) } } } - gimplify_and_add (OMP_FOR_PRE_BODY (for_stmt), &for_pre_body); + if (OMP_FOR_PRE_BODY (for_stmt)) + { + if (TREE_CODE (for_stmt) != OMP_TASKLOOP || gimplify_omp_ctxp) + gimplify_and_add (OMP_FOR_PRE_BODY (for_stmt), &for_pre_body); + else + { + struct gimplify_omp_ctx ctx; + memset (&ctx, 0, sizeof (ctx)); + ctx.region_type = ORT_NONE; + gimplify_omp_ctxp = &ctx; + gimplify_and_add (OMP_FOR_PRE_BODY (for_stmt), &for_pre_body); + gimplify_omp_ctxp = NULL; + } + } OMP_FOR_PRE_BODY (for_stmt) = NULL_TREE; if (OMP_FOR_INIT (for_stmt) == NULL_TREE) + for_stmt = inner_for_stmt; + + /* For taskloop, need to gimplify the start, end and step before the + taskloop, outside of the taskloop omp context. */ + if (TREE_CODE (orig_for_stmt) == OMP_TASKLOOP) { - for_stmt = inner_for_stmt; - gimplify_omp_ctxp->combined_loop = true; + for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++) + { + t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i); + if (!is_gimple_constant (TREE_OPERAND (t, 1))) + { + TREE_OPERAND (t, 1) + = get_initialized_tmp_var (TREE_OPERAND (t, 1), + pre_p, NULL); + tree c = build_omp_clause (input_location, + OMP_CLAUSE_FIRSTPRIVATE); + OMP_CLAUSE_DECL (c) = TREE_OPERAND (t, 1); + OMP_CLAUSE_CHAIN (c) = OMP_FOR_CLAUSES (orig_for_stmt); + OMP_FOR_CLAUSES (orig_for_stmt) = c; + } + + /* Handle OMP_FOR_COND. */ + t = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), i); + if (!is_gimple_constant (TREE_OPERAND (t, 1))) + { + TREE_OPERAND (t, 1) + = get_initialized_tmp_var (TREE_OPERAND (t, 1), + gimple_seq_empty_p (for_pre_body) + ? pre_p : &for_pre_body, NULL); + tree c = build_omp_clause (input_location, + OMP_CLAUSE_FIRSTPRIVATE); + OMP_CLAUSE_DECL (c) = TREE_OPERAND (t, 1); + OMP_CLAUSE_CHAIN (c) = OMP_FOR_CLAUSES (orig_for_stmt); + OMP_FOR_CLAUSES (orig_for_stmt) = c; + } + + /* Handle OMP_FOR_INCR. */ + t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i); + if (TREE_CODE (t) == MODIFY_EXPR) + { + decl = TREE_OPERAND (t, 0); + t = TREE_OPERAND (t, 1); + tree *tp = &TREE_OPERAND (t, 1); + if (TREE_CODE (t) == PLUS_EXPR && *tp == decl) + tp = &TREE_OPERAND (t, 0); + + if (!is_gimple_constant (*tp)) + { + gimple_seq *seq = gimple_seq_empty_p (for_pre_body) + ? pre_p : &for_pre_body; + *tp = get_initialized_tmp_var (*tp, seq, NULL); + tree c = build_omp_clause (input_location, + OMP_CLAUSE_FIRSTPRIVATE); + OMP_CLAUSE_DECL (c) = *tp; + OMP_CLAUSE_CHAIN (c) = OMP_FOR_CLAUSES (orig_for_stmt); + OMP_FOR_CLAUSES (orig_for_stmt) = c; + } + } + } + + gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (orig_for_stmt), pre_p, ort, + OMP_TASKLOOP); } + if (orig_for_stmt != for_stmt) + gimplify_omp_ctxp->combined_loop = true; + for_body = NULL; 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))); + + tree c = find_omp_clause (OMP_FOR_CLAUSES (for_stmt), OMP_CLAUSE_ORDERED); + bool is_doacross = false; + if (c && OMP_CLAUSE_ORDERED_EXPR (c)) + { + is_doacross = true; + gimplify_omp_ctxp->loop_iter_var.create (TREE_VEC_LENGTH + (OMP_FOR_INIT (for_stmt)) + * 2); + } + int collapse = 1; + c = find_omp_clause (OMP_FOR_CLAUSES (for_stmt), OMP_CLAUSE_COLLAPSE); + if (c) + collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (c)); for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++) { t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i); @@ -7109,16 +7830,25 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) gcc_assert (DECL_P (decl)); gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (decl)) || POINTER_TYPE_P (TREE_TYPE (decl))); + if (is_doacross) + { + if (TREE_CODE (for_stmt) == OMP_FOR && OMP_FOR_ORIG_DECLS (for_stmt)) + gimplify_omp_ctxp->loop_iter_var.quick_push + (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (for_stmt), i)); + else + gimplify_omp_ctxp->loop_iter_var.quick_push (decl); + gimplify_omp_ctxp->loop_iter_var.quick_push (decl); + } /* Make sure the iteration variable is private. */ tree c = NULL_TREE; tree c2 = NULL_TREE; if (orig_for_stmt != for_stmt) /* Do this only on innermost construct for combined ones. */; - else if (simd) + else if (ort == ORT_SIMD) { splay_tree_node n = splay_tree_lookup (gimplify_omp_ctxp->variables, - (splay_tree_key)decl); + (splay_tree_key) decl); omp_is_private (gimplify_omp_ctxp, decl, 1 + (TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) != 1)); @@ -7169,6 +7899,11 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) else if (omp_check_private (outer, decl, false)) outer = NULL; } + else if (((outer->region_type & ORT_TASK) != 0) + && outer->combined_loop + && !omp_check_private (gimplify_omp_ctxp, + decl, false)) + ; else if (outer->region_type != ORT_COMBINED_PARALLEL) outer = NULL; if (outer) @@ -7213,6 +7948,11 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) else if (omp_check_private (outer, decl, false)) outer = NULL; } + else if (((outer->region_type & ORT_TASK) != 0) + && outer->combined_loop + && !omp_check_private (gimplify_omp_ctxp, + decl, false)) + ; else if (outer->region_type != ORT_COMBINED_PARALLEL) outer = NULL; if (outer) @@ -7255,14 +7995,16 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) if (orig_for_stmt != for_stmt) var = decl; else if (!is_gimple_reg (decl) - || (simd && TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) > 1)) + || (ort == ORT_SIMD + && TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) > 1)) { var = create_tmp_var (TREE_TYPE (decl), get_name (decl)); TREE_OPERAND (t, 0) = var; gimplify_seq_add_stmt (&for_body, gimple_build_assign (decl, var)); - if (simd && TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) == 1) + if (ort == ORT_SIMD + && TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) == 1) { c2 = build_omp_clause (input_location, OMP_CLAUSE_LINEAR); OMP_CLAUSE_LINEAR_NO_COPYIN (c2) = 1; @@ -7396,8 +8138,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) OMP_CLAUSE_LINEAR_STEP (c2) = OMP_CLAUSE_LINEAR_STEP (c); } - if ((var != decl || TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) > 1) - && orig_for_stmt == for_stmt) + if ((var != decl || collapse > 1) && orig_for_stmt == for_stmt) { for (c = OMP_FOR_CLAUSES (for_stmt); c ; c = OMP_CLAUSE_CHAIN (c)) if (((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE @@ -7407,16 +8148,22 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) && OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c) == NULL)) && OMP_CLAUSE_DECL (c) == decl) { - t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i); - gcc_assert (TREE_CODE (t) == MODIFY_EXPR); - gcc_assert (TREE_OPERAND (t, 0) == var); - t = TREE_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)); + if (is_doacross && (collapse == 1 || i >= collapse)) + t = var; + else + { + t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i); + gcc_assert (TREE_CODE (t) == MODIFY_EXPR); + gcc_assert (TREE_OPERAND (t, 0) == var); + t = TREE_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), + is_doacross ? var : decl, + TREE_OPERAND (t, 1)); + } gimple_seq *seq; if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE) seq = &OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c); @@ -7429,14 +8176,39 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) BITMAP_FREE (has_decl_expr); - gimplify_and_add (OMP_FOR_BODY (orig_for_stmt), &for_body); + if (TREE_CODE (orig_for_stmt) == OMP_TASKLOOP) + { + push_gimplify_context (); + if (TREE_CODE (OMP_FOR_BODY (orig_for_stmt)) != BIND_EXPR) + { + OMP_FOR_BODY (orig_for_stmt) + = build3 (BIND_EXPR, void_type_node, NULL, + OMP_FOR_BODY (orig_for_stmt), NULL); + TREE_SIDE_EFFECTS (OMP_FOR_BODY (orig_for_stmt)) = 1; + } + } + + gimple *g = gimplify_and_return_first (OMP_FOR_BODY (orig_for_stmt), + &for_body); + + if (TREE_CODE (orig_for_stmt) == OMP_TASKLOOP) + { + if (gimple_code (g) == GIMPLE_BIND) + pop_gimplify_context (g); + else + pop_gimplify_context (NULL); + } if (orig_for_stmt != for_stmt) for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++) { t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i); decl = TREE_OPERAND (t, 0); + struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp; + if (TREE_CODE (orig_for_stmt) == OMP_TASKLOOP) + gimplify_omp_ctxp = ctx->outer_context; var = create_tmp_var (TREE_TYPE (decl), get_name (decl)); + gimplify_omp_ctxp = ctx; omp_add_variable (gimplify_omp_ctxp, var, GOVD_PRIVATE | GOVD_SEEN); TREE_OPERAND (t, 0) = var; t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i); @@ -7444,7 +8216,8 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) TREE_OPERAND (TREE_OPERAND (t, 1), 0) = var; } - gimplify_adjust_omp_clauses (pre_p, &OMP_FOR_CLAUSES (orig_for_stmt)); + gimplify_adjust_omp_clauses (pre_p, &OMP_FOR_CLAUSES (orig_for_stmt), + TREE_CODE (orig_for_stmt)); int kind; switch (TREE_CODE (orig_for_stmt)) @@ -7454,6 +8227,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) case CILK_SIMD: kind = GF_OMP_FOR_KIND_CILKSIMD; break; case CILK_FOR: kind = GF_OMP_FOR_KIND_CILKFOR; break; case OMP_DISTRIBUTE: kind = GF_OMP_FOR_KIND_DISTRIBUTE; break; + case OMP_TASKLOOP: kind = GF_OMP_FOR_KIND_TASKLOOP; break; case OACC_LOOP: kind = GF_OMP_FOR_KIND_OACC_LOOP; break; default: gcc_unreachable (); @@ -7488,7 +8262,139 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) gimple_omp_for_set_incr (gfor, i, TREE_OPERAND (t, 1)); } - gimplify_seq_add_stmt (pre_p, gfor); + /* OMP_TASKLOOP is gimplified as two GIMPLE_OMP_FOR taskloop + constructs with GIMPLE_OMP_TASK sandwiched in between them. + The outer taskloop stands for computing the number of iterations, + counts for collapsed loops and holding taskloop specific clauses. + The task construct stands for the effect of data sharing on the + explicit task it creates and the inner taskloop stands for expansion + of the static loop inside of the explicit task construct. */ + if (TREE_CODE (orig_for_stmt) == OMP_TASKLOOP) + { + tree *gfor_clauses_ptr = gimple_omp_for_clauses_ptr (gfor); + tree task_clauses = NULL_TREE; + tree c = *gfor_clauses_ptr; + tree *gtask_clauses_ptr = &task_clauses; + tree outer_for_clauses = NULL_TREE; + tree *gforo_clauses_ptr = &outer_for_clauses; + for (; c; c = OMP_CLAUSE_CHAIN (c)) + switch (OMP_CLAUSE_CODE (c)) + { + /* These clauses are allowed on task, move them there. */ + case OMP_CLAUSE_SHARED: + case OMP_CLAUSE_FIRSTPRIVATE: + case OMP_CLAUSE_DEFAULT: + case OMP_CLAUSE_IF: + case OMP_CLAUSE_UNTIED: + case OMP_CLAUSE_FINAL: + case OMP_CLAUSE_MERGEABLE: + case OMP_CLAUSE_PRIORITY: + *gtask_clauses_ptr = c; + gtask_clauses_ptr = &OMP_CLAUSE_CHAIN (c); + break; + case OMP_CLAUSE_PRIVATE: + if (OMP_CLAUSE_PRIVATE_TASKLOOP_IV (c)) + { + /* We want private on outer for and firstprivate + on task. */ + *gtask_clauses_ptr + = build_omp_clause (OMP_CLAUSE_LOCATION (c), + OMP_CLAUSE_FIRSTPRIVATE); + OMP_CLAUSE_DECL (*gtask_clauses_ptr) = OMP_CLAUSE_DECL (c); + lang_hooks.decls.omp_finish_clause (*gtask_clauses_ptr, NULL); + gtask_clauses_ptr = &OMP_CLAUSE_CHAIN (*gtask_clauses_ptr); + *gforo_clauses_ptr = c; + gforo_clauses_ptr = &OMP_CLAUSE_CHAIN (c); + } + else + { + *gtask_clauses_ptr = c; + gtask_clauses_ptr = &OMP_CLAUSE_CHAIN (c); + } + break; + /* These clauses go into outer taskloop clauses. */ + case OMP_CLAUSE_GRAINSIZE: + case OMP_CLAUSE_NUM_TASKS: + case OMP_CLAUSE_NOGROUP: + *gforo_clauses_ptr = c; + gforo_clauses_ptr = &OMP_CLAUSE_CHAIN (c); + break; + /* Taskloop clause we duplicate on both taskloops. */ + case OMP_CLAUSE_COLLAPSE: + *gfor_clauses_ptr = c; + gfor_clauses_ptr = &OMP_CLAUSE_CHAIN (c); + *gforo_clauses_ptr = copy_node (c); + gforo_clauses_ptr = &OMP_CLAUSE_CHAIN (*gforo_clauses_ptr); + break; + /* For lastprivate, keep the clause on inner taskloop, and add + a shared clause on task. If the same decl is also firstprivate, + add also firstprivate clause on the inner taskloop. */ + case OMP_CLAUSE_LASTPRIVATE: + if (OMP_CLAUSE_LASTPRIVATE_TASKLOOP_IV (c)) + { + /* For taskloop C++ lastprivate IVs, we want: + 1) private on outer taskloop + 2) firstprivate and shared on task + 3) lastprivate on inner taskloop */ + *gtask_clauses_ptr + = build_omp_clause (OMP_CLAUSE_LOCATION (c), + OMP_CLAUSE_FIRSTPRIVATE); + OMP_CLAUSE_DECL (*gtask_clauses_ptr) = OMP_CLAUSE_DECL (c); + lang_hooks.decls.omp_finish_clause (*gtask_clauses_ptr, NULL); + gtask_clauses_ptr = &OMP_CLAUSE_CHAIN (*gtask_clauses_ptr); + OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c) = 1; + *gforo_clauses_ptr = build_omp_clause (OMP_CLAUSE_LOCATION (c), + OMP_CLAUSE_PRIVATE); + OMP_CLAUSE_DECL (*gforo_clauses_ptr) = OMP_CLAUSE_DECL (c); + OMP_CLAUSE_PRIVATE_TASKLOOP_IV (*gforo_clauses_ptr) = 1; + TREE_TYPE (*gforo_clauses_ptr) = TREE_TYPE (c); + gforo_clauses_ptr = &OMP_CLAUSE_CHAIN (*gforo_clauses_ptr); + } + *gfor_clauses_ptr = c; + gfor_clauses_ptr = &OMP_CLAUSE_CHAIN (c); + *gtask_clauses_ptr + = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_SHARED); + OMP_CLAUSE_DECL (*gtask_clauses_ptr) = OMP_CLAUSE_DECL (c); + if (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c)) + OMP_CLAUSE_SHARED_FIRSTPRIVATE (*gtask_clauses_ptr) = 1; + gtask_clauses_ptr + = &OMP_CLAUSE_CHAIN (*gtask_clauses_ptr); + break; + default: + gcc_unreachable (); + } + *gfor_clauses_ptr = NULL_TREE; + *gtask_clauses_ptr = NULL_TREE; + *gforo_clauses_ptr = NULL_TREE; + g = gimple_build_bind (NULL_TREE, gfor, NULL_TREE); + g = gimple_build_omp_task (g, task_clauses, NULL_TREE, NULL_TREE, + NULL_TREE, NULL_TREE, NULL_TREE); + gimple_omp_task_set_taskloop_p (g, true); + g = gimple_build_bind (NULL_TREE, g, NULL_TREE); + gomp_for *gforo + = gimple_build_omp_for (g, GF_OMP_FOR_KIND_TASKLOOP, outer_for_clauses, + gimple_omp_for_collapse (gfor), + gimple_omp_for_pre_body (gfor)); + gimple_omp_for_set_pre_body (gfor, NULL); + gimple_omp_for_set_combined_p (gforo, true); + gimple_omp_for_set_combined_into_p (gfor, true); + for (i = 0; i < (int) gimple_omp_for_collapse (gfor); i++) + { + t = unshare_expr (gimple_omp_for_index (gfor, i)); + gimple_omp_for_set_index (gforo, i, t); + t = unshare_expr (gimple_omp_for_initial (gfor, i)); + gimple_omp_for_set_initial (gforo, i, t); + gimple_omp_for_set_cond (gforo, i, + gimple_omp_for_cond (gfor, i)); + t = unshare_expr (gimple_omp_for_final (gfor, i)); + gimple_omp_for_set_final (gforo, i, t); + t = unshare_expr (gimple_omp_for_incr (gfor, i)); + gimple_omp_for_set_incr (gforo, i, t); + } + gimplify_seq_add_stmt (pre_p, gforo); + } + else + gimplify_seq_add_stmt (pre_p, gfor); if (ret != GS_ALL_DONE) return GS_ERROR; *expr_p = NULL_TREE; @@ -7511,9 +8417,11 @@ gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p) case OMP_SINGLE: ort = ORT_WORKSHARE; break; + case OMP_TARGET: + ort = OMP_TARGET_COMBINED (expr) ? ORT_COMBINED_TARGET : ORT_TARGET; + break; case OACC_KERNELS: case OACC_PARALLEL: - case OMP_TARGET: ort = ORT_TARGET; break; case OACC_DATA: @@ -7526,8 +8434,9 @@ gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p) default: gcc_unreachable (); } - gimplify_scan_omp_clauses (&OMP_CLAUSES (expr), pre_p, ort); - if (ort == ORT_TARGET || ort == ORT_TARGET_DATA) + gimplify_scan_omp_clauses (&OMP_CLAUSES (expr), pre_p, ort, + TREE_CODE (expr)); + if ((ort & (ORT_TARGET | ORT_TARGET_DATA)) != 0) { push_gimplify_context (); gimple *g = gimplify_and_return_first (OMP_BODY (expr), &body); @@ -7560,7 +8469,7 @@ gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p) } else gimplify_and_add (OMP_BODY (expr), &body); - gimplify_adjust_omp_clauses (pre_p, &OMP_CLAUSES (expr)); + gimplify_adjust_omp_clauses (pre_p, &OMP_CLAUSES (expr), TREE_CODE (expr)); switch (TREE_CODE (expr)) { @@ -7625,12 +8534,19 @@ gimplify_omp_target_update (tree *expr_p, gimple_seq *pre_p) case OMP_TARGET_UPDATE: kind = GF_OMP_TARGET_KIND_UPDATE; break; + case OMP_TARGET_ENTER_DATA: + kind = GF_OMP_TARGET_KIND_ENTER_DATA; + break; + case OMP_TARGET_EXIT_DATA: + kind = GF_OMP_TARGET_KIND_EXIT_DATA; + break; default: gcc_unreachable (); } gimplify_scan_omp_clauses (&OMP_STANDALONE_CLAUSES (expr), pre_p, - ORT_WORKSHARE); - gimplify_adjust_omp_clauses (pre_p, &OMP_STANDALONE_CLAUSES (expr)); + ORT_WORKSHARE, TREE_CODE (expr)); + gimplify_adjust_omp_clauses (pre_p, &OMP_STANDALONE_CLAUSES (expr), + TREE_CODE (expr)); stmt = gimple_build_omp_target (NULL, kind, OMP_STANDALONE_CLAUSES (expr)); gimplify_seq_add_stmt (pre_p, stmt); @@ -7845,6 +8761,93 @@ gimplify_transaction (tree *expr_p, gimple_seq *pre_p) return GS_ALL_DONE; } +/* Gimplify an OMP_ORDERED construct. EXPR is the tree version. BODY + is the OMP_BODY of the original EXPR (which has already been + gimplified so it's not present in the EXPR). + + Return the gimplified GIMPLE_OMP_ORDERED tuple. */ + +static gimple * +gimplify_omp_ordered (tree expr, gimple_seq body) +{ + tree c, decls; + int failures = 0; + unsigned int i; + tree source_c = NULL_TREE; + tree sink_c = NULL_TREE; + + if (gimplify_omp_ctxp) + for (c = OMP_ORDERED_CLAUSES (expr); c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + && gimplify_omp_ctxp->loop_iter_var.is_empty () + && (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK + || OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SOURCE)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% clause must be closely nested " + "inside a loop with % clause with " + "a parameter"); + failures++; + } + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + && OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK) + { + bool fail = false; + for (decls = OMP_CLAUSE_DECL (c), i = 0; + decls && TREE_CODE (decls) == TREE_LIST; + decls = TREE_CHAIN (decls), ++i) + if (i >= gimplify_omp_ctxp->loop_iter_var.length () / 2) + continue; + else if (TREE_VALUE (decls) + != gimplify_omp_ctxp->loop_iter_var[2 * i]) + { + error_at (OMP_CLAUSE_LOCATION (c), + "variable %qE is not an iteration " + "of outermost loop %d, expected %qE", + TREE_VALUE (decls), i + 1, + gimplify_omp_ctxp->loop_iter_var[2 * i]); + fail = true; + failures++; + } + else + TREE_VALUE (decls) + = gimplify_omp_ctxp->loop_iter_var[2 * i + 1]; + if (!fail && i != gimplify_omp_ctxp->loop_iter_var.length () / 2) + { + error_at (OMP_CLAUSE_LOCATION (c), + "number of variables in % " + "clause does not match number of " + "iteration variables"); + failures++; + } + sink_c = c; + } + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + && OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SOURCE) + { + if (source_c) + { + error_at (OMP_CLAUSE_LOCATION (c), + "more than one % clause on an " + "% construct"); + failures++; + } + else + source_c = c; + } + if (source_c && sink_c) + { + error_at (OMP_CLAUSE_LOCATION (source_c), + "% clause specified together with " + "% clauses on the same construct"); + failures++; + } + + if (failures) + return gimple_build_nop (); + return gimple_build_omp_ordered (body, OMP_ORDERED_CLAUSES (expr)); +} + /* Convert the GENERIC expression tree *EXPR_P to GIMPLE. If the expression produces a value to be used as an operand inside a GIMPLE statement, the value will be stored back in *EXPR_P. This value will @@ -8574,6 +9577,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, case CILK_SIMD: case CILK_FOR: case OMP_DISTRIBUTE: + case OMP_TASKLOOP: case OACC_LOOP: ret = gimplify_omp_for (expr_p, pre_p); break; @@ -8619,6 +9623,8 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, case OACC_EXIT_DATA: case OACC_UPDATE: case OMP_TARGET_UPDATE: + case OMP_TARGET_ENTER_DATA: + case OMP_TARGET_EXIT_DATA: gimplify_omp_target_update (expr_p, pre_p); ret = GS_ALL_DONE; break; @@ -8655,11 +9661,17 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, } break; case OMP_ORDERED: - g = gimple_build_omp_ordered (body); + g = gimplify_omp_ordered (*expr_p, body); break; case OMP_CRITICAL: + gimplify_scan_omp_clauses (&OMP_CRITICAL_CLAUSES (*expr_p), + pre_p, ORT_WORKSHARE, OMP_CRITICAL); + gimplify_adjust_omp_clauses (pre_p, + &OMP_CRITICAL_CLAUSES (*expr_p), + OMP_CRITICAL); g = gimple_build_omp_critical (body, - OMP_CRITICAL_NAME (*expr_p)); + OMP_CRITICAL_NAME (*expr_p), + OMP_CRITICAL_CLAUSES (*expr_p)); break; default: gcc_unreachable (); diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c index 71f811cbfc8..f12d3aff96a 100644 --- a/gcc/internal-fn.c +++ b/gcc/internal-fn.c @@ -175,6 +175,22 @@ expand_GOMP_SIMD_LAST_LANE (gcall *) gcc_unreachable (); } +/* This should get expanded in adjust_simduid_builtins. */ + +static void +expand_GOMP_SIMD_ORDERED_START (gcall *) +{ + gcc_unreachable (); +} + +/* This should get expanded in adjust_simduid_builtins. */ + +static void +expand_GOMP_SIMD_ORDERED_END (gcall *) +{ + gcc_unreachable (); +} + /* This should get expanded in the sanopt pass. */ static void diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def index ba5c2c103e6..305cf1b858c 100644 --- a/gcc/internal-fn.def +++ b/gcc/internal-fn.def @@ -44,6 +44,8 @@ DEF_INTERNAL_FN (STORE_LANES, ECF_CONST | ECF_LEAF, NULL) DEF_INTERNAL_FN (GOMP_SIMD_LANE, ECF_NOVOPS | ECF_LEAF | ECF_NOTHROW, NULL) DEF_INTERNAL_FN (GOMP_SIMD_VF, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) DEF_INTERNAL_FN (GOMP_SIMD_LAST_LANE, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) +DEF_INTERNAL_FN (GOMP_SIMD_ORDERED_START, ECF_LEAF | ECF_NOTHROW, NULL) +DEF_INTERNAL_FN (GOMP_SIMD_ORDERED_END, ECF_LEAF | ECF_NOTHROW, NULL) DEF_INTERNAL_FN (LOOP_VECTORIZED, ECF_NOVOPS | ECF_LEAF | ECF_NOTHROW, NULL) DEF_INTERNAL_FN (MASK_LOAD, ECF_PURE | ECF_LEAF, NULL) DEF_INTERNAL_FN (MASK_STORE, ECF_LEAF, NULL) diff --git a/gcc/jit/ChangeLog b/gcc/jit/ChangeLog index 05fa9e6afe9..4922bc0511b 100644 --- a/gcc/jit/ChangeLog +++ b/gcc/jit/ChangeLog @@ -1,3 +1,10 @@ +2015-10-13 Jakub Jelinek + + * jit-builtins.c (DEF_FUNCTION_TYPE_9, DEF_FUNCTION_TYPE_10, + DEF_FUNCTION_TYPE_11): Define. + * jit-builtins.h (DEF_FUNCTION_TYPE_9, DEF_FUNCTION_TYPE_10, + DEF_FUNCTION_TYPE_11): Define. + 2015-09-30 Thomas Schwinge Ulrich Drepper diff --git a/gcc/jit/jit-builtins.c b/gcc/jit/jit-builtins.c index 4ef80edc452..e67c0f86cea 100644 --- a/gcc/jit/jit-builtins.c +++ b/gcc/jit/jit-builtins.c @@ -306,6 +306,20 @@ builtins_manager::make_type (enum jit_builtin_type type_id) ARG6, ARG7, ARG8) \ case ENUM: return make_fn_type (ENUM, RETURN, 0, 8, ARG1, ARG2, ARG3, \ ARG4, ARG5, ARG6, ARG7, ARG8); +#define DEF_FUNCTION_TYPE_9(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9) \ + case ENUM: return make_fn_type (ENUM, RETURN, 0, 9, ARG1, ARG2, ARG3, \ + ARG4, ARG5, ARG6, ARG7, ARG8, ARG9); +#define DEF_FUNCTION_TYPE_10(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9, ARG10) \ + case ENUM: return make_fn_type (ENUM, RETURN, 0, 10, ARG1, ARG2, ARG3, \ + ARG4, ARG5, ARG6, ARG7, ARG8, ARG9, \ + ARG10); +#define DEF_FUNCTION_TYPE_11(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) \ + case ENUM: return make_fn_type (ENUM, RETURN, 0, 11, ARG1, ARG2, ARG3, \ + ARG4, ARG5, ARG6, ARG7, ARG8, ARG9, \ + ARG10, ARG11); #define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \ case ENUM: return make_fn_type (ENUM, RETURN, 1, 0); #define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \ @@ -343,6 +357,9 @@ builtins_manager::make_type (enum jit_builtin_type type_id) #undef DEF_FUNCTION_TYPE_6 #undef DEF_FUNCTION_TYPE_7 #undef DEF_FUNCTION_TYPE_8 +#undef DEF_FUNCTION_TYPE_9 +#undef DEF_FUNCTION_TYPE_10 +#undef DEF_FUNCTION_TYPE_11 #undef DEF_FUNCTION_TYPE_VAR_0 #undef DEF_FUNCTION_TYPE_VAR_1 #undef DEF_FUNCTION_TYPE_VAR_2 diff --git a/gcc/jit/jit-builtins.h b/gcc/jit/jit-builtins.h index 3d762476acc..97e279e328b 100644 --- a/gcc/jit/jit-builtins.h +++ b/gcc/jit/jit-builtins.h @@ -43,6 +43,12 @@ enum jit_builtin_type ARG6, ARG7) NAME, #define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7, ARG8) NAME, +#define DEF_FUNCTION_TYPE_9(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9) NAME, +#define DEF_FUNCTION_TYPE_10(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9, ARG10) NAME, +#define DEF_FUNCTION_TYPE_11(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) NAME, #define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME, #define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME, #define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME, @@ -66,6 +72,9 @@ enum jit_builtin_type #undef DEF_FUNCTION_TYPE_6 #undef DEF_FUNCTION_TYPE_7 #undef DEF_FUNCTION_TYPE_8 +#undef DEF_FUNCTION_TYPE_9 +#undef DEF_FUNCTION_TYPE_10 +#undef DEF_FUNCTION_TYPE_11 #undef DEF_FUNCTION_TYPE_VAR_0 #undef DEF_FUNCTION_TYPE_VAR_1 #undef DEF_FUNCTION_TYPE_VAR_2 diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog index e75b4eaac41..79cd853241a 100644 --- a/gcc/lto/ChangeLog +++ b/gcc/lto/ChangeLog @@ -1,3 +1,8 @@ +2015-10-13 Jakub Jelinek + + * lto-lang.c (DEF_FUNCTION_TYPE_9, DEF_FUNCTION_TYPE_10, + DEF_FUNCTION_TYPE_11): Define. + 2015-10-10 Jan Hubicka * lto.c (hash_canonical_type): Honor diff --git a/gcc/lto/lto-lang.c b/gcc/lto/lto-lang.c index 67ccf57f708..94b54dcb397 100644 --- a/gcc/lto/lto-lang.c +++ b/gcc/lto/lto-lang.c @@ -153,6 +153,12 @@ enum lto_builtin_type ARG6, ARG7) NAME, #define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7, ARG8) NAME, +#define DEF_FUNCTION_TYPE_9(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9) NAME, +#define DEF_FUNCTION_TYPE_10(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9, ARG10) NAME, +#define DEF_FUNCTION_TYPE_11(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) NAME, #define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME, #define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME, #define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME, @@ -176,6 +182,9 @@ enum lto_builtin_type #undef DEF_FUNCTION_TYPE_6 #undef DEF_FUNCTION_TYPE_7 #undef DEF_FUNCTION_TYPE_8 +#undef DEF_FUNCTION_TYPE_9 +#undef DEF_FUNCTION_TYPE_10 +#undef DEF_FUNCTION_TYPE_11 #undef DEF_FUNCTION_TYPE_VAR_0 #undef DEF_FUNCTION_TYPE_VAR_1 #undef DEF_FUNCTION_TYPE_VAR_2 @@ -656,6 +665,18 @@ lto_define_builtins (tree va_list_ref_type_node ATTRIBUTE_UNUSED, ARG6, ARG7, ARG8) \ def_fn_type (ENUM, RETURN, 0, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ ARG7, ARG8); +#define DEF_FUNCTION_TYPE_9(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9) \ + def_fn_type (ENUM, RETURN, 0, 9, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ + ARG7, ARG8, ARG9); +#define DEF_FUNCTION_TYPE_10(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9, ARG10) \ + def_fn_type (ENUM, RETURN, 0, 10, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ + ARG7, ARG8, ARG9, ARG10); +#define DEF_FUNCTION_TYPE_11(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) \ + def_fn_type (ENUM, RETURN, 0, 11, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ + ARG7, ARG8, ARG9, ARG10, ARG11); #define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \ def_fn_type (ENUM, RETURN, 1, 0); #define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \ @@ -689,6 +710,9 @@ lto_define_builtins (tree va_list_ref_type_node ATTRIBUTE_UNUSED, #undef DEF_FUNCTION_TYPE_6 #undef DEF_FUNCTION_TYPE_7 #undef DEF_FUNCTION_TYPE_8 +#undef DEF_FUNCTION_TYPE_9 +#undef DEF_FUNCTION_TYPE_10 +#undef DEF_FUNCTION_TYPE_11 #undef DEF_FUNCTION_TYPE_VAR_0 #undef DEF_FUNCTION_TYPE_VAR_1 #undef DEF_FUNCTION_TYPE_VAR_2 diff --git a/gcc/omp-builtins.def b/gcc/omp-builtins.def index d09bdb69ece..ea9cf0d1372 100644 --- a/gcc/omp-builtins.def +++ b/gcc/omp-builtins.def @@ -129,6 +129,22 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ORDERED_RUNTIME_START, "GOMP_loop_ordered_runtime_start", BT_FN_BOOL_LONG_LONG_LONG_LONGPTR_LONGPTR, ATTR_NOTHROW_LEAF_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_DOACROSS_STATIC_START, + "GOMP_loop_doacross_static_start", + BT_FN_BOOL_UINT_LONGPTR_LONG_LONGPTR_LONGPTR, + ATTR_NOTHROW_LEAF_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_DOACROSS_DYNAMIC_START, + "GOMP_loop_doacross_dynamic_start", + BT_FN_BOOL_UINT_LONGPTR_LONG_LONGPTR_LONGPTR, + ATTR_NOTHROW_LEAF_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_DOACROSS_GUIDED_START, + "GOMP_loop_doacross_guided_start", + BT_FN_BOOL_UINT_LONGPTR_LONG_LONGPTR_LONGPTR, + ATTR_NOTHROW_LEAF_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_DOACROSS_RUNTIME_START, + "GOMP_loop_doacross_runtime_start", + BT_FN_BOOL_UINT_LONGPTR_LONGPTR_LONGPTR, + ATTR_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_STATIC_NEXT, "GOMP_loop_static_next", BT_FN_BOOL_LONGPTR_LONGPTR, ATTR_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_DYNAMIC_NEXT, "GOMP_loop_dynamic_next", @@ -181,6 +197,22 @@ 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_LEAF_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ULL_DOACROSS_STATIC_START, + "GOMP_loop_ull_doacross_static_start", + BT_FN_BOOL_UINT_ULLPTR_ULL_ULLPTR_ULLPTR, + ATTR_NOTHROW_LEAF_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ULL_DOACROSS_DYNAMIC_START, + "GOMP_loop_ull_doacross_dynamic_start", + BT_FN_BOOL_UINT_ULLPTR_ULL_ULLPTR_ULLPTR, + ATTR_NOTHROW_LEAF_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ULL_DOACROSS_GUIDED_START, + "GOMP_loop_ull_doacross_guided_start", + BT_FN_BOOL_UINT_ULLPTR_ULL_ULLPTR_ULLPTR, + ATTR_NOTHROW_LEAF_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ULL_DOACROSS_RUNTIME_START, + "GOMP_loop_ull_doacross_runtime_start", + BT_FN_BOOL_UINT_ULLPTR_ULLPTR_ULLPTR, + ATTR_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ULL_STATIC_NEXT, "GOMP_loop_ull_static_next", BT_FN_BOOL_ULONGLONGPTR_ULONGLONGPTR, ATTR_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ULL_DYNAMIC_NEXT, "GOMP_loop_ull_dynamic_next", @@ -230,10 +262,24 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_ORDERED_START, "GOMP_ordered_start", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_ORDERED_END, "GOMP_ordered_end", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_DOACROSS_POST, "GOMP_doacross_post", + BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_DOACROSS_WAIT, "GOMP_doacross_wait", + BT_FN_VOID_LONG_VAR, ATTR_NOTHROW_LEAF_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_DOACROSS_ULL_POST, "GOMP_doacross_ull_post", + BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_DOACROSS_ULL_WAIT, "GOMP_doacross_ull_wait", + BT_FN_VOID_ULL_VAR, ATTR_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL, "GOMP_parallel", BT_FN_VOID_OMPFN_PTR_UINT_UINT, ATTR_NOTHROW_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASK, "GOMP_task", - BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR, + BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR_INT, + ATTR_NOTHROW_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKLOOP, "GOMP_taskloop", + BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_UINT_LONG_INT_LONG_LONG_LONG, + ATTR_NOTHROW_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKLOOP_ULL, "GOMP_taskloop_ull", + BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_UINT_LONG_INT_ULL_ULL_ULL, ATTR_NOTHROW_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SECTIONS_START, "GOMP_sections_start", BT_FN_UINT_UINT, ATTR_NOTHROW_LEAF_LIST) @@ -256,14 +302,18 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SINGLE_COPY_START, "GOMP_single_copy_start", BT_FN_PTR, ATTR_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SINGLE_COPY_END, "GOMP_single_copy_end", BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) -DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TARGET, "GOMP_target", - BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR, +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TARGET, "GOMP_target_41", + BT_FN_VOID_INT_OMPFN_SIZE_PTR_PTR_PTR_UINT_PTR, ATTR_NOTHROW_LIST) -DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TARGET_DATA, "GOMP_target_data", - BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR, ATTR_NOTHROW_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TARGET_DATA, "GOMP_target_data_41", + BT_FN_VOID_INT_SIZE_PTR_PTR_PTR, ATTR_NOTHROW_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TARGET_END_DATA, "GOMP_target_end_data", BT_FN_VOID, ATTR_NOTHROW_LIST) -DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TARGET_UPDATE, "GOMP_target_update", - BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR, ATTR_NOTHROW_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TARGET_UPDATE, "GOMP_target_update_41", + BT_FN_VOID_INT_SIZE_PTR_PTR_PTR_UINT_PTR, + ATTR_NOTHROW_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TARGET_ENTER_EXIT_DATA, + "GOMP_target_enter_exit_data", + BT_FN_VOID_INT_SIZE_PTR_PTR_PTR_UINT_PTR, ATTR_NOTHROW_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TEAMS, "GOMP_teams", BT_FN_VOID_UINT_UINT, ATTR_NOTHROW_LIST) diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 7e894e4da7a..b444864f0d1 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -95,7 +95,7 @@ along with GCC; see the file COPYING3. If not see /* OMP region information. Every parallel and workshare directive is enclosed between two markers, the OMP_* directive - and a corresponding OMP_RETURN statement. */ + and a corresponding GIMPLE_OMP_RETURN statement. */ struct omp_region { @@ -111,10 +111,10 @@ struct omp_region /* Block containing the omp directive as its last stmt. */ basic_block entry; - /* Block containing the OMP_RETURN as its last stmt. */ + /* Block containing the GIMPLE_OMP_RETURN as its last stmt. */ basic_block exit; - /* Block containing the OMP_CONTINUE as its last stmt. */ + /* Block containing the GIMPLE_OMP_CONTINUE as its last stmt. */ basic_block cont; /* If this is a combined parallel+workshare region, this is a list @@ -125,11 +125,15 @@ struct omp_region /* The code for the omp directive of this region. */ enum gimple_code type; - /* Schedule kind, only used for OMP_FOR type regions. */ + /* Schedule kind, only used for GIMPLE_OMP_FOR type regions. */ enum omp_clause_schedule_kind sched_kind; /* True if this is a combined parallel+workshare region. */ bool is_combined_parallel; + + /* The ordered stmt if type is GIMPLE_OMP_ORDERED and it has + a depend clause. */ + gomp_ordered *ord_stmt; }; /* Levels of parallelism as defined by OpenACC. Increasing numbers @@ -223,7 +227,8 @@ struct omp_for_data gomp_for *for_stmt; tree pre, iter_type; int collapse; - bool have_nowait, have_ordered; + int ordered; + bool have_nowait, have_ordered, simd_schedule; enum omp_clause_schedule_kind sched_kind; struct omp_for_data_loop *loops; }; @@ -310,6 +315,73 @@ oacc_max_threads (omp_context *ctx) return nthreads; } +/* If DECL is the artificial dummy VAR_DECL created for non-static + data member privatization, return the underlying "this" parameter, + otherwise return NULL. */ + +tree +omp_member_access_dummy_var (tree decl) +{ + if (!VAR_P (decl) + || !DECL_ARTIFICIAL (decl) + || !DECL_IGNORED_P (decl) + || !DECL_HAS_VALUE_EXPR_P (decl) + || !lang_hooks.decls.omp_disregard_value_expr (decl, false)) + return NULL_TREE; + + tree v = DECL_VALUE_EXPR (decl); + if (TREE_CODE (v) != COMPONENT_REF) + return NULL_TREE; + + while (1) + switch (TREE_CODE (v)) + { + case COMPONENT_REF: + case MEM_REF: + case INDIRECT_REF: + CASE_CONVERT: + case POINTER_PLUS_EXPR: + v = TREE_OPERAND (v, 0); + continue; + case PARM_DECL: + if (DECL_CONTEXT (v) == current_function_decl + && DECL_ARTIFICIAL (v) + && TREE_CODE (TREE_TYPE (v)) == POINTER_TYPE) + return v; + return NULL_TREE; + default: + return NULL_TREE; + } +} + +/* Helper for unshare_and_remap, called through walk_tree. */ + +static tree +unshare_and_remap_1 (tree *tp, int *walk_subtrees, void *data) +{ + tree *pair = (tree *) data; + if (*tp == pair[0]) + { + *tp = unshare_expr (pair[1]); + *walk_subtrees = 0; + } + else if (IS_TYPE_OR_DECL_P (*tp)) + *walk_subtrees = 0; + return NULL_TREE; +} + +/* Return unshare_expr (X) with all occurrences of FROM + replaced with TO. */ + +static tree +unshare_and_remap (tree x, tree from, tree to) +{ + tree pair[2] = { from, to }; + x = unshare_expr (x); + walk_tree (&x, unshare_and_remap_1, pair, NULL); + return x; +} + /* Holds offload tables with decls. */ vec *offload_funcs, *offload_vars; @@ -361,13 +433,22 @@ is_task_ctx (omp_context *ctx) } +/* Return true if CTX is for an omp taskloop. */ + +static inline bool +is_taskloop_ctx (omp_context *ctx) +{ + return gimple_code (ctx->stmt) == GIMPLE_OMP_FOR + && gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_TASKLOOP; +} + + /* Return true if CTX is for an omp parallel or omp task. */ static inline bool is_taskreg_ctx (omp_context *ctx) { - return gimple_code (ctx->stmt) == GIMPLE_OMP_PARALLEL - || gimple_code (ctx->stmt) == GIMPLE_OMP_TASK; + return is_parallel_ctx (ctx) || is_task_ctx (ctx); } @@ -396,19 +477,24 @@ extract_omp_for_data (gomp_for *for_stmt, struct omp_for_data *fd, bool simd = gimple_omp_for_kind (for_stmt) & GF_OMP_FOR_SIMD; bool distribute = gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_DISTRIBUTE; + bool taskloop = gimple_omp_for_kind (for_stmt) + == GF_OMP_FOR_KIND_TASKLOOP; + tree iterv, countv; fd->for_stmt = for_stmt; fd->pre = NULL; - fd->collapse = gimple_omp_for_collapse (for_stmt); - if (fd->collapse > 1) + if (gimple_omp_for_collapse (for_stmt) > 1) fd->loops = loops; else fd->loops = &fd->loop; fd->have_nowait = distribute || simd; fd->have_ordered = false; + fd->collapse = 1; + fd->ordered = 0; fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC; fd->chunk_size = NULL_TREE; + fd->simd_schedule = false; if (gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_CILKFOR) fd->sched_kind = OMP_CLAUSE_SCHEDULE_CILKFOR; collapse_iter = NULL; @@ -422,17 +508,21 @@ extract_omp_for_data (gomp_for *for_stmt, struct omp_for_data *fd, break; case OMP_CLAUSE_ORDERED: fd->have_ordered = true; + if (OMP_CLAUSE_ORDERED_EXPR (t)) + fd->ordered = tree_to_shwi (OMP_CLAUSE_ORDERED_EXPR (t)); break; case OMP_CLAUSE_SCHEDULE: - gcc_assert (!distribute); + gcc_assert (!distribute && !taskloop); fd->sched_kind = OMP_CLAUSE_SCHEDULE_KIND (t); fd->chunk_size = OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (t); + fd->simd_schedule = OMP_CLAUSE_SCHEDULE_SIMD (t); break; case OMP_CLAUSE_DIST_SCHEDULE: gcc_assert (distribute); fd->chunk_size = OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (t); break; case OMP_CLAUSE_COLLAPSE: + fd->collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (t)); if (fd->collapse > 1) { collapse_iter = &OMP_CLAUSE_COLLAPSE_ITERVAR (t); @@ -442,6 +532,14 @@ extract_omp_for_data (gomp_for *for_stmt, struct omp_for_data *fd, default: break; } + if (fd->ordered && fd->collapse == 1 && loops != NULL) + { + fd->loops = loops; + iterv = NULL_TREE; + countv = NULL_TREE; + collapse_iter = &iterv; + collapse_count = &countv; + } /* FIXME: for now map schedule(auto) to schedule(static). There should be analysis to determine whether all iterations @@ -453,6 +551,8 @@ extract_omp_for_data (gomp_for *for_stmt, struct omp_for_data *fd, gcc_assert (fd->chunk_size == NULL); } gcc_assert (fd->collapse == 1 || collapse_iter != NULL); + if (taskloop) + fd->sched_kind = OMP_CLAUSE_SCHEDULE_RUNTIME; if (fd->sched_kind == OMP_CLAUSE_SCHEDULE_RUNTIME) gcc_assert (fd->chunk_size == NULL); else if (fd->chunk_size == NULL) @@ -465,9 +565,10 @@ extract_omp_for_data (gomp_for *for_stmt, struct omp_for_data *fd, ? integer_zero_node : integer_one_node; } - for (i = 0; i < fd->collapse; i++) + int cnt = fd->ordered ? fd->ordered : fd->collapse; + for (i = 0; i < cnt; i++) { - if (fd->collapse == 1) + if (i == 0 && fd->collapse == 1 && (fd->ordered == 0 || loops == NULL)) loop = &fd->loop; else if (loops != NULL) loop = loops + i; @@ -596,6 +697,9 @@ extract_omp_for_data (gomp_for *for_stmt, struct omp_for_data *fd, } } + if (i >= fd->collapse) + continue; + if (collapse_count && *collapse_count == NULL) { t = fold_binary (loop->cond_code, boolean_type_node, @@ -668,7 +772,7 @@ extract_omp_for_data (gomp_for *for_stmt, struct omp_for_data *fd, *collapse_count = create_tmp_var (iter_type, ".count"); } - if (fd->collapse > 1) + if (fd->collapse > 1 || (fd->ordered && loops)) { fd->loop.v = *collapse_iter; fd->loop.n1 = build_int_cst (TREE_TYPE (fd->loop.v), 0); @@ -676,6 +780,8 @@ extract_omp_for_data (gomp_for *for_stmt, struct omp_for_data *fd, fd->loop.step = build_int_cst (TREE_TYPE (fd->loop.v), 1); fd->loop.cond_code = LT_EXPR; } + else if (loops) + loops[0] = fd->loop; /* For OpenACC loops, force a chunk size of one, as this avoids the default scheduling where several subsequent iterations are being executed by the @@ -763,6 +869,29 @@ workshare_safe_to_combine_p (basic_block ws_entry_bb) } +static int omp_max_vf (void); + +/* Adjust CHUNK_SIZE from SCHEDULE clause, depending on simd modifier + presence (SIMD_SCHEDULE). */ + +static tree +omp_adjust_chunk_size (tree chunk_size, bool simd_schedule) +{ + if (!simd_schedule) + return chunk_size; + + int vf = omp_max_vf (); + if (vf == 1) + return chunk_size; + + tree type = TREE_TYPE (chunk_size); + chunk_size = fold_build2 (PLUS_EXPR, type, chunk_size, + build_int_cst (type, vf - 1)); + return fold_build2 (BIT_AND_EXPR, type, chunk_size, + build_int_cst (type, -vf)); +} + + /* Collect additional arguments needed to emit a combined parallel+workshare call. WS_STMT is the workshare directive being expanded. */ @@ -810,6 +939,7 @@ get_ws_args_for (gimple *par_stmt, gimple *ws_stmt) if (fd.chunk_size) { t = fold_convert_loc (loc, long_integer_type_node, fd.chunk_size); + t = omp_adjust_chunk_size (t, fd.simd_schedule); ws_args->quick_push (t); } @@ -951,23 +1081,34 @@ lookup_field (tree var, omp_context *ctx) } static inline tree -lookup_sfield (tree var, omp_context *ctx) +lookup_sfield (splay_tree_key key, omp_context *ctx) { splay_tree_node n; n = splay_tree_lookup (ctx->sfield_map - ? ctx->sfield_map : ctx->field_map, - (splay_tree_key) var); + ? ctx->sfield_map : ctx->field_map, key); return (tree) n->value; } static inline tree -maybe_lookup_field (tree var, omp_context *ctx) +lookup_sfield (tree var, omp_context *ctx) +{ + return lookup_sfield ((splay_tree_key) var, ctx); +} + +static inline tree +maybe_lookup_field (splay_tree_key key, omp_context *ctx) { splay_tree_node n; - n = splay_tree_lookup (ctx->field_map, (splay_tree_key) var); + n = splay_tree_lookup (ctx->field_map, key); return n ? (tree) n->value : NULL_TREE; } +static inline tree +maybe_lookup_field (tree var, omp_context *ctx) +{ + return maybe_lookup_field ((splay_tree_key) var, ctx); +} + static inline tree lookup_oacc_reduction (const char *id, omp_context *ctx) { @@ -1063,7 +1204,7 @@ use_pointer_for_field (tree decl, omp_context *shared_ctx) tree outer; maybe_mark_addressable_and_ret: outer = maybe_lookup_decl_in_outer_ctx (decl, shared_ctx); - if (is_gimple_reg (outer)) + if (is_gimple_reg (outer) && !omp_member_access_dummy_var (outer)) { /* Taking address of OUTER in lower_send_shared_vars might need regimplification of everything that uses the @@ -1089,6 +1230,14 @@ omp_copy_decl_2 (tree var, tree name, tree type, omp_context *ctx) DECL_CONTEXT (copy) = current_function_decl; DECL_CHAIN (copy) = ctx->block_vars; + /* If VAR is listed in task_shared_vars, it means it wasn't + originally addressable and is just because task needs to take + it's address. But we don't need to take address of privatizations + from that var. */ + if (TREE_ADDRESSABLE (var) + && task_shared_vars + && bitmap_bit_p (task_shared_vars, DECL_UID (var))) + TREE_ADDRESSABLE (copy) = 0; ctx->block_vars = copy; return copy; @@ -1140,7 +1289,7 @@ build_receiver_ref (tree var, bool by_ref, omp_context *ctx) this is some variable. */ static tree -build_outer_var_ref (tree var, omp_context *ctx) +build_outer_var_ref (tree var, omp_context *ctx, bool lastprivate = false) { tree x; @@ -1149,7 +1298,7 @@ build_outer_var_ref (tree var, omp_context *ctx) else if (is_variable_sized (var)) { x = TREE_OPERAND (DECL_VALUE_EXPR (var), 0); - x = build_outer_var_ref (x, ctx); + x = build_outer_var_ref (x, ctx, lastprivate); x = build_simple_mem_ref (x); } else if (is_taskreg_ctx (ctx)) @@ -1170,15 +1319,59 @@ build_outer_var_ref (tree var, omp_context *ctx) if (x == NULL_TREE) x = var; } + else if (lastprivate && is_taskloop_ctx (ctx)) + { + gcc_assert (ctx->outer); + splay_tree_node n + = splay_tree_lookup (ctx->outer->field_map, + (splay_tree_key) &DECL_UID (var)); + if (n == NULL) + { + if (is_global_var (maybe_lookup_decl_in_outer_ctx (var, ctx->outer))) + x = var; + else + x = lookup_decl (var, ctx->outer); + } + else + { + tree field = (tree) n->value; + /* If the receiver record type was remapped in the child function, + remap the field into the new record type. */ + x = maybe_lookup_field (field, ctx->outer); + if (x != NULL) + field = x; + + x = build_simple_mem_ref (ctx->outer->receiver_decl); + x = omp_build_component_ref (x, field); + if (use_pointer_for_field (var, ctx->outer)) + x = build_simple_mem_ref (x); + } + } else if (ctx->outer) x = lookup_decl (var, ctx->outer); else if (is_reference (var)) /* This can happen with orphaned constructs. If var is reference, it is possible it is shared and as such valid. */ x = var; + else if (omp_member_access_dummy_var (var)) + x = var; else gcc_unreachable (); + if (x == var) + { + tree t = omp_member_access_dummy_var (var); + if (t) + { + x = DECL_VALUE_EXPR (var); + tree o = maybe_lookup_decl_in_outer_ctx (t, ctx); + if (o != t) + x = unshare_and_remap (x, t, o); + else + x = unshare_expr (x); + } + } + if (is_reference (var)) x = build_simple_mem_ref (x); @@ -1188,23 +1381,35 @@ build_outer_var_ref (tree var, omp_context *ctx) /* Build tree nodes to access the field for VAR on the sender side. */ static tree -build_sender_ref (tree var, omp_context *ctx) +build_sender_ref (splay_tree_key key, omp_context *ctx) { - tree field = lookup_sfield (var, ctx); + tree field = lookup_sfield (key, ctx); return omp_build_component_ref (ctx->sender_decl, field); } +static tree +build_sender_ref (tree var, omp_context *ctx) +{ + return build_sender_ref ((splay_tree_key) var, ctx); +} + /* Add a new field for VAR inside the structure CTX->SENDER_DECL. */ static void install_var_field (tree var, bool by_ref, int mask, omp_context *ctx) { tree field, type, sfield = NULL_TREE; + splay_tree_key key = (splay_tree_key) var; + if ((mask & 8) != 0) + { + key = (splay_tree_key) &DECL_UID (var); + gcc_checking_assert (key != (splay_tree_key) var); + } gcc_assert ((mask & 1) == 0 - || !splay_tree_lookup (ctx->field_map, (splay_tree_key) var)); + || !splay_tree_lookup (ctx->field_map, key)); gcc_assert ((mask & 2) == 0 || !ctx->sfield_map - || !splay_tree_lookup (ctx->sfield_map, (splay_tree_key) var)); + || !splay_tree_lookup (ctx->sfield_map, key)); gcc_assert ((mask & 3) == 3 || !is_gimple_omp_oacc (ctx->stmt)); @@ -1259,7 +1464,7 @@ install_var_field (tree var, bool by_ref, int mask, omp_context *ctx) ctx->sfield_map = splay_tree_new (splay_tree_compare_pointers, 0, 0); for (t = TYPE_FIELDS (ctx->record_type); t ; t = TREE_CHAIN (t)) { - sfield = build_decl (DECL_SOURCE_LOCATION (var), + sfield = build_decl (DECL_SOURCE_LOCATION (t), FIELD_DECL, DECL_NAME (t), TREE_TYPE (t)); DECL_ABSTRACT_ORIGIN (sfield) = DECL_ABSTRACT_ORIGIN (t); insert_field_into_struct (ctx->srecord_type, sfield); @@ -1274,11 +1479,9 @@ install_var_field (tree var, bool by_ref, int mask, omp_context *ctx) } if (mask & 1) - splay_tree_insert (ctx->field_map, (splay_tree_key) var, - (splay_tree_value) field); + splay_tree_insert (ctx->field_map, key, (splay_tree_value) field); if ((mask & 2) && ctx->sfield_map) - splay_tree_insert (ctx->sfield_map, (splay_tree_key) var, - (splay_tree_value) sfield); + splay_tree_insert (ctx->sfield_map, key, (splay_tree_value) sfield); } static tree @@ -1632,6 +1835,11 @@ fixup_child_record_type (omp_context *ctx) layout_type (type); } + /* In a target region we never modify any of the pointers in *.omp_data_i, + so attempt to help the optimizers. */ + if (is_gimple_omp_offloaded (ctx->stmt)) + type = build_qualified_type (type, TYPE_QUAL_CONST); + TREE_TYPE (ctx->receiver_decl) = build_qualified_type (build_reference_type (type), TYPE_QUAL_RESTRICT); } @@ -1680,6 +1888,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) if (is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx))) break; by_ref = use_pointer_for_field (decl, ctx); + if (OMP_CLAUSE_SHARED_FIRSTPRIVATE (c)) + break; if (! TREE_READONLY (decl) || TREE_ADDRESSABLE (decl) || by_ref @@ -1693,6 +1903,27 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) OMP_CLAUSE_SET_CODE (c, OMP_CLAUSE_FIRSTPRIVATE); goto do_private; + case OMP_CLAUSE_REDUCTION: + decl = OMP_CLAUSE_DECL (c); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + && TREE_CODE (decl) == MEM_REF) + { + tree t = TREE_OPERAND (decl, 0); + if (TREE_CODE (t) == INDIRECT_REF + || TREE_CODE (t) == ADDR_EXPR) + t = TREE_OPERAND (t, 0); + install_var_local (t, ctx); + if (is_taskreg_ctx (ctx) + && !is_global_var (maybe_lookup_decl_in_outer_ctx (t, ctx)) + && !is_variable_sized (t)) + { + by_ref = use_pointer_for_field (t, ctx); + install_var_field (t, by_ref, 3, ctx); + } + break; + } + goto do_private; + case OMP_CLAUSE_LASTPRIVATE: /* Let the corresponding firstprivate clause create the variable. */ @@ -1707,10 +1938,20 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) break; } /* FALLTHRU */ - case OMP_CLAUSE_REDUCTION: case OMP_CLAUSE_LINEAR: decl = OMP_CLAUSE_DECL (c); do_private: + if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IS_DEVICE_PTR) + && is_gimple_omp_offloaded (ctx->stmt)) + { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE) + install_var_field (decl, !is_reference (decl), 3, ctx); + else if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) + install_var_field (decl, true, 3, ctx); + else + install_var_field (decl, false, 3, ctx); + } if (is_variable_sized (decl)) { if (is_task_ctx (ctx)) @@ -1743,9 +1984,9 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) tree ptype = build_pointer_type (type); tree array = create_tmp_var (ptype, oacc_get_reduction_array_id (var)); - omp_context *c = (ctx->field_map ? ctx : ctx->outer); - install_var_field (array, true, 3, c); - install_var_local (array, c); + omp_context *octx = (ctx->field_map ? ctx : ctx->outer); + install_var_field (array, true, 3, octx); + install_var_local (array, octx); /* Insert it into the current context. */ splay_tree_insert (ctx->reduction_map, (splay_tree_key) @@ -1757,8 +1998,30 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) } break; + case OMP_CLAUSE_USE_DEVICE_PTR: + decl = OMP_CLAUSE_DECL (c); + if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) + install_var_field (decl, true, 3, ctx); + else + install_var_field (decl, false, 3, ctx); + if (DECL_SIZE (decl) + && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST) + { + tree decl2 = DECL_VALUE_EXPR (decl); + gcc_assert (TREE_CODE (decl2) == INDIRECT_REF); + decl2 = TREE_OPERAND (decl2, 0); + gcc_assert (DECL_P (decl2)); + install_var_local (decl2, ctx); + } + install_var_local (decl, ctx); + break; + + case OMP_CLAUSE_IS_DEVICE_PTR: + decl = OMP_CLAUSE_DECL (c); + goto do_private; + case OMP_CLAUSE__LOOPTEMP_: - gcc_assert (is_parallel_ctx (ctx)); + gcc_assert (is_taskreg_ctx (ctx)); decl = OMP_CLAUSE_DECL (c); install_var_field (decl, false, 3, ctx); install_var_local (decl, ctx); @@ -1784,6 +2047,9 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_SCHEDULE: case OMP_CLAUSE_DIST_SCHEDULE: case OMP_CLAUSE_DEPEND: + case OMP_CLAUSE_PRIORITY: + case OMP_CLAUSE_GRAINSIZE: + case OMP_CLAUSE_NUM_TASKS: case OMP_CLAUSE__CILK_FOR_COUNT_: case OMP_CLAUSE_NUM_GANGS: case OMP_CLAUSE_NUM_WORKERS: @@ -1803,6 +2069,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) directly. */ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP && DECL_P (decl) + && (OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_FIRSTPRIVATE_POINTER + || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) && is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx)) && varpool_node::get_create (decl)->offloadable) break; @@ -1816,6 +2084,27 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) && !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c)) break; } + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER) + { + if (TREE_CODE (decl) == COMPONENT_REF + || (TREE_CODE (decl) == INDIRECT_REF + && TREE_CODE (TREE_OPERAND (decl, 0)) == COMPONENT_REF + && (TREE_CODE (TREE_TYPE (TREE_OPERAND (decl, 0))) + == REFERENCE_TYPE))) + break; + if (DECL_SIZE (decl) + && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST) + { + tree decl2 = DECL_VALUE_EXPR (decl); + gcc_assert (TREE_CODE (decl2) == INDIRECT_REF); + decl2 = TREE_OPERAND (decl2, 0); + gcc_assert (DECL_P (decl2)); + install_var_local (decl2, ctx); + } + install_var_local (decl, ctx); + break; + } if (DECL_P (decl)) { if (DECL_SIZE (decl) @@ -1825,7 +2114,11 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) gcc_assert (TREE_CODE (decl2) == INDIRECT_REF); decl2 = TREE_OPERAND (decl2, 0); gcc_assert (DECL_P (decl2)); - install_var_field (decl2, true, 3, ctx); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && OMP_CLAUSE_MAP_PRIVATE (c)) + install_var_field (decl2, true, 11, ctx); + else + install_var_field (decl2, true, 3, ctx); install_var_local (decl2, ctx); install_var_local (decl, ctx); } @@ -1836,6 +2129,9 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) && !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c) && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) install_var_field (decl, true, 7, ctx); + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && OMP_CLAUSE_MAP_PRIVATE (c)) + install_var_field (decl, true, 11, ctx); else install_var_field (decl, true, 3, ctx); if (is_gimple_omp_offloaded (ctx->stmt)) @@ -1883,6 +2179,11 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_MERGEABLE: case OMP_CLAUSE_PROC_BIND: case OMP_CLAUSE_SAFELEN: + case OMP_CLAUSE_SIMDLEN: + case OMP_CLAUSE_THREADS: + case OMP_CLAUSE_SIMD: + case OMP_CLAUSE_NOGROUP: + case OMP_CLAUSE_DEFAULTMAP: case OMP_CLAUSE_ASYNC: case OMP_CLAUSE_WAIT: case OMP_CLAUSE_GANG: @@ -1932,19 +2233,41 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) } /* FALLTHRU */ case OMP_CLAUSE_PRIVATE: - case OMP_CLAUSE_REDUCTION: case OMP_CLAUSE_LINEAR: + case OMP_CLAUSE_IS_DEVICE_PTR: decl = OMP_CLAUSE_DECL (c); if (is_variable_sized (decl)) - install_var_local (decl, ctx); + { + if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IS_DEVICE_PTR) + && is_gimple_omp_offloaded (ctx->stmt)) + { + tree decl2 = DECL_VALUE_EXPR (decl); + gcc_assert (TREE_CODE (decl2) == INDIRECT_REF); + decl2 = TREE_OPERAND (decl2, 0); + gcc_assert (DECL_P (decl2)); + install_var_local (decl2, ctx); + fixup_remapped_decl (decl2, ctx, false); + } + install_var_local (decl, ctx); + } fixup_remapped_decl (decl, ctx, OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE && OMP_CLAUSE_PRIVATE_DEBUG (c)); - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION - && OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR + && OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c)) scan_array_reductions = true; - else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR - && OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c)) + break; + + case OMP_CLAUSE_REDUCTION: + decl = OMP_CLAUSE_DECL (c); + if (TREE_CODE (decl) != MEM_REF) + { + if (is_variable_sized (decl)) + install_var_local (decl, ctx); + fixup_remapped_decl (decl, ctx, false); + } + if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)) scan_array_reductions = true; break; @@ -1953,8 +2276,18 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS) break; decl = OMP_CLAUSE_DECL (c); - if (! is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx))) - fixup_remapped_decl (decl, ctx, false); + if (is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx))) + break; + if (OMP_CLAUSE_SHARED_FIRSTPRIVATE (c)) + { + if (is_global_var (maybe_lookup_decl_in_outer_ctx (decl, + ctx->outer))) + break; + bool by_ref = use_pointer_for_field (decl, ctx); + install_var_field (decl, by_ref, 11, ctx); + break; + } + fixup_remapped_decl (decl, ctx, false); break; case OMP_CLAUSE_MAP: @@ -1962,12 +2295,15 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) break; decl = OMP_CLAUSE_DECL (c); if (DECL_P (decl) + && (OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_FIRSTPRIVATE_POINTER + || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) && is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx)) && varpool_node::get_create (decl)->offloadable) break; if (DECL_P (decl)) { - if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER + if ((OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER + || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER) && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE && !COMPLETE_TYPE_P (TREE_TYPE (decl))) { @@ -2008,11 +2344,20 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_MERGEABLE: case OMP_CLAUSE_PROC_BIND: case OMP_CLAUSE_SAFELEN: + case OMP_CLAUSE_SIMDLEN: case OMP_CLAUSE_ALIGNED: case OMP_CLAUSE_DEPEND: case OMP_CLAUSE__LOOPTEMP_: case OMP_CLAUSE_TO: case OMP_CLAUSE_FROM: + case OMP_CLAUSE_PRIORITY: + case OMP_CLAUSE_GRAINSIZE: + case OMP_CLAUSE_NUM_TASKS: + case OMP_CLAUSE_THREADS: + case OMP_CLAUSE_SIMD: + case OMP_CLAUSE_NOGROUP: + case OMP_CLAUSE_DEFAULTMAP: + case OMP_CLAUSE_USE_DEVICE_PTR: case OMP_CLAUSE__CILK_FOR_COUNT_: case OMP_CLAUSE_ASYNC: case OMP_CLAUSE_WAIT: @@ -2202,6 +2547,7 @@ create_omp_child_function (omp_context *ctx, bool task_copy) DECL_ARG_TYPE (t) = ptr_type_node; DECL_CONTEXT (t) = current_function_decl; TREE_USED (t) = 1; + TREE_READONLY (t) = 1; if (cilk_for_count) DECL_CHAIN (t) = DECL_ARGUMENTS (decl); DECL_ARGUMENTS (decl) = t; @@ -2247,7 +2593,8 @@ find_combined_for (gimple_stmt_iterator *gsi_p, case GIMPLE_OMP_FOR: if (gimple_omp_for_combined_into_p (stmt) - && gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_FOR) + && gimple_omp_for_kind (stmt) + == *(const enum gf_mask *) (wi->info)) { wi->info = stmt; return integer_zero_node; @@ -2259,6 +2606,52 @@ find_combined_for (gimple_stmt_iterator *gsi_p, return NULL; } +/* Add _LOOPTEMP_ clauses on OpenMP parallel or task. */ + +static void +add_taskreg_looptemp_clauses (enum gf_mask msk, gimple *stmt, + omp_context *outer_ctx) +{ + struct walk_stmt_info wi; + + memset (&wi, 0, sizeof (wi)); + wi.val_only = true; + wi.info = (void *) &msk; + walk_gimple_seq (gimple_omp_body (stmt), find_combined_for, NULL, &wi); + if (wi.info != (void *) &msk) + { + gomp_for *for_stmt = as_a ((gimple *) wi.info); + struct omp_for_data fd; + extract_omp_for_data (for_stmt, &fd, NULL); + /* We need two temporaries with fd.loop.v type (istart/iend) + and then (fd.collapse - 1) temporaries with the same + type for count2 ... countN-1 vars if not constant. */ + size_t count = 2, i; + tree type = fd.iter_type; + if (fd.collapse > 1 + && TREE_CODE (fd.loop.n2) != INTEGER_CST) + { + count += fd.collapse - 1; + /* For taskloop, if there are lastprivate clauses on the inner + GIMPLE_OMP_FOR, add one more temporaries for the total number + of iterations (product of count1 ... countN-1). */ + if (msk == GF_OMP_FOR_KIND_TASKLOOP + && find_omp_clause (gimple_omp_for_clauses (for_stmt), + OMP_CLAUSE_LASTPRIVATE)) + count++; + } + for (i = 0; i < count; i++) + { + tree temp = create_tmp_var (type); + tree c = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE__LOOPTEMP_); + insert_decl_map (&outer_ctx->cb, temp, temp); + OMP_CLAUSE_DECL (c) = temp; + OMP_CLAUSE_CHAIN (c) = gimple_omp_taskreg_clauses (stmt); + gimple_omp_taskreg_set_clauses (stmt, c); + } + } +} + /* Scan an OpenMP parallel directive. */ static void @@ -2280,38 +2673,7 @@ scan_omp_parallel (gimple_stmt_iterator *gsi, omp_context *outer_ctx) } if (gimple_omp_parallel_combined_p (stmt)) - { - struct walk_stmt_info wi; - - memset (&wi, 0, sizeof (wi)); - wi.val_only = true; - walk_gimple_seq (gimple_omp_body (stmt), - find_combined_for, NULL, &wi); - if (wi.info) - { - gomp_for *for_stmt = as_a ((gimple *) wi.info); - struct omp_for_data fd; - extract_omp_for_data (for_stmt, &fd, NULL); - /* We need two temporaries with fd.loop.v type (istart/iend) - and then (fd.collapse - 1) temporaries with the same - type for count2 ... countN-1 vars if not constant. */ - size_t count = 2, i; - tree type = fd.iter_type; - if (fd.collapse > 1 - && TREE_CODE (fd.loop.n2) != INTEGER_CST) - count += fd.collapse - 1; - for (i = 0; i < count; i++) - { - tree temp = create_tmp_var (type); - tree c = build_omp_clause (UNKNOWN_LOCATION, - OMP_CLAUSE__LOOPTEMP_); - insert_decl_map (&outer_ctx->cb, temp, temp); - OMP_CLAUSE_DECL (c) = temp; - OMP_CLAUSE_CHAIN (c) = gimple_omp_parallel_clauses (stmt); - gimple_omp_parallel_set_clauses (stmt, c); - } - } - } + add_taskreg_looptemp_clauses (GF_OMP_FOR_KIND_FOR, stmt, outer_ctx); ctx = new_omp_context (stmt, outer_ctx); taskreg_contexts.safe_push (ctx); @@ -2354,6 +2716,9 @@ scan_omp_task (gimple_stmt_iterator *gsi, omp_context *outer_ctx) return; } + if (gimple_omp_task_taskloop_p (stmt)) + add_taskreg_looptemp_clauses (GF_OMP_FOR_KIND_TASKLOOP, stmt, outer_ctx); + ctx = new_omp_context (stmt, outer_ctx); taskreg_contexts.safe_push (ctx); if (taskreg_nesting_level > 1) @@ -2418,7 +2783,8 @@ finish_taskreg_scan (omp_context *ctx) for (c = gimple_omp_taskreg_clauses (ctx->stmt); c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED + && !OMP_CLAUSE_SHARED_FIRSTPRIVATE (c)) { tree decl = OMP_CLAUSE_DECL (c); @@ -2475,6 +2841,41 @@ finish_taskreg_scan (omp_context *ctx) else p = &DECL_CHAIN (*p); *p = vla_fields; + if (gimple_omp_task_taskloop_p (ctx->stmt)) + { + /* Move fields corresponding to first and second _looptemp_ + clause first. There are filled by GOMP_taskloop + and thus need to be in specific positions. */ + tree c1 = gimple_omp_task_clauses (ctx->stmt); + c1 = find_omp_clause (c1, OMP_CLAUSE__LOOPTEMP_); + tree c2 = find_omp_clause (OMP_CLAUSE_CHAIN (c1), + OMP_CLAUSE__LOOPTEMP_); + tree f1 = lookup_field (OMP_CLAUSE_DECL (c1), ctx); + tree f2 = lookup_field (OMP_CLAUSE_DECL (c2), ctx); + p = &TYPE_FIELDS (ctx->record_type); + while (*p) + if (*p == f1 || *p == f2) + *p = DECL_CHAIN (*p); + else + p = &DECL_CHAIN (*p); + DECL_CHAIN (f1) = f2; + DECL_CHAIN (f2) = TYPE_FIELDS (ctx->record_type); + TYPE_FIELDS (ctx->record_type) = f1; + if (ctx->srecord_type) + { + f1 = lookup_sfield (OMP_CLAUSE_DECL (c1), ctx); + f2 = lookup_sfield (OMP_CLAUSE_DECL (c2), ctx); + p = &TYPE_FIELDS (ctx->srecord_type); + while (*p) + if (*p == f1 || *p == f2) + *p = DECL_CHAIN (*p); + else + p = &DECL_CHAIN (*p); + DECL_CHAIN (f1) = f2; + DECL_CHAIN (f2) = TYPE_FIELDS (ctx->srecord_type); + TYPE_FIELDS (ctx->srecord_type) = f1; + } + } layout_type (ctx->record_type); fixup_child_record_type (ctx); if (ctx->srecord_type) @@ -2710,6 +3111,8 @@ scan_omp_teams (gomp_teams *stmt, omp_context *outer_ctx) static bool check_omp_nesting_restrictions (gimple *stmt, omp_context *ctx) { + tree c; + /* No nesting of non-OpenACC STMT (that is, an OpenMP one, or a GOMP builtin) inside an OpenACC CTX. */ if (!(is_gimple_omp (stmt) @@ -2730,8 +3133,16 @@ check_omp_nesting_restrictions (gimple *stmt, omp_context *ctx) if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR && gimple_omp_for_kind (ctx->stmt) & GF_OMP_FOR_SIMD) { + c = NULL_TREE; + if (gimple_code (stmt) == GIMPLE_OMP_ORDERED) + { + c = gimple_omp_ordered_clauses (as_a (stmt)); + if (c && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SIMD) + return true; + } error_at (gimple_location (stmt), - "OpenMP constructs may not be nested inside simd region"); + "OpenMP constructs other than %<#pragma omp ordered simd%>" + " may not be nested inside simd region"); return false; } else if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS) @@ -2764,6 +3175,9 @@ check_omp_nesting_restrictions (gimple *stmt, omp_context *ctx) } return true; } + /* We split taskloop into task and nested taskloop in it. */ + if (gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_TASKLOOP) + return true; /* FALLTHRU */ case GIMPLE_CALL: if (is_gimple_call (stmt) @@ -2927,7 +3341,63 @@ check_omp_nesting_restrictions (gimple *stmt, omp_context *ctx) break; } break; + case GIMPLE_OMP_TASK: + for (c = gimple_omp_task_clauses (stmt); c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + && (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SOURCE + || OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK)) + { + enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_KIND (c); + error_at (OMP_CLAUSE_LOCATION (c), + "% is only allowed in %", + kind == OMP_CLAUSE_DEPEND_SOURCE ? "source" : "sink"); + return false; + } + break; case GIMPLE_OMP_ORDERED: + for (c = gimple_omp_ordered_clauses (as_a (stmt)); + c; c = OMP_CLAUSE_CHAIN (c)) + { + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND) + { + gcc_assert (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_THREADS + || (ctx == NULL + && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SIMD)); + continue; + } + enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_KIND (c); + if (kind == OMP_CLAUSE_DEPEND_SOURCE + || kind == OMP_CLAUSE_DEPEND_SINK) + { + tree oclause; + /* Look for containing ordered(N) loop. */ + if (ctx == NULL + || gimple_code (ctx->stmt) != GIMPLE_OMP_FOR + || (oclause + = find_omp_clause (gimple_omp_for_clauses (ctx->stmt), + OMP_CLAUSE_ORDERED)) == NULL_TREE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% clause must be closely nested " + "inside an ordered loop"); + return false; + } + else if (OMP_CLAUSE_ORDERED_EXPR (oclause) == NULL_TREE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% clause must be closely nested " + "inside a loop with % clause with " + "a parameter"); + return false; + } + } + else + { + error_at (OMP_CLAUSE_LOCATION (c), + "invalid depend kind in omp ordered depend"); + return false; + } + } for (; ctx != NULL; ctx = ctx->outer) switch (gimple_code (ctx->stmt)) { @@ -2984,6 +3454,17 @@ check_omp_nesting_restrictions (gimple *stmt, omp_context *ctx) } break; case GIMPLE_OMP_TARGET: + for (c = gimple_omp_target_clauses (stmt); c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + && (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SOURCE + || OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK)) + { + enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_KIND (c); + error_at (OMP_CLAUSE_LOCATION (c), + "% is only allowed in %", + kind == OMP_CLAUSE_DEPEND_SOURCE ? "source" : "sink"); + return false; + } for (; ctx != NULL; ctx = ctx->outer) { if (gimple_code (ctx->stmt) != GIMPLE_OMP_TARGET) @@ -3005,19 +3486,26 @@ check_omp_nesting_restrictions (gimple *stmt, omp_context *ctx) case GF_OMP_TARGET_KIND_REGION: stmt_name = "target"; break; case GF_OMP_TARGET_KIND_DATA: stmt_name = "target data"; break; case GF_OMP_TARGET_KIND_UPDATE: stmt_name = "target update"; break; + case GF_OMP_TARGET_KIND_ENTER_DATA: + stmt_name = "target enter data"; break; + case GF_OMP_TARGET_KIND_EXIT_DATA: + stmt_name = "target exit data"; break; case GF_OMP_TARGET_KIND_OACC_PARALLEL: stmt_name = "parallel"; break; case GF_OMP_TARGET_KIND_OACC_KERNELS: stmt_name = "kernels"; break; case GF_OMP_TARGET_KIND_OACC_DATA: stmt_name = "data"; break; case GF_OMP_TARGET_KIND_OACC_UPDATE: stmt_name = "update"; break; - case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA: stmt_name = "enter/exit data"; break; + case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA: + stmt_name = "enter/exit data"; break; default: gcc_unreachable (); } switch (gimple_omp_target_kind (ctx->stmt)) { case GF_OMP_TARGET_KIND_REGION: ctx_stmt_name = "target"; break; case GF_OMP_TARGET_KIND_DATA: ctx_stmt_name = "target data"; break; - case GF_OMP_TARGET_KIND_OACC_PARALLEL: ctx_stmt_name = "parallel"; break; - case GF_OMP_TARGET_KIND_OACC_KERNELS: ctx_stmt_name = "kernels"; break; + case GF_OMP_TARGET_KIND_OACC_PARALLEL: + ctx_stmt_name = "parallel"; break; + case GF_OMP_TARGET_KIND_OACC_KERNELS: + ctx_stmt_name = "kernels"; break; case GF_OMP_TARGET_KIND_OACC_DATA: ctx_stmt_name = "data"; break; default: gcc_unreachable (); } @@ -3585,11 +4073,8 @@ handle_simd_reference (location_t loc, tree new_vard, gimple_seq *ilist) tree z = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (new_vard))); if (TREE_CONSTANT (z)) { - const char *name = NULL; - if (DECL_NAME (new_vard)) - name = IDENTIFIER_POINTER (DECL_NAME (new_vard)); - - z = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (new_vard)), name); + z = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (new_vard)), + get_name (new_vard)); gimple_add_tmp_var (z); TREE_ADDRESSABLE (z) = 1; z = build_fold_addr_expr_loc (loc, z); @@ -3632,13 +4117,17 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, if (OMP_CLAUSE_LINEAR_ARRAY (c)) max_vf = 1; /* FALLTHRU */ - case OMP_CLAUSE_REDUCTION: case OMP_CLAUSE_PRIVATE: case OMP_CLAUSE_FIRSTPRIVATE: case OMP_CLAUSE_LASTPRIVATE: if (is_variable_sized (OMP_CLAUSE_DECL (c))) max_vf = 1; break; + case OMP_CLAUSE_REDUCTION: + if (TREE_CODE (OMP_CLAUSE_DECL (c)) == MEM_REF + || is_variable_sized (OMP_CLAUSE_DECL (c))) + max_vf = 1; + break; default: continue; } @@ -3668,19 +4157,24 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, continue; if (maybe_lookup_decl (OMP_CLAUSE_DECL (c), ctx) == NULL) { - gcc_assert (is_global_var (OMP_CLAUSE_DECL (c))); + gcc_assert (OMP_CLAUSE_SHARED_FIRSTPRIVATE (c) + || is_global_var (OMP_CLAUSE_DECL (c))); continue; } case OMP_CLAUSE_FIRSTPRIVATE: case OMP_CLAUSE_COPYIN: + break; case OMP_CLAUSE_LINEAR: + if (!OMP_CLAUSE_LINEAR_NO_COPYIN (c) + && !OMP_CLAUSE_LINEAR_NO_COPYOUT (c)) + lastprivate_firstprivate = true; break; case OMP_CLAUSE_REDUCTION: if (OMP_CLAUSE_REDUCTION_OMP_ORIG_REF (c)) reduction_omp_orig_ref = true; break; case OMP_CLAUSE__LOOPTEMP_: - /* Handle _looptemp_ clauses only on parallel. */ + /* Handle _looptemp_ clauses only on parallel/task. */ if (fd) continue; break; @@ -3688,7 +4182,7 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, if (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c)) { lastprivate_firstprivate = true; - if (pass != 0) + if (pass != 0 || is_taskloop_ctx (ctx)) continue; } /* Even without corresponding firstprivate, if @@ -3740,6 +4234,22 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, } new_var = var = OMP_CLAUSE_DECL (c); + if (c_kind == OMP_CLAUSE_REDUCTION && TREE_CODE (var) == MEM_REF) + { + var = TREE_OPERAND (var, 0); + if (TREE_CODE (var) == INDIRECT_REF + || TREE_CODE (var) == ADDR_EXPR) + var = TREE_OPERAND (var, 0); + if (is_variable_sized (var)) + { + gcc_assert (DECL_HAS_VALUE_EXPR_P (var)); + var = DECL_VALUE_EXPR (var); + gcc_assert (TREE_CODE (var) == INDIRECT_REF); + var = TREE_OPERAND (var, 0); + gcc_assert (DECL_P (var)); + } + new_var = var; + } if (c_kind != OMP_CLAUSE_COPYIN) new_var = lookup_decl (var, ctx); @@ -3748,28 +4258,259 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, if (pass != 0) continue; } - else if (is_variable_sized (var)) + /* C/C++ array section reductions. */ + else if (c_kind == OMP_CLAUSE_REDUCTION + && var != OMP_CLAUSE_DECL (c)) { - /* For variable sized types, we need to allocate the - actual storage here. Call alloca and store the - result in the pointer decl that we created elsewhere. */ if (pass == 0) continue; - if (c_kind != OMP_CLAUSE_FIRSTPRIVATE || !is_task_ctx (ctx)) + tree orig_var = TREE_OPERAND (OMP_CLAUSE_DECL (c), 0); + if (TREE_CODE (orig_var) == INDIRECT_REF + || TREE_CODE (orig_var) == ADDR_EXPR) + orig_var = TREE_OPERAND (orig_var, 0); + tree d = OMP_CLAUSE_DECL (c); + tree type = TREE_TYPE (d); + gcc_assert (TREE_CODE (type) == ARRAY_TYPE); + tree v = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); + const char *name = get_name (orig_var); + if (TREE_CONSTANT (v)) { - gcall *stmt; - tree tmp, atmp; - - ptr = DECL_VALUE_EXPR (new_var); - gcc_assert (TREE_CODE (ptr) == INDIRECT_REF); - ptr = TREE_OPERAND (ptr, 0); + x = create_tmp_var_raw (type, name); + gimple_add_tmp_var (x); + TREE_ADDRESSABLE (x) = 1; + x = build_fold_addr_expr_loc (clause_loc, x); + } + else + { + tree atmp + = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN); + tree t = maybe_lookup_decl (v, ctx); + if (t) + v = t; + else + v = maybe_lookup_decl_in_outer_ctx (v, ctx); + gimplify_expr (&v, ilist, NULL, is_gimple_val, fb_rvalue); + t = fold_build2_loc (clause_loc, PLUS_EXPR, + TREE_TYPE (v), v, + build_int_cst (TREE_TYPE (v), 1)); + t = fold_build2_loc (clause_loc, MULT_EXPR, + TREE_TYPE (v), t, + TYPE_SIZE_UNIT (TREE_TYPE (type))); + tree al = size_int (TYPE_ALIGN (TREE_TYPE (type))); + x = build_call_expr_loc (clause_loc, atmp, 2, t, al); + } + + tree ptype = build_pointer_type (TREE_TYPE (type)); + x = fold_convert_loc (clause_loc, ptype, x); + tree y = create_tmp_var (ptype, name); + gimplify_assign (y, x, ilist); + x = y; + if (TREE_CODE (TREE_OPERAND (d, 0)) == ADDR_EXPR) + { + if (orig_var != var) + { + gcc_assert (is_variable_sized (orig_var)); + x = fold_convert_loc (clause_loc, TREE_TYPE (new_var), + x); + gimplify_assign (new_var, x, ilist); + tree new_orig_var = lookup_decl (orig_var, ctx); + tree t = build_fold_indirect_ref (new_var); + DECL_IGNORED_P (new_var) = 0; + TREE_THIS_NOTRAP (t); + SET_DECL_VALUE_EXPR (new_orig_var, t); + DECL_HAS_VALUE_EXPR_P (new_orig_var) = 1; + } + else + { + x = build2 (MEM_REF, TREE_TYPE (new_var), x, + build_int_cst (ptype, 0)); + SET_DECL_VALUE_EXPR (new_var, x); + DECL_HAS_VALUE_EXPR_P (new_var) = 1; + } + } + else + { + gcc_assert (orig_var == var); + if (TREE_CODE (TREE_OPERAND (d, 0)) == INDIRECT_REF) + { + x = create_tmp_var (ptype, name); + TREE_ADDRESSABLE (x) = 1; + gimplify_assign (x, y, ilist); + x = build_fold_addr_expr_loc (clause_loc, x); + } + x = fold_convert_loc (clause_loc, TREE_TYPE (new_var), x); + gimplify_assign (new_var, x, ilist); + } + tree y1 = create_tmp_var (ptype, NULL); + gimplify_assign (y1, y, ilist); + tree i2 = NULL_TREE, y2 = NULL_TREE; + tree body2 = NULL_TREE, end2 = NULL_TREE; + tree y3 = NULL_TREE, y4 = NULL_TREE; + if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) || is_simd) + { + y2 = create_tmp_var (ptype, NULL); + gimplify_assign (y2, y, ilist); + tree ref = build_outer_var_ref (var, ctx); + /* For ref build_outer_var_ref already performs this. */ + if (TREE_CODE (TREE_OPERAND (d, 0)) == INDIRECT_REF) + gcc_assert (is_reference (var)); + else if (TREE_CODE (TREE_OPERAND (d, 0)) == ADDR_EXPR) + ref = build_fold_addr_expr (ref); + else if (is_reference (var)) + ref = build_fold_addr_expr (ref); + ref = fold_convert_loc (clause_loc, ptype, ref); + if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) + && OMP_CLAUSE_REDUCTION_OMP_ORIG_REF (c)) + { + y3 = create_tmp_var (ptype, NULL); + gimplify_assign (y3, unshare_expr (ref), ilist); + } + if (is_simd) + { + y4 = create_tmp_var (ptype, NULL); + gimplify_assign (y4, ref, dlist); + } + } + tree i = create_tmp_var (TREE_TYPE (v), NULL); + gimplify_assign (i, build_int_cst (TREE_TYPE (v), 0), ilist); + tree body = create_artificial_label (UNKNOWN_LOCATION); + tree end = create_artificial_label (UNKNOWN_LOCATION); + gimple_seq_add_stmt (ilist, gimple_build_label (body)); + if (y2) + { + i2 = create_tmp_var (TREE_TYPE (v), NULL); + gimplify_assign (i2, build_int_cst (TREE_TYPE (v), 0), dlist); + body2 = create_artificial_label (UNKNOWN_LOCATION); + end2 = create_artificial_label (UNKNOWN_LOCATION); + gimple_seq_add_stmt (dlist, gimple_build_label (body2)); + } + if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)) + { + tree placeholder = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c); + tree decl_placeholder + = OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c); + SET_DECL_VALUE_EXPR (decl_placeholder, + build_simple_mem_ref (y1)); + DECL_HAS_VALUE_EXPR_P (decl_placeholder) = 1; + SET_DECL_VALUE_EXPR (placeholder, + y3 ? build_simple_mem_ref (y3) + : error_mark_node); + DECL_HAS_VALUE_EXPR_P (placeholder) = 1; + x = lang_hooks.decls.omp_clause_default_ctor + (c, build_simple_mem_ref (y1), + y3 ? build_simple_mem_ref (y3) : NULL_TREE); + if (x) + gimplify_and_add (x, ilist); + if (OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c)) + { + gimple_seq tseq = OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c); + lower_omp (&tseq, ctx); + gimple_seq_add_seq (ilist, tseq); + } + OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c) = NULL; + if (is_simd) + { + SET_DECL_VALUE_EXPR (decl_placeholder, + build_simple_mem_ref (y2)); + SET_DECL_VALUE_EXPR (placeholder, + build_simple_mem_ref (y4)); + gimple_seq tseq = OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c); + lower_omp (&tseq, ctx); + gimple_seq_add_seq (dlist, tseq); + OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c) = NULL; + } + DECL_HAS_VALUE_EXPR_P (placeholder) = 0; + DECL_HAS_VALUE_EXPR_P (decl_placeholder) = 0; + x = lang_hooks.decls.omp_clause_dtor + (c, build_simple_mem_ref (y2)); + if (x) + { + gimple_seq tseq = NULL; + dtor = x; + gimplify_stmt (&dtor, &tseq); + gimple_seq_add_seq (dlist, tseq); + } + } + else + { + x = omp_reduction_init (c, TREE_TYPE (type)); + enum tree_code code = OMP_CLAUSE_REDUCTION_CODE (c); + + /* reduction(-:var) sums up the partial results, so it + acts identically to reduction(+:var). */ + if (code == MINUS_EXPR) + code = PLUS_EXPR; + + gimplify_assign (build_simple_mem_ref (y1), x, ilist); + if (is_simd) + { + x = build2 (code, TREE_TYPE (type), + build_simple_mem_ref (y4), + build_simple_mem_ref (y2)); + gimplify_assign (build_simple_mem_ref (y4), x, dlist); + } + } + gimple *g + = gimple_build_assign (y1, POINTER_PLUS_EXPR, y1, + TYPE_SIZE_UNIT (TREE_TYPE (type))); + gimple_seq_add_stmt (ilist, g); + if (y3) + { + g = gimple_build_assign (y3, POINTER_PLUS_EXPR, y3, + TYPE_SIZE_UNIT (TREE_TYPE (type))); + gimple_seq_add_stmt (ilist, g); + } + g = gimple_build_assign (i, PLUS_EXPR, i, + build_int_cst (TREE_TYPE (i), 1)); + gimple_seq_add_stmt (ilist, g); + g = gimple_build_cond (LE_EXPR, i, v, body, end); + gimple_seq_add_stmt (ilist, g); + gimple_seq_add_stmt (ilist, gimple_build_label (end)); + if (y2) + { + g = gimple_build_assign (y2, POINTER_PLUS_EXPR, y2, + TYPE_SIZE_UNIT (TREE_TYPE (type))); + gimple_seq_add_stmt (dlist, g); + if (y4) + { + g = gimple_build_assign + (y4, POINTER_PLUS_EXPR, y4, + TYPE_SIZE_UNIT (TREE_TYPE (type))); + gimple_seq_add_stmt (dlist, g); + } + g = gimple_build_assign (i2, PLUS_EXPR, i2, + build_int_cst (TREE_TYPE (i2), 1)); + gimple_seq_add_stmt (dlist, g); + g = gimple_build_cond (LE_EXPR, i2, v, body2, end2); + gimple_seq_add_stmt (dlist, g); + gimple_seq_add_stmt (dlist, gimple_build_label (end2)); + } + continue; + } + else if (is_variable_sized (var)) + { + /* For variable sized types, we need to allocate the + actual storage here. Call alloca and store the + result in the pointer decl that we created elsewhere. */ + if (pass == 0) + continue; + + if (c_kind != OMP_CLAUSE_FIRSTPRIVATE || !is_task_ctx (ctx)) + { + gcall *stmt; + tree tmp, atmp; + + ptr = DECL_VALUE_EXPR (new_var); + gcc_assert (TREE_CODE (ptr) == INDIRECT_REF); + ptr = TREE_OPERAND (ptr, 0); gcc_assert (DECL_P (ptr)); x = TYPE_SIZE_UNIT (TREE_TYPE (new_var)); /* void *tmp = __builtin_alloca */ - atmp = builtin_decl_explicit (BUILT_IN_ALLOCA); - stmt = gimple_build_call (atmp, 1, x); + atmp = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN); + stmt = gimple_build_call (atmp, 2, x, + size_int (DECL_ALIGN (var))); tmp = create_tmp_var_raw (ptr_type_node); gimple_add_tmp_var (tmp); gimple_call_set_lhs (stmt, tmp); @@ -3806,12 +4547,8 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, x = NULL_TREE; else { - const char *name = NULL; - if (DECL_NAME (var)) - name = IDENTIFIER_POINTER (DECL_NAME (new_var)); - x = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (new_var)), - name); + get_name (var)); gimple_add_tmp_var (x); TREE_ADDRESSABLE (x) = 1; x = build_fold_addr_expr_loc (clause_loc, x); @@ -3819,8 +4556,11 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, } else { - tree atmp = builtin_decl_explicit (BUILT_IN_ALLOCA); - x = build_call_expr_loc (clause_loc, atmp, 1, x); + tree atmp + = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN); + tree rtype = TREE_TYPE (TREE_TYPE (new_var)); + tree al = size_int (TYPE_ALIGN (rtype)); + x = build_call_expr_loc (clause_loc, atmp, 2, x, al); } if (x) @@ -3849,6 +4589,11 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, /* Shared global vars are just accessed directly. */ if (is_global_var (new_var)) break; + /* For taskloop firstprivate/lastprivate, represented + as firstprivate and shared clause on the task, new_var + is the firstprivate var. */ + if (OMP_CLAUSE_SHARED_FIRSTPRIVATE (c)) + break; /* Set up the DECL_VALUE_EXPR for shared variables now. This needs to be delayed until after fixup_child_record_type so that we get the correct type during the dereference. */ @@ -3885,7 +4630,8 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, x = NULL; do_private: tree nx; - nx = lang_hooks.decls.omp_clause_default_ctor (c, new_var, x); + nx = lang_hooks.decls.omp_clause_default_ctor + (c, unshare_expr (new_var), x); if (is_simd) { tree y = lang_hooks.decls.omp_clause_dtor (c, new_var); @@ -4039,12 +4785,13 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, break; } } - x = lang_hooks.decls.omp_clause_copy_ctor (c, new_var, x); + x = lang_hooks.decls.omp_clause_copy_ctor + (c, unshare_expr (new_var), x); gimplify_and_add (x, ilist); goto do_dtor; case OMP_CLAUSE__LOOPTEMP_: - gcc_assert (is_parallel_ctx (ctx)); + gcc_assert (is_taskreg_ctx (ctx)); x = build_outer_var_ref (var, ctx); x = build2 (MODIFY_EXPR, TREE_TYPE (new_var), new_var, x); gimplify_and_add (x, ilist); @@ -4380,7 +5127,15 @@ lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *stmt_list, && !OMP_CLAUSE_LINEAR_NO_COPYOUT (c))) { var = OMP_CLAUSE_DECL (c); - new_var = lookup_decl (var, ctx); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE + && OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c) + && is_taskloop_ctx (ctx)) + { + gcc_checking_assert (ctx->outer && is_task_ctx (ctx->outer)); + new_var = lookup_decl (var, ctx->outer); + } + else + new_var = lookup_decl (var, ctx); if (simduid && DECL_HAS_VALUE_EXPR_P (new_var)) { @@ -4424,7 +5179,18 @@ lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *stmt_list, OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c) = NULL; } - x = build_outer_var_ref (var, ctx); + x = NULL_TREE; + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE + && OMP_CLAUSE_LASTPRIVATE_TASKLOOP_IV (c)) + { + gcc_checking_assert (is_taskloop_ctx (ctx)); + tree ovar = maybe_lookup_decl_in_outer_ctx (var, + ctx->outer->outer); + if (is_global_var (ovar)) + x = ovar; + } + if (!x) + x = build_outer_var_ref (var, ctx, true); if (is_reference (var)) new_var = build_simple_mem_ref_loc (clause_loc, new_var); x = lang_hooks.decls.omp_clause_assign_op (c, x, new_var); @@ -4525,7 +5291,8 @@ lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp, omp_context *ctx) for (c = clauses; c && count < 2; c = OMP_CLAUSE_CHAIN (c)) if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) { - if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)) + if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) + || TREE_CODE (OMP_CLAUSE_DECL (c)) == MEM_REF) { /* Never use OMP_ATOMIC for array reductions or UDRs. */ count = -1; @@ -4550,16 +5317,32 @@ lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp, omp_context *ctx) for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c)) { - tree var, ref, new_var; + tree var, ref, new_var, orig_var; enum tree_code code; location_t clause_loc = OMP_CLAUSE_LOCATION (c); if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION) continue; - var = OMP_CLAUSE_DECL (c); + orig_var = var = OMP_CLAUSE_DECL (c); + if (TREE_CODE (var) == MEM_REF) + { + var = TREE_OPERAND (var, 0); + if (TREE_CODE (var) == INDIRECT_REF + || TREE_CODE (var) == ADDR_EXPR) + var = TREE_OPERAND (var, 0); + orig_var = var; + if (is_variable_sized (var)) + { + gcc_assert (DECL_HAS_VALUE_EXPR_P (var)); + var = DECL_VALUE_EXPR (var); + gcc_assert (TREE_CODE (var) == INDIRECT_REF); + var = TREE_OPERAND (var, 0); + gcc_assert (DECL_P (var)); + } + } new_var = lookup_decl (var, ctx); - if (is_reference (var)) + if (var == OMP_CLAUSE_DECL (c) && is_reference (var)) new_var = build_simple_mem_ref_loc (clause_loc, new_var); ref = build_outer_var_ref (var, ctx); code = OMP_CLAUSE_REDUCTION_CODE (c); @@ -4586,6 +5369,92 @@ lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp, omp_context *ctx) gimplify_and_add (x, stmt_seqp); return; } + else if (TREE_CODE (OMP_CLAUSE_DECL (c)) == MEM_REF) + { + tree d = OMP_CLAUSE_DECL (c); + tree type = TREE_TYPE (d); + tree v = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); + tree i = create_tmp_var (TREE_TYPE (v), NULL); + tree ptype = build_pointer_type (TREE_TYPE (type)); + /* For ref build_outer_var_ref already performs this, so + only new_var needs a dereference. */ + if (TREE_CODE (TREE_OPERAND (d, 0)) == INDIRECT_REF) + { + new_var = build_simple_mem_ref_loc (clause_loc, new_var); + gcc_assert (is_reference (var) && var == orig_var); + } + else if (TREE_CODE (TREE_OPERAND (d, 0)) == ADDR_EXPR) + { + if (orig_var == var) + { + new_var = build_fold_addr_expr (new_var); + ref = build_fold_addr_expr (ref); + } + } + else + { + gcc_assert (orig_var == var); + if (is_reference (var)) + ref = build_fold_addr_expr (ref); + } + if (DECL_P (v)) + { + tree t = maybe_lookup_decl (v, ctx); + if (t) + v = t; + else + v = maybe_lookup_decl_in_outer_ctx (v, ctx); + gimplify_expr (&v, stmt_seqp, NULL, is_gimple_val, fb_rvalue); + } + new_var = fold_convert_loc (clause_loc, ptype, new_var); + ref = fold_convert_loc (clause_loc, ptype, ref); + tree m = create_tmp_var (ptype, NULL); + gimplify_assign (m, new_var, stmt_seqp); + new_var = m; + m = create_tmp_var (ptype, NULL); + gimplify_assign (m, ref, stmt_seqp); + ref = m; + gimplify_assign (i, build_int_cst (TREE_TYPE (v), 0), stmt_seqp); + tree body = create_artificial_label (UNKNOWN_LOCATION); + tree end = create_artificial_label (UNKNOWN_LOCATION); + gimple_seq_add_stmt (&sub_seq, gimple_build_label (body)); + tree priv = build_simple_mem_ref_loc (clause_loc, new_var); + tree out = build_simple_mem_ref_loc (clause_loc, ref); + if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)) + { + tree placeholder = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c); + tree decl_placeholder + = OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c); + SET_DECL_VALUE_EXPR (placeholder, out); + DECL_HAS_VALUE_EXPR_P (placeholder) = 1; + SET_DECL_VALUE_EXPR (decl_placeholder, priv); + DECL_HAS_VALUE_EXPR_P (decl_placeholder) = 1; + lower_omp (&OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c), ctx); + gimple_seq_add_seq (&sub_seq, + OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c)); + OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c) = NULL; + OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = NULL; + OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c) = NULL; + } + else + { + x = build2 (code, TREE_TYPE (out), out, priv); + out = unshare_expr (out); + gimplify_assign (out, x, &sub_seq); + } + gimple *g = gimple_build_assign (new_var, POINTER_PLUS_EXPR, new_var, + TYPE_SIZE_UNIT (TREE_TYPE (type))); + gimple_seq_add_stmt (&sub_seq, g); + g = gimple_build_assign (ref, POINTER_PLUS_EXPR, ref, + TYPE_SIZE_UNIT (TREE_TYPE (type))); + gimple_seq_add_stmt (&sub_seq, g); + g = gimple_build_assign (i, PLUS_EXPR, i, + build_int_cst (TREE_TYPE (i), 1)); + gimple_seq_add_stmt (&sub_seq, g); + g = gimple_build_cond (LE_EXPR, i, v, body, end); + gimple_seq_add_stmt (&sub_seq, g); + gimple_seq_add_stmt (&sub_seq, gimple_build_label (end)); + } else if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)) { tree placeholder = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c); @@ -4680,7 +5549,17 @@ static void lower_send_clauses (tree clauses, gimple_seq *ilist, gimple_seq *olist, omp_context *ctx) { - tree c; + tree c, t; + int ignored_looptemp = 0; + bool is_taskloop = false; + + /* For taskloop, ignore first two _looptemp_ clauses, those are initialized + by GOMP_taskloop. */ + if (is_task_ctx (ctx) && gimple_omp_task_taskloop_p (ctx->stmt)) + { + ignored_looptemp = 2; + is_taskloop = true; + } for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c)) { @@ -4698,19 +5577,76 @@ lower_send_clauses (tree clauses, gimple_seq *ilist, gimple_seq *olist, case OMP_CLAUSE_COPYIN: case OMP_CLAUSE_LASTPRIVATE: case OMP_CLAUSE_REDUCTION: + break; + case OMP_CLAUSE_SHARED: + if (OMP_CLAUSE_SHARED_FIRSTPRIVATE (c)) + break; + continue; case OMP_CLAUSE__LOOPTEMP_: + if (ignored_looptemp) + { + ignored_looptemp--; + continue; + } break; default: continue; } val = OMP_CLAUSE_DECL (c); - var = lookup_decl_in_outer_ctx (val, ctx); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + && TREE_CODE (val) == MEM_REF) + { + val = TREE_OPERAND (val, 0); + if (TREE_CODE (val) == INDIRECT_REF + || TREE_CODE (val) == ADDR_EXPR) + val = TREE_OPERAND (val, 0); + if (is_variable_sized (val)) + continue; + } + + /* For OMP_CLAUSE_SHARED_FIRSTPRIVATE, look beyond the + outer taskloop region. */ + omp_context *ctx_for_o = ctx; + if (is_taskloop + && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED + && OMP_CLAUSE_SHARED_FIRSTPRIVATE (c)) + ctx_for_o = ctx->outer; + + var = lookup_decl_in_outer_ctx (val, ctx_for_o); if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_COPYIN && is_global_var (var)) continue; - if (is_variable_sized (val)) + + t = omp_member_access_dummy_var (var); + if (t) + { + var = DECL_VALUE_EXPR (var); + tree o = maybe_lookup_decl_in_outer_ctx (t, ctx_for_o); + if (o != t) + var = unshare_and_remap (var, t, o); + else + var = unshare_expr (var); + } + + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED) + { + /* Handle taskloop firstprivate/lastprivate, where the + lastprivate on GIMPLE_OMP_TASK is represented as + OMP_CLAUSE_SHARED_FIRSTPRIVATE. */ + tree f = lookup_sfield ((splay_tree_key) &DECL_UID (val), ctx); + x = omp_build_component_ref (ctx->sender_decl, f); + if (use_pointer_for_field (val, ctx)) + var = build_fold_addr_expr (var); + gimplify_assign (x, var, ilist); + DECL_ABSTRACT_ORIGIN (f) = NULL; + continue; + } + + if ((OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION + || val == OMP_CLAUSE_DECL (c)) + && is_variable_sized (val)) continue; by_ref = use_pointer_for_field (val, NULL); @@ -4740,7 +5676,10 @@ lower_send_clauses (tree clauses, gimple_seq *ilist, gimple_seq *olist, case OMP_CLAUSE_REDUCTION: do_in = true; - do_out = !(by_ref || is_reference (val)); + if (val == OMP_CLAUSE_DECL (c)) + do_out = !(by_ref || is_reference (val)); + else + by_ref = TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE; break; default: @@ -4771,7 +5710,7 @@ lower_send_clauses (tree clauses, gimple_seq *ilist, gimple_seq *olist, static void lower_send_shared_vars (gimple_seq *ilist, gimple_seq *olist, omp_context *ctx) { - tree var, ovar, nvar, f, x, record_type; + tree var, ovar, nvar, t, f, x, record_type; if (ctx->record_type == NULL) return; @@ -4780,6 +5719,9 @@ lower_send_shared_vars (gimple_seq *ilist, gimple_seq *olist, omp_context *ctx) for (f = TYPE_FIELDS (record_type); f ; f = DECL_CHAIN (f)) { ovar = DECL_ABSTRACT_ORIGIN (f); + if (!ovar || TREE_CODE (ovar) == FIELD_DECL) + continue; + nvar = maybe_lookup_decl (ovar, ctx); if (!nvar || !DECL_HAS_VALUE_EXPR_P (nvar)) continue; @@ -4789,6 +5731,17 @@ lower_send_shared_vars (gimple_seq *ilist, gimple_seq *olist, omp_context *ctx) mapping for OVAR. */ var = lookup_decl_in_outer_ctx (ovar, ctx); + t = omp_member_access_dummy_var (var); + if (t) + { + var = DECL_VALUE_EXPR (var); + tree o = maybe_lookup_decl_in_outer_ctx (t, ctx); + if (o != t) + var = unshare_and_remap (var, t, o); + else + var = unshare_expr (var); + } + if (use_pointer_for_field (ovar, ctx)) { x = build_sender_ref (ovar, ctx); @@ -4830,6 +5783,8 @@ gimple_build_cond_empty (tree cond) return gimple_build_cond (pred_code, lhs, rhs, NULL_TREE, NULL_TREE); } +static void expand_omp_build_assign (gimple_stmt_iterator *, tree, tree, + bool = false); /* Build the function calls to GOMP_parallel_start etc to actually generate the parallel operation. REGION is the parallel region @@ -4947,13 +5902,12 @@ expand_parallel_call (struct omp_region *region, basic_block bb, gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); gsi = gsi_start_bb (then_bb); - stmt = gimple_build_assign (tmp_then, val); - gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); + expand_omp_build_assign (&gsi, tmp_then, val, true); gsi = gsi_start_bb (else_bb); - stmt = gimple_build_assign - (tmp_else, build_int_cst (unsigned_type_node, 1)); - gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); + expand_omp_build_assign (&gsi, tmp_else, + build_int_cst (unsigned_type_node, 1), + true); make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE); make_edge (cond_bb, else_bb, EDGE_FALSE_VALUE); @@ -5043,42 +5997,111 @@ expand_cilk_for_call (basic_block bb, gomp_parallel *entry_stmt, generate the task operation. BB is the block where to insert the code. */ static void -expand_task_call (basic_block bb, gomp_task *entry_stmt) +expand_task_call (struct omp_region *region, basic_block bb, + gomp_task *entry_stmt) { - tree t, t1, t2, t3, flags, cond, c, c2, clauses, depend; + tree t1, t2, t3; gimple_stmt_iterator gsi; location_t loc = gimple_location (entry_stmt); - clauses = gimple_omp_task_clauses (entry_stmt); + tree clauses = gimple_omp_task_clauses (entry_stmt); + + tree ifc = find_omp_clause (clauses, OMP_CLAUSE_IF); + tree untied = find_omp_clause (clauses, OMP_CLAUSE_UNTIED); + tree mergeable = find_omp_clause (clauses, OMP_CLAUSE_MERGEABLE); + tree depend = find_omp_clause (clauses, OMP_CLAUSE_DEPEND); + tree finalc = find_omp_clause (clauses, OMP_CLAUSE_FINAL); + tree priority = find_omp_clause (clauses, OMP_CLAUSE_PRIORITY); + + unsigned int iflags + = (untied ? GOMP_TASK_FLAG_UNTIED : 0) + | (mergeable ? GOMP_TASK_FLAG_MERGEABLE : 0) + | (depend ? GOMP_TASK_FLAG_DEPEND : 0); + + bool taskloop_p = gimple_omp_task_taskloop_p (entry_stmt); + tree startvar = NULL_TREE, endvar = NULL_TREE, step = NULL_TREE; + tree num_tasks = NULL_TREE; + bool ull = false; + if (taskloop_p) + { + gimple *g = last_stmt (region->outer->entry); + gcc_assert (gimple_code (g) == GIMPLE_OMP_FOR + && gimple_omp_for_kind (g) == GF_OMP_FOR_KIND_TASKLOOP); + struct omp_for_data fd; + extract_omp_for_data (as_a (g), &fd, NULL); + startvar = find_omp_clause (clauses, OMP_CLAUSE__LOOPTEMP_); + endvar = find_omp_clause (OMP_CLAUSE_CHAIN (startvar), + OMP_CLAUSE__LOOPTEMP_); + startvar = OMP_CLAUSE_DECL (startvar); + endvar = OMP_CLAUSE_DECL (endvar); + step = fold_convert_loc (loc, fd.iter_type, fd.loop.step); + if (fd.loop.cond_code == LT_EXPR) + iflags |= GOMP_TASK_FLAG_UP; + tree tclauses = gimple_omp_for_clauses (g); + num_tasks = find_omp_clause (tclauses, OMP_CLAUSE_NUM_TASKS); + if (num_tasks) + num_tasks = OMP_CLAUSE_NUM_TASKS_EXPR (num_tasks); + else + { + num_tasks = find_omp_clause (tclauses, OMP_CLAUSE_GRAINSIZE); + if (num_tasks) + { + iflags |= GOMP_TASK_FLAG_GRAINSIZE; + num_tasks = OMP_CLAUSE_GRAINSIZE_EXPR (num_tasks); + } + else + num_tasks = integer_zero_node; + } + num_tasks = fold_convert_loc (loc, long_integer_type_node, num_tasks); + if (ifc == NULL_TREE) + iflags |= GOMP_TASK_FLAG_IF; + if (find_omp_clause (tclauses, OMP_CLAUSE_NOGROUP)) + iflags |= GOMP_TASK_FLAG_NOGROUP; + ull = fd.iter_type == long_long_unsigned_type_node; + } + else if (priority) + iflags |= GOMP_TASK_FLAG_PRIORITY; - c = find_omp_clause (clauses, OMP_CLAUSE_IF); - if (c) - cond = gimple_boolify (OMP_CLAUSE_IF_EXPR (c)); - else - cond = boolean_true_node; + tree flags = build_int_cst (unsigned_type_node, iflags); - c = find_omp_clause (clauses, OMP_CLAUSE_UNTIED); - c2 = find_omp_clause (clauses, OMP_CLAUSE_MERGEABLE); - depend = find_omp_clause (clauses, OMP_CLAUSE_DEPEND); - flags = build_int_cst (unsigned_type_node, - (c ? 1 : 0) + (c2 ? 4 : 0) + (depend ? 8 : 0)); + tree cond = boolean_true_node; + if (ifc) + { + if (taskloop_p) + { + tree t = gimple_boolify (OMP_CLAUSE_IF_EXPR (ifc)); + t = fold_build3_loc (loc, COND_EXPR, unsigned_type_node, t, + build_int_cst (unsigned_type_node, + GOMP_TASK_FLAG_IF), + build_int_cst (unsigned_type_node, 0)); + flags = fold_build2_loc (loc, PLUS_EXPR, unsigned_type_node, + flags, t); + } + else + cond = gimple_boolify (OMP_CLAUSE_IF_EXPR (ifc)); + } - c = find_omp_clause (clauses, OMP_CLAUSE_FINAL); - if (c) + if (finalc) { - c = gimple_boolify (OMP_CLAUSE_FINAL_EXPR (c)); - c = fold_build3_loc (loc, COND_EXPR, unsigned_type_node, c, - build_int_cst (unsigned_type_node, 2), + tree t = gimple_boolify (OMP_CLAUSE_FINAL_EXPR (finalc)); + t = fold_build3_loc (loc, COND_EXPR, unsigned_type_node, t, + build_int_cst (unsigned_type_node, + GOMP_TASK_FLAG_FINAL), build_int_cst (unsigned_type_node, 0)); - flags = fold_build2_loc (loc, PLUS_EXPR, unsigned_type_node, flags, c); + flags = fold_build2_loc (loc, PLUS_EXPR, unsigned_type_node, flags, t); } if (depend) depend = OMP_CLAUSE_DECL (depend); else depend = build_int_cst (ptr_type_node, 0); + if (priority) + priority = fold_convert (integer_type_node, + OMP_CLAUSE_PRIORITY_EXPR (priority)); + else + priority = integer_zero_node; gsi = gsi_last_bb (bb); - t = gimple_omp_task_data_arg (entry_stmt); + tree t = gimple_omp_task_data_arg (entry_stmt); if (t == NULL) t2 = null_pointer_node; else @@ -5090,11 +6113,20 @@ expand_task_call (basic_block bb, gomp_task *entry_stmt) else t3 = build_fold_addr_expr_loc (loc, t); - t = build_call_expr (builtin_decl_explicit (BUILT_IN_GOMP_TASK), - 8, t1, t2, t3, - gimple_omp_task_arg_size (entry_stmt), - gimple_omp_task_arg_align (entry_stmt), cond, flags, - depend); + if (taskloop_p) + t = build_call_expr (ull + ? builtin_decl_explicit (BUILT_IN_GOMP_TASKLOOP_ULL) + : builtin_decl_explicit (BUILT_IN_GOMP_TASKLOOP), + 11, t1, t2, t3, + gimple_omp_task_arg_size (entry_stmt), + gimple_omp_task_arg_align (entry_stmt), flags, + num_tasks, priority, startvar, endvar, step); + else + t = build_call_expr (builtin_decl_explicit (BUILT_IN_GOMP_TASK), + 9, t1, t2, t3, + gimple_omp_task_arg_size (entry_stmt), + gimple_omp_task_arg_align (entry_stmt), cond, flags, + depend, priority); force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, false, GSI_CONTINUE_LINKING); @@ -5336,16 +6368,21 @@ expand_omp_regimplify_p (tree *tp, int *walk_subtrees, void *) return NULL_TREE; } -/* Prepend TO = FROM assignment before *GSI_P. */ +/* Prepend or append TO = FROM assignment before or after *GSI_P. */ static void -expand_omp_build_assign (gimple_stmt_iterator *gsi_p, tree to, tree from) +expand_omp_build_assign (gimple_stmt_iterator *gsi_p, tree to, tree from, + bool after) { bool simple_p = DECL_P (to) && TREE_ADDRESSABLE (to); from = force_gimple_operand_gsi (gsi_p, from, simple_p, NULL_TREE, - true, GSI_SAME_STMT); + !after, after ? GSI_CONTINUE_LINKING + : GSI_SAME_STMT); gimple *stmt = gimple_build_assign (to, from); - gsi_insert_before (gsi_p, stmt, GSI_SAME_STMT); + if (after) + gsi_insert_after (gsi_p, stmt, GSI_CONTINUE_LINKING); + else + gsi_insert_before (gsi_p, stmt, GSI_SAME_STMT); if (walk_tree (&from, expand_omp_regimplify_p, NULL, NULL) || walk_tree (&to, expand_omp_regimplify_p, NULL, NULL)) { @@ -5639,7 +6676,7 @@ expand_omp_taskreg (struct omp_region *region) expand_parallel_call (region, new_bb, as_a (entry_stmt), ws_args); else - expand_task_call (new_bb, as_a (entry_stmt)); + expand_task_call (region, new_bb, as_a (entry_stmt)); if (gimple_in_ssa_p (cfun)) update_ssa (TODO_update_ssa_only_virtuals); } @@ -5701,7 +6738,8 @@ expand_omp_taskreg (struct omp_region *region) static void expand_omp_for_init_counts (struct omp_for_data *fd, gimple_stmt_iterator *gsi, basic_block &entry_bb, tree *counts, - basic_block &zero_iter_bb, int &first_zero_iter, + basic_block &zero_iter1_bb, int &first_zero_iter1, + basic_block &zero_iter2_bb, int &first_zero_iter2, basic_block &l2_dom_bb) { tree t, type = TREE_TYPE (fd->loop.v); @@ -5714,6 +6752,7 @@ expand_omp_for_init_counts (struct omp_for_data *fd, gimple_stmt_iterator *gsi, if (gimple_omp_for_combined_into_p (fd->for_stmt) && TREE_CODE (fd->loop.n2) != INTEGER_CST) { + gcc_assert (fd->ordered == 0); /* First two _looptemp_ clauses are for istart/iend, counts[0] isn't supposed to be handled, as the inner loop doesn't use it. */ @@ -5733,11 +6772,27 @@ expand_omp_for_init_counts (struct omp_for_data *fd, gimple_stmt_iterator *gsi, return; } - for (i = 0; i < fd->collapse; i++) + for (i = fd->collapse; i < fd->ordered; i++) + { + tree itype = TREE_TYPE (fd->loops[i].v); + counts[i] = NULL_TREE; + t = fold_binary (fd->loops[i].cond_code, boolean_type_node, + fold_convert (itype, fd->loops[i].n1), + fold_convert (itype, fd->loops[i].n2)); + if (t && integer_zerop (t)) + { + for (i = fd->collapse; i < fd->ordered; i++) + counts[i] = build_int_cst (type, 0); + break; + } + } + for (i = 0; i < (fd->ordered ? fd->ordered : fd->collapse); i++) { tree itype = TREE_TYPE (fd->loops[i].v); - if (SSA_VAR_P (fd->loop.n2) + if (i >= fd->collapse && counts[i]) + continue; + if ((SSA_VAR_P (fd->loop.n2) || i >= fd->collapse) && ((t = fold_binary (fd->loops[i].cond_code, boolean_type_node, fold_convert (itype, fd->loops[i].n1), fold_convert (itype, fd->loops[i].n2))) @@ -5763,6 +6818,10 @@ expand_omp_for_init_counts (struct omp_for_data *fd, gimple_stmt_iterator *gsi, gimple_regimplify_operands (cond_stmt, gsi); } e = split_block (entry_bb, cond_stmt); + basic_block &zero_iter_bb + = i < fd->collapse ? zero_iter1_bb : zero_iter2_bb; + int &first_zero_iter + = i < fd->collapse ? first_zero_iter1 : first_zero_iter2; if (zero_iter_bb == NULL) { gassign *assign_stmt; @@ -5770,8 +6829,15 @@ expand_omp_for_init_counts (struct omp_for_data *fd, gimple_stmt_iterator *gsi, zero_iter_bb = create_empty_bb (entry_bb); add_bb_to_loop (zero_iter_bb, entry_bb->loop_father); *gsi = gsi_after_labels (zero_iter_bb); - assign_stmt = gimple_build_assign (fd->loop.n2, - build_zero_cst (type)); + if (i < fd->collapse) + assign_stmt = gimple_build_assign (fd->loop.n2, + build_zero_cst (type)); + else + { + counts[i] = create_tmp_reg (type, ".count"); + assign_stmt + = gimple_build_assign (counts[i], build_zero_cst (type)); + } gsi_insert_before (gsi, assign_stmt, GSI_SAME_STMT); set_immediate_dominator (CDI_DOMINATORS, zero_iter_bb, entry_bb); @@ -5815,10 +6881,11 @@ expand_omp_for_init_counts (struct omp_for_data *fd, gimple_stmt_iterator *gsi, counts[i] = t; else { - counts[i] = create_tmp_reg (type, ".count"); + if (i < fd->collapse || i != first_zero_iter2) + counts[i] = create_tmp_reg (type, ".count"); expand_omp_build_assign (gsi, counts[i], t); } - if (SSA_VAR_P (fd->loop.n2)) + if (SSA_VAR_P (fd->loop.n2) && i < fd->collapse) { if (i == 0) t = counts[0]; @@ -5854,8 +6921,8 @@ expand_omp_for_init_vars (struct omp_for_data *fd, gimple_stmt_iterator *gsi, if (TREE_CODE (fd->loop.n2) == INTEGER_CST) return; - tree clauses = gimple_code (inner_stmt) == GIMPLE_OMP_PARALLEL - ? gimple_omp_parallel_clauses (inner_stmt) + tree clauses = gimple_code (inner_stmt) != GIMPLE_OMP_FOR + ? gimple_omp_taskreg_clauses (inner_stmt) : gimple_omp_for_clauses (inner_stmt); /* First two _looptemp_ clauses are for istart/iend, counts[0] isn't supposed to be handled, as the inner loop doesn't @@ -6009,53 +7076,433 @@ extract_omp_for_update_vars (struct omp_for_data *fd, basic_block cont_bb, } -/* A subroutine of expand_omp_for. Generate code for a parallel - loop with any schedule. Given parameters: - - for (V = N1; V cond N2; V += STEP) BODY; +/* Expand #pragma omp ordered depend(source). */ - where COND is "<" or ">", we generate pseudocode +static void +expand_omp_ordered_source (gimple_stmt_iterator *gsi, struct omp_for_data *fd, + tree *counts, location_t loc) +{ + enum built_in_function source_ix + = fd->iter_type == long_integer_type_node + ? BUILT_IN_GOMP_DOACROSS_POST : BUILT_IN_GOMP_DOACROSS_ULL_POST; + gimple *g + = gimple_build_call (builtin_decl_explicit (source_ix), 1, + build_fold_addr_expr (counts[fd->ordered])); + gimple_set_location (g, loc); + gsi_insert_before (gsi, g, GSI_SAME_STMT); +} - more = GOMP_loop_foo_start (N1, N2, STEP, CHUNK, &istart0, &iend0); - if (more) goto L0; else goto L3; - L0: - V = istart0; - iend = iend0; - L1: - BODY; - V += STEP; - if (V cond iend) goto L1; else goto L2; - L2: - if (GOMP_loop_foo_next (&istart0, &iend0)) goto L0; else goto L3; - L3: +/* Expand a single depend from #pragma omp ordered depend(sink:...). */ - If this is a combined omp parallel loop, instead of the call to - GOMP_loop_foo_start, we call GOMP_loop_foo_next. - If this is gimple_omp_for_combined_p loop, then instead of assigning - V and iend in L0 we assign the first two _looptemp_ clause decls of the - inner GIMPLE_OMP_FOR and V += STEP; and - if (V cond iend) goto L1; else goto L2; are removed. +static void +expand_omp_ordered_sink (gimple_stmt_iterator *gsi, struct omp_for_data *fd, + tree *counts, tree c, location_t loc) +{ + auto_vec args; + enum built_in_function sink_ix + = fd->iter_type == long_integer_type_node + ? BUILT_IN_GOMP_DOACROSS_WAIT : BUILT_IN_GOMP_DOACROSS_ULL_WAIT; + tree t, off, coff = NULL_TREE, deps = OMP_CLAUSE_DECL (c), cond = NULL_TREE; + int i; + gimple_stmt_iterator gsi2 = *gsi; + bool warned_step = false; - For collapsed loops, given parameters: - collapse(3) - for (V1 = N11; V1 cond1 N12; V1 += STEP1) - for (V2 = N21; V2 cond2 N22; V2 += STEP2) - for (V3 = N31; V3 cond3 N32; V3 += STEP3) - BODY; + for (i = 0; i < fd->ordered; i++) + { + off = TREE_PURPOSE (deps); + if (!integer_zerop (off)) + { + gcc_assert (fd->loops[i].cond_code == LT_EXPR + || fd->loops[i].cond_code == GT_EXPR); + bool forward = fd->loops[i].cond_code == LT_EXPR; + if (forward ^ OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps)) + warning_at (loc, 0, "% clause waiting for " + "lexically later iteration"); + break; + } + deps = TREE_CHAIN (deps); + } + /* If all offsets corresponding to the collapsed loops are zero, + this depend clause can be ignored. FIXME: but there is still a + flush needed. We need to emit one __sync_synchronize () for it + though (perhaps conditionally)? Solve this together with the + conservative dependence folding optimization. + if (i >= fd->collapse) + return; */ - we generate pseudocode + deps = OMP_CLAUSE_DECL (c); + gsi_prev (&gsi2); + edge e1 = split_block (gsi_bb (gsi2), gsi_stmt (gsi2)); + edge e2 = split_block_after_labels (e1->dest); - if (__builtin_expect (N32 cond3 N31, 0)) goto Z0; - if (cond3 is <) - adj = STEP3 - 1; - else - adj = STEP3 + 1; - count3 = (adj + N32 - N31) / STEP3; - if (__builtin_expect (N22 cond2 N21, 0)) goto Z0; - if (cond2 is <) - adj = STEP2 - 1; - else - adj = STEP2 + 1; + *gsi = gsi_after_labels (e1->dest); + for (i = 0; i < fd->ordered; i++) + { + tree itype = TREE_TYPE (fd->loops[i].v); + if (POINTER_TYPE_P (itype)) + itype = sizetype; + if (i) + deps = TREE_CHAIN (deps); + off = TREE_PURPOSE (deps); + tree s = fold_convert_loc (loc, itype, fd->loops[i].step); + + if (integer_zerop (off)) + t = boolean_true_node; + else + { + tree a; + tree co = fold_convert_loc (loc, itype, off); + if (POINTER_TYPE_P (TREE_TYPE (fd->loops[i].v))) + { + if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps)) + co = fold_build1_loc (loc, NEGATE_EXPR, itype, co); + a = fold_build2_loc (loc, POINTER_PLUS_EXPR, + TREE_TYPE (fd->loops[i].v), fd->loops[i].v, + co); + } + else if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps)) + a = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (fd->loops[i].v), + fd->loops[i].v, co); + else + a = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (fd->loops[i].v), + fd->loops[i].v, co); + if (fd->loops[i].cond_code == LT_EXPR) + { + if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps)) + t = fold_build2_loc (loc, GE_EXPR, boolean_type_node, a, + fd->loops[i].n1); + else + t = fold_build2_loc (loc, LT_EXPR, boolean_type_node, a, + fd->loops[i].n2); + } + else if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps)) + t = fold_build2_loc (loc, GT_EXPR, boolean_type_node, a, + fd->loops[i].n2); + else + t = fold_build2_loc (loc, LE_EXPR, boolean_type_node, a, + fd->loops[i].n1); + } + if (cond) + cond = fold_build2_loc (loc, BIT_AND_EXPR, boolean_type_node, cond, t); + else + cond = t; + + off = fold_convert_loc (loc, itype, off); + + if (fd->loops[i].cond_code == LT_EXPR + ? !integer_onep (fd->loops[i].step) + : !integer_minus_onep (fd->loops[i].step)) + { + if (TYPE_UNSIGNED (itype) && fd->loops[i].cond_code == GT_EXPR) + t = fold_build2_loc (loc, TRUNC_MOD_EXPR, itype, off, + fold_build1_loc (loc, NEGATE_EXPR, itype, + s)); + else + t = fold_build2_loc (loc, TRUNC_MOD_EXPR, itype, off, s); + t = fold_build2_loc (loc, EQ_EXPR, boolean_type_node, t, + build_int_cst (itype, 0)); + if (integer_zerop (t) && !warned_step) + { + warning_at (loc, 0, "% refers to iteration never " + "in the iteration space"); + warned_step = true; + } + cond = fold_build2_loc (loc, BIT_AND_EXPR, boolean_type_node, + cond, t); + } + + if (i <= fd->collapse - 1 && fd->collapse > 1) + t = fd->loop.v; + else if (counts[i]) + t = counts[i]; + else + { + t = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (fd->loops[i].v), + fd->loops[i].v, fd->loops[i].n1); + t = fold_convert_loc (loc, fd->iter_type, t); + } + if (TYPE_UNSIGNED (itype) && fd->loops[i].cond_code == GT_EXPR) + off = fold_build2_loc (loc, TRUNC_DIV_EXPR, itype, off, + fold_build1_loc (loc, NEGATE_EXPR, itype, + s)); + else + off = fold_build2_loc (loc, TRUNC_DIV_EXPR, itype, off, s); + if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps)) + off = fold_build1_loc (loc, NEGATE_EXPR, itype, off); + off = fold_convert_loc (loc, fd->iter_type, off); + if (i <= fd->collapse - 1 && fd->collapse > 1) + { + if (i) + off = fold_build2_loc (loc, PLUS_EXPR, fd->iter_type, coff, + off); + if (i < fd->collapse - 1) + { + coff = fold_build2_loc (loc, MULT_EXPR, fd->iter_type, off, + counts[i]); + continue; + } + } + off = unshare_expr (off); + t = fold_build2_loc (loc, PLUS_EXPR, fd->iter_type, t, off); + t = force_gimple_operand_gsi (gsi, t, true, NULL_TREE, + true, GSI_SAME_STMT); + args.safe_push (t); + } + gimple *g = gimple_build_call_vec (builtin_decl_explicit (sink_ix), args); + gimple_set_location (g, loc); + gsi_insert_before (gsi, g, GSI_SAME_STMT); + + *gsi = gsi_last_bb (e1->src); + cond = unshare_expr (cond); + cond = force_gimple_operand_gsi (gsi, cond, true, NULL_TREE, false, + GSI_CONTINUE_LINKING); + gsi_insert_after (gsi, gimple_build_cond_empty (cond), GSI_NEW_STMT); + edge e3 = make_edge (e1->src, e2->dest, EDGE_FALSE_VALUE); + e3->probability = REG_BR_PROB_BASE / 8; + e1->probability = REG_BR_PROB_BASE - e3->probability; + e1->flags = EDGE_TRUE_VALUE; + set_immediate_dominator (CDI_DOMINATORS, e2->dest, e1->src); + + *gsi = gsi_after_labels (e2->dest); +} + +/* Expand all #pragma omp ordered depend(source) and + #pragma omp ordered depend(sink:...) constructs in the current + #pragma omp for ordered(n) region. */ + +static void +expand_omp_ordered_source_sink (struct omp_region *region, + struct omp_for_data *fd, tree *counts, + basic_block cont_bb) +{ + struct omp_region *inner; + int i; + for (i = fd->collapse - 1; i < fd->ordered; i++) + if (i == fd->collapse - 1 && fd->collapse > 1) + counts[i] = NULL_TREE; + else if (i >= fd->collapse && !cont_bb) + counts[i] = build_zero_cst (fd->iter_type); + else if (!POINTER_TYPE_P (TREE_TYPE (fd->loops[i].v)) + && integer_onep (fd->loops[i].step)) + counts[i] = NULL_TREE; + else + counts[i] = create_tmp_var (fd->iter_type, ".orditer"); + tree atype + = build_array_type_nelts (fd->iter_type, fd->ordered - fd->collapse + 1); + counts[fd->ordered] = create_tmp_var (atype, ".orditera"); + TREE_ADDRESSABLE (counts[fd->ordered]) = 1; + + for (inner = region->inner; inner; inner = inner->next) + if (inner->type == GIMPLE_OMP_ORDERED) + { + gomp_ordered *ord_stmt = inner->ord_stmt; + gimple_stmt_iterator gsi = gsi_for_stmt (ord_stmt); + location_t loc = gimple_location (ord_stmt); + tree c; + for (c = gimple_omp_ordered_clauses (ord_stmt); + c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SOURCE) + break; + if (c) + expand_omp_ordered_source (&gsi, fd, counts, loc); + for (c = gimple_omp_ordered_clauses (ord_stmt); + c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK) + expand_omp_ordered_sink (&gsi, fd, counts, c, loc); + gsi_remove (&gsi, true); + } +} + +/* Wrap the body into fd->ordered - fd->collapse loops that aren't + collapsed. */ + +static basic_block +expand_omp_for_ordered_loops (struct omp_for_data *fd, tree *counts, + basic_block cont_bb, basic_block body_bb, + bool ordered_lastprivate) +{ + if (fd->ordered == fd->collapse) + return cont_bb; + + if (!cont_bb) + { + gimple_stmt_iterator gsi = gsi_after_labels (body_bb); + for (int i = fd->collapse; i < fd->ordered; i++) + { + tree type = TREE_TYPE (fd->loops[i].v); + tree n1 = fold_convert (type, fd->loops[i].n1); + expand_omp_build_assign (&gsi, fd->loops[i].v, n1); + tree aref = build4 (ARRAY_REF, fd->iter_type, counts[fd->ordered], + size_int (i - fd->collapse + 1), + NULL_TREE, NULL_TREE); + expand_omp_build_assign (&gsi, aref, build_zero_cst (fd->iter_type)); + } + return NULL; + } + + for (int i = fd->ordered - 1; i >= fd->collapse; i--) + { + tree t, type = TREE_TYPE (fd->loops[i].v); + gimple_stmt_iterator gsi = gsi_after_labels (body_bb); + expand_omp_build_assign (&gsi, fd->loops[i].v, + fold_convert (type, fd->loops[i].n1)); + if (counts[i]) + expand_omp_build_assign (&gsi, counts[i], + build_zero_cst (fd->iter_type)); + tree aref = build4 (ARRAY_REF, fd->iter_type, counts[fd->ordered], + size_int (i - fd->collapse + 1), + NULL_TREE, NULL_TREE); + expand_omp_build_assign (&gsi, aref, build_zero_cst (fd->iter_type)); + if (!gsi_end_p (gsi)) + gsi_prev (&gsi); + else + gsi = gsi_last_bb (body_bb); + edge e1 = split_block (body_bb, gsi_stmt (gsi)); + basic_block new_body = e1->dest; + if (body_bb == cont_bb) + cont_bb = new_body; + edge e2 = NULL; + basic_block new_header; + if (EDGE_COUNT (cont_bb->preds) > 0) + { + gsi = gsi_last_bb (cont_bb); + if (POINTER_TYPE_P (type)) + t = fold_build_pointer_plus (fd->loops[i].v, + fold_convert (sizetype, + fd->loops[i].step)); + else + t = fold_build2 (PLUS_EXPR, type, fd->loops[i].v, + fold_convert (type, fd->loops[i].step)); + expand_omp_build_assign (&gsi, fd->loops[i].v, t); + if (counts[i]) + { + t = fold_build2 (PLUS_EXPR, fd->iter_type, counts[i], + build_int_cst (fd->iter_type, 1)); + expand_omp_build_assign (&gsi, counts[i], t); + t = counts[i]; + } + else + { + t = fold_build2 (MINUS_EXPR, TREE_TYPE (fd->loops[i].v), + fd->loops[i].v, fd->loops[i].n1); + t = fold_convert (fd->iter_type, t); + t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, + true, GSI_SAME_STMT); + } + aref = build4 (ARRAY_REF, fd->iter_type, counts[fd->ordered], + size_int (i - fd->collapse + 1), + NULL_TREE, NULL_TREE); + expand_omp_build_assign (&gsi, aref, t); + gsi_prev (&gsi); + e2 = split_block (cont_bb, gsi_stmt (gsi)); + new_header = e2->dest; + } + else + new_header = cont_bb; + gsi = gsi_after_labels (new_header); + tree v = force_gimple_operand_gsi (&gsi, fd->loops[i].v, true, NULL_TREE, + true, GSI_SAME_STMT); + tree n2 + = force_gimple_operand_gsi (&gsi, fold_convert (type, fd->loops[i].n2), + true, NULL_TREE, true, GSI_SAME_STMT); + t = build2 (fd->loops[i].cond_code, boolean_type_node, v, n2); + gsi_insert_before (&gsi, gimple_build_cond_empty (t), GSI_NEW_STMT); + edge e3 = split_block (new_header, gsi_stmt (gsi)); + cont_bb = e3->dest; + remove_edge (e1); + make_edge (body_bb, new_header, EDGE_FALLTHRU); + e3->flags = EDGE_FALSE_VALUE; + e3->probability = REG_BR_PROB_BASE / 8; + e1 = make_edge (new_header, new_body, EDGE_TRUE_VALUE); + e1->probability = REG_BR_PROB_BASE - e3->probability; + + set_immediate_dominator (CDI_DOMINATORS, new_header, body_bb); + set_immediate_dominator (CDI_DOMINATORS, new_body, new_header); + + if (e2) + { + struct loop *loop = alloc_loop (); + loop->header = new_header; + loop->latch = e2->src; + add_loop (loop, body_bb->loop_father); + } + } + + /* If there are any lastprivate clauses and it is possible some loops + might have zero iterations, ensure all the decls are initialized, + otherwise we could crash evaluating C++ class iterators with lastprivate + clauses. */ + bool need_inits = false; + for (int i = fd->collapse; ordered_lastprivate && i < fd->ordered; i++) + if (need_inits) + { + tree type = TREE_TYPE (fd->loops[i].v); + gimple_stmt_iterator gsi = gsi_after_labels (body_bb); + expand_omp_build_assign (&gsi, fd->loops[i].v, + fold_convert (type, fd->loops[i].n1)); + } + else + { + tree type = TREE_TYPE (fd->loops[i].v); + tree this_cond = fold_build2 (fd->loops[i].cond_code, + boolean_type_node, + fold_convert (type, fd->loops[i].n1), + fold_convert (type, fd->loops[i].n2)); + if (!integer_onep (this_cond)) + need_inits = true; + } + + return cont_bb; +} + + +/* A subroutine of expand_omp_for. Generate code for a parallel + loop with any schedule. Given parameters: + + for (V = N1; V cond N2; V += STEP) BODY; + + where COND is "<" or ">", we generate pseudocode + + more = GOMP_loop_foo_start (N1, N2, STEP, CHUNK, &istart0, &iend0); + if (more) goto L0; else goto L3; + L0: + V = istart0; + iend = iend0; + L1: + BODY; + V += STEP; + if (V cond iend) goto L1; else goto L2; + L2: + if (GOMP_loop_foo_next (&istart0, &iend0)) goto L0; else goto L3; + L3: + + If this is a combined omp parallel loop, instead of the call to + GOMP_loop_foo_start, we call GOMP_loop_foo_next. + If this is gimple_omp_for_combined_p loop, then instead of assigning + V and iend in L0 we assign the first two _looptemp_ clause decls of the + inner GIMPLE_OMP_FOR and V += STEP; and + if (V cond iend) goto L1; else goto L2; are removed. + + For collapsed loops, given parameters: + collapse(3) + for (V1 = N11; V1 cond1 N12; V1 += STEP1) + for (V2 = N21; V2 cond2 N22; V2 += STEP2) + for (V3 = N31; V3 cond3 N32; V3 += STEP3) + BODY; + + we generate pseudocode + + if (__builtin_expect (N32 cond3 N31, 0)) goto Z0; + if (cond3 is <) + adj = STEP3 - 1; + else + adj = STEP3 + 1; + count3 = (adj + N32 - N31) / STEP3; + if (__builtin_expect (N22 cond2 N21, 0)) goto Z0; + if (cond2 is <) + adj = STEP2 - 1; + else + adj = STEP2 + 1; count2 = (adj + N22 - N21) / STEP2; if (__builtin_expect (N12 cond1 N11, 0)) goto Z0; if (cond1 is <) @@ -6118,40 +7565,12 @@ expand_omp_for_generic (struct omp_region *region, edge e, ne; tree *counts = NULL; int i; + bool ordered_lastprivate = false; gcc_assert (!broken_loop || !in_combined_parallel); gcc_assert (fd->iter_type == long_integer_type_node || !in_combined_parallel); - type = TREE_TYPE (fd->loop.v); - istart0 = create_tmp_var (fd->iter_type, ".istart0"); - iend0 = create_tmp_var (fd->iter_type, ".iend0"); - TREE_ADDRESSABLE (istart0) = 1; - TREE_ADDRESSABLE (iend0) = 1; - - /* See if we need to bias by LLONG_MIN. */ - if (fd->iter_type == long_long_unsigned_type_node - && TREE_CODE (type) == INTEGER_TYPE - && !TYPE_UNSIGNED (type)) - { - tree n1, n2; - - if (fd->loop.cond_code == LT_EXPR) - { - n1 = fd->loop.n1; - n2 = fold_build2 (PLUS_EXPR, type, fd->loop.n2, fd->loop.step); - } - else - { - n1 = fold_build2 (MINUS_EXPR, type, fd->loop.n2, fd->loop.step); - n2 = fd->loop.n1; - } - if (TREE_CODE (n1) != INTEGER_CST - || TREE_CODE (n2) != INTEGER_CST - || ((tree_int_cst_sgn (n1) < 0) ^ (tree_int_cst_sgn (n2) < 0))) - bias = fold_convert (fd->iter_type, TYPE_MIN_VALUE (type)); - } - entry_bb = region->entry; cont_bb = region->cont; collapse_bb = NULL; @@ -6176,36 +7595,104 @@ expand_omp_for_generic (struct omp_region *region, gsi = gsi_last_bb (entry_bb); gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR); - if (fd->collapse > 1) + if (fd->ordered + && find_omp_clause (gimple_omp_for_clauses (gsi_stmt (gsi)), + OMP_CLAUSE_LASTPRIVATE)) + ordered_lastprivate = false; + if (fd->collapse > 1 || fd->ordered) { - int first_zero_iter = -1; - basic_block zero_iter_bb = NULL, l2_dom_bb = NULL; + int first_zero_iter1 = -1, first_zero_iter2 = -1; + basic_block zero_iter1_bb = NULL, zero_iter2_bb = NULL, l2_dom_bb = NULL; - counts = XALLOCAVEC (tree, fd->collapse); + counts = XALLOCAVEC (tree, fd->ordered ? fd->ordered + 1 : fd->collapse); expand_omp_for_init_counts (fd, &gsi, entry_bb, counts, - zero_iter_bb, first_zero_iter, - l2_dom_bb); + zero_iter1_bb, first_zero_iter1, + zero_iter2_bb, first_zero_iter2, l2_dom_bb); - if (zero_iter_bb) + if (zero_iter1_bb) { /* Some counts[i] vars might be uninitialized if some loop has zero iterations. But the body shouldn't be executed in that case, so just avoid uninit warnings. */ - for (i = first_zero_iter; i < fd->collapse; i++) + for (i = first_zero_iter1; + i < (fd->ordered ? fd->ordered : fd->collapse); i++) if (SSA_VAR_P (counts[i])) TREE_NO_WARNING (counts[i]) = 1; gsi_prev (&gsi); e = split_block (entry_bb, gsi_stmt (gsi)); entry_bb = e->dest; - make_edge (zero_iter_bb, entry_bb, EDGE_FALLTHRU); + make_edge (zero_iter1_bb, entry_bb, EDGE_FALLTHRU); gsi = gsi_last_bb (entry_bb); set_immediate_dominator (CDI_DOMINATORS, entry_bb, get_immediate_dominator (CDI_DOMINATORS, - zero_iter_bb)); + zero_iter1_bb)); + } + if (zero_iter2_bb) + { + /* Some counts[i] vars might be uninitialized if + some loop has zero iterations. But the body shouldn't + be executed in that case, so just avoid uninit warnings. */ + for (i = first_zero_iter2; i < fd->ordered; i++) + if (SSA_VAR_P (counts[i])) + TREE_NO_WARNING (counts[i]) = 1; + if (zero_iter1_bb) + make_edge (zero_iter2_bb, entry_bb, EDGE_FALLTHRU); + else + { + gsi_prev (&gsi); + e = split_block (entry_bb, gsi_stmt (gsi)); + entry_bb = e->dest; + make_edge (zero_iter2_bb, entry_bb, EDGE_FALLTHRU); + gsi = gsi_last_bb (entry_bb); + set_immediate_dominator (CDI_DOMINATORS, entry_bb, + get_immediate_dominator + (CDI_DOMINATORS, zero_iter2_bb)); + } + } + if (fd->collapse == 1) + { + counts[0] = fd->loop.n2; + fd->loop = fd->loops[0]; + } + } + + type = TREE_TYPE (fd->loop.v); + istart0 = create_tmp_var (fd->iter_type, ".istart0"); + iend0 = create_tmp_var (fd->iter_type, ".iend0"); + TREE_ADDRESSABLE (istart0) = 1; + TREE_ADDRESSABLE (iend0) = 1; + + /* See if we need to bias by LLONG_MIN. */ + if (fd->iter_type == long_long_unsigned_type_node + && TREE_CODE (type) == INTEGER_TYPE + && !TYPE_UNSIGNED (type) + && fd->ordered == 0) + { + tree n1, n2; + + if (fd->loop.cond_code == LT_EXPR) + { + n1 = fd->loop.n1; + n2 = fold_build2 (PLUS_EXPR, type, fd->loop.n2, fd->loop.step); } + else + { + n1 = fold_build2 (MINUS_EXPR, type, fd->loop.n2, fd->loop.step); + n2 = fd->loop.n1; + } + if (TREE_CODE (n1) != INTEGER_CST + || TREE_CODE (n2) != INTEGER_CST + || ((tree_int_cst_sgn (n1) < 0) ^ (tree_int_cst_sgn (n2) < 0))) + bias = fold_convert (fd->iter_type, TYPE_MIN_VALUE (type)); } + + gimple_stmt_iterator gsif = gsi; + gsi_prev (&gsif); + + tree arr = NULL_TREE; if (in_combined_parallel) { + gcc_assert (fd->ordered == 0); /* In a combined parallel loop, emit a call to GOMP_loop_foo_next. */ t = build_call_expr (builtin_decl_explicit (next_fn), 2, @@ -6219,47 +7706,95 @@ expand_omp_for_generic (struct omp_region *region, GOMP_loop_foo_start in ENTRY_BB. */ t4 = build_fold_addr_expr (iend0); t3 = build_fold_addr_expr (istart0); - t2 = fold_convert (fd->iter_type, fd->loop.step); - t1 = fd->loop.n2; - t0 = fd->loop.n1; - if (gimple_omp_for_combined_into_p (fd->for_stmt)) - { - tree innerc = find_omp_clause (gimple_omp_for_clauses (fd->for_stmt), - OMP_CLAUSE__LOOPTEMP_); - gcc_assert (innerc); - t0 = OMP_CLAUSE_DECL (innerc); - innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc), - OMP_CLAUSE__LOOPTEMP_); - gcc_assert (innerc); - t1 = OMP_CLAUSE_DECL (innerc); - } - if (POINTER_TYPE_P (TREE_TYPE (t0)) - && TYPE_PRECISION (TREE_TYPE (t0)) - != TYPE_PRECISION (fd->iter_type)) + if (fd->ordered) { - /* Avoid casting pointers to integer of a different size. */ - tree itype = signed_type_for (type); - t1 = fold_convert (fd->iter_type, fold_convert (itype, t1)); - t0 = fold_convert (fd->iter_type, fold_convert (itype, t0)); + t0 = build_int_cst (unsigned_type_node, + fd->ordered - fd->collapse + 1); + arr = create_tmp_var (build_array_type_nelts (fd->iter_type, + fd->ordered + - fd->collapse + 1), + ".omp_counts"); + DECL_NAMELESS (arr) = 1; + TREE_ADDRESSABLE (arr) = 1; + TREE_STATIC (arr) = 1; + vec *v; + vec_alloc (v, fd->ordered - fd->collapse + 1); + int idx; + + for (idx = 0; idx < fd->ordered - fd->collapse + 1; idx++) + { + tree c; + if (idx == 0 && fd->collapse > 1) + c = fd->loop.n2; + else + c = counts[idx + fd->collapse - 1]; + tree purpose = size_int (idx); + CONSTRUCTOR_APPEND_ELT (v, purpose, c); + if (TREE_CODE (c) != INTEGER_CST) + TREE_STATIC (arr) = 0; + } + + DECL_INITIAL (arr) = build_constructor (TREE_TYPE (arr), v); + if (!TREE_STATIC (arr)) + force_gimple_operand_gsi (&gsi, build1 (DECL_EXPR, + void_type_node, arr), + true, NULL_TREE, true, GSI_SAME_STMT); + t1 = build_fold_addr_expr (arr); + t2 = NULL_TREE; } else { - t1 = fold_convert (fd->iter_type, t1); - t0 = fold_convert (fd->iter_type, t0); - } - if (bias) - { - t1 = fold_build2 (PLUS_EXPR, fd->iter_type, t1, bias); - t0 = fold_build2 (PLUS_EXPR, fd->iter_type, t0, bias); + t2 = fold_convert (fd->iter_type, fd->loop.step); + t1 = fd->loop.n2; + t0 = fd->loop.n1; + if (gimple_omp_for_combined_into_p (fd->for_stmt)) + { + tree innerc + = find_omp_clause (gimple_omp_for_clauses (fd->for_stmt), + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + t0 = OMP_CLAUSE_DECL (innerc); + innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc), + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + t1 = OMP_CLAUSE_DECL (innerc); + } + if (POINTER_TYPE_P (TREE_TYPE (t0)) + && TYPE_PRECISION (TREE_TYPE (t0)) + != TYPE_PRECISION (fd->iter_type)) + { + /* Avoid casting pointers to integer of a different size. */ + tree itype = signed_type_for (type); + t1 = fold_convert (fd->iter_type, fold_convert (itype, t1)); + t0 = fold_convert (fd->iter_type, fold_convert (itype, t0)); + } + else + { + t1 = fold_convert (fd->iter_type, t1); + t0 = fold_convert (fd->iter_type, t0); + } + if (bias) + { + t1 = fold_build2 (PLUS_EXPR, fd->iter_type, t1, bias); + t0 = fold_build2 (PLUS_EXPR, fd->iter_type, t0, bias); + } } - if (fd->iter_type == long_integer_type_node) + if (fd->iter_type == long_integer_type_node || fd->ordered) { if (fd->chunk_size) { t = fold_convert (fd->iter_type, fd->chunk_size); - t = build_call_expr (builtin_decl_explicit (start_fn), - 6, t0, t1, t2, t, t3, t4); + t = omp_adjust_chunk_size (t, fd->simd_schedule); + if (fd->ordered) + t = build_call_expr (builtin_decl_explicit (start_fn), + 5, t0, t1, t, t3, t4); + else + t = build_call_expr (builtin_decl_explicit (start_fn), + 6, t0, t1, t2, t, t3, t4); } + else if (fd->ordered) + t = build_call_expr (builtin_decl_explicit (start_fn), + 4, t0, t1, t3, t4); else t = build_call_expr (builtin_decl_explicit (start_fn), 5, t0, t1, t2, t3, t4); @@ -6282,6 +7817,7 @@ expand_omp_for_generic (struct omp_region *region, { tree bfn_decl = builtin_decl_explicit (start_fn); t = fold_convert (fd->iter_type, fd->chunk_size); + t = omp_adjust_chunk_size (t, fd->simd_schedule); t = build_call_expr (bfn_decl, 7, t5, t0, t1, t2, t, t3, t4); } else @@ -6294,11 +7830,22 @@ expand_omp_for_generic (struct omp_region *region, t, build_int_cst (TREE_TYPE (t), 0)); t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, true, GSI_SAME_STMT); + if (arr && !TREE_STATIC (arr)) + { + tree clobber = build_constructor (TREE_TYPE (arr), NULL); + TREE_THIS_VOLATILE (clobber) = 1; + gsi_insert_before (&gsi, gimple_build_assign (arr, clobber), + GSI_SAME_STMT); + } gsi_insert_after (&gsi, gimple_build_cond_empty (t), GSI_SAME_STMT); /* Remove the GIMPLE_OMP_FOR statement. */ gsi_remove (&gsi, true); + if (gsi_end_p (gsif)) + gsif = gsi_after_labels (gsi_bb (gsif)); + gsi_next (&gsif); + /* Iteration setup for sequential loop goes in L0_BB. */ tree startvar = fd->loop.v; tree endvar = NULL_TREE; @@ -6320,11 +7867,29 @@ expand_omp_for_generic (struct omp_region *region, gsi = gsi_start_bb (l0_bb); t = istart0; - if (bias) + if (fd->ordered && fd->collapse == 1) + t = fold_build2 (MULT_EXPR, fd->iter_type, t, + fold_convert (fd->iter_type, fd->loop.step)); + else if (bias) t = fold_build2 (MINUS_EXPR, fd->iter_type, t, bias); - if (POINTER_TYPE_P (TREE_TYPE (startvar))) - t = fold_convert (signed_type_for (TREE_TYPE (startvar)), t); - t = fold_convert (TREE_TYPE (startvar), t); + if (fd->ordered && fd->collapse == 1) + { + if (POINTER_TYPE_P (TREE_TYPE (startvar))) + t = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (startvar), + fd->loop.n1, fold_convert (sizetype, t)); + else + { + t = fold_convert (TREE_TYPE (startvar), t); + t = fold_build2 (PLUS_EXPR, TREE_TYPE (startvar), + fd->loop.n1, t); + } + } + else + { + if (POINTER_TYPE_P (TREE_TYPE (startvar))) + t = fold_convert (signed_type_for (TREE_TYPE (startvar)), t); + t = fold_convert (TREE_TYPE (startvar), t); + } t = force_gimple_operand_gsi (&gsi, t, DECL_P (startvar) && TREE_ADDRESSABLE (startvar), @@ -6333,16 +7898,34 @@ expand_omp_for_generic (struct omp_region *region, gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING); t = iend0; - if (bias) + if (fd->ordered && fd->collapse == 1) + t = fold_build2 (MULT_EXPR, fd->iter_type, t, + fold_convert (fd->iter_type, fd->loop.step)); + else if (bias) t = fold_build2 (MINUS_EXPR, fd->iter_type, t, bias); - if (POINTER_TYPE_P (TREE_TYPE (startvar))) - t = fold_convert (signed_type_for (TREE_TYPE (startvar)), t); - t = fold_convert (TREE_TYPE (startvar), t); - iend = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, - false, GSI_CONTINUE_LINKING); - if (endvar) + if (fd->ordered && fd->collapse == 1) { - assign_stmt = gimple_build_assign (endvar, iend); + if (POINTER_TYPE_P (TREE_TYPE (startvar))) + t = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (startvar), + fd->loop.n1, fold_convert (sizetype, t)); + else + { + t = fold_convert (TREE_TYPE (startvar), t); + t = fold_build2 (PLUS_EXPR, TREE_TYPE (startvar), + fd->loop.n1, t); + } + } + else + { + if (POINTER_TYPE_P (TREE_TYPE (startvar))) + t = fold_convert (signed_type_for (TREE_TYPE (startvar)), t); + t = fold_convert (TREE_TYPE (startvar), t); + } + iend = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, + false, GSI_CONTINUE_LINKING); + if (endvar) + { + assign_stmt = gimple_build_assign (endvar, iend); gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING); if (useless_type_conversion_p (TREE_TYPE (fd->loop.v), TREE_TYPE (iend))) assign_stmt = gimple_build_assign (fd->loop.v, iend); @@ -6350,9 +7933,130 @@ expand_omp_for_generic (struct omp_region *region, assign_stmt = gimple_build_assign (fd->loop.v, NOP_EXPR, iend); gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING); } + /* Handle linear clause adjustments. */ + tree itercnt = NULL_TREE; + if (gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_FOR) + for (tree c = gimple_omp_for_clauses (fd->for_stmt); + c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR + && !OMP_CLAUSE_LINEAR_NO_COPYIN (c)) + { + tree d = OMP_CLAUSE_DECL (c); + bool is_ref = is_reference (d); + tree t = d, a, dest; + if (is_ref) + t = build_simple_mem_ref_loc (OMP_CLAUSE_LOCATION (c), t); + tree type = TREE_TYPE (t); + if (POINTER_TYPE_P (type)) + type = sizetype; + dest = unshare_expr (t); + tree v = create_tmp_var (TREE_TYPE (t), NULL); + expand_omp_build_assign (&gsif, v, t); + if (itercnt == NULL_TREE) + { + itercnt = startvar; + tree n1 = fd->loop.n1; + if (POINTER_TYPE_P (TREE_TYPE (itercnt))) + { + itercnt + = fold_convert (signed_type_for (TREE_TYPE (itercnt)), + itercnt); + n1 = fold_convert (TREE_TYPE (itercnt), n1); + } + itercnt = fold_build2 (MINUS_EXPR, TREE_TYPE (itercnt), + itercnt, n1); + itercnt = fold_build2 (EXACT_DIV_EXPR, TREE_TYPE (itercnt), + itercnt, fd->loop.step); + itercnt = force_gimple_operand_gsi (&gsi, itercnt, true, + NULL_TREE, false, + GSI_CONTINUE_LINKING); + } + a = fold_build2 (MULT_EXPR, type, + fold_convert (type, itercnt), + fold_convert (type, OMP_CLAUSE_LINEAR_STEP (c))); + t = fold_build2 (type == TREE_TYPE (t) ? PLUS_EXPR + : POINTER_PLUS_EXPR, TREE_TYPE (t), v, a); + t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, + false, GSI_CONTINUE_LINKING); + assign_stmt = gimple_build_assign (dest, t); + gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING); + } if (fd->collapse > 1) expand_omp_for_init_vars (fd, &gsi, counts, inner_stmt, startvar); + if (fd->ordered) + { + /* Until now, counts array contained number of iterations or + variable containing it for ith loop. From now on, we need + those counts only for collapsed loops, and only for the 2nd + till the last collapsed one. Move those one element earlier, + we'll use counts[fd->collapse - 1] for the first source/sink + iteration counter and so on and counts[fd->ordered] + as the array holding the current counter values for + depend(source). */ + if (fd->collapse > 1) + memmove (counts, counts + 1, (fd->collapse - 1) * sizeof (counts[0])); + if (broken_loop) + { + int i; + for (i = fd->collapse; i < fd->ordered; i++) + { + tree type = TREE_TYPE (fd->loops[i].v); + tree this_cond + = fold_build2 (fd->loops[i].cond_code, boolean_type_node, + fold_convert (type, fd->loops[i].n1), + fold_convert (type, fd->loops[i].n2)); + if (!integer_onep (this_cond)) + break; + } + if (i < fd->ordered) + { + cont_bb + = create_empty_bb (EXIT_BLOCK_PTR_FOR_FN (cfun)->prev_bb); + add_bb_to_loop (cont_bb, l1_bb->loop_father); + gimple_stmt_iterator gsi = gsi_after_labels (cont_bb); + gimple *g = gimple_build_omp_continue (fd->loop.v, fd->loop.v); + gsi_insert_before (&gsi, g, GSI_SAME_STMT); + make_edge (cont_bb, l3_bb, EDGE_FALLTHRU); + make_edge (cont_bb, l1_bb, 0); + l2_bb = create_empty_bb (cont_bb); + broken_loop = false; + } + } + expand_omp_ordered_source_sink (region, fd, counts, cont_bb); + cont_bb = expand_omp_for_ordered_loops (fd, counts, cont_bb, l1_bb, + ordered_lastprivate); + if (counts[fd->collapse - 1]) + { + gcc_assert (fd->collapse == 1); + gsi = gsi_last_bb (l0_bb); + expand_omp_build_assign (&gsi, counts[fd->collapse - 1], + istart0, true); + gsi = gsi_last_bb (cont_bb); + t = fold_build2 (PLUS_EXPR, fd->iter_type, counts[fd->collapse - 1], + build_int_cst (fd->iter_type, 1)); + expand_omp_build_assign (&gsi, counts[fd->collapse - 1], t); + tree aref = build4 (ARRAY_REF, fd->iter_type, counts[fd->ordered], + size_zero_node, NULL_TREE, NULL_TREE); + expand_omp_build_assign (&gsi, aref, counts[fd->collapse - 1]); + t = counts[fd->collapse - 1]; + } + else if (fd->collapse > 1) + t = fd->loop.v; + else + { + t = fold_build2 (MINUS_EXPR, TREE_TYPE (fd->loops[0].v), + fd->loops[0].v, fd->loops[0].n1); + t = fold_convert (fd->iter_type, t); + } + gsi = gsi_last_bb (l0_bb); + tree aref = build4 (ARRAY_REF, fd->iter_type, counts[fd->ordered], + size_zero_node, NULL_TREE, NULL_TREE); + t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, + false, GSI_CONTINUE_LINKING); + expand_omp_build_assign (&gsi, aref, t, true); + } + if (!broken_loop) { /* Code to control the increment and predicate for the sequential @@ -6376,6 +8080,24 @@ expand_omp_for_generic (struct omp_region *region, assign_stmt = gimple_build_assign (vback, t); gsi_insert_before (&gsi, assign_stmt, GSI_SAME_STMT); + if (fd->ordered && counts[fd->collapse - 1] == NULL_TREE) + { + if (fd->collapse > 1) + t = fd->loop.v; + else + { + t = fold_build2 (MINUS_EXPR, TREE_TYPE (fd->loops[0].v), + fd->loops[0].v, fd->loops[0].n1); + t = fold_convert (fd->iter_type, t); + } + tree aref = build4 (ARRAY_REF, fd->iter_type, + counts[fd->ordered], size_zero_node, + NULL_TREE, NULL_TREE); + t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, + true, GSI_SAME_STMT); + expand_omp_build_assign (&gsi, aref, t); + } + t = build2 (fd->loop.cond_code, boolean_type_node, DECL_P (vback) && TREE_ADDRESSABLE (vback) ? t : vback, iend); @@ -6416,6 +8138,14 @@ expand_omp_for_generic (struct omp_region *region, if (gimple_omp_return_lhs (gsi_stmt (gsi))) gimple_call_set_lhs (call_stmt, gimple_omp_return_lhs (gsi_stmt (gsi))); gsi_insert_after (&gsi, call_stmt, GSI_SAME_STMT); + if (fd->ordered) + { + tree arr = counts[fd->ordered]; + tree clobber = build_constructor (TREE_TYPE (arr), NULL); + TREE_THIS_VOLATILE (clobber) = 1; + gsi_insert_after (&gsi, gimple_build_assign (arr, clobber), + GSI_SAME_STMT); + } gsi_remove (&gsi, true); /* Connect the new blocks. */ @@ -6627,13 +8357,13 @@ expand_omp_for_static_nochunk (struct omp_region *region, if (fd->collapse > 1) { - int first_zero_iter = -1; - basic_block l2_dom_bb = NULL; + int first_zero_iter = -1, dummy = -1; + basic_block l2_dom_bb = NULL, dummy_bb = NULL; counts = XALLOCAVEC (tree, fd->collapse); expand_omp_for_init_counts (fd, &gsi, entry_bb, counts, fin_bb, first_zero_iter, - l2_dom_bb); + dummy_bb, dummy, l2_dom_bb); t = NULL_TREE; } else if (gimple_omp_for_combined_into_p (fd->for_stmt)) @@ -6836,6 +8566,49 @@ expand_omp_for_static_nochunk (struct omp_region *region, assign_stmt = gimple_build_assign (fd->loop.v, NOP_EXPR, e); gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING); } + /* Handle linear clause adjustments. */ + tree itercnt = NULL_TREE; + if (gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_FOR) + for (tree c = gimple_omp_for_clauses (fd->for_stmt); + c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR + && !OMP_CLAUSE_LINEAR_NO_COPYIN (c)) + { + tree d = OMP_CLAUSE_DECL (c); + bool is_ref = is_reference (d); + tree t = d, a, dest; + if (is_ref) + t = build_simple_mem_ref_loc (OMP_CLAUSE_LOCATION (c), t); + if (itercnt == NULL_TREE) + { + if (gimple_omp_for_combined_into_p (fd->for_stmt)) + { + itercnt = fold_build2 (MINUS_EXPR, itype, + fold_convert (itype, n1), + fold_convert (itype, fd->loop.n1)); + itercnt = fold_build2 (EXACT_DIV_EXPR, itype, itercnt, step); + itercnt = fold_build2 (PLUS_EXPR, itype, itercnt, s0); + itercnt = force_gimple_operand_gsi (&gsi, itercnt, true, + NULL_TREE, false, + GSI_CONTINUE_LINKING); + } + else + itercnt = s0; + } + tree type = TREE_TYPE (t); + if (POINTER_TYPE_P (type)) + type = sizetype; + a = fold_build2 (MULT_EXPR, type, + fold_convert (type, itercnt), + fold_convert (type, OMP_CLAUSE_LINEAR_STEP (c))); + dest = unshare_expr (t); + t = fold_build2 (type == TREE_TYPE (t) ? PLUS_EXPR + : POINTER_PLUS_EXPR, TREE_TYPE (t), t, a); + t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, + false, GSI_CONTINUE_LINKING); + assign_stmt = gimple_build_assign (dest, t); + gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING); + } if (fd->collapse > 1) expand_omp_for_init_vars (fd, &gsi, counts, inner_stmt, startvar); @@ -7055,13 +8828,13 @@ expand_omp_for_static_chunk (struct omp_region *region, if (fd->collapse > 1) { - int first_zero_iter = -1; - basic_block l2_dom_bb = NULL; + int first_zero_iter = -1, dummy = -1; + basic_block l2_dom_bb = NULL, dummy_bb = NULL; counts = XALLOCAVEC (tree, fd->collapse); expand_omp_for_init_counts (fd, &gsi, entry_bb, counts, fin_bb, first_zero_iter, - l2_dom_bb); + dummy_bb, dummy, l2_dom_bb); t = NULL_TREE; } else if (gimple_omp_for_combined_into_p (fd->for_stmt)) @@ -7157,9 +8930,11 @@ expand_omp_for_static_chunk (struct omp_region *region, true, NULL_TREE, true, GSI_SAME_STMT); step = force_gimple_operand_gsi (&gsi, fold_convert (itype, step), true, NULL_TREE, true, GSI_SAME_STMT); - fd->chunk_size - = force_gimple_operand_gsi (&gsi, fold_convert (itype, fd->chunk_size), - true, NULL_TREE, true, GSI_SAME_STMT); + tree chunk_size = fold_convert (itype, fd->chunk_size); + chunk_size = omp_adjust_chunk_size (chunk_size, fd->simd_schedule); + chunk_size + = force_gimple_operand_gsi (&gsi, chunk_size, true, NULL_TREE, true, + GSI_SAME_STMT); t = build_int_cst (itype, (fd->loop.cond_code == LT_EXPR ? -1 : 1)); t = fold_build2 (PLUS_EXPR, itype, step, t); @@ -7193,7 +8968,7 @@ expand_omp_for_static_chunk (struct omp_region *region, = gimple_build_assign (trip_init, build_int_cst (itype, 0)); gsi_insert_before (&gsi, assign_stmt, GSI_SAME_STMT); - t = fold_build2 (MULT_EXPR, itype, threadid, fd->chunk_size); + t = fold_build2 (MULT_EXPR, itype, threadid, chunk_size); t = fold_build2 (MULT_EXPR, itype, t, step); if (POINTER_TYPE_P (type)) t = fold_build_pointer_plus (n1, t); @@ -7205,16 +8980,18 @@ expand_omp_for_static_chunk (struct omp_region *region, /* Remove the GIMPLE_OMP_FOR. */ gsi_remove (&gsi, true); + gimple_stmt_iterator gsif = gsi; + /* Iteration space partitioning goes in ITER_PART_BB. */ gsi = gsi_last_bb (iter_part_bb); t = fold_build2 (MULT_EXPR, itype, trip_main, nthreads); t = fold_build2 (PLUS_EXPR, itype, t, threadid); - t = fold_build2 (MULT_EXPR, itype, t, fd->chunk_size); + t = fold_build2 (MULT_EXPR, itype, t, chunk_size); s0 = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, false, GSI_CONTINUE_LINKING); - t = fold_build2 (PLUS_EXPR, itype, s0, fd->chunk_size); + t = fold_build2 (PLUS_EXPR, itype, s0, chunk_size); t = fold_build2 (MIN_EXPR, itype, t, n); e0 = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, false, GSI_CONTINUE_LINKING); @@ -7275,6 +9052,56 @@ expand_omp_for_static_chunk (struct omp_region *region, assign_stmt = gimple_build_assign (fd->loop.v, NOP_EXPR, e); gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING); } + /* Handle linear clause adjustments. */ + tree itercnt = NULL_TREE, itercntbias = NULL_TREE; + if (gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_FOR) + for (tree c = gimple_omp_for_clauses (fd->for_stmt); + c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR + && !OMP_CLAUSE_LINEAR_NO_COPYIN (c)) + { + tree d = OMP_CLAUSE_DECL (c); + bool is_ref = is_reference (d); + tree t = d, a, dest; + if (is_ref) + t = build_simple_mem_ref_loc (OMP_CLAUSE_LOCATION (c), t); + tree type = TREE_TYPE (t); + if (POINTER_TYPE_P (type)) + type = sizetype; + dest = unshare_expr (t); + tree v = create_tmp_var (TREE_TYPE (t), NULL); + expand_omp_build_assign (&gsif, v, t); + if (itercnt == NULL_TREE) + { + if (gimple_omp_for_combined_into_p (fd->for_stmt)) + { + itercntbias + = fold_build2 (MINUS_EXPR, itype, fold_convert (itype, n1), + fold_convert (itype, fd->loop.n1)); + itercntbias = fold_build2 (EXACT_DIV_EXPR, itype, + itercntbias, step); + itercntbias + = force_gimple_operand_gsi (&gsif, itercntbias, true, + NULL_TREE, true, + GSI_SAME_STMT); + itercnt = fold_build2 (PLUS_EXPR, itype, itercntbias, s0); + itercnt = force_gimple_operand_gsi (&gsi, itercnt, true, + NULL_TREE, false, + GSI_CONTINUE_LINKING); + } + else + itercnt = s0; + } + a = fold_build2 (MULT_EXPR, type, + fold_convert (type, itercnt), + fold_convert (type, OMP_CLAUSE_LINEAR_STEP (c))); + t = fold_build2 (type == TREE_TYPE (t) ? PLUS_EXPR + : POINTER_PLUS_EXPR, TREE_TYPE (t), v, a); + t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, + false, GSI_CONTINUE_LINKING); + assign_stmt = gimple_build_assign (dest, t); + gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING); + } if (fd->collapse > 1) expand_omp_for_init_vars (fd, &gsi, counts, inner_stmt, startvar); @@ -7780,13 +9607,13 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) gcc_assert (!gimple_in_ssa_p (cfun)); if (fd->collapse > 1) { - int first_zero_iter = -1; - basic_block zero_iter_bb = l2_bb; + int first_zero_iter = -1, dummy = -1; + basic_block zero_iter_bb = l2_bb, dummy_bb = NULL; counts = XALLOCAVEC (tree, fd->collapse); expand_omp_for_init_counts (fd, &gsi, entry_bb, counts, zero_iter_bb, first_zero_iter, - l2_dom_bb); + dummy_bb, dummy, l2_dom_bb); } if (l2_dom_bb == NULL) l2_dom_bb = l1_bb; @@ -7898,7 +9725,11 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) t = fold_convert (type, n2); t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, false, GSI_CONTINUE_LINKING); - t = build2 (fd->loop.cond_code, boolean_type_node, fd->loop.v, t); + tree v = fd->loop.v; + if (DECL_P (v) && TREE_ADDRESSABLE (v)) + v = force_gimple_operand_gsi (&gsi, v, true, NULL_TREE, + false, GSI_CONTINUE_LINKING); + t = build2 (fd->loop.cond_code, boolean_type_node, v, t); cond_stmt = gimple_build_cond_empty (t); gsi_insert_after (&gsi, cond_stmt, GSI_CONTINUE_LINKING); if (walk_tree (gimple_cond_lhs_ptr (cond_stmt), expand_omp_regimplify_p, @@ -7965,25 +9796,419 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) } if (simduid) { - loop->simduid = OMP_CLAUSE__SIMDUID__DECL (simduid); - cfun->has_simduid_loops = true; + loop->simduid = OMP_CLAUSE__SIMDUID__DECL (simduid); + cfun->has_simduid_loops = true; + } + /* If not -fno-tree-loop-vectorize, hint that we want to vectorize + the loop. */ + if ((flag_tree_loop_vectorize + || (!global_options_set.x_flag_tree_loop_vectorize + && !global_options_set.x_flag_tree_vectorize)) + && flag_tree_loop_optimize + && loop->safelen > 1) + { + loop->force_vectorize = true; + cfun->has_force_vectorize_loops = true; + } + } + else if (simduid) + cfun->has_simduid_loops = true; +} + +/* Taskloop construct is represented after gimplification with + two GIMPLE_OMP_FOR constructs with GIMPLE_OMP_TASK sandwiched + in between them. This routine expands the outer GIMPLE_OMP_FOR, + which should just compute all the needed loop temporaries + for GIMPLE_OMP_TASK. */ + +static void +expand_omp_taskloop_for_outer (struct omp_region *region, + struct omp_for_data *fd, + gimple *inner_stmt) +{ + tree type, bias = NULL_TREE; + basic_block entry_bb, cont_bb, exit_bb; + gimple_stmt_iterator gsi; + gassign *assign_stmt; + tree *counts = NULL; + int i; + + gcc_assert (inner_stmt); + gcc_assert (region->cont); + gcc_assert (gimple_code (inner_stmt) == GIMPLE_OMP_TASK + && gimple_omp_task_taskloop_p (inner_stmt)); + type = TREE_TYPE (fd->loop.v); + + /* See if we need to bias by LLONG_MIN. */ + if (fd->iter_type == long_long_unsigned_type_node + && TREE_CODE (type) == INTEGER_TYPE + && !TYPE_UNSIGNED (type)) + { + tree n1, n2; + + if (fd->loop.cond_code == LT_EXPR) + { + n1 = fd->loop.n1; + n2 = fold_build2 (PLUS_EXPR, type, fd->loop.n2, fd->loop.step); + } + else + { + n1 = fold_build2 (MINUS_EXPR, type, fd->loop.n2, fd->loop.step); + n2 = fd->loop.n1; + } + if (TREE_CODE (n1) != INTEGER_CST + || TREE_CODE (n2) != INTEGER_CST + || ((tree_int_cst_sgn (n1) < 0) ^ (tree_int_cst_sgn (n2) < 0))) + bias = fold_convert (fd->iter_type, TYPE_MIN_VALUE (type)); + } + + entry_bb = region->entry; + cont_bb = region->cont; + gcc_assert (EDGE_COUNT (entry_bb->succs) == 2); + gcc_assert (BRANCH_EDGE (entry_bb)->dest == FALLTHRU_EDGE (cont_bb)->dest); + exit_bb = region->exit; + + gsi = gsi_last_bb (entry_bb); + gimple *for_stmt = gsi_stmt (gsi); + gcc_assert (gimple_code (for_stmt) == GIMPLE_OMP_FOR); + if (fd->collapse > 1) + { + int first_zero_iter = -1, dummy = -1; + basic_block zero_iter_bb = NULL, dummy_bb = NULL, l2_dom_bb = NULL; + + counts = XALLOCAVEC (tree, fd->collapse); + expand_omp_for_init_counts (fd, &gsi, entry_bb, counts, + zero_iter_bb, first_zero_iter, + dummy_bb, dummy, l2_dom_bb); + + if (zero_iter_bb) + { + /* Some counts[i] vars might be uninitialized if + some loop has zero iterations. But the body shouldn't + be executed in that case, so just avoid uninit warnings. */ + for (i = first_zero_iter; i < fd->collapse; i++) + if (SSA_VAR_P (counts[i])) + TREE_NO_WARNING (counts[i]) = 1; + gsi_prev (&gsi); + edge e = split_block (entry_bb, gsi_stmt (gsi)); + entry_bb = e->dest; + make_edge (zero_iter_bb, entry_bb, EDGE_FALLTHRU); + gsi = gsi_last_bb (entry_bb); + set_immediate_dominator (CDI_DOMINATORS, entry_bb, + get_immediate_dominator (CDI_DOMINATORS, + zero_iter_bb)); + } + } + + tree t0, t1; + t1 = fd->loop.n2; + t0 = fd->loop.n1; + if (POINTER_TYPE_P (TREE_TYPE (t0)) + && TYPE_PRECISION (TREE_TYPE (t0)) + != TYPE_PRECISION (fd->iter_type)) + { + /* Avoid casting pointers to integer of a different size. */ + tree itype = signed_type_for (type); + t1 = fold_convert (fd->iter_type, fold_convert (itype, t1)); + t0 = fold_convert (fd->iter_type, fold_convert (itype, t0)); + } + else + { + t1 = fold_convert (fd->iter_type, t1); + t0 = fold_convert (fd->iter_type, t0); + } + if (bias) + { + t1 = fold_build2 (PLUS_EXPR, fd->iter_type, t1, bias); + t0 = fold_build2 (PLUS_EXPR, fd->iter_type, t0, bias); + } + + tree innerc = find_omp_clause (gimple_omp_task_clauses (inner_stmt), + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + tree startvar = OMP_CLAUSE_DECL (innerc); + innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc), OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + tree endvar = OMP_CLAUSE_DECL (innerc); + if (fd->collapse > 1 && TREE_CODE (fd->loop.n2) != INTEGER_CST) + { + gcc_assert (innerc); + for (i = 1; i < fd->collapse; i++) + { + innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc), + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + } + innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc), + OMP_CLAUSE__LOOPTEMP_); + if (innerc) + { + /* If needed (inner taskloop has lastprivate clause), propagate + down the total number of iterations. */ + tree t = force_gimple_operand_gsi (&gsi, fd->loop.n2, false, + NULL_TREE, false, + GSI_CONTINUE_LINKING); + assign_stmt = gimple_build_assign (OMP_CLAUSE_DECL (innerc), t); + gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING); + } + } + + t0 = force_gimple_operand_gsi (&gsi, t0, false, NULL_TREE, false, + GSI_CONTINUE_LINKING); + assign_stmt = gimple_build_assign (startvar, t0); + gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING); + + t1 = force_gimple_operand_gsi (&gsi, t1, false, NULL_TREE, false, + GSI_CONTINUE_LINKING); + assign_stmt = gimple_build_assign (endvar, t1); + gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING); + if (fd->collapse > 1) + expand_omp_for_init_vars (fd, &gsi, counts, inner_stmt, startvar); + + /* Remove the GIMPLE_OMP_FOR statement. */ + gsi = gsi_for_stmt (for_stmt); + gsi_remove (&gsi, true); + + gsi = gsi_last_bb (cont_bb); + gsi_remove (&gsi, true); + + gsi = gsi_last_bb (exit_bb); + gsi_remove (&gsi, true); + + FALLTHRU_EDGE (entry_bb)->probability = REG_BR_PROB_BASE; + remove_edge (BRANCH_EDGE (entry_bb)); + FALLTHRU_EDGE (cont_bb)->probability = REG_BR_PROB_BASE; + remove_edge (BRANCH_EDGE (cont_bb)); + set_immediate_dominator (CDI_DOMINATORS, exit_bb, cont_bb); + set_immediate_dominator (CDI_DOMINATORS, region->entry, + recompute_dominator (CDI_DOMINATORS, region->entry)); +} + +/* Taskloop construct is represented after gimplification with + two GIMPLE_OMP_FOR constructs with GIMPLE_OMP_TASK sandwiched + in between them. This routine expands the inner GIMPLE_OMP_FOR. + GOMP_taskloop{,_ull} function arranges for each task to be given just + a single range of iterations. */ + +static void +expand_omp_taskloop_for_inner (struct omp_region *region, + struct omp_for_data *fd, + gimple *inner_stmt) +{ + tree e, t, type, itype, vmain, vback, bias = NULL_TREE; + basic_block entry_bb, exit_bb, body_bb, cont_bb, collapse_bb = NULL; + basic_block fin_bb; + gimple_stmt_iterator gsi; + edge ep; + bool broken_loop = region->cont == NULL; + tree *counts = NULL; + tree n1, n2, step; + + itype = type = TREE_TYPE (fd->loop.v); + if (POINTER_TYPE_P (type)) + itype = signed_type_for (type); + + /* See if we need to bias by LLONG_MIN. */ + if (fd->iter_type == long_long_unsigned_type_node + && TREE_CODE (type) == INTEGER_TYPE + && !TYPE_UNSIGNED (type)) + { + tree n1, n2; + + if (fd->loop.cond_code == LT_EXPR) + { + n1 = fd->loop.n1; + n2 = fold_build2 (PLUS_EXPR, type, fd->loop.n2, fd->loop.step); + } + else + { + n1 = fold_build2 (MINUS_EXPR, type, fd->loop.n2, fd->loop.step); + n2 = fd->loop.n1; + } + if (TREE_CODE (n1) != INTEGER_CST + || TREE_CODE (n2) != INTEGER_CST + || ((tree_int_cst_sgn (n1) < 0) ^ (tree_int_cst_sgn (n2) < 0))) + bias = fold_convert (fd->iter_type, TYPE_MIN_VALUE (type)); + } + + entry_bb = region->entry; + cont_bb = region->cont; + gcc_assert (EDGE_COUNT (entry_bb->succs) == 2); + fin_bb = BRANCH_EDGE (entry_bb)->dest; + gcc_assert (broken_loop + || (fin_bb == FALLTHRU_EDGE (cont_bb)->dest)); + body_bb = FALLTHRU_EDGE (entry_bb)->dest; + if (!broken_loop) + { + gcc_assert (BRANCH_EDGE (cont_bb)->dest == body_bb); + gcc_assert (EDGE_COUNT (cont_bb->succs) == 2); + } + exit_bb = region->exit; + + /* Iteration space partitioning goes in ENTRY_BB. */ + gsi = gsi_last_bb (entry_bb); + gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR); + + if (fd->collapse > 1) + { + int first_zero_iter = -1, dummy = -1; + basic_block l2_dom_bb = NULL, dummy_bb = NULL; + + counts = XALLOCAVEC (tree, fd->collapse); + expand_omp_for_init_counts (fd, &gsi, entry_bb, counts, + fin_bb, first_zero_iter, + dummy_bb, dummy, l2_dom_bb); + t = NULL_TREE; + } + else + t = integer_one_node; + + step = fd->loop.step; + tree innerc = find_omp_clause (gimple_omp_for_clauses (fd->for_stmt), + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + n1 = OMP_CLAUSE_DECL (innerc); + innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc), OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + n2 = OMP_CLAUSE_DECL (innerc); + if (bias) + { + n1 = fold_build2 (PLUS_EXPR, fd->iter_type, n1, bias); + n2 = fold_build2 (PLUS_EXPR, fd->iter_type, n2, bias); + } + n1 = force_gimple_operand_gsi (&gsi, fold_convert (type, n1), + true, NULL_TREE, true, GSI_SAME_STMT); + n2 = force_gimple_operand_gsi (&gsi, fold_convert (itype, n2), + true, NULL_TREE, true, GSI_SAME_STMT); + step = force_gimple_operand_gsi (&gsi, fold_convert (itype, step), + true, NULL_TREE, true, GSI_SAME_STMT); + + tree startvar = fd->loop.v; + tree endvar = NULL_TREE; + + if (gimple_omp_for_combined_p (fd->for_stmt)) + { + tree clauses = gimple_omp_for_clauses (inner_stmt); + tree innerc = find_omp_clause (clauses, OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + startvar = OMP_CLAUSE_DECL (innerc); + innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc), + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + endvar = OMP_CLAUSE_DECL (innerc); + } + t = fold_convert (TREE_TYPE (startvar), n1); + t = force_gimple_operand_gsi (&gsi, t, + DECL_P (startvar) + && TREE_ADDRESSABLE (startvar), + NULL_TREE, false, GSI_CONTINUE_LINKING); + gimple *assign_stmt = gimple_build_assign (startvar, t); + gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING); + + t = fold_convert (TREE_TYPE (startvar), n2); + e = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, + false, GSI_CONTINUE_LINKING); + if (endvar) + { + assign_stmt = gimple_build_assign (endvar, e); + gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING); + if (useless_type_conversion_p (TREE_TYPE (fd->loop.v), TREE_TYPE (e))) + assign_stmt = gimple_build_assign (fd->loop.v, e); + else + assign_stmt = gimple_build_assign (fd->loop.v, NOP_EXPR, e); + gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING); + } + if (fd->collapse > 1) + expand_omp_for_init_vars (fd, &gsi, counts, inner_stmt, startvar); + + if (!broken_loop) + { + /* The code controlling the sequential loop replaces the + GIMPLE_OMP_CONTINUE. */ + gsi = gsi_last_bb (cont_bb); + gomp_continue *cont_stmt = as_a (gsi_stmt (gsi)); + gcc_assert (gimple_code (cont_stmt) == GIMPLE_OMP_CONTINUE); + vmain = gimple_omp_continue_control_use (cont_stmt); + vback = gimple_omp_continue_control_def (cont_stmt); + + if (!gimple_omp_for_combined_p (fd->for_stmt)) + { + if (POINTER_TYPE_P (type)) + t = fold_build_pointer_plus (vmain, step); + else + t = fold_build2 (PLUS_EXPR, type, vmain, step); + t = force_gimple_operand_gsi (&gsi, t, + DECL_P (vback) + && TREE_ADDRESSABLE (vback), + NULL_TREE, true, GSI_SAME_STMT); + assign_stmt = gimple_build_assign (vback, t); + gsi_insert_before (&gsi, assign_stmt, GSI_SAME_STMT); + + t = build2 (fd->loop.cond_code, boolean_type_node, + DECL_P (vback) && TREE_ADDRESSABLE (vback) + ? t : vback, e); + gsi_insert_before (&gsi, gimple_build_cond_empty (t), GSI_SAME_STMT); + } + + /* Remove the GIMPLE_OMP_CONTINUE statement. */ + gsi_remove (&gsi, true); + + if (fd->collapse > 1 && !gimple_omp_for_combined_p (fd->for_stmt)) + collapse_bb = extract_omp_for_update_vars (fd, cont_bb, body_bb); + } + + /* Remove the GIMPLE_OMP_FOR statement. */ + gsi = gsi_for_stmt (fd->for_stmt); + gsi_remove (&gsi, true); + + /* Remove the GIMPLE_OMP_RETURN statement. */ + gsi = gsi_last_bb (exit_bb); + gsi_remove (&gsi, true); + + FALLTHRU_EDGE (entry_bb)->probability = REG_BR_PROB_BASE; + if (!broken_loop) + remove_edge (BRANCH_EDGE (entry_bb)); + else + { + remove_edge_and_dominated_blocks (BRANCH_EDGE (entry_bb)); + region->outer->cont = NULL; + } + + /* Connect all the blocks. */ + if (!broken_loop) + { + ep = find_edge (cont_bb, body_bb); + if (gimple_omp_for_combined_p (fd->for_stmt)) + { + remove_edge (ep); + ep = NULL; } - /* If not -fno-tree-loop-vectorize, hint that we want to vectorize - the loop. */ - if ((flag_tree_loop_vectorize - || (!global_options_set.x_flag_tree_loop_vectorize - && !global_options_set.x_flag_tree_vectorize)) - && flag_tree_loop_optimize - && loop->safelen > 1) + else if (fd->collapse > 1) { - loop->force_vectorize = true; - cfun->has_force_vectorize_loops = true; + remove_edge (ep); + ep = make_edge (cont_bb, collapse_bb, EDGE_TRUE_VALUE); } + else + ep->flags = EDGE_TRUE_VALUE; + find_edge (cont_bb, fin_bb)->flags + = ep ? EDGE_FALSE_VALUE : EDGE_FALLTHRU; } - else if (simduid) - cfun->has_simduid_loops = true; -} + set_immediate_dominator (CDI_DOMINATORS, body_bb, + recompute_dominator (CDI_DOMINATORS, body_bb)); + if (!broken_loop) + set_immediate_dominator (CDI_DOMINATORS, fin_bb, + recompute_dominator (CDI_DOMINATORS, fin_bb)); + + if (!broken_loop && !gimple_omp_for_combined_p (fd->for_stmt)) + { + struct loop *loop = alloc_loop (); + loop->header = body_bb; + if (collapse_bb == NULL) + loop->latch = cont_bb; + add_loop (loop, body_bb->loop_father); + } +} /* Expand the OMP loop defined by REGION. */ @@ -8020,6 +10245,13 @@ expand_omp_for (struct omp_region *region, gimple *inner_stmt) expand_omp_simd (region, &fd); else if (gimple_omp_for_kind (fd.for_stmt) == GF_OMP_FOR_KIND_CILKFOR) expand_cilk_for (region, &fd); + else if (gimple_omp_for_kind (fd.for_stmt) == GF_OMP_FOR_KIND_TASKLOOP) + { + if (gimple_omp_for_combined_into_p (fd.for_stmt)) + expand_omp_taskloop_for_inner (region, &fd, inner_stmt); + else + expand_omp_taskloop_for_outer (region, &fd, inner_stmt); + } else if (fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC && !fd.have_ordered) { @@ -8040,8 +10272,12 @@ expand_omp_for (struct omp_region *region, gimple *inner_stmt) gcc_assert (fd.sched_kind != OMP_CLAUSE_SCHEDULE_AUTO); fn_index = (fd.sched_kind == OMP_CLAUSE_SCHEDULE_RUNTIME) ? 3 : fd.sched_kind; - fn_index += fd.have_ordered * 4; - start_ix = ((int)BUILT_IN_GOMP_LOOP_STATIC_START) + fn_index; + if (!fd.ordered) + fn_index += fd.have_ordered * 4; + if (fd.ordered) + start_ix = ((int)BUILT_IN_GOMP_LOOP_DOACROSS_STATIC_START) + fn_index; + else + start_ix = ((int)BUILT_IN_GOMP_LOOP_STATIC_START) + fn_index; next_ix = ((int)BUILT_IN_GOMP_LOOP_STATIC_NEXT) + fn_index; if (fd.iter_type == long_long_unsigned_type_node) { @@ -9049,10 +11285,12 @@ expand_omp_target (struct omp_region *region) offloaded = is_gimple_omp_offloaded (entry_stmt); switch (gimple_omp_target_kind (entry_stmt)) { - case GF_OMP_TARGET_KIND_OACC_PARALLEL: - case GF_OMP_TARGET_KIND_OACC_KERNELS: case GF_OMP_TARGET_KIND_REGION: case GF_OMP_TARGET_KIND_UPDATE: + case GF_OMP_TARGET_KIND_ENTER_DATA: + case GF_OMP_TARGET_KIND_EXIT_DATA: + case GF_OMP_TARGET_KIND_OACC_PARALLEL: + case GF_OMP_TARGET_KIND_OACC_KERNELS: case GF_OMP_TARGET_KIND_OACC_UPDATE: case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA: data_region = false; @@ -9252,9 +11490,10 @@ expand_omp_target (struct omp_region *region) /* Emit a library call to launch the offloading region, or do data transfers. */ - tree t1, t2, t3, t4, device, cond, c, clauses; + tree t1, t2, t3, t4, device, cond, depend, c, clauses; enum built_in_function start_ix; location_t clause_loc; + unsigned int flags_i = 0; switch (gimple_omp_target_kind (entry_stmt)) { @@ -9267,6 +11506,13 @@ expand_omp_target (struct omp_region *region) case GF_OMP_TARGET_KIND_UPDATE: start_ix = BUILT_IN_GOMP_TARGET_UPDATE; break; + case GF_OMP_TARGET_KIND_ENTER_DATA: + start_ix = BUILT_IN_GOMP_TARGET_ENTER_EXIT_DATA; + break; + case GF_OMP_TARGET_KIND_EXIT_DATA: + start_ix = BUILT_IN_GOMP_TARGET_ENTER_EXIT_DATA; + flags_i |= GOMP_TARGET_FLAG_EXIT_DATA; + break; case GF_OMP_TARGET_KIND_OACC_PARALLEL: case GF_OMP_TARGET_KIND_OACC_KERNELS: start_ix = BUILT_IN_GOACC_PARALLEL; @@ -9302,7 +11548,8 @@ expand_omp_target (struct omp_region *region) defined/used for the OpenMP target ones. */ gcc_checking_assert (start_ix == BUILT_IN_GOMP_TARGET || start_ix == BUILT_IN_GOMP_TARGET_DATA - || start_ix == BUILT_IN_GOMP_TARGET_UPDATE); + || start_ix == BUILT_IN_GOMP_TARGET_UPDATE + || start_ix == BUILT_IN_GOMP_TARGET_ENTER_EXIT_DATA); device = OMP_CLAUSE_DEVICE_ID (c); clause_loc = OMP_CLAUSE_LOCATION (c); @@ -9310,6 +11557,10 @@ expand_omp_target (struct omp_region *region) else clause_loc = gimple_location (entry_stmt); + c = find_omp_clause (clauses, OMP_CLAUSE_NOWAIT); + if (c) + flags_i |= GOMP_TARGET_FLAG_NOWAIT; + /* Ensure 'device' is of the correct type. */ device = fold_convert_loc (clause_loc, integer_type_node, device); @@ -9390,23 +11641,6 @@ expand_omp_target (struct omp_region *region) args.quick_push (device); if (offloaded) args.quick_push (build_fold_addr_expr (child_fn)); - switch (start_ix) - { - case BUILT_IN_GOMP_TARGET: - case BUILT_IN_GOMP_TARGET_DATA: - case BUILT_IN_GOMP_TARGET_UPDATE: - /* This const void * is part of the current ABI, but we're not actually - using it. */ - args.quick_push (build_zero_cst (ptr_type_node)); - break; - case BUILT_IN_GOACC_DATA_START: - case BUILT_IN_GOACC_ENTER_EXIT_DATA: - case BUILT_IN_GOACC_PARALLEL: - case BUILT_IN_GOACC_UPDATE: - break; - default: - gcc_unreachable (); - } args.quick_push (t1); args.quick_push (t2); args.quick_push (t3); @@ -9414,9 +11648,18 @@ expand_omp_target (struct omp_region *region) switch (start_ix) { case BUILT_IN_GOACC_DATA_START: - case BUILT_IN_GOMP_TARGET: case BUILT_IN_GOMP_TARGET_DATA: + break; + case BUILT_IN_GOMP_TARGET: case BUILT_IN_GOMP_TARGET_UPDATE: + case BUILT_IN_GOMP_TARGET_ENTER_EXIT_DATA: + args.quick_push (build_int_cst (unsigned_type_node, flags_i)); + c = find_omp_clause (clauses, OMP_CLAUSE_DEPEND); + if (c) + depend = OMP_CLAUSE_DECL (c); + else + depend = build_int_cst (ptr_type_node, 0); + args.quick_push (depend); break; case BUILT_IN_GOACC_PARALLEL: { @@ -9511,8 +11754,7 @@ expand_omp_target (struct omp_region *region) gcc_assert (g && gimple_code (g) == GIMPLE_OMP_TARGET); gsi_remove (&gsi, true); } - if (data_region - && region->exit) + if (data_region && region->exit) { gsi = gsi_last_bb (region->exit); g = gsi_stmt (gsi); @@ -9576,9 +11818,24 @@ expand_omp (struct omp_region *region) expand_omp_single (region); break; + case GIMPLE_OMP_ORDERED: + { + gomp_ordered *ord_stmt + = as_a (last_stmt (region->entry)); + if (find_omp_clause (gimple_omp_ordered_clauses (ord_stmt), + OMP_CLAUSE_DEPEND)) + { + /* We'll expand these when expanding corresponding + worksharing region with ordered(n) clause. */ + gcc_assert (region->outer + && region->outer->type == GIMPLE_OMP_FOR); + region->ord_stmt = ord_stmt; + break; + } + } + /* FALLTHRU */ case GIMPLE_OMP_MASTER: case GIMPLE_OMP_TASKGROUP: - case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_CRITICAL: case GIMPLE_OMP_TEAMS: expand_omp_synch (region); @@ -9669,6 +11926,8 @@ build_omp_regions_1 (basic_block bb, struct omp_region *parent, case GF_OMP_TARGET_KIND_OACC_DATA: break; case GF_OMP_TARGET_KIND_UPDATE: + case GF_OMP_TARGET_KIND_ENTER_DATA: + case GF_OMP_TARGET_KIND_EXIT_DATA: case GF_OMP_TARGET_KIND_OACC_UPDATE: case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA: /* ..., other than for those stand-alone directives... */ @@ -9678,6 +11937,13 @@ build_omp_regions_1 (basic_block bb, struct omp_region *parent, gcc_unreachable (); } } + else if (code == GIMPLE_OMP_ORDERED + && find_omp_clause (gimple_omp_ordered_clauses + (as_a (stmt)), + OMP_CLAUSE_DEPEND)) + /* #pragma omp ordered depend is also just a stand-alone + directive. */ + region = NULL; /* ..., this directive becomes the parent for a new region. */ if (region) parent = region; @@ -10600,6 +12866,243 @@ lower_omp_taskgroup (gimple_stmt_iterator *gsi_p, omp_context *ctx) } +/* Fold the OMP_ORDERED_CLAUSES for the OMP_ORDERED in STMT if possible. */ + +static void +lower_omp_ordered_clauses (gimple_stmt_iterator *gsi_p, gomp_ordered *ord_stmt, + omp_context *ctx) +{ + struct omp_for_data fd; + if (!ctx->outer || gimple_code (ctx->outer->stmt) != GIMPLE_OMP_FOR) + return; + + unsigned int len = gimple_omp_for_collapse (ctx->outer->stmt); + struct omp_for_data_loop *loops = XALLOCAVEC (struct omp_for_data_loop, len); + extract_omp_for_data (as_a (ctx->outer->stmt), &fd, loops); + if (!fd.ordered) + return; + + tree *list_p = gimple_omp_ordered_clauses_ptr (ord_stmt); + tree c = gimple_omp_ordered_clauses (ord_stmt); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + && OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK) + { + /* Merge depend clauses from multiple adjacent + #pragma omp ordered depend(sink:...) constructs + into one #pragma omp ordered depend(sink:...), so that + we can optimize them together. */ + gimple_stmt_iterator gsi = *gsi_p; + gsi_next (&gsi); + while (!gsi_end_p (gsi)) + { + gimple *stmt = gsi_stmt (gsi); + if (is_gimple_debug (stmt) + || gimple_code (stmt) == GIMPLE_NOP) + { + gsi_next (&gsi); + continue; + } + if (gimple_code (stmt) != GIMPLE_OMP_ORDERED) + break; + gomp_ordered *ord_stmt2 = as_a (stmt); + c = gimple_omp_ordered_clauses (ord_stmt2); + if (c == NULL_TREE + || OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + || OMP_CLAUSE_DEPEND_KIND (c) != OMP_CLAUSE_DEPEND_SINK) + break; + while (*list_p) + list_p = &OMP_CLAUSE_CHAIN (*list_p); + *list_p = c; + gsi_remove (&gsi, true); + } + } + + /* Canonicalize sink dependence clauses into one folded clause if + possible. + + The basic algorithm is to create a sink vector whose first + element is the GCD of all the first elements, and whose remaining + elements are the minimum of the subsequent columns. + + We ignore dependence vectors whose first element is zero because + such dependencies are known to be executed by the same thread. + + We take into account the direction of the loop, so a minimum + becomes a maximum if the loop is iterating forwards. We also + ignore sink clauses where the loop direction is unknown, or where + the offsets are clearly invalid because they are not a multiple + of the loop increment. + + For example: + + #pragma omp for ordered(2) + for (i=0; i < N; ++i) + for (j=0; j < M; ++j) + { + #pragma omp ordered \ + depend(sink:i-8,j-2) \ + depend(sink:i,j-1) \ // Completely ignored because i+0. + depend(sink:i-4,j-3) \ + depend(sink:i-6,j-4) + #pragma omp ordered depend(source) + } + + Folded clause is: + + depend(sink:-gcd(8,4,6),-min(2,3,4)) + -or- + depend(sink:-2,-2) + */ + + /* FIXME: Computing GCD's where the first element is zero is + non-trivial in the presence of collapsed loops. Do this later. */ + if (fd.collapse > 1) + return; + + wide_int *folded_deps = XALLOCAVEC (wide_int, 2 * len - 1); + memset (folded_deps, 0, sizeof (*folded_deps) * (2 * len - 1)); + tree folded_dep = NULL_TREE; + /* TRUE if the first dimension's offset is negative. */ + bool neg_offset_p = false; + + list_p = gimple_omp_ordered_clauses_ptr (ord_stmt); + unsigned int i; + while ((c = *list_p) != NULL) + { + bool remove = false; + + gcc_assert (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND); + if (OMP_CLAUSE_DEPEND_KIND (c) != OMP_CLAUSE_DEPEND_SINK) + goto next_ordered_clause; + + tree vec; + for (vec = OMP_CLAUSE_DECL (c), i = 0; + vec && TREE_CODE (vec) == TREE_LIST; + vec = TREE_CHAIN (vec), ++i) + { + gcc_assert (i < len); + + /* extract_omp_for_data has canonicalized the condition. */ + gcc_assert (fd.loops[i].cond_code == LT_EXPR + || fd.loops[i].cond_code == GT_EXPR); + bool forward = fd.loops[i].cond_code == LT_EXPR; + bool maybe_lexically_later = true; + + /* While the committee makes up its mind, bail if we have any + non-constant steps. */ + if (TREE_CODE (fd.loops[i].step) != INTEGER_CST) + goto lower_omp_ordered_ret; + + tree itype = TREE_TYPE (TREE_VALUE (vec)); + if (POINTER_TYPE_P (itype)) + itype = sizetype; + wide_int offset = wide_int::from (TREE_PURPOSE (vec), + TYPE_PRECISION (itype), + TYPE_SIGN (itype)); + + /* Ignore invalid offsets that are not multiples of the step. */ + if (!wi::multiple_of_p + (wi::abs (offset), wi::abs ((wide_int) fd.loops[i].step), + UNSIGNED)) + { + warning_at (OMP_CLAUSE_LOCATION (c), 0, + "ignoring sink clause with offset that is not " + "a multiple of the loop step"); + remove = true; + goto next_ordered_clause; + } + + /* Calculate the first dimension. The first dimension of + the folded dependency vector is the GCD of the first + elements, while ignoring any first elements whose offset + is 0. */ + if (i == 0) + { + /* Ignore dependence vectors whose first dimension is 0. */ + if (offset == 0) + { + remove = true; + goto next_ordered_clause; + } + else + { + if (!TYPE_UNSIGNED (itype) && (forward ^ wi::neg_p (offset))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "first offset must be in opposite direction " + "of loop iterations"); + goto lower_omp_ordered_ret; + } + if (forward) + offset = -offset; + neg_offset_p = forward; + /* Initialize the first time around. */ + if (folded_dep == NULL_TREE) + { + folded_dep = c; + folded_deps[0] = offset; + } + else + folded_deps[0] = wi::gcd (folded_deps[0], + offset, UNSIGNED); + } + } + /* Calculate minimum for the remaining dimensions. */ + else + { + folded_deps[len + i - 1] = offset; + if (folded_dep == c) + folded_deps[i] = offset; + else if (maybe_lexically_later + && !wi::eq_p (folded_deps[i], offset)) + { + if (forward ^ wi::gts_p (folded_deps[i], offset)) + { + unsigned int j; + folded_dep = c; + for (j = 1; j <= i; j++) + folded_deps[j] = folded_deps[len + j - 1]; + } + else + maybe_lexically_later = false; + } + } + } + gcc_assert (i == len); + + remove = true; + + next_ordered_clause: + if (remove) + *list_p = OMP_CLAUSE_CHAIN (c); + else + list_p = &OMP_CLAUSE_CHAIN (c); + } + + if (folded_dep) + { + if (neg_offset_p) + folded_deps[0] = -folded_deps[0]; + + tree itype = TREE_TYPE (TREE_VALUE (OMP_CLAUSE_DECL (folded_dep))); + if (POINTER_TYPE_P (itype)) + itype = sizetype; + + TREE_PURPOSE (OMP_CLAUSE_DECL (folded_dep)) + = wide_int_to_tree (itype, folded_deps[0]); + OMP_CLAUSE_CHAIN (folded_dep) = gimple_omp_ordered_clauses (ord_stmt); + *gimple_omp_ordered_clauses_ptr (ord_stmt) = folded_dep; + } + + lower_omp_ordered_ret: + + /* Ordered without clauses is #pragma omp threads, while we want + a nop instead if we remove all clauses. */ + if (gimple_omp_ordered_clauses (ord_stmt) == NULL_TREE) + gsi_replace (gsi_p, gimple_build_nop (), true); +} + + /* Expand code for an OpenMP ordered directive. */ static void @@ -10607,8 +13110,23 @@ lower_omp_ordered (gimple_stmt_iterator *gsi_p, omp_context *ctx) { tree block; gimple *stmt = gsi_stmt (*gsi_p); + gomp_ordered *ord_stmt = as_a (stmt); gcall *x; gbind *bind; + bool simd + = find_omp_clause (gimple_omp_ordered_clauses (ord_stmt), OMP_CLAUSE_SIMD); + + if (find_omp_clause (gimple_omp_ordered_clauses (ord_stmt), + OMP_CLAUSE_DEPEND)) + { + /* FIXME: This is needs to be moved to the expansion to verify various + conditions only testable on cfg with dominators computed, and also + all the depend clauses to be merged still might need to be available + for the runtime checks. */ + if (0) + lower_omp_ordered_clauses (gsi_p, ord_stmt, ctx); + return; + } push_gimplify_context (); @@ -10617,8 +13135,14 @@ lower_omp_ordered (gimple_stmt_iterator *gsi_p, omp_context *ctx) gsi_replace (gsi_p, bind, true); gimple_bind_add_stmt (bind, stmt); - x = gimple_build_call (builtin_decl_explicit (BUILT_IN_GOMP_ORDERED_START), - 0); + if (simd) + { + x = gimple_build_call_internal (IFN_GOMP_SIMD_ORDERED_START, 0); + cfun->has_simduid_loops = true; + } + else + x = gimple_build_call (builtin_decl_explicit (BUILT_IN_GOMP_ORDERED_START), + 0); gimple_bind_add_stmt (bind, x); lower_omp (gimple_omp_body_ptr (stmt), ctx); @@ -10626,7 +13150,11 @@ lower_omp_ordered (gimple_stmt_iterator *gsi_p, omp_context *ctx) gimple_bind_add_seq (bind, gimple_omp_body (stmt)); gimple_omp_set_body (stmt, NULL); - x = gimple_build_call (builtin_decl_explicit (BUILT_IN_GOMP_ORDERED_END), 0); + if (simd) + x = gimple_build_call_internal (IFN_GOMP_SIMD_ORDERED_END, 0); + else + x = gimple_build_call (builtin_decl_explicit (BUILT_IN_GOMP_ORDERED_END), + 0); gimple_bind_add_stmt (bind, x); gimple_bind_add_stmt (bind, gimple_build_omp_return (true)); @@ -10773,15 +13301,42 @@ lower_omp_for_lastprivate (struct omp_for_data *fd, gimple_seq *body_p, tree n2 = fd->loop.n2; if (fd->collapse > 1 && TREE_CODE (n2) != INTEGER_CST - && gimple_omp_for_combined_into_p (fd->for_stmt) - && gimple_code (ctx->outer->stmt) == GIMPLE_OMP_FOR) + && gimple_omp_for_combined_into_p (fd->for_stmt)) { - gomp_for *gfor = as_a (ctx->outer->stmt); - if (gimple_omp_for_kind (gfor) == GF_OMP_FOR_KIND_FOR) + struct omp_context *task_ctx = NULL; + if (gimple_code (ctx->outer->stmt) == GIMPLE_OMP_FOR) + { + gomp_for *gfor = as_a (ctx->outer->stmt); + if (gimple_omp_for_kind (gfor) == GF_OMP_FOR_KIND_FOR) + { + struct omp_for_data outer_fd; + extract_omp_for_data (gfor, &outer_fd, NULL); + n2 = fold_convert (TREE_TYPE (n2), outer_fd.loop.n2); + } + else if (gimple_omp_for_kind (gfor) == GF_OMP_FOR_KIND_TASKLOOP) + task_ctx = ctx->outer->outer; + } + else if (is_task_ctx (ctx->outer)) + task_ctx = ctx->outer; + if (task_ctx) { - struct omp_for_data outer_fd; - extract_omp_for_data (gfor, &outer_fd, NULL); - n2 = fold_convert (TREE_TYPE (n2), outer_fd.loop.n2); + int i; + tree innerc + = find_omp_clause (gimple_omp_task_clauses (task_ctx->stmt), + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + for (i = 0; i < fd->collapse; i++) + { + innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc), + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + } + innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc), + OMP_CLAUSE__LOOPTEMP_); + if (innerc) + n2 = fold_convert (TREE_TYPE (n2), + lookup_decl (OMP_CLAUSE_DECL (innerc), + task_ctx)); } } cond = build2 (cond_code, boolean_type_node, fd->loop.v, n2); @@ -10863,17 +13418,19 @@ lower_omp_for (gimple_stmt_iterator *gsi_p, omp_context *ctx) if (fd.collapse > 1 && TREE_CODE (fd.loop.n2) != INTEGER_CST) count += fd.collapse - 1; - bool parallel_for = gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_FOR; + bool taskreg_for + = (gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_FOR + || gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_TASKLOOP); tree outerc = NULL, *pc = gimple_omp_for_clauses_ptr (stmt); tree clauses = *pc; - if (parallel_for) + if (taskreg_for) outerc - = find_omp_clause (gimple_omp_parallel_clauses (ctx->outer->stmt), + = find_omp_clause (gimple_omp_taskreg_clauses (ctx->outer->stmt), OMP_CLAUSE__LOOPTEMP_); for (i = 0; i < count; i++) { tree temp; - if (parallel_for) + if (taskreg_for) { gcc_assert (outerc); temp = lookup_decl (OMP_CLAUSE_DECL (outerc), ctx->outer); @@ -10928,6 +13485,18 @@ lower_omp_for (gimple_stmt_iterator *gsi_p, omp_context *ctx) lower_omp_for_lastprivate (&fd, &body, &dlist, ctx); + if (gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_FOR) + for (tree c = gimple_omp_for_clauses (stmt); c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR + && !OMP_CLAUSE_LINEAR_NO_COPYIN (c)) + { + OMP_CLAUSE_DECL (c) = lookup_decl (OMP_CLAUSE_DECL (c), ctx); + if (DECL_P (OMP_CLAUSE_LINEAR_STEP (c))) + OMP_CLAUSE_LINEAR_STEP (c) + = maybe_lookup_decl_in_outer_ctx (OMP_CLAUSE_LINEAR_STEP (c), + ctx); + } + gimple_seq_add_stmt (&body, stmt); gimple_seq_add_seq (&body, gimple_omp_body (stmt)); @@ -11138,15 +13707,19 @@ create_task_copyfn (gomp_task *task_stmt, omp_context *ctx) for (c = gimple_omp_task_clauses (task_stmt); c; c = OMP_CLAUSE_CHAIN (c)) switch (OMP_CLAUSE_CODE (c)) { + splay_tree_key key; case OMP_CLAUSE_SHARED: decl = OMP_CLAUSE_DECL (c); - n = splay_tree_lookup (ctx->field_map, (splay_tree_key) decl); + key = (splay_tree_key) decl; + if (OMP_CLAUSE_SHARED_FIRSTPRIVATE (c)) + key = (splay_tree_key) &DECL_UID (decl); + n = splay_tree_lookup (ctx->field_map, key); if (n == NULL) break; f = (tree) n->value; if (tcctx.cb.decl_map) f = *tcctx.cb.decl_map->get (f); - n = splay_tree_lookup (ctx->sfield_map, (splay_tree_key) decl); + n = splay_tree_lookup (ctx->sfield_map, key); sf = (tree) n->value; if (tcctx.cb.decl_map) sf = *tcctx.cb.decl_map->get (sf); @@ -11267,14 +13840,13 @@ create_task_copyfn (gomp_task *task_stmt, omp_context *ctx) } static void -lower_depend_clauses (gimple *stmt, gimple_seq *iseq, gimple_seq *oseq) +lower_depend_clauses (tree *pclauses, gimple_seq *iseq, gimple_seq *oseq) { tree c, clauses; gimple *g; size_t n_in = 0, n_out = 0, idx = 2, i; - clauses = find_omp_clause (gimple_omp_task_clauses (stmt), - OMP_CLAUSE_DEPEND); + clauses = find_omp_clause (*pclauses, OMP_CLAUSE_DEPEND); gcc_assert (clauses); for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND) @@ -11287,11 +13859,15 @@ lower_depend_clauses (gimple *stmt, gimple_seq *iseq, gimple_seq *oseq) case OMP_CLAUSE_DEPEND_INOUT: n_out++; break; + case OMP_CLAUSE_DEPEND_SOURCE: + case OMP_CLAUSE_DEPEND_SINK: + /* FALLTHRU */ default: gcc_unreachable (); } tree type = build_array_type_nelts (ptr_type_node, n_in + n_out + 2); tree array = create_tmp_var (type); + TREE_ADDRESSABLE (array) = 1; tree r = build4 (ARRAY_REF, ptr_type_node, array, size_int (0), NULL_TREE, NULL_TREE); g = gimple_build_assign (r, build_int_cst (ptr_type_node, n_in + n_out)); @@ -11317,11 +13893,10 @@ lower_depend_clauses (gimple *stmt, gimple_seq *iseq, gimple_seq *oseq) gimple_seq_add_stmt (iseq, g); } } - tree *p = gimple_omp_task_clauses_ptr (stmt); c = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE_DEPEND); OMP_CLAUSE_DECL (c) = build_fold_addr_expr (array); - OMP_CLAUSE_CHAIN (c) = *p; - *p = c; + OMP_CLAUSE_CHAIN (c) = *pclauses; + *pclauses = c; tree clobber = build_constructor (type, NULL); TREE_THIS_VOLATILE (clobber) = 1; g = gimple_build_assign (array, clobber); @@ -11366,7 +13941,8 @@ lower_omp_taskreg (gimple_stmt_iterator *gsi_p, omp_context *ctx) { push_gimplify_context (); dep_bind = gimple_build_bind (NULL, NULL, make_node (BLOCK)); - lower_depend_clauses (stmt, &dep_ilist, &dep_olist); + lower_depend_clauses (gimple_omp_task_clauses_ptr (stmt), + &dep_ilist, &dep_olist); } if (ctx->srecord_type) @@ -11464,17 +14040,20 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) tree clauses; tree child_fn, t, c; gomp_target *stmt = as_a (gsi_stmt (*gsi_p)); - gbind *tgt_bind, *bind; + gbind *tgt_bind, *bind, *dep_bind = NULL; gimple_seq tgt_body, olist, ilist, orlist, irlist, new_body; location_t loc = gimple_location (stmt); bool offloaded, data_region; unsigned int map_cnt = 0; + bool has_depend = false; offloaded = is_gimple_omp_offloaded (stmt); switch (gimple_omp_target_kind (stmt)) { case GF_OMP_TARGET_KIND_REGION: case GF_OMP_TARGET_KIND_UPDATE: + case GF_OMP_TARGET_KIND_ENTER_DATA: + case GF_OMP_TARGET_KIND_EXIT_DATA: case GF_OMP_TARGET_KIND_OACC_PARALLEL: case GF_OMP_TARGET_KIND_OACC_KERNELS: case GF_OMP_TARGET_KIND_OACC_UPDATE: @@ -11491,6 +14070,17 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) clauses = gimple_omp_target_clauses (stmt); + gimple_seq dep_ilist = NULL; + gimple_seq dep_olist = NULL; + if (find_omp_clause (clauses, OMP_CLAUSE_DEPEND)) + { + push_gimplify_context (); + dep_bind = gimple_build_bind (NULL, NULL, make_node (BLOCK)); + lower_depend_clauses (gimple_omp_target_clauses_ptr (stmt), + &dep_ilist, &dep_olist); + has_depend = true; + } + tgt_bind = NULL; tgt_body = NULL; if (offloaded) @@ -11528,13 +14118,19 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) case GOMP_MAP_TOFROM: case GOMP_MAP_POINTER: case GOMP_MAP_TO_PSET: + case GOMP_MAP_FORCE_DEALLOC: + case GOMP_MAP_RELEASE: + case GOMP_MAP_ALWAYS_TO: + case GOMP_MAP_ALWAYS_FROM: + case GOMP_MAP_ALWAYS_TOFROM: + case GOMP_MAP_FIRSTPRIVATE_POINTER: + case GOMP_MAP_STRUCT: break; case GOMP_MAP_FORCE_ALLOC: case GOMP_MAP_FORCE_TO: case GOMP_MAP_FORCE_FROM: case GOMP_MAP_FORCE_TOFROM: case GOMP_MAP_FORCE_PRESENT: - case GOMP_MAP_FORCE_DEALLOC: case GOMP_MAP_FORCE_DEVICEPTR: gcc_assert (is_gimple_omp_oacc (stmt)); break; @@ -11549,7 +14145,9 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) if (!DECL_P (var)) { if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP - || !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c)) + || (!OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c) + && (OMP_CLAUSE_MAP_KIND (c) + != GOMP_MAP_FIRSTPRIVATE_POINTER))) map_cnt++; continue; } @@ -11564,6 +14162,32 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) var = var2; } + if (offloaded + && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER) + { + if (TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE) + { + if (is_global_var (maybe_lookup_decl_in_outer_ctx (var, ctx)) + && varpool_node::get_create (var)->offloadable) + continue; + + tree type = build_pointer_type (TREE_TYPE (var)); + tree new_var = lookup_decl (var, ctx); + x = create_tmp_var_raw (type, get_name (new_var)); + gimple_add_tmp_var (x); + x = build_simple_mem_ref (x); + SET_DECL_VALUE_EXPR (new_var, x); + DECL_HAS_VALUE_EXPR_P (new_var) = 1; + } + continue; + } + + if (offloaded && OMP_CLAUSE_MAP_PRIVATE (c)) + { + map_cnt++; + continue; + } + if (!maybe_lookup_field (var, ctx)) continue; @@ -11571,6 +14195,7 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) { x = build_receiver_ref (var, true, ctx); tree new_var = lookup_decl (var, ctx); + if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER && !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c) && TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE) @@ -11579,6 +14204,77 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) DECL_HAS_VALUE_EXPR_P (new_var) = 1; } map_cnt++; + break; + + case OMP_CLAUSE_FIRSTPRIVATE: + map_cnt++; + var = OMP_CLAUSE_DECL (c); + if (!is_reference (var) + && !is_gimple_reg_type (TREE_TYPE (var))) + { + tree new_var = lookup_decl (var, ctx); + if (is_variable_sized (var)) + { + tree pvar = DECL_VALUE_EXPR (var); + gcc_assert (TREE_CODE (pvar) == INDIRECT_REF); + pvar = TREE_OPERAND (pvar, 0); + gcc_assert (DECL_P (pvar)); + tree new_pvar = lookup_decl (pvar, ctx); + x = build_fold_indirect_ref (new_pvar); + TREE_THIS_NOTRAP (x) = 1; + } + else + x = build_receiver_ref (var, true, ctx); + SET_DECL_VALUE_EXPR (new_var, x); + DECL_HAS_VALUE_EXPR_P (new_var) = 1; + } + break; + + case OMP_CLAUSE_PRIVATE: + var = OMP_CLAUSE_DECL (c); + if (is_variable_sized (var)) + { + tree new_var = lookup_decl (var, ctx); + tree pvar = DECL_VALUE_EXPR (var); + gcc_assert (TREE_CODE (pvar) == INDIRECT_REF); + pvar = TREE_OPERAND (pvar, 0); + gcc_assert (DECL_P (pvar)); + tree new_pvar = lookup_decl (pvar, ctx); + x = build_fold_indirect_ref (new_pvar); + TREE_THIS_NOTRAP (x) = 1; + SET_DECL_VALUE_EXPR (new_var, x); + DECL_HAS_VALUE_EXPR_P (new_var) = 1; + } + break; + + case OMP_CLAUSE_USE_DEVICE_PTR: + case OMP_CLAUSE_IS_DEVICE_PTR: + var = OMP_CLAUSE_DECL (c); + map_cnt++; + if (is_variable_sized (var)) + { + tree new_var = lookup_decl (var, ctx); + tree pvar = DECL_VALUE_EXPR (var); + gcc_assert (TREE_CODE (pvar) == INDIRECT_REF); + pvar = TREE_OPERAND (pvar, 0); + gcc_assert (DECL_P (pvar)); + tree new_pvar = lookup_decl (pvar, ctx); + x = build_fold_indirect_ref (new_pvar); + TREE_THIS_NOTRAP (x) = 1; + SET_DECL_VALUE_EXPR (new_var, x); + DECL_HAS_VALUE_EXPR_P (new_var) = 1; + } + else if (TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE) + { + tree new_var = lookup_decl (var, ctx); + tree type = build_pointer_type (TREE_TYPE (var)); + x = create_tmp_var_raw (type, get_name (new_var)); + gimple_add_tmp_var (x); + x = build_simple_mem_ref (x); + SET_DECL_VALUE_EXPR (new_var, x); + DECL_HAS_VALUE_EXPR_P (new_var) = 1; + } + break; } if (offloaded) @@ -11614,18 +14310,8 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) DECL_NAMELESS (TREE_VEC_ELT (t, 1)) = 1; TREE_ADDRESSABLE (TREE_VEC_ELT (t, 1)) = 1; TREE_STATIC (TREE_VEC_ELT (t, 1)) = 1; - tree tkind_type; - int talign_shift; - if (is_gimple_omp_oacc (stmt)) - { - tkind_type = short_unsigned_type_node; - talign_shift = 8; - } - else - { - tkind_type = unsigned_char_type_node; - talign_shift = 3; - } + tree tkind_type = short_unsigned_type_node; + int talign_shift = 8; TREE_VEC_ELT (t, 2) = create_tmp_var (build_array_type_nelts (tkind_type, map_cnt), ".omp_data_kinds"); @@ -11643,7 +14329,8 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c)) switch (OMP_CLAUSE_CODE (c)) { - tree ovar, nc; + tree ovar, nc, s, purpose, var, x, type; + unsigned int talign; default: break; @@ -11652,6 +14339,9 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) case OMP_CLAUSE_FROM: nc = c; ovar = OMP_CLAUSE_DECL (c); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER) + break; if (!DECL_P (ovar)) { if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP @@ -11682,17 +14372,29 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) gcc_assert (DECL_P (ovar2)); ovar = ovar2; } - if (!maybe_lookup_field (ovar, ctx)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && OMP_CLAUSE_MAP_PRIVATE (c)) + { + if (!maybe_lookup_field ((splay_tree_key) &DECL_UID (ovar), + ctx)) + continue; + } + else if (!maybe_lookup_field (ovar, ctx)) continue; } - unsigned int talign = TYPE_ALIGN_UNIT (TREE_TYPE (ovar)); + talign = TYPE_ALIGN_UNIT (TREE_TYPE (ovar)); if (DECL_P (ovar) && DECL_ALIGN_UNIT (ovar) > talign) talign = DECL_ALIGN_UNIT (ovar); if (nc) { - tree var = lookup_decl_in_outer_ctx (ovar, ctx); - tree x = build_sender_ref (ovar, ctx); + var = lookup_decl_in_outer_ctx (ovar, ctx); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && OMP_CLAUSE_MAP_PRIVATE (c)) + x = build_sender_ref ((splay_tree_key) &DECL_UID (ovar), + ctx); + else + x = build_sender_ref (ovar, ctx); if (maybe_lookup_oacc_reduction (var, ctx)) { gcc_checking_assert (offloaded @@ -11730,7 +14432,7 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) || map_kind == GOMP_MAP_FORCE_DEVICEPTR) && !TYPE_READONLY (TREE_TYPE (var))) { - x = build_sender_ref (ovar, ctx); + x = unshare_expr (x); x = build_simple_mem_ref (x); gimplify_assign (var, x, &olist); } @@ -11741,40 +14443,215 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) gimplify_assign (x, var, &ilist); } } - tree s = OMP_CLAUSE_SIZE (c); + s = OMP_CLAUSE_SIZE (c); if (s == NULL_TREE) s = TYPE_SIZE_UNIT (TREE_TYPE (ovar)); s = fold_convert (size_type_node, s); - tree purpose = size_int (map_idx++); + purpose = size_int (map_idx++); CONSTRUCTOR_APPEND_ELT (vsize, purpose, s); if (TREE_CODE (s) != INTEGER_CST) TREE_STATIC (TREE_VEC_ELT (t, 1)) = 0; - unsigned HOST_WIDE_INT tkind; + unsigned HOST_WIDE_INT tkind, tkind_zero; switch (OMP_CLAUSE_CODE (c)) { case OMP_CLAUSE_MAP: tkind = OMP_CLAUSE_MAP_KIND (c); + tkind_zero = tkind; + if (OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION (c)) + switch (tkind) + { + case GOMP_MAP_ALLOC: + case GOMP_MAP_TO: + case GOMP_MAP_FROM: + case GOMP_MAP_TOFROM: + case GOMP_MAP_ALWAYS_TO: + case GOMP_MAP_ALWAYS_FROM: + case GOMP_MAP_ALWAYS_TOFROM: + case GOMP_MAP_RELEASE: + tkind_zero = GOMP_MAP_ZERO_LEN_ARRAY_SECTION; + break; + case GOMP_MAP_DELETE: + tkind_zero = GOMP_MAP_DELETE_ZERO_LEN_ARRAY_SECTION; + default: + break; + } + if (tkind_zero != tkind) + { + if (integer_zerop (s)) + tkind = tkind_zero; + else if (integer_nonzerop (s)) + tkind_zero = tkind; + } break; case OMP_CLAUSE_TO: tkind = GOMP_MAP_TO; + tkind_zero = tkind; break; case OMP_CLAUSE_FROM: tkind = GOMP_MAP_FROM; + tkind_zero = tkind; break; default: gcc_unreachable (); } gcc_checking_assert (tkind < (HOST_WIDE_INT_C (1U) << talign_shift)); + gcc_checking_assert (tkind_zero + < (HOST_WIDE_INT_C (1U) << talign_shift)); talign = ceil_log2 (talign); tkind |= talign << talign_shift; + tkind_zero |= talign << talign_shift; gcc_checking_assert (tkind <= tree_to_uhwi (TYPE_MAX_VALUE (tkind_type))); - CONSTRUCTOR_APPEND_ELT (vkind, purpose, - build_int_cstu (tkind_type, tkind)); + gcc_checking_assert (tkind_zero + <= tree_to_uhwi (TYPE_MAX_VALUE (tkind_type))); + if (tkind == tkind_zero) + x = build_int_cstu (tkind_type, tkind); + else + { + TREE_STATIC (TREE_VEC_ELT (t, 2)) = 0; + x = build3 (COND_EXPR, tkind_type, + fold_build2 (EQ_EXPR, boolean_type_node, + unshare_expr (s), size_zero_node), + build_int_cstu (tkind_type, tkind_zero), + build_int_cstu (tkind_type, tkind)); + } + CONSTRUCTOR_APPEND_ELT (vkind, purpose, x); if (nc && nc != c) c = nc; + break; + + case OMP_CLAUSE_FIRSTPRIVATE: + ovar = OMP_CLAUSE_DECL (c); + if (is_reference (ovar)) + talign = TYPE_ALIGN_UNIT (TREE_TYPE (TREE_TYPE (ovar))); + else + talign = DECL_ALIGN_UNIT (ovar); + var = lookup_decl_in_outer_ctx (ovar, ctx); + x = build_sender_ref (ovar, ctx); + tkind = GOMP_MAP_FIRSTPRIVATE; + type = TREE_TYPE (ovar); + if (is_reference (ovar)) + type = TREE_TYPE (type); + bool use_firstprivate_int, force_addr; + use_firstprivate_int = false; + force_addr = false; + if ((INTEGRAL_TYPE_P (type) + && TYPE_PRECISION (type) <= POINTER_SIZE) + || TREE_CODE (type) == POINTER_TYPE) + use_firstprivate_int = true; + if (has_depend) + { + if (is_reference (var)) + use_firstprivate_int = false; + else if (is_gimple_reg (var)) + { + if (DECL_HAS_VALUE_EXPR_P (var)) + { + tree v = get_base_address (var); + if (DECL_P (v) && TREE_ADDRESSABLE (v)) + { + use_firstprivate_int = false; + force_addr = true; + } + else + switch (TREE_CODE (v)) + { + case INDIRECT_REF: + case MEM_REF: + use_firstprivate_int = false; + force_addr = true; + break; + default: + break; + } + } + } + else + use_firstprivate_int = false; + } + if (use_firstprivate_int) + { + tkind = GOMP_MAP_FIRSTPRIVATE_INT; + tree t = var; + if (is_reference (var)) + t = build_simple_mem_ref (var); + if (TREE_CODE (type) != POINTER_TYPE) + t = fold_convert (pointer_sized_int_node, t); + t = fold_convert (TREE_TYPE (x), t); + gimplify_assign (x, t, &ilist); + } + else if (is_reference (var)) + gimplify_assign (x, var, &ilist); + else if (!force_addr && is_gimple_reg (var)) + { + tree avar = create_tmp_var (TREE_TYPE (var)); + mark_addressable (avar); + gimplify_assign (avar, var, &ilist); + avar = build_fold_addr_expr (avar); + gimplify_assign (x, avar, &ilist); + } + else + { + var = build_fold_addr_expr (var); + gimplify_assign (x, var, &ilist); + } + if (tkind == GOMP_MAP_FIRSTPRIVATE_INT) + s = size_int (0); + else if (is_reference (var)) + s = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ovar))); + else + s = TYPE_SIZE_UNIT (TREE_TYPE (ovar)); + s = fold_convert (size_type_node, s); + purpose = size_int (map_idx++); + CONSTRUCTOR_APPEND_ELT (vsize, purpose, s); + if (TREE_CODE (s) != INTEGER_CST) + TREE_STATIC (TREE_VEC_ELT (t, 1)) = 0; + + gcc_checking_assert (tkind + < (HOST_WIDE_INT_C (1U) << talign_shift)); + talign = ceil_log2 (talign); + tkind |= talign << talign_shift; + gcc_checking_assert (tkind + <= tree_to_uhwi (TYPE_MAX_VALUE (tkind_type))); + CONSTRUCTOR_APPEND_ELT (vkind, purpose, + build_int_cstu (tkind_type, tkind)); + break; + + case OMP_CLAUSE_USE_DEVICE_PTR: + case OMP_CLAUSE_IS_DEVICE_PTR: + ovar = OMP_CLAUSE_DECL (c); + var = lookup_decl_in_outer_ctx (ovar, ctx); + x = build_sender_ref (ovar, ctx); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_USE_DEVICE_PTR) + tkind = GOMP_MAP_USE_DEVICE_PTR; + else + tkind = GOMP_MAP_FIRSTPRIVATE_INT; + type = TREE_TYPE (ovar); + if (TREE_CODE (type) == ARRAY_TYPE) + var = build_fold_addr_expr (var); + else + { + if (is_reference (ovar)) + { + type = TREE_TYPE (type); + if (TREE_CODE (type) != ARRAY_TYPE) + var = build_simple_mem_ref (var); + var = fold_convert (TREE_TYPE (x), var); + } + } + gimplify_assign (x, var, &ilist); + s = size_int (0); + purpose = size_int (map_idx++); + CONSTRUCTOR_APPEND_ELT (vsize, purpose, s); + gcc_checking_assert (tkind + < (HOST_WIDE_INT_C (1U) << talign_shift)); + gcc_checking_assert (tkind + <= tree_to_uhwi (TYPE_MAX_VALUE (tkind_type))); + CONSTRUCTOR_APPEND_ELT (vkind, purpose, + build_int_cstu (tkind_type, tkind)); + break; } gcc_assert (map_idx == map_cnt); @@ -11783,21 +14660,22 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) = build_constructor (TREE_TYPE (TREE_VEC_ELT (t, 1)), vsize); DECL_INITIAL (TREE_VEC_ELT (t, 2)) = build_constructor (TREE_TYPE (TREE_VEC_ELT (t, 2)), vkind); - if (!TREE_STATIC (TREE_VEC_ELT (t, 1))) - { - gimple_seq initlist = NULL; - force_gimple_operand (build1 (DECL_EXPR, void_type_node, - TREE_VEC_ELT (t, 1)), - &initlist, true, NULL_TREE); - gimple_seq_add_seq (&ilist, initlist); - - tree clobber = build_constructor (TREE_TYPE (TREE_VEC_ELT (t, 1)), - NULL); - TREE_THIS_VOLATILE (clobber) = 1; - gimple_seq_add_stmt (&olist, - gimple_build_assign (TREE_VEC_ELT (t, 1), - clobber)); - } + for (int i = 1; i <= 2; i++) + if (!TREE_STATIC (TREE_VEC_ELT (t, i))) + { + gimple_seq initlist = NULL; + force_gimple_operand (build1 (DECL_EXPR, void_type_node, + TREE_VEC_ELT (t, i)), + &initlist, true, NULL_TREE); + gimple_seq_add_seq (&ilist, initlist); + + tree clobber = build_constructor (TREE_TYPE (TREE_VEC_ELT (t, i)), + NULL); + TREE_THIS_VOLATILE (clobber) = 1; + gimple_seq_add_stmt (&olist, + gimple_build_assign (TREE_VEC_ELT (t, i), + clobber)); + } tree clobber = build_constructor (ctx->record_type, NULL); TREE_THIS_VOLATILE (clobber) = 1; @@ -11820,10 +14698,330 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) gimple_build_assign (ctx->receiver_decl, t)); } - if (offloaded) + if (offloaded || data_region) { + tree prev = NULL_TREE; + for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c)) + switch (OMP_CLAUSE_CODE (c)) + { + tree var, x; + default: + break; + case OMP_CLAUSE_FIRSTPRIVATE: + var = OMP_CLAUSE_DECL (c); + if (is_reference (var) + || is_gimple_reg_type (TREE_TYPE (var))) + { + tree new_var = lookup_decl (var, ctx); + tree type; + type = TREE_TYPE (var); + if (is_reference (var)) + type = TREE_TYPE (type); + bool use_firstprivate_int; + use_firstprivate_int = false; + if ((INTEGRAL_TYPE_P (type) + && TYPE_PRECISION (type) <= POINTER_SIZE) + || TREE_CODE (type) == POINTER_TYPE) + use_firstprivate_int = true; + if (has_depend) + { + tree v = lookup_decl_in_outer_ctx (var, ctx); + if (is_reference (v)) + use_firstprivate_int = false; + else if (is_gimple_reg (v)) + { + if (DECL_HAS_VALUE_EXPR_P (v)) + { + v = get_base_address (v); + if (DECL_P (v) && TREE_ADDRESSABLE (v)) + use_firstprivate_int = false; + else + switch (TREE_CODE (v)) + { + case INDIRECT_REF: + case MEM_REF: + use_firstprivate_int = false; + break; + default: + break; + } + } + } + else + use_firstprivate_int = false; + } + if (use_firstprivate_int) + { + x = build_receiver_ref (var, false, ctx); + if (TREE_CODE (type) != POINTER_TYPE) + x = fold_convert (pointer_sized_int_node, x); + x = fold_convert (type, x); + gimplify_expr (&x, &new_body, NULL, is_gimple_val, + fb_rvalue); + if (is_reference (var)) + { + tree v = create_tmp_var_raw (type, get_name (var)); + gimple_add_tmp_var (v); + TREE_ADDRESSABLE (v) = 1; + gimple_seq_add_stmt (&new_body, + gimple_build_assign (v, x)); + x = build_fold_addr_expr (v); + } + gimple_seq_add_stmt (&new_body, + gimple_build_assign (new_var, x)); + } + else + { + x = build_receiver_ref (var, !is_reference (var), ctx); + gimplify_expr (&x, &new_body, NULL, is_gimple_val, + fb_rvalue); + gimple_seq_add_stmt (&new_body, + gimple_build_assign (new_var, x)); + } + } + else if (is_variable_sized (var)) + { + tree pvar = DECL_VALUE_EXPR (var); + gcc_assert (TREE_CODE (pvar) == INDIRECT_REF); + pvar = TREE_OPERAND (pvar, 0); + gcc_assert (DECL_P (pvar)); + tree new_var = lookup_decl (pvar, ctx); + x = build_receiver_ref (var, false, ctx); + gimplify_expr (&x, &new_body, NULL, is_gimple_val, fb_rvalue); + gimple_seq_add_stmt (&new_body, + gimple_build_assign (new_var, x)); + } + break; + case OMP_CLAUSE_PRIVATE: + var = OMP_CLAUSE_DECL (c); + if (is_reference (var)) + { + location_t clause_loc = OMP_CLAUSE_LOCATION (c); + tree new_var = lookup_decl (var, ctx); + x = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (new_var))); + if (TREE_CONSTANT (x)) + { + x = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (new_var)), + get_name (var)); + gimple_add_tmp_var (x); + TREE_ADDRESSABLE (x) = 1; + x = build_fold_addr_expr_loc (clause_loc, x); + } + else + { + tree atmp + = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN); + tree rtype = TREE_TYPE (TREE_TYPE (new_var)); + tree al = size_int (TYPE_ALIGN (rtype)); + x = build_call_expr_loc (clause_loc, atmp, 2, x, al); + } + + x = fold_convert_loc (clause_loc, TREE_TYPE (new_var), x); + gimplify_expr (&x, &new_body, NULL, is_gimple_val, fb_rvalue); + gimple_seq_add_stmt (&new_body, + gimple_build_assign (new_var, x)); + } + break; + case OMP_CLAUSE_USE_DEVICE_PTR: + case OMP_CLAUSE_IS_DEVICE_PTR: + var = OMP_CLAUSE_DECL (c); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_USE_DEVICE_PTR) + x = build_sender_ref (var, ctx); + else + x = build_receiver_ref (var, false, ctx); + if (is_variable_sized (var)) + { + tree pvar = DECL_VALUE_EXPR (var); + gcc_assert (TREE_CODE (pvar) == INDIRECT_REF); + pvar = TREE_OPERAND (pvar, 0); + gcc_assert (DECL_P (pvar)); + tree new_var = lookup_decl (pvar, ctx); + gimplify_expr (&x, &new_body, NULL, is_gimple_val, fb_rvalue); + gimple_seq_add_stmt (&new_body, + gimple_build_assign (new_var, x)); + } + else if (TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE) + { + tree new_var = lookup_decl (var, ctx); + new_var = DECL_VALUE_EXPR (new_var); + gcc_assert (TREE_CODE (new_var) == MEM_REF); + new_var = TREE_OPERAND (new_var, 0); + gcc_assert (DECL_P (new_var)); + gimplify_expr (&x, &new_body, NULL, is_gimple_val, fb_rvalue); + gimple_seq_add_stmt (&new_body, + gimple_build_assign (new_var, x)); + } + else + { + tree type = TREE_TYPE (var); + tree new_var = lookup_decl (var, ctx); + if (is_reference (var)) + { + type = TREE_TYPE (type); + if (TREE_CODE (type) != ARRAY_TYPE) + { + tree v = create_tmp_var_raw (type, get_name (var)); + gimple_add_tmp_var (v); + TREE_ADDRESSABLE (v) = 1; + x = fold_convert (type, x); + gimplify_expr (&x, &new_body, NULL, is_gimple_val, + fb_rvalue); + gimple_seq_add_stmt (&new_body, + gimple_build_assign (v, x)); + x = build_fold_addr_expr (v); + } + } + x = fold_convert (TREE_TYPE (new_var), x); + gimplify_expr (&x, &new_body, NULL, is_gimple_val, fb_rvalue); + gimple_seq_add_stmt (&new_body, + gimple_build_assign (new_var, x)); + } + break; + } + /* Handle GOMP_MAP_FIRSTPRIVATE_POINTER in second pass, + so that firstprivate vars holding OMP_CLAUSE_SIZE if needed + are already handled. */ + for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c)) + switch (OMP_CLAUSE_CODE (c)) + { + tree var; + default: + break; + case OMP_CLAUSE_MAP: + if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER) + { + location_t clause_loc = OMP_CLAUSE_LOCATION (c); + HOST_WIDE_INT offset = 0; + gcc_assert (prev); + var = OMP_CLAUSE_DECL (c); + if (DECL_P (var) + && TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE + && is_global_var (maybe_lookup_decl_in_outer_ctx (var, + ctx)) + && varpool_node::get_create (var)->offloadable) + break; + if (TREE_CODE (var) == INDIRECT_REF + && TREE_CODE (TREE_OPERAND (var, 0)) == COMPONENT_REF) + var = TREE_OPERAND (var, 0); + if (TREE_CODE (var) == COMPONENT_REF) + { + var = get_addr_base_and_unit_offset (var, &offset); + gcc_assert (var != NULL_TREE && DECL_P (var)); + } + else if (DECL_SIZE (var) + && TREE_CODE (DECL_SIZE (var)) != INTEGER_CST) + { + tree var2 = DECL_VALUE_EXPR (var); + gcc_assert (TREE_CODE (var2) == INDIRECT_REF); + var2 = TREE_OPERAND (var2, 0); + gcc_assert (DECL_P (var2)); + var = var2; + } + tree new_var = lookup_decl (var, ctx), x; + tree type = TREE_TYPE (new_var); + bool is_ref; + if (TREE_CODE (OMP_CLAUSE_DECL (c)) == INDIRECT_REF + && (TREE_CODE (TREE_OPERAND (OMP_CLAUSE_DECL (c), 0)) + == COMPONENT_REF)) + { + type = TREE_TYPE (TREE_OPERAND (OMP_CLAUSE_DECL (c), 0)); + is_ref = true; + new_var = build2 (MEM_REF, type, + build_fold_addr_expr (new_var), + build_int_cst (build_pointer_type (type), + offset)); + } + else if (TREE_CODE (OMP_CLAUSE_DECL (c)) == COMPONENT_REF) + { + type = TREE_TYPE (OMP_CLAUSE_DECL (c)); + is_ref = TREE_CODE (type) == REFERENCE_TYPE; + new_var = build2 (MEM_REF, type, + build_fold_addr_expr (new_var), + build_int_cst (build_pointer_type (type), + offset)); + } + else + is_ref = is_reference (var); + bool ref_to_array = false; + if (is_ref) + { + type = TREE_TYPE (type); + if (TREE_CODE (type) == ARRAY_TYPE) + { + type = build_pointer_type (type); + ref_to_array = true; + } + } + else if (TREE_CODE (type) == ARRAY_TYPE) + { + tree decl2 = DECL_VALUE_EXPR (new_var); + gcc_assert (TREE_CODE (decl2) == MEM_REF); + decl2 = TREE_OPERAND (decl2, 0); + gcc_assert (DECL_P (decl2)); + new_var = decl2; + type = TREE_TYPE (new_var); + } + x = build_receiver_ref (OMP_CLAUSE_DECL (prev), false, ctx); + x = fold_convert_loc (clause_loc, type, x); + if (!integer_zerop (OMP_CLAUSE_SIZE (c))) + { + tree bias = OMP_CLAUSE_SIZE (c); + if (DECL_P (bias)) + bias = lookup_decl (bias, ctx); + bias = fold_convert_loc (clause_loc, sizetype, bias); + bias = fold_build1_loc (clause_loc, NEGATE_EXPR, sizetype, + bias); + x = fold_build2_loc (clause_loc, POINTER_PLUS_EXPR, + TREE_TYPE (x), x, bias); + } + if (ref_to_array) + x = fold_convert_loc (clause_loc, TREE_TYPE (new_var), x); + gimplify_expr (&x, &new_body, NULL, is_gimple_val, fb_rvalue); + if (is_ref && !ref_to_array) + { + tree t = create_tmp_var_raw (type, get_name (var)); + gimple_add_tmp_var (t); + TREE_ADDRESSABLE (t) = 1; + gimple_seq_add_stmt (&new_body, + gimple_build_assign (t, x)); + x = build_fold_addr_expr_loc (clause_loc, t); + } + gimple_seq_add_stmt (&new_body, + gimple_build_assign (new_var, x)); + prev = NULL_TREE; + } + else if (OMP_CLAUSE_CHAIN (c) + && OMP_CLAUSE_CODE (OMP_CLAUSE_CHAIN (c)) + == OMP_CLAUSE_MAP + && OMP_CLAUSE_MAP_KIND (OMP_CLAUSE_CHAIN (c)) + == GOMP_MAP_FIRSTPRIVATE_POINTER) + prev = c; + break; + case OMP_CLAUSE_PRIVATE: + var = OMP_CLAUSE_DECL (c); + if (is_variable_sized (var)) + { + location_t clause_loc = OMP_CLAUSE_LOCATION (c); + tree new_var = lookup_decl (var, ctx); + tree pvar = DECL_VALUE_EXPR (var); + gcc_assert (TREE_CODE (pvar) == INDIRECT_REF); + pvar = TREE_OPERAND (pvar, 0); + gcc_assert (DECL_P (pvar)); + tree new_pvar = lookup_decl (pvar, ctx); + tree atmp = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN); + tree al = size_int (DECL_ALIGN (var)); + tree x = TYPE_SIZE_UNIT (TREE_TYPE (new_var)); + x = build_call_expr_loc (clause_loc, atmp, 2, x, al); + x = fold_convert_loc (clause_loc, TREE_TYPE (new_pvar), x); + gimplify_expr (&x, &new_body, NULL, is_gimple_val, fb_rvalue); + gimple_seq_add_stmt (&new_body, + gimple_build_assign (new_pvar, x)); + } + break; + } gimple_seq_add_seq (&new_body, tgt_body); - new_body = maybe_catch_exception (new_body); + if (offloaded) + new_body = maybe_catch_exception (new_body); } else if (data_region) new_body = tgt_body; @@ -11836,7 +15034,7 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) bind = gimple_build_bind (NULL, NULL, tgt_bind ? gimple_bind_block (tgt_bind) : NULL_TREE); - gsi_replace (gsi_p, bind, true); + gsi_replace (gsi_p, dep_bind ? dep_bind : bind, true); gimple_bind_add_seq (bind, irlist); gimple_bind_add_seq (bind, ilist); gimple_bind_add_stmt (bind, stmt); @@ -11844,6 +15042,14 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) gimple_bind_add_seq (bind, orlist); pop_gimplify_context (NULL); + + if (dep_bind) + { + gimple_bind_add_seq (dep_bind, dep_ilist); + gimple_bind_add_stmt (dep_bind, bind); + gimple_bind_add_seq (dep_bind, dep_olist); + pop_gimplify_context (dep_bind); + } } /* Expand code for an OpenMP teams directive. */ @@ -11935,10 +15141,73 @@ lower_omp_regimplify_p (tree *tp, int *walk_subtrees, if (data == NULL && TREE_CODE (t) == ADDR_EXPR) recompute_tree_invariant_for_addr_expr (t); - *walk_subtrees = !TYPE_P (t) && !DECL_P (t); + *walk_subtrees = !IS_TYPE_OR_DECL_P (t); + return NULL_TREE; +} + +/* Data to be communicated between lower_omp_regimplify_operands and + lower_omp_regimplify_operands_p. */ + +struct lower_omp_regimplify_operands_data +{ + omp_context *ctx; + vec *decls; +}; + +/* Helper function for lower_omp_regimplify_operands. Find + omp_member_access_dummy_var vars and adjust temporarily their + DECL_VALUE_EXPRs if needed. */ + +static tree +lower_omp_regimplify_operands_p (tree *tp, int *walk_subtrees, + void *data) +{ + tree t = omp_member_access_dummy_var (*tp); + if (t) + { + struct walk_stmt_info *wi = (struct walk_stmt_info *) data; + lower_omp_regimplify_operands_data *ldata + = (lower_omp_regimplify_operands_data *) wi->info; + tree o = maybe_lookup_decl (t, ldata->ctx); + if (o != t) + { + ldata->decls->safe_push (DECL_VALUE_EXPR (*tp)); + ldata->decls->safe_push (*tp); + tree v = unshare_and_remap (DECL_VALUE_EXPR (*tp), t, o); + SET_DECL_VALUE_EXPR (*tp, v); + } + } + *walk_subtrees = !IS_TYPE_OR_DECL_P (*tp); return NULL_TREE; } +/* Wrapper around gimple_regimplify_operands that adjusts DECL_VALUE_EXPRs + of omp_member_access_dummy_var vars during regimplification. */ + +static void +lower_omp_regimplify_operands (omp_context *ctx, gimple *stmt, + gimple_stmt_iterator *gsi_p) +{ + auto_vec decls; + if (ctx) + { + struct walk_stmt_info wi; + memset (&wi, '\0', sizeof (wi)); + struct lower_omp_regimplify_operands_data data; + data.ctx = ctx; + data.decls = &decls; + wi.info = &data; + walk_gimple_op (stmt, lower_omp_regimplify_operands_p, &wi); + } + gimple_regimplify_operands (stmt, gsi_p); + while (!decls.is_empty ()) + { + tree t = decls.pop (); + tree v = decls.pop (); + SET_DECL_VALUE_EXPR (t, v); + } +} + static void lower_omp_1 (gimple_stmt_iterator *gsi_p, omp_context *ctx) { @@ -11973,7 +15242,7 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p, omp_context *ctx) || walk_tree (gimple_cond_rhs_ptr (cond_stmt), lower_omp_regimplify_p, ctx ? NULL : &wi, NULL))) - gimple_regimplify_operands (cond_stmt, gsi_p); + lower_omp_regimplify_operands (ctx, cond_stmt, gsi_p); } break; case GIMPLE_CATCH: @@ -12046,7 +15315,7 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p, omp_context *ctx) && walk_tree (gimple_omp_atomic_load_rhs_ptr ( as_a (stmt)), lower_omp_regimplify_p, ctx ? NULL : &wi, NULL)) - gimple_regimplify_operands (stmt, gsi_p); + lower_omp_regimplify_operands (ctx, stmt, gsi_p); break; case GIMPLE_OMP_TARGET: ctx = maybe_lookup_ctx (stmt); @@ -12127,7 +15396,7 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p, omp_context *ctx) gsi_replace (gsi_p, gimple_build_nop (), true); break; } - gimple_regimplify_operands (stmt, gsi_p); + lower_omp_regimplify_operands (ctx, stmt, gsi_p); } break; } @@ -12502,13 +15771,21 @@ make_gimple_omp_edges (basic_block bb, struct omp_region **region, case GIMPLE_OMP_TEAMS: case GIMPLE_OMP_MASTER: case GIMPLE_OMP_TASKGROUP: - case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_CRITICAL: case GIMPLE_OMP_SECTION: cur_region = new_omp_region (bb, code, cur_region); fallthru = true; break; + case GIMPLE_OMP_ORDERED: + cur_region = new_omp_region (bb, code, cur_region); + fallthru = true; + if (find_omp_clause (gimple_omp_ordered_clauses + (as_a (last)), + OMP_CLAUSE_DEPEND)) + cur_region = cur_region->outer; + break; + case GIMPLE_OMP_TARGET: cur_region = new_omp_region (bb, code, cur_region); fallthru = true; @@ -12521,6 +15798,8 @@ make_gimple_omp_edges (basic_block bb, struct omp_region **region, case GF_OMP_TARGET_KIND_OACC_DATA: break; case GF_OMP_TARGET_KIND_UPDATE: + case GF_OMP_TARGET_KIND_ENTER_DATA: + case GF_OMP_TARGET_KIND_EXIT_DATA: case GF_OMP_TARGET_KIND_OACC_UPDATE: case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA: cur_region = cur_region->outer; @@ -12826,8 +16105,29 @@ simd_clone_clauses_extract (struct cgraph_node *node, tree clauses, } else { - clone_info->args[argno].arg_type - = SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP; + enum cgraph_simd_clone_arg_type arg_type; + if (TREE_CODE (args[argno]) == REFERENCE_TYPE) + switch (OMP_CLAUSE_LINEAR_KIND (t)) + { + case OMP_CLAUSE_LINEAR_REF: + arg_type + = SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP; + break; + case OMP_CLAUSE_LINEAR_UVAL: + arg_type + = SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP; + break; + case OMP_CLAUSE_LINEAR_VAL: + case OMP_CLAUSE_LINEAR_DEFAULT: + arg_type + = SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP; + break; + default: + gcc_unreachable (); + } + else + arg_type = SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP; + clone_info->args[argno].arg_type = arg_type; clone_info->args[argno].linear_step = tree_to_shwi (step); } } @@ -12929,12 +16229,25 @@ simd_clone_mangle (struct cgraph_node *node, { struct cgraph_simd_clone_arg arg = clone_info->args[n]; - if (arg.arg_type == SIMD_CLONE_ARG_TYPE_UNIFORM) - pp_character (&pp, 'u'); - else if (arg.arg_type == SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP) + switch (arg.arg_type) { - gcc_assert (arg.linear_step != 0); + case SIMD_CLONE_ARG_TYPE_UNIFORM: + pp_character (&pp, 'u'); + break; + case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP: pp_character (&pp, 'l'); + goto mangle_linear; + case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP: + pp_character (&pp, 'R'); + goto mangle_linear; + case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP: + pp_character (&pp, 'L'); + goto mangle_linear; + case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP: + pp_character (&pp, 'U'); + goto mangle_linear; + mangle_linear: + gcc_assert (arg.linear_step != 0); if (arg.linear_step > 1) pp_unsigned_wide_integer (&pp, arg.linear_step); else if (arg.linear_step < 0) @@ -12943,14 +16256,14 @@ simd_clone_mangle (struct cgraph_node *node, pp_unsigned_wide_integer (&pp, (-(unsigned HOST_WIDE_INT) arg.linear_step)); } - } - else if (arg.arg_type == SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP) - { + break; + case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP: pp_character (&pp, 's'); pp_unsigned_wide_integer (&pp, arg.linear_step); + break; + default: + pp_character (&pp, 'v'); } - else - pp_character (&pp, 'v'); if (arg.alignment) { pp_character (&pp, 'a'); @@ -13128,13 +16441,22 @@ simd_clone_adjust_argument_types (struct cgraph_node *node) node->simdclone->args[i].orig_arg = node->definition ? parm : NULL_TREE; node->simdclone->args[i].orig_type = parm_type; - if (node->simdclone->args[i].arg_type != SIMD_CLONE_ARG_TYPE_VECTOR) + switch (node->simdclone->args[i].arg_type) { + default: /* No adjustment necessary for scalar arguments. */ adj.op = IPA_PARM_OP_COPY; - } - else - { + break; + case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP: + if (node->definition) + node->simdclone->args[i].simd_array + = create_tmp_simd_array (IDENTIFIER_POINTER (DECL_NAME (parm)), + TREE_TYPE (parm_type), + node->simdclone->simdlen); + adj.op = IPA_PARM_OP_COPY; + break; + case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP: + case SIMD_CLONE_ARG_TYPE_VECTOR: if (INTEGRAL_TYPE_P (parm_type) || POINTER_TYPE_P (parm_type)) veclen = node->simdclone->vecsize_int; else @@ -13266,7 +16588,8 @@ simd_clone_init_simd_arrays (struct cgraph_node *node, arg; arg = DECL_CHAIN (arg), i++, j++) { - if (adjustments[j].op == IPA_PARM_OP_COPY) + if (adjustments[j].op == IPA_PARM_OP_COPY + || POINTER_TYPE_P (TREE_TYPE (arg))) continue; node->simdclone->args[i].vector_arg = arg; @@ -13756,8 +17079,10 @@ simd_clone_adjust (struct cgraph_node *node) SET_USE (use_p, repl); } } - else if (node->simdclone->args[i].arg_type - == SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP) + else if ((node->simdclone->args[i].arg_type + == SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP) + || (node->simdclone->args[i].arg_type + == SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP)) { tree orig_arg = node->simdclone->args[i].orig_arg; gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (orig_arg)) @@ -13816,6 +17141,78 @@ simd_clone_adjust (struct cgraph_node *node) SET_USE (use_p, iter1); } } + else if (node->simdclone->args[i].arg_type + == SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP) + { + tree orig_arg = node->simdclone->args[i].orig_arg; + tree def = ssa_default_def (cfun, orig_arg); + gcc_assert (!TREE_ADDRESSABLE (orig_arg) + && TREE_CODE (TREE_TYPE (orig_arg)) == REFERENCE_TYPE); + if (def && !has_zero_uses (def)) + { + tree rtype = TREE_TYPE (TREE_TYPE (orig_arg)); + iter1 = make_ssa_name (orig_arg); + iter2 = make_ssa_name (orig_arg); + tree iter3 = make_ssa_name (rtype); + tree iter4 = make_ssa_name (rtype); + tree iter5 = make_ssa_name (rtype); + gsi = gsi_after_labels (entry_bb); + gimple *load + = gimple_build_assign (iter3, build_simple_mem_ref (def)); + gsi_insert_before (&gsi, load, GSI_NEW_STMT); + + tree array = node->simdclone->args[i].simd_array; + TREE_ADDRESSABLE (array) = 1; + tree ptr = build_fold_addr_expr (array); + phi = create_phi_node (iter1, body_bb); + add_phi_arg (phi, ptr, preheader_edge, UNKNOWN_LOCATION); + add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION); + g = gimple_build_assign (iter2, POINTER_PLUS_EXPR, iter1, + TYPE_SIZE_UNIT (TREE_TYPE (iter3))); + gsi = gsi_last_bb (incr_bb); + gsi_insert_before (&gsi, g, GSI_SAME_STMT); + + phi = create_phi_node (iter4, body_bb); + add_phi_arg (phi, iter3, preheader_edge, UNKNOWN_LOCATION); + add_phi_arg (phi, iter5, latch_edge, UNKNOWN_LOCATION); + enum tree_code code = INTEGRAL_TYPE_P (TREE_TYPE (iter3)) + ? PLUS_EXPR : POINTER_PLUS_EXPR; + tree addtype = INTEGRAL_TYPE_P (TREE_TYPE (iter3)) + ? TREE_TYPE (iter3) : sizetype; + tree addcst + = build_int_cst (addtype, node->simdclone->args[i].linear_step); + g = gimple_build_assign (iter5, code, iter4, addcst); + gsi = gsi_last_bb (incr_bb); + gsi_insert_before (&gsi, g, GSI_SAME_STMT); + + g = gimple_build_assign (build_simple_mem_ref (iter1), iter4); + gsi = gsi_after_labels (body_bb); + gsi_insert_before (&gsi, g, GSI_SAME_STMT); + + imm_use_iterator iter; + use_operand_p use_p; + gimple *use_stmt; + FOR_EACH_IMM_USE_STMT (use_stmt, iter, def) + if (use_stmt == load) + continue; + else + FOR_EACH_IMM_USE_ON_STMT (use_p, iter) + SET_USE (use_p, iter1); + + if (!TYPE_READONLY (rtype)) + { + tree v = make_ssa_name (rtype); + tree aref = build4 (ARRAY_REF, rtype, array, + size_zero_node, NULL_TREE, + NULL_TREE); + gsi = gsi_after_labels (new_exit_bb); + g = gimple_build_assign (v, aref); + gsi_insert_before (&gsi, g, GSI_SAME_STMT); + g = gimple_build_assign (build_simple_mem_ref (def), v); + gsi_insert_before (&gsi, g, GSI_SAME_STMT); + } + } + } calculate_dominance_info (CDI_DOMINATORS); add_loop (loop, loop->header->loop_father); diff --git a/gcc/omp-low.h b/gcc/omp-low.h index 4730815bba3..2fb2028f6cf 100644 --- a/gcc/omp-low.h +++ b/gcc/omp-low.h @@ -29,6 +29,7 @@ extern tree omp_reduction_init_op (location_t, enum tree_code, tree); extern tree omp_reduction_init (tree, tree); extern bool make_gimple_omp_edges (basic_block, struct omp_region **, int *); extern void omp_finish_file (void); +extern tree omp_member_access_dummy_var (tree); extern tree get_oacc_fn_attrib (tree); extern GTY(()) vec *offload_funcs; diff --git a/gcc/passes.def b/gcc/passes.def index 28dea9e4b10..dc3f44c122c 100644 --- a/gcc/passes.def +++ b/gcc/passes.def @@ -341,6 +341,7 @@ along with GCC; see the file COPYING3. If not see NEXT_PASS (pass_tm_memopt); NEXT_PASS (pass_tm_edges); POP_INSERT_PASSES () + NEXT_PASS (pass_simduid_cleanup); NEXT_PASS (pass_vtable_verify); NEXT_PASS (pass_lower_vaarg); NEXT_PASS (pass_lower_vector); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e8ead84ac8e..c4fd225d4a0 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,78 @@ +2015-10-13 Jakub Jelinek + Aldy Hernandez + + * c-c++-common/gomp/cancel-1.c (f2): Add map clause to target data. + * c-c++-common/gomp/clauses-1.c: New test. + * c-c++-common/gomp/clauses-2.c: New test. + * c-c++-common/gomp/clauses-3.c: New test. + * c-c++-common/gomp/clauses-4.c: New test. + * c-c++-common/gomp/declare-target-1.c: New test. + * c-c++-common/gomp/declare-target-2.c: New test. + * c-c++-common/gomp/depend-3.c: New test. + * c-c++-common/gomp/depend-4.c: New test. + * c-c++-common/gomp/doacross-1.c: New test. + * c-c++-common/gomp/if-1.c: New test. + * c-c++-common/gomp/if-2.c: New test. + * c-c++-common/gomp/linear-1.c: New test. + * c-c++-common/gomp/map-2.c: New test. + * c-c++-common/gomp/map-3.c: New test. + * c-c++-common/gomp/nesting-1.c (f_omp_parallel, + f_omp_target_data): Add map clause to target data. + * c-c++-common/gomp/nesting-warn-1.c (f_omp_target): Likewise. + * c-c++-common/gomp/ordered-1.c: New test. + * c-c++-common/gomp/ordered-2.c: New test. + * c-c++-common/gomp/ordered-3.c: New test. + * c-c++-common/gomp/pr61486-1.c (foo): Remove linear clause + on non-iterator. + * c-c++-common/gomp/pr61486-2.c (test, test2): Remove ordered + clause and ordered construct where no longer allowed. + * c-c++-common/gomp/priority-1.c: New test. + * c-c++-common/gomp/reduction-1.c: New test. + * c-c++-common/gomp/schedule-simd-1.c: New test. + * c-c++-common/gomp/sink-1.c: New test. + * c-c++-common/gomp/sink-2.c: New test. + * c-c++-common/gomp/sink-3.c: New test. + * c-c++-common/gomp/sink-4.c: New test. + * c-c++-common/gomp/udr-1.c: New test. + * c-c++-common/taskloop-1.c: New test. + * c-c++-common/cpp/openmp-define-3.c: Adjust for the new + value of _OPENMP macro. + * c-c++-common/cilk-plus/PS/body.c (foo): Adjust expected diagnostics. + * c-c++-common/goacc-gomp/nesting-fail-1.c (f_acc_parallel, + f_acc_kernels, f_acc_data, f_acc_loop): Add map clause to target data. + * gcc.dg/gomp/clause-1.c: + * gcc.dg/gomp/reduction-1.c: New test. + * gcc.dg/gomp/sink-fold-1.c: New test. + * gcc.dg/gomp/sink-fold-2.c: New test. + * gcc.dg/gomp/sink-fold-3.c: New test. + * gcc.dg/vect/vect-simd-clone-15.c: New test. + * g++.dg/gomp/clause-1.C (T::test): Remove dg-error on privatization + of non-static data members. + * g++.dg/gomp/clause-3.C (foo): Remove one dg-error directive. + Add some linear clause tests. + * g++.dg/gomp/declare-simd-3.C: New test. + * g++.dg/gomp/linear-1.C: New test. + * g++.dg/gomp/member-1.C: New test. + * g++.dg/gomp/member-2.C: New test. + * g++.dg/gomp/pr66571-2.C: New test. + * g++.dg/gomp/pr67504.C (foo): Add test for ordered clause with + dependent argument. + * g++.dg/gomp/pr67522.C (foo): Add test for invalid array section + in reduction clause. + * g++.dg/gomp/reference-1.C: New test. + * g++.dg/gomp/sink-1.C: New test. + * g++.dg/gomp/sink-2.C: New test. + * g++.dg/gomp/sink-3.C: New test. + * g++.dg/gomp/task-1.C: Remove both dg-error directives. + * g++.dg/gomp/this-1.C: New test. + * g++.dg/gomp/this-2.C: New test. + * g++.dg/vect/simd-clone-2.cc: New test. + * g++.dg/vect/simd-clone-2.h: New test. + * g++.dg/vect/simd-clone-3.cc: New test. + * g++.dg/vect/simd-clone-4.cc: New test. + * g++.dg/vect/simd-clone-4.h: New test. + * g++.dg/vect/simd-clone-5.cc: New test. + 2015-10-13 Christophe Lyon * gcc/testsuite/gcc.target/aarch64/table-intrinsics.c: Fix regexp diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/body.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/body.c index 82c0a0c20bf..ed85a7a65eb 100644 --- a/gcc/testsuite/c-c++-common/cilk-plus/PS/body.c +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/body.c @@ -27,7 +27,7 @@ void foo() #pragma simd for (int i=0; i < 1000; ++i) { -#pragma omp for /* { dg-error "OpenMP constructs may not" } */ +#pragma omp for /* { dg-error "OpenMP constructs other than" } */ for (j=0; j < 1000; ++j) a[i] = b[i]; } diff --git a/gcc/testsuite/c-c++-common/cpp/openmp-define-3.c b/gcc/testsuite/c-c++-common/cpp/openmp-define-3.c index 6986c5507b9..ef283d4e7ce 100644 --- a/gcc/testsuite/c-c++-common/cpp/openmp-define-3.c +++ b/gcc/testsuite/c-c++-common/cpp/openmp-define-3.c @@ -6,6 +6,6 @@ # error _OPENMP not defined #endif -#if _OPENMP != 201307 +#if _OPENMP != 201511 # error _OPENMP defined to wrong value #endif diff --git a/gcc/testsuite/c-c++-common/goacc-gomp/nesting-fail-1.c b/gcc/testsuite/c-c++-common/goacc-gomp/nesting-fail-1.c index 411fb5f8755..ac614e7d646 100644 --- a/gcc/testsuite/c-c++-common/goacc-gomp/nesting-fail-1.c +++ b/gcc/testsuite/c-c++-common/goacc-gomp/nesting-fail-1.c @@ -230,7 +230,7 @@ f_acc_parallel (void) { #pragma omp target /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ ; -#pragma omp target data /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ +#pragma omp target data map(i) /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ ; #pragma omp target update to(i) /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ } @@ -300,7 +300,7 @@ f_acc_kernels (void) { #pragma omp target /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ ; -#pragma omp target data /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ +#pragma omp target data map(i) /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ ; #pragma omp target update to(i) /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ } @@ -370,7 +370,7 @@ f_acc_data (void) { #pragma omp target /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ ; -#pragma omp target data /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ +#pragma omp target data map(i) /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ ; #pragma omp target update to(i) /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ } @@ -450,7 +450,7 @@ f_acc_loop (void) { #pragma omp target /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ ; -#pragma omp target data /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ +#pragma omp target data map(i) /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ ; #pragma omp target update to(i) /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ } diff --git a/gcc/testsuite/c-c++-common/gomp/cancel-1.c b/gcc/testsuite/c-c++-common/gomp/cancel-1.c index d8f7bc1b8fa..13de881d049 100644 --- a/gcc/testsuite/c-c++-common/gomp/cancel-1.c +++ b/gcc/testsuite/c-c++-common/gomp/cancel-1.c @@ -17,7 +17,7 @@ f1 (void) void f2 (void) { - int i; + int i, j = 0; #pragma omp parallel { #pragma omp cancel parallel @@ -132,7 +132,7 @@ f2 (void) #pragma omp cancellation point taskgroup/* { dg-error "not closely nested inside" } */ } } - #pragma omp target data + #pragma omp target data map(j) { #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */ #pragma omp cancel for /* { dg-error "not closely nested inside" } */ @@ -155,7 +155,7 @@ f2 (void) #pragma omp cancellation point taskgroup /* { dg-error "not closely nested inside" } */ } } - #pragma omp target data + #pragma omp target data map(j) { #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */ #pragma omp cancel for /* { dg-error "not closely nested inside" } */ @@ -214,7 +214,7 @@ f2 (void) } #pragma omp for for (i = 0; i < 10; i++) - #pragma omp target data + #pragma omp target data map(j) { #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */ #pragma omp cancel for /* { dg-error "not closely nested inside" } */ @@ -241,7 +241,7 @@ f2 (void) #pragma omp for ordered for (i = 0; i < 10; i++) #pragma omp ordered - #pragma omp target data + #pragma omp target data map(j) { #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */ #pragma omp cancel for /* { dg-error "not closely nested inside" } */ @@ -292,7 +292,7 @@ f2 (void) } #pragma omp sections { - #pragma omp target data + #pragma omp target data map(j) { #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */ #pragma omp cancel for /* { dg-error "not closely nested inside" } */ @@ -304,7 +304,7 @@ f2 (void) #pragma omp cancellation point taskgroup /* { dg-error "not closely nested inside" } */ } #pragma omp section - #pragma omp target data + #pragma omp target data map(j) { #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */ #pragma omp cancel for /* { dg-error "not closely nested inside" } */ diff --git a/gcc/testsuite/c-c++-common/gomp/clauses-1.c b/gcc/testsuite/c-c++-common/gomp/clauses-1.c new file mode 100644 index 00000000000..2d1c352a3f2 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/clauses-1.c @@ -0,0 +1,162 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ +/* { dg-additional-options "-std=c99" { target c } } */ + +int t; +#pragma omp threadprivate (t) + +#pragma omp declare target +int f, l, ll, r; + +void +foo (int d, int m, int i1, int i2, int p, int *idp, int s, + int nte, int tl, int nth, int g, int nta, int fi, int pp, int *q) +{ + #pragma omp distribute parallel for \ + private (p) firstprivate (f) collapse(1) dist_schedule(static, 16) \ + if (parallel: i2) default(shared) shared(s) reduction(+:r) num_threads (nth) proc_bind(spread) \ + lastprivate (l) schedule(static, 4) + for (int i = 0; i < 64; i++) + ll++; + #pragma omp distribute parallel for simd \ + private (p) firstprivate (f) collapse(1) dist_schedule(static, 16) \ + if (parallel: i2) default(shared) shared(s) reduction(+:r) num_threads (nth) proc_bind(spread) \ + lastprivate (l) schedule(static, 4) \ + safelen(8) simdlen(4) aligned(q: 32) + for (int i = 0; i < 64; i++) + ll++; + #pragma omp distribute simd \ + private (p) firstprivate (f) collapse(1) dist_schedule(static, 16) \ + safelen(8) simdlen(4) aligned(q: 32) reduction(+:r) + for (int i = 0; i < 64; i++) + ll++; +} +#pragma omp end declare target + +void +bar (int d, int m, int i1, int i2, int p, int *idp, int s, + int nte, int tl, int nth, int g, int nta, int fi, int pp, int *q) +{ + #pragma omp for simd \ + private (p) firstprivate (f) lastprivate (l) linear (ll:1) reduction(+:r) schedule(static, 4) collapse(1) nowait \ + safelen(8) simdlen(4) aligned(q: 32) + for (int i = 0; i < 64; i++) + ll++; + #pragma omp parallel for \ + private (p) firstprivate (f) if (parallel: i2) default(shared) shared(s) copyin(t) reduction(+:r) num_threads (nth) proc_bind(spread) \ + lastprivate (l) linear (ll:1) ordered schedule(static, 4) collapse(1) + for (int i = 0; i < 64; i++) + ll++; + #pragma omp parallel for simd \ + private (p) firstprivate (f) if (parallel: i2) default(shared) shared(s) copyin(t) reduction(+:r) num_threads (nth) proc_bind(spread) \ + lastprivate (l) linear (ll:1) schedule(static, 4) collapse(1) \ + safelen(8) simdlen(4) aligned(q: 32) + for (int i = 0; i < 64; i++) + ll++; + #pragma omp parallel sections \ + private (p) firstprivate (f) if (parallel: i2) default(shared) shared(s) copyin(t) reduction(+:r) num_threads (nth) proc_bind(spread) \ + lastprivate (l) + { + #pragma omp section + {} + #pragma omp section + {} + } + #pragma omp target parallel \ + device(d) map (tofrom: m) if (target: i1) private (p) firstprivate (f) defaultmap(tofrom: scalar) is_device_ptr (idp) \ + if (parallel: i2) default(shared) shared(s) reduction(+:r) num_threads (nth) proc_bind(spread) + ; + #pragma omp target parallel for \ + device(d) map (tofrom: m) if (target: i1) private (p) firstprivate (f) defaultmap(tofrom: scalar) is_device_ptr (idp) \ + if (parallel: i2) default(shared) shared(s) reduction(+:r) num_threads (nth) proc_bind(spread) \ + lastprivate (l) linear (ll:1) ordered schedule(static, 4) collapse(1) + for (int i = 0; i < 64; i++) + ll++; + #pragma omp target parallel for simd \ + device(d) map (tofrom: m) if (target: i1) private (p) firstprivate (f) defaultmap(tofrom: scalar) is_device_ptr (idp) \ + if (parallel: i2) default(shared) shared(s) reduction(+:r) num_threads (nth) proc_bind(spread) \ + lastprivate (l) linear (ll:1) schedule(static, 4) collapse(1) \ + safelen(8) simdlen(4) aligned(q: 32) + for (int i = 0; i < 64; i++) + ll++; + #pragma omp target teams \ + device(d) map (tofrom: m) if (target: i1) private (p) firstprivate (f) defaultmap(tofrom: scalar) is_device_ptr (idp) \ + shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) + ; + #pragma omp target teams distribute \ + device(d) map (tofrom: m) if (target: i1) private (p) firstprivate (f) defaultmap(tofrom: scalar) is_device_ptr (idp) \ + shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) \ + collapse(1) dist_schedule(static, 16) + for (int i = 0; i < 64; i++) + ; + #pragma omp target teams distribute parallel for \ + device(d) map (tofrom: m) if (target: i1) private (p) firstprivate (f) defaultmap(tofrom: scalar) is_device_ptr (idp) \ + shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) \ + collapse(1) dist_schedule(static, 16) \ + if (parallel: i2) num_threads (nth) proc_bind(spread) \ + lastprivate (l) schedule(static, 4) + for (int i = 0; i < 64; i++) + ll++; + #pragma omp target teams distribute parallel for simd \ + device(d) map (tofrom: m) if (target: i1) private (p) firstprivate (f) defaultmap(tofrom: scalar) is_device_ptr (idp) \ + shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) \ + collapse(1) dist_schedule(static, 16) \ + if (parallel: i2) num_threads (nth) proc_bind(spread) \ + lastprivate (l) schedule(static, 4) \ + safelen(8) simdlen(4) aligned(q: 32) + for (int i = 0; i < 64; i++) + ll++; + #pragma omp target teams distribute simd \ + device(d) map (tofrom: m) if (target: i1) private (p) firstprivate (f) defaultmap(tofrom: scalar) is_device_ptr (idp) \ + shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) \ + collapse(1) dist_schedule(static, 16) \ + safelen(8) simdlen(4) aligned(q: 32) + for (int i = 0; i < 64; i++) + ll++; + #pragma omp target simd \ + device(d) map (tofrom: m) if (target: i1) private (p) firstprivate (f) defaultmap(tofrom: scalar) is_device_ptr (idp) \ + safelen(8) simdlen(4) lastprivate (l) linear(ll: 1) aligned(q: 32) reduction(+:r) + for (int i = 0; i < 64; i++) + ll++; + #pragma omp taskloop simd \ + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable nogroup priority (pp) \ + safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(+:r) + for (int i = 0; i < 64; i++) + ll++; + #pragma omp taskwait + #pragma omp taskloop simd \ + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) if(taskloop: i1) final(fi) priority (pp) \ + safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(+:r) + for (int i = 0; i < 64; i++) + ll++; + #pragma omp target + #pragma omp teams distribute \ + private(p) firstprivate (f) shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) \ + collapse(1) dist_schedule(static, 16) + for (int i = 0; i < 64; i++) + ; + #pragma omp target + #pragma omp teams distribute parallel for \ + private(p) firstprivate (f) shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) \ + collapse(1) dist_schedule(static, 16) \ + if (parallel: i2) num_threads (nth) proc_bind(spread) \ + lastprivate (l) schedule(static, 4) + for (int i = 0; i < 64; i++) + ll++; + #pragma omp target + #pragma omp teams distribute parallel for simd \ + private(p) firstprivate (f) shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) \ + collapse(1) dist_schedule(static, 16) \ + if (parallel: i2) num_threads (nth) proc_bind(spread) \ + lastprivate (l) schedule(static, 4) \ + safelen(8) simdlen(4) aligned(q: 32) + for (int i = 0; i < 64; i++) + ll++; + #pragma omp target + #pragma omp teams distribute simd \ + private(p) firstprivate (f) shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) \ + collapse(1) dist_schedule(static, 16) \ + safelen(8) simdlen(4) aligned(q: 32) + for (int i = 0; i < 64; i++) + ll++; +} diff --git a/gcc/testsuite/c-c++-common/gomp/clauses-2.c b/gcc/testsuite/c-c++-common/gomp/clauses-2.c new file mode 100644 index 00000000000..6e136bacc53 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/clauses-2.c @@ -0,0 +1,53 @@ +struct S { int r; int *s; int t[10]; }; +void bar (int *); + +void +foo (int *p, int q, struct S t, int i, int j, int k, int l) +{ + #pragma omp target map (q), firstprivate (q) + bar (&q); + #pragma omp target map (p[0]) firstprivate (p) /* { dg-error "appears more than once in data clauses" } */ + bar (p); + #pragma omp target firstprivate (p), map (p[0]) /* { dg-error "appears more than once in data clauses" } */ + bar (p); + #pragma omp target map (p[0]) map (p) + bar (p); + #pragma omp target map (p) , map (p[0]) + bar (p); + #pragma omp target map (q) map (q) /* { dg-error "appears more than once in map clauses" } */ + bar (&q); + #pragma omp target map (p[0]) map (p[0]) /* { dg-error "appears more than once in data clauses" } */ + bar (p); + #pragma omp target map (t) map (t.r) /* { dg-error "appears more than once in map clauses" } */ + bar (&t.r); + #pragma omp target map (t.r) map (t) /* { dg-error "appears more than once in map clauses" } */ + bar (&t.r); + #pragma omp target map (t.r) map (t.r) /* { dg-error "appears more than once in map clauses" } */ + bar (&t.r); + #pragma omp target firstprivate (t), map (t.r) + bar (&t.r); + #pragma omp target map (t.r) firstprivate (t) + bar (&t.r); + #pragma omp target map (t.s[0]) map (t) + bar (t.s); + #pragma omp target map (t) map(t.s[0]) + bar (t.s); + #pragma omp target firstprivate (t) map (t.s[0]) /* { dg-error "appears more than once in data clauses" } */ + bar (t.s); + #pragma omp target map (t.s[0]) firstprivate (t) /* { dg-error "appears more than once in data clauses" } */ + bar (t.s); + #pragma omp target map (t.s[0]) map (t.s[2]) /* { dg-error "appears more than once in map clauses" } */ + bar (t.s); + #pragma omp target map (t.t[0:2]) map (t.t[4:6]) /* { dg-error "appears more than once in map clauses" } */ + bar (t.t); + #pragma omp target map (t.t[i:j]) map (t.t[k:l]) /* { dg-error "appears more than once in map clauses" } */ + bar (t.t); + #pragma omp target map (t.s[0]) map (t.r) + bar (t.s); + #pragma omp target map (t.r) ,map (t.s[0]) + bar (t.s); + #pragma omp target map (t.r) map (t) map (t.s[0]) firstprivate (t) /* { dg-error "appears more than once in map clauses" } */ + bar (t.s); /* { dg-error "appears more than once in data clauses" "" { target *-*-* } 49 } */ + #pragma omp target map (t) map (t.r) firstprivate (t) map (t.s[0]) /* { dg-error "appears more than once in map clauses" } */ + bar (t.s); /* { dg-error "appears more than once in data clauses" "" { target *-*-* } 51 } */ +} diff --git a/gcc/testsuite/c-c++-common/gomp/clauses-3.c b/gcc/testsuite/c-c++-common/gomp/clauses-3.c new file mode 100644 index 00000000000..7e07a81c319 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/clauses-3.c @@ -0,0 +1,23 @@ +struct T { int a; int *b; }; +struct S { int *s; char u; struct T v; long x; }; + +void bar (int *); +#pragma omp declare target to (bar) + +int +main () +{ + int a[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + struct S s = { a, 5, { 6, a + 5 }, 99L }; + #pragma omp target map (s.v.a, s.u, s.x) + ; + #pragma omp target map (s.v.a, s.u, s.x) + bar (&s.v.a); + #pragma omp target map (s.v.a) map (always, to: s.u) map (s.x) + ; + #pragma omp target map (s.s[0]) map (s.v.b[:3]) + ; + #pragma omp target map (s.s[0]) map (s.v.b[:3]) + bar (s.s); + return 0; +} diff --git a/gcc/testsuite/c-c++-common/gomp/clauses-4.c b/gcc/testsuite/c-c++-common/gomp/clauses-4.c new file mode 100644 index 00000000000..104b129a9aa --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/clauses-4.c @@ -0,0 +1,96 @@ +int t; +#pragma omp threadprivate (t) + +void +foo (int y, short z) +{ + int x; + #pragma omp target teams map (from: x) + #pragma omp distribute simd linear (x : 2) + for (x = 0; x < 64; x += 2) + ; + #pragma omp target teams map (from: x) + #pragma omp distribute parallel for simd linear (x) + for (x = 0; x < 64; x++) + ; + #pragma omp target teams map (tofrom: y) + #pragma omp distribute simd linear (y : 2) /* { dg-error ".linear. clause for variable other than loop iterator specified on construct combined with .distribute." } */ + for (x = 0; x < 64; x += 2) + y += 2; + #pragma omp target teams map (tofrom: z) + #pragma omp distribute parallel for simd linear (z) /* { dg-error ".linear. clause for variable other than loop iterator specified on construct combined with .distribute." } */ + for (x = 0; x < 64; x++) + z++; + #pragma omp target teams map (tofrom: z) + #pragma omp distribute parallel for linear (z: 4) /* { dg-error ".linear. is not valid for .#pragma omp distribute parallel for." } */ + for (x = 0; x < 64; x++) + z += 4; + #pragma omp target map (from: x) + #pragma omp teams distribute simd linear (x : 2) + for (x = 0; x < 64; x += 2) + ; + #pragma omp target map (from: x) + #pragma omp teams distribute parallel for simd linear (x) + for (x = 0; x < 64; x++) + ; + #pragma omp target map (tofrom: y) + #pragma omp teams distribute simd linear (y : 2) /* { dg-error ".linear. clause for variable other than loop iterator specified on construct combined with .distribute." } */ + for (x = 0; x < 64; x += 2) + y += 2; + #pragma omp target map (tofrom: z) + #pragma omp teams distribute parallel for simd linear (z) /* { dg-error ".linear. clause for variable other than loop iterator specified on construct combined with .distribute." } */ + for (x = 0; x < 64; x++) + z++; + #pragma omp target map (tofrom: z) + #pragma omp teams distribute parallel for linear (z: 4) /* { dg-error ".linear. is not valid for .#pragma omp teams distribute parallel for." } */ + for (x = 0; x < 64; x++) + z += 4; + #pragma omp target parallel copyin (t) /* { dg-error ".copyin. is not valid for .#pragma omp target parallel." } */ + ; + #pragma omp target parallel for copyin (t) /* { dg-error ".copyin. is not valid for .#pragma omp target parallel for." } */ + for (x = 0; x < 64; x++) + ; + #pragma omp target parallel for simd copyin (t) /* { dg-error ".copyin. is not valid for .#pragma omp target parallel for simd." } */ + for (x = 0; x < 64; x++) + ; + #pragma omp target teams + #pragma omp distribute parallel for ordered /* { dg-error ".ordered. is not valid for .#pragma omp distribute parallel for." } */ + for (x = 0; x < 64; x++) + { + #pragma omp ordered /* { dg-error "ordered region must be closely nested inside a loop region with an ordered clause" } */ + ; + } + #pragma omp target teams + #pragma omp distribute parallel for simd ordered /* { dg-error ".ordered. is not valid for .#pragma omp distribute parallel for simd." } */ + for (x = 0; x < 64; x++) + { + #pragma omp ordered simd, threads /* { dg-error "OpenMP constructs other than .#pragma omp ordered simd. may not be nested inside simd region" } */ + ; + } + #pragma omp target + #pragma omp teams distribute parallel for ordered /* { dg-error ".ordered. is not valid for .#pragma omp teams distribute parallel for." } */ + for (x = 0; x < 64; x++) + { + #pragma omp ordered /* { dg-error "ordered region must be closely nested inside a loop region with an ordered clause" } */ + ; + } + #pragma omp target + #pragma omp teams distribute parallel for simd ordered /* { dg-error ".ordered. is not valid for .#pragma omp teams distribute parallel for simd." } */ + for (x = 0; x < 64; x++) + { + #pragma omp ordered simd, threads /* { dg-error "OpenMP constructs other than .#pragma omp ordered simd. may not be nested inside simd region" } */ + ; + } + #pragma omp target teams distribute parallel for ordered /* { dg-error ".ordered. is not valid for .#pragma omp target teams distribute parallel for." } */ + for (x = 0; x < 64; x++) + { + #pragma omp ordered /* { dg-error "ordered region must be closely nested inside a loop region with an ordered clause" } */ + ; + } + #pragma omp target teams distribute parallel for simd ordered /* { dg-error ".ordered. is not valid for .#pragma omp target teams distribute parallel for simd." } */ + for (x = 0; x < 64; x++) + { + #pragma omp ordered simd, threads /* { dg-error "OpenMP constructs other than .#pragma omp ordered simd. may not be nested inside simd region" } */ + ; + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/declare-target-1.c b/gcc/testsuite/c-c++-common/gomp/declare-target-1.c new file mode 100644 index 00000000000..a1f1ea717b7 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/declare-target-1.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +int foo (void), bar (void); +extern int a; +int b; +char d; +#pragma omp declare target +long c; +#pragma omp end declare target + +#pragma omp declare target (bar, a) +#pragma omp declare target to (b) link (d) to (foo) diff --git a/gcc/testsuite/c-c++-common/gomp/declare-target-2.c b/gcc/testsuite/c-c++-common/gomp/declare-target-2.c new file mode 100644 index 00000000000..b9313d86447 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/declare-target-2.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +extern int a; +#pragma omp declare target +#pragma omp declare target to (a) /* { dg-error "with clauses in between" } */ +#pragma omp end declare target +int b; +#pragma omp declare target to (b) link (b) /* { dg-error "specified both in declare target" } */ +int c; +#pragma omp declare target (c) +#pragma omp declare target link (c) /* { dg-error "specified both in declare target" } */ +int foo (void); +#pragma omp declare target link (foo) /* { dg-error "is not a variable in clause" } */ +struct S; +extern struct S d[]; /* { dg-error "array type has incomplete element type" "" { target c } } */ +#pragma omp declare target to (d) /* { dg-error "does not have a mappable type in" } */ +extern struct S e; +#pragma omp declare target link (e) /* { dg-error "does not have a mappable type in" } */ +extern int f[]; +#pragma omp declare target to (f) /* { dg-error "does not have a mappable type in" } */ +int g, h; +#pragma omp threadprivate (g, h) +#pragma omp declare target to (g) /* { dg-error "is threadprivate variable in" } */ +#pragma omp declare target link (h) /* { dg-error "is threadprivate variable in" } */ +int j[10]; +#pragma omp declare target to (j[0:4]) /* { dg-error "expected" } */ diff --git a/gcc/testsuite/c-c++-common/gomp/depend-3.c b/gcc/testsuite/c-c++-common/gomp/depend-3.c new file mode 100644 index 00000000000..22fcd8d9c70 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/depend-3.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +void bar (int a[10][10][10]); +void +foo (int a[10][10][10], int **b, int x) +{ + int c[10][10][10]; + #pragma omp task depend(out: a[2:4][3:0][:7]) /* { dg-error "zero length array section" } */ + bar (a); + #pragma omp task depend(inout: b[:7][0:0][:0]) /* { dg-error "zero length array section" } */ + bar (a); + #pragma omp task depend(in: c[:][:][10:]) /* { dg-error "zero length array section" } */ + bar (c); + #pragma omp task depend(out: a[2:4][3:0][:x]) /* { dg-error "zero length array section" } */ + bar (a); + #pragma omp task depend(inout: b[:x][0:0][:0]) /* { dg-error "zero length array section" } */ + bar (a); + #pragma omp task depend(in: c[:][x-2:x][10:]) /* { dg-error "zero length array section" } */ + bar (c); +} diff --git a/gcc/testsuite/c-c++-common/gomp/depend-4.c b/gcc/testsuite/c-c++-common/gomp/depend-4.c new file mode 100644 index 00000000000..d40b1fa83cd --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/depend-4.c @@ -0,0 +1,44 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +void +foo (int *p, int (*q)[10], int r[10], int s[10][10]) +{ + int a[10], b[10][10]; + #pragma omp task depend (inout: p[-1:2]) + ; + #pragma omp task depend (inout: q[-1:2][2:4]) + ; + #pragma omp task depend (inout: q[-1:2][-2:4]) /* { dg-error "negative low bound in array section in" } */ + ; + #pragma omp task depend (inout: r[-1:2]) + ; + #pragma omp task depend (inout: s[-1:2][2:4]) + ; + #pragma omp task depend (inout: s[-1:2][-2:4]) /* { dg-error "negative low bound in array section in" } */ + ; + #pragma omp task depend (inout: a[-1:2]) /* { dg-error "negative low bound in array section in" } */ + ; + #pragma omp task depend (inout: b[-1:2][2:4]) /* { dg-error "negative low bound in array section in" } */ + ; + #pragma omp task depend (inout: b[1:2][-2:4]) /* { dg-error "negative low bound in array section in" } */ + ; + #pragma omp task depend (inout: p[2:-3]) /* { dg-error "negative length in array section in" } */ + ; + #pragma omp task depend (inout: q[2:-3][:]) /* { dg-error "negative length in array section in" } */ + ; + #pragma omp task depend (inout: q[2:3][0:-1]) /* { dg-error "negative length in array section in" } */ + ; + #pragma omp task depend (inout: r[2:-5]) /* { dg-error "negative length in array section in" } */ + ; + #pragma omp task depend (inout: s[2:-5][:]) /* { dg-error "negative length in array section in" } */ + ; + #pragma omp task depend (inout: s[2:5][0:-4]) /* { dg-error "negative length in array section in" } */ + ; + #pragma omp task depend (inout: a[2:-5]) /* { dg-error "negative length in array section in" } */ + ; + #pragma omp task depend (inout: b[2:-5][0:10]) /* { dg-error "negative length in array section in" } */ + ; + #pragma omp task depend (inout: b[2:5][0:-4]) /* { dg-error "negative length in array section in" } */ + ; +} diff --git a/gcc/testsuite/c-c++-common/gomp/doacross-1.c b/gcc/testsuite/c-c++-common/gomp/doacross-1.c new file mode 100644 index 00000000000..89c3dd3c7c6 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/doacross-1.c @@ -0,0 +1,48 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +void +foo (void) +{ + int i, j, k; + #pragma omp for ordered (1) + for (i = 0; i < 64; i++) + { + #pragma omp ordered depend (sink: i - 1) + #pragma omp ordered depend (source) + } + #pragma omp for ordered (1) collapse (1) + for (i = 0; i < 64; i++) + { + #pragma omp ordered depend (sink: i - 1) + #pragma omp ordered depend (source) + } + #pragma omp for collapse (2) ordered (1) /* { dg-error "clause parameter is less than" } */ + for (i = 0; i < 64; i++) + for (j = 0; j < 64; j++) + { + #pragma omp ordered depend (sink: i - 1) /* { dg-error "does not match number" } */ + #pragma omp ordered depend (source) + } + #pragma omp for ordered (2) collapse (3) /* { dg-error "clause parameter is less than" } */ + for (i = 0; i < 64; i++) + for (j = 0; j < 64; j++) + for (k = 0; k < 64; k++) + { + #pragma omp ordered depend (sink: i - 1, j - 2) /* { dg-error "does not match number" } */ + #pragma omp ordered depend (source) + } + #pragma omp ordered depend (sink: j) /* { dg-error "clause must be closely nested inside an ordered loop" } */ + #pragma omp ordered depend (source) /* { dg-error "clause must be closely nested inside an ordered loop" } */ + #pragma omp for ordered (1) + for (i = 0; i < 64; i++) + { + #pragma omp ordered depend (sink: i - 1) depend (sink: i - 2) + #pragma omp ordered depend (source) depend (source) /* { dg-error "more than one .depend.source.. clause on an" } */ + } + #pragma omp for ordered (1) + for (i = 0; i < 64; i++) + { + #pragma omp ordered depend (sink: i - 1) depend (source) depend (sink: i - 2) /* { dg-error "clause specified together with" } */ + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/if-1.c b/gcc/testsuite/c-c++-common/gomp/if-1.c new file mode 100644 index 00000000000..4ba708c50c3 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/if-1.c @@ -0,0 +1,48 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +void +foo (int a, int b, int *p, int *q) +{ + int i; + #pragma omp parallel if (a) + ; + #pragma omp parallel if (parallel:a) + ; + #pragma omp parallel for simd if (a) + for (i = 0; i < 16; i++) + ; + #pragma omp parallel for simd if (parallel : a) + for (i = 0; i < 16; i++) + ; + #pragma omp task if (a) + ; + #pragma omp task if (task: a) + ; + #pragma omp taskloop if (a) + for (i = 0; i < 16; i++) + ; + #pragma omp taskloop if (taskloop : a) + for (i = 0; i < 16; i++) + ; + #pragma omp target if (a) + ; + #pragma omp target if (target: a) + ; + #pragma omp target teams distribute parallel for simd if (a) + for (i = 0; i < 16; i++) + ; + #pragma omp target teams distribute parallel for simd if (parallel : a) if (target: b) + for (i = 0; i < 16; i++) + ; + #pragma omp target data if (a) map (p[0:2]) + ; + #pragma omp target data if (target data: a) map (p[0:2]) + ; + #pragma omp target enter data if (a) map (to: p[0:2]) + #pragma omp target enter data if (target enter data: a) map (to: p[0:2]) + #pragma omp target exit data if (a) map (from: p[0:2]) + #pragma omp target exit data if (target exit data: a) map (from: p[0:2]) + #pragma omp target update if (a) to (q[0:3]) + #pragma omp target update if (target update:a) to (q[0:3]) +} diff --git a/gcc/testsuite/c-c++-common/gomp/if-2.c b/gcc/testsuite/c-c++-common/gomp/if-2.c new file mode 100644 index 00000000000..f1f417ed235 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/if-2.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +void +foo (int a, int b, int *p, int *q, int task) +{ + int i; + #pragma omp parallel if (a) if (b) /* { dg-error "too many .if. clauses without modifier" } */ + ; + #pragma omp parallel if (a) if (parallel: b) /* { dg-error "if any .if. clause has modifier, then all .if. clauses have to use modifier" } */ + ; + #pragma omp parallel if (parallel: a) if (b) /* { dg-error "if any .if. clause has modifier, then all .if. clauses have to use modifier" } */ + ; + #pragma omp parallel if (parallel:a) if (parallel:a) /* { dg-error "too many .if. clauses with .parallel. modifier" } */ + ; + #pragma omp parallel if (task:a) /* { dg-error "expected .parallel. .if. clause modifier rather than .task." } */ \ + if (taskloop: b) /* { dg-error "expected .parallel. .if. clause modifier rather than .taskloop." } */ + ; + #pragma omp parallel if (target update:a) /* { dg-error "expected .parallel. .if. clause modifier rather than .target update." } */ + ; + #pragma omp parallel for simd if (target update: a) /* { dg-error "expected .parallel. .if. clause modifier rather than .target update." } */ + for (i = 0; i < 16; i++) + ; + #pragma omp task if (task) + ; + #pragma omp task if (task: task) + ; + #pragma omp task if (parallel: a) /* { dg-error "expected .task. .if. clause modifier rather than .parallel." } */ + ; + #pragma omp taskloop if (task : a) /* { dg-error "expected .taskloop. .if. clause modifier rather than .task." } */ + for (i = 0; i < 16; i++) + ; + #pragma omp target if (taskloop: a) /* { dg-error "expected .target. .if. clause modifier rather than .taskloop." } */ + ; + #pragma omp target teams distribute parallel for simd if (target exit data : a) /* { dg-error "expected .parallel. or .target. .if. clause modifier" } */ + for (i = 0; i < 16; i++) + ; + #pragma omp target data if (target: a) map (p[0:2]) /* { dg-error "expected .target data. .if. clause modifier rather than .target." } */ + ; + #pragma omp target enter data if (target data: a) map (to: p[0:2]) /* { dg-error "expected .target enter data. .if. clause modifier rather than .target data." } */ + #pragma omp target exit data if (target enter data: a) map (from: p[0:2]) /* { dg-error "expected .target exit data. .if. clause modifier rather than .target enter data." } */ + #pragma omp target update if (target exit data:a) to (q[0:3]) /* { dg-error "expected .target update. .if. clause modifier rather than .target exit data." } */ +} diff --git a/gcc/testsuite/c-c++-common/gomp/linear-1.c b/gcc/testsuite/c-c++-common/gomp/linear-1.c new file mode 100644 index 00000000000..4557e22cb4f --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/linear-1.c @@ -0,0 +1,42 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +int i; + +#pragma omp declare simd linear (val (x) : 1) linear (y : 2) +int bar (int x, int y, int z); + +void +foo (int x, int y) +{ + #pragma omp simd linear (i: 3) + for (i = 0; i < 33; i += 3) + ; + #pragma omp simd linear (val (i): 3) /* { dg-error "modifier should not be specified in" } */ + for (i = 0; i < 33; i += 3) + ; + #pragma omp simd linear (x: y + 1) + for (i = 0; i < 10; i++) + x += y + 1; + #pragma omp simd linear (val (x): y + 1) /* { dg-error "modifier should not be specified in" } */ + for (i = 0; i < 10; i++) + x += y + 1; + #pragma omp for linear (x: y + 1) + for (i = 0; i < 10; i++) + x += y + 1; + #pragma omp for linear (val (x): y + 1) /* { dg-error "modifier should not be specified in" } */ + for (i = 0; i < 10; i++) + x += y + 1; + #pragma omp for simd linear (i: 3) + for (i = 0; i < 33; i += 3) + ; + #pragma omp for simd linear (val (i): 3) /* { dg-error "modifier should not be specified in" } */ + for (i = 0; i < 33; i += 3) + ; + #pragma omp for simd linear (x: y + 1) + for (i = 0; i < 10; i++) + x += y + 1; + #pragma omp for simd linear (val (x): y + 1) /* { dg-error "modifier should not be specified in" } */ + for (i = 0; i < 10; i++) + x += y + 1; +} diff --git a/gcc/testsuite/c-c++-common/gomp/map-2.c b/gcc/testsuite/c-c++-common/gomp/map-2.c new file mode 100644 index 00000000000..101f4047b85 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/map-2.c @@ -0,0 +1,44 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +void +foo (int *p, int (*q)[10], int r[10], int s[10][10]) +{ + int a[10], b[10][10]; + #pragma omp target map (tofrom: p[-1:2]) + ; + #pragma omp target map (tofrom: q[-1:2][0:10]) + ; + #pragma omp target map (tofrom: q[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */ + ; + #pragma omp target map (tofrom: r[-1:2]) + ; + #pragma omp target map (tofrom: s[-1:2][:]) + ; + #pragma omp target map (tofrom: s[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */ + ; + #pragma omp target map (tofrom: a[-1:2]) /* { dg-error "negative low bound in array section in" } */ + ; + #pragma omp target map (tofrom: b[-1:2][0:]) /* { dg-error "negative low bound in array section in" } */ + ; + #pragma omp target map (tofrom: b[1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */ + ; + #pragma omp target map (tofrom: p[2:-3]) /* { dg-error "negative length in array section in" } */ + ; + #pragma omp target map (tofrom: q[2:-3][:]) /* { dg-error "negative length in array section in" } */ + ; + #pragma omp target map (tofrom: q[2:3][0:-1]) /* { dg-error "negative length in array section in" } */ + ; + #pragma omp target map (tofrom: r[2:-5]) /* { dg-error "negative length in array section in" } */ + ; + #pragma omp target map (tofrom: s[2:-5][:]) /* { dg-error "negative length in array section in" } */ + ; + #pragma omp target map (tofrom: s[2:5][0:-4]) /* { dg-error "negative length in array section in" } */ + ; + #pragma omp target map (tofrom: a[2:-5]) /* { dg-error "negative length in array section in" } */ + ; + #pragma omp target map (tofrom: b[2:-5][0:10]) /* { dg-error "negative length in array section in" } */ + ; + #pragma omp target map (tofrom: b[2:5][0:-4]) /* { dg-error "negative length in array section in" } */ + ; +} diff --git a/gcc/testsuite/c-c++-common/gomp/map-3.c b/gcc/testsuite/c-c++-common/gomp/map-3.c new file mode 100644 index 00000000000..8a14b9c888e --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/map-3.c @@ -0,0 +1,21 @@ +struct S { int i : 1; int j : 4; long long k : 25; }; +void bar (struct S, int); +#pragma omp declare target to (bar) + +void +foo (struct S a, struct S b, struct S c, struct S d) +{ + #pragma omp target map (a) + bar (a, 0); + #pragma omp target map (a) map (b.i) /* { dg-error "bit-field .b.\(S::\|\)i. in .map. clause" } */ + bar (a, b.i); + #pragma omp target map (a) map (b.j) /* { dg-error "bit-field .b.\(S::\|\)j. in .map. clause" } */ + bar (a, b.j); + #pragma omp target map (a) map (b.k) /* { dg-error "bit-field .b.\(S::\|\)k. in .map. clause" } */ + bar (a, b.k); + #pragma omp target data map (a) map (b.i) /* { dg-error "bit-field .b.\(S::\|\)i. in .map. clause" } */ + { + #pragma omp target enter data map (alloc: a) map (to: c.j) /* { dg-error "bit-field .c.\(S::\|\)j. in .map. clause" } */ + #pragma omp target exit data map (release: a) map (from: d.k) /* { dg-error "bit-field .d.\(S::\|\)k. in .map. clause" } */ + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/nesting-1.c b/gcc/testsuite/c-c++-common/gomp/nesting-1.c index 711ff8ea86b..61b2f818b08 100644 --- a/gcc/testsuite/c-c++-common/gomp/nesting-1.c +++ b/gcc/testsuite/c-c++-common/gomp/nesting-1.c @@ -11,12 +11,12 @@ f_omp_parallel (void) #pragma omp target ; -#pragma omp target data +#pragma omp target data map(i) ; #pragma omp target update to(i) -#pragma omp target data +#pragma omp target data map(i) { #pragma omp parallel ; @@ -24,7 +24,7 @@ f_omp_parallel (void) #pragma omp target ; -#pragma omp target data +#pragma omp target data map(i) ; #pragma omp target update to(i) @@ -45,7 +45,7 @@ f_omp_target (void) void f_omp_target_data (void) { -#pragma omp target data +#pragma omp target data map(i) { #pragma omp parallel ; @@ -53,12 +53,12 @@ f_omp_target_data (void) #pragma omp target ; -#pragma omp target data +#pragma omp target data map(i) ; #pragma omp target update to(i) -#pragma omp target data +#pragma omp target data map(i) { #pragma omp parallel ; @@ -66,7 +66,7 @@ f_omp_target_data (void) #pragma omp target ; -#pragma omp target data +#pragma omp target data map(i) ; #pragma omp target update to(i) diff --git a/gcc/testsuite/c-c++-common/gomp/nesting-warn-1.c b/gcc/testsuite/c-c++-common/gomp/nesting-warn-1.c index c39dd49f123..92ced709907 100644 --- a/gcc/testsuite/c-c++-common/gomp/nesting-warn-1.c +++ b/gcc/testsuite/c-c++-common/gomp/nesting-warn-1.c @@ -7,7 +7,7 @@ f_omp_target (void) { #pragma omp target /* { dg-warning "target construct inside of target region" } */ ; -#pragma omp target data /* { dg-warning "target data construct inside of target region" } */ +#pragma omp target data map(i) /* { dg-warning "target data construct inside of target region" } */ ; #pragma omp target update to(i) /* { dg-warning "target update construct inside of target region" } */ @@ -15,7 +15,7 @@ f_omp_target (void) { #pragma omp target /* { dg-warning "target construct inside of target region" } */ ; -#pragma omp target data /* { dg-warning "target data construct inside of target region" } */ +#pragma omp target data map(i) /* { dg-warning "target data construct inside of target region" } */ ; #pragma omp target update to(i) /* { dg-warning "target update construct inside of target region" } */ } diff --git a/gcc/testsuite/c-c++-common/gomp/ordered-1.c b/gcc/testsuite/c-c++-common/gomp/ordered-1.c new file mode 100644 index 00000000000..11022593e3e --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/ordered-1.c @@ -0,0 +1,91 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -fopenmp-simd" } */ +/* { dg-additional-options "-msse2" { target sse2_runtime } } */ +/* { dg-additional-options "-mavx" { target avx_runtime } } */ + +#define N 1024 +extern +#ifdef __cplusplus +"C" +#endif +void abort (void); + +int last; + +void +bar (unsigned char *a, int i, int safelen) +{ + int j, k; + if (i != last++) + abort (); + for (j = i - safelen - 32; j < i; j++) + if (j >= 0 && a[j] != 2) + break; + if (j <= i - safelen || a[j] != 1) + abort (); + for (k = j; k < i + safelen + 32; k++) + if (k >= N || a[k] != 1) + break; + if (k <= i || k > j + safelen) + abort (); + if (k < N && a[k] != 0) + abort (); + for (; k < i + safelen + 32; k++) + if (k < N && a[k] != 0) + abort (); +} + +static inline void +foo (unsigned char *a, int i) +{ + #pragma omp ordered simd + bar (a, i, 64); +} + +int +main () +{ + unsigned char a[N], b[N]; + int i; + #pragma omp simd + for (i = 0; i < N; i++) + a[i] = 0; + #pragma omp simd safelen (64) + for (i = 0; i < N; i++) + { + a[i]++; + foo (a, i); + a[i]++; + } + #pragma omp simd + for (i = 0; i < N; i++) + { + a[i] = 0; + b[i] = 0; + } + last = 0; + #pragma omp simd safelen (32) + for (i = 0; i < N; i++) + { + a[i]++; + #pragma omp ordered simd + bar (a, i, 32); + a[i]++; + } + for (i = 0; i < N; i++) + if (a[i] != 2) + abort (); + #pragma omp simd safelen (32) + for (i = 1; i < N; i++) + { + #pragma omp ordered simd + b[i] = b[i - 1] + 1; + a[i]++; + #pragma omp ordered simd + a[i] += a[i - 1]; + } + for (i = 0; i < N; i++) + if (a[i] != (unsigned char) (2 + 3 * i) || b[i] != (unsigned char) i) + abort (); + return 0; +} diff --git a/gcc/testsuite/c-c++-common/gomp/ordered-2.c b/gcc/testsuite/c-c++-common/gomp/ordered-2.c new file mode 100644 index 00000000000..96442978a9f --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/ordered-2.c @@ -0,0 +1,4 @@ +/* { dg-do run } */ +/* { dg-options "-O0 -fopenmp-simd" } */ + +#include "ordered-1.c" diff --git a/gcc/testsuite/c-c++-common/gomp/ordered-3.c b/gcc/testsuite/c-c++-common/gomp/ordered-3.c new file mode 100644 index 00000000000..1d7ff80f743 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/ordered-3.c @@ -0,0 +1,91 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +void +foo (void) +{ + int i; + #pragma omp for ordered + for (i = 0; i < 64; i++) + { + #pragma omp ordered + ; + } + #pragma omp for ordered + for (i = 0; i < 64; i++) + { + #pragma omp ordered threads + ; + } + #pragma omp for ordered + for (i = 0; i < 64; i++) + { + #pragma omp ordered threads threads /* { dg-error "too many .threads. clauses" } */ + ; + } + #pragma omp simd + for (i = 0; i < 64; i++) + { + #pragma omp ordered simd + ; + } + #pragma omp simd + for (i = 0; i < 64; i++) + { + #pragma omp ordered simd simd /* { dg-error "too many .simd. clauses" } */ + ; + } + #pragma omp for simd ordered + for (i = 0; i < 64; i++) + { + #pragma omp ordered threads, simd + ; + } + #pragma omp for simd ordered + for (i = 0; i < 64; i++) + { + #pragma omp ordered threads, simd, threads, simd /* { dg-error "too many .threads. clauses" } */ + ; /* { dg-error "too many .simd. clauses" "" { target *-*-* } 47 } */ + } + #pragma omp for simd ordered(1) /* { dg-error ".ordered. clause with parameter may not be specified on .#pragma omp for simd. construct" } */ + for (i = 0; i < 64; i++) + { + #pragma omp ordered depend(sink: i - 1) /* { dg-error "clause must be closely nested inside a loop with .ordered. clause with a parameter" } */ + #pragma omp ordered depend(source) /* { dg-error "clause must be closely nested inside a loop with .ordered. clause with a parameter" } */ + } + #pragma omp parallel for simd ordered(1) /* { dg-error ".ordered. clause with parameter may not be specified on .#pragma omp parallel for simd. construct" } */ + for (i = 0; i < 64; i++) + { + #pragma omp ordered depend(sink: i - 1) /* { dg-error "clause must be closely nested inside a loop with .ordered. clause with a parameter" } */ + #pragma omp ordered depend(source) /* { dg-error "clause must be closely nested inside a loop with .ordered. clause with a parameter" } */ + } +} + +void +bar (int x) +{ + switch (x) + { + case 0: + #pragma omp ordered + ; + break; + case 1: + #pragma omp ordered threads + ; + break; + case 2: + #pragma omp ordered threads, threads /* { dg-error "too many .threads. clauses" } */ + ; + break; + } +} + +void +baz (void) +{ + #pragma omp ordered simd + ; + #pragma omp ordered simd, simd /* { dg-error "too many .simd. clauses" } */ + ; +} diff --git a/gcc/testsuite/c-c++-common/gomp/pr61486-1.c b/gcc/testsuite/c-c++-common/gomp/pr61486-1.c index 9ada58c8ccf..dbd621f0dba 100644 --- a/gcc/testsuite/c-c++-common/gomp/pr61486-1.c +++ b/gcc/testsuite/c-c++-common/gomp/pr61486-1.c @@ -6,8 +6,8 @@ int foo (int *a) { int i, j = 0; - #pragma omp target teams distribute simd linear(i, j) map(a[:10]) + #pragma omp target teams distribute simd linear(i) map(a[:10]) for (i = 0; i < 10; i++) - a[i] = j++; - return i + j; + a[i] = j; + return i; } diff --git a/gcc/testsuite/c-c++-common/gomp/pr61486-2.c b/gcc/testsuite/c-c++-common/gomp/pr61486-2.c index 55332717246..804a8270660 100644 --- a/gcc/testsuite/c-c++-common/gomp/pr61486-2.c +++ b/gcc/testsuite/c-c++-common/gomp/pr61486-2.c @@ -50,22 +50,21 @@ test (int n, int o, int p, int q, int r, int s, int *pp) private (p) firstprivate (q) shared (n) reduction (+: r) \ thread_limit (n * 2) dist_schedule (static, 4) collapse (2) \ num_threads (n + 4) proc_bind (spread) lastprivate (s) \ - ordered schedule (static, 8) + schedule (static, 8) for (i = 0; i < 10; i++) for (j = 0; j < 10; j++) { r = r + 1; p = q; dosomething (a, n, p + q); - #pragma omp ordered - p = q; + p = q; s = i * 10 + j; } #pragma omp target teams distribute parallel for device (n + 1) num_teams (n + 4) \ if (n != 6)map (from: n) map (alloc: a[2:o-2]) default(shared) \ private (p) firstprivate (q) shared (n) reduction (+: r) \ thread_limit (n * 2) dist_schedule (static, 4) num_threads (n + 4) \ - proc_bind (master) lastprivate (s) ordered schedule (static, 8) + proc_bind (master) lastprivate (s) schedule (static, 8) for (i = 0; i < 10; i++) { for (j = 0; j < 10; j++) @@ -74,8 +73,7 @@ test (int n, int o, int p, int q, int r, int s, int *pp) p = q; dosomething (a, n, p + q); } - #pragma omp ordered - p = q; + p = q; s = i * 10; } #pragma omp target teams distribute parallel for simd device (n + 1) \ @@ -165,22 +163,21 @@ test (int n, int o, int p, int q, int r, int s, int *pp) default(shared) private (p) firstprivate (q) shared (n) reduction (+: r) \ thread_limit (n * 2) dist_schedule (static, 4) collapse (2) \ num_threads (n + 4) proc_bind (spread) lastprivate (s) \ - ordered schedule (static, 8) + schedule (static, 8) for (i = 0; i < 10; i++) for (j = 0; j < 10; j++) { r = r + 1; p = q; dosomething (a, n, p + q); - #pragma omp ordered - p = q; + p = q; s = i * 10 + j; } #pragma omp target device (n + 1) if (n != 6)map(from:n) map(alloc:a[2:o-2]) #pragma omp teams distribute parallel for num_teams (n + 4) if (n != 6) \ default(shared) private (p) firstprivate (q) shared (n) reduction (+: r) \ thread_limit (n * 2) dist_schedule (static, 4) num_threads (n + 4) \ - proc_bind (master) lastprivate (s) ordered schedule (static, 8) + proc_bind (master) lastprivate (s) schedule (static, 8) for (i = 0; i < 10; i++) { for (j = 0; j < 10; j++) @@ -189,8 +186,7 @@ test (int n, int o, int p, int q, int r, int s, int *pp) p = q; dosomething (a, n, p + q); } - #pragma omp ordered - p = q; + p = q; s = i * 10; } #pragma omp target device (n + 1) if (n != 6)map(from:n) map(alloc:a[2:o-2]) @@ -273,15 +269,14 @@ test (int n, int o, int p, int q, int r, int s, int *pp) default(shared) private (p) firstprivate (q) shared (n) reduction (+: r) \ collapse (2) dist_schedule (static, 4) \ num_threads (n + 4) proc_bind (spread) lastprivate (s) \ - ordered schedule (static, 8) + schedule (static, 8) for (i = 0; i < 10; i++) for (j = 0; j < 10; j++) { r = r + 1; p = q; dosomething (a, n, p + q); - #pragma omp ordered - p = q; + p = q; s = i * 10 + j; } #pragma omp target teams device (n + 1) if (n != 6)map(from:n) map(alloc:a[2:o-2]) \ @@ -289,7 +284,7 @@ test (int n, int o, int p, int q, int r, int s, int *pp) #pragma omp distribute parallel for if (n != 6) \ default(shared) private (p) firstprivate (q) shared (n) reduction (+: r) \ num_threads (n + 4) dist_schedule (static, 4) \ - proc_bind (master) lastprivate (s) ordered schedule (static, 8) + proc_bind (master) lastprivate (s) schedule (static, 8) for (i = 0; i < 10; i++) { for (j = 0; j < 10; j++) @@ -298,8 +293,7 @@ test (int n, int o, int p, int q, int r, int s, int *pp) p = q; dosomething (a, n, p + q); } - #pragma omp ordered - p = q; + p = q; s = i * 10; } #pragma omp target teams device (n + 1) if (n != 6)map(from:n) map(alloc:a[2:o-2]) \ @@ -385,21 +379,20 @@ test2 (int n, int o, int p, int r, int s, int *pp) default(shared) private (p) firstprivate (q) shared (n) reduction (+: r) \ collapse (2) dist_schedule (static, 4) \ num_threads (n + 4) proc_bind (spread) lastprivate (s) \ - ordered schedule (static, 8) + schedule (static, 8) for (i = 0; i < 10; i++) for (j = 0; j < 10; j++) { r = r + 1; p = q; dosomething (a, n, p + q); - #pragma omp ordered - p = q; + p = q; s = i * 10 + j; } #pragma omp distribute parallel for if (n != 6) \ default(shared) private (p) firstprivate (q) shared (n) reduction (+: r) \ num_threads (n + 4) dist_schedule (static, 4) \ - proc_bind (master) lastprivate (s) ordered schedule (static, 8) + proc_bind (master) lastprivate (s) schedule (static, 8) for (i = 0; i < 10; i++) { for (j = 0; j < 10; j++) @@ -408,8 +401,7 @@ test2 (int n, int o, int p, int r, int s, int *pp) p = q; dosomething (a, n, p + q); } - #pragma omp ordered - p = q; + p = q; s = i * 10; } #pragma omp distribute parallel for simd if (n != 6)default(shared) \ diff --git a/gcc/testsuite/c-c++-common/gomp/priority-1.c b/gcc/testsuite/c-c++-common/gomp/priority-1.c new file mode 100644 index 00000000000..e2eebf9147d --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/priority-1.c @@ -0,0 +1,26 @@ +void bar (void); + +void +foo (int x, unsigned long long y) +{ + #pragma omp task + bar (); + #pragma omp taskloop + for (int i = 0; i < 10; i++) + bar (); + #pragma omp task + bar (); + #pragma omp taskloop + for (unsigned long long int i = 0; i < y; i++) + bar (); + #pragma omp task priority (1) + bar (); + #pragma omp taskloop priority (1) + for (int i = 0; i < 10; i++) + bar (); + #pragma omp task priority (x + 1) + bar (); + #pragma omp taskloop priority (x + 1) + for (unsigned long long int i = 0; i < y; i++) + bar (); +} diff --git a/gcc/testsuite/c-c++-common/gomp/reduction-1.c b/gcc/testsuite/c-c++-common/gomp/reduction-1.c new file mode 100644 index 00000000000..23e79d9c3c7 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/reduction-1.c @@ -0,0 +1,51 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +void bar (int a[10][10][10]); +extern int f[][2]; /* { dg-error "has incomplete type" "" { target c++ } } */ +extern int g[]; /* { dg-error "has incomplete type" "" { target c++ } } */ +void +foo (int a[10][10][10], int **b, int x) +{ + int c[10][10][0]; + int d[0]; + char e[12]; + #pragma omp parallel reduction(+: a[:4][:0][:7]) /* { dg-error "zero length array section" } */ + bar (a); + #pragma omp parallel reduction(+: b[:7][0:0][:0]) /* { dg-error "zero length array section" } */ + bar (a); + #pragma omp parallel reduction(+: c[:][:][0:]) /* { dg-error "zero length array section|for unknown bound array type length expression must be specified" } */ + bar (a); + #pragma omp parallel reduction(+: a[:4][:0][:x]) /* { dg-error "zero length array section" } */ + bar (a); + #pragma omp parallel reduction(+: b[:x][0:0][:0]) /* { dg-error "zero length array section" } */ + bar (a); + #pragma omp parallel reduction(+: c[:][:x][0:]) /* { dg-error "zero length array section|for unknown bound array type length expression must be specified" } */ + bar (a); + #pragma omp parallel reduction(+: d) /* { dg-error "is a zero size array" } */ + bar (a); + #pragma omp parallel reduction(+: a[0:4]) + bar (a); + #pragma omp parallel reduction(+: a[2:4]) /* { dg-error "array section has to be zero-based" } */ + bar (a); + #pragma omp parallel reduction(+: e[2:4]) /* { dg-error "array section has to be zero-based" } */ + bar (a); + #pragma omp parallel reduction(+: a[0.5:2]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */ + bar (a); + #pragma omp parallel reduction(+: a[0:2.5]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */ + bar (a); + #pragma omp parallel reduction(+: f[:][0:2]) /* { dg-error "for unknown bound array type length expression must be specified" } */ + bar (a); + #pragma omp parallel reduction(+: a[:][0:10]) /* { dg-error "for pointer type length expression must be specified" } */ + bar (a); + #pragma omp parallel reduction(+: a[:10][0:12]) /* { dg-error "above array section size" } */ + bar (a); + #pragma omp parallel reduction(+: b[0:10][0:10]) /* { dg-error "array section is not contiguous" } */ + bar (a); + #pragma omp parallel reduction(+: a[0:2][0:9]) /* { dg-error "array section is not contiguous" } */ + bar (a); + #pragma omp parallel reduction(+: f) /* { dg-error "has an incomplete type|invalid use of array with unspecified bounds" } */ + bar (a); + #pragma omp parallel reduction(+: g) /* { dg-error "has an incomplete type|invalid use of array with unspecified bounds" } */ + bar (a); +} diff --git a/gcc/testsuite/c-c++-common/gomp/schedule-simd-1.c b/gcc/testsuite/c-c++-common/gomp/schedule-simd-1.c new file mode 100644 index 00000000000..e6a7bb92fcf --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/schedule-simd-1.c @@ -0,0 +1,51 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -O2" } */ +/* { dg-additional-options "-mavx512f" { target { x86_64-*-* i?86-*-* } } } */ + +#define N 1024 +int a[N], b[N], c[N]; + +void +f1 (void) +{ + int i; + #pragma omp parallel for simd schedule (simd:static) + for (i = 0; i < N; i++) + a[i] = b[i] + c[i]; +} + +void +f2 (void) +{ + int i; + #pragma omp parallel for simd schedule (simd: static, 7) + for (i = 0; i < N; i++) + a[i] = b[i] + c[i]; +} + +void +f3 (void) +{ + int i; + #pragma omp parallel for simd schedule (simd : dynamic, 7) + for (i = 0; i < N; i++) + a[i] = b[i] + c[i]; +} + +void +f4 (void) +{ + int i; + #pragma omp parallel for simd schedule ( simd:runtime) + for (i = 0; i < N; i++) + a[i] = b[i] + c[i]; +} + +void +f5 (void) +{ + int i; + #pragma omp parallel for simd schedule (simd:auto) + for (i = 0; i < N; i++) + a[i] = b[i] + c[i]; +} diff --git a/gcc/testsuite/c-c++-common/gomp/sink-1.c b/gcc/testsuite/c-c++-common/gomp/sink-1.c new file mode 100644 index 00000000000..4872a072315 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/sink-1.c @@ -0,0 +1,96 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -Wunknown-pragmas -Werror" } */ + +extern void bark (void); +int i,j,k; +int array[555]; + +int +main() +{ +#pragma omp parallel for ordered(2) + for (i=0; i < 100; ++i) + for (j=0; j < 100; ++j) + { +/* OUT variant does not apply to ORDERED construct. */ +#pragma omp ordered depend(out:i) /* { dg-error "invalid depend kind" } */ + +/* depend(sink...) is allowed without an offset. */ +#pragma omp ordered depend(sink:i,j-1) + +#pragma omp ordered depend(sink:i-1,j+2) + bark (); + } + +/* depend(sink...) does not apply to `omp task'. */ +#pragma omp task depend(sink:i+3) /* { dg-error "only allowed in 'omp ordered'" } */ + bark(); + +#pragma omp ordered depend(source) /* { dg-error "'depend' clause must be closely nested" } */ + +#pragma omp parallel for ordered(2) + for (i=0; i < 100; ++i) + for (j=0; j < 100; ++j) + { +/* Multiple depend(source) allowed. */ +#pragma omp ordered depend(source) +#pragma omp ordered depend(source) + } + +#pragma omp parallel for ordered(2) + for (i=0; i < 100; ++i) + for (j=0; j < 100; ++j) + { +#pragma omp ordered depend(sink:i-2,j-2,k+2) /* { dg-error "does not match number of iteration var" } */ + bark(); + } + +#pragma omp parallel for ordered(2) + for (i=0; i < 100; ++i) + for (j=0; j < 100; ++j) + { +#pragma omp ordered depend(sink:i-2) /* { dg-error "does not match number of iteration variables" } */ + bark(); + } + +#pragma omp parallel for ordered(2) + for (i=0; i < 100; ++i) + for (j=0; j < 100; ++j) + { +#pragma omp ordered depend(sink:k,i) /* { dg-error "is not an iteration" } */ + bark(); + } +} + +void bar (int, int, int); + +void +foo (int n, int m, int o) +{ + int i, j, k; + #pragma omp for collapse(2) ordered(3) + for (i = 0; i < m; i++) + { + for (j = 0; j < n; j++) + for (k = 0; k < o; k++) + { +#pragma omp ordered depend(sink: i-1,j,k) depend(sink: i,j-1,k-1) depend(sink: i-1,j-1,k+1) + bar (i, j, k); +#pragma omp ordered depend(source) + } + } +} + +int +baz () +{ + int i, j; +#pragma omp parallel for ordered(2) + for (i=0; i < 100; ++i) + for (j=0; j < 100; ++j) + { +#pragma omp ordered depend(sink:i-1,j-3) + bar (i, j, 0); +#pragma omp ordered depend(source) + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/sink-2.c b/gcc/testsuite/c-c++-common/gomp/sink-2.c new file mode 100644 index 00000000000..e781a6fd945 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/sink-2.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ + +void bar (int *); + +void +foo () +{ + int i,j; +#pragma omp parallel for ordered(1) + for (i=0; i < 100; ++i) + { +#pragma omp ordered depend(sink:i-1) + bar(&i); +#pragma omp ordered depend(source) + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/sink-3.c b/gcc/testsuite/c-c++-common/gomp/sink-3.c new file mode 100644 index 00000000000..7cb16ed0f76 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/sink-3.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +/* Test that we can handle multiple undeclared sink variables + gracefully. */ + +void bar (int *); + +void +foo () +{ + int i,j; +#pragma omp parallel for ordered(1) + for (i=0; i < 100; ++i) + { +#pragma omp ordered depend(sink:poo-1,paa+1) /* { dg-error "poo.*declared.*paa.*declared" } */ + bar(&i); +#pragma omp ordered depend(source) + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/sink-4.c b/gcc/testsuite/c-c++-common/gomp/sink-4.c new file mode 100644 index 00000000000..11b6d9973c9 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/sink-4.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -fdump-tree-omplower" } */ + +/* Test that we adjust pointer offsets for sink variables + correctly. */ + +typedef struct { + char stuff[400]; +} foo; + +void +funk (foo *begin, foo *end) +{ + foo *p; +#pragma omp parallel for ordered(1) + for (p=end; p > begin; p--) + { +#pragma omp ordered depend(sink:p+1) + void bar (); + bar(); +#pragma omp ordered depend(source) + } +} + +/* { dg-final { scan-tree-dump-times "depend\\(sink:p\\+400\\)" 1 "omplower" } } */ diff --git a/gcc/testsuite/c-c++-common/gomp/udr-1.c b/gcc/testsuite/c-c++-common/gomp/udr-1.c new file mode 100644 index 00000000000..7c50ff6f9b7 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/udr-1.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +struct S {}; +void foo (void *, void *); +void bar (void *, void *); +void baz (void *); +#pragma omp declare reduction(+:struct S:foo (&omp_out, &omp_in))initializer(bar(&omp_priv, &omp_orig)) + +void +test (void) +{ + struct S a, b[10]; + #pragma omp parallel reduction(+:a) + baz (&a); +} diff --git a/gcc/testsuite/c-c++-common/taskloop-1.c b/gcc/testsuite/c-c++-common/taskloop-1.c new file mode 100644 index 00000000000..f5c3a5d153f --- /dev/null +++ b/gcc/testsuite/c-c++-common/taskloop-1.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ + +int e; +int bar (int, int); +void baz (int, int, int, int *, int *, int *); + +void +foo (int a, int b, int c, int d, int f, int g, int h, int j, int k, int l) +{ + int i; + #pragma omp taskloop if (a) final (b) untied default(none) mergeable \ + private(c) firstprivate (e) shared (d) num_tasks(f) collapse(1) + for (i = bar (g, h) + j; i < k; i += l) + baz (i, d, e++, &c, &d, &e); +} diff --git a/gcc/testsuite/g++.dg/gomp/clause-1.C b/gcc/testsuite/g++.dg/gomp/clause-1.C index 76683ecf6ee..76ee4970fc3 100644 --- a/gcc/testsuite/g++.dg/gomp/clause-1.C +++ b/gcc/testsuite/g++.dg/gomp/clause-1.C @@ -9,22 +9,22 @@ struct T void T::test() { - #pragma omp parallel private(n) // { dg-error "T::n" } + #pragma omp parallel private(n) n = 1; #pragma omp parallel shared(n) // { dg-error "T::n" } n = 1; - #pragma omp parallel firstprivate(n) // { dg-error "T::n" } + #pragma omp parallel firstprivate(n) n = 1; - #pragma omp sections lastprivate(n) // { dg-error "T::n" } + #pragma omp sections lastprivate(n) { n = 1; } - #pragma omp parallel reduction(+:n) // { dg-error "T::n" } + #pragma omp parallel reduction(+:n) n = 1; - #pragma omp single copyprivate(n) // { dg-error "T::n" } + #pragma omp single copyprivate(n) n = 1; #pragma omp parallel copyin(n) // { dg-error "T::n" } diff --git a/gcc/testsuite/g++.dg/gomp/clause-3.C b/gcc/testsuite/g++.dg/gomp/clause-3.C index 1a20440d7c2..54f795717dd 100644 --- a/gcc/testsuite/g++.dg/gomp/clause-3.C +++ b/gcc/testsuite/g++.dg/gomp/clause-3.C @@ -34,6 +34,9 @@ foo (int x) #pragma omp p for lastprivate (x, x) // { dg-error "more than once" } for (i = 0; i < 10; i++) ; +#pragma omp p for linear (x, x) // { dg-error "more than once" } + for (i = 0; i < 10; i++) + ; #pragma omp single private (x) copyprivate (x) // { dg-error "more than once" } ; #pragma omp p shared (bar) // { dg-error "is not a variable" } @@ -46,7 +49,7 @@ foo (int x) ; #pragma omp p reduction (*:s) // { dg-error "user defined reduction not found for" } ; -#pragma omp p reduction (-:a) // { dg-error "has invalid type for" } +#pragma omp p reduction (-:a) ; d = 0; #pragma omp p reduction (*:d) @@ -80,6 +83,9 @@ foo (int x) ; #pragma omp p reduction (*:t) // { dg-error "predetermined 'threadprivate'" } ; +#pragma omp p for linear (t) // { dg-error "predetermined 'threadprivate'" } + for (i = 0; i < 10; i++) + ; #pragma omp p shared (c) // { dg-error "predetermined 'shared'" } ; #pragma omp p private (c) // { dg-error "predetermined 'shared'" } @@ -91,4 +97,7 @@ foo (int x) ; #pragma omp p reduction (*:c) // { dg-error "predetermined 'shared'" } ; +#pragma omp p for linear (c:2) // { dg-error "predetermined 'shared'" } + for (i = 0; i < 10; i++) + ; } diff --git a/gcc/testsuite/g++.dg/gomp/declare-simd-3.C b/gcc/testsuite/g++.dg/gomp/declare-simd-3.C new file mode 100644 index 00000000000..5a444e57121 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/declare-simd-3.C @@ -0,0 +1,49 @@ +// { dg-do compile } + +#pragma omp declare simd uniform(b) linear(c, d) linear(uval(e)) linear(ref(f)) +int f1 (int a, int b, int c, int &d, int &e, int &f) +{ + a++; + b++; + c++; + d++; + e++; + f++; + return a + b + c + d + e + f; +} + +#pragma omp declare simd uniform(b) linear(c, d) linear(uval(e)) linear(ref(f)) +int f2 (int a, int b, int c, int &d, int &e, int &f) +{ + asm volatile ("" : : "r" (&a)); + asm volatile ("" : : "r" (&b)); + asm volatile ("" : : "r" (&c)); + asm volatile ("" : : "r" (&d)); + asm volatile ("" : : "r" (&e)); + asm volatile ("" : : "r" (&f)); + a++; + b++; + c++; + d++; + e++; + f++; + return a + b + c + d + e + f; +} + +#pragma omp declare simd uniform(b) linear(c, d) linear(uval(e)) linear(ref(f)) +int f3 (const int a, const int b, const int c, const int &d, const int &e, const int &f) +{ + return a + b + c + d + e + f; +} + +#pragma omp declare simd uniform(b) linear(c, d) linear(uval(e)) linear(ref(f)) +int f4 (const int a, const int b, const int c, const int &d, const int &e, const int &f) +{ + asm volatile ("" : : "r" (&a)); + asm volatile ("" : : "r" (&b)); + asm volatile ("" : : "r" (&c)); + asm volatile ("" : : "r" (&d)); + asm volatile ("" : : "r" (&e)); + asm volatile ("" : : "r" (&f)); + return a + b + c + d + e + f; +} diff --git a/gcc/testsuite/g++.dg/gomp/linear-1.C b/gcc/testsuite/g++.dg/gomp/linear-1.C new file mode 100644 index 00000000000..68d58fee59f --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/linear-1.C @@ -0,0 +1,48 @@ +// { dg-do compile } +// { dg-options "-fopenmp" } + +int i; + +#pragma omp declare simd linear (ref (x) : 1) linear (uval (y) : 2) +int bar (int &x, int &y, int z); + +void +foo (int &x, int &y) +{ + #pragma omp simd linear (x: y + 1) + for (i = 0; i < 10; i++) + x += y + 1; + #pragma omp simd linear (val (x): y + 1) // { dg-error "modifier should not be specified in" } + for (i = 0; i < 10; i++) + x += y + 1; + #pragma omp simd linear (ref (x): y + 1) // { dg-error "modifier should not be specified in" } + for (i = 0; i < 10; i++) + x += y + 1; + #pragma omp simd linear (uval (x): y + 1) // { dg-error "modifier should not be specified in" } + for (i = 0; i < 10; i++) + x += y + 1; + #pragma omp for linear (x: y + 1) + for (i = 0; i < 10; i++) + x += y + 1; + #pragma omp for linear (val (x): y + 1) // { dg-error "modifier should not be specified in" } + for (i = 0; i < 10; i++) + x += y + 1; + #pragma omp for linear (ref (x): y + 1) // { dg-error "modifier should not be specified in" } + for (i = 0; i < 10; i++) + x += y + 1; + #pragma omp for linear (uval (x): y + 1) // { dg-error "modifier should not be specified in" } + for (i = 0; i < 10; i++) + x += y + 1; + #pragma omp for simd linear (x: y + 1) + for (i = 0; i < 10; i++) + x += y + 1; + #pragma omp for simd linear (val (x): y + 1) // { dg-error "modifier should not be specified in" } + for (i = 0; i < 10; i++) + x += y + 1; + #pragma omp for simd linear (ref (x): y + 1) // { dg-error "modifier should not be specified in" } + for (i = 0; i < 10; i++) + x += y + 1; + #pragma omp for simd linear (uval (x): y + 1) // { dg-error "modifier should not be specified in" } + for (i = 0; i < 10; i++) + x += y + 1; +} diff --git a/gcc/testsuite/g++.dg/gomp/member-1.C b/gcc/testsuite/g++.dg/gomp/member-1.C new file mode 100644 index 00000000000..cf32b098123 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/member-1.C @@ -0,0 +1,252 @@ +struct T { T () {}; virtual ~T () {}; int t; }; +struct S : virtual public T { int a; void foo (); }; +template +struct U { U () {}; virtual ~U () {}; T t; }; +template +struct V : virtual public U { T a; void foo (); }; + +void +S::foo () +{ +#pragma omp parallel firstprivate (a, t) + { + int *q1 = &a; + int *q2 = &this->a; + int q3 = a; + int q4 = this->a; + int *q5 = &t; + int *q6 = &this->t; + int q7 = t; + int q8 = this->t; + int q9 = T::t; + int q10 = this->T::t; + int &q11 = a; + int &q12 = this->a; + int &q13 = t; + int &q14 = this->t; + int &q15 = S::a; + int &q16 = this->S::a; + int &q17 = T::t; + int &q18 = this->T::t; + } +#pragma omp parallel private (a, t) + { + a = 7; + S::a += 9; + t = 10; + T::t += 11; + } +#pragma omp parallel + { + #pragma omp sections lastprivate (S::a, T::t) + { + #pragma omp section + { + S::a = 6; + T::t = 8; + } + } + } +#pragma omp parallel + { + #pragma omp for firstprivate (a, t) lastprivate (a, t) + for (int i = 0; i < 10; i++) + { + int q19 = a + t; + if (i == 9) + { + a = i; + T::t = i + 2; + } + } + } +#pragma omp sections lastprivate (a, t) + { + #pragma omp section + { + a = 5; + t = 6; + } + } +#pragma omp for firstprivate (a, t) lastprivate (a, t) + for (int i = 0; i < 10; i++) + { + int q20 = a + t; + if (i == 9) + { + a = i; + T::t = i + 2; + } + } +#pragma omp parallel sections lastprivate (a, t) + { + #pragma omp section + { + a = 5; + t = 6; + } + } +#pragma omp parallel + { + #pragma omp task firstprivate (a, t) + { + S::a++; + t++; + } + } +#pragma omp parallel + { + #pragma omp taskloop firstprivate (a, t) lastprivate (t) + for (int i = 0; i < a; i++) + t++; + } +#pragma omp taskloop firstprivate (a, t) lastprivate (t) + for (int i = 0; i < a; i++) + t++; + a = 1; + t = 0; +#pragma omp parallel sections reduction (*: S::a) reduction (+: t) + { + { + a = 1; + t = 2; + } + #pragma omp section + { + a = 2; + t = 3; + } + #pragma omp section + { + a = 3; + t = 4; + } + } +} + +template +void +V::foo () +{ +#pragma omp parallel firstprivate (a, U::t) + { + int *q1 = &a; + int *q2 = &this->a; + int q3 = a; + int q4 = this->a; + int *q5 = &(U::t); + int *q6 = &this->U::t; + int q7 = U::t; + int q8 = this->U::t; + int q9 = U::t; + int q10 = this->U::t; + int &q11 = a; + int &q12 = this->a; + int &q13 = U::t; + int &q14 = this->U::t; + int &q15 = V::a; + int &q16 = this->V::a; + int &q17 = U::t; + int &q18 = this->U::t; + } +#pragma omp parallel private (a, U::t) + { + a = 7; + V::a += 9; + U::t = 10; + U::t += 11; + } +#pragma omp parallel + { + #pragma omp sections lastprivate (V::a, U::t) + { + #pragma omp section + { + V::a = 6; + U::t = 8; + } + } + } +#pragma omp parallel + { + #pragma omp for firstprivate (a, U::t) lastprivate (a, U::t) + for (int i = 0; i < 10; i++) + { + int q19 = a + U::t; + if (i == 9) + { + a = i; + U::t = i + 2; + } + } + } +#pragma omp sections lastprivate (a, U::t) + { + #pragma omp section + { + a = 5; + U::t = 6; + } + } +#pragma omp for firstprivate (a, U::t) lastprivate (a, U::t) + for (int i = 0; i < 10; i++) + { + int q20 = a + U::t; + if (i == 9) + { + a = i; + U::t = i + 2; + } + } +#pragma omp parallel sections lastprivate (a, U::t) + { + #pragma omp section + { + a = 5; + U::t = 6; + } + } +#pragma omp parallel + { + #pragma omp task firstprivate (a, U::t) + { + V::a++; + U::t++; + } + } +#pragma omp parallel + { + #pragma omp taskloop firstprivate (a, U::t) lastprivate (U::t) + for (int i = 0; i < a; i++) + U::t++; + } +#pragma omp taskloop firstprivate (a, U::t) lastprivate (U::t) + for (int i = 0; i < a; i++) + U::t++; + a = 1; + U::t = 0; +#pragma omp parallel sections reduction (*: V::a) reduction (+: U::t) + { + { + a = 1; + U::t = 2; + } + #pragma omp section + { + a = 2; + U::t = 3; + } + #pragma omp section + { + a = 3; + U::t = 4; + } + } +} + +void +bar () +{ + V v; + v.foo (); +} diff --git a/gcc/testsuite/g++.dg/gomp/member-2.C b/gcc/testsuite/g++.dg/gomp/member-2.C new file mode 100644 index 00000000000..97c03952a13 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/member-2.C @@ -0,0 +1,168 @@ +// { dg-do compile } +// { dg-options "-fopenmp" } + +int d; + +struct A +{ + A () : a(2), b(3), c(d) {} + A (int x) : a(2), b(x), c(d) {} + int a; + A (const A &); + A &operator= (const A &); + const A &operator= (const A &) const; + mutable int b; + int &c; +}; + +struct B : public A +{ + B () : h(5) {} + ~B (); + B (const B &); + A e; + mutable A f; + const A g; + const int h; + int m1 (); + int m2 (); + int m3 () const; + int m4 () const; +}; + +void foo (A &); + +#pragma omp declare reduction (+:A:omp_out.b += omp_in.b) initializer (foo (omp_priv)) + +int +B::m1 () +{ + #pragma omp parallel private (a, b, c, e, f, g) + ; + #pragma omp parallel firstprivate (a, b, c, e, f, g) + ; + #pragma omp parallel for lastprivate (a, b, c, e, f, g) + for (int i = 0; i < 10; i++) + ; + #pragma omp simd linear (a, b, c : 1) + for (int i = 0; i < 10; i++) + { + a++; + b++; + c++; + } + #pragma omp parallel for reduction (+:a, b, c, e, f) + for (int i = 0; i < 10; i++) + ; + return 0; +} + +int +B::m2 () +{ + #pragma omp parallel private (h) // { dg-error "is predetermined .shared. for .private." } + ; + #pragma omp parallel firstprivate (h) + ; + #pragma omp parallel for lastprivate (h) // { dg-error "is predetermined .shared. for .lastprivate." } + for (int i = 0; i < 10; i++) + ; + #pragma omp simd linear (h : 1) // { dg-error "is predetermined .shared. for .linear." } + for (int i = 0; i < 10; i++) + ; + #pragma omp parallel for reduction (+:h) // { dg-error "is predetermined .shared. for .reduction." } + for (int i = 0; i < 10; i++) + ; + #pragma omp parallel for reduction (+:g) // { dg-error "has const type for .reduction." } + for (int i = 0; i < 10; i++) + ; + #pragma omp parallel shared (a) // { dg-error "is not a variable in clause" } + ; + #pragma omp parallel shared (b) // { dg-error "is not a variable in clause" } + ; + #pragma omp parallel shared (c) // { dg-error "is not a variable in clause" } + ; + #pragma omp parallel shared (e) // { dg-error "is not a variable in clause" } + ; + #pragma omp parallel shared (f) // { dg-error "is not a variable in clause" } + ; + #pragma omp parallel shared (g) // { dg-error "is not a variable in clause" } + ; + #pragma omp parallel shared (h) // { dg-error "is not a variable in clause" } + ; + return 0; +} + +int +B::m3 () const +{ + #pragma omp parallel private (b, c, e, f, g) + ; + #pragma omp parallel firstprivate (b, c, e, f, g) + ; + #pragma omp parallel for lastprivate (b, c, e, f, g) + for (int i = 0; i < 10; i++) + ; + #pragma omp simd linear (b, c : 1) + for (int i = 0; i < 10; i++) + { + b++; + c++; + } + #pragma omp parallel for reduction (+:b, c, f) + for (int i = 0; i < 10; i++) + ; + return 0; +} + +int +B::m4 () const +{ + #pragma omp parallel private (a) // { dg-error "is predetermined .shared. for .private." } + ; + #pragma omp parallel firstprivate (a) + ; + #pragma omp parallel for lastprivate (a) // { dg-error "is predetermined .shared. for .lastprivate." } + for (int i = 0; i < 10; i++) + ; + #pragma omp simd linear (a : 1) // { dg-error "is predetermined .shared. for .linear." } + for (int i = 0; i < 10; i++) + ; + #pragma omp parallel for reduction (+:a) // { dg-error "is predetermined .shared. for .reduction." } + for (int i = 0; i < 10; i++) + ; + #pragma omp parallel private (h) // { dg-error "is predetermined .shared. for .private." } + ; + #pragma omp parallel firstprivate (h) + ; + #pragma omp parallel for lastprivate (h) // { dg-error "is predetermined .shared. for .lastprivate." } + for (int i = 0; i < 10; i++) + ; + #pragma omp simd linear (h : 1) // { dg-error "is predetermined .shared. for .linear." } + for (int i = 0; i < 10; i++) + ; + #pragma omp parallel for reduction (+:h) // { dg-error "is predetermined .shared. for .reduction." } + for (int i = 0; i < 10; i++) + ; + #pragma omp parallel for reduction (+:e) // { dg-error "has const type for .reduction." } + for (int i = 0; i < 10; i++) + ; + #pragma omp parallel for reduction (+:g) // { dg-error "has const type for .reduction." } + for (int i = 0; i < 10; i++) + ; + #pragma omp parallel shared (a) // { dg-error "is not a variable in clause" } + ; + #pragma omp parallel shared (b) // { dg-error "is not a variable in clause" } + ; + #pragma omp parallel shared (c) // { dg-error "is not a variable in clause" } + ; + #pragma omp parallel shared (e) // { dg-error "is not a variable in clause" } + ; + #pragma omp parallel shared (f) // { dg-error "is not a variable in clause" } + ; + #pragma omp parallel shared (g) // { dg-error "is not a variable in clause" } + ; + #pragma omp parallel shared (h) // { dg-error "is not a variable in clause" } + ; + return 0; +} diff --git a/gcc/testsuite/g++.dg/gomp/pr66571-2.C b/gcc/testsuite/g++.dg/gomp/pr66571-2.C new file mode 100644 index 00000000000..ac4c609c90c --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/pr66571-2.C @@ -0,0 +1,36 @@ +// PR c++/66571 +// { dg-do compile } +// { dg-options "-fopenmp" } + +template +extern void bar (T, T, T, T); + +template +void +foo (T a, T b, T c, T d) +{ + #pragma omp parallel for simd private (a) firstprivate (b) lastprivate (c) linear (d:2) + for (int i = 0; i < 10; i++) + bar (a, b, c, d), d += 2; + #pragma omp parallel private (c) + #pragma omp single copyprivate (c) + bar (a, b, c, d); + T e = a; + T f = b; + T g = c; + T h = d; + #pragma omp parallel for simd private (e) firstprivate (f) lastprivate (g) linear (h:2) + for (int i = 0; i < 10; i++) + bar (e, f, g, h), h += 2; + #pragma omp parallel private (g) + #pragma omp single copyprivate (g) + bar (e, f, g, h); +} + +void +baz () +{ + int a = 0, b = 0, c = 0, d = 0; + foo (a, b, c, d); + foo (a, b, c, d); +} diff --git a/gcc/testsuite/g++.dg/gomp/pr67504.C b/gcc/testsuite/g++.dg/gomp/pr67504.C index 0f1758b6f14..8270b7cf494 100644 --- a/gcc/testsuite/g++.dg/gomp/pr67504.C +++ b/gcc/testsuite/g++.dg/gomp/pr67504.C @@ -12,4 +12,8 @@ foo (T x) #pragma omp for collapse (x + 1) // { dg-error "collapse argument needs positive constant integer expression" } for (int i = 0; i < 10; i++) ; + #pragma omp for ordered (x + 1) // { dg-error "ordered argument needs positive constant integer expression" } + for (int i = 0; i < 10; i++) + for (int j = 0; j < 10; j++) + ; } diff --git a/gcc/testsuite/g++.dg/gomp/pr67522.C b/gcc/testsuite/g++.dg/gomp/pr67522.C index 84c854afd92..da8cb74d1fa 100644 --- a/gcc/testsuite/g++.dg/gomp/pr67522.C +++ b/gcc/testsuite/g++.dg/gomp/pr67522.C @@ -17,6 +17,10 @@ foo (void) #pragma omp task depend (inout: S[0:10]) // { dg-error "is not a variable in" } ; + + #pragma omp for reduction (+:S[0:10]) // { dg-error "is not a variable in" } + for (int i = 0; i < 16; i++) + ; } void diff --git a/gcc/testsuite/g++.dg/gomp/reference-1.C b/gcc/testsuite/g++.dg/gomp/reference-1.C new file mode 100644 index 00000000000..d53ca93d6f1 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/reference-1.C @@ -0,0 +1,26 @@ +// { dg-do compile } + +struct S; // { dg-message "forward declaration" } +void foo (S &); + +void +f1 (S &x) // { dg-error "has incomplete type" } +{ +#pragma omp parallel private (x) + foo (x); +} + +void +f2 (S &x) // { dg-error "has incomplete type" } +{ +#pragma omp parallel firstprivate (x) + foo (x); +} + +void +f3 (S &x) // { dg-error "has incomplete type" } +{ +#pragma omp parallel for lastprivate (x) + for (int i = 0; i < 10; i++) + foo (x); +} diff --git a/gcc/testsuite/g++.dg/gomp/sink-1.C b/gcc/testsuite/g++.dg/gomp/sink-1.C new file mode 100644 index 00000000000..982d36c7aa0 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/sink-1.C @@ -0,0 +1,22 @@ +/* { dg-do compile } */ + +void bar (int, int, int); + +template +void baz () +{ + T i, j; +#pragma omp parallel for ordered(2) + for (i=0; i < 100; ++i) + for (j=0; j < 100; ++j) + { +#pragma omp ordered depend(sink:i-3,j) + bar (i, j, 0); +#pragma omp ordered depend(source) + } +} + +int main() +{ + baz(); +} diff --git a/gcc/testsuite/g++.dg/gomp/sink-2.C b/gcc/testsuite/g++.dg/gomp/sink-2.C new file mode 100644 index 00000000000..d1681a77aad --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/sink-2.C @@ -0,0 +1,64 @@ +/* { dg-do compile } */ + +/* Tests iterators are allowed in ordered loops and that we keep track + of the original iterator DECL for diagnostic purposes. */ + +#include +#include + +/* Test plain iterator. */ +void foo1 () +{ + std::vector v; + for (int i=1; i<=5; i++) v.push_back(i); + + std::vector::const_iterator it; + +#pragma omp parallel for ordered(1) + for (it = v.begin(); it < v.end(); ++it) + { +#pragma omp ordered depend(sink:it-1) + std::cout << *it << '\n'; +#pragma omp ordered depend(source) + } +} + +/* Test non-dependent iterator in a template. */ +template +void foo2 () +{ + std::vector v; + for (int i=1; i<=5; i++) v.push_back(i); + + std::vector::const_iterator it; +#pragma omp parallel for ordered(1) + for (it = v.begin(); it < v.end(); ++it) + { +#pragma omp ordered depend(sink:it-1) + std::cout << *it << '\n'; +#pragma omp ordered depend(source) + } +} + +/* Test dependent iterator in a template. */ +template +void foo3 () +{ + std::vector v; + for (int i=1; i<=5; i++) v.push_back(i); + + typename std::vector::const_iterator it; +#pragma omp parallel for ordered(1) + for (it = v.begin(); it < v.end(); ++it) + { +#pragma omp ordered depend(sink:it-1) + std::cout << *it << '\n'; +#pragma omp ordered depend(source) + } +} + +int main () +{ + foo2 <0> (); + foo3 (); +} diff --git a/gcc/testsuite/g++.dg/gomp/sink-3.C b/gcc/testsuite/g++.dg/gomp/sink-3.C new file mode 100644 index 00000000000..4271d66faef --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/sink-3.C @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -fdump-tree-gimple" } */ + +/* Test that we adjust pointer offsets for sink variables + correctly. */ + +typedef struct { + char stuff[400]; +} foo; + +foo *end, *begin, *p; + +template +void +funk () +{ + int i,j; +#pragma omp parallel for ordered(1) + for (p=end; p > begin; p--) + { +#pragma omp ordered depend(sink:p+1) + void bar (); + bar(); +#pragma omp ordered depend(source) + } +} + +void foobar() +{ + funk<3>(); +} + +/* { dg-final { scan-tree-dump-times "depend\\(sink:p\\+400\\)" 1 "gimple" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/task-1.C b/gcc/testsuite/g++.dg/gomp/task-1.C index 0000e6f1fa9..7f40279caf7 100644 --- a/gcc/testsuite/g++.dg/gomp/task-1.C +++ b/gcc/testsuite/g++.dg/gomp/task-1.C @@ -10,8 +10,8 @@ const A a; void foo (A &p) { const A &q = a; -#pragma omp task // { dg-error "has reference type" } +#pragma omp task bar (p); -#pragma omp task // { dg-error "has reference type" } +#pragma omp task bar (q); } diff --git a/gcc/testsuite/g++.dg/gomp/this-1.C b/gcc/testsuite/g++.dg/gomp/this-1.C new file mode 100644 index 00000000000..0e2dd8caa23 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/this-1.C @@ -0,0 +1,68 @@ +// { dg-do compile } +// { dg-options "-fopenmp" } + +struct S +{ + #pragma omp declare simd linear(this) // { dg-error "is not an function argument" } + static void foo (); + void bar (); +}; + +void +S::bar () +{ + #pragma omp parallel firstprivate (this) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + ; + #pragma omp parallel for lastprivate (this) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + for (int i = 0; i < 10; i++) + ; + #pragma omp parallel shared (this) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + ; + #pragma omp for linear (this) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + for (int i = 0; i < 10; i++) + ; + #pragma omp task depend(inout: this) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + ; + #pragma omp task depend(inout: this[0]) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + ; + #pragma omp parallel private (this) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + { + #pragma omp single copyprivate (this) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + ; + } +} + +template +struct T +{ + #pragma omp declare simd linear(this) // { dg-error "is not an function argument" } + static void foo (); + void bar (); +}; + +template +void +T::bar () +{ + #pragma omp parallel firstprivate (this) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + ; + #pragma omp parallel for lastprivate (this) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + for (int i = 0; i < 10; i++) + ; + #pragma omp parallel shared (this) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + ; + #pragma omp for linear (this) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + for (int i = 0; i < 10; i++) + ; + #pragma omp task depend(inout: this) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + ; + #pragma omp task depend(inout: this[0]) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + ; + #pragma omp parallel private (this) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + { + #pragma omp single copyprivate (this) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + ; + } +} + +template struct T<0>; diff --git a/gcc/testsuite/g++.dg/gomp/this-2.C b/gcc/testsuite/g++.dg/gomp/this-2.C new file mode 100644 index 00000000000..d03b8a0728e --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/this-2.C @@ -0,0 +1,42 @@ +// { dg-do compile } +// { dg-options "-fopenmp" } + +struct S +{ + void bar (int); +}; + +void +S::bar (int x) +{ + #pragma omp target map (this, x) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + ; + #pragma omp target map (this[0], x) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + ; + #pragma omp target update to (this, x) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + #pragma omp target update to (this[0], x) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + #pragma omp target update from (this, x) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + #pragma omp target update from (this[1], x) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } +} + +template +struct T +{ + void bar (int); +}; + +template +void +T::bar (int x) +{ + #pragma omp target map (this, x) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + ; + #pragma omp target map (this[0], x) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + ; + #pragma omp target update to (this, x) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + #pragma omp target update to (this[0], x) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + #pragma omp target update from (this, x) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + #pragma omp target update from (this[1], x) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } +} + +template struct T<0>; diff --git a/gcc/testsuite/g++.dg/vect/simd-clone-2.cc b/gcc/testsuite/g++.dg/vect/simd-clone-2.cc new file mode 100644 index 00000000000..1a1b982fc20 --- /dev/null +++ b/gcc/testsuite/g++.dg/vect/simd-clone-2.cc @@ -0,0 +1,55 @@ +// { dg-require-effective-target vect_simd_clones } +// { dg-additional-options "-fopenmp-simd -fno-inline -DONE_FILE" } +// { dg-additional-options "-mavx" { target avx_runtime } } + +#include "../../gcc.dg/vect/tree-vect.h" + +#ifdef ONE_FILE +#include "simd-clone-3.cc" +#else +#include "simd-clone-2.h" +#endif + +T b __attribute__((aligned (32))); + +void +do_main () +{ + int i, r = 0; + S a[64]; + for (i = 0; i < 64; i++) + { + a[i].s = i; + b.t[i] = i; + } + #pragma omp simd reduction(+:r) + for (i = 0; i < 64; i++) + r += a[16].f0 (i); + if (r != 64 * 63 / 2 + 64 * 16) + __builtin_abort (); + r = 0; + #pragma omp simd reduction(+:r) + for (i = 0; i < 64; i++) + r += a[32].f1 (i); + if (r != 64 * 63 / 2 + 64 * 32) + __builtin_abort (); + r = 0; + #pragma omp simd reduction(+:r) + for (i = 0; i < 64; i++) + r += a[i].f2 (i); + if (r != 64 * 63) + __builtin_abort (); + r = 0; + #pragma omp simd reduction(+:r) + for (i = 0; i < 64; i++) + r += b.f3 (i); + if (r != 64 * 63 / 2) + __builtin_abort (); +} + +int +main () +{ + check_vect (); + do_main (); +} diff --git a/gcc/testsuite/g++.dg/vect/simd-clone-2.h b/gcc/testsuite/g++.dg/vect/simd-clone-2.h new file mode 100644 index 00000000000..d082330f6b7 --- /dev/null +++ b/gcc/testsuite/g++.dg/vect/simd-clone-2.h @@ -0,0 +1,17 @@ +struct S +{ + int s; + #pragma omp declare simd notinbranch + int f0 (int x); + #pragma omp declare simd notinbranch uniform(this) + int f1 (int x); + #pragma omp declare simd notinbranch linear(this:sizeof(this)/sizeof(this)) + int f2 (int x); +}; + +struct T +{ + int t[64]; + #pragma omp declare simd aligned(this:32) uniform(this) linear(x) + int f3 (int x); +}; diff --git a/gcc/testsuite/g++.dg/vect/simd-clone-3.cc b/gcc/testsuite/g++.dg/vect/simd-clone-3.cc new file mode 100644 index 00000000000..1057a7eb5f6 --- /dev/null +++ b/gcc/testsuite/g++.dg/vect/simd-clone-3.cc @@ -0,0 +1,34 @@ +// { dg-require-effective-target vect_simd_clones } +// { dg-additional-options "-fopenmp-simd -fno-inline" } +// { dg-additional-options "-mavx" { target avx_runtime } } +// { dg-additional-sources "simd-clone-2.cc" } + +#include "simd-clone-2.h" + +#pragma omp declare simd notinbranch +int +S::f0 (int x) +{ + return x + s; +} + +#pragma omp declare simd notinbranch uniform(this) +int +S::f1 (int x) +{ + return x + s; +} + +#pragma omp declare simd notinbranch linear(this:sizeof(this)/sizeof(this)) +int +S::f2 (int x) +{ + return x + this->S::s; +} + +#pragma omp declare simd uniform(this) aligned(this:32) linear(x) +int +T::f3 (int x) +{ + return t[x]; +} diff --git a/gcc/testsuite/g++.dg/vect/simd-clone-4.cc b/gcc/testsuite/g++.dg/vect/simd-clone-4.cc new file mode 100644 index 00000000000..32bdfd446ae --- /dev/null +++ b/gcc/testsuite/g++.dg/vect/simd-clone-4.cc @@ -0,0 +1,55 @@ +// { dg-require-effective-target vect_simd_clones } +// { dg-additional-options "-fopenmp-simd -fno-inline -DONE_FILE" } +// { dg-additional-options "-mavx" { target avx_runtime } } + +#include "../../gcc.dg/vect/tree-vect.h" + +#ifdef ONE_FILE +#include "simd-clone-5.cc" +#else +#include "simd-clone-4.h" +#endif + +T<0> b __attribute__((aligned (32))); + +void +do_main () +{ + int i, r = 0; + S<0> a[64]; + for (i = 0; i < 64; i++) + { + a[i].s = i; + b.t[i] = i; + } + #pragma omp simd reduction(+:r) + for (i = 0; i < 64; i++) + r += a[16].f0 (i); + if (r != 64 * 63 / 2 + 64 * 16) + __builtin_abort (); + r = 0; + #pragma omp simd reduction(+:r) + for (i = 0; i < 64; i++) + r += a[32].f1 (i); + if (r != 64 * 63 / 2 + 64 * 32) + __builtin_abort (); + r = 0; + #pragma omp simd reduction(+:r) + for (i = 0; i < 64; i++) + r += a[i].f2 (i); + if (r != 64 * 63) + __builtin_abort (); + r = 0; + #pragma omp simd reduction(+:r) + for (i = 0; i < 64; i++) + r += b.f3 (i); + if (r != 64 * 63 / 2) + __builtin_abort (); +} + +int +main () +{ + check_vect (); + do_main (); +} diff --git a/gcc/testsuite/g++.dg/vect/simd-clone-4.h b/gcc/testsuite/g++.dg/vect/simd-clone-4.h new file mode 100644 index 00000000000..2b0244cac9c --- /dev/null +++ b/gcc/testsuite/g++.dg/vect/simd-clone-4.h @@ -0,0 +1,19 @@ +template +struct S +{ + int s; + #pragma omp declare simd notinbranch + int f0 (int x); + #pragma omp declare simd notinbranch uniform(this) + int f1 (int x); + #pragma omp declare simd notinbranch linear(this:sizeof(this)/sizeof(this)) + int f2 (int x); +}; + +template +struct T +{ + int t[64]; + #pragma omp declare simd aligned(this:32) uniform(this) linear(x) + int f3 (int x); +}; diff --git a/gcc/testsuite/g++.dg/vect/simd-clone-5.cc b/gcc/testsuite/g++.dg/vect/simd-clone-5.cc new file mode 100644 index 00000000000..07ec8a8079e --- /dev/null +++ b/gcc/testsuite/g++.dg/vect/simd-clone-5.cc @@ -0,0 +1,41 @@ +// { dg-require-effective-target vect_simd_clones } +// { dg-additional-options "-fopenmp-simd -fno-inline" } +// { dg-additional-options "-mavx" { target avx_runtime } } +// { dg-additional-sources "simd-clone-4.cc" } + +#include "simd-clone-4.h" + +#pragma omp declare simd notinbranch +template +int +S::f0 (int x) +{ + return x + s; +} + +#pragma omp declare simd notinbranch uniform(this) +template +int +S::f1 (int x) +{ + return x + s; +} + +#pragma omp declare simd notinbranch linear(this:sizeof(this)/sizeof(this)) +template +int +S::f2 (int x) +{ + return x + this->S::s; +} + +#pragma omp declare simd uniform(this) aligned(this:32) linear(x) +template +int +T::f3 (int x) +{ + return t[x]; +} + +template struct S<0>; +template struct T<0>; diff --git a/gcc/testsuite/gcc.dg/gomp/clause-1.c b/gcc/testsuite/gcc.dg/gomp/clause-1.c index fc7d72b7cd2..c2d1fc69ed4 100644 --- a/gcc/testsuite/gcc.dg/gomp/clause-1.c +++ b/gcc/testsuite/gcc.dg/gomp/clause-1.c @@ -34,6 +34,9 @@ foo (int x) #pragma omp p for lastprivate (x, x) /* { dg-error "more than once" } */ for (i = 0; i < 10; i++) ; +#pragma omp p for linear (x, x) /* { dg-error "more than once" } */ + for (i = 0; i < 10; i++) + ; #pragma omp single private (x) copyprivate (x) /* { dg-error "more than" } */ ; #pragma omp p shared (bar) /* { dg-error "is not a variable" } */ @@ -46,7 +49,7 @@ foo (int x) ; #pragma omp p reduction (*:s) /* { dg-error "user defined reduction not found for" } */ ; -#pragma omp p reduction (-:a) /* { dg-error "user defined reduction not found for" } */ +#pragma omp p reduction (-:a) ; d = 0; #pragma omp p reduction (*:d) @@ -80,6 +83,9 @@ foo (int x) ; #pragma omp p reduction (*:t) /* { dg-error "predetermined 'threadprivate" } */ ; +#pragma omp p for linear (t) /* { dg-error "predetermined 'threadprivate" } */ + for (i = 0; i < 10; i++) + ; #pragma omp p shared (c) /* { dg-error "predetermined 'shared'" } */ ; #pragma omp p private (c) /* { dg-error "predetermined 'shared'" } */ @@ -91,4 +97,7 @@ foo (int x) ; #pragma omp p reduction (*:c) /* { dg-error "predetermined 'shared'" } */ ; +#pragma omp p for linear (c) /* { dg-error "predetermined 'shared'" } */ + for (i = 0; i < 10; i++) + ; } diff --git a/gcc/testsuite/gcc.dg/gomp/reduction-1.c b/gcc/testsuite/gcc.dg/gomp/reduction-1.c new file mode 100644 index 00000000000..0aeb21e6d15 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gomp/reduction-1.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +struct S {}; +void foo (void *, void *); +void bar (void *, void *); +void baz (void *); +#pragma omp declare reduction(+:struct S:foo (&omp_out, &omp_in))initializer(bar(&omp_priv, &omp_orig)) + +void +test (void) +{ + struct S b[10]; + #pragma omp parallel reduction(+:b[0:5]) /* { dg-error "zero length array section" } */ + baz (b); + #pragma omp parallel reduction(+:b[:10]) /* { dg-error "zero length array section" } */ + baz (b); + #pragma omp parallel reduction(+:b) /* { dg-error "is a zero size array" } */ + baz (b); +} diff --git a/gcc/testsuite/gcc.dg/gomp/sink-fold-1.c b/gcc/testsuite/gcc.dg/gomp/sink-fold-1.c new file mode 100644 index 00000000000..d166dac950b --- /dev/null +++ b/gcc/testsuite/gcc.dg/gomp/sink-fold-1.c @@ -0,0 +1,31 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -fdump-tree-omplower" } */ + +/* Test depend(sink) clause folding. */ + +int i,j,k, N; + +extern void bar(); + +void +funk () +{ +#pragma omp parallel for ordered(3) + for (i=0; i < N; i++) + for (j=0; j < N; ++j) + for (k=0; k < N; ++k) + { +/* We remove the (sink:i,j-1,k) by virtue of it the i+0. The remaining + clauses get folded with a GCD of -2 for `i' and a maximum of -2, +2 for + 'j' and 'k'. */ +#pragma omp ordered \ + depend(sink:i-8,j-2,k+2) \ + depend(sink:i, j-1,k) \ + depend(sink:i-4,j-3,k+6) \ + depend(sink:i-6,j-4,k-6) + bar(); +#pragma omp ordered depend(source) + } +} + +/* { dg-final { scan-tree-dump-times "omp ordered depend\\(sink:i-2,j-2,k\\+2\\)" 1 "omplower" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/gomp/sink-fold-2.c b/gcc/testsuite/gcc.dg/gomp/sink-fold-2.c new file mode 100644 index 00000000000..f3cdaee1900 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gomp/sink-fold-2.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ + +int i,j, N; + +extern void bar(); + +void +funk () +{ +#pragma omp parallel for ordered(2) + for (i=0; i < N; i += 3) + for (j=0; j < N; ++j) + { +#pragma omp ordered depend(sink:i-8,j-1) /* { dg-warning "refers to iteration never in the iteration space" } */ +#pragma omp ordered depend(sink:i+3,j-1) /* { dg-warning "waiting for lexically later iteration" } */ + bar(); +#pragma omp ordered depend(source) + } +} diff --git a/gcc/testsuite/gcc.dg/gomp/sink-fold-3.c b/gcc/testsuite/gcc.dg/gomp/sink-fold-3.c new file mode 100644 index 00000000000..d3af18e17e7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gomp/sink-fold-3.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -fdump-tree-omplower" } */ + +/* Test that we fold sink offsets correctly while taking into account + pointer sizes. */ + +typedef struct { + char stuff[400]; +} foo; + +void +funk (foo *begin, foo *end) +{ + foo *p; +#pragma omp parallel for ordered(1) + for (p=end; p > begin; p--) + { +#pragma omp ordered depend(sink:p+2) depend(sink:p+4) + void bar (); + bar(); +#pragma omp ordered depend(source) + } +} + +/* { dg-final { scan-tree-dump-times "depend\\(sink:p\\+800\\)" 1 "omplower" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-simd-clone-15.c b/gcc/testsuite/gcc.dg/vect/vect-simd-clone-15.c new file mode 100644 index 00000000000..675ac7026b6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-simd-clone-15.c @@ -0,0 +1,39 @@ +/* { dg-require-effective-target vect_simd_clones } */ +/* { dg-additional-options "-fopenmp-simd" } */ +/* { dg-additional-options "-mavx" { target avx_runtime } } */ + +#include "tree-vect.h" + +#ifndef N +#define N 1024 +#endif + +int array[N]; + +#pragma omp declare simd linear(val(b):-3), notinbranch +__attribute__((noinline)) int +foo (int a, int b) +{ + return a + b; +} + +__attribute__((noinline, noclone)) void +bar () +{ + int i; +#pragma omp simd + for (i = 0; i < N; ++i) + array[i] = foo (i >> 1, -i * 3); +} + +int +main () +{ + int i; + check_vect (); + bar (); + for (i = 0; i < N; i++) + if (array[i] != ((i >> 1) + (-3 * i))) + abort (); + return 0; +} diff --git a/gcc/tree-core.h b/gcc/tree-core.h index 1883fd7234f..6b17da718b3 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -232,7 +232,10 @@ 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_{INIT,MERGE}. */ + placeholder used in OMP_CLAUSE_REDUCTION_{INIT,MERGE}. + Operand 4: OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER: Another dummy + VAR_DECL placeholder, used like the above for C/C++ array + reductions. */ OMP_CLAUSE_REDUCTION, /* OpenMP clause: copyin (variable_list). */ @@ -253,6 +256,13 @@ enum omp_clause_code { /* OpenMP clause: uniform (argument-list). */ OMP_CLAUSE_UNIFORM, + /* OpenMP clause: to (extended-list). + Only when it appears in declare target. */ + OMP_CLAUSE_TO_DECLARE, + + /* OpenMP clause: link (variable-list). */ + OMP_CLAUSE_LINK, + /* OpenMP clause: from (variable-list). */ OMP_CLAUSE_FROM, @@ -267,6 +277,12 @@ enum omp_clause_code { OpenMP clause: map ({alloc:,to:,from:,tofrom:,}variable-list). */ OMP_CLAUSE_MAP, + /* OpenMP clause: use_device_ptr (variable-list). */ + OMP_CLAUSE_USE_DEVICE_PTR, + + /* OpenMP clause: is_device_ptr (variable-list). */ + OMP_CLAUSE_IS_DEVICE_PTR, + /* Internal structure to hold OpenACC cache directive's variable-list. #pragma acc cache (variable-list). */ OMP_CLAUSE__CACHE_, @@ -312,7 +328,7 @@ enum omp_clause_code { /* OpenMP clause: nowait. */ OMP_CLAUSE_NOWAIT, - /* OpenMP clause: ordered. */ + /* OpenMP clause: ordered [(constant-integer-expression)]. */ OMP_CLAUSE_ORDERED, /* OpenMP clause: default. */ @@ -369,6 +385,30 @@ enum omp_clause_code { /* OpenMP clause: taskgroup. */ OMP_CLAUSE_TASKGROUP, + /* OpenMP clause: priority (integer-expression). */ + OMP_CLAUSE_PRIORITY, + + /* OpenMP clause: grainsize (integer-expression). */ + OMP_CLAUSE_GRAINSIZE, + + /* OpenMP clause: num_tasks (integer-expression). */ + OMP_CLAUSE_NUM_TASKS, + + /* OpenMP clause: nogroup. */ + OMP_CLAUSE_NOGROUP, + + /* OpenMP clause: threads. */ + OMP_CLAUSE_THREADS, + + /* OpenMP clause: simd. */ + OMP_CLAUSE_SIMD, + + /* OpenMP clause: hint (integer-expression). */ + OMP_CLAUSE_HINT, + + /* OpenMP clause: defaultmap (tofrom: scalar). */ + OMP_CLAUSE_DEFAULTMAP, + /* Internally used only clause, holding SIMD uid. */ OMP_CLAUSE__SIMDUID_, @@ -1218,6 +1258,8 @@ enum omp_clause_depend_kind OMP_CLAUSE_DEPEND_IN, OMP_CLAUSE_DEPEND_OUT, OMP_CLAUSE_DEPEND_INOUT, + OMP_CLAUSE_DEPEND_SOURCE, + OMP_CLAUSE_DEPEND_SINK, OMP_CLAUSE_DEPEND_LAST }; @@ -1232,6 +1274,14 @@ enum omp_clause_proc_bind_kind OMP_CLAUSE_PROC_BIND_LAST }; +enum omp_clause_linear_kind +{ + OMP_CLAUSE_LINEAR_DEFAULT, + OMP_CLAUSE_LINEAR_REF, + OMP_CLAUSE_LINEAR_VAL, + OMP_CLAUSE_LINEAR_UVAL +}; + struct GTY(()) tree_exp { struct tree_typed typed; location_t locus; @@ -1293,9 +1343,11 @@ struct GTY(()) tree_omp_clause { enum omp_clause_schedule_kind schedule_kind; enum omp_clause_depend_kind depend_kind; /* See include/gomp-constants.h for enum gomp_map_kind's values. */ - unsigned char map_kind; + unsigned int map_kind; enum omp_clause_proc_bind_kind proc_bind_kind; enum tree_code reduction_code; + enum omp_clause_linear_kind linear_kind; + enum tree_code if_modifier; } GTY ((skip)) subcode; /* The gimplification of OMP_CLAUSE_REDUCTION_{INIT,MERGE} for omp-low's diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 9b525f388fc..b8269eff633 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -1481,7 +1481,9 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id) case GIMPLE_OMP_ORDERED: s1 = remap_gimple_seq (gimple_omp_body (stmt), id); - copy = gimple_build_omp_ordered (s1); + copy = gimple_build_omp_ordered + (s1, + gimple_omp_ordered_clauses (as_a (stmt))); break; case GIMPLE_OMP_SECTION: @@ -1517,8 +1519,10 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id) case GIMPLE_OMP_CRITICAL: s1 = remap_gimple_seq (gimple_omp_body (stmt), id); copy = gimple_build_omp_critical (s1, - gimple_omp_critical_name ( - as_a (stmt))); + gimple_omp_critical_name + (as_a (stmt)), + gimple_omp_critical_clauses + (as_a (stmt))); break; case GIMPLE_TRANSACTION: @@ -1615,6 +1619,11 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id) gimple_call_set_tail (call_stmt, false); if (gimple_call_from_thunk_p (call_stmt)) gimple_call_set_from_thunk (call_stmt, false); + if (gimple_call_internal_p (call_stmt) + && IN_RANGE (gimple_call_internal_fn (call_stmt), + IFN_GOMP_SIMD_ORDERED_START, + IFN_GOMP_SIMD_ORDERED_END)) + DECL_STRUCT_FUNCTION (id->dst_fn)->has_simduid_loops = true; } /* Remap the region numbers for __builtin_eh_{pointer,filter}, diff --git a/gcc/tree-nested.c b/gcc/tree-nested.c index 4af70e96475..0f509334ef1 100644 --- a/gcc/tree-nested.c +++ b/gcc/tree-nested.c @@ -1102,6 +1102,10 @@ convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi) case OMP_CLAUSE_FIRSTPRIVATE: case OMP_CLAUSE_COPYPRIVATE: case OMP_CLAUSE_SHARED: + case OMP_CLAUSE_TO_DECLARE: + case OMP_CLAUSE_LINK: + case OMP_CLAUSE_USE_DEVICE_PTR: + case OMP_CLAUSE_IS_DEVICE_PTR: do_decl_clause: decl = OMP_CLAUSE_DECL (clause); if (TREE_CODE (decl) == VAR_DECL @@ -1128,6 +1132,11 @@ convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi) case OMP_CLAUSE_NUM_TEAMS: case OMP_CLAUSE_THREAD_LIMIT: case OMP_CLAUSE_SAFELEN: + case OMP_CLAUSE_SIMDLEN: + case OMP_CLAUSE_PRIORITY: + case OMP_CLAUSE_GRAINSIZE: + case OMP_CLAUSE_NUM_TASKS: + case OMP_CLAUSE_HINT: case OMP_CLAUSE__CILK_FOR_COUNT_: wi->val_only = true; wi->is_lhs = false; @@ -1192,6 +1201,10 @@ convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi) case OMP_CLAUSE_UNTIED: case OMP_CLAUSE_MERGEABLE: case OMP_CLAUSE_PROC_BIND: + case OMP_CLAUSE_NOGROUP: + case OMP_CLAUSE_THREADS: + case OMP_CLAUSE_SIMD: + case OMP_CLAUSE_DEFAULTMAP: break; default: @@ -1212,6 +1225,9 @@ convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi) = DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause)); DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause)) = info->context; + if (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause)) + DECL_CONTEXT (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause)) + = info->context; walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op, info, &OMP_CLAUSE_REDUCTION_GIMPLE_INIT (clause)); @@ -1220,6 +1236,9 @@ convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi) &OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (clause)); DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause)) = old_context; + if (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause)) + DECL_CONTEXT (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause)) + = old_context; } break; @@ -1730,6 +1749,10 @@ convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi) case OMP_CLAUSE_FIRSTPRIVATE: case OMP_CLAUSE_COPYPRIVATE: case OMP_CLAUSE_SHARED: + case OMP_CLAUSE_TO_DECLARE: + case OMP_CLAUSE_LINK: + case OMP_CLAUSE_USE_DEVICE_PTR: + case OMP_CLAUSE_IS_DEVICE_PTR: do_decl_clause: decl = OMP_CLAUSE_DECL (clause); if (TREE_CODE (decl) == VAR_DECL @@ -1761,6 +1784,11 @@ convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi) case OMP_CLAUSE_NUM_TEAMS: case OMP_CLAUSE_THREAD_LIMIT: case OMP_CLAUSE_SAFELEN: + case OMP_CLAUSE_SIMDLEN: + case OMP_CLAUSE_PRIORITY: + case OMP_CLAUSE_GRAINSIZE: + case OMP_CLAUSE_NUM_TASKS: + case OMP_CLAUSE_HINT: case OMP_CLAUSE__CILK_FOR_COUNT_: wi->val_only = true; wi->is_lhs = false; @@ -1830,6 +1858,10 @@ convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi) case OMP_CLAUSE_UNTIED: case OMP_CLAUSE_MERGEABLE: case OMP_CLAUSE_PROC_BIND: + case OMP_CLAUSE_NOGROUP: + case OMP_CLAUSE_THREADS: + case OMP_CLAUSE_SIMD: + case OMP_CLAUSE_DEFAULTMAP: break; default: @@ -1850,6 +1882,9 @@ convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi) = DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause)); DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause)) = info->context; + if (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause)) + DECL_CONTEXT (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause)) + = info->context; walk_body (convert_local_reference_stmt, convert_local_reference_op, info, &OMP_CLAUSE_REDUCTION_GIMPLE_INIT (clause)); @@ -1858,6 +1893,9 @@ convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi) &OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (clause)); DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause)) = old_context; + if (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause)) + DECL_CONTEXT (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause)) + = old_context; } break; diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index ce3f6a8a8b2..11f90051107 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -330,6 +330,12 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, int flags) case OMP_CLAUSE_UNIFORM: name = "uniform"; goto print_remap; + case OMP_CLAUSE_USE_DEVICE_PTR: + name = "use_device_ptr"; + goto print_remap; + case OMP_CLAUSE_IS_DEVICE_PTR: + name = "is_device_ptr"; + goto print_remap; case OMP_CLAUSE__LOOPTEMP_: name = "_looptemp_"; goto print_remap; @@ -339,6 +345,12 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, int flags) case OMP_CLAUSE_USE_DEVICE: name = "use_device"; goto print_remap; + case OMP_CLAUSE_TO_DECLARE: + name = "to"; + goto print_remap; + case OMP_CLAUSE_LINK: + name = "link"; + goto print_remap; print_remap: pp_string (pp, name); pp_left_paren (pp); @@ -362,6 +374,20 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, int flags) case OMP_CLAUSE_IF: pp_string (pp, "if("); + switch (OMP_CLAUSE_IF_MODIFIER (clause)) + { + case ERROR_MARK: break; + case OMP_PARALLEL: pp_string (pp, "parallel:"); break; + case OMP_TASK: pp_string (pp, "task:"); break; + case OMP_TASKLOOP: pp_string (pp, "taskloop:"); break; + case OMP_TARGET_DATA: pp_string (pp, "target data:"); break; + case OMP_TARGET: pp_string (pp, "target:"); break; + case OMP_TARGET_UPDATE: pp_string (pp, "target update:"); break; + case OMP_TARGET_ENTER_DATA: + pp_string (pp, "target enter data:"); break; + case OMP_TARGET_EXIT_DATA: pp_string (pp, "target exit data:"); break; + default: gcc_unreachable (); + } dump_generic_node (pp, OMP_CLAUSE_IF_EXPR (clause), spc, flags, false); pp_right_paren (pp); @@ -386,6 +412,13 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, int flags) break; case OMP_CLAUSE_ORDERED: pp_string (pp, "ordered"); + if (OMP_CLAUSE_ORDERED_EXPR (clause)) + { + pp_left_paren (pp); + dump_generic_node (pp, OMP_CLAUSE_ORDERED_EXPR (clause), + spc, flags, false); + pp_right_paren (pp); + } break; case OMP_CLAUSE_DEFAULT: @@ -414,6 +447,8 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, int flags) case OMP_CLAUSE_SCHEDULE: pp_string (pp, "schedule("); + if (OMP_CLAUSE_SCHEDULE_SIMD (clause)) + pp_string (pp, "simd:"); switch (OMP_CLAUSE_SCHEDULE_KIND (clause)) { case OMP_CLAUSE_SCHEDULE_STATIC: @@ -470,8 +505,26 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, int flags) case OMP_CLAUSE_LINEAR: pp_string (pp, "linear("); + switch (OMP_CLAUSE_LINEAR_KIND (clause)) + { + case OMP_CLAUSE_LINEAR_DEFAULT: + break; + case OMP_CLAUSE_LINEAR_REF: + pp_string (pp, "ref("); + break; + case OMP_CLAUSE_LINEAR_VAL: + pp_string (pp, "val("); + break; + case OMP_CLAUSE_LINEAR_UVAL: + pp_string (pp, "uval("); + break; + default: + gcc_unreachable (); + } dump_generic_node (pp, OMP_CLAUSE_DECL (clause), spc, flags, false); + if (OMP_CLAUSE_LINEAR_KIND (clause) != OMP_CLAUSE_LINEAR_DEFAULT) + pp_right_paren (pp); pp_colon (pp); dump_generic_node (pp, OMP_CLAUSE_LINEAR_STEP (clause), spc, flags, false); @@ -504,6 +557,31 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, int flags) case OMP_CLAUSE_DEPEND_INOUT: pp_string (pp, "inout"); break; + case OMP_CLAUSE_DEPEND_SOURCE: + pp_string (pp, "source)"); + return; + case OMP_CLAUSE_DEPEND_SINK: + pp_string (pp, "sink:"); + for (tree t = OMP_CLAUSE_DECL (clause); t; t = TREE_CHAIN (t)) + if (TREE_CODE (t) == TREE_LIST) + { + dump_generic_node (pp, TREE_VALUE (t), spc, flags, false); + if (TREE_PURPOSE (t) != integer_zero_node) + { + if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (t)) + pp_minus (pp); + else + pp_plus (pp); + dump_generic_node (pp, TREE_PURPOSE (t), spc, flags, + false); + } + if (TREE_CHAIN (t)) + pp_comma (pp); + } + else + gcc_unreachable (); + pp_right_paren (pp); + return; default: gcc_unreachable (); } @@ -547,11 +625,29 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, int flags) pp_string (pp, "force_present"); break; case GOMP_MAP_FORCE_DEALLOC: - pp_string (pp, "force_dealloc"); + pp_string (pp, "delete"); break; case GOMP_MAP_FORCE_DEVICEPTR: pp_string (pp, "force_deviceptr"); break; + case GOMP_MAP_ALWAYS_TO: + pp_string (pp, "always,to"); + break; + case GOMP_MAP_ALWAYS_FROM: + pp_string (pp, "always,from"); + break; + case GOMP_MAP_ALWAYS_TOFROM: + pp_string (pp, "always,tofrom"); + break; + case GOMP_MAP_RELEASE: + pp_string (pp, "release"); + break; + case GOMP_MAP_FIRSTPRIVATE_POINTER: + pp_string (pp, "firstprivate"); + break; + case GOMP_MAP_STRUCT: + pp_string (pp, "struct"); + break; default: gcc_unreachable (); } @@ -562,7 +658,9 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, int flags) if (OMP_CLAUSE_SIZE (clause)) { if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_MAP - && OMP_CLAUSE_MAP_KIND (clause) == GOMP_MAP_POINTER) + && (OMP_CLAUSE_MAP_KIND (clause) == GOMP_MAP_POINTER + || OMP_CLAUSE_MAP_KIND (clause) + == GOMP_MAP_FIRSTPRIVATE_POINTER)) pp_string (pp, " [pointer assign, bias: "); else if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_MAP && OMP_CLAUSE_MAP_KIND (clause) == GOMP_MAP_TO_PSET) @@ -660,6 +758,38 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, int flags) pp_right_paren (pp); break; + case OMP_CLAUSE_PRIORITY: + pp_string (pp, "priority("); + dump_generic_node (pp, OMP_CLAUSE_PRIORITY_EXPR (clause), + spc, flags, false); + pp_right_paren (pp); + break; + + case OMP_CLAUSE_GRAINSIZE: + pp_string (pp, "grainsize("); + dump_generic_node (pp, OMP_CLAUSE_GRAINSIZE_EXPR (clause), + spc, flags, false); + pp_right_paren (pp); + break; + + case OMP_CLAUSE_NUM_TASKS: + pp_string (pp, "num_tasks("); + dump_generic_node (pp, OMP_CLAUSE_NUM_TASKS_EXPR (clause), + spc, flags, false); + pp_right_paren (pp); + break; + + case OMP_CLAUSE_HINT: + pp_string (pp, "hint("); + dump_generic_node (pp, OMP_CLAUSE_HINT_EXPR (clause), + spc, flags, false); + pp_right_paren (pp); + break; + + case OMP_CLAUSE_DEFAULTMAP: + pp_string (pp, "defaultmap(tofrom:scalar)"); + break; + case OMP_CLAUSE__SIMDUID_: pp_string (pp, "_simduid_("); dump_generic_node (pp, OMP_CLAUSE__SIMDUID__DECL (clause), @@ -778,6 +908,15 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, int flags) case OMP_CLAUSE_TASKGROUP: pp_string (pp, "taskgroup"); break; + case OMP_CLAUSE_NOGROUP: + pp_string (pp, "nogroup"); + break; + case OMP_CLAUSE_THREADS: + pp_string (pp, "threads"); + break; + case OMP_CLAUSE_SIMD: + pp_string (pp, "simd"); + break; case OMP_CLAUSE_INDEPENDENT: pp_string (pp, "independent"); break; @@ -2624,6 +2763,10 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, int flags, pp_string (pp, "#pragma omp distribute"); goto dump_omp_loop; + case OMP_TASKLOOP: + pp_string (pp, "#pragma omp taskloop"); + goto dump_omp_loop; + case OACC_LOOP: pp_string (pp, "#pragma acc loop"); goto dump_omp_loop; @@ -2638,6 +2781,18 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, int flags, dump_omp_clauses (pp, OMP_TARGET_DATA_CLAUSES (node), spc, flags); goto dump_omp_body; + case OMP_TARGET_ENTER_DATA: + pp_string (pp, "#pragma omp target enter data"); + dump_omp_clauses (pp, OMP_TARGET_ENTER_DATA_CLAUSES (node), spc, flags); + is_expr = false; + break; + + case OMP_TARGET_EXIT_DATA: + pp_string (pp, "#pragma omp target exit data"); + dump_omp_clauses (pp, OMP_TARGET_EXIT_DATA_CLAUSES (node), spc, flags); + is_expr = false; + break; + case OMP_TARGET: pp_string (pp, "#pragma omp target"); dump_omp_clauses (pp, OMP_TARGET_CLAUSES (node), spc, flags); @@ -2738,6 +2893,7 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, int flags, case OMP_ORDERED: pp_string (pp, "#pragma omp ordered"); + dump_omp_clauses (pp, OMP_ORDERED_CLAUSES (node), spc, flags); goto dump_omp_body; case OMP_CRITICAL: @@ -2750,6 +2906,7 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, int flags, flags, false); pp_right_paren (pp); } + dump_omp_clauses (pp, OMP_CRITICAL_CLAUSES (node), spc, flags); goto dump_omp_body; case OMP_ATOMIC: diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index 0073ddb56a4..a5e1cb7a935 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -2892,6 +2892,7 @@ vectorizable_simd_clone_call (gimple *stmt, gimple_stmt_iterator *gsi, i = -1; break; case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP: + case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP: if (arginfo[i].dt == vect_constant_def || arginfo[i].dt == vect_external_def || (arginfo[i].linear_step @@ -2899,6 +2900,8 @@ vectorizable_simd_clone_call (gimple *stmt, gimple_stmt_iterator *gsi, i = -1; break; case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP: + case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP: + case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP: /* FORNOW */ i = -1; break; diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c index 1e4b2a6479e..3e6fd355e83 100644 --- a/gcc/tree-vectorizer.c +++ b/gcc/tree-vectorizer.c @@ -149,8 +149,9 @@ simd_array_to_simduid::equal (const simd_array_to_simduid *p1, return p1->decl == p2->decl; } -/* Fold IFN_GOMP_SIMD_LANE, IFN_GOMP_SIMD_VF and IFN_GOMP_SIMD_LAST_LANE - into their corresponding constants. */ +/* Fold IFN_GOMP_SIMD_LANE, IFN_GOMP_SIMD_VF, IFN_GOMP_SIMD_LAST_LANE, + into their corresponding constants and remove + IFN_GOMP_SIMD_ORDERED_{START,END}. */ static void adjust_simduid_builtins (hash_table *htab) @@ -161,7 +162,7 @@ adjust_simduid_builtins (hash_table *htab) { gimple_stmt_iterator i; - for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i)) + for (i = gsi_start_bb (bb); !gsi_end_p (i); ) { unsigned int vf = 1; enum internal_fn ifn; @@ -169,7 +170,10 @@ adjust_simduid_builtins (hash_table *htab) tree t; if (!is_gimple_call (stmt) || !gimple_call_internal_p (stmt)) - continue; + { + gsi_next (&i); + continue; + } ifn = gimple_call_internal_fn (stmt); switch (ifn) { @@ -177,7 +181,13 @@ adjust_simduid_builtins (hash_table *htab) case IFN_GOMP_SIMD_VF: case IFN_GOMP_SIMD_LAST_LANE: break; + case IFN_GOMP_SIMD_ORDERED_START: + case IFN_GOMP_SIMD_ORDERED_END: + gsi_remove (&i, true); + unlink_stmt_vdef (stmt); + continue; default: + gsi_next (&i); continue; } tree arg = gimple_call_arg (stmt, 0); @@ -206,6 +216,7 @@ adjust_simduid_builtins (hash_table *htab) gcc_unreachable (); } update_call_from_tree (&i, t); + gsi_next (&i); } } } @@ -562,7 +573,7 @@ vectorize_loops (void) free_stmt_vec_info_vec (); - /* Fold IFN_GOMP_SIMD_{VF,LANE,LAST_LANE} builtins. */ + /* Fold IFN_GOMP_SIMD_{VF,LANE,LAST_LANE,ORDERED_{START,END}} builtins. */ if (cfun->has_simduid_loops) adjust_simduid_builtins (simduid_to_vf_htab); @@ -624,7 +635,7 @@ pass_simduid_cleanup::execute (function *fun) note_simd_array_uses (&simd_array_to_simduid_htab); - /* Fold IFN_GOMP_SIMD_{VF,LANE,LAST_LANE} builtins. */ + /* Fold IFN_GOMP_SIMD_{VF,LANE,LAST_LANE,ORDERED_{START,END}} builtins. */ adjust_simduid_builtins (NULL); /* Shrink any "omp array simd" temporary arrays to the diff --git a/gcc/tree.c b/gcc/tree.c index 02f0a7aa4d4..905c60ef269 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -280,16 +280,20 @@ unsigned const char omp_clause_num_ops[] = 1, /* OMP_CLAUSE_SHARED */ 1, /* OMP_CLAUSE_FIRSTPRIVATE */ 2, /* OMP_CLAUSE_LASTPRIVATE */ - 4, /* OMP_CLAUSE_REDUCTION */ + 5, /* OMP_CLAUSE_REDUCTION */ 1, /* OMP_CLAUSE_COPYIN */ 1, /* OMP_CLAUSE_COPYPRIVATE */ 3, /* OMP_CLAUSE_LINEAR */ 2, /* OMP_CLAUSE_ALIGNED */ 1, /* OMP_CLAUSE_DEPEND */ 1, /* OMP_CLAUSE_UNIFORM */ + 1, /* OMP_CLAUSE_TO_DECLARE */ + 1, /* OMP_CLAUSE_LINK */ 2, /* OMP_CLAUSE_FROM */ 2, /* OMP_CLAUSE_TO */ 2, /* OMP_CLAUSE_MAP */ + 1, /* OMP_CLAUSE_USE_DEVICE_PTR */ + 1, /* OMP_CLAUSE_IS_DEVICE_PTR */ 2, /* OMP_CLAUSE__CACHE_ */ 1, /* OMP_CLAUSE_DEVICE_RESIDENT */ 1, /* OMP_CLAUSE_USE_DEVICE */ @@ -303,7 +307,7 @@ unsigned const char omp_clause_num_ops[] = 1, /* OMP_CLAUSE_NUM_THREADS */ 1, /* OMP_CLAUSE_SCHEDULE */ 0, /* OMP_CLAUSE_NOWAIT */ - 0, /* OMP_CLAUSE_ORDERED */ + 1, /* OMP_CLAUSE_ORDERED */ 0, /* OMP_CLAUSE_DEFAULT */ 3, /* OMP_CLAUSE_COLLAPSE */ 0, /* OMP_CLAUSE_UNTIED */ @@ -322,6 +326,14 @@ unsigned const char omp_clause_num_ops[] = 0, /* OMP_CLAUSE_PARALLEL */ 0, /* OMP_CLAUSE_SECTIONS */ 0, /* OMP_CLAUSE_TASKGROUP */ + 1, /* OMP_CLAUSE_PRIORITY */ + 1, /* OMP_CLAUSE_GRAINSIZE */ + 1, /* OMP_CLAUSE_NUM_TASKS */ + 0, /* OMP_CLAUSE_NOGROUP */ + 0, /* OMP_CLAUSE_THREADS */ + 0, /* OMP_CLAUSE_SIMD */ + 1, /* OMP_CLAUSE_HINT */ + 0, /* OMP_CLAUSE_DEFALTMAP */ 1, /* OMP_CLAUSE__SIMDUID_ */ 1, /* OMP_CLAUSE__CILK_FOR_COUNT_ */ 0, /* OMP_CLAUSE_INDEPENDENT */ @@ -346,9 +358,13 @@ const char * const omp_clause_code_name[] = "aligned", "depend", "uniform", + "to", + "link", "from", "to", "map", + "use_device_ptr", + "is_device_ptr", "_cache_", "device_resident", "use_device", @@ -381,6 +397,14 @@ const char * const omp_clause_code_name[] = "parallel", "sections", "taskgroup", + "priority", + "grainsize", + "num_tasks", + "nogroup", + "threads", + "simd", + "hint", + "defaultmap", "_simduid_", "_Cilk_for_count_", "independent", @@ -11458,6 +11482,15 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, case OMP_CLAUSE_DIST_SCHEDULE: case OMP_CLAUSE_SAFELEN: case OMP_CLAUSE_SIMDLEN: + case OMP_CLAUSE_ORDERED: + case OMP_CLAUSE_PRIORITY: + case OMP_CLAUSE_GRAINSIZE: + case OMP_CLAUSE_NUM_TASKS: + case OMP_CLAUSE_HINT: + case OMP_CLAUSE_TO_DECLARE: + case OMP_CLAUSE_LINK: + case OMP_CLAUSE_USE_DEVICE_PTR: + case OMP_CLAUSE_IS_DEVICE_PTR: case OMP_CLAUSE__LOOPTEMP_: case OMP_CLAUSE__SIMDUID_: case OMP_CLAUSE__CILK_FOR_COUNT_: @@ -11466,7 +11499,6 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, case OMP_CLAUSE_INDEPENDENT: case OMP_CLAUSE_NOWAIT: - case OMP_CLAUSE_ORDERED: case OMP_CLAUSE_DEFAULT: case OMP_CLAUSE_UNTIED: case OMP_CLAUSE_MERGEABLE: @@ -11477,6 +11509,10 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, case OMP_CLAUSE_PARALLEL: case OMP_CLAUSE_SECTIONS: case OMP_CLAUSE_TASKGROUP: + case OMP_CLAUSE_NOGROUP: + case OMP_CLAUSE_THREADS: + case OMP_CLAUSE_SIMD: + case OMP_CLAUSE_DEFAULTMAP: case OMP_CLAUSE_AUTO: case OMP_CLAUSE_SEQ: WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp)); @@ -11512,7 +11548,7 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, case OMP_CLAUSE_REDUCTION: { int i; - for (i = 0; i < 4; i++) + for (i = 0; i < 5; i++) WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, i)); WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp)); } diff --git a/gcc/tree.def b/gcc/tree.def index 56580af664c..64e07270a7e 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -1087,32 +1087,41 @@ DEFTREECODE (OMP_TASK, "omp_task", tcc_statement, 2) from INIT, COND, and INCR that are technically part of the OMP_FOR structured block, but are evaluated before the loop body begins. + Operand 6: OMP_FOR_ORIG_DECLS: If non-NULL, list of DECLs initialized + in OMP_FOR_INIT. In some cases, like C++ iterators, the original + DECL init has been lost in gimplification and now contains a + temporary (D.nnnn). This list contains the original DECLs in + the source. VAR must be an integer or pointer variable, which is implicitly thread private. N1, N2 and INCR are required to be loop invariant integer expressions that are evaluated without any synchronization. The evaluation order, frequency of evaluation and side-effects are unspecified by the standards. */ -DEFTREECODE (OMP_FOR, "omp_for", tcc_statement, 6) +DEFTREECODE (OMP_FOR, "omp_for", tcc_statement, 7) /* OpenMP - #pragma omp simd [clause1 ... clauseN] - Operands like for OMP_FOR. */ + Operands like operands 1-6 of OMP_FOR. */ DEFTREECODE (OMP_SIMD, "omp_simd", tcc_statement, 6) /* Cilk Plus - #pragma simd [clause1 ... clauseN] - Operands like for OMP_FOR. */ + Operands like operands 1-6 of OMP_FOR. */ DEFTREECODE (CILK_SIMD, "cilk_simd", tcc_statement, 6) /* Cilk Plus - _Cilk_for (..) - Operands like for OMP_FOR. */ + Operands like operands 1-6 of OMP_FOR. */ DEFTREECODE (CILK_FOR, "cilk_for", tcc_statement, 6) /* OpenMP - #pragma omp distribute [clause1 ... clauseN] - Operands like for OMP_FOR. */ + Operands like operands 1-6 of OMP_FOR. */ DEFTREECODE (OMP_DISTRIBUTE, "omp_distribute", tcc_statement, 6) +/* OpenMP - #pragma omp taskloop [clause1 ... clauseN] + Operands like operands 1-6 of OMP_FOR. */ +DEFTREECODE (OMP_TASKLOOP, "omp_taskloop", tcc_statement, 6) + /* OpenMP - #pragma acc loop [clause1 ... clauseN] - Operands like for OMP_FOR. */ + Operands like operands 1-6 of OMP_FOR. */ DEFTREECODE (OACC_LOOP, "oacc_loop", tcc_statement, 6) /* OpenMP - #pragma omp teams [clause1 ... clauseN] @@ -1135,6 +1144,17 @@ DEFTREECODE (OMP_TARGET, "omp_target", tcc_statement, 2) Operand 1: OMP_SECTIONS_CLAUSES: List of clauses. */ DEFTREECODE (OMP_SECTIONS, "omp_sections", tcc_statement, 2) +/* OpenMP - #pragma omp ordered + Operand 0: OMP_ORDERED_BODY: Master section body. + Operand 1: OMP_ORDERED_CLAUSES: List of clauses. */ +DEFTREECODE (OMP_ORDERED, "omp_ordered", tcc_statement, 2) + +/* OpenMP - #pragma omp critical [name] + Operand 0: OMP_CRITICAL_BODY: Critical section body. + Operand 1: OMP_CRITICAL_CLAUSES: List of clauses. + Operand 2: OMP_CRITICAL_NAME: Identifier for critical section. */ +DEFTREECODE (OMP_CRITICAL, "omp_critical", tcc_statement, 3) + /* OpenMP - #pragma omp single Operand 0: OMP_SINGLE_BODY: Single section body. Operand 1: OMP_SINGLE_CLAUSES: List of clauses. */ @@ -1152,15 +1172,6 @@ DEFTREECODE (OMP_MASTER, "omp_master", tcc_statement, 1) Operand 0: OMP_TASKGROUP_BODY: Taskgroup body. */ DEFTREECODE (OMP_TASKGROUP, "omp_taskgroup", tcc_statement, 1) -/* OpenMP - #pragma omp ordered - Operand 0: OMP_ORDERED_BODY: Master section body. */ -DEFTREECODE (OMP_ORDERED, "omp_ordered", tcc_statement, 1) - -/* OpenMP - #pragma omp critical [name] - Operand 0: OMP_CRITICAL_BODY: Critical section body. - Operand 1: OMP_CRITICAL_NAME: Identifier for critical section. */ -DEFTREECODE (OMP_CRITICAL, "omp_critical", tcc_statement, 2) - /* OpenACC - #pragma acc cache (variable1 ... variableN) Operand 0: OACC_CACHE_CLAUSES: List of variables (transformed into OMP_CLAUSE__CACHE_ clauses). */ @@ -1186,6 +1197,14 @@ DEFTREECODE (OACC_UPDATE, "oacc_update", tcc_statement, 1) Operand 0: OMP_TARGET_UPDATE_CLAUSES: List of clauses. */ DEFTREECODE (OMP_TARGET_UPDATE, "omp_target_update", tcc_statement, 1) +/* OpenMP - #pragma omp target enter data [clause1 ... clauseN] + Operand 0: OMP_TARGET_ENTER_DATA_CLAUSES: List of clauses. */ +DEFTREECODE (OMP_TARGET_ENTER_DATA, "omp_target_enter_data", tcc_statement, 1) + +/* OpenMP - #pragma omp target exit data [clause1 ... clauseN] + Operand 0: OMP_TARGET_EXIT_DATA_CLAUSES: List of clauses. */ +DEFTREECODE (OMP_TARGET_EXIT_DATA, "omp_target_exit_data", tcc_statement, 1) + /* OMP_ATOMIC through OMP_ATOMIC_CAPTURE_NEW must be consecutive, or OMP_ATOMIC_SEQ_CST needs adjusting. */ diff --git a/gcc/tree.h b/gcc/tree.h index a776b899b80..f62cd2746a9 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1204,13 +1204,13 @@ extern void protected_set_expr_location (tree, location_t); /* Generic accessors for OMP nodes that keep the body as operand 0, and clauses as operand 1. */ #define OMP_BODY(NODE) \ - TREE_OPERAND (TREE_RANGE_CHECK (NODE, OACC_PARALLEL, OMP_CRITICAL), 0) + TREE_OPERAND (TREE_RANGE_CHECK (NODE, OACC_PARALLEL, OMP_TASKGROUP), 0) #define OMP_CLAUSES(NODE) \ TREE_OPERAND (TREE_RANGE_CHECK (NODE, OACC_PARALLEL, OMP_SINGLE), 1) /* Generic accessors for OMP nodes that keep clauses as operand 0. */ #define OMP_STANDALONE_CLAUSES(NODE) \ - TREE_OPERAND (TREE_RANGE_CHECK (NODE, OACC_CACHE, OMP_TARGET_UPDATE), 0) + TREE_OPERAND (TREE_RANGE_CHECK (NODE, OACC_CACHE, OMP_TARGET_EXIT_DATA), 0) #define OACC_PARALLEL_BODY(NODE) \ TREE_OPERAND (OACC_PARALLEL_CHECK (NODE), 0) @@ -1264,6 +1264,8 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_FOR_COND(NODE) TREE_OPERAND (OMP_LOOP_CHECK (NODE), 3) #define OMP_FOR_INCR(NODE) TREE_OPERAND (OMP_LOOP_CHECK (NODE), 4) #define OMP_FOR_PRE_BODY(NODE) TREE_OPERAND (OMP_LOOP_CHECK (NODE), 5) +/* Note that this is only available for OMP_FOR, hence OMP_FOR_CHECK. */ +#define OMP_FOR_ORIG_DECLS(NODE) TREE_OPERAND (OMP_FOR_CHECK (NODE), 6) #define OMP_SECTIONS_BODY(NODE) TREE_OPERAND (OMP_SECTIONS_CHECK (NODE), 0) #define OMP_SECTIONS_CLAUSES(NODE) TREE_OPERAND (OMP_SECTIONS_CHECK (NODE), 1) @@ -1278,9 +1280,11 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_TASKGROUP_BODY(NODE) TREE_OPERAND (OMP_TASKGROUP_CHECK (NODE), 0) #define OMP_ORDERED_BODY(NODE) TREE_OPERAND (OMP_ORDERED_CHECK (NODE), 0) +#define OMP_ORDERED_CLAUSES(NODE) TREE_OPERAND (OMP_ORDERED_CHECK (NODE), 1) #define OMP_CRITICAL_BODY(NODE) TREE_OPERAND (OMP_CRITICAL_CHECK (NODE), 0) -#define OMP_CRITICAL_NAME(NODE) TREE_OPERAND (OMP_CRITICAL_CHECK (NODE), 1) +#define OMP_CRITICAL_CLAUSES(NODE) TREE_OPERAND (OMP_CRITICAL_CHECK (NODE), 1) +#define OMP_CRITICAL_NAME(NODE) TREE_OPERAND (OMP_CRITICAL_CHECK (NODE), 2) #define OMP_TEAMS_BODY(NODE) TREE_OPERAND (OMP_TEAMS_CHECK (NODE), 0) #define OMP_TEAMS_CLAUSES(NODE) TREE_OPERAND (OMP_TEAMS_CHECK (NODE), 1) @@ -1296,6 +1300,12 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_TARGET_UPDATE_CLAUSES(NODE)\ TREE_OPERAND (OMP_TARGET_UPDATE_CHECK (NODE), 0) +#define OMP_TARGET_ENTER_DATA_CLAUSES(NODE)\ + TREE_OPERAND (OMP_TARGET_ENTER_DATA_CHECK (NODE), 0) + +#define OMP_TARGET_EXIT_DATA_CLAUSES(NODE)\ + TREE_OPERAND (OMP_TARGET_EXIT_DATA_CHECK (NODE), 0) + #define OMP_CLAUSE_SIZE(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_RANGE_CHECK (OMP_CLAUSE_CHECK (NODE), \ OMP_CLAUSE_FROM, \ @@ -1335,6 +1345,11 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_TEAMS_COMBINED(NODE) \ (OMP_TEAMS_CHECK (NODE)->base.private_flag) +/* True on an OMP_TARGET statement if it represents explicit + combined target teams, target parallel or target simd constructs. */ +#define OMP_TARGET_COMBINED(NODE) \ + (OMP_TARGET_CHECK (NODE)->base.private_flag) + /* True if OMP_ATOMIC* is supposed to be sequentially consistent as opposed to relaxed. */ #define OMP_ATOMIC_SEQ_CST(NODE) \ @@ -1352,6 +1367,12 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_CLAUSE_PRIVATE_OUTER_REF(NODE) \ TREE_PRIVATE (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_PRIVATE)) +/* True if a PRIVATE clause is for a C++ class IV on taskloop construct + (thus should be private on the outer taskloop and firstprivate on + task). */ +#define OMP_CLAUSE_PRIVATE_TASKLOOP_IV(NODE) \ + TREE_PROTECTED (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) \ @@ -1363,6 +1384,21 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ(NODE) \ (OMP_CLAUSE_CHECK (NODE))->omp_clause.gimple_reduction_init +/* True if a LASTPRIVATE clause is for a C++ class IV on taskloop construct + (thus should be lastprivate on the outer taskloop and firstprivate on + task). */ +#define OMP_CLAUSE_LASTPRIVATE_TASKLOOP_IV(NODE) \ + TREE_PROTECTED (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_LASTPRIVATE)) + +/* True on a SHARED clause if a FIRSTPRIVATE clause for the same + decl is present in the chain (this can happen only for taskloop + with FIRSTPRIVATE/LASTPRIVATE on it originally. */ +#define OMP_CLAUSE_SHARED_FIRSTPRIVATE(NODE) \ + (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_SHARED)->base.public_flag) + +#define OMP_CLAUSE_IF_MODIFIER(NODE) \ + (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_IF)->omp_clause.subcode.if_modifier) + #define OMP_CLAUSE_FINAL_EXPR(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_FINAL), 0) #define OMP_CLAUSE_IF_EXPR(NODE) \ @@ -1371,6 +1407,16 @@ extern void protected_set_expr_location (tree, location_t); OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_NUM_THREADS),0) #define OMP_CLAUSE_SCHEDULE_CHUNK_EXPR(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_SCHEDULE), 0) +#define OMP_CLAUSE_NUM_TASKS_EXPR(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_NUM_TASKS), 0) +#define OMP_CLAUSE_HINT_EXPR(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_HINT), 0) + +#define OMP_CLAUSE_GRAINSIZE_EXPR(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_GRAINSIZE),0) + +#define OMP_CLAUSE_PRIORITY_EXPR(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_PRIORITY),0) /* OpenACC clause expressions */ #define OMP_CLAUSE_EXPR(NODE, CLAUSE) \ @@ -1406,17 +1452,28 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_CLAUSE_DEPEND_KIND(NODE) \ (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_DEPEND)->omp_clause.subcode.depend_kind) +#define OMP_CLAUSE_DEPEND_SINK_NEGATIVE(NODE) \ + TREE_PUBLIC (TREE_LIST_CHECK (NODE)) + #define OMP_CLAUSE_MAP_KIND(NODE) \ ((enum gomp_map_kind) OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)->omp_clause.subcode.map_kind) #define OMP_CLAUSE_SET_MAP_KIND(NODE, MAP_KIND) \ (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)->omp_clause.subcode.map_kind \ - = (unsigned char) (MAP_KIND)) + = (unsigned int) (MAP_KIND)) /* Nonzero if this map clause is for array (rather than pointer) based array section with zero bias. Both the non-decl OMP_CLAUSE_MAP and corresponding OMP_CLAUSE_MAP with GOMP_MAP_POINTER are marked with this flag. */ #define OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION(NODE) \ (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)->base.public_flag) +/* Nonzero if the same decl appears both in OMP_CLAUSE_MAP and either + OMP_CLAUSE_PRIVATE or OMP_CLAUSE_FIRSTPRIVATE. */ +#define OMP_CLAUSE_MAP_PRIVATE(NODE) \ + TREE_PRIVATE (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)) +/* Nonzero if this is a mapped array section, that might need special + treatment if OMP_CLAUSE_SIZE is zero. */ +#define OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION(NODE) \ + TREE_PROTECTED (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)) #define OMP_CLAUSE_PROC_BIND_KIND(NODE) \ (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_PROC_BIND)->omp_clause.subcode.proc_bind_kind) @@ -1428,6 +1485,9 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_CLAUSE_COLLAPSE_COUNT(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_COLLAPSE), 2) +#define OMP_CLAUSE_ORDERED_EXPR(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_ORDERED), 0) + #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) \ @@ -1440,6 +1500,8 @@ extern void protected_set_expr_location (tree, location_t); (OMP_CLAUSE_CHECK (NODE))->omp_clause.gimple_reduction_merge #define OMP_CLAUSE_REDUCTION_PLACEHOLDER(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_REDUCTION), 3) +#define OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_REDUCTION), 4) /* True if a REDUCTION clause may reference the original list item (omp_orig) in its OMP_CLAUSE_REDUCTION_{,GIMPLE_}INIT. */ @@ -1474,6 +1536,9 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_CLAUSE_LINEAR_GIMPLE_SEQ(NODE) \ (OMP_CLAUSE_CHECK (NODE))->omp_clause.gimple_reduction_init +#define OMP_CLAUSE_LINEAR_KIND(NODE) \ + (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_LINEAR)->omp_clause.subcode.linear_kind) + #define OMP_CLAUSE_ALIGNED_ALIGNMENT(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_ALIGNED), 1) @@ -1503,6 +1568,10 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_CLAUSE_SCHEDULE_KIND(NODE) \ (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_SCHEDULE)->omp_clause.subcode.schedule_kind) +/* True if a SCHEDULE clause has the simd modifier on it. */ +#define OMP_CLAUSE_SCHEDULE_SIMD(NODE) \ + (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_SCHEDULE)->base.public_flag) + #define OMP_CLAUSE_DEFAULT_KIND(NODE) \ (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_DEFAULT)->omp_clause.subcode.default_kind) diff --git a/gcc/wide-int.h b/gcc/wide-int.h index 6e0275f58c0..ff156791547 100644 --- a/gcc/wide-int.h +++ b/gcc/wide-int.h @@ -507,6 +507,7 @@ namespace wi BINARY_FUNCTION div_round (const T1 &, const T2 &, signop, bool * = 0); BINARY_FUNCTION divmod_trunc (const T1 &, const T2 &, signop, WI_BINARY_RESULT (T1, T2) *); + BINARY_FUNCTION gcd (const T1 &, const T2 &, signop = UNSIGNED); BINARY_FUNCTION mod_trunc (const T1 &, const T2 &, signop, bool * = 0); BINARY_FUNCTION smod_trunc (const T1 &, const T2 &); BINARY_FUNCTION umod_trunc (const T1 &, const T2 &); @@ -2643,6 +2644,27 @@ wi::divmod_trunc (const T1 &x, const T2 &y, signop sgn, return quotient; } +/* Compute the greatest common divisor of two numbers A and B using + Euclid's algorithm. */ +template +inline WI_BINARY_RESULT (T1, T2) +wi::gcd (const T1 &a, const T2 &b, signop sgn) +{ + T1 x, y, z; + + x = wi::abs (a); + y = wi::abs (b); + + while (gt_p (x, 0, sgn)) + { + z = mod_trunc (y, x, sgn); + y = x; + x = z; + } + + return y; +} + /* Compute X / Y, rouding towards 0, and return the remainder. Treat X and Y as having the signedness given by SGN. Indicate in *OVERFLOW if the division overflows. */ diff --git a/include/ChangeLog b/include/ChangeLog index e8fca1e3953..bfec2588e53 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,20 @@ +2015-10-13 Jakub Jelinek + Ilya Verbin + + * gomp-constants.h (GOMP_MAP_FLAG_ALWAYS): Define. + (enum gomp_map_kind): Add GOMP_MAP_FIRSTPRIVATE, + GOMP_MAP_FIRSTPRIVATE_INT, GOMP_MAP_USE_DEVICE_PTR, + GOMP_MAP_ZERO_LEN_ARRAY_SECTION, GOMP_MAP_ALWAYS_TO, + GOMP_MAP_ALWAYS_FROM, GOMP_MAP_ALWAYS_TOFROM, GOMP_MAP_STRUCT, + GOMP_MAP_DELETE_ZERO_LEN_ARRAY_SECTION, GOMP_MAP_DELETE, + GOMP_MAP_RELEASE, GOMP_MAP_FIRSTPRIVATE_POINTER. + (GOMP_MAP_ALWAYS_TO_P, GOMP_MAP_ALWAYS_FROM_P): Define. + (GOMP_TASK_FLAG_UNTIED, GOMP_TASK_FLAG_FINAL, GOMP_TASK_FLAG_MERGEABLE, + GOMP_TASK_FLAG_DEPEND, GOMP_TASK_FLAG_PRIORITY, GOMP_TASK_FLAG_UP, + GOMP_TASK_FLAG_GRAINSIZE, GOMP_TASK_FLAG_IF, GOMP_TASK_FLAG_NOGROUP, + GOMP_TARGET_FLAG_NOWAIT, GOMP_TARGET_FLAG_EXIT_DATA, + GOMP_TARGET_FLAG_UPDATE): Define. + 2015-09-28 Nathan Sidwell * gomp-constants.h (GOMP_VERSION_NVIDIA_PTX): Increment. diff --git a/include/gomp-constants.h b/include/gomp-constants.h index 228d93391a0..f834dec4f1f 100644 --- a/include/gomp-constants.h +++ b/include/gomp-constants.h @@ -41,6 +41,8 @@ #define GOMP_MAP_FLAG_SPECIAL_1 (1 << 3) #define GOMP_MAP_FLAG_SPECIAL (GOMP_MAP_FLAG_SPECIAL_1 \ | GOMP_MAP_FLAG_SPECIAL_0) +/* OpenMP always flag. */ +#define GOMP_MAP_FLAG_ALWAYS (1 << 6) /* Flag to force a specific behavior (or else, trigger a run-time error). */ #define GOMP_MAP_FLAG_FORCE (1 << 7) @@ -70,6 +72,19 @@ enum gomp_map_kind /* Is a device pointer. OMP_CLAUSE_SIZE for these is unused; is implicitly POINTER_SIZE_UNITS. */ GOMP_MAP_FORCE_DEVICEPTR = (GOMP_MAP_FLAG_SPECIAL_1 | 0), + /* Do not map, copy bits for firstprivate instead. */ + GOMP_MAP_FIRSTPRIVATE = (GOMP_MAP_FLAG_SPECIAL | 0), + /* Similarly, but store the value in the pointer rather than + pointed by the pointer. */ + GOMP_MAP_FIRSTPRIVATE_INT = (GOMP_MAP_FLAG_SPECIAL | 1), + /* Pointer translate host address into device address and copy that + back to host. */ + GOMP_MAP_USE_DEVICE_PTR = (GOMP_MAP_FLAG_SPECIAL | 2), + /* Allocate a zero length array section. Prefer next non-zero length + mapping over previous non-zero length mapping over zero length mapping + at the address. If not already mapped, do nothing (and pointer translate + to NULL). */ + GOMP_MAP_ZERO_LEN_ARRAY_SECTION = (GOMP_MAP_FLAG_SPECIAL | 3), /* Allocate. */ GOMP_MAP_FORCE_ALLOC = (GOMP_MAP_FLAG_FORCE | GOMP_MAP_ALLOC), /* ..., and copy to device. */ @@ -77,7 +92,37 @@ enum gomp_map_kind /* ..., and copy from device. */ GOMP_MAP_FORCE_FROM = (GOMP_MAP_FLAG_FORCE | GOMP_MAP_FROM), /* ..., and copy to and from device. */ - GOMP_MAP_FORCE_TOFROM = (GOMP_MAP_FLAG_FORCE | GOMP_MAP_TOFROM) + GOMP_MAP_FORCE_TOFROM = (GOMP_MAP_FLAG_FORCE | GOMP_MAP_TOFROM), + /* If not already present, allocate. And unconditionally copy to + device. */ + GOMP_MAP_ALWAYS_TO = (GOMP_MAP_FLAG_ALWAYS | GOMP_MAP_TO), + /* If not already present, allocate. And unconditionally copy from + device. */ + GOMP_MAP_ALWAYS_FROM = (GOMP_MAP_FLAG_ALWAYS | GOMP_MAP_FROM), + /* If not already present, allocate. And unconditionally copy to and from + device. */ + GOMP_MAP_ALWAYS_TOFROM = (GOMP_MAP_FLAG_ALWAYS | GOMP_MAP_TOFROM), + /* Map a sparse struct; the address is the base of the structure, alignment + it's required alignment, and size is the number of adjacent entries + that belong to the struct. The adjacent entries should be sorted by + increasing address, so it is easy to determine lowest needed address + (address of the first adjacent entry) and highest needed address + (address of the last adjacent entry plus its size). */ + GOMP_MAP_STRUCT = (GOMP_MAP_FLAG_ALWAYS + | GOMP_MAP_FLAG_SPECIAL | 0), + /* Forced deallocation of zero length array section. */ + GOMP_MAP_DELETE_ZERO_LEN_ARRAY_SECTION + = (GOMP_MAP_FLAG_ALWAYS + | GOMP_MAP_FLAG_SPECIAL | 3), + /* OpenMP 4.1 alias for forced deallocation. */ + GOMP_MAP_DELETE = GOMP_MAP_FORCE_DEALLOC, + /* Decrement usage count and deallocate if zero. */ + GOMP_MAP_RELEASE = (GOMP_MAP_FLAG_ALWAYS + | GOMP_MAP_FORCE_DEALLOC), + + /* Internal to GCC, not used in libgomp. */ + /* Do not map, but pointer assign a pointer instead. */ + GOMP_MAP_FIRSTPRIVATE_POINTER = (GOMP_MAP_LAST | 1) }; #define GOMP_MAP_COPY_TO_P(X) \ @@ -91,6 +136,12 @@ enum gomp_map_kind #define GOMP_MAP_POINTER_P(X) \ ((X) == GOMP_MAP_POINTER) +#define GOMP_MAP_ALWAYS_TO_P(X) \ + (((X) == GOMP_MAP_ALWAYS_TO) || ((X) == GOMP_MAP_ALWAYS_TOFROM)) + +#define GOMP_MAP_ALWAYS_FROM_P(X) \ + (((X) == GOMP_MAP_ALWAYS_FROM) || ((X) == GOMP_MAP_ALWAYS_TOFROM)) + /* Asynchronous behavior. Keep in sync with libgomp/{openacc.h,openacc.f90,openacc_lib.h}:acc_async_t. */ @@ -113,6 +164,23 @@ enum gomp_map_kind #define GOMP_DEVICE_ICV -1 #define GOMP_DEVICE_HOST_FALLBACK -2 +/* GOMP_task/GOMP_taskloop* flags argument. */ +#define GOMP_TASK_FLAG_UNTIED (1 << 0) +#define GOMP_TASK_FLAG_FINAL (1 << 1) +#define GOMP_TASK_FLAG_MERGEABLE (1 << 2) +#define GOMP_TASK_FLAG_DEPEND (1 << 3) +#define GOMP_TASK_FLAG_PRIORITY (1 << 4) +#define GOMP_TASK_FLAG_UP (1 << 8) +#define GOMP_TASK_FLAG_GRAINSIZE (1 << 9) +#define GOMP_TASK_FLAG_IF (1 << 10) +#define GOMP_TASK_FLAG_NOGROUP (1 << 11) + +/* GOMP_target{_41,update_41,enter_exit_data} flags argument. */ +#define GOMP_TARGET_FLAG_NOWAIT (1 << 0) +#define GOMP_TARGET_FLAG_EXIT_DATA (1 << 1) +/* Internal to libgomp. */ +#define GOMP_TARGET_FLAG_UPDATE (1U << 31) + /* Versions of libgomp and device-specific plugins. */ #define GOMP_VERSION 0 #define GOMP_VERSION_NVIDIA_PTX 1 diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog index 74a135cd55b..df4e9370f81 100644 --- a/libgomp/ChangeLog +++ b/libgomp/ChangeLog @@ -1,3 +1,317 @@ +2015-10-13 Jakub Jelinek + Aldy Hernandez + Ilya Verbin + + * config/linux/affinity.c (omp_get_place_num_procs, + omp_get_place_proc_ids, gomp_get_place_proc_ids_8): New functions. + * config/linux/doacross.h: New file. + * config/posix/affinity.c (omp_get_place_num_procs, + omp_get_place_proc_ids, gomp_get_place_proc_ids_8): New functions. + * config/posix/doacross.h: New file. + * env.c: Include gomp-constants.h. + (struct gomp_task_icv): Rename run_sched_modifier to + run_sched_chunk_size. + (gomp_max_task_priority_var): New variable. + (parse_schedule): Rename run_sched_modifier to run_sched_chunk_size. + (handle_omp_display_env): Change _OPENMP value from 201307 to + 201511. Print OMP_MAX_TASK_PRIORITY. + (initialize_env): Parse OMP_MAX_TASK_PRIORITY. + (omp_set_schedule, omp_get_schedule): Rename modifier argument to + chunk_size and run_sched_modifier to run_sched_chunk_size. + (omp_get_max_task_priority, omp_get_initial_device, + omp_get_num_places, omp_get_place_num, omp_get_partition_num_places, + omp_get_partition_place_nums): New functions. + * fortran.c (omp_set_schedule_, omp_set_schedule_8_, + omp_get_schedule_, omp_get_schedule_8_): Rename modifier argument + to chunk_size. + (omp_get_num_places_, omp_get_place_num_procs_, + omp_get_place_num_procs_8_, omp_get_place_proc_ids_, + omp_get_place_proc_ids_8_, omp_get_place_num_, + omp_get_partition_num_places_, omp_get_partition_place_nums_, + omp_get_partition_place_nums_8_, omp_get_initial_device_, + omp_get_max_task_priority_): New functions. + * libgomp_g.h (GOMP_loop_doacross_static_start, + GOMP_loop_doacross_dynamic_start, GOMP_loop_doacross_guided_start, + GOMP_loop_doacross_runtime_start, GOMP_loop_ull_doacross_static_start, + GOMP_loop_ull_doacross_dynamic_start, + GOMP_loop_ull_doacross_guided_start, + GOMP_loop_ull_doacross_runtime_start, GOMP_doacross_post, + GOMP_doacross_wait, GOMP_doacross_ull_post, GOMP_doacross_wait, + GOMP_taskloop, GOMP_taskloop_ull, GOMP_target_41, + GOMP_target_data_41, GOMP_target_update_41, + GOMP_target_enter_exit_data): New prototypes. + (GOMP_task): Add prototype argument. + * libgomp.h (_LIBGOMP_CHECKING_): Define to 0 if not yet defined. + (struct gomp_doacross_work_share): New type. + (struct gomp_work_share): Add doacross field. + (struct gomp_task_icv): Rename run_sched_modifier to + run_sched_chunk_size. + (enum gomp_task_kind): Rename GOMP_TASK_IFFALSE to + GOMP_TASK_UNDEFERRED. Add comments. + (struct gomp_task_depend_entry): Add comments. + (struct gomp_task): Likewise. + (struct gomp_taskgroup): Likewise. + (struct gomp_target_task): New type. + (struct gomp_team): Add comment. + (gomp_get_place_proc_ids_8, gomp_doacross_init, + gomp_doacross_ull_init, gomp_task_maybe_wait_for_dependencies, + gomp_create_target_task, gomp_target_task_fn): New prototypes. + (struct target_var_desc): New type. + (struct target_mem_desc): Adjust comment. Use struct + target_var_desc instead of splay_tree_key for list. + (REFCOUNT_INFINITY): Define. + (struct splay_tree_key_s): Remove copy_from field. + (struct gomp_device_descr): Add dev2dev_func field. + (enum gomp_map_vars_kind): New enum. + (gomp_map_vars): Add one argument. + * libgomp.map (OMP_4.5): Export omp_get_max_task_priority, + omp_get_max_task_priority_, omp_get_num_places, omp_get_num_places_, + omp_get_place_num_procs, omp_get_place_num_procs_, + omp_get_place_num_procs_8_, omp_get_place_proc_ids, + omp_get_place_proc_ids_, omp_get_place_proc_ids_8_, omp_get_place_num, + omp_get_place_num_, omp_get_partition_num_places, + omp_get_partition_num_places_, omp_get_partition_place_nums, + omp_get_partition_place_nums_, omp_get_partition_place_nums_8_, + omp_get_initial_device, omp_get_initial_device_, omp_target_alloc, + omp_target_free, omp_target_is_present, omp_target_memcpy, + omp_target_memcpy_rect, omp_target_associate_ptr and + omp_target_disassociate_ptr. + (GOMP_4.0.2): Renamed to ... + (GOMP_4.5): ... this. Export GOMP_target_41, GOMP_target_data_41, + GOMP_target_update_41, GOMP_target_enter_exit_data, GOMP_taskloop, + GOMP_taskloop_ull, GOMP_loop_doacross_dynamic_start, + GOMP_loop_doacross_guided_start, GOMP_loop_doacross_runtime_start, + GOMP_loop_doacross_static_start, GOMP_doacross_post, + GOMP_doacross_wait, GOMP_loop_ull_doacross_dynamic_start, + GOMP_loop_ull_doacross_guided_start, + GOMP_loop_ull_doacross_runtime_start, + GOMP_loop_ull_doacross_static_start, GOMP_doacross_ull_post and + GOMP_doacross_ull_wait. + * libgomp.texi: Document omp_get_max_task_priority. + Rename modifier argument to chunk_size for omp_set_schedule and + omp_get_schedule. Document OMP_MAX_TASK_PRIORITY env var. + * loop.c (GOMP_loop_runtime_start): Adjust for run_sched_modifier + to run_sched_chunk_size renaming. + (GOMP_loop_ordered_runtime_start): Likewise. + (gomp_loop_doacross_static_start, gomp_loop_doacross_dynamic_start, + gomp_loop_doacross_guided_start, GOMP_loop_doacross_runtime_start, + GOMP_parallel_loop_runtime_start): New functions. + (GOMP_parallel_loop_runtime): Adjust for run_sched_modifier + to run_sched_chunk_size renaming. + (GOMP_loop_doacross_static_start, GOMP_loop_doacross_dynamic_start, + GOMP_loop_doacross_guided_start): New functions or aliases. + * loop_ull.c (GOMP_loop_ull_runtime_start): Adjust for + run_sched_modifier to run_sched_chunk_size renaming. + (GOMP_loop_ull_ordered_runtime_start): Likewise. + (gomp_loop_ull_doacross_static_start, + gomp_loop_ull_doacross_dynamic_start, + gomp_loop_ull_doacross_guided_start, + GOMP_loop_ull_doacross_runtime_start): New functions. + (GOMP_loop_ull_doacross_static_start, + GOMP_loop_ull_doacross_dynamic_start, + GOMP_loop_ull_doacross_guided_start): New functions or aliases. + * oacc-mem.c (acc_map_data, present_create_copy, + gomp_acc_insert_pointer): Pass GOMP_MAP_VARS_OPENACC instead of false + to gomp_map_vars. + (gomp_acc_remove_pointer): Use copy_from from target_var_desc. + * oacc-parallel.c (GOACC_data_start): Pass GOMP_MAP_VARS_OPENACC + instead of false to gomp_map_vars. + (GOACC_parallel_keyed): Likewise. Use copy_from from target_var_desc. + * omp.h.in (omp_lock_hint_t): New type. + (omp_init_lock_with_hint, omp_init_nest_lock_with_hint, + omp_get_num_places, omp_get_place_num_procs, omp_get_place_proc_ids, + omp_get_place_num, omp_get_partition_num_places, + omp_get_partition_place_nums, omp_get_initial_device, + omp_get_max_task_priority, omp_target_alloc, omp_target_free, + omp_target_is_present, omp_target_memcpy, omp_target_memcpy_rect, + omp_target_associate_ptr, omp_target_disassociate_ptr): New + prototypes. + * omp_lib.f90.in (omp_lock_hint_kind): New parameter. + (omp_lock_hint_none, omp_lock_hint_uncontended, + omp_lock_hint_contended, omp_lock_hint_nonspeculative, + omp_lock_hint_speculative): New parameters. + (omp_init_lock_with_hint, omp_init_nest_lock_with_hint, + omp_get_num_places, omp_get_place_num_procs, omp_get_place_proc_ids, + omp_get_place_num, omp_get_partition_num_places, + omp_get_partition_place_nums, omp_get_initial_device, + omp_get_max_task_priority): New interfaces. + (omp_set_schedule, omp_get_schedule): Rename modifier argument + to chunk_size. + * omp_lib.h.in (omp_lock_hint_kind): New parameter. + (omp_lock_hint_none, omp_lock_hint_uncontended, + omp_lock_hint_contended, omp_lock_hint_nonspeculative, + omp_lock_hint_speculative): New parameters. + (omp_init_lock_with_hint, omp_init_nest_lock_with_hint, + omp_get_num_places, omp_get_place_num_procs, omp_get_place_proc_ids, + omp_get_place_num, omp_get_partition_num_places, + omp_get_partition_place_nums, omp_get_initial_device, + omp_get_max_task_priority): New functions and subroutines. + * ordered.c: Include stdarg.h and string.h. + (MAX_COLLAPSED_BITS): Define. + (gomp_doacross_init, GOMP_doacross_post, GOMP_doacross_wait, + gomp_doacross_ull_init, GOMP_doacross_ull_post, + GOMP_doacross_ull_wait): New functions. + * target.c: Include errno.h. + (resolve_device): If device is not initialized, call + gomp_init_device on it. + (gomp_map_lookup): New function. + (gomp_map_vars_existing): Add tgt_var argument, fill it in. + Don't bump refcount if REFCOUNT_INFINITY. Handle + GOMP_MAP_ALWAYS_TO_P. + (get_kind): Rename is_openacc argument to short_mapkind. + (gomp_map_pointer): Use gomp_map_lookup. + (gomp_map_fields_existing): New function. + (gomp_map_vars): Rename is_openacc argument to short_mapkind + and is_target to pragma_kind. Handle GOMP_MAP_VARS_ENTER_DATA, + handle GOMP_MAP_FIRSTPRIVATE_INT, GOMP_MAP_STRUCT, + GOMP_MAP_USE_DEVICE_PTR, GOMP_MAP_ZERO_LEN_ARRAY_SECTION. + Adjust for tgt->list changed type and copy_from living in there. + (gomp_copy_from_async): Adjust for tgt->list changed type and + copy_from living in there. + (gomp_unmap_vars): Likewise. + (gomp_update): Likewise. Rename is_openacc argument to + short_mapkind. Don't fail if object is not mapped. + (gomp_load_image_to_device): Initialize refcount to + REFCOUNT_INFINITY. + (gomp_target_fallback): New function. + (gomp_get_target_fn_addr): Likewise. + (GOMP_target): Adjust gomp_map_vars caller, use + gomp_get_target_fn_addr and gomp_target_fallback. + (GOMP_target_41): New function. + (gomp_target_data_fallback): New function. + (GOMP_target_data): Use it, adjust gomp_map_vars caller. + (GOMP_target_data_41): New function. + (GOMP_target_update): Adjust gomp_update caller. + (GOMP_target_update_41): New function. + (gomp_exit_data, GOMP_target_enter_exit_data, + gomp_target_task_fn, omp_target_alloc, omp_target_free, + omp_target_is_present, omp_target_memcpy, + omp_target_memcpy_rect_worker, omp_target_memcpy_rect, + omp_target_associate_ptr, omp_target_disassociate_ptr, + gomp_load_plugin_for_device): New functions. + * task.c: Include gomp-constants.h. Include taskloop.c + twice to get GOMP_taskloop and GOMP_taskloop_ull definitions. + (gomp_task_handle_depend): New function. + (GOMP_task): Use it. Add priority argument. Use + gomp-constant.h constants instead of hardcoded numbers. + Rename GOMP_TASK_IFFALSE to GOMP_TASK_UNDEFERRED. + (gomp_create_target_task): New function. + (verify_children_queue, verify_taskgroup_queue, + verify_task_queue): New functions. + (gomp_task_run_pre): Call verify_*_queue functions. + If an upcoming tied task is about to leave the sibling or + taskgroup queues in an invalid state, adjust appropriately. + Remove taskgroup argument. Add comments. + (gomp_task_run_post_handle_dependers): Add comments. + (gomp_task_run_post_remove_parent): Likewise. + (gomp_barrier_handle_tasks): Adjust gomp_task_run_pre caller. + (GOMP_taskwait): Likewise. Add comments. + (gomp_task_maybe_wait_for_dependencies): Fix scheduling + problem such that the first non parent_depends_on task does not + end up at the end of the children queue. + (GOMP_taskgroup_start): Rename GOMP_TASK_IFFALSE to + GOMP_TASK_UNDEFERRED. + (GOMP_taskgroup_end): Adjust gomp_task_run_pre caller. + * taskloop.c: New file. + * testsuite/lib/libgomp.exp + (check_effective_target_offload_device_nonshared_as): New proc. + * testsuite/libgomp.c/affinity-2.c: New test. + * testsuite/libgomp.c/doacross-1.c: New test. + * testsuite/libgomp.c/doacross-2.c: New test. + * testsuite/libgomp.c/examples-4/declare_target-1.c (fib_wrapper): + Add map clause to target. + * testsuite/libgomp.c/examples-4/declare_target-4.c (accum): Likewise. + * testsuite/libgomp.c/examples-4/declare_target-5.c (accum): Likewise. + * testsuite/libgomp.c/examples-4/device-1.c (main): Likewise. + * testsuite/libgomp.c/examples-4/device-3.c (main): Likewise. + * testsuite/libgomp.c/examples-4/target_data-3.c (gramSchmidt): + Likewise. + * testsuite/libgomp.c/examples-4/teams-2.c (dotprod): Likewise. + * testsuite/libgomp.c/examples-4/teams-3.c (dotprod): Likewise. + * testsuite/libgomp.c/examples-4/teams-4.c (dotprod): Likewise. + * testsuite/libgomp.c/for-2.h (OMPTGT, OMPTO, OMPFROM): Define if + not defined. Use those where needed. + * testsuite/libgomp.c/for-4.c: New test. + * testsuite/libgomp.c/for-5.c: New test. + * testsuite/libgomp.c/for-6.c: New test. + * testsuite/libgomp.c/linear-1.c: New test. + * testsuite/libgomp.c/ordered-4.c: New test. + * testsuite/libgomp.c/pr66199-2.c (f2): Adjust for linear clause + only allowed on the loop iterator. + * testsuite/libgomp.c/pr66199-3.c: New test. + * testsuite/libgomp.c/pr66199-4.c: New test. + * testsuite/libgomp.c/reduction-7.c: New test. + * testsuite/libgomp.c/reduction-8.c: New test. + * testsuite/libgomp.c/reduction-9.c: New test. + * testsuite/libgomp.c/reduction-10.c: New test. + * testsuite/libgomp.c/target-1.c (fn2, fn3, fn4): Add + map(tofrom:s). + * testsuite/libgomp.c/target-2.c (fn2, fn3, fn4): Likewise. + * testsuite/libgomp.c/target-7.c (foo): Add map(h) where needed. + * testsuite/libgomp.c/target-11.c: New test. + * testsuite/libgomp.c/target-12.c: New test. + * testsuite/libgomp.c/target-13.c: New test. + * testsuite/libgomp.c/target-14.c: New test. + * testsuite/libgomp.c/target-15.c: New test. + * testsuite/libgomp.c/target-16.c: New test. + * testsuite/libgomp.c/target-17.c: New test. + * testsuite/libgomp.c/target-18.c: New test. + * testsuite/libgomp.c/target-19.c: New test. + * testsuite/libgomp.c/target-20.c: New test. + * testsuite/libgomp.c/target-21.c: New test. + * testsuite/libgomp.c/target-22.c: New test. + * testsuite/libgomp.c/target-23.c: New test. + * testsuite/libgomp.c/target-24.c: New test. + * testsuite/libgomp.c/target-25.c: New test. + * testsuite/libgomp.c/target-26.c: New test. + * testsuite/libgomp.c/target-27.c: New test. + * testsuite/libgomp.c/taskloop-1.c: New test. + * testsuite/libgomp.c/taskloop-2.c: New test. + * testsuite/libgomp.c/taskloop-3.c: New test. + * testsuite/libgomp.c/taskloop-4.c: New test. + * testsuite/libgomp.c++/ctor-13.C: New test. + * testsuite/libgomp.c++/doacross-1.C: New test. + * testsuite/libgomp.c++/examples-4/declare_target-2.C: + Replace offload_device with offload_device_nonshared_as. + * testsuite/libgomp.c++/for-12.C: New test. + * testsuite/libgomp.c++/for-13.C: New test. + * testsuite/libgomp.c++/for-14.C: New test. + * testsuite/libgomp.c++/linear-1.C: New test. + * testsuite/libgomp.c++/member-1.C: New test. + * testsuite/libgomp.c++/member-2.C: New test. + * testsuite/libgomp.c++/member-3.C: New test. + * testsuite/libgomp.c++/member-4.C: New test. + * testsuite/libgomp.c++/member-5.C: New test. + * testsuite/libgomp.c++/ordered-1.C: New test. + * testsuite/libgomp.c++/reduction-5.C: New test. + * testsuite/libgomp.c++/reduction-6.C: New test. + * testsuite/libgomp.c++/reduction-7.C: New test. + * testsuite/libgomp.c++/reduction-8.C: New test. + * testsuite/libgomp.c++/reduction-9.C: New test. + * testsuite/libgomp.c++/reduction-10.C: New test. + * testsuite/libgomp.c++/reference-1.C: New test. + * testsuite/libgomp.c++/simd14.C: New test. + * testsuite/libgomp.c++/target-2.C (fn2): Add map(tofrom: s) clause. + * testsuite/libgomp.c++/target-5.C: New test. + * testsuite/libgomp.c++/target-6.C: New test. + * testsuite/libgomp.c++/target-7.C: New test. + * testsuite/libgomp.c++/target-8.C: New test. + * testsuite/libgomp.c++/target-9.C: New test. + * testsuite/libgomp.c++/target-10.C: New test. + * testsuite/libgomp.c++/target-11.C: New test. + * testsuite/libgomp.c++/target-12.C: New test. + * testsuite/libgomp.c++/taskloop-1.C: New test. + * testsuite/libgomp.c++/taskloop-2.C: New test. + * testsuite/libgomp.c++/taskloop-3.C: New test. + * testsuite/libgomp.c++/taskloop-4.C: New test. + * testsuite/libgomp.c++/taskloop-5.C: New test. + * testsuite/libgomp.c++/taskloop-6.C: New test. + * testsuite/libgomp.c++/taskloop-7.C: New test. + * testsuite/libgomp.c++/taskloop-8.C: New test. + * testsuite/libgomp.c++/taskloop-9.C: New test. + * testsuite/libgomp.fortran/affinity1.f90: New test. + * testsuite/libgomp.fortran/affinity2.f90: New test. + 2015-10-13 Tom de Vries PR tree-optimization/67476 diff --git a/libgomp/config/linux/affinity.c b/libgomp/config/linux/affinity.c index 17b65afb49a..775ee0a7fdf 100644 --- a/libgomp/config/linux/affinity.c +++ b/libgomp/config/linux/affinity.c @@ -353,6 +353,45 @@ gomp_affinity_print_place (void *p) fprintf (stderr, ":%lu", len); } +int +omp_get_place_num_procs (int place_num) +{ + if (place_num < 0 || place_num >= gomp_places_list_len) + return 0; + + cpu_set_t *cpusetp = (cpu_set_t *) gomp_places_list[place_num]; + return gomp_cpuset_popcount (gomp_cpuset_size, cpusetp); +} + +void +omp_get_place_proc_ids (int place_num, int *ids) +{ + if (place_num < 0 || place_num >= gomp_places_list_len) + return; + + cpu_set_t *cpusetp = (cpu_set_t *) gomp_places_list[place_num]; + unsigned long i, max = 8 * gomp_cpuset_size; + for (i = 0; i < max; i++) + if (CPU_ISSET_S (i, gomp_cpuset_size, cpusetp)) + *ids++ = i; +} + +void +gomp_get_place_proc_ids_8 (int place_num, int64_t *ids) +{ + if (place_num < 0 || place_num >= gomp_places_list_len) + return; + + cpu_set_t *cpusetp = (cpu_set_t *) gomp_places_list[place_num]; + unsigned long i, max = 8 * gomp_cpuset_size; + for (i = 0; i < max; i++) + if (CPU_ISSET_S (i, gomp_cpuset_size, cpusetp)) + *ids++ = i; +} + +ialias(omp_get_place_num_procs) +ialias(omp_get_place_proc_ids) + #else #include "../posix/affinity.c" diff --git a/libgomp/config/linux/doacross.h b/libgomp/config/linux/doacross.h new file mode 100644 index 00000000000..7a5a645f3cf --- /dev/null +++ b/libgomp/config/linux/doacross.h @@ -0,0 +1,57 @@ +/* Copyright (C) 2015 Free Software Foundation, Inc. + Contributed by Jakub Jelinek . + + This file is part of the GNU Offloading and Multi Processing Library + (libgomp). + + Libgomp is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + 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 General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +/* This is a Linux specific implementation of doacross spinning. */ + +#ifndef GOMP_DOACROSS_H +#define GOMP_DOACROSS_H 1 + +#include "libgomp.h" +#include +#include "wait.h" + +#ifdef HAVE_ATTRIBUTE_VISIBILITY +# pragma GCC visibility push(hidden) +#endif + +static inline void doacross_spin (unsigned long *addr, unsigned long expected, + unsigned long cur) +{ + /* FIXME: back off depending on how large expected - cur is. */ + do + { + cpu_relax (); + cur = __atomic_load_n (addr, MEMMODEL_RELAXED); + if (expected < cur) + return; + } + while (1); +} + +#ifdef HAVE_ATTRIBUTE_VISIBILITY +# pragma GCC visibility pop +#endif + +#endif /* GOMP_DOACROSS_H */ diff --git a/libgomp/config/posix/affinity.c b/libgomp/config/posix/affinity.c index 6840d3a727d..9008853c953 100644 --- a/libgomp/config/posix/affinity.c +++ b/libgomp/config/posix/affinity.c @@ -114,3 +114,27 @@ gomp_affinity_print_place (void *p) { (void) p; } + +int +omp_get_place_num_procs (int place_num) +{ + (void) place_num; + return 0; +} + +void +omp_get_place_proc_ids (int place_num, int *ids) +{ + (void) place_num; + (void) ids; +} + +void +gomp_get_place_proc_ids_8 (int place_num, int64_t *ids) +{ + (void) place_num; + (void) ids; +} + +ialias(omp_get_place_num_procs) +ialias(omp_get_place_proc_ids) diff --git a/libgomp/config/posix/doacross.h b/libgomp/config/posix/doacross.h new file mode 100644 index 00000000000..537bcbba51c --- /dev/null +++ b/libgomp/config/posix/doacross.h @@ -0,0 +1,62 @@ +/* Copyright (C) 2015 Free Software Foundation, Inc. + Contributed by Jakub Jelinek . + + This file is part of the GNU Offloading and Multi Processing Library + (libgomp). + + Libgomp is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + 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 General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +/* This is a generic implementation of doacross spinning. */ + +#ifndef GOMP_DOACROSS_H +#define GOMP_DOACROSS_H 1 + +#include "libgomp.h" +#include + +#ifdef HAVE_ATTRIBUTE_VISIBILITY +# pragma GCC visibility push(hidden) +#endif + +static inline void +cpu_relax (void) +{ + __asm volatile ("" : : : "memory"); +} + +static inline void doacross_spin (unsigned long *addr, unsigned long expected, + unsigned long cur) +{ + /* FIXME: back off depending on how large expected - cur is. */ + do + { + cpu_relax (); + cur = __atomic_load_n (addr, MEMMODEL_RELAXED); + if (expected < cur) + return; + } + while (1); +} + +#ifdef HAVE_ATTRIBUTE_VISIBILITY +# pragma GCC visibility pop +#endif + +#endif /* GOMP_DOACROSS_H */ diff --git a/libgomp/env.c b/libgomp/env.c index 6b5e963c4ea..5d6cdcf0184 100644 --- a/libgomp/env.c +++ b/libgomp/env.c @@ -29,6 +29,7 @@ #include "libgomp.h" #include "libgomp_f.h" #include "oacc-int.h" +#include "gomp-constants.h" #include #include #include @@ -58,7 +59,7 @@ struct gomp_task_icv gomp_global_icv = { .nthreads_var = 1, .thread_limit_var = UINT_MAX, .run_sched_var = GFS_DYNAMIC, - .run_sched_modifier = 1, + .run_sched_chunk_size = 1, .default_device_var = 0, .dyn_var = false, .nest_var = false, @@ -68,6 +69,7 @@ struct gomp_task_icv gomp_global_icv = { unsigned long gomp_max_active_levels_var = INT_MAX; bool gomp_cancel_var = false; +int gomp_max_task_priority_var = 0; #ifndef HAVE_SYNC_BUILTINS gomp_mutex_t gomp_managed_threads_lock; #endif @@ -123,7 +125,7 @@ parse_schedule (void) ++env; if (*env == '\0') { - gomp_global_icv.run_sched_modifier + gomp_global_icv.run_sched_chunk_size = gomp_global_icv.run_sched_var != GFS_STATIC; return; } @@ -149,7 +151,7 @@ parse_schedule (void) if (value == 0 && gomp_global_icv.run_sched_var != GFS_STATIC) value = 1; - gomp_global_icv.run_sched_modifier = value; + gomp_global_icv.run_sched_chunk_size = value; return; unknown: @@ -1069,7 +1071,7 @@ handle_omp_display_env (unsigned long stacksize, int wait_policy) fputs ("\nOPENMP DISPLAY ENVIRONMENT BEGIN\n", stderr); - fputs (" _OPENMP = '201307'\n", stderr); + fputs (" _OPENMP = '201511'\n", stderr); fprintf (stderr, " OMP_DYNAMIC = '%s'\n", gomp_global_icv.dyn_var ? "TRUE" : "FALSE"); fprintf (stderr, " OMP_NESTED = '%s'\n", @@ -1157,6 +1159,8 @@ handle_omp_display_env (unsigned long stacksize, int wait_policy) gomp_cancel_var ? "TRUE" : "FALSE"); fprintf (stderr, " OMP_DEFAULT_DEVICE = '%d'\n", gomp_global_icv.default_device_var); + fprintf (stderr, " OMP_MAX_TASK_PRIORITY = '%d'\n", + gomp_max_task_priority_var); if (verbose) { @@ -1189,6 +1193,7 @@ initialize_env (void) parse_boolean ("OMP_NESTED", &gomp_global_icv.nest_var); parse_boolean ("OMP_CANCELLATION", &gomp_cancel_var); parse_int ("OMP_DEFAULT_DEVICE", &gomp_global_icv.default_device_var, true); + parse_int ("OMP_MAX_TASK_PRIORITY", &gomp_max_task_priority_var, true); parse_unsigned_long ("OMP_MAX_ACTIVE_LEVELS", &gomp_max_active_levels_var, true); if (parse_unsigned_long ("OMP_THREAD_LIMIT", &thread_limit_var, false)) @@ -1337,21 +1342,21 @@ omp_get_nested (void) } void -omp_set_schedule (omp_sched_t kind, int modifier) +omp_set_schedule (omp_sched_t kind, int chunk_size) { struct gomp_task_icv *icv = gomp_icv (true); switch (kind) { case omp_sched_static: - if (modifier < 1) - modifier = 0; - icv->run_sched_modifier = modifier; + if (chunk_size < 1) + chunk_size = 0; + icv->run_sched_chunk_size = chunk_size; break; case omp_sched_dynamic: case omp_sched_guided: - if (modifier < 1) - modifier = 1; - icv->run_sched_modifier = modifier; + if (chunk_size < 1) + chunk_size = 1; + icv->run_sched_chunk_size = chunk_size; break; case omp_sched_auto: break; @@ -1362,11 +1367,11 @@ omp_set_schedule (omp_sched_t kind, int modifier) } void -omp_get_schedule (omp_sched_t *kind, int *modifier) +omp_get_schedule (omp_sched_t *kind, int *chunk_size) { struct gomp_task_icv *icv = gomp_icv (false); *kind = icv->run_sched_var; - *modifier = icv->run_sched_modifier; + *chunk_size = icv->run_sched_chunk_size; } int @@ -1402,6 +1407,12 @@ omp_get_cancellation (void) return gomp_cancel_var; } +int +omp_get_max_task_priority (void) +{ + return gomp_max_task_priority_var; +} + omp_proc_bind_t omp_get_proc_bind (void) { @@ -1450,6 +1461,59 @@ omp_is_initial_device (void) return 1; } +int +omp_get_initial_device (void) +{ + return GOMP_DEVICE_HOST_FALLBACK; +} + +int +omp_get_num_places (void) +{ + return gomp_places_list_len; +} + +int +omp_get_place_num (void) +{ + if (gomp_places_list == NULL) + return -1; + + struct gomp_thread *thr = gomp_thread (); + if (thr->place == 0) + gomp_init_affinity (); + + return (int) thr->place - 1; +} + +int +omp_get_partition_num_places (void) +{ + if (gomp_places_list == NULL) + return 0; + + struct gomp_thread *thr = gomp_thread (); + if (thr->place == 0) + gomp_init_affinity (); + + return thr->ts.place_partition_len; +} + +void +omp_get_partition_place_nums (int *place_nums) +{ + if (gomp_places_list == NULL) + return; + + struct gomp_thread *thr = gomp_thread (); + if (thr->place == 0) + gomp_init_affinity (); + + unsigned int i; + for (i = 0; i < thr->ts.place_partition_len; i++) + *place_nums++ = thr->ts.place_partition_off + i; +} + ialias (omp_set_dynamic) ialias (omp_set_nested) ialias (omp_set_num_threads) @@ -1469,3 +1533,9 @@ ialias (omp_get_num_devices) ialias (omp_get_num_teams) ialias (omp_get_team_num) ialias (omp_is_initial_device) +ialias (omp_get_initial_device) +ialias (omp_get_max_task_priority) +ialias (omp_get_num_places) +ialias (omp_get_place_num) +ialias (omp_get_partition_num_places) +ialias (omp_get_partition_place_nums) diff --git a/libgomp/fortran.c b/libgomp/fortran.c index 993145f8890..ceff9ac48e6 100644 --- a/libgomp/fortran.c +++ b/libgomp/fortran.c @@ -68,12 +68,20 @@ ialias_redirect (omp_get_active_level) ialias_redirect (omp_in_final) ialias_redirect (omp_get_cancellation) ialias_redirect (omp_get_proc_bind) +ialias_redirect (omp_get_num_places) +ialias_redirect (omp_get_place_num_procs) +ialias_redirect (omp_get_place_proc_ids) +ialias_redirect (omp_get_place_num) +ialias_redirect (omp_get_partition_num_places) +ialias_redirect (omp_get_partition_place_nums) ialias_redirect (omp_set_default_device) ialias_redirect (omp_get_default_device) ialias_redirect (omp_get_num_devices) ialias_redirect (omp_get_num_teams) ialias_redirect (omp_get_team_num) ialias_redirect (omp_is_initial_device) +ialias_redirect (omp_get_initial_device) +ialias_redirect (omp_get_max_task_priority) #endif #ifndef LIBGOMP_GNU_SYMBOL_VERSIONING @@ -343,35 +351,35 @@ omp_get_wtime_ (void) } void -omp_set_schedule_ (const int32_t *kind, const int32_t *modifier) +omp_set_schedule_ (const int32_t *kind, const int32_t *chunk_size) { - omp_set_schedule (*kind, *modifier); + omp_set_schedule (*kind, *chunk_size); } void -omp_set_schedule_8_ (const int32_t *kind, const int64_t *modifier) +omp_set_schedule_8_ (const int32_t *kind, const int64_t *chunk_size) { - omp_set_schedule (*kind, TO_INT (*modifier)); + omp_set_schedule (*kind, TO_INT (*chunk_size)); } void -omp_get_schedule_ (int32_t *kind, int32_t *modifier) +omp_get_schedule_ (int32_t *kind, int32_t *chunk_size) { omp_sched_t k; - int m; - omp_get_schedule (&k, &m); + int cs; + omp_get_schedule (&k, &cs); *kind = k; - *modifier = m; + *chunk_size = cs; } void -omp_get_schedule_8_ (int32_t *kind, int64_t *modifier) +omp_get_schedule_8_ (int32_t *kind, int64_t *chunk_size) { omp_sched_t k; - int m; - omp_get_schedule (&k, &m); + int cs; + omp_get_schedule (&k, &cs); *kind = k; - *modifier = m; + *chunk_size = cs; } int32_t @@ -452,6 +460,69 @@ omp_get_proc_bind_ (void) return omp_get_proc_bind (); } +int32_t +omp_get_num_places_ (void) +{ + return omp_get_num_places (); +} + +int32_t +omp_get_place_num_procs_ (const int32_t *place_num) +{ + return omp_get_place_num_procs (*place_num); +} + +int32_t +omp_get_place_num_procs_8_ (const int64_t *place_num) +{ + return omp_get_place_num_procs (TO_INT (*place_num)); +} + +void +omp_get_place_proc_ids_ (const int32_t *place_num, int32_t *ids) +{ + omp_get_place_proc_ids (*place_num, ids); +} + +void +omp_get_place_proc_ids_8_ (const int64_t *place_num, int64_t *ids) +{ + gomp_get_place_proc_ids_8 (TO_INT (*place_num), ids); +} + +int32_t +omp_get_place_num_ (void) +{ + return omp_get_place_num (); +} + +int32_t +omp_get_partition_num_places_ (void) +{ + return omp_get_partition_num_places (); +} + +void +omp_get_partition_place_nums_ (int32_t *place_nums) +{ + omp_get_partition_place_nums (place_nums); +} + +void +omp_get_partition_place_nums_8_ (int64_t *place_nums) +{ + if (gomp_places_list == NULL) + return; + + struct gomp_thread *thr = gomp_thread (); + if (thr->place == 0) + gomp_init_affinity (); + + unsigned int i; + for (i = 0; i < thr->ts.place_partition_len; i++) + *place_nums++ = (int64_t) thr->ts.place_partition_off + i; +} + void omp_set_default_device_ (const int32_t *device_num) { @@ -493,3 +564,15 @@ omp_is_initial_device_ (void) { return omp_is_initial_device (); } + +int32_t +omp_get_initial_device_ (void) +{ + return omp_get_initial_device (); +} + +int32_t +omp_get_max_task_priority_ (void) +{ + return omp_get_max_task_priority (); +} diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h index 04262c4ab28..9c8b1fb8744 100644 --- a/libgomp/libgomp.h +++ b/libgomp/libgomp.h @@ -36,6 +36,11 @@ #ifndef LIBGOMP_H #define LIBGOMP_H 1 +#ifndef _LIBGOMP_CHECKING_ +/* Define to 1 to perform internal sanity checks. */ +#define _LIBGOMP_CHECKING_ 0 +#endif + #include "config.h" #include "gstdint.h" #include "libgomp-plugin.h" @@ -78,6 +83,44 @@ enum gomp_schedule_type GFS_AUTO }; +struct gomp_doacross_work_share +{ + union { + /* chunk_size copy, as ws->chunk_size is multiplied by incr for + GFS_DYNAMIC. */ + long chunk_size; + /* Likewise, but for ull implementation. */ + unsigned long long chunk_size_ull; + /* For schedule(static,0) this is the number + of iterations assigned to the last thread, i.e. number of + iterations / number of threads. */ + long q; + /* Likewise, but for ull implementation. */ + unsigned long long q_ull; + }; + /* Size of each array entry (padded to cache line size). */ + unsigned long elt_sz; + /* Number of dimensions in sink vectors. */ + unsigned int ncounts; + /* True if the iterations can be flattened. */ + bool flattened; + /* Actual array (of elt_sz sized units), aligned to cache line size. + This is indexed by team_id for GFS_STATIC and outermost iteration + / chunk_size for other schedules. */ + unsigned char *array; + /* These two are only used for schedule(static,0). */ + /* This one is number of iterations % number of threads. */ + long t; + union { + /* And this one is cached t * (q + 1). */ + long boundary; + /* Likewise, but for the ull implementation. */ + unsigned long long boundary_ull; + }; + /* Array of shift counts for each dimension if they can be flattened. */ + unsigned int shift_counts[]; +}; + struct gomp_work_share { /* This member records the SCHEDULE clause to be used for this construct. @@ -109,13 +152,18 @@ struct gomp_work_share }; }; - /* This is a circular queue that details which threads will be allowed - into the ordered region and in which order. When a thread allocates - iterations on which it is going to work, it also registers itself at - the end of the array. When a thread reaches the ordered region, it - checks to see if it is the one at the head of the queue. If not, it - blocks on its RELEASE semaphore. */ - unsigned *ordered_team_ids; + union { + /* This is a circular queue that details which threads will be allowed + into the ordered region and in which order. When a thread allocates + iterations on which it is going to work, it also registers itself at + the end of the array. When a thread reaches the ordered region, it + checks to see if it is the one at the head of the queue. If not, it + blocks on its RELEASE semaphore. */ + unsigned *ordered_team_ids; + + /* This is a pointer to DOACROSS work share data. */ + struct gomp_doacross_work_share *doacross; + }; /* This is the number of threads that have registered themselves in the circular queue ordered_team_ids. */ @@ -234,7 +282,7 @@ struct gomp_task_icv { unsigned long nthreads_var; enum gomp_schedule_type run_sched_var; - int run_sched_modifier; + int run_sched_chunk_size; int default_device_var; unsigned int thread_limit_var; bool dyn_var; @@ -263,9 +311,13 @@ extern char *goacc_device_type; enum gomp_task_kind { + /* Implicit task. */ GOMP_TASK_IMPLICIT, - GOMP_TASK_IFFALSE, + /* Undeferred task. */ + GOMP_TASK_UNDEFERRED, + /* Task created by GOMP_task and waiting to be run. */ GOMP_TASK_WAITING, + /* Task currently executing or scheduled and about to execute. */ GOMP_TASK_TIED }; @@ -275,10 +327,13 @@ struct htab; struct gomp_task_depend_entry { + /* Address of dependency. */ void *addr; struct gomp_task_depend_entry *next; struct gomp_task_depend_entry *prev; + /* Task that provides the dependency in ADDR. */ struct gomp_task *task; + /* Depend entry is of type "IN". */ bool is_in; bool redundant; bool redundant_out; @@ -306,19 +361,35 @@ struct gomp_taskwait struct gomp_task { + /* Parent circular list. See children description below. */ struct gomp_task *parent; + /* Circular list representing the children of this task. + + In this list we first have parent_depends_on ready to run tasks, + then !parent_depends_on ready to run tasks, and finally already + running tasks. */ struct gomp_task *children; struct gomp_task *next_child; struct gomp_task *prev_child; + /* Circular task_queue in `struct gomp_team'. + + GOMP_TASK_WAITING tasks come before GOMP_TASK_TIED tasks. */ struct gomp_task *next_queue; struct gomp_task *prev_queue; + /* Circular queue in gomp_taskgroup->children. + + GOMP_TASK_WAITING tasks come before GOMP_TASK_TIED tasks. */ struct gomp_task *next_taskgroup; struct gomp_task *prev_taskgroup; + /* Taskgroup this task belongs in. */ struct gomp_taskgroup *taskgroup; + /* Tasks that depend on this task. */ struct gomp_dependers_vec *dependers; struct htab *depend_hash; struct gomp_taskwait *taskwait; + /* Number of items in DEPEND. */ size_t depend_count; + /* Number of tasks in the DEPENDERS field above. */ size_t num_dependees; struct gomp_task_icv icv; void (*fn) (void *); @@ -327,13 +398,23 @@ struct gomp_task bool in_tied_task; bool final_task; bool copy_ctors_done; + /* Set for undeferred tasks with unsatisfied dependencies which + block further execution of their parent until the dependencies + are satisfied. */ bool parent_depends_on; + /* Dependencies provided and/or needed for this task. DEPEND_COUNT + is the number of items available. */ struct gomp_task_depend_entry depend[]; }; struct gomp_taskgroup { struct gomp_taskgroup *prev; + /* Circular list of tasks that belong in this taskgroup. + + Tasks are chained by next/prev_taskgroup within gomp_task, and + are sorted by GOMP_TASK_WAITING tasks, and then GOMP_TASK_TIED + tasks. */ struct gomp_task *children; bool in_taskgroup_wait; bool cancelled; @@ -341,6 +422,17 @@ struct gomp_taskgroup size_t num_children; }; +struct gomp_target_task +{ + struct gomp_device_descr *devicep; + void (*fn) (void *); + size_t mapnum; + size_t *sizes; + unsigned short *kinds; + unsigned int flags; + void *hostaddrs[]; +}; + /* This structure describes a "team" of threads. These are the threads that are spawned by a PARALLEL constructs, as well as the work sharing constructs that the team encounters. */ @@ -403,6 +495,8 @@ struct gomp_team struct gomp_work_share work_shares[8]; gomp_mutex_t task_lock; + /* Scheduled tasks. Chain fields are next/prev_queue within a + gomp_task. */ struct gomp_task *task_queue; /* Number of all GOMP_TASK_{WAITING,TIED} tasks in the team. */ unsigned int task_count; @@ -531,6 +625,7 @@ extern bool gomp_affinity_same_place (void *, void *); extern bool gomp_affinity_finalize_place_list (bool); extern bool gomp_affinity_init_level (int, unsigned long, bool); extern void gomp_affinity_print_place (void *); +extern void gomp_get_place_proc_ids_8 (int, int64_t *); /* alloc.c */ @@ -600,6 +695,9 @@ extern void gomp_ordered_next (void); extern void gomp_ordered_static_init (void); extern void gomp_ordered_static_next (void); extern void gomp_ordered_sync (void); +extern void gomp_doacross_init (unsigned, long *, long); +extern void gomp_doacross_ull_init (unsigned, unsigned long long *, + unsigned long long); /* parallel.c */ @@ -616,6 +714,11 @@ extern void gomp_init_task (struct gomp_task *, struct gomp_task *, struct gomp_task_icv *); extern void gomp_end_task (void); extern void gomp_barrier_handle_tasks (gomp_barrier_state_t); +extern void gomp_task_maybe_wait_for_dependencies (void **); +extern void gomp_create_target_task (struct gomp_device_descr *, + void (*) (void *), size_t, void **, + size_t *, unsigned short *, unsigned int, + void **); static void inline gomp_finish_task (struct gomp_task *task) @@ -636,11 +739,25 @@ extern void gomp_free_thread (void *); extern void gomp_init_targets_once (void); extern int gomp_get_num_devices (void); +extern void gomp_target_task_fn (void *); typedef struct splay_tree_node_s *splay_tree_node; typedef struct splay_tree_s *splay_tree; typedef struct splay_tree_key_s *splay_tree_key; +struct target_var_desc { + /* Splay key. */ + splay_tree_key key; + /* True if data should be copied from device to host at the end. */ + bool copy_from; + /* True if data always should be copied from device to host at the end. */ + bool always_copy_from; + /* Relative offset against key host_start. */ + uintptr_t offset; + /* Actual length. */ + uintptr_t length; +}; + struct target_mem_desc { /* Reference count. */ uintptr_t refcount; @@ -660,11 +777,14 @@ struct target_mem_desc { /* Corresponding target device descriptor. */ struct gomp_device_descr *device_descr; - /* List of splay keys to remove (or decrease refcount) + /* List of target items to remove (or decrease refcount) at the end of region. */ - splay_tree_key list[]; + struct target_var_desc list[]; }; +/* Special value for refcount - infinity. */ +#define REFCOUNT_INFINITY (~(uintptr_t) 0) + struct splay_tree_key_s { /* Address of the host object. */ uintptr_t host_start; @@ -678,8 +798,6 @@ struct splay_tree_key_s { uintptr_t refcount; /* Asynchronous reference count. */ uintptr_t async_refcount; - /* True if data should be copied from device to host at the end. */ - bool copy_from; }; #include "splay-tree.h" @@ -757,6 +875,7 @@ struct gomp_device_descr void (*free_func) (int, void *); void *(*dev2host_func) (int, void *, const void *, size_t); void *(*host2dev_func) (int, void *, const void *, size_t); + void *(*dev2dev_func) (int, void *, const void *, size_t); void (*run_func) (int, void *, void *); /* Splay tree containing information about mapped memory regions. */ @@ -774,12 +893,22 @@ struct gomp_device_descr acc_dispatch_t openacc; }; +/* Kind of the pragma, for which gomp_map_vars () is called. */ +enum gomp_map_vars_kind +{ + GOMP_MAP_VARS_OPENACC, + GOMP_MAP_VARS_TARGET, + GOMP_MAP_VARS_DATA, + GOMP_MAP_VARS_ENTER_DATA +}; + extern void gomp_acc_insert_pointer (size_t, void **, size_t *, void *); extern void gomp_acc_remove_pointer (void *, bool, int, int); extern struct target_mem_desc *gomp_map_vars (struct gomp_device_descr *, size_t, void **, void **, - size_t *, void *, bool, bool); + size_t *, void *, bool, + enum gomp_map_vars_kind); extern void gomp_copy_from_async (struct target_mem_desc *); extern void gomp_unmap_vars (struct target_mem_desc *, bool); extern void gomp_init_device (struct gomp_device_descr *); diff --git a/libgomp/libgomp.map b/libgomp/libgomp.map index 3b3e0c2ac73..2153661ed5a 100644 --- a/libgomp/libgomp.map +++ b/libgomp/libgomp.map @@ -134,6 +134,36 @@ OMP_4.0 { omp_is_initial_device_; } OMP_3.1; +OMP_4.5 { + global: + omp_get_max_task_priority; + omp_get_max_task_priority_; + omp_get_num_places; + omp_get_num_places_; + omp_get_place_num_procs; + omp_get_place_num_procs_; + omp_get_place_num_procs_8_; + omp_get_place_proc_ids; + omp_get_place_proc_ids_; + omp_get_place_proc_ids_8_; + omp_get_place_num; + omp_get_place_num_; + omp_get_partition_num_places; + omp_get_partition_num_places_; + omp_get_partition_place_nums; + omp_get_partition_place_nums_; + omp_get_partition_place_nums_8_; + omp_get_initial_device; + omp_get_initial_device_; + omp_target_alloc; + omp_target_free; + omp_target_is_present; + omp_target_memcpy; + omp_target_memcpy_rect; + omp_target_associate_ptr; + omp_target_disassociate_ptr; +} OMP_4.0; + GOMP_1.0 { global: GOMP_atomic_end; @@ -234,10 +264,28 @@ GOMP_4.0.1 { GOMP_offload_unregister; } GOMP_4.0; -GOMP_4.0.2 { +GOMP_4.5 { global: + GOMP_target_41; + GOMP_target_data_41; + GOMP_target_update_41; + GOMP_target_enter_exit_data; + GOMP_taskloop; + GOMP_taskloop_ull; GOMP_offload_register_ver; GOMP_offload_unregister_ver; + GOMP_loop_doacross_dynamic_start; + GOMP_loop_doacross_guided_start; + GOMP_loop_doacross_runtime_start; + GOMP_loop_doacross_static_start; + GOMP_doacross_post; + GOMP_doacross_wait; + GOMP_loop_ull_doacross_dynamic_start; + GOMP_loop_ull_doacross_guided_start; + GOMP_loop_ull_doacross_runtime_start; + GOMP_loop_ull_doacross_static_start; + GOMP_doacross_ull_post; + GOMP_doacross_ull_wait; } GOMP_4.0.1; OACC_2.0 { diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi index 06b1c67fc02..67e6d199066 100644 --- a/libgomp/libgomp.texi +++ b/libgomp/libgomp.texi @@ -155,6 +155,7 @@ linkage, and do not throw exceptions. * omp_get_dynamic:: Dynamic teams setting * omp_get_level:: Number of parallel regions * omp_get_max_active_levels:: Maximum number of active regions +* omp_get_max_task_priority:: Maximum task priority value that can be set * omp_get_max_threads:: Maximum number of threads of parallel region * omp_get_nested:: Nested parallel regions * omp_get_num_devices:: Number of target devices @@ -388,6 +389,27 @@ This function obtains the maximum allowed number of nested, active parallel regi @end table +@node omp_get_max_task_priority +@section @code{omp_get_max_task_priority} -- Maximum priority value +that can be set for tasks. +@table @asis +@item @emph{Description}: +This function obtains the maximum allowed priority number for tasks. + +@item @emph{C/C++} +@multitable @columnfractions .20 .80 +@item @emph{Prototype}: @tab @code{int omp_get_max_task_priority(void);} +@end multitable + +@item @emph{Fortran}: +@multitable @columnfractions .20 .80 +@item @emph{Interface}: @tab @code{integer function omp_get_max_task_priority()} +@end multitable + +@item @emph{Reference}: +@uref{http://www.openmp.org/, OpenMP specification v4.5}, Section 3.2.29. +@end table + @node omp_get_max_threads @section @code{omp_get_max_threads} -- Maximum number of threads of parallel region @@ -581,18 +603,18 @@ set via @env{OMP_PROC_BIND}. Possible values are @code{omp_proc_bind_false}, Obtain the runtime scheduling method. The @var{kind} argument will be set to the value @code{omp_sched_static}, @code{omp_sched_dynamic}, @code{omp_sched_guided} or @code{omp_sched_auto}. The second argument, -@var{modifier}, is set to the chunk size. +@var{chunk_size}, is set to the chunk size. @item @emph{C/C++} @multitable @columnfractions .20 .80 -@item @emph{Prototype}: @tab @code{void omp_get_schedule(omp_sched_t *kind, int *modifier);} +@item @emph{Prototype}: @tab @code{void omp_get_schedule(omp_sched_t *kind, int *chunk_size);} @end multitable @item @emph{Fortran}: @multitable @columnfractions .20 .80 -@item @emph{Interface}: @tab @code{subroutine omp_get_schedule(kind, modifier)} +@item @emph{Interface}: @tab @code{subroutine omp_get_schedule(kind, chunk_size)} @item @tab @code{integer(kind=omp_sched_kind) kind} -@item @tab @code{integer modifier} +@item @tab @code{integer chunk_size} @end multitable @item @emph{See also}: @@ -929,19 +951,19 @@ Sets the runtime scheduling method. The @var{kind} argument can have the value @code{omp_sched_static}, @code{omp_sched_dynamic}, @code{omp_sched_guided} or @code{omp_sched_auto}. Except for @code{omp_sched_auto}, the chunk size is set to the value of -@var{modifier} if positive, or to the default value if zero or negative. -For @code{omp_sched_auto} the @var{modifier} argument is ignored. +@var{chunk_size} if positive, or to the default value if zero or negative. +For @code{omp_sched_auto} the @var{chunk_size} argument is ignored. @item @emph{C/C++} @multitable @columnfractions .20 .80 -@item @emph{Prototype}: @tab @code{void omp_set_schedule(omp_sched_t kind, int modifier);} +@item @emph{Prototype}: @tab @code{void omp_set_schedule(omp_sched_t kind, int chunk_size);} @end multitable @item @emph{Fortran}: @multitable @columnfractions .20 .80 -@item @emph{Interface}: @tab @code{subroutine omp_set_schedule(kind, modifier)} +@item @emph{Interface}: @tab @code{subroutine omp_set_schedule(kind, chunk_size)} @item @tab @code{integer(kind=omp_sched_kind) kind} -@item @tab @code{integer modifier} +@item @tab @code{integer chunk_size} @end multitable @item @emph{See also}: @@ -1311,6 +1333,7 @@ beginning with @env{GOMP_} are GNU extensions. * OMP_DEFAULT_DEVICE:: Set the device used in target regions * OMP_DYNAMIC:: Dynamic adjustment of threads * OMP_MAX_ACTIVE_LEVELS:: Set the maximum number of nested parallel regions +* OMP_MAX_TASK_PRIORITY:: Set the maximum task priority value * OMP_NESTED:: Nested parallel regions * OMP_NUM_THREADS:: Specifies the number of threads to use * OMP_PROC_BIND:: Whether theads may be moved between CPUs @@ -1420,6 +1443,26 @@ If undefined, the number of active levels is unlimited. +@node OMP_MAX_TASK_PRIORITY +@section @env{OMP_MAX_TASK_PRIORITY} -- Set the maximum priority +number that can be set for a task. +@cindex Environment Variable +@table @asis +@item @emph{Description}: +Specifies the initial value for the maximum priority value that can be +set for a task. The value of this variable shall be a non-negative +integer, and zero is allowed. If undefined, the default priority is +0. + +@item @emph{See also}: +@ref{omp_get_max_task_priority} + +@item @emph{Reference}: +@uref{http://www.openmp.org/, OpenMP specification v4.5}, Section 4.14 +@end table + + + @node OMP_NESTED @section @env{OMP_NESTED} -- Nested parallel regions @cindex Environment Variable diff --git a/libgomp/libgomp_g.h b/libgomp/libgomp_g.h index e7f4effaf48..c28ad2116dc 100644 --- a/libgomp/libgomp_g.h +++ b/libgomp/libgomp_g.h @@ -71,6 +71,15 @@ extern bool GOMP_loop_ordered_dynamic_next (long *, long *); extern bool GOMP_loop_ordered_guided_next (long *, long *); extern bool GOMP_loop_ordered_runtime_next (long *, long *); +extern bool GOMP_loop_doacross_static_start (unsigned, long *, long, long *, + long *); +extern bool GOMP_loop_doacross_dynamic_start (unsigned, long *, long, long *, + long *); +extern bool GOMP_loop_doacross_guided_start (unsigned, long *, long, long *, + long *); +extern bool GOMP_loop_doacross_runtime_start (unsigned, long *, long *, + long *); + extern void GOMP_parallel_loop_static_start (void (*)(void *), void *, unsigned, long, long, long, long); extern void GOMP_parallel_loop_dynamic_start (void (*)(void *), void *, @@ -164,10 +173,34 @@ extern bool GOMP_loop_ull_ordered_guided_next (unsigned long long *, extern bool GOMP_loop_ull_ordered_runtime_next (unsigned long long *, unsigned long long *); +extern bool GOMP_loop_ull_doacross_static_start (unsigned, + unsigned long long *, + unsigned long long, + unsigned long long *, + unsigned long long *); +extern bool GOMP_loop_ull_doacross_dynamic_start (unsigned, + unsigned long long *, + unsigned long long, + unsigned long long *, + unsigned long long *); +extern bool GOMP_loop_ull_doacross_guided_start (unsigned, + unsigned long long *, + unsigned long long, + unsigned long long *, + unsigned long long *); +extern bool GOMP_loop_ull_doacross_runtime_start (unsigned, + unsigned long long *, + unsigned long long *, + unsigned long long *); + /* ordered.c */ extern void GOMP_ordered_start (void); extern void GOMP_ordered_end (void); +extern void GOMP_doacross_post (long *); +extern void GOMP_doacross_wait (long, ...); +extern void GOMP_doacross_ull_post (unsigned long long *); +extern void GOMP_doacross_ull_wait (unsigned long long, ...); /* parallel.c */ @@ -180,7 +213,15 @@ extern bool GOMP_cancellation_point (int); /* task.c */ extern void GOMP_task (void (*) (void *), void *, void (*) (void *, void *), - long, long, bool, unsigned, void **); + long, long, bool, unsigned, void **, int); +extern void GOMP_taskloop (void (*) (void *), void *, + void (*) (void *, void *), long, long, unsigned, + unsigned long, int, long, long, long); +extern void GOMP_taskloop_ull (void (*) (void *), void *, + void (*) (void *, void *), long, long, + unsigned, unsigned long, int, + unsigned long long, unsigned long long, + unsigned long long); extern void GOMP_taskwait (void); extern void GOMP_taskyield (void); extern void GOMP_taskgroup_start (void); @@ -208,11 +249,20 @@ extern void GOMP_single_copy_end (void *); extern void GOMP_target (int, void (*) (void *), const void *, size_t, void **, size_t *, unsigned char *); +extern void GOMP_target_41 (int, void (*) (void *), size_t, void **, size_t *, + unsigned short *, unsigned int, void **); extern void GOMP_target_data (int, const void *, size_t, void **, size_t *, unsigned char *); +extern void GOMP_target_data_41 (int, size_t, void **, size_t *, + unsigned short *); extern void GOMP_target_end_data (void); extern void GOMP_target_update (int, const void *, size_t, void **, size_t *, unsigned char *); +extern void GOMP_target_update_41 (int, size_t, void **, size_t *, + unsigned short *, unsigned int, void **); +extern void GOMP_target_enter_exit_data (int, size_t, void **, size_t *, + unsigned short *, unsigned int, + void **); extern void GOMP_teams (unsigned int, unsigned int); /* oacc-parallel.c */ diff --git a/libgomp/loop.c b/libgomp/loop.c index 27d78db7a56..812f66cd725 100644 --- a/libgomp/loop.c +++ b/libgomp/loop.c @@ -169,13 +169,16 @@ GOMP_loop_runtime_start (long start, long end, long incr, switch (icv->run_sched_var) { case GFS_STATIC: - return gomp_loop_static_start (start, end, incr, icv->run_sched_modifier, + return gomp_loop_static_start (start, end, incr, + icv->run_sched_chunk_size, istart, iend); case GFS_DYNAMIC: - return gomp_loop_dynamic_start (start, end, incr, icv->run_sched_modifier, + return gomp_loop_dynamic_start (start, end, incr, + icv->run_sched_chunk_size, istart, iend); case GFS_GUIDED: - return gomp_loop_guided_start (start, end, incr, icv->run_sched_modifier, + return gomp_loop_guided_start (start, end, incr, + icv->run_sched_chunk_size, istart, iend); case GFS_AUTO: /* For now map to schedule(static), later on we could play with feedback @@ -266,15 +269,15 @@ GOMP_loop_ordered_runtime_start (long start, long end, long incr, { case GFS_STATIC: return gomp_loop_ordered_static_start (start, end, incr, - icv->run_sched_modifier, + icv->run_sched_chunk_size, istart, iend); case GFS_DYNAMIC: return gomp_loop_ordered_dynamic_start (start, end, incr, - icv->run_sched_modifier, + icv->run_sched_chunk_size, istart, iend); case GFS_GUIDED: return gomp_loop_ordered_guided_start (start, end, incr, - icv->run_sched_modifier, + icv->run_sched_chunk_size, istart, iend); case GFS_AUTO: /* For now map to schedule(static), later on we could play with feedback @@ -286,6 +289,111 @@ GOMP_loop_ordered_runtime_start (long start, long end, long incr, } } +/* The *_doacross_*_start routines are similar. The only difference is that + this work-share construct is initialized to expect an ORDERED(N) - DOACROSS + section, and the worksharing loop iterates always from 0 to COUNTS[0] - 1 + and other COUNTS array elements tell the library number of iterations + in the ordered inner loops. */ + +static bool +gomp_loop_doacross_static_start (unsigned ncounts, long *counts, + long chunk_size, long *istart, long *iend) +{ + struct gomp_thread *thr = gomp_thread (); + + thr->ts.static_trip = 0; + if (gomp_work_share_start (false)) + { + gomp_loop_init (thr->ts.work_share, 0, counts[0], 1, + GFS_STATIC, chunk_size); + gomp_doacross_init (ncounts, counts, chunk_size); + gomp_work_share_init_done (); + } + + return !gomp_iter_static_next (istart, iend); +} + +static bool +gomp_loop_doacross_dynamic_start (unsigned ncounts, long *counts, + long chunk_size, long *istart, long *iend) +{ + struct gomp_thread *thr = gomp_thread (); + bool ret; + + if (gomp_work_share_start (false)) + { + gomp_loop_init (thr->ts.work_share, 0, counts[0], 1, + GFS_DYNAMIC, chunk_size); + gomp_doacross_init (ncounts, counts, chunk_size); + gomp_work_share_init_done (); + } + +#ifdef HAVE_SYNC_BUILTINS + ret = gomp_iter_dynamic_next (istart, iend); +#else + gomp_mutex_lock (&thr->ts.work_share->lock); + ret = gomp_iter_dynamic_next_locked (istart, iend); + gomp_mutex_unlock (&thr->ts.work_share->lock); +#endif + + return ret; +} + +static bool +gomp_loop_doacross_guided_start (unsigned ncounts, long *counts, + long chunk_size, long *istart, long *iend) +{ + struct gomp_thread *thr = gomp_thread (); + bool ret; + + if (gomp_work_share_start (false)) + { + gomp_loop_init (thr->ts.work_share, 0, counts[0], 1, + GFS_GUIDED, chunk_size); + gomp_doacross_init (ncounts, counts, chunk_size); + gomp_work_share_init_done (); + } + +#ifdef HAVE_SYNC_BUILTINS + ret = gomp_iter_guided_next (istart, iend); +#else + gomp_mutex_lock (&thr->ts.work_share->lock); + ret = gomp_iter_guided_next_locked (istart, iend); + gomp_mutex_unlock (&thr->ts.work_share->lock); +#endif + + return ret; +} + +bool +GOMP_loop_doacross_runtime_start (unsigned ncounts, long *counts, + long *istart, long *iend) +{ + struct gomp_task_icv *icv = gomp_icv (false); + switch (icv->run_sched_var) + { + case GFS_STATIC: + return gomp_loop_doacross_static_start (ncounts, counts, + icv->run_sched_chunk_size, + istart, iend); + case GFS_DYNAMIC: + return gomp_loop_doacross_dynamic_start (ncounts, counts, + icv->run_sched_chunk_size, + istart, iend); + case GFS_GUIDED: + return gomp_loop_doacross_guided_start (ncounts, counts, + icv->run_sched_chunk_size, + istart, iend); + case GFS_AUTO: + /* For now map to schedule(static), later on we could play with feedback + driven choice. */ + return gomp_loop_doacross_static_start (ncounts, counts, + 0, istart, iend); + default: + abort (); + } +} + /* The *_next routines are called when the thread completes processing of the iteration block currently assigned to it. If the work-share construct is bound directly to a parallel construct, then the iteration @@ -484,7 +592,7 @@ GOMP_parallel_loop_runtime_start (void (*fn) (void *), void *data, { struct gomp_task_icv *icv = gomp_icv (false); gomp_parallel_loop_start (fn, data, num_threads, start, end, incr, - icv->run_sched_var, icv->run_sched_modifier, 0); + icv->run_sched_var, icv->run_sched_chunk_size, 0); } ialias_redirect (GOMP_parallel_end) @@ -529,7 +637,7 @@ GOMP_parallel_loop_runtime (void (*fn) (void *), void *data, { struct gomp_task_icv *icv = gomp_icv (false); gomp_parallel_loop_start (fn, data, num_threads, start, end, incr, - icv->run_sched_var, icv->run_sched_modifier, + icv->run_sched_var, icv->run_sched_chunk_size, flags); fn (data); GOMP_parallel_end (); @@ -578,6 +686,13 @@ extern __typeof(gomp_loop_ordered_dynamic_start) GOMP_loop_ordered_dynamic_start extern __typeof(gomp_loop_ordered_guided_start) GOMP_loop_ordered_guided_start __attribute__((alias ("gomp_loop_ordered_guided_start"))); +extern __typeof(gomp_loop_doacross_static_start) GOMP_loop_doacross_static_start + __attribute__((alias ("gomp_loop_doacross_static_start"))); +extern __typeof(gomp_loop_doacross_dynamic_start) GOMP_loop_doacross_dynamic_start + __attribute__((alias ("gomp_loop_doacross_dynamic_start"))); +extern __typeof(gomp_loop_doacross_guided_start) GOMP_loop_doacross_guided_start + __attribute__((alias ("gomp_loop_doacross_guided_start"))); + extern __typeof(gomp_loop_static_next) GOMP_loop_static_next __attribute__((alias ("gomp_loop_static_next"))); extern __typeof(gomp_loop_dynamic_next) GOMP_loop_dynamic_next @@ -637,6 +752,30 @@ GOMP_loop_ordered_guided_start (long start, long end, long incr, istart, iend); } +bool +GOMP_loop_doacross_static_start (unsigned ncounts, long *counts, + long chunk_size, long *istart, long *iend) +{ + return gomp_loop_doacross_static_start (ncounts, counts, chunk_size, + istart, iend); +} + +bool +GOMP_loop_doacross_dynamic_start (unsigned ncounts, long *counts, + long chunk_size, long *istart, long *iend) +{ + return gomp_loop_doacross_dynamic_start (ncounts, counts, chunk_size, + istart, iend); +} + +bool +GOMP_loop_doacross_guided_start (unsigned ncounts, long *counts, + long chunk_size, long *istart, long *iend) +{ + return gomp_loop_doacross_guided_start (ncounts, counts, chunk_size, + istart, iend); +} + bool GOMP_loop_static_next (long *istart, long *iend) { diff --git a/libgomp/loop_ull.c b/libgomp/loop_ull.c index de56ae0b7ce..1f2ed546024 100644 --- a/libgomp/loop_ull.c +++ b/libgomp/loop_ull.c @@ -175,15 +175,15 @@ GOMP_loop_ull_runtime_start (bool up, gomp_ull start, gomp_ull end, { case GFS_STATIC: return gomp_loop_ull_static_start (up, start, end, incr, - icv->run_sched_modifier, + icv->run_sched_chunk_size, istart, iend); case GFS_DYNAMIC: return gomp_loop_ull_dynamic_start (up, start, end, incr, - icv->run_sched_modifier, + icv->run_sched_chunk_size, istart, iend); case GFS_GUIDED: return gomp_loop_ull_guided_start (up, start, end, incr, - icv->run_sched_modifier, + icv->run_sched_chunk_size, istart, iend); case GFS_AUTO: /* For now map to schedule(static), later on we could play with feedback @@ -279,15 +279,15 @@ GOMP_loop_ull_ordered_runtime_start (bool up, gomp_ull start, gomp_ull end, { case GFS_STATIC: return gomp_loop_ull_ordered_static_start (up, start, end, incr, - icv->run_sched_modifier, + icv->run_sched_chunk_size, istart, iend); case GFS_DYNAMIC: return gomp_loop_ull_ordered_dynamic_start (up, start, end, incr, - icv->run_sched_modifier, + icv->run_sched_chunk_size, istart, iend); case GFS_GUIDED: return gomp_loop_ull_ordered_guided_start (up, start, end, incr, - icv->run_sched_modifier, + icv->run_sched_chunk_size, istart, iend); case GFS_AUTO: /* For now map to schedule(static), later on we could play with feedback @@ -299,6 +299,114 @@ GOMP_loop_ull_ordered_runtime_start (bool up, gomp_ull start, gomp_ull end, } } +/* The *_doacross_*_start routines are similar. The only difference is that + this work-share construct is initialized to expect an ORDERED(N) - DOACROSS + section, and the worksharing loop iterates always from 0 to COUNTS[0] - 1 + and other COUNTS array elements tell the library number of iterations + in the ordered inner loops. */ + +static bool +gomp_loop_ull_doacross_static_start (unsigned ncounts, gomp_ull *counts, + gomp_ull chunk_size, gomp_ull *istart, + gomp_ull *iend) +{ + struct gomp_thread *thr = gomp_thread (); + + thr->ts.static_trip = 0; + if (gomp_work_share_start (false)) + { + gomp_loop_ull_init (thr->ts.work_share, true, 0, counts[0], 1, + GFS_STATIC, chunk_size); + gomp_doacross_ull_init (ncounts, counts, chunk_size); + gomp_work_share_init_done (); + } + + return !gomp_iter_ull_static_next (istart, iend); +} + +static bool +gomp_loop_ull_doacross_dynamic_start (unsigned ncounts, gomp_ull *counts, + gomp_ull chunk_size, gomp_ull *istart, + gomp_ull *iend) +{ + struct gomp_thread *thr = gomp_thread (); + bool ret; + + if (gomp_work_share_start (false)) + { + gomp_loop_ull_init (thr->ts.work_share, true, 0, counts[0], 1, + GFS_DYNAMIC, chunk_size); + gomp_doacross_ull_init (ncounts, counts, chunk_size); + gomp_work_share_init_done (); + } + +#if defined HAVE_SYNC_BUILTINS && defined __LP64__ + ret = gomp_iter_ull_dynamic_next (istart, iend); +#else + gomp_mutex_lock (&thr->ts.work_share->lock); + ret = gomp_iter_ull_dynamic_next_locked (istart, iend); + gomp_mutex_unlock (&thr->ts.work_share->lock); +#endif + + return ret; +} + +static bool +gomp_loop_ull_doacross_guided_start (unsigned ncounts, gomp_ull *counts, + gomp_ull chunk_size, gomp_ull *istart, + gomp_ull *iend) +{ + struct gomp_thread *thr = gomp_thread (); + bool ret; + + if (gomp_work_share_start (false)) + { + gomp_loop_ull_init (thr->ts.work_share, true, 0, counts[0], 1, + GFS_GUIDED, chunk_size); + gomp_doacross_ull_init (ncounts, counts, chunk_size); + gomp_work_share_init_done (); + } + +#if defined HAVE_SYNC_BUILTINS && defined __LP64__ + ret = gomp_iter_ull_guided_next (istart, iend); +#else + gomp_mutex_lock (&thr->ts.work_share->lock); + ret = gomp_iter_ull_guided_next_locked (istart, iend); + gomp_mutex_unlock (&thr->ts.work_share->lock); +#endif + + return ret; +} + +bool +GOMP_loop_ull_doacross_runtime_start (unsigned ncounts, gomp_ull *counts, + gomp_ull *istart, gomp_ull *iend) +{ + struct gomp_task_icv *icv = gomp_icv (false); + switch (icv->run_sched_var) + { + case GFS_STATIC: + return gomp_loop_ull_doacross_static_start (ncounts, counts, + icv->run_sched_chunk_size, + istart, iend); + case GFS_DYNAMIC: + return gomp_loop_ull_doacross_dynamic_start (ncounts, counts, + icv->run_sched_chunk_size, + istart, iend); + case GFS_GUIDED: + return gomp_loop_ull_doacross_guided_start (ncounts, counts, + icv->run_sched_chunk_size, + istart, iend); + case GFS_AUTO: + /* For now map to schedule(static), later on we could play with feedback + driven choice. */ + return gomp_loop_ull_doacross_static_start (ncounts, counts, + 0, istart, iend); + default: + abort (); + } +} + /* The *_next routines are called when the thread completes processing of the iteration block currently assigned to it. If the work-share construct is bound directly to a parallel construct, then the iteration @@ -466,6 +574,13 @@ extern __typeof(gomp_loop_ull_ordered_dynamic_start) GOMP_loop_ull_ordered_dynam extern __typeof(gomp_loop_ull_ordered_guided_start) GOMP_loop_ull_ordered_guided_start __attribute__((alias ("gomp_loop_ull_ordered_guided_start"))); +extern __typeof(gomp_loop_ull_doacross_static_start) GOMP_loop_ull_doacross_static_start + __attribute__((alias ("gomp_loop_ull_doacross_static_start"))); +extern __typeof(gomp_loop_ull_doacross_dynamic_start) GOMP_loop_ull_doacross_dynamic_start + __attribute__((alias ("gomp_loop_ull_doacross_dynamic_start"))); +extern __typeof(gomp_loop_ull_doacross_guided_start) GOMP_loop_ull_doacross_guided_start + __attribute__((alias ("gomp_loop_ull_doacross_guided_start"))); + extern __typeof(gomp_loop_ull_static_next) GOMP_loop_ull_static_next __attribute__((alias ("gomp_loop_ull_static_next"))); extern __typeof(gomp_loop_ull_dynamic_next) GOMP_loop_ull_dynamic_next @@ -534,6 +649,33 @@ GOMP_loop_ull_ordered_guided_start (bool up, gomp_ull start, gomp_ull end, istart, iend); } +bool +GOMP_loop_ull_doacross_static_start (unsigned ncounts, gomp_ull *counts, + gomp_ull chunk_size, gomp_ull *istart, + gomp_ull *iend) +{ + return gomp_loop_ull_doacross_static_start (ncounts, counts, chunk_size, + istart, iend); +} + +bool +GOMP_loop_ull_doacross_dynamic_start (unsigned ncounts, gomp_ull *counts, + gomp_ull chunk_size, gomp_ull *istart, + gomp_ull *iend) +{ + return gomp_loop_ull_doacross_dynamic_start (ncounts, counts, chunk_size, + istart, iend); +} + +bool +GOMP_loop_ull_doacross_guided_start (unsigned ncounts, gomp_ull *counts, + gomp_ull chunk_size, gomp_ull *istart, + gomp_ull *iend) +{ + return gomp_loop_ull_doacross_guided_start (ncounts, counts, chunk_size, + istart, iend); +} + bool GOMP_loop_ull_static_next (gomp_ull *istart, gomp_ull *iend) { diff --git a/libgomp/oacc-mem.c b/libgomp/oacc-mem.c index 90d43eb2b8a..af067d6e73c 100644 --- a/libgomp/oacc-mem.c +++ b/libgomp/oacc-mem.c @@ -289,7 +289,8 @@ acc_map_data (void *h, void *d, size_t s) if (d != h) gomp_fatal ("cannot map data on shared-memory system"); - tgt = gomp_map_vars (NULL, 0, NULL, NULL, NULL, NULL, true, false); + tgt = gomp_map_vars (NULL, 0, NULL, NULL, NULL, NULL, true, + GOMP_MAP_VARS_OPENACC); } else { @@ -318,7 +319,7 @@ acc_map_data (void *h, void *d, size_t s) gomp_mutex_unlock (&acc_dev->lock); tgt = gomp_map_vars (acc_dev, mapnum, &hostaddrs, &devaddrs, &sizes, - &kinds, true, false); + &kinds, true, GOMP_MAP_VARS_OPENACC); } gomp_mutex_lock (&acc_dev->lock); @@ -447,7 +448,7 @@ present_create_copy (unsigned f, void *h, size_t s) gomp_mutex_unlock (&acc_dev->lock); tgt = gomp_map_vars (acc_dev, mapnum, &hostaddrs, NULL, &s, &kinds, true, - false); + GOMP_MAP_VARS_OPENACC); gomp_mutex_lock (&acc_dev->lock); @@ -594,7 +595,7 @@ gomp_acc_insert_pointer (size_t mapnum, void **hostaddrs, size_t *sizes, gomp_debug (0, " %s: prepare mappings\n", __FUNCTION__); tgt = gomp_map_vars (acc_dev, mapnum, hostaddrs, - NULL, sizes, kinds, true, false); + NULL, sizes, kinds, true, GOMP_MAP_VARS_OPENACC); gomp_debug (0, " %s: mappings prepared\n", __FUNCTION__); gomp_mutex_lock (&acc_dev->lock); @@ -651,7 +652,7 @@ gomp_acc_remove_pointer (void *h, bool force_copyfrom, int async, int mapnum) } if (force_copyfrom) - t->list[0]->copy_from = 1; + t->list[0].copy_from = 1; gomp_mutex_unlock (&acc_dev->lock); diff --git a/libgomp/oacc-parallel.c b/libgomp/oacc-parallel.c index e31bc0a7bc6..b150106981e 100644 --- a/libgomp/oacc-parallel.c +++ b/libgomp/oacc-parallel.c @@ -168,12 +168,12 @@ GOACC_parallel_keyed (int device, void (*fn) (void *), tgt_fn = (void (*)) fn; tgt = gomp_map_vars (acc_dev, mapnum, hostaddrs, NULL, sizes, kinds, true, - false); + GOMP_MAP_VARS_OPENACC); devaddrs = gomp_alloca (sizeof (void *) * mapnum); for (i = 0; i < mapnum; i++) - devaddrs[i] = (void *) (tgt->list[i]->tgt->tgt_start - + tgt->list[i]->tgt_offset); + devaddrs[i] = (void *) (tgt->list[i].key->tgt->tgt_start + + tgt->list[i].key->tgt_offset); acc_dev->openacc.exec_func (tgt_fn, mapnum, hostaddrs, devaddrs, sizes, kinds, async, dims, tgt); @@ -228,7 +228,8 @@ GOACC_data_start (int device, size_t mapnum, if ((acc_dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM) || host_fallback) { - tgt = gomp_map_vars (NULL, 0, NULL, NULL, NULL, NULL, true, false); + tgt = gomp_map_vars (NULL, 0, NULL, NULL, NULL, NULL, true, + GOMP_MAP_VARS_OPENACC); tgt->prev = thr->mapped_data; thr->mapped_data = tgt; @@ -237,7 +238,7 @@ GOACC_data_start (int device, size_t mapnum, gomp_debug (0, " %s: prepare mappings\n", __FUNCTION__); tgt = gomp_map_vars (acc_dev, mapnum, hostaddrs, NULL, sizes, kinds, true, - false); + GOMP_MAP_VARS_OPENACC); gomp_debug (0, " %s: mappings prepared\n", __FUNCTION__); tgt->prev = thr->mapped_data; thr->mapped_data = tgt; diff --git a/libgomp/omp.h.in b/libgomp/omp.h.in index dac3e8ad6ef..090498ad784 100644 --- a/libgomp/omp.h.in +++ b/libgomp/omp.h.in @@ -62,6 +62,15 @@ typedef enum omp_proc_bind_t omp_proc_bind_spread = 4 } omp_proc_bind_t; +typedef enum omp_lock_hint_t +{ + omp_lock_hint_none = 0, + omp_lock_hint_uncontended = 1, + omp_lock_hint_contended = 2, + omp_lock_hint_nonspeculative = 4, + omp_lock_hint_speculative = 8, +} omp_lock_hint_t; + #ifdef __cplusplus extern "C" { # define __GOMP_NOTHROW throw () @@ -84,12 +93,16 @@ extern void omp_set_nested (int) __GOMP_NOTHROW; extern int omp_get_nested (void) __GOMP_NOTHROW; extern void omp_init_lock (omp_lock_t *) __GOMP_NOTHROW; +extern void omp_init_lock_with_hint (omp_lock_t *, omp_lock_hint_t) + __GOMP_NOTHROW; extern void omp_destroy_lock (omp_lock_t *) __GOMP_NOTHROW; extern void omp_set_lock (omp_lock_t *) __GOMP_NOTHROW; extern void omp_unset_lock (omp_lock_t *) __GOMP_NOTHROW; extern int omp_test_lock (omp_lock_t *) __GOMP_NOTHROW; extern void omp_init_nest_lock (omp_nest_lock_t *) __GOMP_NOTHROW; +extern void omp_init_nest_lock_with_hint (omp_lock_t *, omp_lock_hint_t) + __GOMP_NOTHROW; extern void omp_destroy_nest_lock (omp_nest_lock_t *) __GOMP_NOTHROW; extern void omp_set_nest_lock (omp_nest_lock_t *) __GOMP_NOTHROW; extern void omp_unset_nest_lock (omp_nest_lock_t *) __GOMP_NOTHROW; @@ -112,6 +125,12 @@ extern int omp_in_final (void) __GOMP_NOTHROW; extern int omp_get_cancellation (void) __GOMP_NOTHROW; extern omp_proc_bind_t omp_get_proc_bind (void) __GOMP_NOTHROW; +extern int omp_get_num_places (void) __GOMP_NOTHROW; +extern int omp_get_place_num_procs (int) __GOMP_NOTHROW; +extern void omp_get_place_proc_ids (int, int *) __GOMP_NOTHROW; +extern int omp_get_place_num (void) __GOMP_NOTHROW; +extern int omp_get_partition_num_places (void) __GOMP_NOTHROW; +extern void omp_get_partition_place_nums (int *) __GOMP_NOTHROW; extern void omp_set_default_device (int) __GOMP_NOTHROW; extern int omp_get_default_device (void) __GOMP_NOTHROW; @@ -120,6 +139,24 @@ extern int omp_get_num_teams (void) __GOMP_NOTHROW; extern int omp_get_team_num (void) __GOMP_NOTHROW; extern int omp_is_initial_device (void) __GOMP_NOTHROW; +extern int omp_get_initial_device (void) __GOMP_NOTHROW; +extern int omp_get_max_task_priority (void) __GOMP_NOTHROW; + +extern void *omp_target_alloc (__SIZE_TYPE__, int) __GOMP_NOTHROW; +extern void omp_target_free (void *, int) __GOMP_NOTHROW; +extern int omp_target_is_present (void *, int) __GOMP_NOTHROW; +extern int omp_target_memcpy (void *, void *, __SIZE_TYPE__, __SIZE_TYPE__, + __SIZE_TYPE__, int, int) __GOMP_NOTHROW; +extern int omp_target_memcpy_rect (void *, void *, __SIZE_TYPE__, int, + const __SIZE_TYPE__ *, + const __SIZE_TYPE__ *, + const __SIZE_TYPE__ *, + const __SIZE_TYPE__ *, + const __SIZE_TYPE__ *, int, int) + __GOMP_NOTHROW; +extern int omp_target_associate_ptr (void *, void *, __SIZE_TYPE__, + __SIZE_TYPE__, int) __GOMP_NOTHROW; +extern int omp_target_disassociate_ptr (void *, int) __GOMP_NOTHROW; #ifdef __cplusplus } diff --git a/libgomp/omp_lib.f90.in b/libgomp/omp_lib.f90.in index 122563e625a..28df9c1664e 100644 --- a/libgomp/omp_lib.f90.in +++ b/libgomp/omp_lib.f90.in @@ -29,15 +29,31 @@ integer, parameter :: omp_nest_lock_kind = @OMP_NEST_LOCK_KIND@ integer, parameter :: omp_sched_kind = 4 integer, parameter :: omp_proc_bind_kind = 4 + integer, parameter :: omp_lock_hint_kind = 4 integer (omp_sched_kind), parameter :: omp_sched_static = 1 integer (omp_sched_kind), parameter :: omp_sched_dynamic = 2 integer (omp_sched_kind), parameter :: omp_sched_guided = 3 integer (omp_sched_kind), parameter :: omp_sched_auto = 4 - integer (omp_proc_bind_kind), parameter :: omp_proc_bind_false = 0 - integer (omp_proc_bind_kind), parameter :: omp_proc_bind_true = 1 - integer (omp_proc_bind_kind), parameter :: omp_proc_bind_master = 2 - integer (omp_proc_bind_kind), parameter :: omp_proc_bind_close = 3 - integer (omp_proc_bind_kind), parameter :: omp_proc_bind_spread = 4 + integer (omp_proc_bind_kind), & + parameter :: omp_proc_bind_false = 0 + integer (omp_proc_bind_kind), & + parameter :: omp_proc_bind_true = 1 + integer (omp_proc_bind_kind), & + parameter :: omp_proc_bind_master = 2 + integer (omp_proc_bind_kind), & + parameter :: omp_proc_bind_close = 3 + integer (omp_proc_bind_kind), & + parameter :: omp_proc_bind_spread = 4 + integer (omp_lock_hint_kind), & + parameter :: omp_lock_hint_none = 0 + integer (omp_lock_hint_kind), & + parameter :: omp_lock_hint_uncontended = 1 + integer (omp_lock_hint_kind), & + parameter :: omp_lock_hint_contended = 2 + integer (omp_lock_hint_kind), & + parameter :: omp_lock_hint_nonspeculative = 4 + integer (omp_lock_hint_kind), & + parameter :: omp_lock_hint_speculative = 8 end module module omp_lib @@ -52,6 +68,14 @@ end subroutine omp_init_lock end interface + interface + subroutine omp_init_lock_with_hint (svar, hint) + use omp_lib_kinds + integer (omp_lock_kind), intent (out) :: svar + integer (omp_lock_hint_kind), intent (in) :: hint + end subroutine omp_init_lock_with_hint + end interface + interface subroutine omp_init_nest_lock (nvar) use omp_lib_kinds @@ -59,6 +83,14 @@ end subroutine omp_init_nest_lock end interface + interface + subroutine omp_init_nest_lock_with_hint (nvar, hint) + use omp_lib_kinds + integer (omp_nest_lock_kind), intent (out) :: nvar + integer (omp_lock_hint_kind), intent (in) :: hint + end subroutine omp_init_nest_lock_with_hint + end interface + interface subroutine omp_destroy_lock (svar) use omp_lib_kinds @@ -199,28 +231,28 @@ end interface interface omp_set_schedule - subroutine omp_set_schedule (kind, modifier) + subroutine omp_set_schedule (kind, chunk_size) use omp_lib_kinds integer (omp_sched_kind), intent (in) :: kind - integer (4), intent (in) :: modifier + integer (4), intent (in) :: chunk_size end subroutine omp_set_schedule - subroutine omp_set_schedule_8 (kind, modifier) + subroutine omp_set_schedule_8 (kind, chunk_size) use omp_lib_kinds integer (omp_sched_kind), intent (in) :: kind - integer (8), intent (in) :: modifier + integer (8), intent (in) :: chunk_size end subroutine omp_set_schedule_8 end interface interface omp_get_schedule - subroutine omp_get_schedule (kind, modifier) + subroutine omp_get_schedule (kind, chunk_size) use omp_lib_kinds integer (omp_sched_kind), intent (out) :: kind - integer (4), intent (out) :: modifier + integer (4), intent (out) :: chunk_size end subroutine omp_get_schedule - subroutine omp_get_schedule_8 (kind, modifier) + subroutine omp_get_schedule_8 (kind, chunk_size) use omp_lib_kinds integer (omp_sched_kind), intent (out) :: kind - integer (8), intent (out) :: modifier + integer (8), intent (out) :: chunk_size end subroutine omp_get_schedule_8 end interface @@ -298,6 +330,58 @@ end function omp_get_proc_bind end interface + interface + function omp_get_num_places () + integer (4) :: omp_get_num_places + end function omp_get_num_places + end interface + + interface omp_get_place_num_procs + function omp_get_place_num_procs (place_num) + integer (4), intent(in) :: place_num + integer (4) :: omp_get_place_num_procs + end function omp_get_place_num_procs + + function omp_get_place_num_procs_8 (place_num) + integer (8), intent(in) :: place_num + integer (4) :: omp_get_place_num_procs_8 + end function omp_get_place_num_procs_8 + end interface + + interface omp_get_place_proc_ids + subroutine omp_get_place_proc_ids (place_num, ids) + integer (4), intent(in) :: place_num + integer (4), intent(out) :: ids(*) + end subroutine omp_get_place_proc_ids + + subroutine omp_get_place_proc_ids_8 (place_num, ids) + integer (8), intent(in) :: place_num + integer (8), intent(out) :: ids(*) + end subroutine omp_get_place_proc_ids_8 + end interface + + interface + function omp_get_place_num () + integer (4) :: omp_get_place_num + end function omp_get_place_num + end interface + + interface + function omp_get_partition_num_places () + integer (4) :: omp_get_partition_num_places + end function omp_get_partition_num_places + end interface + + interface omp_get_partition_place_nums + subroutine omp_get_partition_place_nums (place_nums) + integer (4), intent(out) :: place_nums(*) + end subroutine omp_get_partition_place_nums + + subroutine omp_get_partition_place_nums_8 (place_nums) + integer (8), intent(out) :: place_nums(*) + end subroutine omp_get_partition_place_nums_8 + end interface + interface omp_set_default_device subroutine omp_set_default_device (device_num) integer (4), intent (in) :: device_num @@ -337,4 +421,16 @@ end function omp_is_initial_device end interface + interface + function omp_get_initial_device () + integer (4) :: omp_get_initial_device + end function omp_get_initial_device + end interface + + interface + function omp_get_max_task_priority () + integer (4) :: omp_get_max_task_priority + end function omp_get_max_task_priority + end interface + end module omp_lib diff --git a/libgomp/omp_lib.h.in b/libgomp/omp_lib.h.in index d590bc15135..81662424500 100644 --- a/libgomp/omp_lib.h.in +++ b/libgomp/omp_lib.h.in @@ -46,9 +46,23 @@ parameter (omp_proc_bind_master = 2) parameter (omp_proc_bind_close = 3) parameter (omp_proc_bind_spread = 4) + integer omp_lock_hint_kind + parameter (omp_lock_hint_kind = 4) + integer (omp_lock_hint_kind) omp_lock_hint_none + integer (omp_lock_hint_kind) omp_lock_hint_uncontended + integer (omp_lock_hint_kind) omp_lock_hint_contended + integer (omp_lock_hint_kind) omp_lock_hint_nonspeculative + integer (omp_lock_hint_kind) omp_lock_hint_speculative + parameter (omp_lock_hint_none = 0) + parameter (omp_lock_hint_uncontended = 1) + parameter (omp_lock_hint_contended = 2) + parameter (omp_lock_hint_nonspeculative = 4) + parameter (omp_lock_hint_speculative = 8) parameter (openmp_version = 201307) external omp_init_lock, omp_init_nest_lock + external omp_init_lock_with_hint + external omp_init_nest_lock_with_hint external omp_destroy_lock, omp_destroy_nest_lock external omp_set_lock, omp_set_nest_lock external omp_unset_lock, omp_unset_nest_lock @@ -88,6 +102,17 @@ external omp_get_proc_bind integer(omp_proc_bind_kind) omp_get_proc_bind + integer(4) omp_get_num_places + external omp_get_num_places + integer(4) omp_get_place_num_procs + external omp_get_place_num_procs + external omp_get_place_proc_ids + integer(4) omp_get_place_num + external omp_get_place_num + integer(4) omp_get_partition_num_places + external omp_get_partition_num_places + external omp_get_partition_place_nums + external omp_set_default_device, omp_get_default_device external omp_get_num_devices, omp_get_num_teams external omp_get_team_num @@ -96,3 +121,8 @@ external omp_is_initial_device logical(4) omp_is_initial_device + external omp_get_initial_device + integer(4) omp_get_initial_device + + external omp_get_max_task_priority + integer(4) omp_get_max_task_priority diff --git a/libgomp/ordered.c b/libgomp/ordered.c index 69ca217b4d5..fdac3ee8f58 100644 --- a/libgomp/ordered.c +++ b/libgomp/ordered.c @@ -26,6 +26,9 @@ /* This file handles the ORDERED construct. */ #include "libgomp.h" +#include +#include +#include "doacross.h" /* This function is called when first allocating an iteration block. That @@ -250,3 +253,521 @@ void GOMP_ordered_end (void) { } + +/* DOACROSS initialization. */ + +#define MAX_COLLAPSED_BITS (__SIZEOF_LONG__ * __CHAR_BIT__) + +void +gomp_doacross_init (unsigned ncounts, long *counts, long chunk_size) +{ + struct gomp_thread *thr = gomp_thread (); + struct gomp_team *team = thr->ts.team; + struct gomp_work_share *ws = thr->ts.work_share; + unsigned int i, bits[MAX_COLLAPSED_BITS], num_bits = 0; + unsigned long ent, num_ents, elt_sz, shift_sz; + struct gomp_doacross_work_share *doacross; + + if (team == NULL || team->nthreads == 1) + return; + + for (i = 0; i < ncounts; i++) + { + /* If any count is 0, GOMP_doacross_{post,wait} can't be called. */ + if (counts[i] == 0) + return; + + if (num_bits <= MAX_COLLAPSED_BITS) + { + unsigned int this_bits; + if (counts[i] == 1) + this_bits = 1; + else + this_bits = __SIZEOF_LONG__ * __CHAR_BIT__ + - __builtin_clzl (counts[i] - 1); + if (num_bits + this_bits <= MAX_COLLAPSED_BITS) + { + bits[i] = this_bits; + num_bits += this_bits; + } + else + num_bits = MAX_COLLAPSED_BITS + 1; + } + } + + if (ws->sched == GFS_STATIC) + num_ents = team->nthreads; + else + num_ents = (counts[0] - 1) / chunk_size + 1; + if (num_bits <= MAX_COLLAPSED_BITS) + { + elt_sz = sizeof (unsigned long); + shift_sz = ncounts * sizeof (unsigned int); + } + else + { + elt_sz = sizeof (unsigned long) * ncounts; + shift_sz = 0; + } + elt_sz = (elt_sz + 63) & ~63UL; + + doacross = gomp_malloc (sizeof (*doacross) + 63 + num_ents * elt_sz + + shift_sz); + doacross->chunk_size = chunk_size; + doacross->elt_sz = elt_sz; + doacross->ncounts = ncounts; + doacross->flattened = false; + doacross->array = (unsigned char *) + ((((uintptr_t) (doacross + 1)) + 63 + shift_sz) + & ~(uintptr_t) 63); + if (num_bits <= MAX_COLLAPSED_BITS) + { + unsigned int shift_count = 0; + doacross->flattened = true; + for (i = ncounts; i > 0; i--) + { + doacross->shift_counts[i - 1] = shift_count; + shift_count += bits[i - 1]; + } + for (ent = 0; ent < num_ents; ent++) + *(unsigned long *) (doacross->array + ent * elt_sz) = 0; + } + else + for (ent = 0; ent < num_ents; ent++) + memset (doacross->array + ent * elt_sz, '\0', + sizeof (unsigned long) * ncounts); + if (ws->sched == GFS_STATIC && chunk_size == 0) + { + unsigned long q = counts[0] / num_ents; + unsigned long t = counts[0] % num_ents; + doacross->boundary = t * (q + 1); + doacross->q = q; + doacross->t = t; + } + ws->doacross = doacross; +} + +/* DOACROSS POST operation. */ + +void +GOMP_doacross_post (long *counts) +{ + struct gomp_thread *thr = gomp_thread (); + struct gomp_work_share *ws = thr->ts.work_share; + struct gomp_doacross_work_share *doacross = ws->doacross; + unsigned long ent; + unsigned int i; + + if (__builtin_expect (doacross == NULL, 0)) + { + __sync_synchronize (); + return; + } + + if (__builtin_expect (ws->sched == GFS_STATIC, 1)) + ent = thr->ts.team_id; + else + ent = counts[0] / doacross->chunk_size; + unsigned long *array = (unsigned long *) (doacross->array + + ent * doacross->elt_sz); + + if (__builtin_expect (doacross->flattened, 1)) + { + unsigned long flattened + = (unsigned long) counts[0] << doacross->shift_counts[0]; + + for (i = 1; i < doacross->ncounts; i++) + flattened |= (unsigned long) counts[i] + << doacross->shift_counts[i]; + flattened++; + if (flattened == __atomic_load_n (array, MEMMODEL_ACQUIRE)) + __atomic_thread_fence (MEMMODEL_RELEASE); + else + __atomic_store_n (array, flattened, MEMMODEL_RELEASE); + return; + } + + __atomic_thread_fence (MEMMODEL_ACQUIRE); + for (i = doacross->ncounts; i-- > 0; ) + { + if (counts[i] + 1UL != __atomic_load_n (&array[i], MEMMODEL_RELAXED)) + __atomic_store_n (&array[i], counts[i] + 1UL, MEMMODEL_RELEASE); + } +} + +/* DOACROSS WAIT operation. */ + +void +GOMP_doacross_wait (long first, ...) +{ + struct gomp_thread *thr = gomp_thread (); + struct gomp_work_share *ws = thr->ts.work_share; + struct gomp_doacross_work_share *doacross = ws->doacross; + va_list ap; + unsigned long ent; + unsigned int i; + + if (__builtin_expect (doacross == NULL, 0)) + { + __sync_synchronize (); + return; + } + + if (__builtin_expect (ws->sched == GFS_STATIC, 1)) + { + if (ws->chunk_size == 0) + { + if (first < doacross->boundary) + ent = first / (doacross->q + 1); + else + ent = (first - doacross->boundary) / doacross->q + + doacross->t; + } + else + ent = first / ws->chunk_size % thr->ts.team->nthreads; + } + else + ent = first / doacross->chunk_size; + unsigned long *array = (unsigned long *) (doacross->array + + ent * doacross->elt_sz); + + if (__builtin_expect (doacross->flattened, 1)) + { + unsigned long flattened + = (unsigned long) first << doacross->shift_counts[0]; + unsigned long cur; + + va_start (ap, first); + for (i = 1; i < doacross->ncounts; i++) + flattened |= (unsigned long) va_arg (ap, long) + << doacross->shift_counts[i]; + cur = __atomic_load_n (array, MEMMODEL_ACQUIRE); + if (flattened < cur) + { + __atomic_thread_fence (MEMMODEL_RELEASE); + va_end (ap); + return; + } + doacross_spin (array, flattened, cur); + __atomic_thread_fence (MEMMODEL_RELEASE); + va_end (ap); + return; + } + + do + { + va_start (ap, first); + for (i = 0; i < doacross->ncounts; i++) + { + unsigned long thisv + = (unsigned long) (i ? va_arg (ap, long) : first) + 1; + unsigned long cur = __atomic_load_n (&array[i], MEMMODEL_RELAXED); + if (thisv < cur) + { + i = doacross->ncounts; + break; + } + if (thisv > cur) + break; + } + va_end (ap); + if (i == doacross->ncounts) + break; + cpu_relax (); + } + while (1); + __sync_synchronize (); +} + +typedef unsigned long long gomp_ull; + +void +gomp_doacross_ull_init (unsigned ncounts, gomp_ull *counts, gomp_ull chunk_size) +{ + struct gomp_thread *thr = gomp_thread (); + struct gomp_team *team = thr->ts.team; + struct gomp_work_share *ws = thr->ts.work_share; + unsigned int i, bits[MAX_COLLAPSED_BITS], num_bits = 0; + unsigned long ent, num_ents, elt_sz, shift_sz; + struct gomp_doacross_work_share *doacross; + + if (team == NULL || team->nthreads == 1) + return; + + for (i = 0; i < ncounts; i++) + { + /* If any count is 0, GOMP_doacross_{post,wait} can't be called. */ + if (counts[i] == 0) + return; + + if (num_bits <= MAX_COLLAPSED_BITS) + { + unsigned int this_bits; + if (counts[i] == 1) + this_bits = 1; + else + this_bits = __SIZEOF_LONG_LONG__ * __CHAR_BIT__ + - __builtin_clzll (counts[i] - 1); + if (num_bits + this_bits <= MAX_COLLAPSED_BITS) + { + bits[i] = this_bits; + num_bits += this_bits; + } + else + num_bits = MAX_COLLAPSED_BITS + 1; + } + } + + if (ws->sched == GFS_STATIC) + num_ents = team->nthreads; + else + num_ents = (counts[0] - 1) / chunk_size + 1; + if (num_bits <= MAX_COLLAPSED_BITS) + { + elt_sz = sizeof (unsigned long); + shift_sz = ncounts * sizeof (unsigned int); + } + else + { + if (sizeof (gomp_ull) == sizeof (unsigned long)) + elt_sz = sizeof (gomp_ull) * ncounts; + else if (sizeof (gomp_ull) == 2 * sizeof (unsigned long)) + elt_sz = sizeof (unsigned long) * 2 * ncounts; + else + abort (); + shift_sz = 0; + } + elt_sz = (elt_sz + 63) & ~63UL; + + doacross = gomp_malloc (sizeof (*doacross) + 63 + num_ents * elt_sz + + shift_sz); + doacross->chunk_size_ull = chunk_size; + doacross->elt_sz = elt_sz; + doacross->ncounts = ncounts; + doacross->flattened = false; + doacross->boundary = 0; + doacross->array = (unsigned char *) + ((((uintptr_t) (doacross + 1)) + 63 + shift_sz) + & ~(uintptr_t) 63); + if (num_bits <= MAX_COLLAPSED_BITS) + { + unsigned int shift_count = 0; + doacross->flattened = true; + for (i = ncounts; i > 0; i--) + { + doacross->shift_counts[i - 1] = shift_count; + shift_count += bits[i - 1]; + } + for (ent = 0; ent < num_ents; ent++) + *(unsigned long *) (doacross->array + ent * elt_sz) = 0; + } + else + for (ent = 0; ent < num_ents; ent++) + memset (doacross->array + ent * elt_sz, '\0', + sizeof (unsigned long) * ncounts); + if (ws->sched == GFS_STATIC && chunk_size == 0) + { + gomp_ull q = counts[0] / num_ents; + gomp_ull t = counts[0] % num_ents; + doacross->boundary_ull = t * (q + 1); + doacross->q_ull = q; + doacross->t = t; + } + ws->doacross = doacross; +} + +/* DOACROSS POST operation. */ + +void +GOMP_doacross_ull_post (gomp_ull *counts) +{ + struct gomp_thread *thr = gomp_thread (); + struct gomp_work_share *ws = thr->ts.work_share; + struct gomp_doacross_work_share *doacross = ws->doacross; + unsigned long ent; + unsigned int i; + + if (__builtin_expect (doacross == NULL, 0)) + { + __sync_synchronize (); + return; + } + + if (__builtin_expect (ws->sched == GFS_STATIC, 1)) + ent = thr->ts.team_id; + else + ent = counts[0] / doacross->chunk_size_ull; + + if (__builtin_expect (doacross->flattened, 1)) + { + unsigned long *array = (unsigned long *) (doacross->array + + ent * doacross->elt_sz); + gomp_ull flattened + = counts[0] << doacross->shift_counts[0]; + + for (i = 1; i < doacross->ncounts; i++) + flattened |= counts[i] << doacross->shift_counts[i]; + flattened++; + if (flattened == __atomic_load_n (array, MEMMODEL_ACQUIRE)) + __atomic_thread_fence (MEMMODEL_RELEASE); + else + __atomic_store_n (array, flattened, MEMMODEL_RELEASE); + return; + } + + __atomic_thread_fence (MEMMODEL_ACQUIRE); + if (sizeof (gomp_ull) == sizeof (unsigned long)) + { + gomp_ull *array = (gomp_ull *) (doacross->array + + ent * doacross->elt_sz); + + for (i = doacross->ncounts; i-- > 0; ) + { + if (counts[i] + 1UL != __atomic_load_n (&array[i], MEMMODEL_RELAXED)) + __atomic_store_n (&array[i], counts[i] + 1UL, MEMMODEL_RELEASE); + } + } + else + { + unsigned long *array = (unsigned long *) (doacross->array + + ent * doacross->elt_sz); + + for (i = doacross->ncounts; i-- > 0; ) + { + gomp_ull cull = counts[i] + 1UL; + unsigned long c = (unsigned long) cull; + if (c != __atomic_load_n (&array[2 * i + 1], MEMMODEL_RELAXED)) + __atomic_store_n (&array[2 * i + 1], c, MEMMODEL_RELEASE); + c = cull >> (__SIZEOF_LONG_LONG__ * __CHAR_BIT__ / 2); + if (c != __atomic_load_n (&array[2 * i], MEMMODEL_RELAXED)) + __atomic_store_n (&array[2 * i], c, MEMMODEL_RELEASE); + } + } +} + +/* DOACROSS WAIT operation. */ + +void +GOMP_doacross_ull_wait (gomp_ull first, ...) +{ + struct gomp_thread *thr = gomp_thread (); + struct gomp_work_share *ws = thr->ts.work_share; + struct gomp_doacross_work_share *doacross = ws->doacross; + va_list ap; + unsigned long ent; + unsigned int i; + + if (__builtin_expect (doacross == NULL, 0)) + { + __sync_synchronize (); + return; + } + + if (__builtin_expect (ws->sched == GFS_STATIC, 1)) + { + if (ws->chunk_size_ull == 0) + { + if (first < doacross->boundary_ull) + ent = first / (doacross->q_ull + 1); + else + ent = (first - doacross->boundary_ull) / doacross->q_ull + + doacross->t; + } + else + ent = first / ws->chunk_size_ull % thr->ts.team->nthreads; + } + else + ent = first / doacross->chunk_size_ull; + + if (__builtin_expect (doacross->flattened, 1)) + { + unsigned long *array = (unsigned long *) (doacross->array + + ent * doacross->elt_sz); + gomp_ull flattened = first << doacross->shift_counts[0]; + unsigned long cur; + + va_start (ap, first); + for (i = 1; i < doacross->ncounts; i++) + flattened |= va_arg (ap, gomp_ull) + << doacross->shift_counts[i]; + cur = __atomic_load_n (array, MEMMODEL_ACQUIRE); + if (flattened < cur) + { + __atomic_thread_fence (MEMMODEL_RELEASE); + va_end (ap); + return; + } + doacross_spin (array, flattened, cur); + __atomic_thread_fence (MEMMODEL_RELEASE); + va_end (ap); + return; + } + + if (sizeof (gomp_ull) == sizeof (unsigned long)) + { + gomp_ull *array = (gomp_ull *) (doacross->array + + ent * doacross->elt_sz); + do + { + va_start (ap, first); + for (i = 0; i < doacross->ncounts; i++) + { + gomp_ull thisv + = (i ? va_arg (ap, gomp_ull) : first) + 1; + gomp_ull cur = __atomic_load_n (&array[i], MEMMODEL_RELAXED); + if (thisv < cur) + { + i = doacross->ncounts; + break; + } + if (thisv > cur) + break; + } + va_end (ap); + if (i == doacross->ncounts) + break; + cpu_relax (); + } + while (1); + } + else + { + unsigned long *array = (unsigned long *) (doacross->array + + ent * doacross->elt_sz); + do + { + va_start (ap, first); + for (i = 0; i < doacross->ncounts; i++) + { + gomp_ull thisv + = (i ? va_arg (ap, gomp_ull) : first) + 1; + unsigned long t + = thisv >> (__SIZEOF_LONG_LONG__ * __CHAR_BIT__ / 2); + unsigned long cur + = __atomic_load_n (&array[2 * i], MEMMODEL_RELAXED); + if (t < cur) + { + i = doacross->ncounts; + break; + } + if (t > cur) + break; + t = thisv; + cur = __atomic_load_n (&array[2 * i + 1], MEMMODEL_RELAXED); + if (t < cur) + { + i = doacross->ncounts; + break; + } + if (t > cur) + break; + } + va_end (ap); + if (i == doacross->ncounts) + break; + cpu_relax (); + } + while (1); + } + __sync_synchronize (); +} diff --git a/libgomp/target.c b/libgomp/target.c index 758ece5d78c..de6a2c9c9c5 100644 --- a/libgomp/target.c +++ b/libgomp/target.c @@ -38,6 +38,7 @@ #endif #include #include +#include #ifdef PLUGIN_SUPPORT #include @@ -133,17 +134,48 @@ resolve_device (int device_id) if (device_id < 0 || device_id >= gomp_get_num_devices ()) return NULL; + gomp_mutex_lock (&devices[device_id].lock); + if (!devices[device_id].is_initialized) + gomp_init_device (&devices[device_id]); + gomp_mutex_unlock (&devices[device_id].lock); + return &devices[device_id]; } -/* Handle the case where splay_tree_lookup found oldn for newn. +static inline splay_tree_key +gomp_map_lookup (splay_tree mem_map, splay_tree_key key) +{ + if (key->host_start != key->host_end) + return splay_tree_lookup (mem_map, key); + + key->host_end++; + splay_tree_key n = splay_tree_lookup (mem_map, key); + key->host_end--; + if (n) + return n; + key->host_start--; + n = splay_tree_lookup (mem_map, key); + key->host_start++; + if (n) + return n; + return splay_tree_lookup (mem_map, key); +} + +/* Handle the case where gomp_map_lookup found oldn for newn. Helper function of gomp_map_vars. */ static inline void gomp_map_vars_existing (struct gomp_device_descr *devicep, splay_tree_key oldn, - splay_tree_key newn, unsigned char kind) + splay_tree_key newn, struct target_var_desc *tgt_var, + unsigned char kind) { + tgt_var->key = oldn; + tgt_var->copy_from = GOMP_MAP_COPY_FROM_P (kind); + tgt_var->always_copy_from = GOMP_MAP_ALWAYS_FROM_P (kind); + tgt_var->offset = newn->host_start - oldn->host_start; + tgt_var->length = newn->host_end - newn->host_start; + if ((kind & GOMP_MAP_FLAG_FORCE) || oldn->host_start > newn->host_start || oldn->host_end < newn->host_end) @@ -154,14 +186,22 @@ gomp_map_vars_existing (struct gomp_device_descr *devicep, splay_tree_key oldn, (void *) newn->host_start, (void *) newn->host_end, (void *) oldn->host_start, (void *) oldn->host_end); } - oldn->refcount++; + + if (GOMP_MAP_ALWAYS_TO_P (kind)) + devicep->host2dev_func (devicep->target_id, + (void *) (oldn->tgt->tgt_start + oldn->tgt_offset + + newn->host_start - oldn->host_start), + (void *) newn->host_start, + newn->host_end - newn->host_start); + if (oldn->refcount != REFCOUNT_INFINITY) + oldn->refcount++; } static int -get_kind (bool is_openacc, void *kinds, int idx) +get_kind (bool short_mapkind, void *kinds, int idx) { - return is_openacc ? ((unsigned short *) kinds)[idx] - : ((unsigned char *) kinds)[idx]; + return short_mapkind ? ((unsigned short *) kinds)[idx] + : ((unsigned char *) kinds)[idx]; } static void @@ -185,20 +225,8 @@ gomp_map_pointer (struct target_mem_desc *tgt, uintptr_t host_ptr, } /* Add bias to the pointer value. */ cur_node.host_start += bias; - cur_node.host_end = cur_node.host_start + 1; - splay_tree_key n = splay_tree_lookup (mem_map, &cur_node); - if (n == NULL) - { - /* Could be possibly zero size array section. */ - cur_node.host_end--; - n = splay_tree_lookup (mem_map, &cur_node); - if (n == NULL) - { - cur_node.host_start--; - n = splay_tree_lookup (mem_map, &cur_node); - cur_node.host_start++; - } - } + cur_node.host_end = cur_node.host_start; + splay_tree_key n = gomp_map_lookup (mem_map, &cur_node); if (n == NULL) { gomp_mutex_unlock (&devicep->lock); @@ -218,20 +246,81 @@ gomp_map_pointer (struct target_mem_desc *tgt, uintptr_t host_ptr, sizeof (void *)); } +static void +gomp_map_fields_existing (struct target_mem_desc *tgt, splay_tree_key n, + size_t first, size_t i, void **hostaddrs, + size_t *sizes, void *kinds) +{ + struct gomp_device_descr *devicep = tgt->device_descr; + struct splay_tree_s *mem_map = &devicep->mem_map; + struct splay_tree_key_s cur_node; + int kind; + const bool short_mapkind = true; + const int typemask = short_mapkind ? 0xff : 0x7; + + cur_node.host_start = (uintptr_t) hostaddrs[i]; + cur_node.host_end = cur_node.host_start + sizes[i]; + splay_tree_key n2 = splay_tree_lookup (mem_map, &cur_node); + kind = get_kind (short_mapkind, kinds, i); + if (n2 + && n2->tgt == n->tgt + && n2->host_start - n->host_start == n2->tgt_offset - n->tgt_offset) + { + gomp_map_vars_existing (devicep, n2, &cur_node, + &tgt->list[i], kind & typemask); + return; + } + if (sizes[i] == 0) + { + if (cur_node.host_start > (uintptr_t) hostaddrs[first - 1]) + { + cur_node.host_start--; + n2 = splay_tree_lookup (mem_map, &cur_node); + cur_node.host_start++; + if (n2 + && n2->tgt == n->tgt + && n2->host_start - n->host_start + == n2->tgt_offset - n->tgt_offset) + { + gomp_map_vars_existing (devicep, n2, &cur_node, &tgt->list[i], + kind & typemask); + return; + } + } + cur_node.host_end++; + n2 = splay_tree_lookup (mem_map, &cur_node); + cur_node.host_end--; + if (n2 + && n2->tgt == n->tgt + && n2->host_start - n->host_start == n2->tgt_offset - n->tgt_offset) + { + gomp_map_vars_existing (devicep, n2, &cur_node, &tgt->list[i], + kind & typemask); + return; + } + } + gomp_mutex_unlock (&devicep->lock); + gomp_fatal ("Trying to map into device [%p..%p) structure element when " + "other mapped elements from the same structure weren't mapped " + "together with it", (void *) cur_node.host_start, + (void *) cur_node.host_end); +} + attribute_hidden struct target_mem_desc * gomp_map_vars (struct gomp_device_descr *devicep, size_t mapnum, void **hostaddrs, void **devaddrs, size_t *sizes, void *kinds, - bool is_openacc, bool is_target) + bool short_mapkind, enum gomp_map_vars_kind pragma_kind) { size_t i, tgt_align, tgt_size, not_found_cnt = 0; - const int rshift = is_openacc ? 8 : 3; - const int typemask = is_openacc ? 0xff : 0x7; + bool has_firstprivate = false; + const int rshift = short_mapkind ? 8 : 3; + const int typemask = short_mapkind ? 0xff : 0x7; struct splay_tree_s *mem_map = &devicep->mem_map; struct splay_tree_key_s cur_node; struct target_mem_desc *tgt = gomp_malloc (sizeof (*tgt) + sizeof (tgt->list[0]) * mapnum); tgt->list_count = mapnum; - tgt->refcount = 1; + tgt->refcount = pragma_kind == GOMP_MAP_VARS_ENTER_DATA ? 0 : 1; tgt->device_descr = devicep; if (mapnum == 0) @@ -239,7 +328,7 @@ gomp_map_vars (struct gomp_device_descr *devicep, size_t mapnum, tgt_align = sizeof (void *); tgt_size = 0; - if (is_target) + if (pragma_kind == GOMP_MAP_VARS_TARGET) { size_t align = 4 * sizeof (void *); tgt_align = align; @@ -250,10 +339,61 @@ gomp_map_vars (struct gomp_device_descr *devicep, size_t mapnum, for (i = 0; i < mapnum; i++) { - int kind = get_kind (is_openacc, kinds, i); - if (hostaddrs[i] == NULL) + int kind = get_kind (short_mapkind, kinds, i); + if (hostaddrs[i] == NULL + || (kind & typemask) == GOMP_MAP_FIRSTPRIVATE_INT) { - tgt->list[i] = NULL; + tgt->list[i].key = NULL; + tgt->list[i].offset = ~(uintptr_t) 0; + continue; + } + else if ((kind & typemask) == GOMP_MAP_USE_DEVICE_PTR) + { + cur_node.host_start = (uintptr_t) hostaddrs[i]; + cur_node.host_end = cur_node.host_start; + splay_tree_key n = gomp_map_lookup (mem_map, &cur_node); + if (n == NULL) + { + gomp_mutex_unlock (&devicep->lock); + gomp_fatal ("use_device_ptr pointer wasn't mapped"); + } + cur_node.host_start -= n->host_start; + hostaddrs[i] + = (void *) (n->tgt->tgt_start + n->tgt_offset + + cur_node.host_start); + tgt->list[i].key = NULL; + tgt->list[i].offset = ~(uintptr_t) 0; + continue; + } + else if ((kind & typemask) == GOMP_MAP_STRUCT) + { + size_t first = i + 1; + size_t last = i + sizes[i]; + cur_node.host_start = (uintptr_t) hostaddrs[i]; + cur_node.host_end = (uintptr_t) hostaddrs[last] + + sizes[last]; + tgt->list[i].key = NULL; + tgt->list[i].offset = ~(uintptr_t) 2; + splay_tree_key n = splay_tree_lookup (mem_map, &cur_node); + if (n == NULL) + { + size_t align = (size_t) 1 << (kind >> rshift); + if (tgt_align < align) + tgt_align = align; + tgt_size -= (uintptr_t) hostaddrs[first] + - (uintptr_t) hostaddrs[i]; + tgt_size = (tgt_size + align - 1) & ~(align - 1); + tgt_size += cur_node.host_end - (uintptr_t) hostaddrs[i]; + not_found_cnt += last - i; + for (i = first; i <= last; i++) + tgt->list[i].key = NULL; + i--; + continue; + } + for (i = first; i <= last; i++) + gomp_map_fields_existing (tgt, n, first, i, hostaddrs, + sizes, kinds); + i--; continue; } cur_node.host_start = (uintptr_t) hostaddrs[i]; @@ -261,15 +401,37 @@ gomp_map_vars (struct gomp_device_descr *devicep, size_t mapnum, cur_node.host_end = cur_node.host_start + sizes[i]; else cur_node.host_end = cur_node.host_start + sizeof (void *); - splay_tree_key n = splay_tree_lookup (mem_map, &cur_node); - if (n) + if ((kind & typemask) == GOMP_MAP_FIRSTPRIVATE) + { + tgt->list[i].key = NULL; + + size_t align = (size_t) 1 << (kind >> rshift); + if (tgt_align < align) + tgt_align = align; + tgt_size = (tgt_size + align - 1) & ~(align - 1); + tgt_size += cur_node.host_end - cur_node.host_start; + has_firstprivate = true; + continue; + } + splay_tree_key n; + if ((kind & typemask) == GOMP_MAP_ZERO_LEN_ARRAY_SECTION) { - tgt->list[i] = n; - gomp_map_vars_existing (devicep, n, &cur_node, kind & typemask); + n = gomp_map_lookup (mem_map, &cur_node); + if (!n) + { + tgt->list[i].key = NULL; + tgt->list[i].offset = ~(uintptr_t) 1; + continue; + } } + else + n = splay_tree_lookup (mem_map, &cur_node); + if (n) + gomp_map_vars_existing (devicep, n, &cur_node, &tgt->list[i], + kind & typemask); else { - tgt->list[i] = NULL; + tgt->list[i].key = NULL; size_t align = (size_t) 1 << (kind >> rshift); not_found_cnt++; @@ -281,7 +443,7 @@ gomp_map_vars (struct gomp_device_descr *devicep, size_t mapnum, { size_t j; for (j = i + 1; j < mapnum; j++) - if (!GOMP_MAP_POINTER_P (get_kind (is_openacc, kinds, j) + if (!GOMP_MAP_POINTER_P (get_kind (short_mapkind, kinds, j) & typemask)) break; else if ((uintptr_t) hostaddrs[j] < cur_node.host_start @@ -290,7 +452,7 @@ gomp_map_vars (struct gomp_device_descr *devicep, size_t mapnum, break; else { - tgt->list[j] = NULL; + tgt->list[j].key = NULL; i++; } } @@ -308,7 +470,7 @@ gomp_map_vars (struct gomp_device_descr *devicep, size_t mapnum, tgt->tgt_start = (uintptr_t) tgt->to_free; tgt->tgt_end = tgt->tgt_start + sizes[0]; } - else if (not_found_cnt || is_target) + else if (not_found_cnt || pragma_kind == GOMP_MAP_VARS_TARGET) { /* Allocate tgt_align aligned tgt_size block of memory. */ /* FIXME: Perhaps change interface to allocate properly aligned @@ -327,22 +489,74 @@ gomp_map_vars (struct gomp_device_descr *devicep, size_t mapnum, } tgt_size = 0; - if (is_target) + if (pragma_kind == GOMP_MAP_VARS_TARGET) tgt_size = mapnum * sizeof (void *); tgt->array = NULL; - if (not_found_cnt) + if (not_found_cnt || has_firstprivate) { - tgt->array = gomp_malloc (not_found_cnt * sizeof (*tgt->array)); + if (not_found_cnt) + tgt->array = gomp_malloc (not_found_cnt * sizeof (*tgt->array)); splay_tree_node array = tgt->array; - size_t j; + size_t j, field_tgt_offset = 0, field_tgt_clear = ~(size_t) 0; + uintptr_t field_tgt_base = 0; for (i = 0; i < mapnum; i++) - if (tgt->list[i] == NULL) + if (tgt->list[i].key == NULL) { - int kind = get_kind (is_openacc, kinds, i); + int kind = get_kind (short_mapkind, kinds, i); if (hostaddrs[i] == NULL) continue; + switch (kind & typemask) + { + size_t align, len, first, last; + splay_tree_key n; + case GOMP_MAP_FIRSTPRIVATE: + align = (size_t) 1 << (kind >> rshift); + tgt_size = (tgt_size + align - 1) & ~(align - 1); + tgt->list[i].offset = tgt_size; + len = sizes[i]; + devicep->host2dev_func (devicep->target_id, + (void *) (tgt->tgt_start + tgt_size), + (void *) hostaddrs[i], len); + tgt_size += len; + continue; + case GOMP_MAP_FIRSTPRIVATE_INT: + case GOMP_MAP_USE_DEVICE_PTR: + case GOMP_MAP_ZERO_LEN_ARRAY_SECTION: + continue; + case GOMP_MAP_STRUCT: + first = i + 1; + last = i + sizes[i]; + cur_node.host_start = (uintptr_t) hostaddrs[i]; + cur_node.host_end = (uintptr_t) hostaddrs[last] + + sizes[last]; + if (tgt->list[first].key != NULL) + continue; + n = splay_tree_lookup (mem_map, &cur_node); + if (n == NULL) + { + size_t align = (size_t) 1 << (kind >> rshift); + tgt_size -= (uintptr_t) hostaddrs[first] + - (uintptr_t) hostaddrs[i]; + tgt_size = (tgt_size + align - 1) & ~(align - 1); + tgt_size += (uintptr_t) hostaddrs[first] + - (uintptr_t) hostaddrs[i]; + field_tgt_base = (uintptr_t) hostaddrs[first]; + field_tgt_offset = tgt_size; + field_tgt_clear = last; + tgt_size += cur_node.host_end + - (uintptr_t) hostaddrs[first]; + continue; + } + for (i = first; i <= last; i++) + gomp_map_fields_existing (tgt, n, first, i, hostaddrs, + sizes, kinds); + i--; + continue; + default: + break; + } splay_tree_key k = &array->key; k->host_start = (uintptr_t) hostaddrs[i]; if (!GOMP_MAP_POINTER_P (kind & typemask)) @@ -351,19 +565,31 @@ gomp_map_vars (struct gomp_device_descr *devicep, size_t mapnum, k->host_end = k->host_start + sizeof (void *); splay_tree_key n = splay_tree_lookup (mem_map, k); if (n) - { - tgt->list[i] = n; - gomp_map_vars_existing (devicep, n, k, kind & typemask); - } + gomp_map_vars_existing (devicep, n, k, &tgt->list[i], + kind & typemask); else { size_t align = (size_t) 1 << (kind >> rshift); - tgt->list[i] = k; - tgt_size = (tgt_size + align - 1) & ~(align - 1); + tgt->list[i].key = k; k->tgt = tgt; - k->tgt_offset = tgt_size; - tgt_size += k->host_end - k->host_start; - k->copy_from = GOMP_MAP_COPY_FROM_P (kind & typemask); + if (field_tgt_clear != ~(size_t) 0) + { + k->tgt_offset = k->host_start - field_tgt_base + + field_tgt_offset; + if (i == field_tgt_clear) + field_tgt_clear = ~(size_t) 0; + } + else + { + tgt_size = (tgt_size + align - 1) & ~(align - 1); + k->tgt_offset = tgt_size; + tgt_size += k->host_end - k->host_start; + } + tgt->list[i].copy_from = GOMP_MAP_COPY_FROM_P (kind & typemask); + tgt->list[i].always_copy_from + = GOMP_MAP_ALWAYS_FROM_P (kind & typemask); + tgt->list[i].offset = 0; + tgt->list[i].length = k->host_end - k->host_start; k->refcount = 1; k->async_refcount = 0; tgt->refcount++; @@ -376,11 +602,14 @@ gomp_map_vars (struct gomp_device_descr *devicep, size_t mapnum, case GOMP_MAP_FROM: case GOMP_MAP_FORCE_ALLOC: case GOMP_MAP_FORCE_FROM: + case GOMP_MAP_ALWAYS_FROM: break; case GOMP_MAP_TO: case GOMP_MAP_TOFROM: case GOMP_MAP_FORCE_TO: case GOMP_MAP_FORCE_TOFROM: + case GOMP_MAP_ALWAYS_TO: + case GOMP_MAP_ALWAYS_TOFROM: /* FIXME: Perhaps add some smarts, like if copying several adjacent fields from host to target, use some host buffer to avoid sending each var individually. */ @@ -403,7 +632,8 @@ gomp_map_vars (struct gomp_device_descr *devicep, size_t mapnum, k->host_end - k->host_start); for (j = i + 1; j < mapnum; j++) - if (!GOMP_MAP_POINTER_P (get_kind (is_openacc, kinds, j) + if (!GOMP_MAP_POINTER_P (get_kind (short_mapkind, kinds, + j) & typemask)) break; else if ((uintptr_t) hostaddrs[j] < k->host_start @@ -412,8 +642,11 @@ gomp_map_vars (struct gomp_device_descr *devicep, size_t mapnum, break; else { - tgt->list[j] = k; - k->refcount++; + tgt->list[j].key = k; + tgt->list[j].copy_from = false; + tgt->list[j].always_copy_from = false; + if (k->refcount != REFCOUNT_INFINITY) + k->refcount++; gomp_map_pointer (tgt, (uintptr_t) *(void **) hostaddrs[j], k->tgt_offset @@ -460,15 +693,30 @@ gomp_map_vars (struct gomp_device_descr *devicep, size_t mapnum, } } - if (is_target) + if (pragma_kind == GOMP_MAP_VARS_TARGET) { for (i = 0; i < mapnum; i++) { - if (tgt->list[i] == NULL) - cur_node.tgt_offset = (uintptr_t) NULL; + if (tgt->list[i].key == NULL) + { + if (tgt->list[i].offset == ~(uintptr_t) 0) + cur_node.tgt_offset = (uintptr_t) hostaddrs[i]; + else if (tgt->list[i].offset == ~(uintptr_t) 1) + cur_node.tgt_offset = 0; + else if (tgt->list[i].offset == ~(uintptr_t) 2) + cur_node.tgt_offset = tgt->list[i + 1].key->tgt->tgt_start + + tgt->list[i + 1].key->tgt_offset + + tgt->list[i + 1].offset + + (uintptr_t) hostaddrs[i] + - (uintptr_t) hostaddrs[i + 1]; + else + cur_node.tgt_offset = tgt->tgt_start + + tgt->list[i].offset; + } else - cur_node.tgt_offset = tgt->list[i]->tgt->tgt_start - + tgt->list[i]->tgt_offset; + cur_node.tgt_offset = tgt->list[i].key->tgt->tgt_start + + tgt->list[i].key->tgt_offset + + tgt->list[i].offset; /* FIXME: see above FIXME comment. */ devicep->host2dev_func (devicep->target_id, (void *) (tgt->tgt_start @@ -478,6 +726,15 @@ gomp_map_vars (struct gomp_device_descr *devicep, size_t mapnum, } } + /* If the variable from "omp target enter data" map-list was already mapped, + tgt is not needed. Otherwise tgt will be freed by gomp_unmap_vars or + gomp_exit_data. */ + if (pragma_kind == GOMP_MAP_VARS_ENTER_DATA && tgt->refcount == 0) + { + free (tgt); + tgt = NULL; + } + gomp_mutex_unlock (&devicep->lock); return tgt; } @@ -508,17 +765,17 @@ gomp_copy_from_async (struct target_mem_desc *tgt) gomp_mutex_lock (&devicep->lock); for (i = 0; i < tgt->list_count; i++) - if (tgt->list[i] == NULL) + if (tgt->list[i].key == NULL) ; - else if (tgt->list[i]->refcount > 1) + else if (tgt->list[i].key->refcount > 1) { - tgt->list[i]->refcount--; - tgt->list[i]->async_refcount++; + tgt->list[i].key->refcount--; + tgt->list[i].key->async_refcount++; } else { - splay_tree_key k = tgt->list[i]; - if (k->copy_from) + splay_tree_key k = tgt->list[i].key; + if (tgt->list[i].copy_from) devicep->dev2host_func (devicep->target_id, (void *) k->host_start, (void *) (k->tgt->tgt_start + k->tgt_offset), k->host_end - k->host_start); @@ -546,25 +803,41 @@ gomp_unmap_vars (struct target_mem_desc *tgt, bool do_copyfrom) size_t i; for (i = 0; i < tgt->list_count; i++) - if (tgt->list[i] == NULL) - ; - else if (tgt->list[i]->refcount > 1) - tgt->list[i]->refcount--; - else if (tgt->list[i]->async_refcount > 0) - tgt->list[i]->async_refcount--; - else - { - splay_tree_key k = tgt->list[i]; - if (k->copy_from && do_copyfrom) - devicep->dev2host_func (devicep->target_id, (void *) k->host_start, - (void *) (k->tgt->tgt_start + k->tgt_offset), - k->host_end - k->host_start); - splay_tree_remove (&devicep->mem_map, k); - if (k->tgt->refcount > 1) - k->tgt->refcount--; - else - gomp_unmap_tgt (k->tgt); - } + { + splay_tree_key k = tgt->list[i].key; + if (k == NULL) + continue; + + bool do_unmap = false; + if (k->refcount > 1 && k->refcount != REFCOUNT_INFINITY) + k->refcount--; + else if (k->refcount == 1) + { + if (k->async_refcount > 0) + k->async_refcount--; + else + { + k->refcount--; + do_unmap = true; + } + } + + if ((do_unmap && do_copyfrom && tgt->list[i].copy_from) + || tgt->list[i].always_copy_from) + devicep->dev2host_func (devicep->target_id, + (void *) (k->host_start + tgt->list[i].offset), + (void *) (k->tgt->tgt_start + k->tgt_offset + + tgt->list[i].offset), + tgt->list[i].length); + if (do_unmap) + { + splay_tree_remove (&devicep->mem_map, k); + if (k->tgt->refcount > 1) + k->tgt->refcount--; + else + gomp_unmap_tgt (k->tgt); + } + } if (tgt->refcount > 1) tgt->refcount--; @@ -576,11 +849,11 @@ gomp_unmap_vars (struct target_mem_desc *tgt, bool do_copyfrom) static void gomp_update (struct gomp_device_descr *devicep, size_t mapnum, void **hostaddrs, - size_t *sizes, void *kinds, bool is_openacc) + size_t *sizes, void *kinds, bool short_mapkind) { size_t i; struct splay_tree_key_s cur_node; - const int typemask = is_openacc ? 0xff : 0x7; + const int typemask = short_mapkind ? 0xff : 0x7; if (!devicep) return; @@ -597,7 +870,7 @@ gomp_update (struct gomp_device_descr *devicep, size_t mapnum, void **hostaddrs, splay_tree_key n = splay_tree_lookup (&devicep->mem_map, &cur_node); if (n) { - int kind = get_kind (is_openacc, kinds, i); + int kind = get_kind (short_mapkind, kinds, i); if (n->host_start > cur_node.host_start || n->host_end < cur_node.host_end) { @@ -626,13 +899,6 @@ gomp_update (struct gomp_device_descr *devicep, size_t mapnum, void **hostaddrs, - n->host_start), cur_node.host_end - cur_node.host_start); } - else - { - gomp_mutex_unlock (&devicep->lock); - gomp_fatal ("Trying to update [%p..%p) object that is not mapped", - (void *) cur_node.host_start, - (void *) cur_node.host_end); - } } gomp_mutex_unlock (&devicep->lock); } @@ -678,7 +944,7 @@ gomp_load_image_to_device (struct gomp_device_descr *devicep, unsigned version, /* Insert host-target address mapping into splay tree. */ struct target_mem_desc *tgt = gomp_malloc (sizeof (*tgt)); tgt->array = gomp_malloc ((num_funcs + num_vars) * sizeof (*tgt->array)); - tgt->refcount = 1; + tgt->refcount = REFCOUNT_INFINITY; tgt->tgt_start = 0; tgt->tgt_end = 0; tgt->to_free = NULL; @@ -694,9 +960,8 @@ gomp_load_image_to_device (struct gomp_device_descr *devicep, unsigned version, k->host_end = k->host_start + 1; k->tgt = tgt; k->tgt_offset = target_table[i].start; - k->refcount = 1; + k->refcount = REFCOUNT_INFINITY; k->async_refcount = 0; - k->copy_from = false; array->left = NULL; array->right = NULL; splay_tree_insert (&devicep->mem_map, array); @@ -720,9 +985,8 @@ gomp_load_image_to_device (struct gomp_device_descr *devicep, unsigned version, k->host_end = k->host_start + (uintptr_t) host_var_table[i * 2 + 1]; k->tgt = tgt; k->tgt_offset = target_var->start; - k->refcount = 1; + k->refcount = REFCOUNT_INFINITY; k->async_refcount = 0; - k->copy_from = false; array->left = NULL; array->right = NULL; splay_tree_insert (&devicep->mem_map, array); @@ -945,6 +1209,47 @@ gomp_fini_device (struct gomp_device_descr *devicep) devicep->is_initialized = false; } +/* Host fallback for GOMP_target{,_41} routines. */ + +static void +gomp_target_fallback (void (*fn) (void *), void **hostaddrs) +{ + struct gomp_thread old_thr, *thr = gomp_thread (); + old_thr = *thr; + memset (thr, '\0', sizeof (*thr)); + if (gomp_places_list) + { + thr->place = old_thr.place; + thr->ts.place_partition_len = gomp_places_list_len; + } + fn (hostaddrs); + gomp_free_thread (thr); + *thr = old_thr; +} + +/* Helper function of GOMP_target{,_41} routines. */ + +static void * +gomp_get_target_fn_addr (struct gomp_device_descr *devicep, + void (*host_fn) (void *)) +{ + if (devicep->capabilities & GOMP_OFFLOAD_CAP_NATIVE_EXEC) + return (void *) host_fn; + else + { + gomp_mutex_lock (&devicep->lock); + struct splay_tree_key_s k; + k.host_start = (uintptr_t) host_fn; + k.host_end = k.host_start + 1; + splay_tree_key tgt_fn = splay_tree_lookup (&devicep->mem_map, &k); + gomp_mutex_unlock (&devicep->lock); + if (tgt_fn == NULL) + gomp_fatal ("Target function wasn't mapped"); + + return (void *) tgt_fn->tgt_offset; + } +} + /* Called when encountering a target directive. If DEVICE is GOMP_DEVICE_ICV, it means use device-var ICV. If it is GOMP_DEVICE_HOST_FALLBACK (or any value @@ -964,51 +1269,85 @@ GOMP_target (int device, void (*fn) (void *), const void *unused, if (devicep == NULL || !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)) + return gomp_target_fallback (fn, hostaddrs); + + void *fn_addr = gomp_get_target_fn_addr (devicep, fn); + + struct target_mem_desc *tgt_vars + = gomp_map_vars (devicep, mapnum, hostaddrs, NULL, sizes, kinds, false, + GOMP_MAP_VARS_TARGET); + struct gomp_thread old_thr, *thr = gomp_thread (); + old_thr = *thr; + memset (thr, '\0', sizeof (*thr)); + if (gomp_places_list) { - /* Host fallback. */ - struct gomp_thread old_thr, *thr = gomp_thread (); - old_thr = *thr; - memset (thr, '\0', sizeof (*thr)); - if (gomp_places_list) - { - thr->place = old_thr.place; - thr->ts.place_partition_len = gomp_places_list_len; - } - fn (hostaddrs); - gomp_free_thread (thr); - *thr = old_thr; - return; + thr->place = old_thr.place; + thr->ts.place_partition_len = gomp_places_list_len; } + devicep->run_func (devicep->target_id, fn_addr, (void *) tgt_vars->tgt_start); + gomp_free_thread (thr); + *thr = old_thr; + gomp_unmap_vars (tgt_vars, true); +} - gomp_mutex_lock (&devicep->lock); - if (!devicep->is_initialized) - gomp_init_device (devicep); - gomp_mutex_unlock (&devicep->lock); +void +GOMP_target_41 (int device, void (*fn) (void *), size_t mapnum, + void **hostaddrs, size_t *sizes, unsigned short *kinds, + unsigned int flags, void **depend) +{ + struct gomp_device_descr *devicep = resolve_device (device); - void *fn_addr; + /* If there are depend clauses, but nowait is not present, + block the parent task until the dependencies are resolved + and then just continue with the rest of the function as if it + is a merged task. */ + if (depend != NULL) + { + struct gomp_thread *thr = gomp_thread (); + if (thr->task && thr->task->depend_hash) + gomp_task_maybe_wait_for_dependencies (depend); + } - if (devicep->capabilities & GOMP_OFFLOAD_CAP_NATIVE_EXEC) - fn_addr = (void *) fn; - else + if (devicep == NULL + || !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)) { - gomp_mutex_lock (&devicep->lock); - struct splay_tree_key_s k; - k.host_start = (uintptr_t) fn; - k.host_end = k.host_start + 1; - splay_tree_key tgt_fn = splay_tree_lookup (&devicep->mem_map, &k); - if (tgt_fn == NULL) + size_t i, tgt_align = 0, tgt_size = 0; + char *tgt = NULL; + for (i = 0; i < mapnum; i++) + if ((kinds[i] & 0xff) == GOMP_MAP_FIRSTPRIVATE) + { + size_t align = (size_t) 1 << (kinds[i] >> 8); + if (tgt_align < align) + tgt_align = align; + tgt_size = (tgt_size + align - 1) & ~(align - 1); + tgt_size += sizes[i]; + } + if (tgt_align) { - gomp_mutex_unlock (&devicep->lock); - gomp_fatal ("Target function wasn't mapped"); + tgt = gomp_alloca (tgt_size + tgt_align - 1); + uintptr_t al = (uintptr_t) tgt & (tgt_align - 1); + if (al) + tgt += tgt_align - al; + tgt_size = 0; + for (i = 0; i < mapnum; i++) + if ((kinds[i] & 0xff) == GOMP_MAP_FIRSTPRIVATE) + { + size_t align = (size_t) 1 << (kinds[i] >> 8); + tgt_size = (tgt_size + align - 1) & ~(align - 1); + memcpy (tgt + tgt_size, hostaddrs[i], sizes[i]); + hostaddrs[i] = tgt + tgt_size; + tgt_size = tgt_size + sizes[i]; + } } - gomp_mutex_unlock (&devicep->lock); - - fn_addr = (void *) tgt_fn->tgt_offset; + gomp_target_fallback (fn, hostaddrs); + return; } + void *fn_addr = gomp_get_target_fn_addr (devicep, fn); + struct target_mem_desc *tgt_vars - = gomp_map_vars (devicep, mapnum, hostaddrs, NULL, sizes, kinds, false, - true); + = gomp_map_vars (devicep, mapnum, hostaddrs, NULL, sizes, kinds, true, + GOMP_MAP_VARS_TARGET); struct gomp_thread old_thr, *thr = gomp_thread (); old_thr = *thr; memset (thr, '\0', sizeof (*thr)); @@ -1023,6 +1362,26 @@ GOMP_target (int device, void (*fn) (void *), const void *unused, gomp_unmap_vars (tgt_vars, true); } +/* Host fallback for GOMP_target_data{,_41} routines. */ + +static void +gomp_target_data_fallback (void) +{ + struct gomp_task_icv *icv = gomp_icv (false); + if (icv->target_data) + { + /* Even when doing a host fallback, if there are any active + #pragma omp target data constructs, need to remember the + new #pragma omp target data, otherwise GOMP_target_end_data + would get out of sync. */ + struct target_mem_desc *tgt + = gomp_map_vars (NULL, 0, NULL, NULL, NULL, NULL, false, + GOMP_MAP_VARS_DATA); + tgt->prev = icv->target_data; + icv->target_data = tgt; + } +} + void GOMP_target_data (int device, const void *unused, size_t mapnum, void **hostaddrs, size_t *sizes, unsigned char *kinds) @@ -1031,31 +1390,29 @@ GOMP_target_data (int device, const void *unused, size_t mapnum, if (devicep == NULL || !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)) - { - /* Host fallback. */ - struct gomp_task_icv *icv = gomp_icv (false); - if (icv->target_data) - { - /* Even when doing a host fallback, if there are any active - #pragma omp target data constructs, need to remember the - new #pragma omp target data, otherwise GOMP_target_end_data - would get out of sync. */ - struct target_mem_desc *tgt - = gomp_map_vars (NULL, 0, NULL, NULL, NULL, NULL, false, false); - tgt->prev = icv->target_data; - icv->target_data = tgt; - } - return; - } - - gomp_mutex_lock (&devicep->lock); - if (!devicep->is_initialized) - gomp_init_device (devicep); - gomp_mutex_unlock (&devicep->lock); + return gomp_target_data_fallback (); struct target_mem_desc *tgt = gomp_map_vars (devicep, mapnum, hostaddrs, NULL, sizes, kinds, false, - false); + GOMP_MAP_VARS_DATA); + struct gomp_task_icv *icv = gomp_icv (true); + tgt->prev = icv->target_data; + icv->target_data = tgt; +} + +void +GOMP_target_data_41 (int device, size_t mapnum, void **hostaddrs, size_t *sizes, + unsigned short *kinds) +{ + struct gomp_device_descr *devicep = resolve_device (device); + + if (devicep == NULL + || !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)) + return gomp_target_data_fallback (); + + struct target_mem_desc *tgt + = gomp_map_vars (devicep, mapnum, hostaddrs, NULL, sizes, kinds, true, + GOMP_MAP_VARS_DATA); struct gomp_task_icv *icv = gomp_icv (true); tgt->prev = icv->target_data; icv->target_data = tgt; @@ -1083,12 +1440,230 @@ GOMP_target_update (int device, const void *unused, size_t mapnum, || !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)) return; + gomp_update (devicep, mapnum, hostaddrs, sizes, kinds, false); +} + +void +GOMP_target_update_41 (int device, size_t mapnum, void **hostaddrs, + size_t *sizes, unsigned short *kinds, + unsigned int flags, void **depend) +{ + struct gomp_device_descr *devicep = resolve_device (device); + + /* If there are depend clauses, but nowait is not present, + block the parent task until the dependencies are resolved + and then just continue with the rest of the function as if it + is a merged task. Until we are able to schedule task during + variable mapping or unmapping, ignore nowait if depend clauses + are not present. */ + if (depend != NULL) + { + struct gomp_thread *thr = gomp_thread (); + if (thr->task && thr->task->depend_hash) + { + if ((flags & GOMP_TARGET_FLAG_NOWAIT) + && thr->ts.team + && !thr->task->final_task) + { + gomp_create_target_task (devicep, (void (*) (void *)) NULL, + mapnum, hostaddrs, sizes, kinds, + flags | GOMP_TARGET_FLAG_UPDATE, + depend); + return; + } + + struct gomp_team *team = thr->ts.team; + /* If parallel or taskgroup has been cancelled, don't start new + tasks. */ + if (team + && (gomp_team_barrier_cancelled (&team->barrier) + || (thr->task->taskgroup + && thr->task->taskgroup->cancelled))) + return; + + gomp_task_maybe_wait_for_dependencies (depend); + } + } + + if (devicep == NULL + || !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)) + return; + + struct gomp_thread *thr = gomp_thread (); + struct gomp_team *team = thr->ts.team; + /* If parallel or taskgroup has been cancelled, don't start new tasks. */ + if (team + && (gomp_team_barrier_cancelled (&team->barrier) + || (thr->task->taskgroup && thr->task->taskgroup->cancelled))) + return; + + gomp_update (devicep, mapnum, hostaddrs, sizes, kinds, true); +} + +static void +gomp_exit_data (struct gomp_device_descr *devicep, size_t mapnum, + void **hostaddrs, size_t *sizes, unsigned short *kinds) +{ + const int typemask = 0xff; + size_t i; gomp_mutex_lock (&devicep->lock); - if (!devicep->is_initialized) - gomp_init_device (devicep); + for (i = 0; i < mapnum; i++) + { + struct splay_tree_key_s cur_node; + unsigned char kind = kinds[i] & typemask; + switch (kind) + { + case GOMP_MAP_FROM: + case GOMP_MAP_ALWAYS_FROM: + case GOMP_MAP_DELETE: + case GOMP_MAP_RELEASE: + case GOMP_MAP_ZERO_LEN_ARRAY_SECTION: + case GOMP_MAP_DELETE_ZERO_LEN_ARRAY_SECTION: + cur_node.host_start = (uintptr_t) hostaddrs[i]; + cur_node.host_end = cur_node.host_start + sizes[i]; + splay_tree_key k = (kind == GOMP_MAP_DELETE_ZERO_LEN_ARRAY_SECTION + || kind == GOMP_MAP_ZERO_LEN_ARRAY_SECTION) + ? gomp_map_lookup (&devicep->mem_map, &cur_node) + : splay_tree_lookup (&devicep->mem_map, &cur_node); + if (!k) + continue; + + if (k->refcount > 0 && k->refcount != REFCOUNT_INFINITY) + k->refcount--; + if ((kind == GOMP_MAP_DELETE + || kind == GOMP_MAP_DELETE_ZERO_LEN_ARRAY_SECTION) + && k->refcount != REFCOUNT_INFINITY) + k->refcount = 0; + + if ((kind == GOMP_MAP_FROM && k->refcount == 0) + || kind == GOMP_MAP_ALWAYS_FROM) + devicep->dev2host_func (devicep->target_id, + (void *) cur_node.host_start, + (void *) (k->tgt->tgt_start + k->tgt_offset + + cur_node.host_start + - k->host_start), + cur_node.host_end - cur_node.host_start); + if (k->refcount == 0) + { + splay_tree_remove (&devicep->mem_map, k); + if (k->tgt->refcount > 1) + k->tgt->refcount--; + else + gomp_unmap_tgt (k->tgt); + } + + break; + default: + gomp_mutex_unlock (&devicep->lock); + gomp_fatal ("GOMP_target_enter_exit_data unhandled kind 0x%.2x", + kind); + } + } + gomp_mutex_unlock (&devicep->lock); +} - gomp_update (devicep, mapnum, hostaddrs, sizes, kinds, false); +void +GOMP_target_enter_exit_data (int device, size_t mapnum, void **hostaddrs, + size_t *sizes, unsigned short *kinds, + unsigned int flags, void **depend) +{ + struct gomp_device_descr *devicep = resolve_device (device); + + /* If there are depend clauses, but nowait is not present, + block the parent task until the dependencies are resolved + and then just continue with the rest of the function as if it + is a merged task. Until we are able to schedule task during + variable mapping or unmapping, ignore nowait if depend clauses + are not present. */ + if (depend != NULL) + { + struct gomp_thread *thr = gomp_thread (); + if (thr->task && thr->task->depend_hash) + { + if ((flags & GOMP_TARGET_FLAG_NOWAIT) + && thr->ts.team + && !thr->task->final_task) + { + gomp_create_target_task (devicep, (void (*) (void *)) NULL, + mapnum, hostaddrs, sizes, kinds, + flags, depend); + return; + } + + struct gomp_team *team = thr->ts.team; + /* If parallel or taskgroup has been cancelled, don't start new + tasks. */ + if (team + && (gomp_team_barrier_cancelled (&team->barrier) + || (thr->task->taskgroup + && thr->task->taskgroup->cancelled))) + return; + + gomp_task_maybe_wait_for_dependencies (depend); + } + } + + if (devicep == NULL + || !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)) + return; + + struct gomp_thread *thr = gomp_thread (); + struct gomp_team *team = thr->ts.team; + /* If parallel or taskgroup has been cancelled, don't start new tasks. */ + if (team + && (gomp_team_barrier_cancelled (&team->barrier) + || (thr->task->taskgroup && thr->task->taskgroup->cancelled))) + return; + + size_t i; + if ((flags & GOMP_TARGET_FLAG_EXIT_DATA) == 0) + for (i = 0; i < mapnum; i++) + if ((kinds[i] & 0xff) == GOMP_MAP_STRUCT) + { + gomp_map_vars (devicep, sizes[i] + 1, &hostaddrs[i], NULL, &sizes[i], + &kinds[i], true, GOMP_MAP_VARS_ENTER_DATA); + i += sizes[i]; + } + else + gomp_map_vars (devicep, 1, &hostaddrs[i], NULL, &sizes[i], &kinds[i], + true, GOMP_MAP_VARS_ENTER_DATA); + else + gomp_exit_data (devicep, mapnum, hostaddrs, sizes, kinds); +} + +void +gomp_target_task_fn (void *data) +{ + struct gomp_target_task *ttask = (struct gomp_target_task *) data; + if (ttask->fn != NULL) + { + /* GOMP_target_41 */ + } + else if (ttask->devicep == NULL + || !(ttask->devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)) + return; + + size_t i; + if (ttask->flags & GOMP_TARGET_FLAG_UPDATE) + gomp_update (ttask->devicep, ttask->mapnum, ttask->hostaddrs, ttask->sizes, + ttask->kinds, true); + else if ((ttask->flags & GOMP_TARGET_FLAG_EXIT_DATA) == 0) + for (i = 0; i < ttask->mapnum; i++) + if ((ttask->kinds[i] & 0xff) == GOMP_MAP_STRUCT) + { + gomp_map_vars (ttask->devicep, ttask->sizes[i] + 1, + &ttask->hostaddrs[i], NULL, &ttask->sizes[i], + &ttask->kinds[i], true, GOMP_MAP_VARS_ENTER_DATA); + i += ttask->sizes[i]; + } + else + gomp_map_vars (ttask->devicep, 1, &ttask->hostaddrs[i], NULL, + &ttask->sizes[i], &ttask->kinds[i], + true, GOMP_MAP_VARS_ENTER_DATA); + else + gomp_exit_data (ttask->devicep, ttask->mapnum, ttask->hostaddrs, + ttask->sizes, ttask->kinds); } void @@ -1103,6 +1678,384 @@ GOMP_teams (unsigned int num_teams, unsigned int thread_limit) (void) num_teams; } +void * +omp_target_alloc (size_t size, int device_num) +{ + if (device_num == GOMP_DEVICE_HOST_FALLBACK) + return malloc (size); + + if (device_num < 0) + return NULL; + + struct gomp_device_descr *devicep = resolve_device (device_num); + if (devicep == NULL) + return NULL; + + if (!(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)) + return malloc (size); + + gomp_mutex_lock (&devicep->lock); + void *ret = devicep->alloc_func (devicep->target_id, size); + gomp_mutex_unlock (&devicep->lock); + return ret; +} + +void +omp_target_free (void *device_ptr, int device_num) +{ + if (device_ptr == NULL) + return; + + if (device_num == GOMP_DEVICE_HOST_FALLBACK) + { + free (device_ptr); + return; + } + + if (device_num < 0) + return; + + struct gomp_device_descr *devicep = resolve_device (device_num); + if (devicep == NULL) + return; + + if (!(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)) + { + free (device_ptr); + return; + } + + gomp_mutex_lock (&devicep->lock); + devicep->free_func (devicep->target_id, device_ptr); + gomp_mutex_unlock (&devicep->lock); +} + +int +omp_target_is_present (void *ptr, int device_num) +{ + if (ptr == NULL) + return 1; + + if (device_num == GOMP_DEVICE_HOST_FALLBACK) + return 1; + + if (device_num < 0) + return 0; + + struct gomp_device_descr *devicep = resolve_device (device_num); + if (devicep == NULL) + return 0; + + if (!(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)) + return 1; + + gomp_mutex_lock (&devicep->lock); + struct splay_tree_s *mem_map = &devicep->mem_map; + struct splay_tree_key_s cur_node; + + cur_node.host_start = (uintptr_t) ptr; + cur_node.host_end = cur_node.host_start; + splay_tree_key n = gomp_map_lookup (mem_map, &cur_node); + int ret = n != NULL; + gomp_mutex_unlock (&devicep->lock); + return ret; +} + +int +omp_target_memcpy (void *dst, void *src, size_t length, size_t dst_offset, + size_t src_offset, int dst_device_num, int src_device_num) +{ + struct gomp_device_descr *dst_devicep = NULL, *src_devicep = NULL; + + if (dst_device_num != GOMP_DEVICE_HOST_FALLBACK) + { + if (dst_device_num < 0) + return EINVAL; + + dst_devicep = resolve_device (dst_device_num); + if (dst_devicep == NULL) + return EINVAL; + + if (!(dst_devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)) + dst_devicep = NULL; + } + if (src_device_num != GOMP_DEVICE_HOST_FALLBACK) + { + if (src_device_num < 0) + return EINVAL; + + src_devicep = resolve_device (src_device_num); + if (src_devicep == NULL) + return EINVAL; + + if (!(src_devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)) + src_devicep = NULL; + } + if (src_devicep == NULL && dst_devicep == NULL) + { + memcpy ((char *) dst + dst_offset, (char *) src + src_offset, length); + return 0; + } + if (src_devicep == NULL) + { + gomp_mutex_lock (&dst_devicep->lock); + dst_devicep->host2dev_func (dst_devicep->target_id, + (char *) dst + dst_offset, + (char *) src + src_offset, length); + gomp_mutex_unlock (&dst_devicep->lock); + return 0; + } + if (dst_devicep == NULL) + { + gomp_mutex_lock (&src_devicep->lock); + src_devicep->dev2host_func (src_devicep->target_id, + (char *) dst + dst_offset, + (char *) src + src_offset, length); + gomp_mutex_unlock (&src_devicep->lock); + return 0; + } + if (src_devicep == dst_devicep) + { + gomp_mutex_lock (&src_devicep->lock); + src_devicep->dev2dev_func (src_devicep->target_id, + (char *) dst + dst_offset, + (char *) src + src_offset, length); + gomp_mutex_unlock (&src_devicep->lock); + return 0; + } + return EINVAL; +} + +static int +omp_target_memcpy_rect_worker (void *dst, void *src, size_t element_size, + int num_dims, const size_t *volume, + const size_t *dst_offsets, + const size_t *src_offsets, + const size_t *dst_dimensions, + const size_t *src_dimensions, + struct gomp_device_descr *dst_devicep, + struct gomp_device_descr *src_devicep) +{ + size_t dst_slice = element_size; + size_t src_slice = element_size; + size_t j, dst_off, src_off, length; + int i, ret; + + if (num_dims == 1) + { + if (__builtin_mul_overflow (element_size, volume[0], &length) + || __builtin_mul_overflow (element_size, dst_offsets[0], &dst_off) + || __builtin_mul_overflow (element_size, src_offsets[0], &src_off)) + return EINVAL; + if (dst_devicep == NULL && src_devicep == NULL) + memcpy ((char *) dst + dst_off, (char *) src + src_off, length); + else if (src_devicep == NULL) + dst_devicep->host2dev_func (dst_devicep->target_id, + (char *) dst + dst_off, + (char *) src + src_off, length); + else if (dst_devicep == NULL) + src_devicep->dev2host_func (src_devicep->target_id, + (char *) dst + dst_off, + (char *) src + src_off, length); + else if (src_devicep == dst_devicep) + src_devicep->dev2dev_func (src_devicep->target_id, + (char *) dst + dst_off, + (char *) src + src_off, length); + else + return EINVAL; + return 0; + } + + /* FIXME: it would be nice to have some plugin function to handle + num_dims == 2 and num_dims == 3 more efficiently. Larger ones can + be handled in the generic recursion below, and for host-host it + should be used even for any num_dims >= 2. */ + + for (i = 1; i < num_dims; i++) + if (__builtin_mul_overflow (dst_slice, dst_dimensions[i], &dst_slice) + || __builtin_mul_overflow (src_slice, src_dimensions[i], &src_slice)) + return EINVAL; + if (__builtin_mul_overflow (dst_slice, dst_offsets[0], &dst_off) + || __builtin_mul_overflow (src_slice, src_offsets[0], &src_off)) + return EINVAL; + for (j = 0; j < volume[0]; j++) + { + ret = omp_target_memcpy_rect_worker ((char *) dst + dst_off, + (char *) src + src_off, + element_size, num_dims - 1, + volume + 1, dst_offsets + 1, + src_offsets + 1, dst_dimensions + 1, + src_dimensions + 1, dst_devicep, + src_devicep); + if (ret) + return ret; + dst_off += dst_slice; + src_off += src_slice; + } + return 0; +} + +int +omp_target_memcpy_rect (void *dst, void *src, size_t element_size, + int num_dims, const size_t *volume, + const size_t *dst_offsets, + const size_t *src_offsets, + const size_t *dst_dimensions, + const size_t *src_dimensions, + int dst_device_num, int src_device_num) +{ + struct gomp_device_descr *dst_devicep = NULL, *src_devicep = NULL; + + if (!dst && !src) + return INT_MAX; + + if (dst_device_num != GOMP_DEVICE_HOST_FALLBACK) + { + if (dst_device_num < 0) + return EINVAL; + + dst_devicep = resolve_device (dst_device_num); + if (dst_devicep == NULL) + return EINVAL; + + if (!(dst_devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)) + dst_devicep = NULL; + } + if (src_device_num != GOMP_DEVICE_HOST_FALLBACK) + { + if (src_device_num < 0) + return EINVAL; + + src_devicep = resolve_device (src_device_num); + if (src_devicep == NULL) + return EINVAL; + + if (!(src_devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)) + src_devicep = NULL; + } + + if (src_devicep != NULL && dst_devicep != NULL && src_devicep != dst_devicep) + return EINVAL; + + if (src_devicep) + gomp_mutex_lock (&src_devicep->lock); + else if (dst_devicep) + gomp_mutex_lock (&dst_devicep->lock); + int ret = omp_target_memcpy_rect_worker (dst, src, element_size, num_dims, + volume, dst_offsets, src_offsets, + dst_dimensions, src_dimensions, + dst_devicep, src_devicep); + if (src_devicep) + gomp_mutex_unlock (&src_devicep->lock); + else if (dst_devicep) + gomp_mutex_unlock (&dst_devicep->lock); + return ret; +} + +int +omp_target_associate_ptr (void *host_ptr, void *device_ptr, size_t size, + size_t device_offset, int device_num) +{ + if (device_num == GOMP_DEVICE_HOST_FALLBACK) + return EINVAL; + + if (device_num < 0) + return EINVAL; + + struct gomp_device_descr *devicep = resolve_device (device_num); + if (devicep == NULL) + return EINVAL; + + if (!(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)) + return EINVAL; + + gomp_mutex_lock (&devicep->lock); + + struct splay_tree_s *mem_map = &devicep->mem_map; + struct splay_tree_key_s cur_node; + int ret = EINVAL; + + cur_node.host_start = (uintptr_t) host_ptr; + cur_node.host_end = cur_node.host_start + size; + splay_tree_key n = gomp_map_lookup (mem_map, &cur_node); + if (n) + { + if (n->tgt->tgt_start + n->tgt_offset + == (uintptr_t) device_ptr + device_offset + && n->host_start <= cur_node.host_start + && n->host_end >= cur_node.host_end) + ret = 0; + } + else + { + struct target_mem_desc *tgt = gomp_malloc (sizeof (*tgt)); + tgt->array = gomp_malloc (sizeof (*tgt->array)); + tgt->refcount = 1; + tgt->tgt_start = 0; + tgt->tgt_end = 0; + tgt->to_free = NULL; + tgt->prev = NULL; + tgt->list_count = 0; + tgt->device_descr = devicep; + splay_tree_node array = tgt->array; + splay_tree_key k = &array->key; + k->host_start = cur_node.host_start; + k->host_end = cur_node.host_end; + k->tgt = tgt; + k->tgt_offset = (uintptr_t) device_ptr + device_offset; + k->refcount = REFCOUNT_INFINITY; + k->async_refcount = 0; + array->left = NULL; + array->right = NULL; + splay_tree_insert (&devicep->mem_map, array); + ret = 0; + } + gomp_mutex_unlock (&devicep->lock); + return ret; +} + +int +omp_target_disassociate_ptr (void *ptr, int device_num) +{ + if (device_num == GOMP_DEVICE_HOST_FALLBACK) + return EINVAL; + + if (device_num < 0) + return EINVAL; + + struct gomp_device_descr *devicep = resolve_device (device_num); + if (devicep == NULL) + return EINVAL; + + if (!(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)) + return EINVAL; + + gomp_mutex_lock (&devicep->lock); + + struct splay_tree_s *mem_map = &devicep->mem_map; + struct splay_tree_key_s cur_node; + int ret = EINVAL; + + cur_node.host_start = (uintptr_t) ptr; + cur_node.host_end = cur_node.host_start; + splay_tree_key n = gomp_map_lookup (mem_map, &cur_node); + if (n + && n->host_start == cur_node.host_start + && n->refcount == REFCOUNT_INFINITY + && n->tgt->tgt_start == 0 + && n->tgt->to_free == NULL + && n->tgt->refcount == 1 + && n->tgt->list_count == 0) + { + splay_tree_remove (&devicep->mem_map, n); + gomp_unmap_tgt (n->tgt); + ret = 0; + } + + gomp_mutex_unlock (&devicep->lock); + return ret; +} + #ifdef PLUGIN_SUPPORT /* This function tries to load a plugin for DEVICE. Name of plugin is passed @@ -1153,7 +2106,10 @@ gomp_load_plugin_for_device (struct gomp_device_descr *device, DLSYM (host2dev); device->capabilities = device->get_caps_func (); if (device->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400) - DLSYM (run); + { + DLSYM (run); + DLSYM (dev2dev); + } if (device->capabilities & GOMP_OFFLOAD_CAP_OPENACC_200) { if (!DLSYM_OPT (openacc.exec, openacc_parallel) diff --git a/libgomp/task.c b/libgomp/task.c index 74920d5ddb8..1246c6ae318 100644 --- a/libgomp/task.c +++ b/libgomp/task.c @@ -29,6 +29,7 @@ #include "libgomp.h" #include #include +#include "gomp-constants.h" typedef struct gomp_task_depend_entry *hash_entry_type; @@ -91,6 +92,8 @@ gomp_end_task (void) thr->task = task->parent; } +/* Orphan the task in CHILDREN and all its siblings. */ + static inline void gomp_clear_parent (struct gomp_task *children) { @@ -105,16 +108,136 @@ gomp_clear_parent (struct gomp_task *children) while (task != children); } -static void gomp_task_maybe_wait_for_dependencies (void **depend); +/* Helper function for GOMP_task and gomp_create_target_task. Depend clause + handling for undeferred task creation. */ + +static void +gomp_task_handle_depend (struct gomp_task *task, struct gomp_task *parent, + void **depend) +{ + size_t ndepend = (uintptr_t) depend[0]; + size_t nout = (uintptr_t) depend[1]; + size_t i; + hash_entry_type ent; + + task->depend_count = ndepend; + task->num_dependees = 0; + if (parent->depend_hash == NULL) + parent->depend_hash = htab_create (2 * ndepend > 12 ? 2 * ndepend : 12); + for (i = 0; i < ndepend; i++) + { + task->depend[i].addr = depend[2 + i]; + task->depend[i].next = NULL; + task->depend[i].prev = NULL; + task->depend[i].task = task; + task->depend[i].is_in = i >= nout; + task->depend[i].redundant = false; + task->depend[i].redundant_out = false; + + hash_entry_type *slot = htab_find_slot (&parent->depend_hash, + &task->depend[i], INSERT); + hash_entry_type out = NULL, last = NULL; + if (*slot) + { + /* If multiple depends on the same task are the same, all but the + first one are redundant. As inout/out come first, if any of them + is inout/out, it will win, which is the right semantics. */ + if ((*slot)->task == task) + { + task->depend[i].redundant = true; + continue; + } + for (ent = *slot; ent; ent = ent->next) + { + if (ent->redundant_out) + break; + + last = ent; + + /* depend(in:...) doesn't depend on earlier depend(in:...). */ + if (i >= nout && ent->is_in) + continue; + + if (!ent->is_in) + out = ent; + + struct gomp_task *tsk = ent->task; + if (tsk->dependers == NULL) + { + tsk->dependers + = gomp_malloc (sizeof (struct gomp_dependers_vec) + + 6 * sizeof (struct gomp_task *)); + tsk->dependers->n_elem = 1; + tsk->dependers->allocated = 6; + tsk->dependers->elem[0] = task; + task->num_dependees++; + continue; + } + /* We already have some other dependency on tsk from earlier + depend clause. */ + else if (tsk->dependers->n_elem + && (tsk->dependers->elem[tsk->dependers->n_elem - 1] + == task)) + continue; + else if (tsk->dependers->n_elem == tsk->dependers->allocated) + { + tsk->dependers->allocated + = tsk->dependers->allocated * 2 + 2; + tsk->dependers + = gomp_realloc (tsk->dependers, + sizeof (struct gomp_dependers_vec) + + (tsk->dependers->allocated + * sizeof (struct gomp_task *))); + } + tsk->dependers->elem[tsk->dependers->n_elem++] = task; + task->num_dependees++; + } + task->depend[i].next = *slot; + (*slot)->prev = &task->depend[i]; + } + *slot = &task->depend[i]; + + /* There is no need to store more than one depend({,in}out:) task per + address in the hash table chain for the purpose of creation of + deferred tasks, because each out depends on all earlier outs, thus it + is enough to record just the last depend({,in}out:). For depend(in:), + we need to keep all of the previous ones not terminated yet, because + a later depend({,in}out:) might need to depend on all of them. So, if + the new task's clause is depend({,in}out:), we know there is at most + one other depend({,in}out:) clause in the list (out). For + non-deferred tasks we want to see all outs, so they are moved to the + end of the chain, after first redundant_out entry all following + entries should be redundant_out. */ + if (!task->depend[i].is_in && out) + { + if (out != last) + { + out->next->prev = out->prev; + out->prev->next = out->next; + out->next = last->next; + out->prev = last; + last->next = out; + if (out->next) + out->next->prev = out; + } + out->redundant_out = true; + } + } +} /* Called when encountering an explicit task directive. If IF_CLAUSE is false, then we must not delay in executing the task. If UNTIED is true, - then the task may be executed by any member of the team. */ + then the task may be executed by any member of the team. + + DEPEND is an array containing: + depend[0]: number of depend elements. + depend[1]: number of depend elements of type "out". + depend[2..N+1]: address of [1..N]th depend element. */ void GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *), long arg_size, long arg_align, bool if_clause, unsigned flags, - void **depend) + void **depend, int priority) { struct gomp_thread *thr = gomp_thread (); struct gomp_team *team = thr->ts.team; @@ -126,8 +249,7 @@ GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *), might be running on different thread than FN. */ if (cpyfn) if_clause = false; - if (flags & 1) - flags &= ~1; + flags &= ~GOMP_TASK_FLAG_UNTIED; #endif /* If parallel or taskgroup has been cancelled, don't start new tasks. */ @@ -136,6 +258,11 @@ GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *), || (thr->task->taskgroup && thr->task->taskgroup->cancelled))) return; + if ((flags & GOMP_TASK_FLAG_PRIORITY) == 0) + priority = 0; + /* FIXME, use priority. */ + (void) priority; + if (!if_clause || team == NULL || (thr->task && thr->task->final_task) || team->task_count > 64 * team->nthreads) @@ -148,12 +275,14 @@ GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *), depend clauses for non-deferred tasks other than this, because the parent task is suspended until the child task finishes and thus it can't start further child tasks. */ - if ((flags & 8) && thr->task && thr->task->depend_hash) + if ((flags & GOMP_TASK_FLAG_DEPEND) + && thr->task && thr->task->depend_hash) gomp_task_maybe_wait_for_dependencies (depend); gomp_init_task (&task, thr->task, gomp_icv (false)); - task.kind = GOMP_TASK_IFFALSE; - task.final_task = (thr->task && thr->task->final_task) || (flags & 2); + task.kind = GOMP_TASK_UNDEFERRED; + task.final_task = (thr->task && thr->task->final_task) + || (flags & GOMP_TASK_FLAG_FINAL); if (thr->task) { task.in_tied_task = thr->task->in_tied_task; @@ -196,7 +325,7 @@ GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *), bool do_wake; size_t depend_size = 0; - if (flags & 8) + if (flags & GOMP_TASK_FLAG_DEPEND) depend_size = ((uintptr_t) depend[0] * sizeof (struct gomp_task_depend_entry)); task = gomp_malloc (sizeof (*task) + depend_size @@ -204,7 +333,7 @@ GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *), arg = (char *) (((uintptr_t) (task + 1) + depend_size + arg_align - 1) & ~(uintptr_t) (arg_align - 1)); gomp_init_task (task, parent, gomp_icv (false)); - task->kind = GOMP_TASK_IFFALSE; + task->kind = GOMP_TASK_UNDEFERRED; task->in_tied_task = parent->in_tied_task; task->taskgroup = taskgroup; thr->task = task; @@ -219,7 +348,7 @@ GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *), task->kind = GOMP_TASK_WAITING; task->fn = fn; task->fn_data = arg; - task->final_task = (flags & 2) >> 1; + task->final_task = (flags & GOMP_TASK_FLAG_FINAL) >> 1; gomp_mutex_lock (&team->task_lock); /* If parallel or taskgroup has been cancelled, don't start new tasks. */ @@ -236,123 +365,7 @@ GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *), taskgroup->num_children++; if (depend_size) { - size_t ndepend = (uintptr_t) depend[0]; - size_t nout = (uintptr_t) depend[1]; - size_t i; - hash_entry_type ent; - - task->depend_count = ndepend; - task->num_dependees = 0; - if (parent->depend_hash == NULL) - parent->depend_hash - = htab_create (2 * ndepend > 12 ? 2 * ndepend : 12); - for (i = 0; i < ndepend; i++) - { - task->depend[i].addr = depend[2 + i]; - task->depend[i].next = NULL; - task->depend[i].prev = NULL; - task->depend[i].task = task; - task->depend[i].is_in = i >= nout; - task->depend[i].redundant = false; - task->depend[i].redundant_out = false; - - hash_entry_type *slot - = htab_find_slot (&parent->depend_hash, &task->depend[i], - INSERT); - hash_entry_type out = NULL, last = NULL; - if (*slot) - { - /* If multiple depends on the same task are the - same, all but the first one are redundant. - As inout/out come first, if any of them is - inout/out, it will win, which is the right - semantics. */ - if ((*slot)->task == task) - { - task->depend[i].redundant = true; - continue; - } - for (ent = *slot; ent; ent = ent->next) - { - if (ent->redundant_out) - break; - - last = ent; - - /* depend(in:...) doesn't depend on earlier - depend(in:...). */ - if (i >= nout && ent->is_in) - continue; - - if (!ent->is_in) - out = ent; - - struct gomp_task *tsk = ent->task; - if (tsk->dependers == NULL) - { - tsk->dependers - = gomp_malloc (sizeof (struct gomp_dependers_vec) - + 6 * sizeof (struct gomp_task *)); - tsk->dependers->n_elem = 1; - tsk->dependers->allocated = 6; - tsk->dependers->elem[0] = task; - task->num_dependees++; - continue; - } - /* We already have some other dependency on tsk - from earlier depend clause. */ - else if (tsk->dependers->n_elem - && (tsk->dependers->elem[tsk->dependers->n_elem - - 1] - == task)) - continue; - else if (tsk->dependers->n_elem - == tsk->dependers->allocated) - { - tsk->dependers->allocated - = tsk->dependers->allocated * 2 + 2; - tsk->dependers - = gomp_realloc (tsk->dependers, - sizeof (struct gomp_dependers_vec) - + (tsk->dependers->allocated - * sizeof (struct gomp_task *))); - } - tsk->dependers->elem[tsk->dependers->n_elem++] = task; - task->num_dependees++; - } - task->depend[i].next = *slot; - (*slot)->prev = &task->depend[i]; - } - *slot = &task->depend[i]; - - /* There is no need to store more than one depend({,in}out:) - task per address in the hash table chain for the purpose - of creation of deferred tasks, because each out - depends on all earlier outs, thus it is enough to record - just the last depend({,in}out:). For depend(in:), we need - to keep all of the previous ones not terminated yet, because - a later depend({,in}out:) might need to depend on all of - them. So, if the new task's clause is depend({,in}out:), - we know there is at most one other depend({,in}out:) clause - in the list (out). For non-deferred tasks we want to see - all outs, so they are moved to the end of the chain, - after first redundant_out entry all following entries - should be redundant_out. */ - if (!task->depend[i].is_in && out) - { - if (out != last) - { - out->next->prev = out->prev; - out->prev->next = out->next; - out->next = last->next; - out->prev = last; - last->next = out; - if (out->next) - out->next->prev = out; - } - out->redundant_out = true; - } - } + gomp_task_handle_depend (task, parent, depend); if (task->num_dependees) { gomp_mutex_unlock (&team->task_lock); @@ -374,6 +387,7 @@ GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *), parent->children = task; if (taskgroup) { + /* If applicable, place task into its taskgroup. */ if (taskgroup->children) { task->next_taskgroup = taskgroup->children; @@ -412,26 +426,340 @@ GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *), } } +ialias (GOMP_taskgroup_start) +ialias (GOMP_taskgroup_end) + +#define TYPE long +#define UTYPE unsigned long +#define TYPE_is_long 1 +#include "taskloop.c" +#undef TYPE +#undef UTYPE +#undef TYPE_is_long + +#define TYPE unsigned long long +#define UTYPE TYPE +#define GOMP_taskloop GOMP_taskloop_ull +#include "taskloop.c" +#undef TYPE +#undef UTYPE +#undef GOMP_taskloop + +/* Called for nowait target tasks. */ + +void +gomp_create_target_task (struct gomp_device_descr *devicep, + void (*fn) (void *), size_t mapnum, void **hostaddrs, + size_t *sizes, unsigned short *kinds, + unsigned int flags, void **depend) +{ + struct gomp_thread *thr = gomp_thread (); + struct gomp_team *team = thr->ts.team; + + /* If parallel or taskgroup has been cancelled, don't start new tasks. */ + if (team + && (gomp_team_barrier_cancelled (&team->barrier) + || (thr->task->taskgroup && thr->task->taskgroup->cancelled))) + return; + + struct gomp_target_task *ttask; + struct gomp_task *task; + struct gomp_task *parent = thr->task; + struct gomp_taskgroup *taskgroup = parent->taskgroup; + bool do_wake; + size_t depend_size = 0; + + if (depend != NULL) + depend_size = ((uintptr_t) depend[0] + * sizeof (struct gomp_task_depend_entry)); + task = gomp_malloc (sizeof (*task) + depend_size + + sizeof (*ttask) + + mapnum * (sizeof (void *) + sizeof (size_t) + + sizeof (unsigned short))); + gomp_init_task (task, parent, gomp_icv (false)); + task->kind = GOMP_TASK_WAITING; + task->in_tied_task = parent->in_tied_task; + task->taskgroup = taskgroup; + ttask = (struct gomp_target_task *) &task->depend[(uintptr_t) depend[0]]; + ttask->devicep = devicep; + ttask->fn = fn; + ttask->mapnum = mapnum; + memcpy (ttask->hostaddrs, hostaddrs, mapnum * sizeof (void *)); + ttask->sizes = (size_t *) &ttask->hostaddrs[mapnum]; + memcpy (ttask->sizes, sizes, mapnum * sizeof (size_t)); + ttask->kinds = (unsigned short *) &ttask->sizes[mapnum]; + memcpy (ttask->kinds, kinds, mapnum * sizeof (unsigned short)); + ttask->flags = flags; + task->fn = gomp_target_task_fn; + task->fn_data = ttask; + task->final_task = 0; + gomp_mutex_lock (&team->task_lock); + /* If parallel or taskgroup has been cancelled, don't start new tasks. */ + if (__builtin_expect (gomp_team_barrier_cancelled (&team->barrier) + || (taskgroup && taskgroup->cancelled), 0)) + { + gomp_mutex_unlock (&team->task_lock); + gomp_finish_task (task); + free (task); + return; + } + if (taskgroup) + taskgroup->num_children++; + if (depend_size) + { + gomp_task_handle_depend (task, parent, depend); + if (task->num_dependees) + { + gomp_mutex_unlock (&team->task_lock); + return; + } + } + if (parent->children) + { + task->next_child = parent->children; + task->prev_child = parent->children->prev_child; + task->next_child->prev_child = task; + task->prev_child->next_child = task; + } + else + { + task->next_child = task; + task->prev_child = task; + } + parent->children = task; + if (taskgroup) + { + /* If applicable, place task into its taskgroup. */ + if (taskgroup->children) + { + task->next_taskgroup = taskgroup->children; + task->prev_taskgroup = taskgroup->children->prev_taskgroup; + task->next_taskgroup->prev_taskgroup = task; + task->prev_taskgroup->next_taskgroup = task; + } + else + { + task->next_taskgroup = task; + task->prev_taskgroup = task; + } + taskgroup->children = task; + } + if (team->task_queue) + { + task->next_queue = team->task_queue; + task->prev_queue = team->task_queue->prev_queue; + task->next_queue->prev_queue = task; + task->prev_queue->next_queue = task; + } + else + { + task->next_queue = task; + task->prev_queue = task; + team->task_queue = task; + } + ++team->task_count; + ++team->task_queued_count; + gomp_team_barrier_set_task_pending (&team->barrier); + do_wake = team->task_running_count + !parent->in_tied_task + < team->nthreads; + gomp_mutex_unlock (&team->task_lock); + if (do_wake) + gomp_team_barrier_wake (&team->barrier, 1); +} + +#if _LIBGOMP_CHECKING +/* Sanity check TASK to make sure it is in its parent's children + queue, and that the tasks therein are in the right order. + + The expected order is: + parent_depends_on WAITING tasks + !parent_depends_on WAITING tasks + TIED tasks + + PARENT is the alleged parent of TASK. */ + +static void +verify_children_queue (struct gomp_task *task, struct gomp_task *parent) +{ + if (task->parent != parent) + gomp_fatal ("verify_children_queue: incompatible parents"); + /* It's OK, Annie was an orphan and she turned out all right. */ + if (!parent) + return; + + bool seen_tied = false; + bool seen_plain_waiting = false; + bool found = false; + struct gomp_task *t = parent->children; + while (1) + { + if (t == task) + found = true; + if (seen_tied && t->kind == GOMP_TASK_WAITING) + gomp_fatal ("verify_children_queue: WAITING task after TIED"); + if (t->kind == GOMP_TASK_TIED) + seen_tied = true; + else if (t->kind == GOMP_TASK_WAITING) + { + if (t->parent_depends_on) + { + if (seen_plain_waiting) + gomp_fatal ("verify_children_queue: parent_depends_on after " + "!parent_depends_on"); + } + else + seen_plain_waiting = true; + } + t = t->next_child; + if (t == parent->children) + break; + } + if (!found) + gomp_fatal ("verify_children_queue: child not found in parent queue"); +} + +/* Sanity check TASK to make sure it is in its taskgroup queue (if + applicable), and that the tasks therein are in the right order. + + The expected order is that GOMP_TASK_WAITING tasks must come before + GOMP_TASK_TIED tasks. + + TASK is the task. */ + +static void +verify_taskgroup_queue (struct gomp_task *task) +{ + struct gomp_taskgroup *taskgroup = task->taskgroup; + if (!taskgroup) + return; + + bool seen_tied = false; + bool found = false; + struct gomp_task *t = taskgroup->children; + while (1) + { + if (t == task) + found = true; + if (t->kind == GOMP_TASK_WAITING && seen_tied) + gomp_fatal ("verify_taskgroup_queue: WAITING task after TIED"); + if (t->kind == GOMP_TASK_TIED) + seen_tied = true; + t = t->next_taskgroup; + if (t == taskgroup->children) + break; + } + if (!found) + gomp_fatal ("verify_taskgroup_queue: child not found in parent queue"); +} + +/* Verify that TASK is in the team's task queue. */ + +static void +verify_task_queue (struct gomp_task *task, struct gomp_team *team) +{ + struct gomp_task *t = team->task_queue; + if (team) + while (1) + { + if (t == task) + return; + t = t->next_queue; + if (t == team->task_queue) + break; + } + gomp_fatal ("verify_team_queue: child not in team"); +} +#endif + static inline bool gomp_task_run_pre (struct gomp_task *child_task, struct gomp_task *parent, - struct gomp_taskgroup *taskgroup, struct gomp_team *team) + struct gomp_team *team) { +#if _LIBGOMP_CHECKING + verify_children_queue (child_task, parent); + verify_taskgroup_queue (child_task); + verify_task_queue (child_task, team); +#endif + if (parent) { + /* Adjust children such that it will point to a next child, + while the current one is scheduled to be executed. This way, + GOMP_taskwait (and others) can schedule a next task while + waiting. + + Do not remove it entirely from the circular list, as it is + still a child, though not one we should consider first (say + by GOMP_taskwait). */ if (parent->children == child_task) parent->children = child_task->next_child; + /* TIED tasks cannot come before WAITING tasks. If we're about + to make this task TIED, rewire things appropriately. + However, a TIED task at the end is perfectly fine. */ + else if (child_task->next_child->kind == GOMP_TASK_WAITING + && child_task->next_child != parent->children) + { + /* Remove from the list. */ + child_task->prev_child->next_child = child_task->next_child; + child_task->next_child->prev_child = child_task->prev_child; + /* Rewire at the end of its siblings. */ + child_task->next_child = parent->children; + child_task->prev_child = parent->children->prev_child; + parent->children->prev_child->next_child = child_task; + parent->children->prev_child = child_task; + } + + /* If the current task (child_task) is at the top of the + parent's last_parent_depends_on, it's about to be removed + from it. Adjust last_parent_depends_on appropriately. */ if (__builtin_expect (child_task->parent_depends_on, 0) && parent->taskwait->last_parent_depends_on == child_task) { + /* The last_parent_depends_on list was built with all + parent_depends_on entries linked to the prev_child. Grab + the next last_parent_depends_on head from this prev_child if + available... */ if (child_task->prev_child->kind == GOMP_TASK_WAITING && child_task->prev_child->parent_depends_on) parent->taskwait->last_parent_depends_on = child_task->prev_child; else - parent->taskwait->last_parent_depends_on = NULL; + { + /* ...otherwise, there are no more parent_depends_on + entries waiting to run. In which case, clear the + list. */ + parent->taskwait->last_parent_depends_on = NULL; + } } } - if (taskgroup && taskgroup->children == child_task) - taskgroup->children = child_task->next_taskgroup; + + /* Adjust taskgroup to point to the next taskgroup. See note above + regarding adjustment of children as to why the child_task is not + removed entirely from the circular list. */ + struct gomp_taskgroup *taskgroup = child_task->taskgroup; + if (taskgroup) + { + if (taskgroup->children == child_task) + taskgroup->children = child_task->next_taskgroup; + /* TIED tasks cannot come before WAITING tasks. If we're about + to make this task TIED, rewire things appropriately. + However, a TIED task at the end is perfectly fine. */ + else if (child_task->next_taskgroup->kind == GOMP_TASK_WAITING + && child_task->next_taskgroup != taskgroup->children) + { + /* Remove from the list. */ + child_task->prev_taskgroup->next_taskgroup + = child_task->next_taskgroup; + child_task->next_taskgroup->prev_taskgroup + = child_task->prev_taskgroup; + /* Rewire at the end of its taskgroup. */ + child_task->next_taskgroup = taskgroup->children; + child_task->prev_taskgroup = taskgroup->children->prev_taskgroup; + taskgroup->children->prev_taskgroup->next_taskgroup = child_task; + taskgroup->children->prev_taskgroup = child_task; + } + } + + /* Remove child_task from the task_queue. */ child_task->prev_queue->next_queue = child_task->next_queue; child_task->next_queue->prev_queue = child_task->prev_queue; if (team->task_queue == child_task) @@ -442,6 +770,7 @@ gomp_task_run_pre (struct gomp_task *child_task, struct gomp_task *parent, team->task_queue = NULL; } child_task->kind = GOMP_TASK_TIED; + if (--team->task_queued_count == 0) gomp_team_barrier_clear_task_pending (&team->barrier); if ((gomp_team_barrier_cancelled (&team->barrier) @@ -479,6 +808,11 @@ gomp_task_run_post_handle_depend_hash (struct gomp_task *child_task) } } +/* After CHILD_TASK has been run, adjust the various task queues to + give higher priority to the tasks that depend on CHILD_TASK. + + TEAM is the team to which CHILD_TASK belongs to. */ + static size_t gomp_task_run_post_handle_dependers (struct gomp_task *child_task, struct gomp_team *team) @@ -502,6 +836,7 @@ gomp_task_run_post_handle_dependers (struct gomp_task *child_task, if (parent->taskwait && parent->taskwait->last_parent_depends_on && !task->parent_depends_on) { + /* Put depender in last_parent_depends_on. */ struct gomp_task *last_parent_depends_on = parent->taskwait->last_parent_depends_on; task->next_child = last_parent_depends_on->next_child; @@ -509,6 +844,8 @@ gomp_task_run_post_handle_dependers (struct gomp_task *child_task, } else { + /* Make depender a sibling of child_task, and place + it at the top of said sibling list. */ task->next_child = parent->children; task->prev_child = parent->children->prev_child; parent->children = task; @@ -518,6 +855,7 @@ gomp_task_run_post_handle_dependers (struct gomp_task *child_task, } else { + /* Make depender a sibling of child_task. */ task->next_child = task; task->prev_child = task; parent->children = task; @@ -539,6 +877,8 @@ gomp_task_run_post_handle_dependers (struct gomp_task *child_task, parent->taskwait->last_parent_depends_on = task; } } + /* If depender is in a taskgroup, put it at the TOP of its + taskgroup. */ if (taskgroup) { if (taskgroup->children) @@ -560,6 +900,8 @@ gomp_task_run_post_handle_dependers (struct gomp_task *child_task, gomp_sem_post (&taskgroup->taskgroup_sem); } } + /* Put depender of child_task at the END of the team's + task_queue. */ if (team->task_queue) { task->next_queue = team->task_queue; @@ -602,12 +944,18 @@ gomp_task_run_post_handle_depend (struct gomp_task *child_task, return gomp_task_run_post_handle_dependers (child_task, team); } +/* Remove CHILD_TASK from its parent. */ + static inline void gomp_task_run_post_remove_parent (struct gomp_task *child_task) { struct gomp_task *parent = child_task->parent; if (parent == NULL) return; + + /* If this was the last task the parent was depending on, + synchronize with gomp_task_maybe_wait_for_dependencies so it can + clean up and return. */ if (__builtin_expect (child_task->parent_depends_on, 0) && --parent->taskwait->n_depend == 0 && parent->taskwait->in_depend_wait) @@ -615,6 +963,8 @@ gomp_task_run_post_remove_parent (struct gomp_task *child_task) parent->taskwait->in_depend_wait = false; gomp_sem_post (&parent->taskwait->taskwait_sem); } + + /* Remove CHILD_TASK from its sibling list. */ child_task->prev_child->next_child = child_task->next_child; child_task->next_child->prev_child = child_task->prev_child; if (parent->children != child_task) @@ -637,6 +987,8 @@ gomp_task_run_post_remove_parent (struct gomp_task *child_task) } } +/* Remove CHILD_TASK from its taskgroup. */ + static inline void gomp_task_run_post_remove_taskgroup (struct gomp_task *child_task) { @@ -701,7 +1053,7 @@ gomp_barrier_handle_tasks (gomp_barrier_state_t state) { child_task = team->task_queue; cancelled = gomp_task_run_pre (child_task, child_task->parent, - child_task->taskgroup, team); + team); if (__builtin_expect (cancelled, 0)) { if (to_free) @@ -766,7 +1118,9 @@ gomp_barrier_handle_tasks (gomp_barrier_state_t state) } } -/* Called when encountering a taskwait directive. */ +/* Called when encountering a taskwait directive. + + Wait for all children of the current task. */ void GOMP_taskwait (void) @@ -812,8 +1166,7 @@ GOMP_taskwait (void) { child_task = task->children; cancelled - = gomp_task_run_pre (child_task, task, child_task->taskgroup, - team); + = gomp_task_run_pre (child_task, task, team); if (__builtin_expect (cancelled, 0)) { if (to_free) @@ -863,6 +1216,9 @@ GOMP_taskwait (void) finish_cancelled:; size_t new_tasks = gomp_task_run_post_handle_depend (child_task, team); + + /* Remove child_task from children list, and set up the next + sibling to be run. */ child_task->prev_child->next_child = child_task->next_child; child_task->next_child->prev_child = child_task->prev_child; if (task->children == child_task) @@ -872,8 +1228,12 @@ GOMP_taskwait (void) else task->children = NULL; } + /* Orphan all the children of CHILD_TASK. */ gomp_clear_parent (child_task->children); + + /* Remove CHILD_TASK from its taskgroup. */ gomp_task_run_post_remove_taskgroup (child_task); + to_free = child_task; child_task = NULL; team->task_count--; @@ -889,9 +1249,11 @@ GOMP_taskwait (void) } /* This is like GOMP_taskwait, but we only wait for tasks that the - upcoming task depends on. */ + upcoming task depends on. -static void + DEPEND is as in GOMP_task. */ + +void gomp_task_maybe_wait_for_dependencies (void **depend) { struct gomp_thread *thr = gomp_thread (); @@ -923,11 +1285,33 @@ gomp_task_maybe_wait_for_dependencies (void **depend) { tsk->parent_depends_on = true; ++num_awaited; + /* If a task we need to wait for is not already + running and is ready to be scheduled, move it to + front, so that we run it as soon as possible. + + We rearrange the children queue such that all + parent_depends_on tasks are first, and + last_parent_depends_on points to the last such task + we rearranged. For example, given the following + children where PD[123] are the parent_depends_on + tasks: + + task->children + | + V + C1 -> C2 -> C3 -> PD1 -> PD2 -> PD3 -> C4 + + We rearrange such that: + + task->children + | +--- last_parent_depends_on + | | + V V + PD1 -> PD2 -> PD3 -> C1 -> C2 -> C3 -> C4 + */ + if (tsk->num_dependees == 0 && tsk->kind == GOMP_TASK_WAITING) { - /* If a task we need to wait for is not already - running and is ready to be scheduled, move it - to front, so that we run it as soon as possible. */ if (last_parent_depends_on) { tsk->prev_child->next_child = tsk->next_child; @@ -941,8 +1325,8 @@ gomp_task_maybe_wait_for_dependencies (void **depend) { tsk->prev_child->next_child = tsk->next_child; tsk->next_child->prev_child = tsk->prev_child; - tsk->prev_child = task->children; - tsk->next_child = task->children->next_child; + tsk->prev_child = task->children->prev_child; + tsk->next_child = task->children; task->children = tsk; tsk->prev_child->next_child = tsk; tsk->next_child->prev_child = tsk; @@ -983,8 +1367,7 @@ gomp_task_maybe_wait_for_dependencies (void **depend) { child_task = task->children; cancelled - = gomp_task_run_pre (child_task, task, child_task->taskgroup, - team); + = gomp_task_run_pre (child_task, task, team); if (__builtin_expect (cancelled, 0)) { if (to_free) @@ -1028,6 +1411,8 @@ gomp_task_maybe_wait_for_dependencies (void **depend) = gomp_task_run_post_handle_depend (child_task, team); if (child_task->parent_depends_on) --taskwait.n_depend; + + /* Remove child_task from sibling list. */ child_task->prev_child->next_child = child_task->next_child; child_task->next_child->prev_child = child_task->prev_child; if (task->children == child_task) @@ -1037,6 +1422,7 @@ gomp_task_maybe_wait_for_dependencies (void **depend) else task->children = NULL; } + gomp_clear_parent (child_task->children); gomp_task_run_post_remove_taskgroup (child_task); to_free = child_task; @@ -1070,7 +1456,7 @@ GOMP_taskgroup_start (void) struct gomp_taskgroup *taskgroup; /* If team is NULL, all tasks are executed as - GOMP_TASK_IFFALSE tasks and thus all children tasks of + GOMP_TASK_UNDEFERRED tasks and thus all children tasks of taskgroup and their descendant tasks will be finished by the time GOMP_taskgroup_end is called. */ if (team == NULL) @@ -1137,8 +1523,7 @@ GOMP_taskgroup_end (void) if (child_task->kind == GOMP_TASK_WAITING) { cancelled - = gomp_task_run_pre (child_task, child_task->parent, taskgroup, - team); + = gomp_task_run_pre (child_task, child_task->parent, team); if (__builtin_expect (cancelled, 0)) { if (to_free) diff --git a/libgomp/taskloop.c b/libgomp/taskloop.c new file mode 100644 index 00000000000..f57a5a16ef2 --- /dev/null +++ b/libgomp/taskloop.c @@ -0,0 +1,363 @@ +/* Copyright (C) 2015 Free Software Foundation, Inc. + Contributed by Jakub Jelinek . + + This file is part of the GNU Offloading and Multi Processing Library + (libgomp). + + Libgomp is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + 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 General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +/* This file handles the taskloop construct. It is included twice, once + for the long and once for unsigned long long variant. */ + +/* Called when encountering an explicit task directive. If IF_CLAUSE is + false, then we must not delay in executing the task. If UNTIED is true, + then the task may be executed by any member of the team. */ + +void +GOMP_taskloop (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *), + long arg_size, long arg_align, unsigned flags, + unsigned long num_tasks, int priority, + TYPE start, TYPE end, TYPE step) +{ + struct gomp_thread *thr = gomp_thread (); + struct gomp_team *team = thr->ts.team; + +#ifdef HAVE_BROKEN_POSIX_SEMAPHORES + /* If pthread_mutex_* is used for omp_*lock*, then each task must be + tied to one thread all the time. This means UNTIED tasks must be + tied and if CPYFN is non-NULL IF(0) must be forced, as CPYFN + might be running on different thread than FN. */ + if (cpyfn) + flags &= ~GOMP_TASK_FLAG_IF; + flags &= ~GOMP_TASK_FLAG_UNTIED; +#endif + + /* If parallel or taskgroup has been cancelled, don't start new tasks. */ + if (team && gomp_team_barrier_cancelled (&team->barrier)) + return; + +#ifdef TYPE_is_long + TYPE s = step; + if (step > 0) + { + if (start >= end) + return; + s--; + } + else + { + if (start <= end) + return; + s++; + } + UTYPE n = (end - start + s) / step; +#else + UTYPE n; + if (flags & GOMP_TASK_FLAG_UP) + { + if (start >= end) + return; + n = (end - start + step - 1) / step; + } + else + { + if (start <= end) + return; + n = (start - end - step - 1) / -step; + } +#endif + + TYPE task_step = step; + unsigned long nfirst = n; + if (flags & GOMP_TASK_FLAG_GRAINSIZE) + { + unsigned long grainsize = num_tasks; +#ifdef TYPE_is_long + num_tasks = n / grainsize; +#else + UTYPE ndiv = n / grainsize; + num_tasks = ndiv; + if (num_tasks != ndiv) + num_tasks = ~0UL; +#endif + if (num_tasks <= 1) + { + num_tasks = 1; + task_step = end - start; + } + else if (num_tasks >= grainsize +#ifndef TYPE_is_long + && num_tasks != ~0UL +#endif + ) + { + UTYPE mul = num_tasks * grainsize; + task_step = (TYPE) grainsize * step; + if (mul != n) + { + task_step += step; + nfirst = n - mul - 1; + } + } + else + { + UTYPE div = n / num_tasks; + UTYPE mod = n % num_tasks; + task_step = (TYPE) div * step; + if (mod) + { + task_step += step; + nfirst = mod - 1; + } + } + } + else + { + if (num_tasks == 0) + num_tasks = team ? team->nthreads : 1; + if (num_tasks >= n) + num_tasks = n; + else + { + UTYPE div = n / num_tasks; + UTYPE mod = n % num_tasks; + task_step = (TYPE) div * step; + if (mod) + { + task_step += step; + nfirst = mod - 1; + } + } + } + + if (flags & GOMP_TASK_FLAG_NOGROUP) + { + if (thr->task && thr->task->taskgroup && thr->task->taskgroup->cancelled) + return; + } + else + ialias_call (GOMP_taskgroup_start) (); + + /* FIXME, use priority. */ + (void) priority; + + if ((flags & GOMP_TASK_FLAG_IF) == 0 || team == NULL + || (thr->task && thr->task->final_task) + || team->task_count + num_tasks > 64 * team->nthreads) + { + unsigned long i; + if (__builtin_expect (cpyfn != NULL, 0)) + { + struct gomp_task task[num_tasks]; + struct gomp_task *parent = thr->task; + arg_size = (arg_size + arg_align - 1) & ~(arg_align - 1); + char buf[num_tasks * arg_size + arg_align - 1]; + char *arg = (char *) (((uintptr_t) buf + arg_align - 1) + & ~(uintptr_t) (arg_align - 1)); + char *orig_arg = arg; + for (i = 0; i < num_tasks; i++) + { + gomp_init_task (&task[i], parent, gomp_icv (false)); + task[i].kind = GOMP_TASK_UNDEFERRED; + task[i].final_task = (thr->task && thr->task->final_task) + || (flags & GOMP_TASK_FLAG_FINAL); + if (thr->task) + { + task[i].in_tied_task = thr->task->in_tied_task; + task[i].taskgroup = thr->task->taskgroup; + } + thr->task = &task[i]; + cpyfn (arg, data); + arg += arg_size; + } + arg = orig_arg; + for (i = 0; i < num_tasks; i++) + { + thr->task = &task[i]; + ((TYPE *)arg)[0] = start; + start += task_step; + ((TYPE *)arg)[1] = start; + if (i == nfirst) + task_step -= step; + fn (arg); + arg += arg_size; + if (task[i].children != NULL) + { + gomp_mutex_lock (&team->task_lock); + gomp_clear_parent (task[i].children); + gomp_mutex_unlock (&team->task_lock); + } + gomp_end_task (); + } + } + else + for (i = 0; i < num_tasks; i++) + { + struct gomp_task task; + + gomp_init_task (&task, thr->task, gomp_icv (false)); + task.kind = GOMP_TASK_UNDEFERRED; + task.final_task = (thr->task && thr->task->final_task) + || (flags & GOMP_TASK_FLAG_FINAL); + if (thr->task) + { + task.in_tied_task = thr->task->in_tied_task; + task.taskgroup = thr->task->taskgroup; + } + thr->task = &task; + ((TYPE *)data)[0] = start; + start += task_step; + ((TYPE *)data)[1] = start; + if (i == nfirst) + task_step -= step; + fn (data); + if (task.children != NULL) + { + gomp_mutex_lock (&team->task_lock); + gomp_clear_parent (task.children); + gomp_mutex_unlock (&team->task_lock); + } + gomp_end_task (); + } + } + else + { + struct gomp_task *tasks[num_tasks]; + struct gomp_task *parent = thr->task; + struct gomp_taskgroup *taskgroup = parent->taskgroup; + char *arg; + int do_wake; + unsigned long i; + + for (i = 0; i < num_tasks; i++) + { + struct gomp_task *task + = gomp_malloc (sizeof (*task) + arg_size + arg_align - 1); + tasks[i] = task; + arg = (char *) (((uintptr_t) (task + 1) + arg_align - 1) + & ~(uintptr_t) (arg_align - 1)); + gomp_init_task (task, parent, gomp_icv (false)); + task->kind = GOMP_TASK_UNDEFERRED; + task->in_tied_task = parent->in_tied_task; + task->taskgroup = taskgroup; + thr->task = task; + if (cpyfn) + { + cpyfn (arg, data); + task->copy_ctors_done = true; + } + else + memcpy (arg, data, arg_size); + ((TYPE *)arg)[0] = start; + start += task_step; + ((TYPE *)arg)[1] = start; + if (i == nfirst) + task_step -= step; + thr->task = parent; + task->kind = GOMP_TASK_WAITING; + task->fn = fn; + task->fn_data = arg; + task->final_task = (flags & GOMP_TASK_FLAG_FINAL) >> 1; + } + gomp_mutex_lock (&team->task_lock); + /* If parallel or taskgroup has been cancelled, don't start new + tasks. */ + if (__builtin_expect ((gomp_team_barrier_cancelled (&team->barrier) + || (taskgroup && taskgroup->cancelled)) + && cpyfn == NULL, 0)) + { + gomp_mutex_unlock (&team->task_lock); + for (i = 0; i < num_tasks; i++) + { + gomp_finish_task (tasks[i]); + free (tasks[i]); + } + if ((flags & GOMP_TASK_FLAG_NOGROUP) == 0) + ialias_call (GOMP_taskgroup_end) (); + return; + } + if (taskgroup) + taskgroup->num_children += num_tasks; + for (i = 0; i < num_tasks; i++) + { + struct gomp_task *task = tasks[i]; + if (parent->children) + { + task->next_child = parent->children; + task->prev_child = parent->children->prev_child; + task->next_child->prev_child = task; + task->prev_child->next_child = task; + } + else + { + task->next_child = task; + task->prev_child = task; + } + parent->children = task; + if (taskgroup) + { + if (taskgroup->children) + { + task->next_taskgroup = taskgroup->children; + task->prev_taskgroup = taskgroup->children->prev_taskgroup; + task->next_taskgroup->prev_taskgroup = task; + task->prev_taskgroup->next_taskgroup = task; + } + else + { + task->next_taskgroup = task; + task->prev_taskgroup = task; + } + taskgroup->children = task; + } + if (team->task_queue) + { + task->next_queue = team->task_queue; + task->prev_queue = team->task_queue->prev_queue; + task->next_queue->prev_queue = task; + task->prev_queue->next_queue = task; + } + else + { + task->next_queue = task; + task->prev_queue = task; + team->task_queue = task; + } + ++team->task_count; + ++team->task_queued_count; + } + gomp_team_barrier_set_task_pending (&team->barrier); + if (team->task_running_count + !parent->in_tied_task + < team->nthreads) + { + do_wake = team->nthreads - team->task_running_count + - !parent->in_tied_task; + if ((unsigned long) do_wake > num_tasks) + do_wake = num_tasks; + } + else + do_wake = 0; + gomp_mutex_unlock (&team->task_lock); + if (do_wake) + gomp_team_barrier_wake (&team->barrier, do_wake); + } + if ((flags & GOMP_TASK_FLAG_NOGROUP) == 0) + ialias_call (GOMP_taskgroup_end) (); +} diff --git a/libgomp/testsuite/lib/libgomp.exp b/libgomp/testsuite/lib/libgomp.exp index 1040c29e0eb..6dc1e8ef3ca 100644 --- a/libgomp/testsuite/lib/libgomp.exp +++ b/libgomp/testsuite/lib/libgomp.exp @@ -321,6 +321,19 @@ proc check_effective_target_offload_device { } { } ] } +# Return 1 if offload device is available and it has non-shared address space. +proc check_effective_target_offload_device_nonshared_as { } { + return [check_runtime_nocache offload_device_nonshared_as { + int main () + { + int a = 8; + #pragma omp target map(to: a) + a++; + return a != 8; + } + } ] +} + # Return 1 if at least one nvidia board is present. proc check_effective_target_openacc_nvidia_accel_present { } { diff --git a/libgomp/testsuite/libgomp.c++/ctor-13.C b/libgomp/testsuite/libgomp.c++/ctor-13.C new file mode 100644 index 00000000000..8c7a09f315d --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/ctor-13.C @@ -0,0 +1,242 @@ +// { dg-do run } + +#include +#include + +struct B +{ + static int ic, dc, xc, ac, cc; + + B(); + B(const B &); + ~B(); + B& operator=(const B &); + void doit(); + static void clear(); +}; + +int B::ic; +int B::dc; +int B::xc; +int B::cc; +int B::ac; + +B::B() +{ + #pragma omp atomic + ic++; +} + +B::~B() +{ + #pragma omp atomic + dc++; +} + +B::B(const B &) +{ + #pragma omp atomic + cc++; +} + +B& B::operator=(const B &) +{ + #pragma omp atomic + ac++; + return *this; +} + +void B::doit() +{ + #pragma omp atomic + xc++; +} + +void B::clear() +{ + ic = 0; + dc = 0; + cc = 0; + ac = 0; + xc = 0; +} + +static int n; + +void f1(B &a) +{ + B b; + B &c = b; + #pragma omp parallel default(none) private(a, c) shared (n) + { + #pragma omp master + n = omp_get_num_threads (); + a.doit(); + c.doit(); + } +} + +void f2(B &a) +{ + B b; + B &c = b; + #pragma omp parallel default(none) firstprivate(a, c) shared(n) + { + #pragma omp master + n = omp_get_num_threads (); + a.doit(); + c.doit(); + } +} + +void f3(B &a) +{ + B b; + B &c = b; + #pragma omp parallel default(none) shared(n, a, c) + { + #pragma omp master + n = omp_get_num_threads (); + #pragma omp for lastprivate (a, c) + for (int i = 0; i < omp_get_num_threads (); i++) + { + a.doit(); + c.doit(); + } + } +} + +void f4() +{ + B b; + B &c = b; + #pragma omp parallel default(none) private (c) shared (n) + { + B d; + B &e = d; + #pragma omp single copyprivate (c, e) + { + c.doit(); + e.doit(); + } + c.doit(); + e.doit(); + } +} + +void f5(B (&a)[2]) +{ + B b[2]; + B (&c)[2] = b; + #pragma omp parallel default(none) private(a, c) shared (n) + { + #pragma omp master + n = omp_get_num_threads (); + a[0].doit(); + a[1].doit(); + c[0].doit(); + c[1].doit(); + } +} + +void f6(B (&a)[2]) +{ + B b[2]; + B (&c)[2] = b; + #pragma omp parallel default(none) firstprivate(a, c) shared (n) + { + #pragma omp master + n = omp_get_num_threads (); + a[0].doit(); + a[1].doit(); + c[0].doit(); + c[1].doit(); + } +} + +void f7(B (&a)[2]) +{ + B b[2]; + B (&c)[2] = b; + #pragma omp parallel default(none) shared(n, a, c) + { + #pragma omp master + n = omp_get_num_threads (); + #pragma omp for lastprivate (a, c) + for (int i = 0; i < omp_get_num_threads (); i++) + { + a[0].doit(); + a[1].doit(); + c[0].doit(); + c[1].doit(); + } + } +} + +void f8() +{ + B b[2]; + B (&c)[2] = b; + #pragma omp parallel default(none) private (c) shared (n) + { + B d[2]; + B (&e)[2] = d; + #pragma omp single copyprivate (c, e) + { + c[0].doit(); + c[1].doit(); + e[0].doit(); + e[1].doit(); + } + c[0].doit(); + c[1].doit(); + e[0].doit(); + e[1].doit(); + } +} + +int main() +{ + { + B a; + f1(a); + } + assert (B::xc == 2*n && B::ic == 2*n+2 && B::dc == 2*n+2 && B::ac == 0 && B::cc == 0); + B::clear(); + { + B a; + f2(a); + } + assert (B::xc == 2*n && B::ic == 2 && B::dc == 2*n+2 && B::ac == 0 && B::cc == 2*n); + B::clear(); + { + B a; + f3(a); + } + assert (B::xc == 2*n && B::ic == 2*n+2 && B::dc == 2*n+2 && B::ac == 2 && B::cc == 0); + B::clear(); + f4(); + assert (B::xc == 2*n+2 && B::ic == 2*n+1 && B::dc == 2*n+1 && B::ac == 2*n-2 && B::cc == 0); + B::clear(); + { + B a[2]; + f5(a); + } + assert (B::xc == 4*n && B::ic == 4*n+4 && B::dc == 4*n+4 && B::ac == 0 && B::cc == 0); + B::clear(); + { + B a[2]; + f6(a); + } + assert (B::xc == 4*n && B::ic == 4 && B::dc == 4*n+4 && B::ac == 0 && B::cc == 4*n); + B::clear(); + { + B a[2]; + f7(a); + } + assert (B::xc == 4*n && B::ic == 4*n+4 && B::dc == 4*n+4 && B::ac == 4 && B::cc == 0); + B::clear(); + f8(); + assert (B::xc == 4*n+4 && B::ic == 4*n+2 && B::dc == 4*n+2 && B::ac == 4*n-4 && B::cc == 0); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/doacross-1.C b/libgomp/testsuite/libgomp.c++/doacross-1.C new file mode 100644 index 00000000000..bc53ee6e8a2 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/doacross-1.C @@ -0,0 +1,294 @@ +// { dg-do run } + +typedef __PTRDIFF_TYPE__ ptrdiff_t; +extern "C" void abort (); + +template +class I +{ +public: + typedef ptrdiff_t difference_type; + I (); + ~I (); + I (T *); + I (const I &); + T &operator * (); + T *operator -> (); + T &operator [] (const difference_type &) const; + I &operator = (const I &); + I &operator ++ (); + I operator ++ (int); + I &operator -- (); + I operator -- (int); + I &operator += (const difference_type &); + I &operator -= (const difference_type &); + I operator + (const difference_type &) const; + I operator - (const difference_type &) const; + template friend bool operator == (I &, I &); + template friend bool operator == (const I &, const I &); + template friend bool operator < (I &, I &); + template friend bool operator < (const I &, const I &); + template friend bool operator <= (I &, I &); + template friend bool operator <= (const I &, const I &); + template friend bool operator > (I &, I &); + template friend bool operator > (const I &, const I &); + template friend bool operator >= (I &, I &); + template friend bool operator >= (const I &, const I &); + template friend typename I::difference_type operator - (I &, I &); + template friend typename I::difference_type operator - (const I &, const I &); + template friend I operator + (typename I::difference_type , const I &); +private: + T *p; +}; +template I::I () : p (0) {} +template I::~I () {} +template I::I (T *x) : p (x) {} +template I::I (const I &x) : p (x.p) {} +template T &I::operator * () { return *p; } +template T *I::operator -> () { return p; } +template T &I::operator [] (const difference_type &x) const { return p[x]; } +template I &I::operator = (const I &x) { p = x.p; return *this; } +template I &I::operator ++ () { ++p; return *this; } +template I I::operator ++ (int) { return I (p++); } +template I &I::operator -- () { --p; return *this; } +template I I::operator -- (int) { return I (p--); } +template I &I::operator += (const difference_type &x) { p += x; return *this; } +template I &I::operator -= (const difference_type &x) { p -= x; return *this; } +template I I::operator + (const difference_type &x) const { return I (p + x); } +template I I::operator - (const difference_type &x) const { return I (p - x); } +template bool operator == (I &x, I &y) { return x.p == y.p; } +template bool operator == (const I &x, const I &y) { return x.p == y.p; } +template bool operator != (I &x, I &y) { return !(x == y); } +template bool operator != (const I &x, const I &y) { return !(x == y); } +template bool operator < (I &x, I &y) { return x.p < y.p; } +template bool operator < (const I &x, const I &y) { return x.p < y.p; } +template bool operator <= (I &x, I &y) { return x.p <= y.p; } +template bool operator <= (const I &x, const I &y) { return x.p <= y.p; } +template bool operator > (I &x, I &y) { return x.p > y.p; } +template bool operator > (const I &x, const I &y) { return x.p > y.p; } +template bool operator >= (I &x, I &y) { return x.p >= y.p; } +template bool operator >= (const I &x, const I &y) { return x.p >= y.p; } +template typename I::difference_type operator - (I &x, I &y) { return x.p - y.p; } +template typename I::difference_type operator - (const I &x, const I &y) { return x.p - y.p; } +template I operator + (typename I::difference_type x, const I &y) { return I (x + y.p); } + +int results[2048]; + +template +void +baz (I &i, I &j, I &k, T &l) +{ + if (*i < 0 || *i >= 16) + abort (); + if (*j < 0 || *j >= 16) + abort (); + if (*k < 0 || *k >= 16) + abort (); + if (l < 0 || l >= 16) + abort (); + #pragma omp atomic + results[512 * *i + 64 * *j + 8 * *k + l]++; +} + +template +void +baz (T &i, T &j, T &k, T &l) +{ + if (i < 0 || i >= 16) + abort (); + if (j < 0 || j >= 16) + abort (); + if (k < 0 || k >= 16) + abort (); + if (l < 0 || l >= 16) + abort (); + #pragma omp atomic + results[512 * i + 64 * j + 8 * k + l]++; +} + +void +f1 (const I &a, const I &b, const I &c, const I &d, + const I &e, const I &f, int g, int h, + I &r1, I &r2, I &r3) +{ + I i, j, k; + int l; +#pragma omp parallel for ordered(4) lastprivate (i, j, k) schedule(static, 1) + for (i = a; i <= b; i++) + for (j = c; j < d; j++) + for (k = e; k < f; k++) + for (l = g; l < h; l++) + { + #pragma omp ordered depend(sink: i - 1, j, k + 1, l - 2) + baz (i, j, k, l); + if (i > a && k < f - 1 && l > g + 1) + { + int m; + #pragma omp atomic read + m = results[512 * *(i - 1) + 64 * *j + 8 * *(k + 1) + l - 2]; + if (m == 0) + abort (); + } + #pragma omp ordered depend(source) + } + r1 = i; + r2 = j; + r3 = k; +} + +void +f2 (int a, int b, int c, int d, int e, int f, int g, int h, int &r1, int &r2, int &r3) +{ + int i, j, k, l; +#pragma omp parallel for collapse (1) ordered(4) lastprivate (i, j, k) schedule(static, 2) + for (i = a; i <= b; i++) + for (j = c; j < d; j++) + for (k = e; k < f; k++) + for (l = g; l < h; l++) + { + #pragma omp ordered depend(sink: i - 1, j, k + 1, l - 2) + baz (i, j, k, l); + if (i > a && k < f - 1 && l > g + 1) + { + int m; + #pragma omp atomic read + m = results[512 * (i - 1) + 64 * j + 8 * (k + 1) + l - 2]; + if (m == 0) + abort (); + } + #pragma omp ordered depend(source) + } + r1 = i; + r2 = j; + r3 = k; +} + +void +f3 (const I &a, const I &b, const I &c, const I &d, + const I &e, const I &f, int g, int h, + I &r1, I &r2, I &r3) +{ + I i, j, k; + int l; +#pragma omp parallel for collapse (2) ordered(4) lastprivate (i, j, k) schedule(static, 1) + for (i = a; i <= b; i++) + for (j = c; j < d; j++) + for (k = e; k < f; k++) + for (l = g; l < h; l++) + { + #pragma omp ordered depend(sink: i - 1, j, k + 1, l - 2) + baz (i, j, k, l); + if (i > a && k < f - 1 && l > g + 1) + { + int m; + #pragma omp atomic read + m = results[512 * *(i - 1) + 64 * *j + 8 * *(k + 1) + l - 2]; + if (m == 0) + abort (); + } + #pragma omp ordered depend(source) + } + r1 = i; + r2 = j; + r3 = k; +} + +void +f4 (int a, int b, int c, int d, int e, int f, int g, int h, int &r1, int &r2, int &r3) +{ + int i, j, k, l; +#pragma omp parallel for collapse (2) ordered(4) lastprivate (i, j, k) schedule(static, 2) + for (i = a; i <= b; i++) + for (j = c; j < d; j++) + for (k = e; k < f; k++) + for (l = g; l < h; l++) + { + #pragma omp ordered depend(sink: i - 1, j, k + 1, l - 2) + baz (i, j, k, l); + if (i > a && k < f - 1 && l > g + 1) + { + int m; + #pragma omp atomic read + m = results[512 * (i - 1) + 64 * j + 8 * (k + 1) + l - 2]; + if (m == 0) + abort (); + } + #pragma omp ordered depend(source) + } + r1 = i; + r2 = j; + r3 = k; +} + +#define check(expr) \ + for (int i = 0; i < 2048; i++) \ + if (expr) \ + { \ + if (results[i] != 1) \ + abort (); \ + results[i] = 0; \ + } \ + else if (results[i]) \ + abort () + +int +main () +{ + int a[16], s1, s2, s3; + I r1, r2, r3; + for (int i = 0; i < 16; i++) + a[i] = i; + r1 = &a[15]; r2 = &a[15]; r3 = &a[15]; + f1 (&a[1], &a[3], &a[2], &a[5], &a[1], &a[3], 0, 5, r1, r2, r3); + if (*r1 != 4 || *r2 != 5 || *r3 != 3) + abort (); + check ((i / 512) - 1U < 3U && ((i / 64) & 7) - 2U < 3U && ((i / 8) & 7) - 1U < 2U && (i & 7) < 5); + r1 = &a[15]; r2 = &a[15]; r3 = &a[15]; + f1 (&a[1], &a[3], &a[1], &a[4], &a[1], &a[5], 1, 0, r1, r2, r3); + if (*r1 != 4 || *r2 != 4 || *r3 != 5) + abort (); + r1 = &a[15]; r2 = &a[15]; r3 = &a[15]; + f1 (&a[1], &a[3], &a[1], &a[9], &a[7], &a[2], 0, 7, r1, r2, r3); + if (*r1 != 4 || *r2 != 9 || *r3 != 7) + abort (); + s1 = 15; s2 = 15; s3 = 15; + f2 (1, 3, 2, 5, 1, 3, 0, 5, s1, s2, s3); + if (s1 != 4 || s2 != 5 || s3 != 3) + abort (); + check ((i / 512) - 1U < 3U && ((i / 64) & 7) - 2U < 3U && ((i / 8) & 7) - 1U < 2U && (i & 7) < 5); + s1 = 15; s2 = 15; s3 = 15; + f2 (1, 3, 1, 4, 1, 5, 1, 0, s1, s2, s3); + if (s1 != 4 || s2 != 4 || s3 != 5) + abort (); + s1 = 15; s2 = 15; s3 = 15; + f2 (1, 3, 1, 9, 7, 2, 0, 7, s1, s2, s3); + if (s1 != 4 || s2 != 9 || s3 != 7) + abort (); + r1 = &a[15]; r2 = &a[15]; r3 = &a[15]; + f3 (&a[1], &a[3], &a[2], &a[5], &a[1], &a[3], 0, 5, r1, r2, r3); + if (*r1 != 4 || *r2 != 5 || *r3 != 3) + abort (); + check ((i / 512) - 1U < 3U && ((i / 64) & 7) - 2U < 3U && ((i / 8) & 7) - 1U < 2U && (i & 7) < 5); + r1 = &a[15]; r2 = &a[15]; r3 = &a[15]; + f3 (&a[1], &a[3], &a[1], &a[4], &a[1], &a[5], 1, 0, r1, r2, r3); + if (*r1 != 4 || *r2 != 4 || *r3 != 5) + abort (); + r1 = &a[15]; r2 = &a[15]; r3 = &a[15]; + f3 (&a[1], &a[3], &a[1], &a[9], &a[7], &a[2], 0, 7, r1, r2, r3); + if (*r1 != 4 || *r2 != 9 || *r3 != 7) + abort (); + s1 = 15; s2 = 15; s3 = 15; + f4 (1, 3, 2, 5, 1, 3, 0, 5, s1, s2, s3); + if (s1 != 4 || s2 != 5 || s3 != 3) + abort (); + check ((i / 512) - 1U < 3U && ((i / 64) & 7) - 2U < 3U && ((i / 8) & 7) - 1U < 2U && (i & 7) < 5); + s1 = 15; s2 = 15; s3 = 15; + f4 (1, 3, 1, 4, 1, 5, 1, 0, s1, s2, s3); + if (s1 != 4 || s2 != 4 || s3 != 5) + abort (); + s1 = 15; s2 = 15; s3 = 15; + f4 (1, 3, 1, 9, 7, 2, 0, 7, s1, s2, s3); + if (s1 != 4 || s2 != 9 || s3 != 7) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/examples-4/declare_target-2.C b/libgomp/testsuite/libgomp.c++/examples-4/declare_target-2.C index 75276e7c5c6..6d5b5e47990 100644 --- a/libgomp/testsuite/libgomp.c++/examples-4/declare_target-2.C +++ b/libgomp/testsuite/libgomp.c++/examples-4/declare_target-2.C @@ -1,5 +1,5 @@ // { dg-do run } -// { dg-require-effective-target offload_device } +// { dg-require-effective-target offload_device_nonshared_as } #include diff --git a/libgomp/testsuite/libgomp.c++/for-12.C b/libgomp/testsuite/libgomp.c++/for-12.C new file mode 100644 index 00000000000..ea32192e45d --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/for-12.C @@ -0,0 +1,42 @@ +/* { dg-options "-fopenmp" } */ + +extern "C" void abort (void); + +#define M(x, y, z) O(x, y, z) +#define O(x, y, z) x ## _ ## y ## _ ## z + +#define F taskloop +#define G taskloop +#define S +#define N(x) M(x, G, normal) +#include "../libgomp.c/for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F taskloop simd +#define G taskloop_simd +#define S +#define N(x) M(x, G, normal) +#include "../libgomp.c/for-2.h" +#undef S +#undef N +#undef F +#undef G + +int +main () +{ + int err = 0; + #pragma omp parallel reduction(|:err) + #pragma omp single + { + if (test_taskloop_normal () + || test_taskloop_simd_normal ()) + err = 1; + } + if (err) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/for-13.C b/libgomp/testsuite/libgomp.c++/for-13.C new file mode 100644 index 00000000000..ac1601a766f --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/for-13.C @@ -0,0 +1,151 @@ +extern "C" void abort (); + +#define M(x, y, z) O(x, y, z) +#define O(x, y, z) x ## _ ## y ## _ ## z + +#pragma omp declare target + +#define F for +#define G f +#define S +#define N(x) M(x, G, normal) +#include "../libgomp.c/for-2.h" +#undef S +#undef N +#undef F +#undef G + +#pragma omp end declare target + +#undef OMPFROM +#undef OMPTO +#define DO_PRAGMA(x) _Pragma (#x) +#define OMPFROM(v) DO_PRAGMA (omp target update from(v)) +#define OMPTO(v) DO_PRAGMA (omp target update to(v)) + +#define F target parallel for +#define G tpf +#include "../libgomp.c/for-1.h" +#undef F +#undef G + +#define F target simd +#define G t_simd +#define S +#define N(x) M(x, G, normal) +#include "../libgomp.c/for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F target parallel for simd +#define G tpf_simd +#include "../libgomp.c/for-1.h" +#undef F +#undef G + +#define F target teams distribute +#define G ttd +#define S +#define N(x) M(x, G, normal) +#include "../libgomp.c/for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F target teams distribute +#define G ttd_ds128 +#define S dist_schedule(static, 128) +#define N(x) M(x, G, normal) +#include "../libgomp.c/for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F target teams distribute simd +#define G ttds +#define S +#define N(x) M(x, G, normal) +#include "../libgomp.c/for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F target teams distribute simd +#define G ttds_ds128 +#define S dist_schedule(static, 128) +#define N(x) M(x, G, normal) +#include "../libgomp.c/for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F target teams distribute parallel for +#define G ttdpf +#include "../libgomp.c/for-1.h" +#undef F +#undef G + +#define F target teams distribute parallel for dist_schedule(static, 128) +#define G ttdpf_ds128 +#include "../libgomp.c/for-1.h" +#undef F +#undef G + +#define F target teams distribute parallel for simd +#define G ttdpfs +#include "../libgomp.c/for-1.h" +#undef F +#undef G + +#define F target teams distribute parallel for simd dist_schedule(static, 128) +#define G ttdpfs_ds128 +#include "../libgomp.c/for-1.h" +#undef F +#undef G + +int +main () +{ + if (test_tpf_static () + || test_tpf_static32 () + || test_tpf_auto () + || test_tpf_guided32 () + || test_tpf_runtime () + || test_t_simd_normal () + || test_tpf_simd_static () + || test_tpf_simd_static32 () + || test_tpf_simd_auto () + || test_tpf_simd_guided32 () + || test_tpf_simd_runtime () + || test_ttd_normal () + || test_ttd_ds128_normal () + || test_ttds_normal () + || test_ttds_ds128_normal () + || test_ttdpf_static () + || test_ttdpf_static32 () + || test_ttdpf_auto () + || test_ttdpf_guided32 () + || test_ttdpf_runtime () + || test_ttdpf_ds128_static () + || test_ttdpf_ds128_static32 () + || test_ttdpf_ds128_auto () + || test_ttdpf_ds128_guided32 () + || test_ttdpf_ds128_runtime () + || test_ttdpfs_static () + || test_ttdpfs_static32 () + || test_ttdpfs_auto () + || test_ttdpfs_guided32 () + || test_ttdpfs_runtime () + || test_ttdpfs_ds128_static () + || test_ttdpfs_ds128_static32 () + || test_ttdpfs_ds128_auto () + || test_ttdpfs_ds128_guided32 () + || test_ttdpfs_ds128_runtime ()) + abort (); +} diff --git a/libgomp/testsuite/libgomp.c++/for-14.C b/libgomp/testsuite/libgomp.c++/for-14.C new file mode 100644 index 00000000000..7738473b601 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/for-14.C @@ -0,0 +1,120 @@ +extern "C" void abort (); + +#define M(x, y, z) O(x, y, z) +#define O(x, y, z) x ## _ ## y ## _ ## z + +#pragma omp declare target + +#define F for +#define G f +#define S +#define N(x) M(x, G, normal) +#include "../libgomp.c/for-2.h" +#undef S +#undef N +#undef F +#undef G + +#pragma omp end declare target + +#undef OMPTGT +#undef OMPFROM +#undef OMPTO +#define DO_PRAGMA(x) _Pragma (#x) +#define OMPTGT DO_PRAGMA (omp target) +#define OMPFROM(v) DO_PRAGMA (omp target update from(v)) +#define OMPTO(v) DO_PRAGMA (omp target update to(v)) + +#define F teams distribute +#define G td +#define S +#define N(x) M(x, G, normal) +#include "../libgomp.c/for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F teams distribute +#define G td_ds128 +#define S dist_schedule(static, 128) +#define N(x) M(x, G, normal) +#include "../libgomp.c/for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F teams distribute simd +#define G tds +#define S +#define N(x) M(x, G, normal) +#include "../libgomp.c/for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F teams distribute simd +#define G tds_ds128 +#define S dist_schedule(static, 128) +#define N(x) M(x, G, normal) +#include "../libgomp.c/for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F teams distribute parallel for +#define G tdpf +#include "../libgomp.c/for-1.h" +#undef F +#undef G + +#define F teams distribute parallel for dist_schedule(static, 128) +#define G tdpf_ds128 +#include "../libgomp.c/for-1.h" +#undef F +#undef G + +#define F teams distribute parallel for simd +#define G tdpfs +#include "../libgomp.c/for-1.h" +#undef F +#undef G + +#define F teams distribute parallel for simd dist_schedule(static, 128) +#define G tdpfs_ds128 +#include "../libgomp.c/for-1.h" +#undef F +#undef G + +int +main () +{ + if (test_td_normal () + || test_td_ds128_normal () + || test_tds_normal () + || test_tds_ds128_normal () + || test_tdpf_static () + || test_tdpf_static32 () + || test_tdpf_auto () + || test_tdpf_guided32 () + || test_tdpf_runtime () + || test_tdpf_ds128_static () + || test_tdpf_ds128_static32 () + || test_tdpf_ds128_auto () + || test_tdpf_ds128_guided32 () + || test_tdpf_ds128_runtime () + || test_tdpfs_static () + || test_tdpfs_static32 () + || test_tdpfs_auto () + || test_tdpfs_guided32 () + || test_tdpfs_runtime () + || test_tdpfs_ds128_static () + || test_tdpfs_ds128_static32 () + || test_tdpfs_ds128_auto () + || test_tdpfs_ds128_guided32 () + || test_tdpfs_ds128_runtime ()) + abort (); +} diff --git a/libgomp/testsuite/libgomp.c++/linear-1.C b/libgomp/testsuite/libgomp.c++/linear-1.C new file mode 100644 index 00000000000..1dd1ffc8939 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/linear-1.C @@ -0,0 +1,268 @@ +int a[256]; + +__attribute__((noinline, noclone)) int +f1 (int i) +{ + #pragma omp parallel for linear (i: 4) + for (int j = 16; j < 64; j++) + { + a[i] = j; + i += 4; + } + return i; +} + +__attribute__((noinline, noclone)) short int & +f2 (short int &i, char k) +{ + #pragma omp parallel for linear (i: k + 1) + for (long j = 16; j < 64; j++) + { + a[i] = j; + i += 4; + } + return i; +} + +template +__attribute__((noinline, noclone)) T +f3 (T i, T k) +{ + #pragma omp parallel for linear (i: k) + for (short j = 16; j < 64; j++) + { + a[i] = j; + i += 4; + } + return i; +} + +template +__attribute__((noinline, noclone)) T & +f4 (T &i) +{ + #pragma omp parallel for linear (i: 4) schedule(static, 3) + for (int j = 16; j < 64; j++) + { + a[i] = j; + i += 4; + } + return i; +} + +__attribute__((noinline, noclone)) short int +f5 (short int i, char &k) +{ + #pragma omp parallel for linear (i: k + 1) schedule(static, 5) + for (long j = 16; j < 64; j++) + { + a[i] = j; + i += 4; + } + return i; +} + +template +__attribute__((noinline, noclone)) long long int +f6 (long long int i, long long int k) +{ + #pragma omp parallel for linear (i: k) schedule(static, 7) + for (short j = 16; j < 64; j++) + { + a[i] = j; + i += 4; + } + return i; +} + +__attribute__((noinline, noclone)) int +f7 (int &i) +{ + #pragma omp parallel for linear (i: 4) schedule(dynamic, 3) + for (int j = 16; j < 64; j++) + { + a[i] = j; + i += 4; + } + return i; +} + +__attribute__((noinline, noclone)) short int +f8 (short int i, char k) +{ + #pragma omp parallel for linear (i: k + 1) schedule(dynamic, 5) + for (long j = 16; j < 64; j++) + { + a[i] = j; + i += 4; + } + return i; +} + +__attribute__((noinline, noclone)) long long int +f9 (long long int i, long long int k) +{ + #pragma omp parallel for linear (i: k) schedule(dynamic, 7) + for (short j = 16; j < 64; j++) + { + a[i] = j; + i += 4; + } + return i; +} + +template +__attribute__((noinline, noclone)) T & +f10 (T &i, long &step) +{ + #pragma omp parallel for linear (i: 4) + for (int j = 16; j < 112; j += step) + { + a[i] = j / 2 + 8; + i += 4; + } + return i; +} + +__attribute__((noinline, noclone)) short int +f11 (short int i, char k, char step) +{ + #pragma omp parallel for linear (i: k + 1) + for (long j = 16; j < 112; j += step) + { + a[i] = j / 2 + 8; + i += 4; + } + return i; +} + +__attribute__((noinline, noclone)) long long int +f12 (long long int i, long long int k, int step) +{ + #pragma omp parallel for linear (i: k) + for (short j = 16; j < 112; j += step) + { + a[i] = j / 2 + 8; + i += 4; + } + return i; +} + +__attribute__((noinline, noclone)) int +f13 (int &i, long long int step) +{ + #pragma omp parallel for linear (i: 4) schedule(static, 3) + for (int j = 16; j < 112; j += step) + { + a[i] = j / 2 + 8; + i += 4; + } + return i; +} + +__attribute__((noinline, noclone)) short int +f14 (short int &i, char &k, int &step) +{ + #pragma omp parallel for linear (i: k + 1) schedule(static, 5) + for (long j = 16; j < 112; j += step) + { + a[i] = j / 2 + 8; + i += 4; + } + return i; +} + +template +__attribute__((noinline, noclone)) long long int +f15 (long long int i, long long int k, long int step) +{ + #pragma omp parallel for linear (i: k) schedule(static, 7) + for (short j = 16; j < 112; j += step) + { + a[i] = j / 2 + 8; + i += 4; + } + return i; +} + +__attribute__((noinline, noclone)) int +f16 (int i, long long int step) +{ + #pragma omp parallel for linear (i: 4) schedule(dynamic, 3) + for (int j = 16; j < 112; j += step) + { + a[i] = j / 2 + 8; + i += 4; + } + return i; +} + +__attribute__((noinline, noclone)) short int +f17 (short int i, char k, int step) +{ + #pragma omp parallel for linear (i: k + 1) schedule(dynamic, 5) + for (long j = 16; j < 112; j += step) + { + a[i] = j / 2 + 8; + i += 4; + } + return i; +} + +template +__attribute__((noinline, noclone)) T +f18 (T i, T k, long int step) +{ + #pragma omp parallel for linear (i: k) schedule(dynamic, 7) + for (short j = 16; j < 112; j += step) + { + a[i] = j / 2 + 8; + i += 4; + } + return i; +} + +int +main () +{ +#define TEST(x) \ + if (x != 8 + 48 * 4) \ + __builtin_abort (); \ + for (int i = 0; i < 256; i++) \ + if (a[i] != (((i & 3) == 0 && i >= 8 \ + && i < 8 + 48 * 4) \ + ? ((i - 8) / 4) + 16 : 0)) \ + __builtin_abort (); \ + __builtin_memset (a, 0, sizeof (a)) + TEST (f1 (8)); + short int vs = 8; + TEST (f2 (vs, 3)); + TEST (f3 (8LL, 4LL)); + int vi = 8; + TEST (f4 (vi)); + char vk = 3; + TEST (f5 (8, vk)); + TEST (f6<7> (8LL, 4LL)); + vi = 8; + TEST (f7 (vi)); + TEST (f8 (8, 3)); + TEST (f9 (8LL, 4LL)); + vi = 8; + long vl = 2; + TEST (f10 (vi, vl)); + TEST (f11 (8, 3, 2)); + TEST (f12 (8LL, 4LL, 2)); + vi = 8; + TEST (f13 (vi, 2)); + vs = 8; + vk = 3; + vi = 2; + TEST (f14 (vs, vk, vi)); + TEST (f15<9> (8LL, 4LL, 2)); + TEST (f16 (8, 2)); + TEST (f17 (8, 3, 2)); + long long int vll1 = 8LL; + long long int vll2 = 4LL; + TEST (f18 (vll1, vll2, 2)); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/member-1.C b/libgomp/testsuite/libgomp.c++/member-1.C new file mode 100644 index 00000000000..d2d0c5b2667 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/member-1.C @@ -0,0 +1,206 @@ +// { dg-do run } + +#include + +struct R { R () {}; ~R () {}; int r; }; +struct T { T () {}; virtual ~T () {}; int t; }; +int c; +struct A : public R, virtual public T { A () : b(c) {} int a; int &b; void m1 (); }; + +void +take (int &a, int &b, int &c, int &d) +{ + asm volatile ("" : : "g" (&a), "g" (&b), "g" (&c), "g" (&d) : "memory"); +} + +void +A::m1 () +{ + #pragma omp parallel private (a, r, T::t, A::b) + { + int q = omp_get_thread_num (); + a = q; + r = 2 * q; + t = 3 * q; + b = 4 * q; + take (a, r, t, b); + #pragma omp barrier + if (A::a != q || R::r != 2 * q || T::t != 3 * q || A::b != 4 * q) + __builtin_abort (); + } + a = 7; + r = 8; + t = 9; + b = 10; + #pragma omp parallel firstprivate (A::a, R::r, t, b) + { + int q = omp_get_thread_num (); + take (A::a, R::r, T::t, A::b); + if (a != 7 || r != 8 || t != 9 || b != 10) + __builtin_abort (); + A::a = 5 * q; + R::r = 6 * q; + T::t = 7 * q; + A::b = 8 * q; + take (a, r, t, b); + #pragma omp barrier + if (a != 5 * q || r != 6 * q || t != 7 * q || b != 8 * q) + __builtin_abort (); + } + bool f = false; + a = -5; + b = -4; + r = -3; + t = -2; + int n; + #pragma omp parallel for firstprivate (a, T::t, b, f) lastprivate (A::a, r, t, n) + for (int i = 0; i < omp_get_num_threads (); i++) + { + int q = omp_get_thread_num (); + if (!f) + { + if (A::a != -5 || A::b != -4 || T::t != -2) + __builtin_abort (); + } + else if (a != q || b != 2 * q || r != 3 * q || t != 4 * q) + __builtin_abort (); + take (a, r, t, b); + A::a = q; + A::b = 2 * q; + R::r = 3 * q; + T::t = 4 * q; + n = q; + f = true; + } + if (a != n || r != 3 * n || T::t != 4 * n) + __builtin_abort (); + b = 8; + #pragma omp parallel + #pragma omp single + for (int i = 0; i < 5; i++) + #pragma omp task firstprivate (t, b, n) private (a, R::r) + { + if (t != 4 * n || b != 8) + __builtin_abort (); + a = 9; + r = 8; + t = 12; + b = 18; + take (a, r, t, b); + if (a != 9 || r != 8 || t != 12 || b != 18) + __builtin_abort (); + } + a = 1; + b = 2; + R::r = 3; + t = 4; + #pragma omp parallel private (f) + { + f = false; + #pragma omp single + #pragma omp taskloop firstprivate (r, T::t, b, f) lastprivate (a, t, b, n) + for (int i = 0; i < 30; i++) + { + int q = omp_get_thread_num (); + if (!f) + { + if (R::r != 3 || A::b != 2 || T::t != 4) + __builtin_abort (); + } + else if (a != 7 * q || b != 8 * q || r != 9 * q || t != 10 * q) + __builtin_abort (); + take (a, r, t, b); + A::a = 7 * q; + A::b = 8 * q; + R::r = 9 * q; + T::t = 10 * q; + n = q; + f = true; + } + } + if (a != 7 * n || b != 8 * n || t != 10 * n) + __builtin_abort (); + a = 1; + b = 2; + R::r = 3; + t = 4; + #pragma omp parallel private (f) + { + f = false; + #pragma omp single + #pragma omp taskloop firstprivate (r, T::t, b, A::a, f) + for (int i = 0; i < 30; i++) + { + int q = omp_get_thread_num (); + if (!f) + { + if (A::a != 1 || R::r != 3 || A::b != 2 || T::t != 4) + __builtin_abort (); + } + else if (a != 7 * q || b != 8 * q || r != 9 * q || t != 10 * q) + __builtin_abort (); + take (a, r, t, b); + A::a = 7 * q; + A::b = 8 * q; + R::r = 9 * q; + T::t = 10 * q; + f = true; + } + } + #pragma omp parallel private (f) + { + f = false; + #pragma omp single + #pragma omp taskloop lastprivate (a, t, b, n) + for (int i = 0; i < 30; i++) + { + int q = omp_get_thread_num (); + if (f && (a != 7 * q || b != 8 * q || r != 9 * q || t != 10 * q)) + __builtin_abort (); + take (a, r, t, b); + A::a = 7 * q; + A::b = 8 * q; + R::r = 9 * q; + T::t = 10 * q; + n = q; + f = true; + } + } + if (a != 7 * n || b != 8 * n || t != 10 * n) + __builtin_abort (); + #pragma omp parallel private (a, T::t, A::b, r) + { + int q = omp_get_thread_num (); + a = q; + b = 2 * q; + r = 3 * q; + t = 4 * q; + take (a, b, r, t); + #pragma omp single copyprivate (A::a, t, b, R::r) + n = q; + if (a != n || b != 2 * n || r != 3 * n || t != 4 * n) + __builtin_abort (); + } + a = 0; + b = 0; + R::r = 0; + t = 0; + #pragma omp parallel for reduction (+: A::a, t, b, R::r) + for (int i = 0; i < 30; i++) + { + a += i; + A::b += 2 * i; + r += 3 * i; + T::t += 4 * i; + take (a, b, r, t); + } + if (A::a != 435 || b != 2 * 435 || R::r != 3 * 435 || t != 4 * 435) + __builtin_abort (); +} + +int +main () +{ + A a; + a.m1 (); +} diff --git a/libgomp/testsuite/libgomp.c++/member-2.C b/libgomp/testsuite/libgomp.c++/member-2.C new file mode 100644 index 00000000000..bb348d8a822 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/member-2.C @@ -0,0 +1,211 @@ +// { dg-do run } + +#include + +int c, d, e; +struct R { R () {}; ~R () {}; int r; }; +template +struct T { T () : t(d) {}; virtual ~T () {}; Q t; }; +template +struct A : public R, virtual public T { A () : b(c), a(e) {} Q a; int &b; void m1 (); }; + +void +take (int &a, int &b, int &c, int &d) +{ + asm volatile ("" : : "g" (&a), "g" (&b), "g" (&c), "g" (&d) : "memory"); +} + +template +void +A::m1 () +{ + #pragma omp parallel private (a, r, T::t, A::b) + { + int q = omp_get_thread_num (); + a = q; + r = 2 * q; + T::t = 3 * q; + b = 4 * q; + take (a, r, T::t, b); + #pragma omp barrier + if (A::a != q || R::r != 2 * q || T::t != 3 * q || A::b != 4 * q) + __builtin_abort (); + } + a = 7; + r = 8; + T::t = 9; + b = 10; + #pragma omp parallel firstprivate (A::a, R::r, T::t, b) + { + int q = omp_get_thread_num (); + take (A::a, R::r, T::t, A::b); + if (a != 7 || r != 8 || T::t != 9 || b != 10) + __builtin_abort (); + A::a = 5 * q; + R::r = 6 * q; + T::t = 7 * q; + A::b = 8 * q; + take (a, r, T::t, b); + #pragma omp barrier + if (a != 5 * q || r != 6 * q || T::t != 7 * q || b != 8 * q) + __builtin_abort (); + } + bool f = false; + a = -5; + b = -4; + r = -3; + T::t = -2; + int n; + #pragma omp parallel for firstprivate (a, T::t, b, f) lastprivate (A::a, r, T::t, n) + for (int i = 0; i < omp_get_num_threads (); i++) + { + int q = omp_get_thread_num (); + if (!f) + { + if (A::a != -5 || A::b != -4 || T::t != -2) + __builtin_abort (); + } + else if (a != q || b != 2 * q || r != 3 * q || T::t != 4 * q) + __builtin_abort (); + take (a, r, T::t, b); + A::a = q; + A::b = 2 * q; + R::r = 3 * q; + T::t = 4 * q; + n = q; + f = true; + } + if (a != n || r != 3 * n || T::t != 4 * n) + __builtin_abort (); + b = 8; + #pragma omp parallel + #pragma omp single + for (int i = 0; i < 5; i++) + #pragma omp task firstprivate (T::t, b, n) private (a, R::r) + { + if (T::t != 4 * n || b != 8) + __builtin_abort (); + a = 9; + r = 8; + T::t = 12; + b = 18; + take (a, r, T::t, b); + if (a != 9 || r != 8 || T::t != 12 || b != 18) + __builtin_abort (); + } + a = 1; + b = 2; + R::r = 3; + T::t = 4; + #pragma omp parallel private (f) + { + f = false; + #pragma omp single + #pragma omp taskloop firstprivate (r, T::t, b, f) lastprivate (a, T::t, b, n) + for (int i = 0; i < 30; i++) + { + int q = omp_get_thread_num (); + if (!f) + { + if (R::r != 3 || A::b != 2 || T::t != 4) + __builtin_abort (); + } + else if (a != 7 * q || b != 8 * q || r != 9 * q || T::t != 10 * q) + __builtin_abort (); + take (a, r, T::t, b); + A::a = 7 * q; + A::b = 8 * q; + R::r = 9 * q; + T::t = 10 * q; + n = q; + f = true; + } + } + if (a != 7 * n || b != 8 * n || T::t != 10 * n) + __builtin_abort (); + a = 1; + b = 2; + R::r = 3; + T::t = 4; + #pragma omp parallel private (f) + { + f = false; + #pragma omp single + #pragma omp taskloop firstprivate (r, T::t, b, A::a, f) + for (int i = 0; i < 30; i++) + { + int q = omp_get_thread_num (); + if (!f) + { + if (A::a != 1 || R::r != 3 || A::b != 2 || T::t != 4) + __builtin_abort (); + } + else if (a != 7 * q || b != 8 * q || r != 9 * q || T::t != 10 * q) + __builtin_abort (); + take (a, r, T::t, b); + A::a = 7 * q; + A::b = 8 * q; + R::r = 9 * q; + T::t = 10 * q; + f = true; + } + } + #pragma omp parallel private (f) + { + f = false; + #pragma omp single + #pragma omp taskloop lastprivate (a, T::t, b, n) + for (int i = 0; i < 30; i++) + { + int q = omp_get_thread_num (); + if (f && (a != 7 * q || b != 8 * q || r != 9 * q || T::t != 10 * q)) + __builtin_abort (); + take (a, r, T::t, b); + A::a = 7 * q; + A::b = 8 * q; + R::r = 9 * q; + T::t = 10 * q; + n = q; + f = true; + } + } + if (a != 7 * n || b != 8 * n || T::t != 10 * n) + __builtin_abort (); + #pragma omp parallel private (a, T::t, A::b, r) + { + int q = omp_get_thread_num (); + a = q; + b = 2 * q; + r = 3 * q; + T::t = 4 * q; + take (a, b, r, T::t); + #pragma omp single copyprivate (A::a, T::t, b, R::r) + n = q; + if (a != n || b != 2 * n || r != 3 * n || T::t != 4 * n) + __builtin_abort (); + } + a = 0; + b = 0; + R::r = 0; + T::t = 0; + #pragma omp parallel for reduction (+: A::a, T::t, b, R::r) + for (int i = 0; i < 30; i++) + { + a += i; + A::b += 2 * i; + r += 3 * i; + T::t += 4 * i; + take (a, b, r, T::t); + } + if (A::a != 435 || b != 2 * 435 || R::r != 3 * 435 || T::t != 4 * 435) + __builtin_abort (); +} + +int +main () +{ + A a; + a.m1 (); + A b; + b.m1 (); +} diff --git a/libgomp/testsuite/libgomp.c++/member-3.C b/libgomp/testsuite/libgomp.c++/member-3.C new file mode 100644 index 00000000000..50bd587d86b --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/member-3.C @@ -0,0 +1,105 @@ +// { dg-do run } + +struct R { R () {}; ~R () {}; int r; }; +struct T { T () {}; virtual ~T () {}; int t; }; +int c; +struct A : public R, virtual public T { A () : b(c) {} int a; int &b; void m1 (); }; +int d[64]; + +void +A::m1 () +{ + r = 0; + #pragma omp parallel for private (a) reduction(|:R::r) + for (a = 0; A::a < 31; a += 2) + r |= (1 << A::a); + if (r != 0x55555555) + __builtin_abort (); + #pragma omp parallel for simd linear (R::r) + for (R::r = 0; r < 32; R::r++) + d[r + 8] |= 1; + for (int i = 0; i < 64; i++) + if (d[i] != ((i >= 8 && i < 32 + 8) ? 1 : 0)) + __builtin_abort (); + #pragma omp parallel for lastprivate (t) + for (T::t = 0; t < 32; t += 3) + d[T::t + 2] |= 2; + if (T::t != 33) + __builtin_abort (); + for (int i = 0; i < 64; i++) + if (d[i] != (((i >= 8 && i < 32 + 8) ? 1 : 0) + | ((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 2 : 0))) + __builtin_abort (); + #pragma omp simd linear (t) + for (t = 0; t < 32; t++) + d[T::t + 9] |= 4; + if (t != 32) + __builtin_abort (); + for (int i = 0; i < 64; i++) + if (d[i] != (((i >= 8 && i < 32 + 8) ? 1 : 0) + | ((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 2 : 0) + | ((i >= 9 && i < 32 + 9) ? 4 : 0))) + __builtin_abort (); + r = 0; + #pragma omp parallel for reduction(|:r) + for (a = 0; A::a < 31; a += 2) + r |= (1 << A::a); + if (r != 0x55555555) + __builtin_abort (); + #pragma omp parallel for simd + for (R::r = 0; r < 32; R::r += 2) + d[r + 8] |= 8; + for (int i = 0; i < 64; i++) + if (d[i] != (((i >= 8 && i < 32 + 8) ? ((i & 1) ? 1 : (8 | 1)) : 0) + | ((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 2 : 0) + | ((i >= 9 && i < 32 + 9) ? 4 : 0))) + __builtin_abort (); + #pragma omp simd collapse(2) + for (T::t = 0; t < 7; t += 2) + for (a = 0; A::a < 8; a++) + d[((t << 2) | a) + 3] |= 16; + if (t != 8 || A::a != 8) + __builtin_abort (); + for (int i = 0; i < 64; i++) + if (d[i] != (((i >= 8 && i < 32 + 8) ? ((i & 1) ? 1 : (8 | 1)) : 0) + | ((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 2 : 0) + | ((i >= 9 && i < 32 + 9) ? 4 : 0) + | ((i >= 3 && i < 32 + 3) ? 16 : 0))) + __builtin_abort (); + T::t = 32; + a = 16; + #pragma omp parallel + #pragma omp single + #pragma omp taskloop simd collapse(2) + for (t = 0; T::t < 7; T::t += 2) + for (A::a = 0; a < 8; A::a++) + d[((t << 2) | A::a) + 3] |= 32; + if (T::t != 8 || a != 8) + __builtin_abort (); + for (int i = 0; i < 64; i++) + if (d[i] != (((i >= 8 && i < 32 + 8) ? ((i & 1) ? 1 : (8 | 1)) : 0) + | ((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 2 : 0) + | ((i >= 9 && i < 32 + 9) ? 4 : 0) + | ((i >= 3 && i < 32 + 3) ? (16 | 32) : 0))) + __builtin_abort (); + #pragma omp parallel + #pragma omp single + #pragma omp taskloop simd + for (R::r = 0; r < 31; R::r += 2) + d[r + 8] |= 64; + if (r != 32) + __builtin_abort (); + for (int i = 0; i < 64; i++) + if (d[i] != (((i >= 8 && i < 32 + 8) ? ((i & 1) ? 1 : (64 | 8 | 1)) : 0) + | ((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 2 : 0) + | ((i >= 9 && i < 32 + 9) ? 4 : 0) + | ((i >= 3 && i < 32 + 3) ? (16 | 32) : 0))) + __builtin_abort (); +} + +int +main () +{ + A a; + a.m1 (); +} diff --git a/libgomp/testsuite/libgomp.c++/member-4.C b/libgomp/testsuite/libgomp.c++/member-4.C new file mode 100644 index 00000000000..f76695de6fb --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/member-4.C @@ -0,0 +1,108 @@ +// { dg-do run } + +int c, d, e; +struct R { R () {}; ~R () {}; int r; }; +template +struct T { T () : t(d) {}; virtual ~T () {}; Q t; }; +template +struct A : public R, virtual public T { A () : b(c), a(e) {} Q a; int &b; void m1 (); }; +int f[64]; + +template +void +A::m1 () +{ + r = 0; + #pragma omp parallel for private (a) reduction(|:R::r) + for (a = 0; A::a < 31; a += 2) + r |= (1 << A::a); + if (r != 0x55555555) + __builtin_abort (); + #pragma omp parallel for simd linear (R::r) + for (R::r = 0; r < 32; R::r++) + f[r + 8] |= 1; + for (int i = 0; i < 64; i++) + if (f[i] != ((i >= 8 && i < 32 + 8) ? 1 : 0)) + __builtin_abort (); + #pragma omp parallel for lastprivate (T::t) + for (T::t = 0; T::t < 32; T::t += 3) + f[T::t + 2] |= 2; + if (T::t != 33) + __builtin_abort (); + for (int i = 0; i < 64; i++) + if (f[i] != (((i >= 8 && i < 32 + 8) ? 1 : 0) + | ((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 2 : 0))) + __builtin_abort (); + #pragma omp simd linear (T::t) + for (T::t = 0; T::t < 32; T::t++) + f[T::t + 9] |= 4; + if (T::t != 32) + __builtin_abort (); + for (int i = 0; i < 64; i++) + if (f[i] != (((i >= 8 && i < 32 + 8) ? 1 : 0) + | ((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 2 : 0) + | ((i >= 9 && i < 32 + 9) ? 4 : 0))) + __builtin_abort (); + r = 0; + #pragma omp parallel for reduction(|:r) + for (a = 0; A::a < 31; a += 2) + r |= (1 << A::a); + if (r != 0x55555555) + __builtin_abort (); + #pragma omp parallel for simd + for (R::r = 0; r < 32; R::r += 2) + f[r + 8] |= 8; + for (int i = 0; i < 64; i++) + if (f[i] != (((i >= 8 && i < 32 + 8) ? ((i & 1) ? 1 : (8 | 1)) : 0) + | ((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 2 : 0) + | ((i >= 9 && i < 32 + 9) ? 4 : 0))) + __builtin_abort (); + #pragma omp simd collapse(2) + for (T::t = 0; T::t < 7; T::t += 2) + for (a = 0; A::a < 8; a++) + f[((T::t << 2) | a) + 3] |= 16; + if (T::t != 8 || A::a != 8) + __builtin_abort (); + for (int i = 0; i < 64; i++) + if (f[i] != (((i >= 8 && i < 32 + 8) ? ((i & 1) ? 1 : (8 | 1)) : 0) + | ((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 2 : 0) + | ((i >= 9 && i < 32 + 9) ? 4 : 0) + | ((i >= 3 && i < 32 + 3) ? 16 : 0))) + __builtin_abort (); + T::t = 32; + a = 16; + #pragma omp parallel + #pragma omp single + #pragma omp taskloop simd collapse(2) + for (T::t = 0; T::t < 7; T::t += 2) + for (A::a = 0; a < 8; A::a++) + f[((T::t << 2) | A::a) + 3] |= 32; + if (T::t != 8 || a != 8) + __builtin_abort (); + for (int i = 0; i < 64; i++) + if (f[i] != (((i >= 8 && i < 32 + 8) ? ((i & 1) ? 1 : (8 | 1)) : 0) + | ((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 2 : 0) + | ((i >= 9 && i < 32 + 9) ? 4 : 0) + | ((i >= 3 && i < 32 + 3) ? (16 | 32) : 0))) + __builtin_abort (); + #pragma omp parallel + #pragma omp single + #pragma omp taskloop simd + for (R::r = 0; r < 31; R::r += 2) + f[r + 8] |= 64; + if (r != 32) + __builtin_abort (); + for (int i = 0; i < 64; i++) + if (f[i] != (((i >= 8 && i < 32 + 8) ? ((i & 1) ? 1 : (64 | 8 | 1)) : 0) + | ((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 2 : 0) + | ((i >= 9 && i < 32 + 9) ? 4 : 0) + | ((i >= 3 && i < 32 + 3) ? (16 | 32) : 0))) + __builtin_abort (); +} + +int +main () +{ + A a; + a.m1 (); +} diff --git a/libgomp/testsuite/libgomp.c++/member-5.C b/libgomp/testsuite/libgomp.c++/member-5.C new file mode 100644 index 00000000000..d6fec7a841a --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/member-5.C @@ -0,0 +1,183 @@ +// { dg-do run } + +typedef __PTRDIFF_TYPE__ ptrdiff_t; + +template +class I +{ +public: + typedef ptrdiff_t difference_type; + I (); + ~I (); + I (T *); + I (const I &); + T &operator * (); + T *operator -> (); + T &operator [] (const difference_type &) const; + I &operator = (const I &); + I &operator ++ (); + I operator ++ (int); + I &operator -- (); + I operator -- (int); + I &operator += (const difference_type &); + I &operator -= (const difference_type &); + I operator + (const difference_type &) const; + I operator - (const difference_type &) const; + template friend bool operator == (I &, I &); + template friend bool operator == (const I &, const I &); + template friend bool operator < (I &, I &); + template friend bool operator < (const I &, const I &); + template friend bool operator <= (I &, I &); + template friend bool operator <= (const I &, const I &); + template friend bool operator > (I &, I &); + template friend bool operator > (const I &, const I &); + template friend bool operator >= (I &, I &); + template friend bool operator >= (const I &, const I &); + template friend typename I::difference_type operator - (I &, I &); + template friend typename I::difference_type operator - (const I &, const I &); + template friend I operator + (typename I::difference_type , const I &); +private: + T *p; +}; +template I::I () : p (0) {} +template I::~I () {} +template I::I (T *x) : p (x) {} +template I::I (const I &x) : p (x.p) {} +template T &I::operator * () { return *p; } +template T *I::operator -> () { return p; } +template T &I::operator [] (const difference_type &x) const { return p[x]; } +template I &I::operator = (const I &x) { p = x.p; return *this; } +template I &I::operator ++ () { ++p; return *this; } +template I I::operator ++ (int) { return I (p++); } +template I &I::operator -- () { --p; return *this; } +template I I::operator -- (int) { return I (p--); } +template I &I::operator += (const difference_type &x) { p += x; return *this; } +template I &I::operator -= (const difference_type &x) { p -= x; return *this; } +template I I::operator + (const difference_type &x) const { return I (p + x); } +template I I::operator - (const difference_type &x) const { return I (p - x); } +template bool operator == (I &x, I &y) { return x.p == y.p; } +template bool operator == (const I &x, const I &y) { return x.p == y.p; } +template bool operator != (I &x, I &y) { return !(x == y); } +template bool operator != (const I &x, const I &y) { return !(x == y); } +template bool operator < (I &x, I &y) { return x.p < y.p; } +template bool operator < (const I &x, const I &y) { return x.p < y.p; } +template bool operator <= (I &x, I &y) { return x.p <= y.p; } +template bool operator <= (const I &x, const I &y) { return x.p <= y.p; } +template bool operator > (I &x, I &y) { return x.p > y.p; } +template bool operator > (const I &x, const I &y) { return x.p > y.p; } +template bool operator >= (I &x, I &y) { return x.p >= y.p; } +template bool operator >= (const I &x, const I &y) { return x.p >= y.p; } +template typename I::difference_type operator - (I &x, I &y) { return x.p - y.p; } +template typename I::difference_type operator - (const I &x, const I &y) { return x.p - y.p; } +template I operator + (typename I::difference_type x, const I &y) { return I (x + y.p); } + +struct R { R () {}; ~R () {}; I r; }; +struct T { T () {}; virtual ~T () {}; I t; }; +struct A : public R, virtual public T { A () {} I a; void m1 (const I &, const I &); }; +template +struct U { U () {}; virtual ~U () {}; Q t; }; +template +struct B : public R, virtual public U { B () {} Q a; void m2 (const Q &, const Q &, const I &, const I &); }; + +int d[64]; + +void +A::m1 (const I &x, const I &y) +{ + int w = 0; + #pragma omp parallel for private (a) reduction(|:w) + for (a = x; A::a < y - 33; a += 2) + w |= (1 << *A::a); + if (w != 0x55555555) + __builtin_abort (); + #pragma omp parallel for lastprivate (t) + for (T::t = x; t < y - 32; t += 3) + d[*T::t + 2] |= 1; + if (*T::t != 33) + __builtin_abort (); + for (int i = 0; i < 64; i++) + if (d[i] != ((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 1 : 0)) + __builtin_abort (); + w = 0; + #pragma omp parallel for reduction(|:w) + for (a = x; A::a < y - 33; a += 2) + w |= (1 << *A::a); + if (w != 0x55555555) + __builtin_abort (); + #pragma omp taskloop + for (R::r = x; r < y - 32; R::r += 2) + d[*r + 8] |= 2; + for (int i = 0; i < 64; i++) + if (d[i] != (((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 1 : 0) + | ((i >= 8 && i < 32 + 8 && (i & 1) == 0) ? 2 : 0))) + __builtin_abort (); + #pragma omp taskloop collapse(2) + for (T::t = x; t < y - 57; t += 2) + for (a = x; A::a < y - 56; a++) + d[((*t << 2) | *a) + 3] |= 4; + for (int i = 0; i < 64; i++) + if (d[i] != (((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 1 : 0) + | ((i >= 8 && i < 32 + 8 && (i & 1) == 0) ? 2 : 0) + | ((i >= 3 && i < 32 + 3) ? 4 : 0))) + __builtin_abort (); +} + +template +void +B::m2 (const Q &u, const Q &v, const I &x, const I &y) +{ + int w = 0; + #pragma omp parallel for private (a) reduction(|:w) + for (a = u; B::a < v - 33; a += 2) + w |= (1 << *B::a); + if (w != 0x55555555) + __builtin_abort (); + #pragma omp parallel for lastprivate (U::t) + for (U::t = u; U::t < v - 32; U::t += 3) + d[*U::t + 2] |= 1; + if (*U::t != 33) + __builtin_abort (); + for (int i = 0; i < 64; i++) + if (d[i] != ((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 1 : 0)) + __builtin_abort (); + w = 0; + #pragma omp parallel for reduction(|:w) + for (a = u; B::a < v - 33; a += 2) + w |= (1 << *B::a); + if (w != 0x55555555) + __builtin_abort (); + #pragma omp taskloop + for (R::r = x; r < y - 32; R::r += 2) + d[*r + 8] |= 2; + for (int i = 0; i < 64; i++) + if (d[i] != (((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 1 : 0) + | ((i >= 8 && i < 32 + 8 && (i & 1) == 0) ? 2 : 0))) + __builtin_abort (); + #pragma omp taskloop collapse(2) + for (U::t = u; U::t < v - 57; U::t += 2) + for (a = u; B::a < v - 56; a++) + d[((*U::t << 2) | *a) + 3] |= 4; + for (int i = 0; i < 64; i++) + if (d[i] != (((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 1 : 0) + | ((i >= 8 && i < 32 + 8 && (i & 1) == 0) ? 2 : 0) + | ((i >= 3 && i < 32 + 3) ? 4 : 0))) + __builtin_abort (); +} + +int +main () +{ + A a; + int b[128]; + for (int i = 0; i < 128; i++) + b[i] = i - 32; + a.m1 (&b[32], &b[96]); + for (int i = 0; i < 64; i++) + d[i] = 0; + B > c; + c.m2 (&b[32], &b[96], &b[32], &b[96]); + for (int i = 0; i < 64; i++) + d[i] = 0; + B d; + d.m2 (&b[32], &b[96], &b[32], &b[96]); +} diff --git a/libgomp/testsuite/libgomp.c++/ordered-1.C b/libgomp/testsuite/libgomp.c++/ordered-1.C new file mode 100644 index 00000000000..a1bedd808ac --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/ordered-1.C @@ -0,0 +1 @@ +#include "../libgomp.c/ordered-4.c" diff --git a/libgomp/testsuite/libgomp.c++/reduction-10.C b/libgomp/testsuite/libgomp.c++/reduction-10.C new file mode 100644 index 00000000000..2254430f168 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/reduction-10.C @@ -0,0 +1,201 @@ +template +struct A +{ + A () { t = 0; } + A (T x) { t = x; } + A (const A &x) { t = x.t; } + ~A () {} + T t; +}; +template +struct M +{ + M () { t = 1; } + M (T x) { t = x; } + M (const M &x) { t = x.t; } + ~M () {} + T t; +}; +template +struct B +{ + B () { t = ~(T) 0; } + B (T x) { t = x; } + B (const B &x) { t = x.t; } + ~B () {} + T t; +}; +template +void +add (T &x, T &y) +{ + x.t += y.t; +} +template +void +zero (T &x) +{ + x.t = 0; +} +template +void +orit (T *x, T *y) +{ + y->t |= x->t; +} +B bb; +#pragma omp declare reduction(+:A:omp_out.t += omp_in.t) +#pragma omp declare reduction(+:A:add (omp_out, omp_in)) initializer(zero (omp_priv)) +#pragma omp declare reduction(*:M:omp_out.t *= omp_in.t) initializer(omp_priv = 1) +#pragma omp declare reduction(|:A:orit (&omp_in, &omp_out)) +#pragma omp declare reduction(&:B:omp_out.t = omp_out.t & omp_in.t) initializer(orit (&omp_priv, &omp_orig)) +#pragma omp declare reduction(maxb:short:omp_out = omp_in > omp_out ? omp_in : omp_out) initializer(omp_priv = -6) + +A z[10]; + +template +__attribute__((noinline, noclone)) void +foo (A (*&x)[3][N], M *y, B (&w)[1][N], int p1, long p2, long p3, int p4, + int p5, long p6, short p7) +{ + A a[p7 + 4]; + short bb[p7]; + short (&b)[p7] = bb; + for (int i = 0; i < p7; i++) + bb[i] = -6; + #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2 + N - 2], z[:p3]) \ + reduction(*:y[:p4]) reduction(|:a[:p5 - N + 2]) \ + reduction(&:w[0:p6 - 3 + N][:p6]) reduction(maxb:b) + for (int i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1].t += i; + if ((i & 15) == 1) + y[0].t *= 3; + if ((i & 31) == N) + y[1].t *= 7; + if ((i & 63) == 3) + y[N].t *= 17; + z[i / 32].t += (i & 3); + if (i < 4) + z[i].t += i; + a[i / 32].t |= 1ULL << (i & 30); + w[0][i & 1].t &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[N]) + b[N] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } + for (int i = 0; i < 9; i++) + if (a[i].t != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + if (bb[0] != 78 || bb[1] != 12 || bb[N] != 22 || bb[3] != 84 || bb[4] != 127) + __builtin_abort (); +} + +A a3[4][3][2]; +A (*p3)[3][2] = &a3[1]; +M y3[5] = { 0, 1, 1, 1, 0 }; +B w3[1][2]; + +template +struct S +{ + A (*&x)[3][N]; + M *y; + B (&w)[1][N]; + A z[10]; + short b[5]; + A a[9]; + S() : x(p3), y(y3+1), w(w3), z(), a(), b() {} + __attribute__((noinline, noclone)) void foo (int, long, long, int, int, long, short); +}; + +template +void +S::foo (int p1, long p2, long p3, int p4, int p5, long p6, short p7) +{ + #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2][0:N], z[:p3 + N - 2]) \ + reduction(*:y[:p4]) reduction(|:a[:p5]) \ + reduction(&:w[0:p6 - 3 + N][:p6]) reduction(maxb:b) + for (int i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1].t += i; + if ((i & 15) == 1) + y[0].t *= 3; + if ((i & 31) == N) + y[1].t *= 7; + if ((i & 63) == 3) + y[N].t *= 17; + z[i / 32].t += (i & 3); + if (i < 4) + z[i].t += i; + a[i / 32].t |= 1ULL << (i & 30); + w[0][i & 1].t &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[N]) + b[N] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } +} + +int +main () +{ + A a[4][3][2]; + static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }}, + {{ 312, 381 }, { 295, 356 }, { 337, 335 }}, + {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }}, + {{ 0, 0 }, { 0, 0 }, { 0, 0 }}}; + A (*p)[3][2] = &a[1]; + M y[5] = { 0, 1, 1, 1, 0 }; + int y2[5] = { 0, 6561, 2401, 289, 0 }; + char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 }; + B w[1][2]; + foo<2> (p, y + 1, w, 1, 3L, 4L, 3, 4, 2L, 5); + for (int i = 0; i < 4; i++) + for (int j = 0; j < 3; j++) + for (int k = 0; k < 2; k++) + if (a[i][j][k].t != a2[i][j][k]) + __builtin_abort (); + for (int i = 0; i < 5; i++) + if (y[i].t != y2[i]) + __builtin_abort (); + for (int i = 0; i < 10; i++) + if (z[i].t != z2[i]) + __builtin_abort (); + if (w[0][0].t != ~0x249249L || w[0][1].t != ~0x249249L) + __builtin_abort (); + S<2> s; + s.foo (1, 3L, 4L, 3, 4, 2L, 5); + for (int i = 0; i < 9; i++) + if (s.a[i].t != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + for (int i = 0; i < 4; i++) + for (int j = 0; j < 3; j++) + for (int k = 0; k < 2; k++) + if (a3[i][j][k].t != a2[i][j][k]) + __builtin_abort (); + for (int i = 0; i < 5; i++) + if (y3[i].t != y2[i]) + __builtin_abort (); + for (int i = 0; i < 10; i++) + if (s.z[i].t != z2[i]) + __builtin_abort (); + if (w3[0][0].t != ~0x249249L || w3[0][1].t != ~0x249249L) + __builtin_abort (); + if (s.b[0] != 78 || s.b[1] != 12 || s.b[2] != 22 + || s.b[3] != 84 || s.b[4] != 127) + __builtin_abort (); +} diff --git a/libgomp/testsuite/libgomp.c++/reduction-5.C b/libgomp/testsuite/libgomp.c++/reduction-5.C new file mode 100644 index 00000000000..212fd69be58 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/reduction-5.C @@ -0,0 +1,127 @@ +char z[10] = { 0 }; + +__attribute__((noinline, noclone)) void +foo (int (*&x)[3][2], int *y, long (&w)[1][2]) +{ + unsigned long long a[9] = {}; + short b[5] = {}; + #pragma omp parallel for reduction(+:x[0:2][:][0:2], z[:4]) \ + reduction(*:y[:3]) reduction(|:a[:4]) \ + reduction(&:w[0:][:2]) reduction(max:b) + for (int i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1] += i; + if ((i & 15) == 1) + y[0] *= 3; + if ((i & 31) == 2) + y[1] *= 7; + if ((i & 63) == 3) + y[2] *= 17; + z[i / 32] += (i & 3); + if (i < 4) + z[i] += i; + a[i / 32] |= 1ULL << (i & 30); + w[0][i & 1] &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[2]) + b[2] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } + for (int i = 0; i < 9; i++) + if (a[i] != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + if (b[0] != 78 || b[1] != 12 || b[2] != 22 || b[3] != 84 || b[4] != 127) + __builtin_abort (); +} + +int a3[4][3][2]; +int (*p3)[3][2] = &a3[1]; +int y3[5] = { 0, 1, 1, 1, 0 }; +long w3[1][2] = { ~0L, ~0L }; +short bb[5]; + +struct S +{ + int (*&x)[3][2]; + int *y; + long (&w)[1][2]; + char z[10]; + short (&b)[5]; + unsigned long long a[9]; + S() : x(p3), y(y3+1), w(w3), z(), a(), b(bb) {} + __attribute__((noinline, noclone)) void foo (); +}; + +void +S::foo () +{ + #pragma omp parallel for reduction(+:x[0:2][:][0:2], z[:4]) \ + reduction(*:y[:3]) reduction(|:a[:4]) \ + reduction(&:w[0:][:2]) reduction(max:b) + for (int i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1] += i; + if ((i & 15) == 1) + y[0] *= 3; + if ((i & 31) == 2) + y[1] *= 7; + if ((i & 63) == 3) + y[2] *= 17; + z[i / 32] += (i & 3); + if (i < 4) + z[i] += i; + a[i / 32] |= 1ULL << (i & 30); + w[0][i & 1] &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[2]) + b[2] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } +} + +int +main () +{ + int a[4][3][2] = {}; + static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }}, + {{ 312, 381 }, { 295, 356 }, { 337, 335 }}, + {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }}, + {{ 0, 0 }, { 0, 0 }, { 0, 0 }}}; + int (*p)[3][2] = &a[1]; + int y[5] = { 0, 1, 1, 1, 0 }; + int y2[5] = { 0, 6561, 2401, 289, 0 }; + char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 }; + long w[1][2] = { ~0L, ~0L }; + foo (p, y + 1, w); + if (__builtin_memcmp (a, a2, sizeof (a)) + || __builtin_memcmp (y, y2, sizeof (y)) + || __builtin_memcmp (z, z2, sizeof (z)) + || w[0][0] != ~0x249249L + || w[0][1] != ~0x249249L) + __builtin_abort (); + S s; + s.foo (); + for (int i = 0; i < 9; i++) + if (s.a[i] != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + if (__builtin_memcmp (a3, a2, sizeof (a3)) + || __builtin_memcmp (y3, y2, sizeof (y3)) + || __builtin_memcmp (s.z, z2, sizeof (s.z)) + || w3[0][0] != ~0x249249L + || w3[0][1] != ~0x249249L) + __builtin_abort (); + if (bb[0] != 78 || bb[1] != 12 || bb[2] != 22 || bb[3] != 84 || bb[4] != 127) + __builtin_abort (); +} diff --git a/libgomp/testsuite/libgomp.c++/reduction-6.C b/libgomp/testsuite/libgomp.c++/reduction-6.C new file mode 100644 index 00000000000..f180ca35edd --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/reduction-6.C @@ -0,0 +1,195 @@ +template +struct A +{ + A () { t = 0; } + A (T x) { t = x; } + A (const A &x) { t = x.t; } + ~A () {} + T t; +}; +template +struct M +{ + M () { t = 1; } + M (T x) { t = x; } + M (const M &x) { t = x.t; } + ~M () {} + T t; +}; +template +struct B +{ + B () { t = ~(T) 0; } + B (T x) { t = x; } + B (const B &x) { t = x.t; } + ~B () {} + T t; +}; +template +void +add (T &x, T &y) +{ + x.t += y.t; +} +template +void +zero (T &x) +{ + x.t = 0; +} +template +void +orit (T *x, T *y) +{ + y->t |= x->t; +} +B bb; +#pragma omp declare reduction(+:A:omp_out.t += omp_in.t) +#pragma omp declare reduction(+:A:add (omp_out, omp_in)) initializer(zero (omp_priv)) +#pragma omp declare reduction(*:M:omp_out.t *= omp_in.t) initializer(omp_priv = 1) +#pragma omp declare reduction(|:A:orit (&omp_in, &omp_out)) +#pragma omp declare reduction(&:B:omp_out.t = omp_out.t & omp_in.t) initializer(orit (&omp_priv, &omp_orig)) +#pragma omp declare reduction(maxb:short:omp_out = omp_in > omp_out ? omp_in : omp_out) initializer(omp_priv = -6) + +A z[10]; + +__attribute__((noinline, noclone)) void +foo (A (*&x)[3][2], M *y, B (&w)[1][2]) +{ + A a[9]; + short bb[5] = {}; + short (&b)[5] = bb; + #pragma omp parallel for reduction(+:x[0:2][:][0:2], z[:4]) \ + reduction(*:y[:3]) reduction(|:a[:4]) \ + reduction(&:w[0:][:2]) reduction(maxb:b) + for (int i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1].t += i; + if ((i & 15) == 1) + y[0].t *= 3; + if ((i & 31) == 2) + y[1].t *= 7; + if ((i & 63) == 3) + y[2].t *= 17; + z[i / 32].t += (i & 3); + if (i < 4) + z[i].t += i; + a[i / 32].t |= 1ULL << (i & 30); + w[0][i & 1].t &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[2]) + b[2] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } + for (int i = 0; i < 9; i++) + if (a[i].t != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + if (bb[0] != 78 || bb[1] != 12 || bb[2] != 22 || bb[3] != 84 || bb[4] != 127) + __builtin_abort (); +} + +A a3[4][3][2]; +A (*p3)[3][2] = &a3[1]; +M y3[5] = { 0, 1, 1, 1, 0 }; +B w3[1][2]; + +struct S +{ + A (*&x)[3][2]; + M *y; + B (&w)[1][2]; + A z[10]; + short b[5]; + A a[9]; + S() : x(p3), y(y3+1), w(w3), z(), a(), b() {} + __attribute__((noinline, noclone)) void foo (); +}; + +void +S::foo () +{ + #pragma omp parallel for reduction(+:x[0:2][:][0:2], z[:4]) \ + reduction(*:y[:3]) reduction(|:a[:4]) \ + reduction(&:w[0:][:2]) reduction(maxb:b) + for (int i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1].t += i; + if ((i & 15) == 1) + y[0].t *= 3; + if ((i & 31) == 2) + y[1].t *= 7; + if ((i & 63) == 3) + y[2].t *= 17; + z[i / 32].t += (i & 3); + if (i < 4) + z[i].t += i; + a[i / 32].t |= 1ULL << (i & 30); + w[0][i & 1].t &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[2]) + b[2] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } +} + +int +main () +{ + A a[4][3][2]; + static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }}, + {{ 312, 381 }, { 295, 356 }, { 337, 335 }}, + {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }}, + {{ 0, 0 }, { 0, 0 }, { 0, 0 }}}; + A (*p)[3][2] = &a[1]; + M y[5] = { 0, 1, 1, 1, 0 }; + int y2[5] = { 0, 6561, 2401, 289, 0 }; + char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 }; + B w[1][2]; + foo (p, y + 1, w); + for (int i = 0; i < 4; i++) + for (int j = 0; j < 3; j++) + for (int k = 0; k < 2; k++) + if (a[i][j][k].t != a2[i][j][k]) + __builtin_abort (); + for (int i = 0; i < 5; i++) + if (y[i].t != y2[i]) + __builtin_abort (); + for (int i = 0; i < 10; i++) + if (z[i].t != z2[i]) + __builtin_abort (); + if (w[0][0].t != ~0x249249L || w[0][1].t != ~0x249249L) + __builtin_abort (); + S s; + s.foo (); + for (int i = 0; i < 9; i++) + if (s.a[i].t != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + for (int i = 0; i < 4; i++) + for (int j = 0; j < 3; j++) + for (int k = 0; k < 2; k++) + if (a3[i][j][k].t != a2[i][j][k]) + __builtin_abort (); + for (int i = 0; i < 5; i++) + if (y3[i].t != y2[i]) + __builtin_abort (); + for (int i = 0; i < 10; i++) + if (s.z[i].t != z2[i]) + __builtin_abort (); + if (w3[0][0].t != ~0x249249L || w3[0][1].t != ~0x249249L) + __builtin_abort (); + if (s.b[0] != 78 || s.b[1] != 12 || s.b[2] != 22 + || s.b[3] != 84 || s.b[4] != 127) + __builtin_abort (); +} diff --git a/libgomp/testsuite/libgomp.c++/reduction-7.C b/libgomp/testsuite/libgomp.c++/reduction-7.C new file mode 100644 index 00000000000..75f9d08aac4 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/reduction-7.C @@ -0,0 +1,134 @@ +char z[10] = { 0 }; + +__attribute__((noinline, noclone)) void +foo (int (*&x)[3][2], int *y, long (&w)[1][2], int p1, long p2, long p3, int p4, + int p5, long p6, short p7) +{ + unsigned long long a[p7 + 4]; + short b[p7]; + for (int i = 0; i < p7 + 4; i++) + { + if (i < p7) + b[i] = -6; + a[i] = 0; + } + #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2], z[:p3]) \ + reduction(*:y[:p4]) reduction(|:a[:p5]) \ + reduction(&:w[0:p6 - 1][:p6]) reduction(max:b) + for (int i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1] += i; + if ((i & 15) == 1) + y[0] *= 3; + if ((i & 31) == 2) + y[1] *= 7; + if ((i & 63) == 3) + y[2] *= 17; + z[i / 32] += (i & 3); + if (i < 4) + z[i] += i; + a[i / 32] |= 1ULL << (i & 30); + w[0][i & 1] &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[2]) + b[2] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } + for (int i = 0; i < 9; i++) + if (a[i] != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + if (b[0] != 78 || b[1] != 12 || b[2] != 22 || b[3] != 84 || b[4] != 127) + __builtin_abort (); +} + +int a3[4][3][2]; +int (*p3)[3][2] = &a3[1]; +int y3[5] = { 0, 1, 1, 1, 0 }; +long w3[1][2] = { ~0L, ~0L }; +short bb[5]; + +struct S +{ + int (*&x)[3][2]; + int *y; + long (&w)[1][2]; + char z[10]; + short (&b)[5]; + unsigned long long a[9]; + S() : x(p3), y(y3+1), w(w3), z(), a(), b(bb) {} + __attribute__((noinline, noclone)) void foo (int, long, long, int, int, long, short); +}; + +void +S::foo (int p1, long p2, long p3, int p4, int p5, long p6, short p7) +{ + #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2], z[:p3]) \ + reduction(*:y[:p4]) reduction(|:a[:p5]) \ + reduction(&:w[0:p6 - 1][:p6]) reduction(max:b[0:p7]) + for (int i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1] += i; + if ((i & 15) == 1) + y[0] *= 3; + if ((i & 31) == 2) + y[1] *= 7; + if ((i & 63) == 3) + y[2] *= 17; + z[i / 32] += (i & 3); + if (i < 4) + z[i] += i; + a[i / 32] |= 1ULL << (i & 30); + w[0][i & 1] &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[2]) + b[2] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } +} + +int +main () +{ + int a[4][3][2] = {}; + static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }}, + {{ 312, 381 }, { 295, 356 }, { 337, 335 }}, + {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }}, + {{ 0, 0 }, { 0, 0 }, { 0, 0 }}}; + int (*p)[3][2] = &a[1]; + int y[5] = { 0, 1, 1, 1, 0 }; + int y2[5] = { 0, 6561, 2401, 289, 0 }; + char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 }; + long w[1][2] = { ~0L, ~0L }; + foo (p, y + 1, w, 1, 3L, 4L, 3, 4, 2L, 5); + if (__builtin_memcmp (a, a2, sizeof (a)) + || __builtin_memcmp (y, y2, sizeof (y)) + || __builtin_memcmp (z, z2, sizeof (z)) + || w[0][0] != ~0x249249L + || w[0][1] != ~0x249249L) + __builtin_abort (); + S s; + s.foo (1, 3L, 4L, 3, 4, 2L, 5); + for (int i = 0; i < 9; i++) + if (s.a[i] != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + if (__builtin_memcmp (a3, a2, sizeof (a3)) + || __builtin_memcmp (y3, y2, sizeof (y3)) + || __builtin_memcmp (s.z, z2, sizeof (s.z)) + || w3[0][0] != ~0x249249L + || w3[0][1] != ~0x249249L) + __builtin_abort (); + if (bb[0] != 78 || bb[1] != 12 || bb[2] != 22 || bb[3] != 84 || bb[4] != 127) + __builtin_abort (); +} diff --git a/libgomp/testsuite/libgomp.c++/reduction-8.C b/libgomp/testsuite/libgomp.c++/reduction-8.C new file mode 100644 index 00000000000..cffd7cc2d4c --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/reduction-8.C @@ -0,0 +1,198 @@ +template +struct A +{ + A () { t = 0; } + A (T x) { t = x; } + A (const A &x) { t = x.t; } + ~A () {} + T t; +}; +template +struct M +{ + M () { t = 1; } + M (T x) { t = x; } + M (const M &x) { t = x.t; } + ~M () {} + T t; +}; +template +struct B +{ + B () { t = ~(T) 0; } + B (T x) { t = x; } + B (const B &x) { t = x.t; } + ~B () {} + T t; +}; +template +void +add (T &x, T &y) +{ + x.t += y.t; +} +template +void +zero (T &x) +{ + x.t = 0; +} +template +void +orit (T *x, T *y) +{ + y->t |= x->t; +} +B bb; +#pragma omp declare reduction(+:A:omp_out.t += omp_in.t) +#pragma omp declare reduction(+:A:add (omp_out, omp_in)) initializer(zero (omp_priv)) +#pragma omp declare reduction(*:M:omp_out.t *= omp_in.t) initializer(omp_priv = 1) +#pragma omp declare reduction(|:A:orit (&omp_in, &omp_out)) +#pragma omp declare reduction(&:B:omp_out.t = omp_out.t & omp_in.t) initializer(orit (&omp_priv, &omp_orig)) +#pragma omp declare reduction(maxb:short:omp_out = omp_in > omp_out ? omp_in : omp_out) initializer(omp_priv = -6) + +A z[10]; + +__attribute__((noinline, noclone)) void +foo (A (*&x)[3][2], M *y, B (&w)[1][2], int p1, long p2, long p3, int p4, + int p5, long p6, short p7) +{ + A a[p7 + 4]; + short bb[p7]; + short (&b)[p7] = bb; + for (int i = 0; i < p7; i++) + bb[i] = -6; + #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2], z[:p3]) \ + reduction(*:y[:p4]) reduction(|:a[:p5]) \ + reduction(&:w[0:p6 - 1][:p6]) reduction(maxb:b) + for (int i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1].t += i; + if ((i & 15) == 1) + y[0].t *= 3; + if ((i & 31) == 2) + y[1].t *= 7; + if ((i & 63) == 3) + y[2].t *= 17; + z[i / 32].t += (i & 3); + if (i < 4) + z[i].t += i; + a[i / 32].t |= 1ULL << (i & 30); + w[0][i & 1].t &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[2]) + b[2] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } + for (int i = 0; i < 9; i++) + if (a[i].t != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + if (bb[0] != 78 || bb[1] != 12 || bb[2] != 22 || bb[3] != 84 || bb[4] != 127) + __builtin_abort (); +} + +A a3[4][3][2]; +A (*p3)[3][2] = &a3[1]; +M y3[5] = { 0, 1, 1, 1, 0 }; +B w3[1][2]; + +struct S +{ + A (*&x)[3][2]; + M *y; + B (&w)[1][2]; + A z[10]; + short b[5]; + A a[9]; + S() : x(p3), y(y3+1), w(w3), z(), a(), b() {} + __attribute__((noinline, noclone)) void foo (int, long, long, int, int, long, short); +}; + +void +S::foo (int p1, long p2, long p3, int p4, int p5, long p6, short p7) +{ + #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2][0:2], z[:p3]) \ + reduction(*:y[:p4]) reduction(|:a[:p5]) \ + reduction(&:w[0:p6 - 1][:p6]) reduction(maxb:b) + for (int i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1].t += i; + if ((i & 15) == 1) + y[0].t *= 3; + if ((i & 31) == 2) + y[1].t *= 7; + if ((i & 63) == 3) + y[2].t *= 17; + z[i / 32].t += (i & 3); + if (i < 4) + z[i].t += i; + a[i / 32].t |= 1ULL << (i & 30); + w[0][i & 1].t &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[2]) + b[2] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } +} + +int +main () +{ + A a[4][3][2]; + static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }}, + {{ 312, 381 }, { 295, 356 }, { 337, 335 }}, + {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }}, + {{ 0, 0 }, { 0, 0 }, { 0, 0 }}}; + A (*p)[3][2] = &a[1]; + M y[5] = { 0, 1, 1, 1, 0 }; + int y2[5] = { 0, 6561, 2401, 289, 0 }; + char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 }; + B w[1][2]; + foo (p, y + 1, w, 1, 3L, 4L, 3, 4, 2L, 5); + for (int i = 0; i < 4; i++) + for (int j = 0; j < 3; j++) + for (int k = 0; k < 2; k++) + if (a[i][j][k].t != a2[i][j][k]) + __builtin_abort (); + for (int i = 0; i < 5; i++) + if (y[i].t != y2[i]) + __builtin_abort (); + for (int i = 0; i < 10; i++) + if (z[i].t != z2[i]) + __builtin_abort (); + if (w[0][0].t != ~0x249249L || w[0][1].t != ~0x249249L) + __builtin_abort (); + S s; + s.foo (1, 3L, 4L, 3, 4, 2L, 5); + for (int i = 0; i < 9; i++) + if (s.a[i].t != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + for (int i = 0; i < 4; i++) + for (int j = 0; j < 3; j++) + for (int k = 0; k < 2; k++) + if (a3[i][j][k].t != a2[i][j][k]) + __builtin_abort (); + for (int i = 0; i < 5; i++) + if (y3[i].t != y2[i]) + __builtin_abort (); + for (int i = 0; i < 10; i++) + if (s.z[i].t != z2[i]) + __builtin_abort (); + if (w3[0][0].t != ~0x249249L || w3[0][1].t != ~0x249249L) + __builtin_abort (); + if (s.b[0] != 78 || s.b[1] != 12 || s.b[2] != 22 + || s.b[3] != 84 || s.b[4] != 127) + __builtin_abort (); +} diff --git a/libgomp/testsuite/libgomp.c++/reduction-9.C b/libgomp/testsuite/libgomp.c++/reduction-9.C new file mode 100644 index 00000000000..117a8f66c52 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/reduction-9.C @@ -0,0 +1,130 @@ +char z[10] = { 0 }; + +template +__attribute__((noinline, noclone)) void +foo (int (*&x)[3][N], int *y, long (&w)[1][N]) +{ + unsigned long long a[9] = {}; + short b[5] = {}; + #pragma omp parallel for reduction(+:x[0:N][:][0:N], z[:4]) \ + reduction(*:y[:3]) reduction(|:a[:4]) \ + reduction(&:w[0:][:N]) reduction(max:b) + for (int i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1] += i; + if ((i & 15) == 1) + y[0] *= 3; + if ((i & 31) == N) + y[1] *= 7; + if ((i & 63) == 3) + y[N] *= 17; + z[i / 32] += (i & 3); + if (i < 4) + z[i] += i; + a[i / 32] |= 1ULL << (i & 30); + w[0][i & 1] &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[N]) + b[N] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } + for (int i = 0; i < 9; i++) + if (a[i] != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + if (b[0] != 78 || b[1] != 12 || b[N] != 22 || b[3] != 84 || b[4] != 127) + __builtin_abort (); +} + +int a3[4][3][2]; +int (*p3)[3][2] = &a3[1]; +int y3[5] = { 0, 1, 1, 1, 0 }; +long w3[1][2] = { ~0L, ~0L }; +short bb[5]; + +template +struct S +{ + int (*&x)[3][N]; + int *y; + long (&w)[1][N]; + char z[10]; + short (&b)[5]; + unsigned long long a[9]; + S() : x(p3), y(y3+1), w(w3), z(), a(), b(bb) {} + __attribute__((noinline, noclone)) void foo (); +}; + +template +void +S::foo () +{ + #pragma omp parallel for reduction(+:x[0:N][:][0:N], z[:4]) \ + reduction(*:y[:3]) reduction(|:a[:4]) \ + reduction(&:w[0:][:N]) reduction(max:b) + for (int i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1] += i; + if ((i & 15) == 1) + y[0] *= 3; + if ((i & 31) == N) + y[1] *= 7; + if ((i & 63) == 3) + y[N] *= 17; + z[i / 32] += (i & 3); + if (i < 4) + z[i] += i; + a[i / 32] |= 1ULL << (i & 30); + w[0][i & 1] &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[N]) + b[N] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } +} + +int +main () +{ + int a[4][3][2] = {}; + static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }}, + {{ 312, 381 }, { 295, 356 }, { 337, 335 }}, + {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }}, + {{ 0, 0 }, { 0, 0 }, { 0, 0 }}}; + int (*p)[3][2] = &a[1]; + int y[5] = { 0, 1, 1, 1, 0 }; + int y2[5] = { 0, 6561, 2401, 289, 0 }; + char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 }; + long w[1][2] = { ~0L, ~0L }; + foo<2> (p, y + 1, w); + if (__builtin_memcmp (a, a2, sizeof (a)) + || __builtin_memcmp (y, y2, sizeof (y)) + || __builtin_memcmp (z, z2, sizeof (z)) + || w[0][0] != ~0x249249L + || w[0][1] != ~0x249249L) + __builtin_abort (); + S<2> s; + s.foo (); + for (int i = 0; i < 9; i++) + if (s.a[i] != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + if (__builtin_memcmp (a3, a2, sizeof (a3)) + || __builtin_memcmp (y3, y2, sizeof (y3)) + || __builtin_memcmp (s.z, z2, sizeof (s.z)) + || w3[0][0] != ~0x249249L + || w3[0][1] != ~0x249249L) + __builtin_abort (); + if (bb[0] != 78 || bb[1] != 12 || bb[2] != 22 || bb[3] != 84 || bb[4] != 127) + __builtin_abort (); +} diff --git a/libgomp/testsuite/libgomp.c++/reference-1.C b/libgomp/testsuite/libgomp.c++/reference-1.C new file mode 100644 index 00000000000..f2a78614a13 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/reference-1.C @@ -0,0 +1,57 @@ +// { dg-do run } + +#include + +__attribute__((noinline, noclone)) void +foo (int &a, short &d, char &g) +{ + unsigned long b = 12; + unsigned long &c = b; + long long e = 21; + long long &f = e; + unsigned int h = 12; + unsigned int &k = h; + #pragma omp parallel default(none) private(a, c) firstprivate(d, f) shared(g, k) + { + int i = omp_get_thread_num (); + a = i; + c = 2 * i; + if (d != 27 || f != 21) + __builtin_abort (); + d = 3 * (i & 0xfff); + f = 4 * i; + #pragma omp barrier + if (a != i || c != 2 * i || d != 3 * (i & 0xfff) || f != 4 * i) + __builtin_abort (); + #pragma omp for lastprivate(g, k) + for (int j = 0; j < 32; j++) + { + g = j; + k = 3 * j; + } + } + if (g != 31 || k != 31 * 3) + __builtin_abort (); + #pragma omp parallel for firstprivate (g, k) lastprivate (g, k) + for (int j = 0; j < 32; j++) + { + if (g != 31 || k != 31 * 3) + __builtin_abort (); + if (j == 31) + { + g = 29; + k = 138; + } + } + if (g != 29 || k != 138) + __builtin_abort (); +} + +int +main () +{ + int a = 5; + short d = 27; + char g = ' '; + foo (a, d, g); +} diff --git a/libgomp/testsuite/libgomp.c++/simd14.C b/libgomp/testsuite/libgomp.c++/simd14.C new file mode 100644 index 00000000000..dc18cb619ac --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/simd14.C @@ -0,0 +1,43 @@ +// { dg-do run } +// { dg-options "-O2" } +// { dg-additional-options "-msse2" { target sse2_runtime } } +// { dg-additional-options "-mavx" { target avx_runtime } } + +int a[1024]; +short b[2048]; + +static inline void +bar (int &x, unsigned long long &y, short *&z) +{ + a[x] = x + y + *z; + x++; + y += 17; + z += 2; +} + +__attribute__((noinline, noclone)) int +foo (unsigned long long &s, short *&t) +{ + int i, j = 0; + int &r = j; +#pragma omp parallel for simd linear(r) linear(s:17ULL) linear(t:2) + for (i = 0; i < 1024; i++) + bar (r, s, t); + return j; +} + +int +main () +{ + int i; + for (i = 0; i < 2048; i++) + b[i] = 3 * i; + unsigned long long s = 12; + short *t = b; + int j = foo (s, t); + for (i = 0; i < 1024; i++) + if (a[i] != 12 + 24 * i) + __builtin_abort (); + if (j != 1024 || s != 12 + 1024 * 17ULL || t != &b[2048]) + __builtin_abort (); +} diff --git a/libgomp/testsuite/libgomp.c++/target-10.C b/libgomp/testsuite/libgomp.c++/target-10.C new file mode 100644 index 00000000000..860773eed15 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/target-10.C @@ -0,0 +1,154 @@ +extern "C" void abort (void); +union U { int x; long long y; }; +struct T { int a; union U b; int c; }; +struct S { int s; int u; T v; int x[10]; union U w; int y[10]; int z[10]; }; +volatile int z; + +template +void +foo () +{ + R s; + s.template s = 0; + s.u = 1; + s.v.a = 2; + s.v.b.y = 3LL; + s.v.c = 19; + s.w.x = 4; + s.template x[0] = 7; + s.x[1] = 8; + s.y[3] = 9; + s.y[4] = 10; + s.y[5] = 11; + int err = 0; + #pragma omp target map (to:s.template v.template b, s.u, s.x[0:z + 2]) \ + map (tofrom:s.y[3:3]) \ + map (from: s.w, s.template z[z + 1:z + 3], err) + { + err = 0; + if (s.u != 1 || s.v.b.y != 3LL || s.x[0] != 7 || s.x[1] != 8 + || s.y[3] != 9 || s.y[4] != 10 || s.y[5] != 11) + err = 1; + s.w.x = 6; + s.y[3] = 12; + s.y[4] = 13; + s.y[5] = 14; + s.z[1] = 15; + s.z[2] = 16; + s.z[3] = 17; + } + if (err || s.w.x != 6 || s.y[3] != 12 || s.y[4] != 13 || s.y[5] != 14 + || s.z[1] != 15 || s.z[2] != 16 || s.z[3] != 17) + abort (); + s.u++; + s.v.a++; + s.v.b.y++; + s.w.x++; + s.x[1] = 18; + s.z[0] = 19; + #pragma omp target data map (tofrom: s) + #pragma omp target map (always to: s.template w, s.x[1], err) map (alloc:s.u, s. template v.template b, s.z[z:z + 1]) + { + err = 0; + if (s.u != 2 || s.v.b.y != 4LL || s.w.x != 7 || s.x[1] != 18 || s.z[0] != 19) + err = 1; + s.w.x = 8; + s.x[1] = 20; + s.z[0] = 21; + } + if (err || s.w.x != 8 || s.x[1] != 20 || s.z[0] != 21) + abort (); + s.u++; + s.v.a++; + s.v.b.y++; + s.w.x++; + s.x[0] = 22; + s.x[1] = 23; + #pragma omp target data map (from: s.w, s.x[0:2]) map (to: s.v.b, s.u) + #pragma omp target map (always to: s.w, s.x[0:2], err) map (alloc:s.u, s.v.b) + { + err = 0; + if (s.u != 3 || s.v.b.y != 5LL || s.w.x != 9 || s.x[0] != 22 || s.x[1] != 23) + err = 1; + s.w.x = 11; + s.x[0] = 24; + s.x[1] = 25; + } + if (err || s.w.x != 11 || s.x[0] != 24 || s.x[1] != 25) + abort (); +} + +int +main () +{ + S s; + s.s = 0; + s.u = 1; + s.v.a = 2; + s.v.b.y = 3LL; + s.v.c = 19; + s.w.x = 4; + s.x[0] = 7; + s.x[1] = 8; + s.y[3] = 9; + s.y[4] = 10; + s.y[5] = 11; + int err = 0; + #pragma omp target map (to:s.v.b, s.u, s.x[0:z + 2]) \ + map (tofrom:s.y[3:3]) \ + map (from: s.w, s.z[z + 1:z + 3], err) + { + err = 0; + if (s.u != 1 || s.v.b.y != 3LL || s.x[0] != 7 || s.x[1] != 8 + || s.y[3] != 9 || s.y[4] != 10 || s.y[5] != 11) + err = 1; + s.w.x = 6; + s.y[3] = 12; + s.y[4] = 13; + s.y[5] = 14; + s.z[1] = 15; + s.z[2] = 16; + s.z[3] = 17; + } + if (err || s.w.x != 6 || s.y[3] != 12 || s.y[4] != 13 || s.y[5] != 14 + || s.z[1] != 15 || s.z[2] != 16 || s.z[3] != 17) + abort (); + s.u++; + s.v.a++; + s.v.b.y++; + s.w.x++; + s.x[1] = 18; + s.z[0] = 19; + #pragma omp target data map (tofrom: s) + #pragma omp target map (always to: s.w, s.x[1], err) map (alloc:s.u, s.v.b, s.z[z:z + 1]) + { + err = 0; + if (s.u != 2 || s.v.b.y != 4LL || s.w.x != 7 || s.x[1] != 18 || s.z[0] != 19) + err = 1; + s.w.x = 8; + s.x[1] = 20; + s.z[0] = 21; + } + if (err || s.w.x != 8 || s.x[1] != 20 || s.z[0] != 21) + abort (); + s.u++; + s.v.a++; + s.v.b.y++; + s.w.x++; + s.x[0] = 22; + s.x[1] = 23; + #pragma omp target data map (from: s.w, s.x[0:2]) map (to: s.v.b, s.u) + #pragma omp target map (always to: s.w, s.x[0:2], err) map (alloc:s.u, s.v.b) + { + err = 0; + if (s.u != 3 || s.v.b.y != 5LL || s.w.x != 9 || s.x[0] != 22 || s.x[1] != 23) + err = 1; + s.w.x = 11; + s.x[0] = 24; + s.x[1] = 25; + } + if (err || s.w.x != 11 || s.x[0] != 24 || s.x[1] != 25) + abort (); + foo (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/target-11.C b/libgomp/testsuite/libgomp.c++/target-11.C new file mode 100644 index 00000000000..fe99603351d --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/target-11.C @@ -0,0 +1,121 @@ +extern "C" void abort (); +struct T { int a; int *b; int c; char (&d)[10]; }; +struct S { int *s; char *u; T v; short *w; short *&x; }; +volatile int z; + +template +void +foo () +{ + A d[10]; + B *e; + C a[32], i; + A b[32]; + B c[32]; + for (i = 0; i < 32; i++) + { + a[i] = i; + b[i] = 32 + i; + c[i] = 64 + i; + } + for (i = 0; i < 10; i++) + d[i] = 17 + i; + e = c + 18; + D s = { a, b + 2, { 0, a + 16, 0, d }, c + 3, e }; + int err = 0; + #pragma omp target map (to:s.v.b[0:z + 7], s.template u[z + 1:z + 4]) \ + map (tofrom:s.s[3:3], s. template v. template d[z + 1:z + 3]) \ + map (from: s.w[z:4], s.x[1:3], err) private (i) + { + err = 0; + for (i = 0; i < 7; i++) + if (s.v.b[i] != 16 + i) + err = 1; + for (i = 1; i < 5; i++) + if (s.u[i] != 34 + i) + err = 1; + for (i = 3; i < 6; i++) + if (s.s[i] != i) + err = 1; + else + s.s[i] = 128 + i; + for (i = 1; i < 4; i++) + if (s.v.d[i] != 17 + i) + err = 1; + else + s.v.d[i] = 23 + i; + for (i = 0; i < 4; i++) + s.w[i] = 96 + i; + for (i = 1; i < 4; i++) + s.x[i] = 173 + i; + } + if (err) + abort (); + for (i = 0; i < 32; i++) + if (a[i] != ((i >= 3 && i < 6) ? 128 + i : i) + || b[i] != 32 + i + || c[i] != ((i >= 3 && i < 7) ? 93 + i : ((i >= 19 && i < 22) ? 155 + i : 64 + i))) + abort (); + for (i = 0; i < 10; i++) + if (d[i] != ((i >= 1 && i < 4) ? 23 + i : 17 + i)) + abort (); +} + +int +main () +{ + char d[10]; + short *e; + int a[32], i; + char b[32]; + short c[32]; + for (i = 0; i < 32; i++) + { + a[i] = i; + b[i] = 32 + i; + c[i] = 64 + i; + } + for (i = 0; i < 10; i++) + d[i] = 17 + i; + e = c + 18; + S s = { a, b + 2, { 0, a + 16, 0, d }, c + 3, e }; + int err = 0; + #pragma omp target map (to:s.v.b[0:z + 7], s.u[z + 1:z + 4]) \ + map (tofrom:s.s[3:3], s.v.d[z + 1:z + 3]) \ + map (from: s.w[z:4], s.x[1:3], err) private (i) + { + err = 0; + for (i = 0; i < 7; i++) + if (s.v.b[i] != 16 + i) + err = 1; + for (i = 1; i < 5; i++) + if (s.u[i] != 34 + i) + err = 1; + for (i = 3; i < 6; i++) + if (s.s[i] != i) + err = 1; + else + s.s[i] = 128 + i; + for (i = 1; i < 4; i++) + if (s.v.d[i] != 17 + i) + err = 1; + else + s.v.d[i] = 23 + i; + for (i = 0; i < 4; i++) + s.w[i] = 96 + i; + for (i = 1; i < 4; i++) + s.x[i] = 173 + i; + } + if (err) + abort (); + for (i = 0; i < 32; i++) + if (a[i] != ((i >= 3 && i < 6) ? 128 + i : i) + || b[i] != 32 + i + || c[i] != ((i >= 3 && i < 7) ? 93 + i : ((i >= 19 && i < 22) ? 155 + i : 64 + i))) + abort (); + for (i = 0; i < 10; i++) + if (d[i] != ((i >= 1 && i < 4) ? 23 + i : 17 + i)) + abort (); + foo (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/target-12.C b/libgomp/testsuite/libgomp.c++/target-12.C new file mode 100644 index 00000000000..3b4ed57df68 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/target-12.C @@ -0,0 +1,93 @@ +extern "C" void abort (void); +struct S { int s; int *u; int v[5]; }; +volatile int z; + +template +void +foo () +{ + int u[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, err = 0; + T s = { 9, u + 3, { 10, 11, 12, 13, 14 } }; + int *v = u + 4; + #pragma omp target enter data map (to: s.s, s.template u[0:5]) map (alloc: s.template v[1:3]) + s.s++; + u[3]++; + s.v[1]++; + #pragma omp target update to (s.template s) to (s.u[0:2], s.v[1:3]) + #pragma omp target map (alloc: s.s, s.v[1:3]) map (from: err) + { + err = 0; + if (s.s != 10 || s.v[1] != 12 || s.v[2] != 12 || s.v[3] != 13) + err = 1; + if (v[-1] != 4 || v[0] != 4 || v[1] != 5 || v[2] != 6 || v[3] != 7) + err = 1; + s.s++; + s.v[2] += 2; + v[-1] = 5; + v[3] = 9; + } + if (err) + abort (); + #pragma omp target map (alloc: s.u[0:5]) + { + err = 0; + if (s.u[0] != 5 || s.u[1] != 4 || s.u[2] != 5 || s.u[3] != 6 || s.u[4] != 9) + err = 1; + s.u[1] = 12; + } + #pragma omp target update from (s.s, s.u[0:5]) from (s.v[1:3]) + if (err || s.s != 11 || u[0] != 0 || u[1] != 1 || u[2] != 2 || u[3] != 5 + || u[4] != 12 || u[5] != 5 || u[6] != 6 || u[7] != 9 || u[8] != 8 + || u[9] != 9 || s.v[0] != 10 || s.v[1] != 12 || s.v[2] != 14 + || s.v[3] != 13 || s.v[4] != 14) + abort (); + #pragma omp target exit data map (release: s.s) + #pragma omp target exit data map (release: s.u[0:5]) + #pragma omp target exit data map (delete: s.v[1:3]) + #pragma omp target exit data map (release: s.s) +} + +int +main () +{ + int u[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, err = 0; + S s = { 9, u + 3, { 10, 11, 12, 13, 14 } }; + int *v = u + 4; + #pragma omp target enter data map (to: s.s, s.u[0:5]) map (alloc: s.v[1:3]) + s.s++; + u[3]++; + s.v[1]++; + #pragma omp target update to (s.s) to (s.u[0:2], s.v[1:3]) + #pragma omp target map (alloc: s.s, s.v[1:3]) map (from: err) + { + err = 0; + if (s.s != 10 || s.v[1] != 12 || s.v[2] != 12 || s.v[3] != 13) + err = 1; + if (v[-1] != 4 || v[0] != 4 || v[1] != 5 || v[2] != 6 || v[3] != 7) + err = 1; + s.s++; + s.v[2] += 2; + v[-1] = 5; + v[3] = 9; + } + if (err) + abort (); + #pragma omp target map (alloc: s.u[0:5]) + { + err = 0; + if (s.u[0] != 5 || s.u[1] != 4 || s.u[2] != 5 || s.u[3] != 6 || s.u[4] != 9) + err = 1; + s.u[1] = 12; + } + #pragma omp target update from (s.s, s.u[0:5]) from (s.v[1:3]) + if (err || s.s != 11 || u[0] != 0 || u[1] != 1 || u[2] != 2 || u[3] != 5 + || u[4] != 12 || u[5] != 5 || u[6] != 6 || u[7] != 9 || u[8] != 8 + || u[9] != 9 || s.v[0] != 10 || s.v[1] != 12 || s.v[2] != 14 + || s.v[3] != 13 || s.v[4] != 14) + abort (); + #pragma omp target exit data map (release: s.s) + #pragma omp target exit data map (release: s.u[0:5]) + #pragma omp target exit data map (always, delete: s.v[1:3]) + #pragma omp target exit data map (release: s.s) + #pragma omp target exit data map (always delete : s.v[1:3]) +} diff --git a/libgomp/testsuite/libgomp.c++/target-2.C b/libgomp/testsuite/libgomp.c++/target-2.C index 35e910acc2e..1eab7f29b4a 100644 --- a/libgomp/testsuite/libgomp.c++/target-2.C +++ b/libgomp/testsuite/libgomp.c++/target-2.C @@ -33,7 +33,8 @@ fn2 (int x, double (&dr) [1024], double *&er) int j; fn1 (hr + 2 * x, ir + 2 * x, x); #pragma omp target map(to: br[:x], cr[0:x], dr[x:x], er[x:x]) \ - map(to: fr[0:x], gr[0:x], hr[2 * x:x], ir[2 * x:x]) + map(to: fr[0:x], gr[0:x], hr[2 * x:x], ir[2 * x:x]) \ + map(tofrom: s) #pragma omp parallel for reduction(+:s) for (j = 0; j < x; j++) s += br[j] * cr[j] + dr[x + j] + er[x + j] diff --git a/libgomp/testsuite/libgomp.c++/target-5.C b/libgomp/testsuite/libgomp.c++/target-5.C new file mode 100644 index 00000000000..6639be394c6 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/target-5.C @@ -0,0 +1 @@ +#include "../libgomp.c/target-13.c" diff --git a/libgomp/testsuite/libgomp.c++/target-6.C b/libgomp/testsuite/libgomp.c++/target-6.C new file mode 100644 index 00000000000..8dbafb0437b --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/target-6.C @@ -0,0 +1,64 @@ +extern "C" void abort (void); +struct S { int s, t; }; + +void +foo (int &x, int &y, S &u, S &v, double &s, double &t) +{ + int err = 0, i; + int a[y - 2], b[y - 2]; + int (&c)[y - 2] = a, (&d)[y - 2] = b; + for (i = 0; i < y - 2; i++) + { + c[i] = i; + d[i] = 3 + i; + } + #pragma omp target private (x, u, s, c, i) firstprivate (y, v, t, d) map(from:err) + { + x = y; + u = v; + s = t; + for (i = 0; i < y - 2; i++) + c[i] = d[i]; + err = (x != 6 || y != 6 + || u.s != 9 || u.t != 10 || v.s != 9 || v.t != 10 + || s != 12.5 || t != 12.5); + for (i = 0; i < y - 2; i++) + if (d[i] != 3 + i || c[i] != 3 + i) + err = 1; + else + { + c[i] += 2 * i; + d[i] += i; + } + x += 1; + y += 2; + u.s += 3; + v.t += 4; + s += 2.5; + t += 3.0; + if (x != 7 || y != 8 + || u.s != 12 || u.t != 10 || v.s != 9 || v.t != 14 + || s != 15.0 || t != 15.5) + err = 1; + for (i = 0; i < y - 4; i++) + if (d[i] != 3 + 2 * i || c[i] != 3 + 3 * i) + err = 1; + } + if (err || x != 5 || y != 6 + || u.s != 7 || u.t != 8 || v.s != 9 || v.t != 10 + || s != 11.5 || t != 12.5) + abort (); + for (i = 0; i < y - 2; i++) + if (d[i] != 3 + i || c[i] != i) + abort (); +} + +int +main () +{ + int x = 5, y = 6; + S u = { 7, 8 }, v = { 9, 10 }; + double s = 11.5, t = 12.5; + foo (x, y, u, v, s, t); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/target-7.C b/libgomp/testsuite/libgomp.c++/target-7.C new file mode 100644 index 00000000000..e13c50f26da --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/target-7.C @@ -0,0 +1,90 @@ +extern "C" void abort (); + +void +foo (int *x, int *&y, int (&z)[15]) +{ + int a[10], b[15], err, i; + for (i = 0; i < 10; i++) + a[i] = 7 * i; + for (i = 0; i < 15; i++) + b[i] = 8 * i; + #pragma omp target map(to:x[5:10], y[5:10], z[5:10], a[0:10], b[5:10]) map(from:err) + { + err = 0; + for (i = 0; i < 10; i++) + if (x[5 + i] != 20 + 4 * i + || y[5 + i] != 25 + 5 * i + || z[5 + i] != 30 + 6 * i + || a[i] != 7 * i + || b[5 + i] != 40 + 8 * i) + err = 1; + } + if (err) + abort (); +} + +void +bar (int n, int v) +{ + int a[n], b[n], c[n], d[n], e[n], err, i; + int (*x)[n] = &c; + int (*y2)[n] = &d; + int (*&y)[n] = y2; + int (&z)[n] = e; + for (i = 0; i < n; i++) + { + (*x)[i] = 4 * i; + (*y)[i] = 5 * i; + z[i] = 6 * i; + a[i] = 7 * i; + b[i] = 8 * i; + } + #pragma omp target map(to:x[0][5:10], y[0][5:10], z[5:10], a[0:10], b[5:10]) map(from:err) + { + err = 0; + for (i = 0; i < 10; i++) + if ((*x)[5 + i] != 20 + 4 * i + || (*y)[5 + i] != 25 + 5 * i + || z[5 + i] != 30 + 6 * i + || a[i] != 7 * i + || b[5 + i] != 40 + 8 * i) + err = 1; + } + if (err) + abort (); + for (i = 0; i < n; i++) + { + (*x)[i] = 9 * i; + (*y)[i] = 10 * i; + z[i] = 11 * i; + a[i] = 12 * i; + b[i] = 13 * i; + } + #pragma omp target map(to:x[0][v:v+5], y[0][v:v+5], z[v:v+5], a[v-5:v+5], b[v:v+5]) map(from:err) + { + err = 0; + for (i = 0; i < 10; i++) + if ((*x)[5 + i] != 45 + 9 * i + || (*y)[5 + i] != 50 + 10 * i + || z[5 + i] != 55 + 11 * i + || a[i] != 12 * i + || b[5 + i] != 65 + 13 * i) + err = 1; + } + if (err) + abort (); +} + +int +main () +{ + int x[15], y2[15], z[15], *y = y2, i; + for (i = 0; i < 15; i++) + { + x[i] = 4 * i; + y[i] = 5 * i; + z[i] = 6 * i; + } + foo (x, y, z); + bar (15, 5); +} diff --git a/libgomp/testsuite/libgomp.c++/target-8.C b/libgomp/testsuite/libgomp.c++/target-8.C new file mode 100644 index 00000000000..d886b476754 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/target-8.C @@ -0,0 +1,58 @@ +extern "C" void abort (); +struct S { int a; }; +#ifdef __SIZEOF_INT128__ +typedef __int128 T; +#else +typedef long long int T; +#endif + +void +foo (T a, int b, struct S c) +{ + int err; + #pragma omp target firstprivate (a, b, c) map(from:err) + { + err = 0; + if (a != 131 || b != 276 || c.a != 59) + err = 1; + a = 936; + b = 27; + c.a = 98; + if (a != 936 || b != 27 || c.a != 98) + err = 1; + } + if (err || a != 131 || b != 276 || c.a != 59) + abort (); +} + +void +bar (T &a, int &b, struct S &c) +{ + int err; + #pragma omp target firstprivate (a, b, c) map(from:err) + { + err = 0; + if (a != 131 || b != 276 || c.a != 59) + err = 1; + a = 936; + b = 27; + c.a = 98; + if (a != 936 || b != 27 || c.a != 98) + err = 1; + } + if (err || a != 131 || b != 276 || c.a != 59) + abort (); +} + +int +main () +{ + T a = 131; + int b = 276; + struct S c; + c.a = 59; + foo (a, b, c); + bar (a, b, c); + if (a != 131 || b != 276 || c.a != 59) + abort (); +} diff --git a/libgomp/testsuite/libgomp.c++/target-9.C b/libgomp/testsuite/libgomp.c++/target-9.C new file mode 100644 index 00000000000..a5d171b0b3d --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/target-9.C @@ -0,0 +1,73 @@ +extern "C" void abort (void); + +void +foo (int *&p, int (&s)[5], int n) +{ + int a[4] = { 7, 8, 9, 10 }, b[n], c[3] = { 20, 21, 22 }; + int *r = a + 1, *q = p - 1, i, err; + for (i = 0; i < n; i++) + b[i] = 9 + i; + #pragma omp target data map(to:a) + #pragma omp target data use_device_ptr(r) map(from:err) + #pragma omp target is_device_ptr(r) private(i) map(from:err) + { + err = 0; + for (i = 0; i < 4; i++) + if (r[i - 1] != 7 + i) + err = 1; + } + if (err) + abort (); + #pragma omp target data map(to:q[:4]) + #pragma omp target data use_device_ptr(p) map(from:err) + #pragma omp target is_device_ptr(p) private(i) map(from:err) + { + err = 0; + for (i = 0; i < 4; i++) + if (p[i - 1] != i) + err = 1; + } + if (err) + abort (); + #pragma omp target data map(to:b) + #pragma omp target data use_device_ptr(b) map(from:err) + #pragma omp target is_device_ptr(b) private(i) map(from:err) + { + err = 0; + for (i = 0; i < n; i++) + if (b[i] != 9 + i) + err = 1; + } + if (err) + abort (); + #pragma omp target data map(to:c) + #pragma omp target data use_device_ptr(c) map(from:err) + #pragma omp target is_device_ptr(c) private(i) map(from:err) + { + err = 0; + for (i = 0; i < 3; i++) + if (c[i] != 20 + i) + err = 1; + } + if (err) + abort (); + #pragma omp target data map(to:s[:5]) + #pragma omp target data use_device_ptr(s) map(from:err) + #pragma omp target is_device_ptr(s) private(i) map(from:err) + { + err = 0; + for (i = 0; i < 5; i++) + if (s[i] != 17 + i) + err = 1; + } + if (err) + abort (); +} + +int +main () +{ + int a[4] = { 0, 1, 2, 3 }, b[5] = { 17, 18, 19, 20, 21 }; + int *p = a + 1; + foo (p, b, 9); +} diff --git a/libgomp/testsuite/libgomp.c++/taskloop-1.C b/libgomp/testsuite/libgomp.c++/taskloop-1.C new file mode 100644 index 00000000000..66f8e0b1d7c --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/taskloop-1.C @@ -0,0 +1,4 @@ +// { dg-do run } +// { dg-options "-O2 -fopenmp" } + +#include "../libgomp.c/taskloop-1.c" diff --git a/libgomp/testsuite/libgomp.c++/taskloop-2.C b/libgomp/testsuite/libgomp.c++/taskloop-2.C new file mode 100644 index 00000000000..67a0e92717e --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/taskloop-2.C @@ -0,0 +1,6 @@ +// { dg-do run } +// { dg-options "-O2" } +// { dg-additional-options "-msse2" { target sse2_runtime } } +// { dg-additional-options "-mavx" { target avx_runtime } } + +#include "../libgomp.c/taskloop-2.c" diff --git a/libgomp/testsuite/libgomp.c++/taskloop-3.C b/libgomp/testsuite/libgomp.c++/taskloop-3.C new file mode 100644 index 00000000000..bfd793c1c58 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/taskloop-3.C @@ -0,0 +1,4 @@ +// { dg-do run } +// { dg-options "-O2 -fopenmp" } + +#include "../libgomp.c/taskloop-3.c" diff --git a/libgomp/testsuite/libgomp.c++/taskloop-4.C b/libgomp/testsuite/libgomp.c++/taskloop-4.C new file mode 100644 index 00000000000..937cfcc0029 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/taskloop-4.C @@ -0,0 +1,4 @@ +// { dg-do run } +// { dg-options "-O2 -fopenmp" } + +#include "../libgomp.c/taskloop-4.c" diff --git a/libgomp/testsuite/libgomp.c++/taskloop-5.C b/libgomp/testsuite/libgomp.c++/taskloop-5.C new file mode 100644 index 00000000000..eb464467b66 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/taskloop-5.C @@ -0,0 +1,73 @@ +#include + +__attribute__((noinline, noclone)) void +foo (int &b) +{ +#pragma omp parallel +#pragma omp single + { + bool f = false; + #pragma omp taskloop firstprivate (b, f) + for (int i = 0; i < 30; i++) + { + int q = omp_get_thread_num (); + if (!f) + { + if (b != 2) + __builtin_abort (); + } + else if (b != 8 * q) + __builtin_abort (); + b = 8 * q; + f = true; + } + } + int n; +#pragma omp parallel +#pragma omp single + { + bool f = false; + #pragma omp taskloop firstprivate (f) lastprivate (b, n) + for (int i = 0; i < 30; i++) + { + int q = omp_get_thread_num (); + if (f && b != 8 * q) + __builtin_abort (); + b = 8 * q; + n = q; + f = true; + } + } + if (b != 8 * n) + __builtin_abort (); + b = 9; +#pragma omp parallel +#pragma omp single + { + bool f = false; + #pragma omp taskloop firstprivate (b, f) lastprivate (b, n) + for (int i = 0; i < 30; i++) + { + int q = omp_get_thread_num (); + if (!f) + { + if (b != 9) + __builtin_abort (); + } + else if (b != 11 * q) + __builtin_abort (); + b = 11 * q; + n = q; + f = true; + } + } + if (b != 11 * n) + __builtin_abort (); +} + +int +main () +{ + int b = 2; + foo (b); +} diff --git a/libgomp/testsuite/libgomp.c++/taskloop-6.C b/libgomp/testsuite/libgomp.c++/taskloop-6.C new file mode 100644 index 00000000000..edf7f7a371b --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/taskloop-6.C @@ -0,0 +1,442 @@ +// { dg-do run } + +typedef __PTRDIFF_TYPE__ ptrdiff_t; +extern "C" void abort (); + +template +class I +{ +public: + typedef ptrdiff_t difference_type; + I (); + ~I (); + I (T *); + I (const I &); + T &operator * (); + T *operator -> (); + T &operator [] (const difference_type &) const; + I &operator = (const I &); + I &operator ++ (); + I operator ++ (int); + I &operator -- (); + I operator -- (int); + I &operator += (const difference_type &); + I &operator -= (const difference_type &); + I operator + (const difference_type &) const; + I operator - (const difference_type &) const; + template friend bool operator == (I &, I &); + template friend bool operator == (const I &, const I &); + template friend bool operator < (I &, I &); + template friend bool operator < (const I &, const I &); + template friend bool operator <= (I &, I &); + template friend bool operator <= (const I &, const I &); + template friend bool operator > (I &, I &); + template friend bool operator > (const I &, const I &); + template friend bool operator >= (I &, I &); + template friend bool operator >= (const I &, const I &); + template friend typename I::difference_type operator - (I &, I &); + template friend typename I::difference_type operator - (const I &, const I &); + template friend I operator + (typename I::difference_type , const I &); +private: + T *p; +}; +template I::I () : p (0) {} +template I::~I () {} +template I::I (T *x) : p (x) {} +template I::I (const I &x) : p (x.p) {} +template T &I::operator * () { return *p; } +template T *I::operator -> () { return p; } +template T &I::operator [] (const difference_type &x) const { return p[x]; } +template I &I::operator = (const I &x) { p = x.p; return *this; } +template I &I::operator ++ () { ++p; return *this; } +template I I::operator ++ (int) { return I (p++); } +template I &I::operator -- () { --p; return *this; } +template I I::operator -- (int) { return I (p--); } +template I &I::operator += (const difference_type &x) { p += x; return *this; } +template I &I::operator -= (const difference_type &x) { p -= x; return *this; } +template I I::operator + (const difference_type &x) const { return I (p + x); } +template I I::operator - (const difference_type &x) const { return I (p - x); } +template bool operator == (I &x, I &y) { return x.p == y.p; } +template bool operator == (const I &x, const I &y) { return x.p == y.p; } +template bool operator != (I &x, I &y) { return !(x == y); } +template bool operator != (const I &x, const I &y) { return !(x == y); } +template bool operator < (I &x, I &y) { return x.p < y.p; } +template bool operator < (const I &x, const I &y) { return x.p < y.p; } +template bool operator <= (I &x, I &y) { return x.p <= y.p; } +template bool operator <= (const I &x, const I &y) { return x.p <= y.p; } +template bool operator > (I &x, I &y) { return x.p > y.p; } +template bool operator > (const I &x, const I &y) { return x.p > y.p; } +template bool operator >= (I &x, I &y) { return x.p >= y.p; } +template bool operator >= (const I &x, const I &y) { return x.p >= y.p; } +template typename I::difference_type operator - (I &x, I &y) { return x.p - y.p; } +template typename I::difference_type operator - (const I &x, const I &y) { return x.p - y.p; } +template I operator + (typename I::difference_type x, const I &y) { return I (x + y.p); } + +template +class J +{ +public: + J(const I &x, const I &y) : b (x), e (y) {} + const I &begin (); + const I &end (); +private: + I b, e; +}; + +template const I &J::begin () { return b; } +template const I &J::end () { return e; } + +int results[2000]; + +template +void +baz (I &i) +{ + if (*i < 0 || *i >= 2000) + abort (); + results[*i]++; +} + +void +f1 (const I &x, const I &y) +{ +#pragma omp parallel +#pragma omp single +#pragma omp taskloop num_tasks(22) + for (I i = x; i <= y; i += 6) + baz (i); +} + +void +f2 (const I &x, const I &y) +{ + I i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop grainsize(384) private(i) + for (i = x; i < y - 1; i = 1 - 6 + 7 + i) + baz (i); +} + +template +void +f3 (const I &x, const I &y) +{ +#pragma omp parallel +#pragma omp single +#pragma omp taskloop default(none) firstprivate (x, y) + for (I i = x; i <= y; i = i + 9 - 8) + baz (i); +} + +template +void +f4 (const I &x, const I &y) +{ + I i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop lastprivate(i) + for (i = x + 2000 - 64; i > y + 10; --i) + baz (i); +} + +void +f5 (const I &x, const I &y) +{ +#pragma omp parallel +#pragma omp single +#pragma omp taskloop + for (I i = x + 2000 - 64; i > y + 10; i -= 10) + baz (i); +} + +template +void +f6 (const I &x, const I &y) +{ +#pragma omp parallel +#pragma omp single +#pragma omp taskloop + for (I i = x + 2000 - 64; i > y + 10; i = i - 12 + 2) + { + I j = i + N; + baz (j); + } +} + +template +void +f7 (I i, const I &x, const I &y) +{ +#pragma omp parallel +#pragma omp single +#pragma omp taskloop default(none) firstprivate (x, y) + for (i = x - 10; i <= y + 10; i += N) + baz (i); +} + +template +void +f8 (J j) +{ + I i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop default(none) num_tasks(*I (j.begin ())) firstprivate (j) + for (i = j.begin (); i <= j.end () + N; i += 2) + baz (i); +} + +template +void +f9 (const I &x, const I &y) +{ +#pragma omp parallel +#pragma omp single +#pragma omp taskloop grainsize(163) + for (I i = x; i <= y; i = i + N) + baz (i); +} + +template +void +f10 (const I &x, const I &y) +{ + I i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop + for (i = x; i > y; i = i + N) + baz (i); +} + +template +void +f11 (const T &x, const T &y) +{ +#pragma omp parallel + { +#pragma omp single nowait +#pragma omp taskloop nogroup + for (T i = x; i <= y; i += 3) + baz (i); +#pragma omp single nowait + { + T j = y + 3; + baz (j); + } + } +} + +template +void +f12 (const T &x, const T &y) +{ + T i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop + for (i = x; i > y; --i) + baz (i); +} + +template +struct K +{ + template + static void + f13 (const T &x, const T &y) + { +#pragma omp parallel +#pragma omp single +#pragma omp taskloop + for (T i = x; i <= y + N; i += N) + baz (i); + } +}; + +I +f14 (const I &x, const I &y) +{ + I i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop lastprivate(i) + for (i = x; i < y - 1; i = 1 - 6 + 7 + i) + baz (i); + return i; +} + +template +I +f15 (const I &x, const I &y) +{ + I i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop lastprivate(i) + for (i = x + 2000 - 64; i > y + 10; --i) + baz (i); + return i; +} + +template +I +f16 (I i, const I &x, const I &y) +{ +#pragma omp parallel +#pragma omp single +#pragma omp taskloop lastprivate(i) + for (i = x - 10; i <= y + 10; i += N) + baz (i); + return i; +} + +template +I +f17 (J j) +{ + static I i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop lastprivate(i) + for (i = j.begin (); i <= j.end () + N; i += 2) + baz (i); + return i; +} + +template +I +f18 (const I &x, const I &y) +{ + static I i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop lastprivate(i) + for (i = x; i > y; i = i + N) + baz (i); + return i; +} + +template +T +f19 (const T &x, const T &y) +{ + T i; +#pragma omp parallel + { +#pragma omp single nowait +#pragma omp taskloop nogroup lastprivate(i) + for (i = x; i <= y; i += 3) + baz (i); +#pragma omp single nowait + { + T j = y + 3; + baz (j); + } + } + return i; +} + +template +T +f20 (const T &x, const T &y) +{ + T i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop lastprivate(i) + for (i = x; i > y; --i) + baz (i); + return i; +} + +#define check(expr) \ + for (int i = 0; i < 2000; i++) \ + if (expr) \ + { \ + if (results[i] != 1) \ + abort (); \ + results[i] = 0; \ + } \ + else if (results[i]) \ + abort () + +int +main () +{ + int a[2000]; + long b[2000]; + for (int i = 0; i < 2000; i++) + { + a[i] = i; + b[i] = i; + } + f1 (&a[10], &a[1990]); + check (i >= 10 && i <= 1990 && (i - 10) % 6 == 0); + f2 (&a[0], &a[1999]); + check (i < 1998 && (i & 1) == 0); + f3 (&a[20], &a[1837]); + check (i >= 20 && i <= 1837); + f4 (&a[0], &a[30]); + check (i > 40 && i <= 2000 - 64); + f5 (&a[0], &a[100]); + check (i >= 116 && i <= 2000 - 64 && (i - 116) % 10 == 0); + f6<-10> (&a[10], &a[110]); + check (i >= 116 && i <= 2000 - 64 && (i - 116) % 10 == 0); + f7<6> (I (), &a[12], &a[1800]); + check (i >= 2 && i <= 1808 && (i - 2) % 6 == 0); + f8<121> (J (&a[14], &a[1803])); + check (i >= 14 && i <= 1924 && (i & 1) == 0); + f9 (&a[33], &a[1967]); + check (i >= 33 && i <= 1967 && (i - 33) % 7 == 0); + f10 (&a[1939], &a[17]); + check (i >= 21 && i <= 1939 && (i - 21) % 7 == 0); + f11 > (&a[16], &a[1981]); + check (i >= 16 && i <= 1984 && (i - 16) % 3 == 0); + f12 > (&a[1761], &a[37]); + check (i > 37 && i <= 1761); + K<5>::f13 > (&a[1], &a[1935]); + check (i >= 1 && i <= 1936 && (i - 1) % 5 == 0); + if (f14 (&a[0], &a[1999]) != I(&a[1998])) + abort (); + check (i < 1998 && (i & 1) == 0); + if (f15 (&a[0], &a[30]) != I(&a[40])) + abort (); + check (i > 40 && i <= 2000 - 64); + if (f16<6> (I (), &a[12], &a[1800]) != I(&a[1814])) + abort (); + check (i >= 2 && i <= 1808 && (i - 2) % 6 == 0); + if (f17<121> (J (&a[14], &a[1803])) != I(&a[1926])) + abort (); + check (i >= 14 && i <= 1924 && (i & 1) == 0); + if (f18 (&a[1939], &a[17]) != I(&a[14])) + abort (); + check (i >= 21 && i <= 1939 && (i - 21) % 7 == 0); + if (f19 > (&a[16], &a[1981]) != I(&a[1984])) + abort (); + check (i >= 16 && i <= 1984 && (i - 16) % 3 == 0); + if (f20 > (&a[1761], &a[37]) != I(&a[37])) + abort (); + check (i > 37 && i <= 1761); + f9 (&b[33], &b[1967]); + check (i >= 33 && i <= 1967 && (i - 33) % 7 == 0); + f10 (&b[1939], &b[17]); + check (i >= 21 && i <= 1939 && (i - 21) % 7 == 0); + f11 > (&b[16], &b[1981]); + check (i >= 16 && i <= 1984 && (i - 16) % 3 == 0); + f12 > (&b[1761], &b[37]); + check (i > 37 && i <= 1761); + K<5>::f13 > (&b[1], &b[1935]); + check (i >= 1 && i <= 1936 && (i - 1) % 5 == 0); + if (f18 (&b[1939], &b[17]) != I(&b[14])) + abort (); + check (i >= 21 && i <= 1939 && (i - 21) % 7 == 0); + if (f19 > (&b[16], &b[1981]) != I(&b[1984])) + abort (); + check (i >= 16 && i <= 1984 && (i - 16) % 3 == 0); + if (f20 > (&b[1761], &b[37]) != I(&b[37])) + abort (); + check (i > 37 && i <= 1761); +} diff --git a/libgomp/testsuite/libgomp.c++/taskloop-7.C b/libgomp/testsuite/libgomp.c++/taskloop-7.C new file mode 100644 index 00000000000..b9a3c81e381 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/taskloop-7.C @@ -0,0 +1,400 @@ +// { dg-do run } + +#include +#include + +template +class J +{ +public: + typedef typename std::vector::const_iterator const_iterator; + J(const const_iterator &x, const const_iterator &y) : b (x), e (y) {} + const const_iterator &begin (); + const const_iterator &end (); +private: + const_iterator b, e; +}; + +template +const typename std::vector::const_iterator &J::begin () { return b; } +template +const typename std::vector::const_iterator &J::end () { return e; } + +int results[2000]; + +template +void +baz (T &i) +{ + if (*i < 0 || *i >= 2000) + std::abort (); + results[*i]++; +} + +void +f1 (const std::vector::const_iterator &x, + const std::vector::const_iterator &y) +{ +#pragma omp parallel +#pragma omp single +#pragma omp taskloop + for (std::vector::const_iterator i = x; i <= y; i += 6) + baz (i); +} + +void +f2 (const std::vector::const_iterator &x, + const std::vector::const_iterator &y) +{ + std::vector::const_iterator i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop private(i) + for (i = x; i < y - 1; i = 1 - 6 + 7 + i) + baz (i); +} + +template +void +f3 (const std::vector::const_iterator &x, + const std::vector::const_iterator &y) +{ +#pragma omp parallel +#pragma omp single +#pragma omp taskloop + for (std::vector::const_iterator i = x; i <= y; i = i + 9 - 8) + baz (i); +} + +template +void +f4 (const std::vector::const_iterator &x, + const std::vector::const_iterator &y) +{ + std::vector::const_iterator i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop lastprivate(i) + for (i = x + 2000 - 64; i > y + 10; --i) + baz (i); +} + +void +f5 (const std::vector::const_iterator &x, + const std::vector::const_iterator &y) +{ +#pragma omp parallel +#pragma omp single +#pragma omp taskloop + for (std::vector::const_iterator i = x + 2000 - 64; i > y + 10; i -= 10) + baz (i); +} + +template +void +f6 (const std::vector::const_iterator &x, + const std::vector::const_iterator &y) +{ +#pragma omp parallel +#pragma omp single +#pragma omp taskloop + for (std::vector::const_iterator i = x + 2000 - 64; + i > y + 10; i = i - 12 + 2) + { + std::vector::const_iterator j = i + N; + baz (j); + } +} + +template +void +f7 (std::vector::const_iterator i, + const std::vector::const_iterator &x, + const std::vector::const_iterator &y) +{ +#pragma omp parallel +#pragma omp single +#pragma omp taskloop + for (i = x - 10; i <= y + 10; i += N) + baz (i); +} + +template +void +f8 (J j) +{ + std::vector::const_iterator i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop + for (i = j.begin (); i <= j.end () + N; i += 2) + baz (i); +} + +template +void +f9 (const typename std::vector::const_iterator &x, + const typename std::vector::const_iterator &y) +{ +#pragma omp parallel +#pragma omp single +#pragma omp taskloop + for (typename std::vector::const_iterator i = x; i <= y; i = i + N) + baz (i); +} + +template +void +f10 (const typename std::vector::const_iterator &x, + const typename std::vector::const_iterator &y) +{ + typename std::vector::const_iterator i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop + for (i = x; i > y; i = i + N) + baz (i); +} + +template +void +f11 (const T &x, const T &y) +{ +#pragma omp parallel + { +#pragma omp single nowait +#pragma omp taskloop nogroup + for (T i = x; i <= y; i += 3) + baz (i); +#pragma omp single nowait + { + T j = y + 3; + baz (j); + } + } +} + +template +void +f12 (const T &x, const T &y) +{ + T i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop + for (i = x; i > y; --i) + baz (i); +} + +template +struct K +{ + template + static void + f13 (const T &x, const T &y) + { +#pragma omp parallel +#pragma omp single +#pragma omp taskloop + for (T i = x; i <= y + N; i += N) + baz (i); + } +}; + +std::vector::const_iterator +f14 (const std::vector::const_iterator &x, + const std::vector::const_iterator &y) +{ + std::vector::const_iterator i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop lastprivate(i) + for (i = x; i < y - 1; i = 1 - 6 + 7 + i) + baz (i); + return i; +} + +template +std::vector::const_iterator +f15 (const std::vector::const_iterator &x, + const std::vector::const_iterator &y) +{ + std::vector::const_iterator i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop lastprivate(i) + for (i = x + 2000 - 64; i > y + 10; --i) + baz (i); + return i; +} + +template +std::vector::const_iterator +f16 (std::vector::const_iterator i, + const std::vector::const_iterator &x, + const std::vector::const_iterator &y) +{ +#pragma omp parallel +#pragma omp single +#pragma omp taskloop lastprivate(i) + for (i = x - 10; i <= y + 10; i += N) + baz (i); + return i; +} + +template +std::vector::const_iterator +f17 (J j) +{ + static std::vector::const_iterator i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop lastprivate(i) + for (i = j.begin (); i <= j.end () + N; i += 2) + baz (i); + return i; +} + +template +typename std::vector::const_iterator +f18 (const typename std::vector::const_iterator &x, + const typename std::vector::const_iterator &y) +{ + static typename std::vector::const_iterator i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop lastprivate(i) + for (i = x; i > y; i = i + N) + baz (i); + return i; +} + +template +T +f19 (const T &x, const T &y) +{ + T i; +#pragma omp parallel + { +#pragma omp single nowait +#pragma omp taskloop nogroup lastprivate(i) + for (i = x; i <= y; i += 3) + baz (i); +#pragma omp single nowait + { + T j = y + 3; + baz (j); + } + } + return i; +} + +template +T +f20 (const T &x, const T &y) +{ + T i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop lastprivate(i) + for (i = x; i > y; --i) + baz (i); + return i; +} + +#define check(expr) \ + for (int i = 0; i < 2000; i++) \ + if (expr) \ + { \ + if (results[i] != 1) \ + std::abort (); \ + results[i] = 0; \ + } \ + else if (results[i]) \ + std::abort () + +int +main () +{ + std::vector a(2000); + std::vector b(2000); + for (int i = 0; i < 2000; i++) + { + a[i] = i; + b[i] = i; + } + f1 (a.begin () + 10, a.begin () + 1990); + check (i >= 10 && i <= 1990 && (i - 10) % 6 == 0); + f2 (a.begin () + 0, a.begin () + 1999); + check (i < 1998 && (i & 1) == 0); + f3 (a.begin () + 20, a.begin () + 1837); + check (i >= 20 && i <= 1837); + f4 (a.begin () + 0, a.begin () + 30); + check (i > 40 && i <= 2000 - 64); + f5 (a.begin () + 0, a.begin () + 100); + check (i >= 116 && i <= 2000 - 64 && (i - 116) % 10 == 0); + f6<-10> (a.begin () + 10, a.begin () + 110); + check (i >= 116 && i <= 2000 - 64 && (i - 116) % 10 == 0); + f7<6> (std::vector::const_iterator (), a.begin () + 12, + a.begin () + 1800); + check (i >= 2 && i <= 1808 && (i - 2) % 6 == 0); + f8<121> (J (a.begin () + 14, a.begin () + 1803)); + check (i >= 14 && i <= 1924 && (i & 1) == 0); + f9 (a.begin () + 33, a.begin () + 1967); + check (i >= 33 && i <= 1967 && (i - 33) % 7 == 0); + f10 (a.begin () + 1939, a.begin () + 17); + check (i >= 21 && i <= 1939 && (i - 21) % 7 == 0); + f11::const_iterator > (a.begin () + 16, a.begin () + 1981); + check (i >= 16 && i <= 1984 && (i - 16) % 3 == 0); + f12::const_iterator > (a.begin () + 1761, a.begin () + 37); + check (i > 37 && i <= 1761); + K<5>::f13::const_iterator > (a.begin () + 1, + a.begin () + 1935); + check (i >= 1 && i <= 1936 && (i - 1) % 5 == 0); + if (f14 (a.begin () + 0, a.begin () + 1999) != a.begin () + 1998) + std::abort (); + check (i < 1998 && (i & 1) == 0); + if (f15 (a.begin () + 0, a.begin () + 30) != a.begin () + 40) + std::abort (); + check (i > 40 && i <= 2000 - 64); + if (f16<6> (std::vector::const_iterator (), a.begin () + 12, + a.begin () + 1800) != a.begin () + 1814) + std::abort (); + check (i >= 2 && i <= 1808 && (i - 2) % 6 == 0); + if (f17<121> (J (a.begin () + 14, a.begin () + 1803)) != a.begin () + 1926) + std::abort (); + check (i >= 14 && i <= 1924 && (i & 1) == 0); + if (f18 (a.begin () + 1939, a.begin () + 17) != a.begin () + 14) + std::abort (); + check (i >= 21 && i <= 1939 && (i - 21) % 7 == 0); + if (f19::const_iterator > (a.begin () + 16, a.begin () + 1981) + != a.begin () + 1984) + std::abort (); + check (i >= 16 && i <= 1984 && (i - 16) % 3 == 0); + if (f20::const_iterator > (a.begin () + 1761, a.begin () + 37) + != a.begin () + 37) + std::abort (); + check (i > 37 && i <= 1761); + f9 (b.begin () + 33, b.begin () + 1967); + check (i >= 33 && i <= 1967 && (i - 33) % 7 == 0); + f10 (b.begin () + 1939, b.begin () + 17); + check (i >= 21 && i <= 1939 && (i - 21) % 7 == 0); + f11::const_iterator > (b.begin () + 16, b.begin () + 1981); + check (i >= 16 && i <= 1984 && (i - 16) % 3 == 0); + f12::const_iterator > (b.begin () + 1761, b.begin () + 37); + check (i > 37 && i <= 1761); + K<5>::f13::const_iterator > (b.begin () + 1, + b.begin () + 1935); + check (i >= 1 && i <= 1936 && (i - 1) % 5 == 0); + if (f18 (b.begin () + 1939, b.begin () + 17) != b.begin () + 14) + std::abort (); + check (i >= 21 && i <= 1939 && (i - 21) % 7 == 0); + if (f19::const_iterator > (b.begin () + 16, b.begin () + 1981) + != b.begin () + 1984) + std::abort (); + check (i >= 16 && i <= 1984 && (i - 16) % 3 == 0); + if (f20::const_iterator > (b.begin () + 1761, b.begin () + 37) + != b.begin () + 37) + std::abort (); + check (i > 37 && i <= 1761); +} diff --git a/libgomp/testsuite/libgomp.c++/taskloop-8.C b/libgomp/testsuite/libgomp.c++/taskloop-8.C new file mode 100644 index 00000000000..d164907d1d6 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/taskloop-8.C @@ -0,0 +1,250 @@ +// { dg-do run } + +#include +#include + +template +class J +{ +public: + typedef typename std::basic_string::iterator iterator; + J(const iterator &x, const iterator &y) : b (x), e (y) {} + const iterator &begin (); + const iterator &end (); +private: + iterator b, e; +}; + +template +const typename std::basic_string::iterator &J::begin () { return b; } +template +const typename std::basic_string::iterator &J::end () { return e; } + +template +void +baz (T &i) +{ + if (*i < L'a' || *i >= L'a' + 2000) + std::abort (); + (*i)++; +} + +void +f1 (const std::basic_string::iterator &x, + const std::basic_string::iterator &y) +{ +#pragma omp parallel +#pragma omp single +#pragma omp taskloop + for (std::basic_string::iterator i = x; i <= y; i += 6) + baz (i); +} + +void +f2 (const std::basic_string::iterator &x, + const std::basic_string::iterator &y) +{ + std::basic_string::iterator i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop private(i) + for (i = x; i < y - 1; i = 1 - 6 + 7 + i) + baz (i); +} + +template +void +f3 (const std::basic_string::iterator &x, + const std::basic_string::iterator &y) +{ +#pragma omp parallel +#pragma omp single +#pragma omp taskloop + for (std::basic_string::iterator i = x; i <= y; i = i + 9 - 8) + baz (i); +} + +template +void +f4 (const std::basic_string::iterator &x, + const std::basic_string::iterator &y) +{ + std::basic_string::iterator i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop lastprivate(i) + for (i = x + 2000 - 64; i > y + 10; --i) + baz (i); +} + +void +f5 (const std::basic_string::iterator &x, + const std::basic_string::iterator &y) +{ +#pragma omp parallel +#pragma omp single +#pragma omp taskloop + for (std::basic_string::iterator i = x + 2000 - 64; + i > y + 10; i -= 10) + baz (i); +} + +template +void +f6 (const std::basic_string::iterator &x, + const std::basic_string::iterator &y) +{ +#pragma omp parallel +#pragma omp single +#pragma omp taskloop + for (std::basic_string::iterator i = x + 2000 - 64; + i > y + 10; i = i - 12 + 2) + { + std::basic_string::iterator j = i + N; + baz (j); + } +} + +template +void +f7 (std::basic_string::iterator i, + const std::basic_string::iterator &x, + const std::basic_string::iterator &y) +{ +#pragma omp parallel +#pragma omp single +#pragma omp taskloop + for (i = x - 10; i <= y + 10; i += N) + baz (i); +} + +template +void +f8 (J j) +{ + std::basic_string::iterator i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop + for (i = j.begin (); i <= j.end () + N; i += 2) + baz (i); +} + +template +void +f9 (const typename std::basic_string::iterator &x, + const typename std::basic_string::iterator &y) +{ +#pragma omp parallel +#pragma omp single +#pragma omp taskloop + for (typename std::basic_string::iterator i = x; i <= y; i = i + N) + baz (i); +} + +template +void +f10 (const typename std::basic_string::iterator &x, + const typename std::basic_string::iterator &y) +{ + typename std::basic_string::iterator i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop + for (i = x; i > y; i = i + N) + baz (i); +} + +template +void +f11 (const T &x, const T &y) +{ +#pragma omp parallel + { +#pragma omp single nowait +#pragma omp taskloop nogroup + for (T i = x; i <= y; i += 3) + baz (i); +#pragma omp single nowait + { + T j = y + 3; + baz (j); + } + } +} + +template +void +f12 (const T &x, const T &y) +{ + T i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop private(i) + for (i = x; i > y; --i) + baz (i); +} + +template +struct K +{ + template + static void + f13 (const T &x, const T &y) + { +#pragma omp parallel +#pragma omp single +#pragma omp taskloop + for (T i = x; i <= y + N; i += N) + baz (i); + } +}; + +#define check(expr) \ + for (int i = 0; i < 2000; i++) \ + if (expr) \ + { \ + if (a[i] != L'a' + i + 1) \ + std::abort (); \ + a[i] = L'a' + i; \ + } \ + else if (a[i] != L'a' + i) \ + std::abort () + +int +main () +{ + std::basic_string a = L""; + for (int i = 0; i < 2000; i++) + a += L'a' + i; + f1 (a.begin () + 10, a.begin () + 1990); + check (i >= 10 && i <= 1990 && (i - 10) % 6 == 0); + f2 (a.begin () + 0, a.begin () + 1999); + check (i < 1998 && (i & 1) == 0); + f3 (a.begin () + 20, a.begin () + 1837); + check (i >= 20 && i <= 1837); + f4 (a.begin () + 0, a.begin () + 30); + check (i > 40 && i <= 2000 - 64); + f5 (a.begin () + 0, a.begin () + 100); + check (i >= 116 && i <= 2000 - 64 && (i - 116) % 10 == 0); + f6<-10> (a.begin () + 10, a.begin () + 110); + check (i >= 116 && i <= 2000 - 64 && (i - 116) % 10 == 0); + f7<6> (std::basic_string::iterator (), a.begin () + 12, + a.begin () + 1800); + check (i >= 2 && i <= 1808 && (i - 2) % 6 == 0); + f8<121> (J (a.begin () + 14, a.begin () + 1803)); + check (i >= 14 && i <= 1924 && (i & 1) == 0); + f9 (a.begin () + 33, a.begin () + 1967); + check (i >= 33 && i <= 1967 && (i - 33) % 7 == 0); + f10 (a.begin () + 1939, a.begin () + 17); + check (i >= 21 && i <= 1939 && (i - 21) % 7 == 0); + f11::iterator > (a.begin () + 16, + a.begin () + 1981); + check (i >= 16 && i <= 1984 && (i - 16) % 3 == 0); + f12::iterator > (a.begin () + 1761, + a.begin () + 37); + check (i > 37 && i <= 1761); + K<5>::f13::iterator > (a.begin () + 1, + a.begin () + 1935); + check (i >= 1 && i <= 1936 && (i - 1) % 5 == 0); +} diff --git a/libgomp/testsuite/libgomp.c++/taskloop-9.C b/libgomp/testsuite/libgomp.c++/taskloop-9.C new file mode 100644 index 00000000000..65abc31ff8d --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/taskloop-9.C @@ -0,0 +1,323 @@ +// { dg-do run } + +typedef __PTRDIFF_TYPE__ ptrdiff_t; +extern "C" void abort (); + +template +class I +{ +public: + typedef ptrdiff_t difference_type; + I (); + ~I (); + I (T *); + I (const I &); + T &operator * (); + T *operator -> (); + T &operator [] (const difference_type &) const; + I &operator = (const I &); + I &operator ++ (); + I operator ++ (int); + I &operator -- (); + I operator -- (int); + I &operator += (const difference_type &); + I &operator -= (const difference_type &); + I operator + (const difference_type &) const; + I operator - (const difference_type &) const; + template friend bool operator == (I &, I &); + template friend bool operator == (const I &, const I &); + template friend bool operator < (I &, I &); + template friend bool operator < (const I &, const I &); + template friend bool operator <= (I &, I &); + template friend bool operator <= (const I &, const I &); + template friend bool operator > (I &, I &); + template friend bool operator > (const I &, const I &); + template friend bool operator >= (I &, I &); + template friend bool operator >= (const I &, const I &); + template friend typename I::difference_type operator - (I &, I &); + template friend typename I::difference_type operator - (const I &, const I &); + template friend I operator + (typename I::difference_type , const I &); +private: + T *p; +}; +template I::I () : p (0) {} +template I::~I () { p = (T *) 0; } +template I::I (T *x) : p (x) {} +template I::I (const I &x) : p (x.p) {} +template T &I::operator * () { return *p; } +template T *I::operator -> () { return p; } +template T &I::operator [] (const difference_type &x) const { return p[x]; } +template I &I::operator = (const I &x) { p = x.p; return *this; } +template I &I::operator ++ () { ++p; return *this; } +template I I::operator ++ (int) { return I (p++); } +template I &I::operator -- () { --p; return *this; } +template I I::operator -- (int) { return I (p--); } +template I &I::operator += (const difference_type &x) { p += x; return *this; } +template I &I::operator -= (const difference_type &x) { p -= x; return *this; } +template I I::operator + (const difference_type &x) const { return I (p + x); } +template I I::operator - (const difference_type &x) const { return I (p - x); } +template bool operator == (I &x, I &y) { return x.p == y.p; } +template bool operator == (const I &x, const I &y) { return x.p == y.p; } +template bool operator != (I &x, I &y) { return !(x == y); } +template bool operator != (const I &x, const I &y) { return !(x == y); } +template bool operator < (I &x, I &y) { return x.p < y.p; } +template bool operator < (const I &x, const I &y) { return x.p < y.p; } +template bool operator <= (I &x, I &y) { return x.p <= y.p; } +template bool operator <= (const I &x, const I &y) { return x.p <= y.p; } +template bool operator > (I &x, I &y) { return x.p > y.p; } +template bool operator > (const I &x, const I &y) { return x.p > y.p; } +template bool operator >= (I &x, I &y) { return x.p >= y.p; } +template bool operator >= (const I &x, const I &y) { return x.p >= y.p; } +template typename I::difference_type operator - (I &x, I &y) { return x.p - y.p; } +template typename I::difference_type operator - (const I &x, const I &y) { return x.p - y.p; } +template I operator + (typename I::difference_type x, const I &y) { return I (x + y.p); } + +template +class J +{ +public: + J(const I &x, const I &y) : b (x), e (y) {} + const I &begin (); + const I &end (); +private: + I b, e; +}; + +template const I &J::begin () { return b; } +template const I &J::end () { return e; } + +int results[2000]; + +template +void +baz (I &i) +{ + if (*i < 0 || *i >= 2000) + abort (); + results[*i]++; +} + +I +f1 (const I &x, const I &y) +{ + I i; +#pragma omp parallel shared (i) + { + #pragma omp single + #pragma omp taskloop lastprivate (i) + for (i = x; i < y - 1; ++i) + baz (i); + #pragma omp single + i += 3; + } + return I (i); +} + +I +f2 (const I &x, const I &y) +{ + I i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop lastprivate (i) + for (i = x; i < y - 1; i = 1 - 6 + 7 + i) + baz (i); + return I (i); +} + +template +I +f3 (const I &x, const I &y) +{ + I i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop lastprivate (i) + for (i = x + 1000 - 64; i <= y - 10; i++) + baz (i); + return i; +} + +template +I +f4 (const I &x, const I &y) +{ + I i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop lastprivate (i) + for (i = x + 2000 - 64; i > y + 10; --i) + baz (i); + return I (i); +} + +template +I +f5 (const I &x, const I &y) +{ + I i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop lastprivate (i) + for (i = x; i > y + T (6); i--) + baz (i); + return i; +} + +template +I +f6 (const I &x, const I &y) +{ + I i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop lastprivate (i) + for (i = x - T (7); i > y; i -= T (2)) + baz (i); + return I (i); +} + +template +I +f7 (I i, const I &x, const I &y) +{ +#pragma omp parallel +#pragma omp single +#pragma omp taskloop lastprivate (i) + for (i = x - 10; i <= y + 10; i += N) + baz (i); + return I (i); +} + +template +I +f8 (J j) +{ + I i; +#pragma omp parallel shared (i) + #pragma omp single + #pragma omp taskloop lastprivate (i) + for (i = j.begin (); i <= j.end () + N; i += 2) + baz (i); + return i; +} + +I i9; + +template +I & +f9 (J j) +{ +#pragma omp parallel +#pragma omp single +#pragma omp taskloop lastprivate (i9) + for (i9 = j.begin () + N; i9 <= j.end () - N; i9 = i9 - N) + baz (i9); + return i9; +} + +template +I +f10 (const I &x, const I &y) +{ + I i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop lastprivate (i) + for (i = x; i > y; i = i + N) + baz (i); + return i; +} + +template +T +f11 (T i, const T &x, const T &y) +{ +#pragma omp parallel + #pragma omp single + #pragma omp taskloop lastprivate (i) + for (i = x + U (2); i <= y + U (1); i = U (2) + U (3) + i) + baz (i); + return T (i); +} + +template +T +f12 (const T &x, const T &y) +{ + T i; +#pragma omp parallel +#pragma omp single +#pragma omp taskloop lastprivate (i) + for (i = x; i > y; --i) + baz (i); + return i; +} + +#define check(expr) \ + for (int i = 0; i < 2000; i++) \ + if (expr) \ + { \ + if (results[i] != 1) \ + abort (); \ + results[i] = 0; \ + } \ + else if (results[i]) \ + abort () + +int +main () +{ + int a[2000]; + long b[2000]; + for (int i = 0; i < 2000; i++) + { + a[i] = i; + b[i] = i; + } + if (*f1 (&a[10], &a[1873]) != 1875) + abort (); + check (i >= 10 && i < 1872); + if (*f2 (&a[0], &a[1998]) != 1998) + abort (); + check (i < 1997 && (i & 1) == 0); + if (*f3 (&a[10], &a[1971]) != 1962) + abort (); + check (i >= 946 && i <= 1961); + if (*f4 (&a[0], &a[30]) != 40) + abort (); + check (i > 40 && i <= 2000 - 64); + if (*f5 (&a[1931], &a[17]) != 23) + abort (); + check (i > 23 && i <= 1931); + if (*f6 (&a[1931], &a[17]) != 16) + abort (); + check (i > 17 && i <= 1924 && (i & 1) == 0); + if (*f7<6> (I (), &a[12], &a[1800]) != 1814) + abort (); + check (i >= 2 && i <= 1808 && (i - 2) % 6 == 0); + if (*f8<121> (J (&a[14], &a[1803])) != 1926) + abort (); + check (i >= 14 && i <= 1924 && (i & 1) == 0); + if (*f9<-3L> (J (&a[27], &a[1761])) != 1767) + abort (); + check (i >= 24 && i <= 1764 && (i % 3) == 0); + if (*f10 (&a[1939], &a[17]) != 14) + abort (); + check (i >= 21 && i <= 1939 && i % 7 == 0); + if (*f11, short> (I (), &a[71], &a[1941]) != 1943) + abort (); + check (i >= 73 && i <= 1938 && (i - 73) % 5 == 0); + if (*f12 > (&a[1761], &a[37]) != 37) + abort (); + check (i > 37 && i <= 1761); + if (*f10 (&b[1939], &b[17]) != 14) + abort (); + check (i >= 21 && i <= 1939 && i % 7 == 0); + if (*f11, short> (I (), &b[71], &b[1941]) != 1943) + abort (); + check (i >= 73 && i <= 1938 && (i - 73) % 5 == 0); + if (*f12 > (&b[1761], &b[37]) != 37) + abort (); + check (i > 37 && i <= 1761); +} diff --git a/libgomp/testsuite/libgomp.c/affinity-2.c b/libgomp/testsuite/libgomp.c/affinity-2.c new file mode 100644 index 00000000000..f8216574704 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/affinity-2.c @@ -0,0 +1,89 @@ +/* { dg-do run } */ +/* { dg-set-target-env-var OMP_PROC_BIND "spread,close" } */ +/* { dg-set-target-env-var OMP_PLACES "{6,7}:4:-2,!{2,3}" } */ +/* { dg-set-target-env-var OMP_NUM_THREADS "2" } */ + +#include +#include +#include + +int * +get_buf (int nump) +{ + static int *buf; + static size_t buf_size; + if ((size_t) nump > buf_size) + { + buf_size *= 2; + if (nump > buf_size) + buf_size = nump + 64; + int *bufn = realloc (buf, buf_size * sizeof (int)); + if (bufn == NULL) + { + fprintf (stderr, "memory allocation error\n"); + exit (1); + } + buf = bufn; + } + return buf; +} + +void +print_place (int count, int *ids) +{ + int i, j; + printf ("{"); + for (i = 0; i < count; i++) + { + for (j = i + 1; j < count; j++) + if (ids[j] != ids[i] + (j - i)) + break; + if (i) + printf (","); + if (j == i + 1) + printf ("%d", ids[i]); + else + { + printf ("%d:%d", ids[i], j - i); + i = j - 1; + } + } + printf ("}\n"); +} + +void +print_place_var (void) +{ + int place = omp_get_place_num (); + int num_places = omp_get_partition_num_places (); + int *ids = get_buf (num_places); + omp_get_partition_place_nums (ids); + printf ("place %d\n", place); + if (num_places) + printf ("partition %d-%d\n", ids[0], ids[num_places - 1]); +} + +int +main () +{ + int i, num = omp_get_num_places (), nump, *ids; + printf ("omp_get_num_places () == %d\n", num); + for (i = 0; i < num; i++) + { + printf ("place %d ", i); + nump = omp_get_place_num_procs (i); + ids = get_buf (nump); + omp_get_place_proc_ids (i, ids); + print_place (nump, ids); + } + print_place_var (); + omp_set_nested (1); + #pragma omp parallel + if (omp_get_thread_num () == omp_get_num_threads () - 1) + { + #pragma omp parallel + if (omp_get_thread_num () == omp_get_num_threads () - 1) + print_place_var (); + } + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/doacross-1.c b/libgomp/testsuite/libgomp.c/doacross-1.c new file mode 100644 index 00000000000..0794c80ec2e --- /dev/null +++ b/libgomp/testsuite/libgomp.c/doacross-1.c @@ -0,0 +1,181 @@ +extern void abort (void); + +#define N 256 +int a[N], b[N / 16][8][4], c[N / 32][8][8]; +volatile int d, e; + +int +main () +{ + int i, j, k, l, m; + #pragma omp parallel private (l) + { + #pragma omp for schedule(static, 1) ordered (1) nowait + for (i = 0; i < N; i++) + { + #pragma omp atomic write + a[i] = 1; + #pragma omp ordered depend(sink: i - 1) + if (i) + { + #pragma omp atomic read + l = a[i - 1]; + if (l < 2) + abort (); + } + #pragma omp atomic write + a[i] = 2; + if (i < N - 1) + { + #pragma omp atomic read + l = a[i + 1]; + if (l == 3) + abort (); + } + #pragma omp ordered depend(source) + #pragma omp atomic write + a[i] = 3; + } + #pragma omp for schedule(static, 0) ordered (3) nowait + for (i = 2; i < N / 16 - 1; i++) + for (j = 0; j < 8; j += 2) + for (k = 1; k <= 3; k++) + { + #pragma omp atomic write + b[i][j][k] = 1; + #pragma omp ordered depend(sink: i, j - 2, k - 1) \ + depend(sink: i - 2, j - 2, k + 1) + #pragma omp ordered depend(sink: i - 3, j + 2, k - 2) + if (j >= 2 && k > 1) + { + #pragma omp atomic read + l = b[i][j - 2][k - 1]; + if (l < 2) + abort (); + } + #pragma omp atomic write + b[i][j][k] = 2; + if (i >= 4 && j >= 2 && k < 3) + { + #pragma omp atomic read + l = b[i - 2][j - 2][k + 1]; + if (l < 2) + abort (); + } + if (i >= 5 && j < N / 16 - 3 && k == 3) + { + #pragma omp atomic read + l = b[i - 3][j + 2][k - 2]; + if (l < 2) + abort (); + } + #pragma omp ordered depend(source) + #pragma omp atomic write + b[i][j][k] = 3; + } +#define A(n) int n; +#define B(n) A(n##0) A(n##1) A(n##2) A(n##3) +#define C(n) B(n##0) B(n##1) B(n##2) B(n##3) +#define D(n) C(n##0) C(n##1) C(n##2) C(n##3) + D(m) +#undef A + #pragma omp for collapse (2) ordered(61) schedule(dynamic, 15) + for (i = 0; i < N / 32; i++) + for (j = 7; j > 1; j--) + for (k = 6; k >= 0; k -= 2) +#define A(n) for (n = 4; n < 5; n++) + D(m) +#undef A + { + #pragma omp atomic write + c[i][j][k] = 1; +#define A(n) ,n +#define E(n) C(n##0) C(n##1) C(n##2) B(n##30) B(n##31) A(n##320) A(n##321) + #pragma omp ordered depend (sink: i, j, k + 2 E(m)) \ + depend (sink:i - 2, j + 1, k - 4 E(m)) \ + depend(sink: i - 1, j - 2, k - 2 E(m)) + if (k <= 4) + { + l = c[i][j][k + 2]; + if (l < 2) + abort (); + } + #pragma omp atomic write + c[i][j][k] = 2; + if (i >= 2 && j < 7 && k >= 4) + { + l = c[i - 2][j + 1][k - 4]; + if (l < 2) + abort (); + } + if (i >= 1 && j >= 4 && k >= 2) + { + l = c[i - 1][j - 2][k - 2]; + if (l < 2) + abort (); + } + #pragma omp ordered depend (source) + #pragma omp atomic write + c[i][j][k] = 3; + } + + #pragma omp for collapse(2) ordered(4) lastprivate (i, j, k) + for (i = 0; i < d + 1; i++) + for (j = d + 1; j >= 0; j--) + for (k = 0; k < d; k++) + for (l = 0; l < d + 2; l++) + { + #pragma omp ordered depend (source) + #pragma omp ordered depend (sink:i - 2, j + 2, k - 2, l) + if (!e) + abort (); + } + #pragma omp single + { + if (i != 1 || j != -1 || k != 0) + abort (); + i = 8; j = 9; k = 10; + } + #pragma omp for collapse(2) ordered(4) lastprivate (i, j, k, m) + for (i = 0; i < d + 1; i++) + for (j = d + 1; j >= 0; j--) + for (k = 0; k < d + 2; k++) + for (m = 0; m < d; m++) + { + #pragma omp ordered depend (source) + #pragma omp ordered depend (sink:i - 2, j + 2, k - 2, m) + abort (); + } + #pragma omp single + if (i != 1 || j != -1 || k != 2 || m != 0) + abort (); + #pragma omp for collapse(2) ordered(4) nowait + for (i = 0; i < d + 1; i++) + for (j = d; j > 0; j--) + for (k = 0; k < d + 2; k++) + for (l = 0; l < d + 4; l++) + { + #pragma omp ordered depend (source) + #pragma omp ordered depend (sink:i - 2, j + 2, k - 2, l) + if (!e) + abort (); + } + #pragma omp for nowait + for (i = 0; i < N; i++) + if (a[i] != 3) + abort (); + #pragma omp for collapse(2) private(k) nowait + for (i = 0; i < N / 16; i++) + for (j = 0; j < 8; j++) + for (k = 0; k < 4; k++) + if (b[i][j][k] != 3 * (i >= 2 && i < N / 16 - 1 && (j & 1) == 0 && k >= 1)) + abort (); + #pragma omp for collapse(3) nowait + for (i = 0; i < N / 32; i++) + for (j = 0; j < 8; j++) + for (k = 0; k < 8; k++) + if (c[i][j][k] != 3 * (j >= 2 && (k & 1) == 0)) + abort (); + } + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/doacross-2.c b/libgomp/testsuite/libgomp.c/doacross-2.c new file mode 100644 index 00000000000..e491bb22965 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/doacross-2.c @@ -0,0 +1,225 @@ +extern void abort (void); + +#define N 256 +int a[N], b[N / 16][8][4], c[N / 32][8][8], g[N / 16][8][6]; +volatile int d, e; +volatile unsigned long long f; + +int +main () +{ + unsigned long long i; + int j, k, l, m; + #pragma omp parallel private (l) + { + #pragma omp for schedule(static, 1) ordered (1) nowait + for (i = 1; i < N + f; i++) + { + #pragma omp atomic write + a[i] = 1; + #pragma omp ordered depend(sink: i - 1) + if (i > 1) + { + #pragma omp atomic read + l = a[i - 1]; + if (l < 2) + abort (); + } + #pragma omp atomic write + a[i] = 2; + if (i < N - 1) + { + #pragma omp atomic read + l = a[i + 1]; + if (l == 3) + abort (); + } + #pragma omp ordered depend(source) + #pragma omp atomic write + a[i] = 3; + } + #pragma omp for schedule(static, 0) ordered (3) nowait + for (i = 3; i < N / 16 - 1 + f; i++) + for (j = 0; j < 8; j += 2) + for (k = 1; k <= 3; k++) + { + #pragma omp atomic write + b[i][j][k] = 1; + #pragma omp ordered depend(sink: i, j - 2, k - 1) \ + depend(sink: i - 2, j - 2, k + 1) + #pragma omp ordered depend(sink: i - 3, j + 2, k - 2) + if (j >= 2 && k > 1) + { + #pragma omp atomic read + l = b[i][j - 2][k - 1]; + if (l < 2) + abort (); + } + #pragma omp atomic write + b[i][j][k] = 2; + if (i >= 5 && j >= 2 && k < 3) + { + #pragma omp atomic read + l = b[i - 2][j - 2][k + 1]; + if (l < 2) + abort (); + } + if (i >= 6 && j < N / 16 - 3 && k == 3) + { + #pragma omp atomic read + l = b[i - 3][j + 2][k - 2]; + if (l < 2) + abort (); + } + #pragma omp ordered depend(source) + #pragma omp atomic write + b[i][j][k] = 3; + } +#define A(n) int n; +#define B(n) A(n##0) A(n##1) A(n##2) A(n##3) +#define C(n) B(n##0) B(n##1) B(n##2) B(n##3) +#define D(n) C(n##0) C(n##1) C(n##2) C(n##3) + D(m) +#undef A + #pragma omp for collapse (2) ordered(61) schedule(dynamic, 15) + for (i = 2; i < N / 32 + f; i++) + for (j = 7; j > 1; j--) + for (k = 6; k >= 0; k -= 2) +#define A(n) for (n = 4; n < 5; n++) + D(m) +#undef A + { + #pragma omp atomic write + c[i][j][k] = 1; +#define A(n) ,n +#define E(n) C(n##0) C(n##1) C(n##2) B(n##30) B(n##31) A(n##320) A(n##321) + #pragma omp ordered depend (sink: i, j, k + 2 E(m)) \ + depend (sink:i - 2, j + 1, k - 4 E(m)) \ + depend(sink: i - 1, j - 2, k - 2 E(m)) + if (k <= 4) + { + l = c[i][j][k + 2]; + if (l < 2) + abort (); + } + #pragma omp atomic write + c[i][j][k] = 2; + if (i >= 4 && j < 7 && k >= 4) + { + l = c[i - 2][j + 1][k - 4]; + if (l < 2) + abort (); + } + if (i >= 3 && j >= 4 && k >= 2) + { + l = c[i - 1][j - 2][k - 2]; + if (l < 2) + abort (); + } + #pragma omp ordered depend (source) + #pragma omp atomic write + c[i][j][k] = 3; + } + #pragma omp for schedule(static, 0) ordered (3) nowait + for (j = 0; j < N / 16 - 1; j++) + for (k = 0; k < 8; k += 2) + for (i = 3; i <= 5 + f; i++) + { + #pragma omp atomic write + g[j][k][i] = 1; + #pragma omp ordered depend(sink: j, k - 2, i - 1) \ + depend(sink: j - 2, k - 2, i + 1) + #pragma omp ordered depend(sink: j - 3, k + 2, i - 2) + if (k >= 2 && i > 3) + { + #pragma omp atomic read + l = g[j][k - 2][i - 1]; + if (l < 2) + abort (); + } + #pragma omp atomic write + g[j][k][i] = 2; + if (j >= 2 && k >= 2 && i < 5) + { + #pragma omp atomic read + l = g[j - 2][k - 2][i + 1]; + if (l < 2) + abort (); + } + if (j >= 3 && k < N / 16 - 3 && i == 5) + { + #pragma omp atomic read + l = g[j - 3][k + 2][i - 2]; + if (l < 2) + abort (); + } + #pragma omp ordered depend(source) + #pragma omp atomic write + g[j][k][i] = 3; + } + #pragma omp for collapse(2) ordered(4) lastprivate (i, j, k) + for (i = 2; i < f + 3; i++) + for (j = d + 1; j >= 0; j--) + for (k = 0; k < d; k++) + for (l = 0; l < d + 2; l++) + { + #pragma omp ordered depend (source) + #pragma omp ordered depend (sink:i - 2, j + 2, k - 2, l) + if (!e) + abort (); + } + #pragma omp single + { + if (i != 3 || j != -1 || k != 0) + abort (); + i = 8; j = 9; k = 10; + } + #pragma omp for collapse(2) ordered(4) lastprivate (i, j, k, m) + for (i = 2; i < f + 3; i++) + for (j = d + 1; j >= 0; j--) + for (k = 0; k < d + 2; k++) + for (m = 0; m < d; m++) + { + #pragma omp ordered depend (source) + #pragma omp ordered depend (sink:i - 2, j + 2, k - 2, m) + abort (); + } + #pragma omp single + if (i != 3 || j != -1 || k != 2 || m != 0) + abort (); + #pragma omp for collapse(2) ordered(4) nowait + for (i = 2; i < f + 3; i++) + for (j = d; j > 0; j--) + for (k = 0; k < d + 2; k++) + for (l = 0; l < d + 4; l++) + { + #pragma omp ordered depend (source) + #pragma omp ordered depend (sink:i - 2, j + 2, k - 2, l) + if (!e) + abort (); + } + #pragma omp for nowait + for (i = 0; i < N; i++) + if (a[i] != 3 * (i >= 1)) + abort (); + #pragma omp for collapse(2) private(k) nowait + for (i = 0; i < N / 16; i++) + for (j = 0; j < 8; j++) + for (k = 0; k < 4; k++) + if (b[i][j][k] != 3 * (i >= 3 && i < N / 16 - 1 && (j & 1) == 0 && k >= 1)) + abort (); + #pragma omp for collapse(3) nowait + for (i = 0; i < N / 32; i++) + for (j = 0; j < 8; j++) + for (k = 0; k < 8; k++) + if (c[i][j][k] != 3 * (i >= 2 && j >= 2 && (k & 1) == 0)) + abort (); + #pragma omp for collapse(2) private(k) nowait + for (i = 0; i < N / 16; i++) + for (j = 0; j < 8; j++) + for (k = 0; k < 6; k++) + if (g[i][j][k] != 3 * (i < N / 16 - 1 && (j & 1) == 0 && k >= 3)) + abort (); + } + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/examples-4/declare_target-1.c b/libgomp/testsuite/libgomp.c/examples-4/declare_target-1.c index beca8555780..6d4bc4fac12 100644 --- a/libgomp/testsuite/libgomp.c/examples-4/declare_target-1.c +++ b/libgomp/testsuite/libgomp.c/examples-4/declare_target-1.c @@ -20,7 +20,7 @@ int fib_wrapper (int n) { int x = 0; - #pragma omp target if(n > THRESHOLD) + #pragma omp target if(n > THRESHOLD) map(from:x) x = fib (n); return x; diff --git a/libgomp/testsuite/libgomp.c/examples-4/declare_target-4.c b/libgomp/testsuite/libgomp.c/examples-4/declare_target-4.c index db70460b309..f2414366951 100644 --- a/libgomp/testsuite/libgomp.c/examples-4/declare_target-4.c +++ b/libgomp/testsuite/libgomp.c/examples-4/declare_target-4.c @@ -41,7 +41,7 @@ float accum (int k) int i; float tmp = 0.0; - #pragma omp target + #pragma omp target map(tofrom:tmp) #pragma omp parallel for reduction(+:tmp) for (i = 0; i < N; i++) tmp += Pfun (i, k); diff --git a/libgomp/testsuite/libgomp.c/examples-4/declare_target-5.c b/libgomp/testsuite/libgomp.c/examples-4/declare_target-5.c index b550f1ff540..33d6137afd5 100644 --- a/libgomp/testsuite/libgomp.c/examples-4/declare_target-5.c +++ b/libgomp/testsuite/libgomp.c/examples-4/declare_target-5.c @@ -48,7 +48,7 @@ float accum () int i, k; float tmp = 0.0; - #pragma omp target + #pragma omp target map(tofrom:tmp) #pragma omp parallel for reduction(+:tmp) for (i = 0; i < N; i++) { diff --git a/libgomp/testsuite/libgomp.c/examples-4/device-1.c b/libgomp/testsuite/libgomp.c/examples-4/device-1.c index f7c84fb4c14..dad8572f8f0 100644 --- a/libgomp/testsuite/libgomp.c/examples-4/device-1.c +++ b/libgomp/testsuite/libgomp.c/examples-4/device-1.c @@ -10,11 +10,11 @@ int main () int b = 0; int c, d; - #pragma omp target if(a > 200 && a < 400) + #pragma omp target if(a > 200 && a < 400) map(from: c) c = omp_is_initial_device (); #pragma omp target data map(to: b) if(a > 200 && a < 400) - #pragma omp target + #pragma omp target map(from: b, d) { b = 100; d = omp_is_initial_device (); @@ -26,11 +26,11 @@ int main () a += 200; b = 0; - #pragma omp target if(a > 200 && a < 400) + #pragma omp target if(a > 200 && a < 400) map(from: c) c = omp_is_initial_device (); #pragma omp target data map(to: b) if(a > 200 && a < 400) - #pragma omp target + #pragma omp target map(from: b, d) { b = 100; d = omp_is_initial_device (); @@ -42,11 +42,11 @@ int main () a += 200; b = 0; - #pragma omp target if(a > 200 && a < 400) + #pragma omp target if(a > 200 && a < 400) map(from: c) c = omp_is_initial_device (); #pragma omp target data map(to: b) if(a > 200 && a < 400) - #pragma omp target + #pragma omp target map(from: b, d) { b = 100; d = omp_is_initial_device (); diff --git a/libgomp/testsuite/libgomp.c/examples-4/device-3.c b/libgomp/testsuite/libgomp.c/examples-4/device-3.c index 8a0cf7c200d..af086533278 100644 --- a/libgomp/testsuite/libgomp.c/examples-4/device-3.c +++ b/libgomp/testsuite/libgomp.c/examples-4/device-3.c @@ -9,7 +9,7 @@ int main () int res; int default_device = omp_get_default_device (); - #pragma omp target + #pragma omp target map(from: res) res = omp_is_initial_device (); if (res) @@ -17,7 +17,7 @@ int main () omp_set_default_device (omp_get_num_devices ()); - #pragma omp target + #pragma omp target map(from: res) res = omp_is_initial_device (); if (!res) diff --git a/libgomp/testsuite/libgomp.c/examples-4/target_data-3.c b/libgomp/testsuite/libgomp.c/examples-4/target_data-3.c index abb283801f8..46b674013d0 100644 --- a/libgomp/testsuite/libgomp.c/examples-4/target_data-3.c +++ b/libgomp/testsuite/libgomp.c/examples-4/target_data-3.c @@ -47,7 +47,7 @@ void gramSchmidt (int Q[][COLS], const int rows, const int cols) { int tmp = 0; - #pragma omp target + #pragma omp target map(tofrom:tmp) #pragma omp parallel for reduction(+:tmp) for (i = 0; i < rows; i++) tmp += (Q[i][k] * Q[i][k]); diff --git a/libgomp/testsuite/libgomp.c/examples-4/teams-2.c b/libgomp/testsuite/libgomp.c/examples-4/teams-2.c index 8bbbc355b17..7d0a60ebb51 100644 --- a/libgomp/testsuite/libgomp.c/examples-4/teams-2.c +++ b/libgomp/testsuite/libgomp.c/examples-4/teams-2.c @@ -32,7 +32,7 @@ float dotprod (float B[], float C[], int n, int block_size, int i, i0; float sum = 0; - #pragma omp target map(to: B[0:n], C[0:n]) + #pragma omp target map(to: B[0:n], C[0:n]) map(tofrom: sum) #pragma omp teams num_teams(num_teams) thread_limit(block_threads) \ reduction(+:sum) #pragma omp distribute diff --git a/libgomp/testsuite/libgomp.c/examples-4/teams-3.c b/libgomp/testsuite/libgomp.c/examples-4/teams-3.c index b6708785884..5fe63a68a4b 100644 --- a/libgomp/testsuite/libgomp.c/examples-4/teams-3.c +++ b/libgomp/testsuite/libgomp.c/examples-4/teams-3.c @@ -31,7 +31,7 @@ float dotprod (float B[], float C[], int n) int i; float sum = 0; - #pragma omp target teams map(to: B[0:n], C[0:n]) + #pragma omp target teams map(to: B[0:n], C[0:n]) map(tofrom: sum) #pragma omp distribute parallel for reduction(+:sum) for (i = 0; i < n; i++) sum += B[i] * C[i]; diff --git a/libgomp/testsuite/libgomp.c/examples-4/teams-4.c b/libgomp/testsuite/libgomp.c/examples-4/teams-4.c index 9aef78ecfba..6136eabef66 100644 --- a/libgomp/testsuite/libgomp.c/examples-4/teams-4.c +++ b/libgomp/testsuite/libgomp.c/examples-4/teams-4.c @@ -31,7 +31,7 @@ float dotprod (float B[], float C[], int n) int i; float sum = 0; - #pragma omp target map(to: B[0:n], C[0:n]) + #pragma omp target map(to: B[0:n], C[0:n]) map(tofrom:sum) #pragma omp teams num_teams(8) thread_limit(16) #pragma omp distribute parallel for reduction(+:sum) \ dist_schedule(static, 1024) \ diff --git a/libgomp/testsuite/libgomp.c/for-2.h b/libgomp/testsuite/libgomp.c/for-2.h index 920d23b5202..0bd116c5aec 100644 --- a/libgomp/testsuite/libgomp.c/for-2.h +++ b/libgomp/testsuite/libgomp.c/for-2.h @@ -11,11 +11,21 @@ noreturn (void) #ifndef SC #define SC #endif +#ifndef OMPTGT +#define OMPTGT +#endif +#ifndef OMPTO +#define OMPTO(v) do {} while (0) +#endif +#ifndef OMPFROM +#define OMPFROM(v) do {} while (0) +#endif __attribute__((noinline, noclone)) void N(f0) (void) { int i; + OMPTGT #pragma omp F S for (i = 0; i < 1500; i++) a[i] += 2; @@ -24,6 +34,7 @@ N(f0) (void) __attribute__((noinline, noclone)) void N(f1) (void) { + OMPTGT #pragma omp F S for (unsigned int i = __INT_MAX__; i < 3000U + __INT_MAX__; i += 2) a[(i - __INT_MAX__) >> 1] -= 2; @@ -33,6 +44,7 @@ __attribute__((noinline, noclone)) void N(f2) (void) { unsigned long long i; + OMPTGT #pragma omp F S for (i = __LONG_LONG_MAX__ + 4500ULL - 27; i > __LONG_LONG_MAX__ - 27ULL; i -= 3) @@ -42,6 +54,7 @@ N(f2) (void) __attribute__((noinline, noclone)) void N(f3) (long long n1, long long n2, long long s3) { + OMPTGT #pragma omp F S for (long long i = n1 + 23; i > n2 - 25; i -= s3) a[i + 48] += 7; @@ -51,6 +64,7 @@ __attribute__((noinline, noclone)) void N(f4) (void) { unsigned int i; + OMPTGT #pragma omp F S for (i = 30; i < 20; i += 2) a[i] += 10; @@ -61,6 +75,7 @@ N(f5) (int n11, int n12, int n21, int n22, int n31, int n32, int s1, int s2, int s3) { SC int v1, v2, v3; + OMPTGT #pragma omp F S collapse(3) for (v1 = n11; v1 < n12; v1 += s1) for (v2 = n21; v2 < n22; v2 += s2) @@ -74,6 +89,7 @@ N(f6) (int n11, int n12, int n21, int n22, long long n31, long long n32, { SC int v1, v2; SC long long v3; + OMPTGT #pragma omp F S collapse(3) for (v1 = n11; v1 > n12; v1 += s1) for (v2 = n21; v2 > n22; v2 += s2) @@ -86,6 +102,7 @@ N(f7) (void) { SC unsigned int v1, v3; SC unsigned long long v2; + OMPTGT #pragma omp F S collapse(3) for (v1 = 0; v1 < 20; v1 += 2) for (v2 = __LONG_LONG_MAX__ + 16ULL; @@ -98,6 +115,7 @@ __attribute__((noinline, noclone)) void N(f8) (void) { SC long long v1, v2, v3; + OMPTGT #pragma omp F S collapse(3) for (v1 = 0; v1 < 20; v1 += 2) for (v2 = 30; v2 < 20; v2++) @@ -109,6 +127,7 @@ __attribute__((noinline, noclone)) void N(f9) (void) { int i; + OMPTGT #pragma omp F S for (i = 20; i < 10; i++) { @@ -122,6 +141,7 @@ __attribute__((noinline, noclone)) void N(f10) (void) { SC int i; + OMPTGT #pragma omp F S collapse(3) for (i = 0; i < 10; i++) for (int j = 10; j < 8; j++) @@ -137,6 +157,7 @@ __attribute__((noinline, noclone)) void N(f11) (int n) { int i; + OMPTGT #pragma omp F S for (i = 20; i < n; i++) { @@ -150,6 +171,7 @@ __attribute__((noinline, noclone)) void N(f12) (int n) { SC int i; + OMPTGT #pragma omp F S collapse(3) for (i = 0; i < 10; i++) for (int j = n; j < 8; j++) @@ -165,6 +187,7 @@ __attribute__((noinline, noclone)) void N(f13) (void) { int *i; + OMPTGT #pragma omp F S for (i = a; i < &a[1500]; i++) i[0] += 2; @@ -174,6 +197,7 @@ __attribute__((noinline, noclone)) void N(f14) (void) { SC float *i; + OMPTGT #pragma omp F S collapse(3) for (i = &b[0][0][0]; i < &b[0][0][10]; i++) for (float *j = &b[0][15][0]; j > &b[0][0][0]; j -= 10) @@ -188,27 +212,34 @@ N(test) (void) int i, j, k; for (i = 0; i < 1500; i++) a[i] = i - 25; + OMPTO (a); N(f0) (); + OMPFROM (a); for (i = 0; i < 1500; i++) if (a[i] != i - 23) return 1; N(f1) (); + OMPFROM (a); for (i = 0; i < 1500; i++) if (a[i] != i - 25) return 1; N(f2) (); + OMPFROM (a); for (i = 0; i < 1500; i++) if (a[i] != i - 29) return 1; N(f3) (1500LL - 1 - 23 - 48, -1LL + 25 - 48, 1LL); + OMPFROM (a); for (i = 0; i < 1500; i++) if (a[i] != i - 22) return 1; N(f3) (1500LL - 1 - 23 - 48, 1500LL - 1, 7LL); + OMPFROM (a); for (i = 0; i < 1500; i++) if (a[i] != i - 22) return 1; N(f4) (); + OMPFROM (a); for (i = 0; i < 1500; i++) if (a[i] != i - 22) return 1; @@ -216,31 +247,37 @@ N(test) (void) for (j = 0; j < 15; j++) for (k = 0; k < 10; k++) b[i][j][k] = i - 2.5 + 1.5 * j - 1.5 * k; + OMPTO (b); N(f5) (0, 10, 0, 15, 0, 10, 1, 1, 1); + OMPFROM (b); for (i = 0; i < 10; i++) for (j = 0; j < 15; j++) for (k = 0; k < 10; k++) if (b[i][j][k] != i + 1.5 * j - 1.5 * k) return 1; N(f5) (0, 10, 30, 15, 0, 10, 4, 5, 6); + OMPFROM (b); for (i = 0; i < 10; i++) for (j = 0; j < 15; j++) for (k = 0; k < 10; k++) if (b[i][j][k] != i + 1.5 * j - 1.5 * k) return 1; N(f6) (9, -1, 29, 0, 9, -1, -1, -2, -1); + OMPFROM (b); for (i = 0; i < 10; i++) for (j = 0; j < 15; j++) for (k = 0; k < 10; k++) if (b[i][j][k] != i - 4.5 + 1.5 * j - 1.5 * k) return 1; N(f7) (); + OMPFROM (b); for (i = 0; i < 10; i++) for (j = 0; j < 15; j++) for (k = 0; k < 10; k++) if (b[i][j][k] != i + 1.0 + 1.5 * j - 1.5 * k) return 1; N(f8) (); + OMPFROM (b); for (i = 0; i < 10; i++) for (j = 0; j < 15; j++) for (k = 0; k < 10; k++) @@ -250,6 +287,8 @@ N(test) (void) N(f10) (); N(f11) (10); N(f12) (12); + OMPFROM (a); + OMPFROM (b); for (i = 0; i < 1500; i++) if (a[i] != i - 22) return 1; @@ -260,6 +299,8 @@ N(test) (void) return 1; N(f13) (); N(f14) (); + OMPFROM (a); + OMPFROM (b); for (i = 0; i < 1500; i++) if (a[i] != i - 20) return 1; diff --git a/libgomp/testsuite/libgomp.c/for-4.c b/libgomp/testsuite/libgomp.c/for-4.c new file mode 100644 index 00000000000..ef5465e1e76 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/for-4.c @@ -0,0 +1,42 @@ +/* { dg-options "-std=gnu99 -fopenmp" } */ + +extern void abort (void); + +#define M(x, y, z) O(x, y, z) +#define O(x, y, z) x ## _ ## y ## _ ## z + +#define F taskloop +#define G taskloop +#define S +#define N(x) M(x, G, normal) +#include "for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F taskloop simd +#define G taskloop_simd +#define S +#define N(x) M(x, G, normal) +#include "for-2.h" +#undef S +#undef N +#undef F +#undef G + +int +main () +{ + int err = 0; + #pragma omp parallel reduction(|:err) + #pragma omp single + { + if (test_taskloop_normal () + || test_taskloop_simd_normal ()) + err = 1; + } + if (err) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/for-5.c b/libgomp/testsuite/libgomp.c/for-5.c new file mode 100644 index 00000000000..84e636ab0f9 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/for-5.c @@ -0,0 +1,154 @@ +/* { dg-additional-options "-std=gnu99" } */ + +extern void abort (); + +#define M(x, y, z) O(x, y, z) +#define O(x, y, z) x ## _ ## y ## _ ## z + +#pragma omp declare target + +#define F for +#define G f +#define S +#define N(x) M(x, G, normal) +#include "for-2.h" +#undef S +#undef N +#undef F +#undef G + +#pragma omp end declare target + +#undef OMPFROM +#undef OMPTO +#define DO_PRAGMA(x) _Pragma (#x) +#define OMPFROM(v) DO_PRAGMA (omp target update from(v)) +#define OMPTO(v) DO_PRAGMA (omp target update to(v)) + +#define F target parallel for +#define G tpf +#include "for-1.h" +#undef F +#undef G + +#define F target simd +#define G t_simd +#define S +#define N(x) M(x, G, normal) +#include "for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F target parallel for simd +#define G tpf_simd +#include "for-1.h" +#undef F +#undef G + +#define F target teams distribute +#define G ttd +#define S +#define N(x) M(x, G, normal) +#include "for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F target teams distribute +#define G ttd_ds128 +#define S dist_schedule(static, 128) +#define N(x) M(x, G, normal) +#include "for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F target teams distribute simd +#define G ttds +#define S +#define N(x) M(x, G, normal) +#include "for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F target teams distribute simd +#define G ttds_ds128 +#define S dist_schedule(static, 128) +#define N(x) M(x, G, normal) +#include "for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F target teams distribute parallel for +#define G ttdpf +#include "for-1.h" +#undef F +#undef G + +#define F target teams distribute parallel for dist_schedule(static, 128) +#define G ttdpf_ds128 +#include "for-1.h" +#undef F +#undef G + +#define F target teams distribute parallel for simd +#define G ttdpfs +#include "for-1.h" +#undef F +#undef G + +#define F target teams distribute parallel for simd dist_schedule(static, 128) +#define G ttdpfs_ds128 +#include "for-1.h" +#undef F +#undef G + +int +main () +{ + if (test_tpf_static () + || test_tpf_static32 () + || test_tpf_auto () + || test_tpf_guided32 () + || test_tpf_runtime () + || test_t_simd_normal () + || test_tpf_simd_static () + || test_tpf_simd_static32 () + || test_tpf_simd_auto () + || test_tpf_simd_guided32 () + || test_tpf_simd_runtime () + || test_ttd_normal () + || test_ttd_ds128_normal () + || test_ttds_normal () + || test_ttds_ds128_normal () + || test_ttdpf_static () + || test_ttdpf_static32 () + || test_ttdpf_auto () + || test_ttdpf_guided32 () + || test_ttdpf_runtime () + || test_ttdpf_ds128_static () + || test_ttdpf_ds128_static32 () + || test_ttdpf_ds128_auto () + || test_ttdpf_ds128_guided32 () + || test_ttdpf_ds128_runtime () + || test_ttdpfs_static () + || test_ttdpfs_static32 () + || test_ttdpfs_auto () + || test_ttdpfs_guided32 () + || test_ttdpfs_runtime () + || test_ttdpfs_ds128_static () + || test_ttdpfs_ds128_static32 () + || test_ttdpfs_ds128_auto () + || test_ttdpfs_ds128_guided32 () + || test_ttdpfs_ds128_runtime ()) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/for-6.c b/libgomp/testsuite/libgomp.c/for-6.c new file mode 100644 index 00000000000..7f3c65e82b1 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/for-6.c @@ -0,0 +1,123 @@ +/* { dg-additional-options "-std=gnu99" } */ + +extern void abort (); + +#define M(x, y, z) O(x, y, z) +#define O(x, y, z) x ## _ ## y ## _ ## z + +#pragma omp declare target + +#define F for +#define G f +#define S +#define N(x) M(x, G, normal) +#include "for-2.h" +#undef S +#undef N +#undef F +#undef G + +#pragma omp end declare target + +#undef OMPTGT +#undef OMPFROM +#undef OMPTO +#define DO_PRAGMA(x) _Pragma (#x) +#define OMPTGT DO_PRAGMA (omp target) +#define OMPFROM(v) DO_PRAGMA (omp target update from(v)) +#define OMPTO(v) DO_PRAGMA (omp target update to(v)) + +#define F teams distribute +#define G td +#define S +#define N(x) M(x, G, normal) +#include "for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F teams distribute +#define G td_ds128 +#define S dist_schedule(static, 128) +#define N(x) M(x, G, normal) +#include "for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F teams distribute simd +#define G tds +#define S +#define N(x) M(x, G, normal) +#include "for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F teams distribute simd +#define G tds_ds128 +#define S dist_schedule(static, 128) +#define N(x) M(x, G, normal) +#include "for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F teams distribute parallel for +#define G tdpf +#include "for-1.h" +#undef F +#undef G + +#define F teams distribute parallel for dist_schedule(static, 128) +#define G tdpf_ds128 +#include "for-1.h" +#undef F +#undef G + +#define F teams distribute parallel for simd +#define G tdpfs +#include "for-1.h" +#undef F +#undef G + +#define F teams distribute parallel for simd dist_schedule(static, 128) +#define G tdpfs_ds128 +#include "for-1.h" +#undef F +#undef G + +int +main () +{ + if (test_td_normal () + || test_td_ds128_normal () + || test_tds_normal () + || test_tds_ds128_normal () + || test_tdpf_static () + || test_tdpf_static32 () + || test_tdpf_auto () + || test_tdpf_guided32 () + || test_tdpf_runtime () + || test_tdpf_ds128_static () + || test_tdpf_ds128_static32 () + || test_tdpf_ds128_auto () + || test_tdpf_ds128_guided32 () + || test_tdpf_ds128_runtime () + || test_tdpfs_static () + || test_tdpfs_static32 () + || test_tdpfs_auto () + || test_tdpfs_guided32 () + || test_tdpfs_runtime () + || test_tdpfs_ds128_static () + || test_tdpfs_ds128_static32 () + || test_tdpfs_ds128_auto () + || test_tdpfs_ds128_guided32 () + || test_tdpfs_ds128_runtime ()) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/linear-1.c b/libgomp/testsuite/libgomp.c/linear-1.c new file mode 100644 index 00000000000..f86fb33c5da --- /dev/null +++ b/libgomp/testsuite/libgomp.c/linear-1.c @@ -0,0 +1,250 @@ +int a[256]; + +__attribute__((noinline, noclone)) int +f1 (int i) +{ + #pragma omp parallel for linear (i: 4) + for (int j = 16; j < 64; j++) + { + a[i] = j; + i += 4; + } + return i; +} + +__attribute__((noinline, noclone)) short int +f2 (short int i, char k) +{ + #pragma omp parallel for linear (i: k + 1) + for (long j = 16; j < 64; j++) + { + a[i] = j; + i += 4; + } + return i; +} + +__attribute__((noinline, noclone)) long long int +f3 (long long int i, long long int k) +{ + #pragma omp parallel for linear (i: k) + for (short j = 16; j < 64; j++) + { + a[i] = j; + i += 4; + } + return i; +} + +__attribute__((noinline, noclone)) int +f4 (int i) +{ + #pragma omp parallel for linear (i: 4) schedule(static, 3) + for (int j = 16; j < 64; j++) + { + a[i] = j; + i += 4; + } + return i; +} + +__attribute__((noinline, noclone)) short int +f5 (short int i, char k) +{ + #pragma omp parallel for linear (i: k + 1) schedule(static, 5) + for (long j = 16; j < 64; j++) + { + a[i] = j; + i += 4; + } + return i; +} + +__attribute__((noinline, noclone)) long long int +f6 (long long int i, long long int k) +{ + #pragma omp parallel for linear (i: k) schedule(static, 7) + for (short j = 16; j < 64; j++) + { + a[i] = j; + i += 4; + } + return i; +} + +__attribute__((noinline, noclone)) int +f7 (int i) +{ + #pragma omp parallel for linear (i: 4) schedule(dynamic, 3) + for (int j = 16; j < 64; j++) + { + a[i] = j; + i += 4; + } + return i; +} + +__attribute__((noinline, noclone)) short int +f8 (short int i, char k) +{ + #pragma omp parallel for linear (i: k + 1) schedule(dynamic, 5) + for (long j = 16; j < 64; j++) + { + a[i] = j; + i += 4; + } + return i; +} + +__attribute__((noinline, noclone)) long long int +f9 (long long int i, long long int k) +{ + #pragma omp parallel for linear (i: k) schedule(dynamic, 7) + for (short j = 16; j < 64; j++) + { + a[i] = j; + i += 4; + } + return i; +} + +__attribute__((noinline, noclone)) int +f10 (int i, long step) +{ + #pragma omp parallel for linear (i: 4) + for (int j = 16; j < 112; j += step) + { + a[i] = j / 2 + 8; + i += 4; + } + return i; +} + +__attribute__((noinline, noclone)) short int +f11 (short int i, char k, char step) +{ + #pragma omp parallel for linear (i: k + 1) + for (long j = 16; j < 112; j += step) + { + a[i] = j / 2 + 8; + i += 4; + } + return i; +} + +__attribute__((noinline, noclone)) long long int +f12 (long long int i, long long int k, int step) +{ + #pragma omp parallel for linear (i: k) + for (short j = 16; j < 112; j += step) + { + a[i] = j / 2 + 8; + i += 4; + } + return i; +} + +__attribute__((noinline, noclone)) int +f13 (int i, long long int step) +{ + #pragma omp parallel for linear (i: 4) schedule(static, 3) + for (int j = 16; j < 112; j += step) + { + a[i] = j / 2 + 8; + i += 4; + } + return i; +} + +__attribute__((noinline, noclone)) short int +f14 (short int i, char k, int step) +{ + #pragma omp parallel for linear (i: k + 1) schedule(static, 5) + for (long j = 16; j < 112; j += step) + { + a[i] = j / 2 + 8; + i += 4; + } + return i; +} + +__attribute__((noinline, noclone)) long long int +f15 (long long int i, long long int k, long int step) +{ + #pragma omp parallel for linear (i: k) schedule(static, 7) + for (short j = 16; j < 112; j += step) + { + a[i] = j / 2 + 8; + i += 4; + } + return i; +} + +__attribute__((noinline, noclone)) int +f16 (int i, long long int step) +{ + #pragma omp parallel for linear (i: 4) schedule(dynamic, 3) + for (int j = 16; j < 112; j += step) + { + a[i] = j / 2 + 8; + i += 4; + } + return i; +} + +__attribute__((noinline, noclone)) short int +f17 (short int i, char k, int step) +{ + #pragma omp parallel for linear (i: k + 1) schedule(dynamic, 5) + for (long j = 16; j < 112; j += step) + { + a[i] = j / 2 + 8; + i += 4; + } + return i; +} + +__attribute__((noinline, noclone)) long long int +f18 (long long int i, long long int k, long int step) +{ + #pragma omp parallel for linear (i: k) schedule(dynamic, 7) + for (short j = 16; j < 112; j += step) + { + a[i] = j / 2 + 8; + i += 4; + } + return i; +} + +int +main () +{ +#define TEST(x) \ + if (x != 8 + 48 * 4) \ + __builtin_abort (); \ + for (int i = 0; i < 256; i++) \ + if (a[i] != (((i & 3) == 0 && i >= 8 \ + && i < 8 + 48 * 4) \ + ? ((i - 8) / 4) + 16 : 0)) \ + __builtin_abort (); \ + __builtin_memset (a, 0, sizeof (a)) + TEST (f1 (8)); + TEST (f2 (8, 3)); + TEST (f3 (8LL, 4LL)); + TEST (f4 (8)); + TEST (f5 (8, 3)); + TEST (f6 (8LL, 4LL)); + TEST (f7 (8)); + TEST (f8 (8, 3)); + TEST (f9 (8LL, 4LL)); + TEST (f10 (8, 2)); + TEST (f11 (8, 3, 2)); + TEST (f12 (8LL, 4LL, 2)); + TEST (f13 (8, 2)); + TEST (f14 (8, 3, 2)); + TEST (f15 (8LL, 4LL, 2)); + TEST (f16 (8, 2)); + TEST (f17 (8, 3, 2)); + TEST (f18 (8LL, 4LL, 2)); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/ordered-4.c b/libgomp/testsuite/libgomp.c/ordered-4.c new file mode 100644 index 00000000000..8412d4715c3 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/ordered-4.c @@ -0,0 +1,83 @@ +extern +#ifdef __cplusplus +"C" +#endif +void abort (void); + +void +foo (int i, char *j) +{ + #pragma omp atomic + j[i]++; + #pragma omp ordered threads + { + int t; + #pragma omp atomic read + t = j[i]; + if (t != 3) + abort (); + if (i > 1) + { + #pragma omp atomic read + t = j[i - 1]; + if (t == 2) + abort (); + } + if (i < 127) + { + #pragma omp atomic read + t = j[i + 1]; + if (t == 4) + abort (); + } + } + #pragma omp atomic + j[i]++; +} + +int +main () +{ + int i; + char j[128]; + #pragma omp parallel + { + #pragma omp for + for (i = 0; i < 128; i++) + j[i] = 0; + #pragma omp for ordered schedule(dynamic, 1) + for (i = 0; i < 128; i++) + { + #pragma omp atomic + j[i]++; + #pragma omp ordered threads + { + int t; + #pragma omp atomic read + t = j[i]; + if (t != 1) + abort (); + if (i > 1) + { + #pragma omp atomic read + t = j[i - 1]; + if (t == 0) + abort (); + } + if (i < 127) + { + #pragma omp atomic read + t = j[i + 1]; + if (t == 2) + abort (); + } + } + #pragma omp atomic + j[i]++; + } + #pragma omp for ordered schedule(static, 1) + for (i = 0; i < 128; i++) + foo (i, j); + } + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/pr66199-2.c b/libgomp/testsuite/libgomp.c/pr66199-2.c index ddb79de8943..2fc9eec529a 100644 --- a/libgomp/testsuite/libgomp.c/pr66199-2.c +++ b/libgomp/testsuite/libgomp.c/pr66199-2.c @@ -18,12 +18,11 @@ __attribute__((noinline, noclone)) void f2 (long a, long b, long c) { long d, e; - #pragma omp target teams distribute parallel for simd default(none) firstprivate (a, b) shared(u, v, w) linear(d) linear(c:5) lastprivate(e) + #pragma omp target teams distribute parallel for simd default(none) firstprivate (a, b, c) shared(u, v, w) linear(d) lastprivate(e) for (d = a; d < b; d++) { u[d] = v[d] + w[d]; - c += 5; - e = c; + e = c + d * 5; } } diff --git a/libgomp/testsuite/libgomp.c/pr66199-3.c b/libgomp/testsuite/libgomp.c/pr66199-3.c new file mode 100644 index 00000000000..fe0ccb47197 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/pr66199-3.c @@ -0,0 +1,50 @@ +/* PR middle-end/66199 */ +/* { dg-do run } */ +/* { dg-options "-O2 -fopenmp" } */ + +int u[1024], v[1024], w[1024]; + +__attribute__((noinline, noclone)) long +f1 (long a, long b) +{ + long d; + #pragma omp parallel for lastprivate (d) default(none) firstprivate (a, b) shared(u, v, w) + for (d = a; d < b; d++) + u[d] = v[d] + w[d]; + return d; +} + +__attribute__((noinline, noclone)) long +f2 (long a, long b, long c) +{ + long d, e; + #pragma omp parallel for lastprivate (d) default(none) firstprivate (a, b) shared(u, v, w) linear(c:5) lastprivate(e) + for (d = a; d < b; d++) + { + u[d] = v[d] + w[d]; + c += 5; + e = c; + } + return d + c + e; +} + +__attribute__((noinline, noclone)) long +f3 (long a1, long b1, long a2, long b2) +{ + long d1, d2; + #pragma omp parallel for default(none) firstprivate (a1, b1, a2, b2) shared(u, v, w) lastprivate(d1, d2) collapse(2) + for (d1 = a1; d1 < b1; d1++) + for (d2 = a2; d2 < b2; d2++) + u[d1 * 32 + d2] = v[d1 * 32 + d2] + w[d1 * 32 + d2]; + return d1 + d2; +} + +int +main () +{ + if (f1 (0, 1024) != 1024 + || f2 (0, 1024, 17) != 1024 + 2 * (17 + 5 * 1024) + || f3 (0, 32, 0, 32) != 64) + __builtin_abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/pr66199-4.c b/libgomp/testsuite/libgomp.c/pr66199-4.c new file mode 100644 index 00000000000..a9b1bb8a59e --- /dev/null +++ b/libgomp/testsuite/libgomp.c/pr66199-4.c @@ -0,0 +1,58 @@ +/* PR middle-end/66199 */ +/* { dg-do run } */ +/* { dg-options "-O2 -fopenmp" } */ + +#pragma omp declare target +int u[1024], v[1024], w[1024]; +#pragma omp end declare target + +__attribute__((noinline, noclone)) void +f1 (long a, long b) +{ + long d; + #pragma omp target teams distribute parallel for default(none) firstprivate (a, b) shared(u, v, w) + for (d = a; d < b; d++) + u[d] = v[d] + w[d]; +} + +__attribute__((noinline, noclone)) void +f2 (long a, long b, long c) +{ + long d, e; + #pragma omp target teams distribute parallel for default(none) firstprivate (a, b, c) shared(u, v, w) lastprivate(d, e) + for (d = a; d < b; d++) + { + u[d] = v[d] + w[d]; + e = c + d * 5; + } +} + +__attribute__((noinline, noclone)) void +f3 (long a1, long b1, long a2, long b2) +{ + long d1, d2; + #pragma omp target teams distribute parallel for default(none) firstprivate (a1, b1, a2, b2) shared(u, v, w) lastprivate(d1, d2) collapse(2) + for (d1 = a1; d1 < b1; d1++) + for (d2 = a2; d2 < b2; d2++) + u[d1 * 32 + d2] = v[d1 * 32 + d2] + w[d1 * 32 + d2]; +} + +__attribute__((noinline, noclone)) void +f4 (long a1, long b1, long a2, long b2) +{ + long d1, d2; + #pragma omp target teams distribute parallel for default(none) firstprivate (a1, b1, a2, b2) shared(u, v, w) collapse(2) + for (d1 = a1; d1 < b1; d1++) + for (d2 = a2; d2 < b2; d2++) + u[d1 * 32 + d2] = v[d1 * 32 + d2] + w[d1 * 32 + d2]; +} + +int +main () +{ + f1 (0, 1024); + f2 (0, 1024, 17); + f3 (0, 32, 0, 32); + f4 (0, 32, 0, 32); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/reduction-10.c b/libgomp/testsuite/libgomp.c/reduction-10.c new file mode 100644 index 00000000000..3c95ebd4a4b --- /dev/null +++ b/libgomp/testsuite/libgomp.c/reduction-10.c @@ -0,0 +1,105 @@ +struct A { int t; }; +struct B { char t; }; +struct C { unsigned long long t; }; +struct D { long t; }; +void +add (struct B *x, struct B *y) +{ + x->t += y->t; +} +void +zero (struct B *x) +{ + x->t = 0; +} +void +orit (struct C *x, struct C *y) +{ + y->t |= x->t; +} +#pragma omp declare reduction(+:struct A:omp_out.t += omp_in.t) +#pragma omp declare reduction(+:struct B:add (&omp_out, &omp_in)) initializer(zero (&omp_priv)) +#pragma omp declare reduction(*:struct A:omp_out.t *= omp_in.t) initializer(omp_priv = { 1 }) +#pragma omp declare reduction(|:struct C:orit (&omp_in, &omp_out)) +#pragma omp declare reduction(&:struct D:omp_out.t = omp_out.t & omp_in.t) initializer(omp_priv = { ~0L }) +#pragma omp declare reduction(maxb:short:omp_out = omp_in > omp_out ? omp_in : omp_out) initializer(omp_priv = -6) + +struct B z[10]; + +__attribute__((noinline, noclone)) void +foo (struct A (*x)[3][2], struct A *y, struct D w[1][2], int p1, long p2, long p3, int p4, + int p5, long p6, short p7) +{ + struct C a[p7 + 4]; + short b[p7]; + int i; + for (i = 0; i < p7 + 4; i++) + { + if (i < p7) + b[i] = -6; + a[i].t = 0; + } + #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2], z[:p3]) \ + reduction(*:y[:p4]) reduction(|:a[:p5]) \ + reduction(&:w[0:p6 - 1][:p6]) reduction(maxb:b) + for (i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1].t += i; + if ((i & 15) == 1) + y[0].t *= 3; + if ((i & 31) == 2) + y[1].t *= 7; + if ((i & 63) == 3) + y[2].t *= 17; + z[i / 32].t += (i & 3); + if (i < 4) + z[i].t += i; + a[i / 32].t |= 1ULL << (i & 30); + w[0][i & 1].t &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[2]) + b[2] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } + for (i = 0; i < 9; i++) + if (a[i].t != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + if (b[0] != 78 || b[1] != 12 || b[2] != 22 || b[3] != 84 || b[4] != 127) + __builtin_abort (); +} + +int +main () +{ + struct A a[4][3][2] = {}; + static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }}, + {{ 312, 381 }, { 295, 356 }, { 337, 335 }}, + {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }}, + {{ 0, 0 }, { 0, 0 }, { 0, 0 }}}; + struct A y[5] = { { 0 }, { 1 }, { 1 }, { 1 }, { 0 } }; + int y2[5] = { 0, 6561, 2401, 289, 0 }; + char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 }; + struct D w[1][2] = { { { ~0L }, { ~0L } } }; + foo (&a[1], y + 1, w, 1, 3L, 4L, 3, 4, 2L, 5); + int i, j, k; + for (i = 0; i < 4; i++) + for (j = 0; j < 3; j++) + for (k = 0; k < 2; k++) + if (a[i][j][k].t != a2[i][j][k]) + __builtin_abort (); + for (i = 0; i < 5; i++) + if (y[i].t != y2[i]) + __builtin_abort (); + for (i = 0; i < 10; i++) + if (z[i].t != z2[i]) + __builtin_abort (); + if (w[0][0].t != ~0x249249L || w[0][1].t != ~0x249249L) + __builtin_abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/reduction-7.c b/libgomp/testsuite/libgomp.c/reduction-7.c new file mode 100644 index 00000000000..347c26f46d3 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/reduction-7.c @@ -0,0 +1,64 @@ +char z[10] = { 0 }; + +__attribute__((noinline, noclone)) void +foo (int (*x)[3][2], int *y, long w[1][2]) +{ + unsigned long long a[9] = {}; + short b[5] = {}; + int i; + #pragma omp parallel for reduction(+:x[0:2][:][0:2], z[:4]) \ + reduction(*:y[:3]) reduction(|:a[:4]) \ + reduction(&:w[0:1][:2]) reduction(max:b) + for (i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1] += i; + if ((i & 15) == 1) + y[0] *= 3; + if ((i & 31) == 2) + y[1] *= 7; + if ((i & 63) == 3) + y[2] *= 17; + z[i / 32] += (i & 3); + if (i < 4) + z[i] += i; + a[i / 32] |= 1ULL << (i & 30); + w[0][i & 1] &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[2]) + b[2] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } + for (i = 0; i < 9; i++) + if (a[i] != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + if (b[0] != 78 || b[1] != 12 || b[2] != 22 || b[3] != 84 || b[4] != 127) + __builtin_abort (); +} + +int +main () +{ + int a[4][3][2] = {}; + static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }}, + {{ 312, 381 }, { 295, 356 }, { 337, 335 }}, + {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }}, + {{ 0, 0 }, { 0, 0 }, { 0, 0 }}}; + int y[5] = { 0, 1, 1, 1, 0 }; + int y2[5] = { 0, 6561, 2401, 289, 0 }; + char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 }; + long w[1][2] = { ~0L, ~0L }; + foo (&a[1], y + 1, w); + if (__builtin_memcmp (a, a2, sizeof (a)) + || __builtin_memcmp (y, y2, sizeof (y)) + || __builtin_memcmp (z, z2, sizeof (z)) + || w[0][0] != ~0x249249L + || w[0][1] != ~0x249249L) + __builtin_abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/reduction-8.c b/libgomp/testsuite/libgomp.c/reduction-8.c new file mode 100644 index 00000000000..f4ec03aabea --- /dev/null +++ b/libgomp/testsuite/libgomp.c/reduction-8.c @@ -0,0 +1,98 @@ +struct A { int t; }; +struct B { char t; }; +struct C { unsigned long long t; }; +struct D { long t; }; +void +add (struct B *x, struct B *y) +{ + x->t += y->t; +} +void +zero (struct B *x) +{ + x->t = 0; +} +void +orit (struct C *x, struct C *y) +{ + y->t |= x->t; +} +#pragma omp declare reduction(+:struct A:omp_out.t += omp_in.t) +#pragma omp declare reduction(+:struct B:add (&omp_out, &omp_in)) initializer(zero (&omp_priv)) +#pragma omp declare reduction(*:struct A:omp_out.t *= omp_in.t) initializer(omp_priv = { 1 }) +#pragma omp declare reduction(|:struct C:orit (&omp_in, &omp_out)) +#pragma omp declare reduction(&:struct D:omp_out.t = omp_out.t & omp_in.t) initializer(omp_priv = { ~0L }) +#pragma omp declare reduction(maxb:short:omp_out = omp_in > omp_out ? omp_in : omp_out) initializer(omp_priv = -6) + +struct B z[10]; + +__attribute__((noinline, noclone)) void +foo (struct A (*x)[3][2], struct A *y, struct D w[1][2]) +{ + struct C a[9] = {}; + short b[5] = {}; + int i; + #pragma omp parallel for reduction(+:x[0:2][:][0:2], z[:4]) \ + reduction(*:y[:3]) reduction(|:a[:4]) \ + reduction(&:w[0:1][:2]) reduction(maxb:b) + for (i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1].t += i; + if ((i & 15) == 1) + y[0].t *= 3; + if ((i & 31) == 2) + y[1].t *= 7; + if ((i & 63) == 3) + y[2].t *= 17; + z[i / 32].t += (i & 3); + if (i < 4) + z[i].t += i; + a[i / 32].t |= 1ULL << (i & 30); + w[0][i & 1].t &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[2]) + b[2] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } + for (i = 0; i < 9; i++) + if (a[i].t != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + if (b[0] != 78 || b[1] != 12 || b[2] != 22 || b[3] != 84 || b[4] != 127) + __builtin_abort (); +} + +int +main () +{ + struct A a[4][3][2] = {}; + static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }}, + {{ 312, 381 }, { 295, 356 }, { 337, 335 }}, + {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }}, + {{ 0, 0 }, { 0, 0 }, { 0, 0 }}}; + struct A y[5] = { { 0 }, { 1 }, { 1 }, { 1 }, { 0 } }; + int y2[5] = { 0, 6561, 2401, 289, 0 }; + char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 }; + struct D w[1][2] = { { { ~0L }, { ~0L } } }; + foo (&a[1], y + 1, w); + int i, j, k; + for (i = 0; i < 4; i++) + for (j = 0; j < 3; j++) + for (k = 0; k < 2; k++) + if (a[i][j][k].t != a2[i][j][k]) + __builtin_abort (); + for (i = 0; i < 5; i++) + if (y[i].t != y2[i]) + __builtin_abort (); + for (i = 0; i < 10; i++) + if (z[i].t != z2[i]) + __builtin_abort (); + if (w[0][0].t != ~0x249249L || w[0][1].t != ~0x249249L) + __builtin_abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/reduction-9.c b/libgomp/testsuite/libgomp.c/reduction-9.c new file mode 100644 index 00000000000..13605c1ab88 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/reduction-9.c @@ -0,0 +1,71 @@ +char z[10] = { 0 }; + +__attribute__((noinline, noclone)) void +foo (int (*x)[3][2], int *y, long w[1][2], int p1, long p2, long p3, int p4, + int p5, long p6, short p7) +{ + unsigned long long a[p7 + 4]; + short b[p7]; + int i; + for (i = 0; i < p7 + 4; i++) + { + if (i < p7) + b[i] = -6; + a[i] = 0; + } + #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2], z[:p3]) \ + reduction(*:y[:p4]) reduction(|:a[:p5]) \ + reduction(&:w[0:p6 - 1][:p6]) reduction(max:b) + for (i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1] += i; + if ((i & 15) == 1) + y[0] *= 3; + if ((i & 31) == 2) + y[1] *= 7; + if ((i & 63) == 3) + y[2] *= 17; + z[i / 32] += (i & 3); + if (i < 4) + z[i] += i; + a[i / 32] |= 1ULL << (i & 30); + w[0][i & 1] &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[2]) + b[2] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } + for (i = 0; i < 9; i++) + if (a[i] != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + if (b[0] != 78 || b[1] != 12 || b[2] != 22 || b[3] != 84 || b[4] != 127) + __builtin_abort (); +} + +int +main () +{ + int a[4][3][2] = {}; + static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }}, + {{ 312, 381 }, { 295, 356 }, { 337, 335 }}, + {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }}, + {{ 0, 0 }, { 0, 0 }, { 0, 0 }}}; + int y[5] = { 0, 1, 1, 1, 0 }; + int y2[5] = { 0, 6561, 2401, 289, 0 }; + char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 }; + long w[1][2] = { ~0L, ~0L }; + foo (&a[1], y + 1, w, 1, 3L, 4L, 3, 4, 2L, 5); + if (__builtin_memcmp (a, a2, sizeof (a)) + || __builtin_memcmp (y, y2, sizeof (y)) + || __builtin_memcmp (z, z2, sizeof (z)) + || w[0][0] != ~0x249249L + || w[0][1] != ~0x249249L) + __builtin_abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/target-1.c b/libgomp/testsuite/libgomp.c/target-1.c index f734d3c279d..c7abb008182 100644 --- a/libgomp/testsuite/libgomp.c/target-1.c +++ b/libgomp/testsuite/libgomp.c/target-1.c @@ -34,7 +34,7 @@ fn2 (int x, int y, int z) fn1 (b, c, x); #pragma omp target data map(to: b) { - #pragma omp target map(tofrom: c) + #pragma omp target map(tofrom: c, s) #pragma omp teams num_teams(y) thread_limit(z) reduction(+:s) firstprivate(x) #pragma omp distribute dist_schedule(static, 4) collapse(1) for (j=0; j < x; j += y) @@ -52,7 +52,7 @@ fn3 (int x) double b[1024], c[1024], s = 0; int i; fn1 (b, c, x); - #pragma omp target map(to: b, c) + #pragma omp target map(to: b, c) map(tofrom:s) #pragma omp parallel for reduction(+:s) for (i = 0; i < x; i++) tgt (), s += b[i] * c[i]; @@ -66,7 +66,8 @@ fn4 (int x, double *p) int i; fn1 (b, c, x); fn1 (d + x, p + x, x); - #pragma omp target map(to: b, c[0:x], d[x:x]) map(to:p[x:64 + (x & 31)]) + #pragma omp target map(to: b, c[0:x], d[x:x]) map(to:p[x:64 + (x & 31)]) \ + map(tofrom: s) #pragma omp parallel for reduction(+:s) for (i = 0; i < x; i++) s += b[i] * c[i] + d[x + i] + p[x + i]; diff --git a/libgomp/testsuite/libgomp.c/target-11.c b/libgomp/testsuite/libgomp.c/target-11.c new file mode 100644 index 00000000000..625c2863f4b --- /dev/null +++ b/libgomp/testsuite/libgomp.c/target-11.c @@ -0,0 +1,86 @@ +/* { dg-require-effective-target offload_device_nonshared_as } */ + +#include +#include + +#define N 32 + +void test_array_section (int *p) +{ + #pragma omp target data map(alloc: p[0:N]) + { + int ok = 1; + for (int i = 10; i < 10 + 4; i++) + p[i] = 997 * i; + + #pragma omp target map(always to:p[10:4]) map(tofrom: ok) + for (int i = 10; i < 10 + 4; i++) + if (p[i] != 997 * i) + ok = 0; + + assert (ok); + + #pragma omp target map(always from:p[7:9]) + for (int i = 0; i < N; i++) + p[i] = i; + } +} + +int main () +{ + int aa = 0, bb = 0, cc = 0, dd = 0; + + #pragma omp target data map(tofrom: aa) map(to: bb) map(from: cc, dd) + { + int ok; + aa = bb = cc = 1; + + /* Set dd on target to 0 for the further check. */ + #pragma omp target map(always to: dd) + ; + + dd = 1; + #pragma omp target map(tofrom: aa) map(always to: bb) \ + map(always from: cc) map(to: dd) map(from: ok) + { + /* bb is always to, aa and dd are not. */ + ok = (aa == 0) && (bb == 1) && (dd == 0); + aa = bb = cc = dd = 2; + } + + assert (ok); + assert (aa == 1); + assert (bb == 1); + assert (cc == 2); /* cc is always from. */ + assert (dd == 1); + + dd = 3; + #pragma omp target map(from: cc) map(always to: dd) map(from: ok) + { + ok = (dd == 3); /* dd is always to. */ + cc = dd = 4; + } + + assert (ok); + assert (cc == 2); + assert (dd == 3); + } + + assert (aa == 2); + assert (bb == 1); + assert (cc == 4); + assert (dd == 4); + + int *array = calloc (N, sizeof (int)); + test_array_section (array); + + for (int i = 0; i < 7; i++) + assert (array[i] == 0); + for (int i = 7; i < 7 + 9; i++) + assert (array[i] == i); + for (int i = 7 + 9; i < N; i++) + assert (array[i] == 0); + + free (array); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/target-12.c b/libgomp/testsuite/libgomp.c/target-12.c new file mode 100644 index 00000000000..e6b009463ad --- /dev/null +++ b/libgomp/testsuite/libgomp.c/target-12.c @@ -0,0 +1,130 @@ +#include +#include + +int +main () +{ + int d = omp_get_default_device (); + int id = omp_get_initial_device (); + int err; + int q[128], i; + void *p; + + if (d < 0 || d >= omp_get_num_devices ()) + d = id; + + for (i = 0; i < 128; i++) + q[i] = i; + + p = omp_target_alloc (130 * sizeof (int), d); + if (p == NULL) + return 0; + + if (omp_target_memcpy_rect (NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, + d, id) < 3 + || omp_target_memcpy_rect (NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, + NULL, id, d) < 3 + || omp_target_memcpy_rect (NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, + NULL, id, id) < 3) + abort (); + + if (omp_target_associate_ptr (q, p, 128 * sizeof (int), sizeof (int), d) == 0) + { + size_t volume[3] = { 128, 0, 0 }; + size_t dst_offsets[3] = { 0, 0, 0 }; + size_t src_offsets[3] = { 1, 0, 0 }; + size_t dst_dimensions[3] = { 128, 0, 0 }; + size_t src_dimensions[3] = { 128, 0, 0 }; + + if (omp_target_associate_ptr (q, p, 128 * sizeof (int), sizeof (int), d) != 0) + abort (); + + if (omp_target_is_present (q, d) != 1 + || omp_target_is_present (&q[32], d) != 1 + || omp_target_is_present (&q[128], d) != 1) + abort (); + + if (omp_target_memcpy (p, q, 128 * sizeof (int), sizeof (int), 0, + d, id) != 0) + abort (); + + #pragma omp target if (d >= 0) device (d >= 0 ? d : 0) map(alloc:q[0:32]) map(from:err) + { + int j; + err = 0; + for (j = 0; j < 128; j++) + if (q[j] != j) + err = 1; + else + q[j] += 4; + } + + if (err) + abort (); + + if (omp_target_memcpy_rect (q, p, sizeof (int), 1, volume, + dst_offsets, src_offsets, dst_dimensions, + src_dimensions, id, d) != 0) + abort (); + + for (i = 0; i < 128; i++) + if (q[i] != i + 4) + abort (); + + volume[2] = 2; + volume[1] = 3; + volume[0] = 6; + dst_offsets[2] = 1; + dst_offsets[1] = 0; + dst_offsets[0] = 0; + src_offsets[2] = 1; + src_offsets[1] = 0; + src_offsets[0] = 3; + dst_dimensions[2] = 2; + dst_dimensions[1] = 3; + dst_dimensions[0] = 6; + src_dimensions[2] = 3; + src_dimensions[1] = 4; + src_dimensions[0] = 6; + if (omp_target_memcpy_rect (p, q, sizeof (int), 3, volume, + dst_offsets, src_offsets, dst_dimensions, + src_dimensions, d, id) != 0) + abort (); + + #pragma omp target if (d >= 0) device (d >= 0 ? d : 0) map(alloc:q[0:32]) map(from:err) + { + int j, k, l; + err = 0; + for (j = 0; j < 6; j++) + for (k = 0; k < 3; k++) + for (l = 0; l < 2; l++) + if (q[j * 6 + k * 2 + l] != 3 * 12 + 4 + 1 + l + k * 3 + j * 12) + err = 1; + } + + if (err) + abort (); + + if (omp_target_memcpy (p, p, 10 * sizeof (int), 51 * sizeof (int), + 111 * sizeof (int), d, d) != 0) + abort (); + + #pragma omp target if (d >= 0) device (d >= 0 ? d : 0) map(alloc:q[0:32]) map(from:err) + { + int j; + err = 0; + for (j = 0; j < 10; j++) + if (q[50 + j] != q[110 + j]) + err = 1; + } + + if (err) + abort (); + + if (omp_target_disassociate_ptr (q, d) != 0) + abort (); + } + + omp_target_free (p, d); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/target-13.c b/libgomp/testsuite/libgomp.c/target-13.c new file mode 100644 index 00000000000..168850b507c --- /dev/null +++ b/libgomp/testsuite/libgomp.c/target-13.c @@ -0,0 +1,45 @@ +#ifdef __cplusplus +extern "C" +#else +extern +#endif +void abort (void); +struct S { int s, t; }; + +void +foo () +{ + int x = 5, y = 6, err = 0; + struct S u = { 7, 8 }, v = { 9, 10 }; + double s = 11.5, t = 12.5; + #pragma omp target private (x, u, s) firstprivate (y, v, t) map(from:err) + { + x = y; + u = v; + s = t; + err = (x != 6 || y != 6 + || u.s != 9 || u.t != 10 || v.s != 9 || v.t != 10 + || s != 12.5 || t != 12.5); + x += 1; + y += 2; + u.s += 3; + v.t += 4; + s += 2.5; + t += 3.0; + if (x != 7 || y != 8 + || u.s != 12 || u.t != 10 || v.s != 9 || v.t != 14 + || s != 15.0 || t != 15.5) + err = 1; + } + if (err || x != 5 || y != 6 + || u.s != 7 || u.t != 8 || v.s != 9 || v.t != 10 + || s != 11.5 || t != 12.5) + abort (); +} + +int +main () +{ + foo (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/target-14.c b/libgomp/testsuite/libgomp.c/target-14.c new file mode 100644 index 00000000000..17d383407a2 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/target-14.c @@ -0,0 +1,38 @@ +#include +#include + +int +main () +{ + int d = omp_get_default_device (); + int id = omp_get_initial_device (); + int err; + void *p; + + if (d < 0 || d >= omp_get_num_devices ()) + d = id; + + p = omp_target_alloc (128 * sizeof (int), d); + if (p == NULL) + return 0; + + #pragma omp target is_device_ptr (p) if (d >= 0) device (d >= 0 ? d : 0) + { + int i, *q = (int *) p; + for (i = 0; i < 128; i++) + q[i] = i + 7; + } + #pragma omp target is_device_ptr (p) if (d >= 0) device (d >= 0 ? d : 0) map(from:err) + { + int i; + err = 0; + for (i = 0; i < 128; i++) + if (((int *) p)[i] != i + 7) + err = 1; + } + if (err) + abort (); + + omp_target_free (p, d); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/target-15.c b/libgomp/testsuite/libgomp.c/target-15.c new file mode 100644 index 00000000000..fee9252ef3d --- /dev/null +++ b/libgomp/testsuite/libgomp.c/target-15.c @@ -0,0 +1,74 @@ +extern void abort (void); + +void +foo (int *x) +{ + int a[10], b[15], err, i; + for (i = 0; i < 10; i++) + a[i] = 7 * i; + for (i = 0; i < 15; i++) + b[i] = 8 * i; + #pragma omp target map(to:x[5:10], a[0:10], b[5:10]) map(from:err) + { + err = 0; + for (i = 0; i < 10; i++) + if (x[5 + i] != 20 + 4 * i + || a[i] != 7 * i + || b[5 + i] != 40 + 8 * i) + err = 1; + } + if (err) + abort (); +} + +void +bar (int n, int v) +{ + int a[n], b[n], c[n], d[n], e[n], err, i; + int (*x)[n] = &c; + for (i = 0; i < n; i++) + { + (*x)[i] = 4 * i; + a[i] = 7 * i; + b[i] = 8 * i; + } + #pragma omp target map(to:x[0][5:10], a[0:10], b[5:10]) map(from:err) + { + err = 0; + for (i = 0; i < 10; i++) + if ((*x)[5 + i] != 20 + 4 * i + || a[i] != 7 * i + || b[5 + i] != 40 + 8 * i) + err = 1; + } + if (err) + abort (); + for (i = 0; i < n; i++) + { + (*x)[i] = 9 * i; + a[i] = 12 * i; + b[i] = 13 * i; + } + #pragma omp target map(to:x[0][v:v+5], a[v-5:v+5], b[v:v+5]) map(from:err) + { + err = 0; + for (i = 0; i < 10; i++) + if ((*x)[5 + i] != 45 + 9 * i + || a[i] != 12 * i + || b[5 + i] != 65 + 13 * i) + err = 1; + } + if (err) + abort (); +} + +int +main () +{ + int x[15], i; + for (i = 0; i < 15; i++) + x[i] = 4 * i; + foo (x); + bar (15, 5); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/target-16.c b/libgomp/testsuite/libgomp.c/target-16.c new file mode 100644 index 00000000000..7b0919b1b00 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/target-16.c @@ -0,0 +1,45 @@ +extern void abort (void); + +void +foo (int n) +{ + int a[n], i, err; + for (i = 0; i < n; i++) + a[i] = 7 * i; + #pragma omp target firstprivate (a) map(from:err) private (i) + { + err = 0; + for (i = 0; i < n; i++) + if (a[i] != 7 * i) + err = 1; + } + if (err) + abort (); +} + +void +bar (int n) +{ + int a[n], i, err; + #pragma omp target private (a) map(from:err) + { + #pragma omp parallel for + for (i = 0; i < n; i++) + a[i] = 7 * i; + err = 0; + #pragma omp parallel for reduction(|:err) + for (i = 0; i < n; i++) + if (a[i] != 7 * i) + err |= 1; + } + if (err) + abort (); +} + +int +main () +{ + foo (7); + bar (7); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/target-17.c b/libgomp/testsuite/libgomp.c/target-17.c new file mode 100644 index 00000000000..4a762012eaf --- /dev/null +++ b/libgomp/testsuite/libgomp.c/target-17.c @@ -0,0 +1,99 @@ +extern void abort (void); + +void +foo (int n) +{ + int a[n], i, err; + for (i = 0; i < n; i++) + a[i] = 5 * i; + #pragma omp target map(to:a) map(from:err) private(i) + { + err = 0; + for (i = 0; i < n; i++) + if (a[i] != 5 * i) + err = 1; + } + if (err) + abort (); + for (i = 0; i < n; i++) + a[i] += i; + #pragma omp target map(from:err) private(i) + { + err = 0; + for (i = 0; i < n; i++) + if (a[i] != 6 * i) + err = 1; + } + if (err) + abort (); + for (i = 0; i < n; i++) + a[i] += i; + #pragma omp target firstprivate (a) map(from:err) private(i) + { + err = 0; + for (i = 0; i < n; i++) + if (a[i] != 7 * i) + err = 1; + } + if (err) + abort (); + int on = n; + #pragma omp target firstprivate (n) map(tofrom: n) + { + n++; + } + if (on != n) + abort (); + #pragma omp target map(tofrom: n) private (n) + { + n = 25; + } + if (on != n) + abort (); + for (i = 0; i < n; i++) + a[i] += i; + #pragma omp target map(to:a) firstprivate (a) map(from:err) private(i) + { + err = 0; + for (i = 0; i < n; i++) + if (a[i] != 8 * i) + err = 1; + } + if (err) + abort (); + for (i = 0; i < n; i++) + a[i] += i; + #pragma omp target firstprivate (a) map(to:a) map(from:err) private(i) + { + err = 0; + for (i = 0; i < n; i++) + if (a[i] != 9 * i) + err = 1; + } + if (err) + abort (); + for (i = 0; i < n; i++) + a[i] += i; + #pragma omp target map(tofrom:a) map(from:err) private(a, i) + { + err = 0; + for (i = 0; i < n; i++) + a[i] = 7; + #pragma omp parallel for reduction(|:err) + for (i = 0; i < n; i++) + if (a[i] != 7) + err |= 1; + } + if (err) + abort (); + for (i = 0; i < n; i++) + if (a[i] != 10 * i) + abort (); +} + +int +main () +{ + foo (9); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/target-18.c b/libgomp/testsuite/libgomp.c/target-18.c new file mode 100644 index 00000000000..cbacaf6a77a --- /dev/null +++ b/libgomp/testsuite/libgomp.c/target-18.c @@ -0,0 +1,52 @@ +extern void abort (void); + +void +foo (int n) +{ + int a[4] = { 0, 1, 2, 3 }, b[n]; + int *p = a + 1, i, err; + for (i = 0; i < n; i++) + b[i] = 9 + i; + #pragma omp target data map(to:a) + #pragma omp target data use_device_ptr(p) map(from:err) + #pragma omp target is_device_ptr(p) private(i) map(from:err) + { + err = 0; + for (i = 0; i < 4; i++) + if (p[i - 1] != i) + err = 1; + } + if (err) + abort (); + for (i = 0; i < 4; i++) + a[i] = 23 + i; + #pragma omp target data map(to:a) + #pragma omp target data use_device_ptr(a) map(from:err) + #pragma omp target is_device_ptr(a) private(i) map(from:err) + { + err = 0; + for (i = 0; i < 4; i++) + if (a[i] != 23 + i) + err = 1; + } + if (err) + abort (); + #pragma omp target data map(to:b) + #pragma omp target data use_device_ptr(b) map(from:err) + #pragma omp target is_device_ptr(b) private(i) map(from:err) + { + err = 0; + for (i = 0; i < 4; i++) + if (b[i] != 9 + i) + err = 1; + } + if (err) + abort (); +} + +int +main () +{ + foo (9); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/target-19.c b/libgomp/testsuite/libgomp.c/target-19.c new file mode 100644 index 00000000000..710c5078ff6 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/target-19.c @@ -0,0 +1,127 @@ +extern void abort (void); + +void +foo (int *p, int *q, int *r, int n, int m) +{ + int i, err, *s = r; + #pragma omp target data map(to:p[0:8]) + { + /* For zero length array sections, p points to the start of + already mapped range, q to the end of it, and r does not point + to an mapped range. */ + #pragma omp target map(alloc:p[:0]) map(to:q[:0]) map(from:r[:0]) private(i) map(from:err) firstprivate (s) + { + err = 0; + for (i = 0; i < 8; i++) + if (p[i] != i + 1 || q[i - 8] != i + 1) + err = 1; + if (p + 8 != q || (r != (int *) 0 && r != s)) + err = 1; + } + if (err) + abort (); + /* Implicit mapping of pointers behaves the same way. */ + #pragma omp target private(i) map(from:err) firstprivate (s) + { + err = 0; + for (i = 0; i < 8; i++) + if (p[i] != i + 1 || q[i - 8] != i + 1) + err = 1; + if (p + 8 != q || (r != (int *) 0 && r != s)) + err = 1; + } + if (err) + abort (); + /* And zero-length array sections, though not known at compile + time, behave the same. */ + #pragma omp target map(p[:n]) map(tofrom:q[:n]) map(alloc:r[:n]) private(i) map(from:err) firstprivate (s) + { + err = 0; + for (i = 0; i < 8; i++) + if (p[i] != i + 1 || q[i - 8] != i + 1) + err = 1; + if (p + 8 != q || (r != (int *) 0 && r != s)) + err = 1; + } + if (err) + abort (); + /* Non-zero length array sections, though not known at compile, + behave differently. */ + #pragma omp target map(p[:m]) map(tofrom:q[:m]) map(to:r[:m]) private(i) map(from:err) + { + err = 0; + for (i = 0; i < 8; i++) + if (p[i] != i + 1) + err = 1; + if (q[0] != 9 || r[0] != 10) + err = 1; + } + if (err) + abort (); + #pragma omp target data map(to:q[0:1]) + { + /* For zero length array sections, p points to the start of + already mapped range, q points to the start of another one, + and r to the end of the second one. */ + #pragma omp target map(to:p[:0]) map(from:q[:0]) map(tofrom:r[:0]) private(i) map(from:err) + { + err = 0; + for (i = 0; i < 8; i++) + if (p[i] != i + 1) + err = 1; + if (q[0] != 9 || r != q + 1) + err = 1; + } + if (err) + abort (); + /* Implicit mapping of pointers behaves the same way. */ + #pragma omp target private(i) map(from:err) + { + err = 0; + for (i = 0; i < 8; i++) + if (p[i] != i + 1) + err = 1; + if (q[0] != 9 || r != q + 1) + err = 1; + } + if (err) + abort (); + /* And zero-length array sections, though not known at compile + time, behave the same. */ + #pragma omp target map(p[:n]) map(alloc:q[:n]) map(from:r[:n]) private(i) map(from:err) + { + err = 0; + for (i = 0; i < 8; i++) + if (p[i] != i + 1) + err = 1; + if (q[0] != 9 || r != q + 1) + err = 1; + } + if (err) + abort (); + /* Non-zero length array sections, though not known at compile, + behave differently. */ + #pragma omp target map(p[:m]) map(alloc:q[:m]) map(tofrom:r[:m]) private(i) map(from:err) + { + err = 0; + for (i = 0; i < 8; i++) + if (p[i] != i + 1) + err = 1; + if (q[0] != 9 || r[0] != 10) + err = 1; + } + if (err) + abort (); + } + } +} + +int +main () +{ + int a[32], i; + for (i = 0; i < 32; i++) + a[i] = i; + foo (a + 1, a + 9, a + 10, 0, 1); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/target-2.c b/libgomp/testsuite/libgomp.c/target-2.c index ada8dad81ad..0ba766c0a82 100644 --- a/libgomp/testsuite/libgomp.c/target-2.c +++ b/libgomp/testsuite/libgomp.c/target-2.c @@ -23,7 +23,7 @@ fn2 (int x) int i; fn1 (b, c, x); fn1 (e, d + x, x); - #pragma omp target map(to: b, c[:x], d[x:x], e) + #pragma omp target map(to: b, c[:x], d[x:x], e) map(tofrom: s) #pragma omp parallel for reduction(+:s) for (i = 0; i < x; i++) s += b[i] * c[i] + d[x + i] + sizeof (b) - sizeof (c); @@ -38,7 +38,7 @@ fn3 (int x) int i; fn1 (b, c, x); fn1 (e, d, x); - #pragma omp target + #pragma omp target map(tofrom: s) #pragma omp parallel for reduction(+:s) for (i = 0; i < x; i++) s += b[i] * c[i] + d[i]; @@ -56,7 +56,7 @@ fn4 (int x) #pragma omp target data map(from: b, c[:x], d[x:x], e) { #pragma omp target update to(b, c[:x], d[x:x], e) - #pragma omp target map(c[:x], d[x:x]) + #pragma omp target map(c[:x], d[x:x], s) #pragma omp parallel for reduction(+:s) for (i = 0; i < x; i++) { diff --git a/libgomp/testsuite/libgomp.c/target-20.c b/libgomp/testsuite/libgomp.c/target-20.c new file mode 100644 index 00000000000..3f4e798a755 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/target-20.c @@ -0,0 +1,120 @@ +/* { dg-require-effective-target offload_device_nonshared_as } */ + +#include +#include + +#define N 40 + +int sum; +int var1 = 1; +int var2 = 2; + +#pragma omp declare target +int D[N]; +#pragma omp end declare target + +void enter_data (int *X) +{ + #pragma omp target enter data map(to: var1, var2, X[:N]) map(alloc: sum) +} + +void exit_data_0 (int *D) +{ + #pragma omp target exit data map(delete: D[:N]) +} + +void exit_data_1 () +{ + #pragma omp target exit data map(from: var1) +} + +void exit_data_2 (int *X) +{ + #pragma omp target exit data map(from: var2) map(release: X[:N], sum) +} + +void exit_data_3 (int *p) +{ + #pragma omp target exit data map(from: p[:0]) +} + +void test_nested () +{ + int X = 0, Y = 0, Z = 0; + + #pragma omp target data map(from: X, Y, Z) + { + #pragma omp target data map(from: X, Y, Z) + { + #pragma omp target map(from: X, Y, Z) + X = Y = Z = 1337; + assert (X == 0); + assert (Y == 0); + assert (Z == 0); + + #pragma omp target exit data map(from: X) map(release: Y) + assert (X == 0); + assert (Y == 0); + + #pragma omp target exit data map(release: Y) map(delete: Z) + assert (Y == 0); + assert (Z == 0); + } + assert (X == 1337); + assert (Y == 0); + assert (Z == 0); + + #pragma omp target map(from: X) + X = 2448; + assert (X == 2448); + assert (Y == 0); + assert (Z == 0); + + X = 4896; + } + assert (X == 4896); + assert (Y == 0); + assert (Z == 0); +} + +int main () +{ + int *X = malloc (N * sizeof (int)); + int *Y = malloc (N * sizeof (int)); + X[10] = 10; + Y[20] = 20; + enter_data (X); + + exit_data_0 (D); /* This should have no effect on D. */ + + #pragma omp target map(alloc: var1, var2, X[:N]) map(to: Y[:N]) map(always from: sum) + { + var1 += X[10]; + var2 += Y[20]; + sum = var1 + var2; + D[sum]++; + } + + assert (var1 == 1); + assert (var2 == 2); + assert (sum == 33); + + exit_data_1 (); + assert (var1 == 11); + assert (var2 == 2); + + /* Increase refcount of already mapped X[0:N]. */ + #pragma omp target enter data map(alloc: X[16:1]) + + exit_data_2 (X); + assert (var2 == 22); + + exit_data_3 (X + 5); /* Unmap X[0:N]. */ + + free (X); + free (Y); + + test_nested (); + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/target-21.c b/libgomp/testsuite/libgomp.c/target-21.c new file mode 100644 index 00000000000..41498cf2148 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/target-21.c @@ -0,0 +1,79 @@ +extern void abort (void); +union U { int x; long long y; }; +struct T { int a; union U b; int c; }; +struct S { int s; int u; struct T v; int x[10]; union U w; int y[10]; int z[10]; }; +volatile int z; + +int +main () +{ + struct S s; + s.s = 0; + s.u = 1; + s.v.a = 2; + s.v.b.y = 3LL; + s.v.c = 19; + s.w.x = 4; + s.x[0] = 7; + s.x[1] = 8; + s.y[3] = 9; + s.y[4] = 10; + s.y[5] = 11; + int err = 0; + #pragma omp target map (to:s.v.b, s.u, s.x[0:z + 2]) \ + map (tofrom:s.y[3:3]) \ + map (from: s.w, s.z[z + 1:z + 3], err) + { + err = 0; + if (s.u != 1 || s.v.b.y != 3LL || s.x[0] != 7 || s.x[1] != 8 + || s.y[3] != 9 || s.y[4] != 10 || s.y[5] != 11) + err = 1; + s.w.x = 6; + s.y[3] = 12; + s.y[4] = 13; + s.y[5] = 14; + s.z[1] = 15; + s.z[2] = 16; + s.z[3] = 17; + } + if (err || s.w.x != 6 || s.y[3] != 12 || s.y[4] != 13 || s.y[5] != 14 + || s.z[1] != 15 || s.z[2] != 16 || s.z[3] != 17) + abort (); + s.u++; + s.v.a++; + s.v.b.y++; + s.w.x++; + s.x[1] = 18; + s.z[0] = 19; + #pragma omp target data map (tofrom: s) + #pragma omp target map (always to: s.w, s.x[1], err) map (alloc:s.u, s.v.b, s.z[z:z + 1]) + { + err = 0; + if (s.u != 2 || s.v.b.y != 4LL || s.w.x != 7 || s.x[1] != 18 || s.z[0] != 19) + err = 1; + s.w.x = 8; + s.x[1] = 20; + s.z[0] = 21; + } + if (err || s.w.x != 8 || s.x[1] != 20 || s.z[0] != 21) + abort (); + s.u++; + s.v.a++; + s.v.b.y++; + s.w.x++; + s.x[0] = 22; + s.x[1] = 23; + #pragma omp target data map (from: s.w, s.x[0:2]) map (to: s.v.b, s.u) + #pragma omp target map (always to: s.w, s.x[0:2], err) map (alloc:s.u, s.v.b) + { + err = 0; + if (s.u != 3 || s.v.b.y != 5LL || s.w.x != 9 || s.x[0] != 22 || s.x[1] != 23) + err = 1; + s.w.x = 11; + s.x[0] = 24; + s.x[1] = 25; + } + if (err || s.w.x != 11 || s.x[0] != 24 || s.x[1] != 25) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/target-22.c b/libgomp/testsuite/libgomp.c/target-22.c new file mode 100644 index 00000000000..aad8a0a09df --- /dev/null +++ b/libgomp/testsuite/libgomp.c/target-22.c @@ -0,0 +1,51 @@ +extern void abort (void); +struct T { int a; int *b; int c; }; +struct S { int *s; char *u; struct T v; short *w; }; +volatile int z; + +int +main () +{ + struct S s; + int a[32], i; + char b[32]; + short c[32]; + for (i = 0; i < 32; i++) + { + a[i] = i; + b[i] = 32 + i; + c[i] = 64 + i; + } + s.s = a; + s.u = b + 2; + s.v.b = a + 16; + s.w = c + 3; + int err = 0; + #pragma omp target map (to:s.v.b[0:z + 7], s.u[z + 1:z + 4]) \ + map (tofrom:s.s[3:3]) \ + map (from: s.w[z:4], err) private (i) + { + err = 0; + for (i = 0; i < 7; i++) + if (s.v.b[i] != 16 + i) + err = 1; + for (i = 1; i < 5; i++) + if (s.u[i] != 34 + i) + err = 1; + for (i = 3; i < 6; i++) + if (s.s[i] != i) + err = 1; + else + s.s[i] = 128 + i; + for (i = 0; i < 4; i++) + s.w[i] = 96 + i; + } + if (err) + abort (); + for (i = 0; i < 32; i++) + if (a[i] != ((i >= 3 && i < 6) ? 128 + i : i) + || b[i] != 32 + i + || c[i] != ((i >= 3 && i < 7) ? 93 + i : 64 + i)) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/target-23.c b/libgomp/testsuite/libgomp.c/target-23.c new file mode 100644 index 00000000000..fb1532a07b2 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/target-23.c @@ -0,0 +1,48 @@ +extern void abort (void); +struct S { int s; int *u; int v[5]; }; +volatile int z; + +int +main () +{ + int u[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, err = 0; + struct S s = { 9, u + 3, { 10, 11, 12, 13, 14 } }; + int *v = u + 4; + #pragma omp target enter data map (to: s.s, s.u[0:5]) map (alloc: s.v[1:3]) + s.s++; + u[3]++; + s.v[1]++; + #pragma omp target update to (s.s) to (s.u[0:2], s.v[1:3]) + #pragma omp target map (alloc: s.s, s.v[1:3]) map (from: err) + { + err = 0; + if (s.s != 10 || s.v[1] != 12 || s.v[2] != 12 || s.v[3] != 13) + err = 1; + if (v[-1] != 4 || v[0] != 4 || v[1] != 5 || v[2] != 6 || v[3] != 7) + err = 1; + s.s++; + s.v[2] += 2; + v[-1] = 5; + v[3] = 9; + } + if (err) + abort (); + #pragma omp target map (alloc: s.u[0:5]) + { + err = 0; + if (s.u[0] != 5 || s.u[1] != 4 || s.u[2] != 5 || s.u[3] != 6 || s.u[4] != 9) + err = 1; + s.u[1] = 12; + } + #pragma omp target update from (s.s, s.u[0:5]) from (s.v[1:3]) + if (err || s.s != 11 || u[0] != 0 || u[1] != 1 || u[2] != 2 || u[3] != 5 + || u[4] != 12 || u[5] != 5 || u[6] != 6 || u[7] != 9 || u[8] != 8 + || u[9] != 9 || s.v[0] != 10 || s.v[1] != 12 || s.v[2] != 14 + || s.v[3] != 13 || s.v[4] != 14) + abort (); + #pragma omp target exit data map (release: s.s) + #pragma omp target exit data map (release: s.u[0:5]) + #pragma omp target exit data map (delete: s.v[1:3]) + #pragma omp target exit data map (release: s.s) + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/target-24.c b/libgomp/testsuite/libgomp.c/target-24.c new file mode 100644 index 00000000000..e0ff29aaee8 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/target-24.c @@ -0,0 +1,43 @@ +#include +#include + +int +main () +{ + int d = omp_get_default_device (); + int id = omp_get_initial_device (); + + if (d < 0 || d >= omp_get_num_devices ()) + d = id; + + int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + int *b = a; + int shared_mem = 0; + #pragma omp target map (alloc: shared_mem) + shared_mem = 1; + if (omp_target_is_present (b, d) != shared_mem) + abort (); + #pragma omp target enter data map (to: a) + if (omp_target_is_present (b, d) == 0) + abort (); + #pragma omp target enter data map (alloc: b[:0]) + if (omp_target_is_present (b, d) == 0) + abort (); + #pragma omp target exit data map (release: b[:0]) + if (omp_target_is_present (b, d) == 0) + abort (); + #pragma omp target exit data map (release: b[:0]) + if (omp_target_is_present (b, d) != shared_mem) + abort (); + #pragma omp target enter data map (to: a) + if (omp_target_is_present (b, d) == 0) + abort (); + #pragma omp target enter data map (always, to: b[:0]) + if (omp_target_is_present (b, d) == 0) + abort (); + #pragma omp target exit data map (delete: b[:0]) + if (omp_target_is_present (b, d) != shared_mem) + abort (); + #pragma omp target exit data map (from: b[:0]) + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/target-25.c b/libgomp/testsuite/libgomp.c/target-25.c new file mode 100644 index 00000000000..aeb19aee510 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/target-25.c @@ -0,0 +1,84 @@ +#include +#include + +int +main () +{ + int x = 0, y = 0, z = 0, s = 11, t = 12, u = 13, w = 7, err; + #pragma omp parallel + #pragma omp single + { + #pragma omp task depend(in: x) + { + usleep (5000); + x = 1; + } + #pragma omp task depend(in: x) + { + usleep (6000); + y = 2; + } + #pragma omp task depend(out: z) + { + usleep (7000); + z = 3; + } + #pragma omp target map(tofrom: x) map(from: err) firstprivate (y) depend(inout: x, z) + err = (x != 1 || y != 2 || z != 3); + if (err) + abort (); + #pragma omp task depend(in: x) + { + usleep (5000); + x = 4; + } + #pragma omp task depend(in: x) + { + usleep (4000); + y = 5; + } + #pragma omp task depend(in: z) + { + usleep (3000); + z = 6; + } + #pragma omp target enter data nowait map (to: w) + #pragma omp target enter data depend (inout: x, z) map (to: x, y, z) + #pragma omp target map (alloc: x, y, z) map(from: err) + { + err = (x != 4 || y != 5 || z != 6); + x = 7; + y = 8; + z = 9; + } + if (err) + abort (); + #pragma omp taskwait + #pragma omp target map (alloc: w) map(from: err) + { + err = w != 7; + w = 17; + } + if (err) + abort (); + #pragma omp task depend(in: x) + { + usleep (2000); + s = 14; + } + #pragma omp task depend(in: x) + { + usleep (3000); + t = 15; + } + #pragma omp task depend(in: z) + { + usleep (4000); + u = 16; + } + #pragma omp target exit data depend (inout: x, z) map (from: x, y, z, w) + if (x != 7 || y != 8 || z != 9 || s != 14 || t != 15 || u != 16 || w != 17) + abort (); + } + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/target-26.c b/libgomp/testsuite/libgomp.c/target-26.c new file mode 100644 index 00000000000..fa6b52598da --- /dev/null +++ b/libgomp/testsuite/libgomp.c/target-26.c @@ -0,0 +1,36 @@ +extern void abort (void); +#pragma omp declare target +int a[4] = { 2, 3, 4, 5 }, *b; +#pragma omp end declare target + +int +main () +{ + int err; + int c[3] = { 6, 7, 8 }; + b = c; + #pragma omp target map(to: a[0:2], b[0:2]) map(from: err) + err = a[0] != 2 || a[1] != 3 || a[2] != 4 || a[3] != 5 || b[0] != 6 || b[1] != 7; + if (err) + abort (); + a[1] = 9; + a[2] = 10; + #pragma omp target map(always,to:a[1:2]) map(from: err) + err = a[0] != 2 || a[1] != 9 || a[2] != 10 || a[3] != 5; + if (err) + abort (); + #pragma omp parallel firstprivate(a, b, c, err) num_threads (2) + #pragma omp single + { + b = c + 1; + a[0] = 11; + a[2] = 13; + c[1] = 14; + int d = 0; + #pragma omp target map(to: a[0:3], b[d:2]) map (from: err) + err = a[0] != 11 || a[1] != 9 || a[2] != 13 || b[0] != 14 || b[1] != 8; + if (err) + abort (); + } + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/target-27.c b/libgomp/testsuite/libgomp.c/target-27.c new file mode 100644 index 00000000000..c86651b02e3 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/target-27.c @@ -0,0 +1,67 @@ +#include +#include + +int +main () +{ + int x = 0, y = 0, z = 0, err; + int shared_mem = 0; + #pragma omp target map(to: shared_mem) + shared_mem = 1; + #pragma omp parallel + #pragma omp single + { + #pragma omp task depend(in: x) + { + usleep (5000); + x = 1; + } + #pragma omp task depend(in: x) + { + usleep (6000); + y = 2; + } + #pragma omp task depend(out: z) + { + usleep (7000); + z = 3; + } + #pragma omp target enter data map(to: x, y, z) depend(inout: x, z) nowait + #pragma omp task depend(inout: x, z) + { + x++; y++; z++; + } + #pragma omp target update to(x, y) depend(inout: x) nowait + #pragma omp target enter data map(always, to: z) depend(inout: z) nowait + #pragma omp target map (alloc: x, y, z) map (from: err) depend(inout: x, z) + { + err = x != 2 || y != 3 || z != 4; + x = 5; y = 6; z = 7; + } + #pragma omp task depend(in: x) + { + usleep (5000); + if (!shared_mem) + x = 1; + } + #pragma omp task depend(in: x) + { + usleep (6000); + if (!shared_mem) + y = 2; + } + #pragma omp task depend(out: z) + { + usleep (3000); + if (!shared_mem) + z = 3; + } + #pragma omp target exit data map(release: z) depend(inout: z) nowait + #pragma omp target exit data map(from: x, y) depend(inout: x) nowait + #pragma omp target exit data map(from: z) depend(inout: z) nowait + #pragma omp taskwait + if (err || x != 5 || y != 6 || z != 7) + abort (); + } + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/target-7.c b/libgomp/testsuite/libgomp.c/target-7.c index 0fe6150283d..41a1332bb0c 100644 --- a/libgomp/testsuite/libgomp.c/target-7.c +++ b/libgomp/testsuite/libgomp.c/target-7.c @@ -37,63 +37,63 @@ foo (int f) abort (); #pragma omp target data device (d) map (to: h) { - #pragma omp target device (d) + #pragma omp target device (d) map (h) if (omp_get_level () != 0 || (f && !omp_is_initial_device ()) || h++ != 5) abort (); #pragma omp target update device (d) from (h) } #pragma omp target data if (v > 1) map (to: h) { - #pragma omp target if (v > 1) + #pragma omp target if (v > 1) map(h) if (omp_get_level () != 0 || !omp_is_initial_device () || h++ != 6) abort (); #pragma omp target update if (v > 1) from (h) } #pragma omp target data device (d) if (v > 1) map (to: h) { - #pragma omp target device (d) if (v > 1) + #pragma omp target device (d) if (v > 1) map(h) if (omp_get_level () != 0 || !omp_is_initial_device () || h++ != 7) abort (); #pragma omp target update device (d) if (v > 1) from (h) } #pragma omp target data if (v <= 1) map (to: h) { - #pragma omp target if (v <= 1) + #pragma omp target if (v <= 1) map (tofrom: h) if (omp_get_level () != 0 || h++ != 8) abort (); #pragma omp target update if (v <= 1) from (h) } #pragma omp target data device (d) if (v <= 1) map (to: h) { - #pragma omp target device (d) if (v <= 1) + #pragma omp target device (d) if (v <= 1) map (h) if (omp_get_level () != 0 || (f && !omp_is_initial_device ()) || h++ != 9) abort (); #pragma omp target update device (d) if (v <= 1) from (h) } #pragma omp target data if (0) map (to: h) { - #pragma omp target if (0) + #pragma omp target if (0) map (h) if (omp_get_level () != 0 || !omp_is_initial_device () || h++ != 10) abort (); #pragma omp target update if (0) from (h) } #pragma omp target data device (d) if (0) map (to: h) { - #pragma omp target device (d) if (0) + #pragma omp target device (d) if (0) map (h) if (omp_get_level () != 0 || !omp_is_initial_device () || h++ != 11) abort (); #pragma omp target update device (d) if (0) from (h) } #pragma omp target data if (1) map (to: h) { - #pragma omp target if (1) + #pragma omp target if (1) map (tofrom: h) if (omp_get_level () != 0 || h++ != 12) abort (); #pragma omp target update if (1) from (h) } #pragma omp target data device (d) if (1) map (to: h) { - #pragma omp target device (d) if (1) + #pragma omp target device (d) if (1) map (tofrom: h) if (omp_get_level () != 0 || (f && !omp_is_initial_device ()) || h++ != 13) abort (); #pragma omp target update device (d) if (1) from (h) diff --git a/libgomp/testsuite/libgomp.c/taskloop-1.c b/libgomp/testsuite/libgomp.c/taskloop-1.c new file mode 100644 index 00000000000..21551f2950c --- /dev/null +++ b/libgomp/testsuite/libgomp.c/taskloop-1.c @@ -0,0 +1,46 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -fopenmp -std=c99" } */ + +int q, r, e; + +__attribute__((noinline, noclone)) void +foo (long a, long b) +{ + #pragma omp taskloop lastprivate (q) nogroup + for (long d = a; d < b; d += 2) + { + q = d; + if (d < 2 || d > 6 || (d & 1)) + #pragma omp atomic + e |= 1; + } +} + +__attribute__((noinline, noclone)) int +bar (int a, int b) +{ + int q = 7; + #pragma omp taskloop lastprivate (q) + for (int d = a; d < b; d++) + { + if (d < 12 || d > 17) + #pragma omp atomic + e |= 1; + q = d; + } + return q; +} + +int +main () +{ + #pragma omp parallel + #pragma omp single + { + foo (2, 7); + r = bar (12, 18); + } + if (q != 6 || r != 17 || e) + __builtin_abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/taskloop-2.c b/libgomp/testsuite/libgomp.c/taskloop-2.c new file mode 100644 index 00000000000..be893ebf80a --- /dev/null +++ b/libgomp/testsuite/libgomp.c/taskloop-2.c @@ -0,0 +1,147 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -std=c99" } */ +/* { dg-additional-options "-msse2" { target sse2_runtime } } */ +/* { dg-additional-options "-mavx" { target avx_runtime } } */ + +int u[1024], v[1024], w[1024], m; + +__attribute__((noinline, noclone)) void +f1 (long a, long b) +{ + #pragma omp taskloop simd default(none) shared(u, v, w) nogroup + for (long d = a; d < b; d++) + u[d] = v[d] + w[d]; +} + +__attribute__((noinline, noclone)) int +f2 (long a, long b, long c) +{ + int d, e; + #pragma omp taskloop simd default(none) shared(u, v, w) linear(d:1) linear(c:5) lastprivate(e) + for (d = a; d < b; d++) + { + u[d] = v[d] + w[d]; + c = c + 5; + e = c + 9; + } + return d + c + e; +} + +__attribute__((noinline, noclone)) int +f3 (long a, long b) +{ + int d; + #pragma omp taskloop simd default(none) shared(u, v, w) + for (d = a; d < b; d++) + { + int *p = &d; + u[d] = v[d] + w[d]; + } + return d; +} + +__attribute__((noinline, noclone)) int +f4 (long a, long b, long c, long d) +{ + int e, f, g; + #pragma omp taskloop simd default(none) shared(u, v, w) collapse(2) lastprivate(g) + for (e = a; e < b; e++) + for (f = c; f < d; f++) + { + int *p = &e; + int *q = &f; + int r = 32 * e + f; + u[r] = v[r] + w[r]; + g = r; + } + return e + f + g; +} + +__attribute__((noinline, noclone)) int +f5 (long a, long b, long c, long d) +{ + int e, f; + #pragma omp taskloop simd default(none) shared(u, v, w) collapse(2) + for (e = a; e < b; e++) + for (f = c; f < d; f++) + { + int r = 32 * e + f; + u[r] = v[r] + w[r]; + } + return e + f; +} + +int +main () +{ + int i; + for (i = 0; i < 1024; i++) + { + v[i] = i; + w[i] = i + 1; + } + #pragma omp parallel + #pragma omp single + f1 (0, 1024); + for (i = 0; i < 1024; i++) + if (u[i] != 2 * i + 1) + __builtin_abort (); + else + { + v[i] = 1024 - i; + w[i] = 512 - i; + } + #pragma omp parallel + #pragma omp single + m = f2 (2, 1022, 17); + for (i = 0; i < 1024; i++) + if ((i < 2 || i >= 1022) ? u[i] != 2 * i + 1 : u[i] != 1536 - 2 * i) + __builtin_abort (); + else + { + v[i] = i; + w[i] = i + 1; + } + if (m != 1022 + 2 * (1020 * 5 + 17) + 9) + __builtin_abort (); + #pragma omp parallel + #pragma omp single + m = f3 (0, 1024); + for (i = 0; i < 1024; i++) + if (u[i] != 2 * i + 1) + __builtin_abort (); + else + { + v[i] = 1024 - i; + w[i] = 512 - i; + } + if (m != 1024) + __builtin_abort (); + #pragma omp parallel + #pragma omp single + m = f4 (0, 32, 0, 32); + for (i = 0; i < 1024; i++) + if (u[i] != 1536 - 2 * i) + __builtin_abort (); + else + { + v[i] = i; + w[i] = i + 1; + } + if (m != 32 + 32 + 1023) + __builtin_abort (); + #pragma omp parallel + #pragma omp single + m = f5 (0, 32, 0, 32); + for (i = 0; i < 1024; i++) + if (u[i] != 2 * i + 1) + __builtin_abort (); + else + { + v[i] = 1024 - i; + w[i] = 512 - i; + } + if (m != 32 + 32) + __builtin_abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/taskloop-3.c b/libgomp/testsuite/libgomp.c/taskloop-3.c new file mode 100644 index 00000000000..5356d7f0251 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/taskloop-3.c @@ -0,0 +1,84 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -fopenmp -std=c99" } */ + +int g; +int a[1024]; + +__attribute__((noinline, noclone)) int +f1 (int x) +{ + #pragma omp taskloop firstprivate (x) lastprivate (x) + for (int i = 0; i < 64; i++) + { + if (x != 74) + __builtin_abort (); + if (i == 63) + x = i + 4; + } + return x; +} + +__attribute__((noinline, noclone)) void +f2 (void) +{ + #pragma omp taskloop firstprivate (g) lastprivate (g) nogroup + for (int i = 0; i < 64; i++) + { + if (g != 77) + __builtin_abort (); + if (i == 63) + g = i + 9; + } +} + +__attribute__((noinline, noclone)) long long +f3 (long long a, long long b, long long c) +{ + long long i; + int l; + #pragma omp taskloop default (none) lastprivate (i, l) + for (i = a; i < b; i += c) + l = i; + return l * 7 + i; +} + +__attribute__((noinline, noclone)) long long +f4 (long long a, long long b, long long c, long long d, + long long e, long long f, int k) +{ + long long i, j; + int l; + #pragma omp taskloop default (none) collapse(2) \ + firstprivate (k) lastprivate (i, j, k, l) + for (i = a; i < b; i += e) + for (j = c; j < d; j += f) + { + if (k != 73) + __builtin_abort (); + if (i == 31 && j == 46) + k = i; + l = j; + } + return i + 5 * j + 11 * k + 17 * l; +} + +int +main () +{ + #pragma omp parallel + #pragma omp single + { + if (f1 (74) != 63 + 4) + __builtin_abort (); + g = 77; + f2 (); + #pragma omp taskwait + if (g != 63 + 9) + __builtin_abort (); + if (f3 (7, 12, 2) != 11 * 7 + 13) + __builtin_abort (); + if (f4 (0, 32, 16, 48, 1, 2, 73) != 32 + 5 * 48 + 11 * 31 + 17 * 46) + __builtin_abort (); + } + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/taskloop-4.c b/libgomp/testsuite/libgomp.c/taskloop-4.c new file mode 100644 index 00000000000..a69be19c9c2 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/taskloop-4.c @@ -0,0 +1,97 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -fopenmp" } */ + +int u[64], v; + +__attribute__((noinline, noclone)) int +test (int a, int b, int c, int d, void (*fn) (int, int, int, int), + int *num_tasks, int *min_iters, int *max_iters) +{ + int i, t = 0; + __builtin_memset (u, 0, sizeof u); + v = 0; + fn (a, b, c, d); + *min_iters = 0; + *max_iters = 0; + *num_tasks = v; + if (v) + { + *min_iters = u[0]; + *max_iters = u[0]; + t = u[0]; + for (i = 1; i < v; i++) + { + if (*min_iters > u[i]) + *min_iters = u[i]; + if (*max_iters < u[i]) + *max_iters = u[i]; + t += u[i]; + } + } + return t; +} + +void +grainsize (int a, int b, int c, int d) +{ + int i, j = 0, k = 0; + #pragma omp taskloop firstprivate (j, k) grainsize(d) + for (i = a; i < b; i += c) + { + if (j == 0) + { + #pragma omp atomic capture + k = v++; + if (k >= 64) + __builtin_abort (); + } + u[k] = ++j; + } +} + +void +num_tasks (int a, int b, int c, int d) +{ + int i, j = 0, k = 0; + #pragma omp taskloop firstprivate (j, k) num_tasks(d) + for (i = a; i < b; i += c) + { + if (j == 0) + { + #pragma omp atomic capture + k = v++; + if (k >= 64) + __builtin_abort (); + } + u[k] = ++j; + } +} + +int +main () +{ + #pragma omp parallel + #pragma omp single + { + int min_iters, max_iters, ntasks; + /* If grainsize is present, # of task loop iters is >= grainsize && < 2 * grainsize, + unless # of loop iterations is smaller than grainsize. */ + if (test (0, 79, 1, 17, grainsize, &ntasks, &min_iters, &max_iters) != 79 + || min_iters < 17 || max_iters >= 17 * 2) + __builtin_abort (); + if (test (-49, 2541, 7, 28, grainsize, &ntasks, &min_iters, &max_iters) != 370 + || min_iters < 28 || max_iters >= 28 * 2) + __builtin_abort (); + if (test (7, 21, 2, 15, grainsize, &ntasks, &min_iters, &max_iters) != 7 + || ntasks != 1 || min_iters != 7 || max_iters != 7) + __builtin_abort (); + /* If num_tasks is present, # of task loop iters is min (# of loop iters, num_tasks). */ + if (test (-51, 2500, 48, 9, num_tasks, &ntasks, &min_iters, &max_iters) != 54 + || ntasks != 9) + __builtin_abort (); + if (test (0, 25, 2, 17, num_tasks, &ntasks, &min_iters, &max_iters) != 13 + || ntasks != 13) + __builtin_abort (); + } + return 0; +} diff --git a/libgomp/testsuite/libgomp.fortran/affinity1.f90 b/libgomp/testsuite/libgomp.fortran/affinity1.f90 new file mode 100644 index 00000000000..26b5185ba3c --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/affinity1.f90 @@ -0,0 +1,49 @@ +! { dg-do run } +! { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O2" } } +! { dg-set-target-env-var OMP_PROC_BIND "spread,close" } +! { dg-set-target-env-var OMP_PLACES "{6,7}:4:-2,!{2,3}" } +! { dg-set-target-env-var OMP_NUM_THREADS "2" } + + use omp_lib + integer :: num, i, nump + num = omp_get_num_places () + print *, 'omp_get_num_places () == ', num + do i = 0, num - 1 + nump = omp_get_place_num_procs (place_num = i) + if (nump .eq. 0) then + print *, 'place ', i, ' {}' + else + call print_place (i, nump) + end if + end do + call print_place_var + call omp_set_nested (nested = .true.) + !$omp parallel + if (omp_get_thread_num () == omp_get_num_threads () - 1) then + !$omp parallel + if (omp_get_thread_num () == omp_get_num_threads () - 1) & + call print_place_var + !$omp end parallel + end if + !$omp end parallel +contains + subroutine print_place (i, nump) + integer, intent (in) :: i, nump + integer :: ids(nump) + call omp_get_place_proc_ids (place_num = i, ids = ids) + print *, 'place ', i, ' {', ids, '}' + end subroutine + subroutine print_place_var + integer :: place, num_places + place = omp_get_place_num () + num_places = omp_get_partition_num_places () + print *, 'place ', place + if (num_places .gt. 0) call print_partition (num_places) + end subroutine + subroutine print_partition (num_places) + integer, intent (in) :: num_places + integer :: place_nums(num_places) + call omp_get_partition_place_nums (place_nums = place_nums) + print *, 'partition ', place_nums(1), '-', place_nums(num_places) + end subroutine +end diff --git a/libgomp/testsuite/libgomp.fortran/affinity2.f90 b/libgomp/testsuite/libgomp.fortran/affinity2.f90 new file mode 100644 index 00000000000..338f0e8bb93 --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/affinity2.f90 @@ -0,0 +1,8 @@ +! { dg-do run } +! { dg-additional-options "-fdefault-integer-8" } +! { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O2" } } +! { dg-set-target-env-var OMP_PROC_BIND "spread,close" } +! { dg-set-target-env-var OMP_PLACES "{6,7}:4:-2,!{2,3}" } +! { dg-set-target-env-var OMP_NUM_THREADS "2" } + +include 'affinity1.f90' diff --git a/liboffloadmic/ChangeLog b/liboffloadmic/ChangeLog index d25d4184121..82e7999188c 100644 --- a/liboffloadmic/ChangeLog +++ b/liboffloadmic/ChangeLog @@ -1,3 +1,10 @@ +2015-10-13 Ilya Verbin + + * plugin/libgomp-plugin-intelmic.cpp (GOMP_OFFLOAD_dev2dev): New + function. + * plugin/offload_target_main.cpp (__offload_target_tgt2tgt): New + static function, register it in liboffloadmic. + 2015-10-08 Ilya Verbin * runtime/offload_engine.cpp (Engine::init_process): Use strdup instead diff --git a/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp b/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp index 9ebd070e0f5..26ac6fed982 100644 --- a/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp +++ b/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp @@ -477,6 +477,29 @@ GOMP_OFFLOAD_dev2host (int device, void *host_ptr, const void *tgt_ptr, return host_ptr; } +extern "C" void * +GOMP_OFFLOAD_dev2dev (int device, void *dst_ptr, const void *src_ptr, + size_t size) +{ + TRACE ("(dst_ptr = %p, src_ptr = %p, size = %d)", dst_ptr, src_ptr, size); + if (!size) + return dst_ptr; + + VarDesc vd1[3] = { vd_host2tgt, vd_host2tgt, vd_host2tgt }; + vd1[0].ptr = &dst_ptr; + vd1[0].size = sizeof (void *); + vd1[1].ptr = &src_ptr; + vd1[1].size = sizeof (void *); + vd1[2].ptr = &size; + vd1[2].size = sizeof (size); + VarDesc2 vd1g[3] = { { "dst_ptr", 0 }, { "src_ptr", 0 }, { "size", 0 } }; + + offload (__FILE__, __LINE__, device, "__offload_target_tgt2tgt", 3, vd1, + vd1g); + + return dst_ptr; +} + extern "C" void GOMP_OFFLOAD_run (int device, void *tgt_fn, void *tgt_vars) { diff --git a/liboffloadmic/plugin/offload_target_main.cpp b/liboffloadmic/plugin/offload_target_main.cpp index 3fead0190cb..18b014641b6 100644 --- a/liboffloadmic/plugin/offload_target_main.cpp +++ b/liboffloadmic/plugin/offload_target_main.cpp @@ -299,6 +299,29 @@ __offload_target_tgt2host_p2 (OFFLOAD ofldt) __offload_target_leave (ofldt); } +/* Copy SIZE bytes from SRC_PTR to DST_PTR. */ +static void +__offload_target_tgt2tgt (OFFLOAD ofldt) +{ + void *src_ptr = NULL; + void *dst_ptr = NULL; + size_t size = 0; + + VarDesc vd1[3] = { vd_host2tgt, vd_host2tgt, vd_host2tgt }; + vd1[0].ptr = &dst_ptr; + vd1[0].size = sizeof (void *); + vd1[1].ptr = &src_ptr; + vd1[1].size = sizeof (void *); + vd1[2].ptr = &size; + vd1[2].size = sizeof (size); + VarDesc2 vd1g[3] = { { "dst_ptr", 0 }, { "src_ptr", 0 }, { "size", 0 } }; + + __offload_target_enter (ofldt, 3, vd1, vd1g); + TRACE ("(dst_ptr = %p, src_ptr = %p, size = %d)", dst_ptr, src_ptr, size); + memcpy (dst_ptr, src_ptr, size); + __offload_target_leave (ofldt); +} + /* Call offload function by the address fn_ptr and pass vars_ptr to it. */ static void __offload_target_run (OFFLOAD ofldt) @@ -363,5 +386,6 @@ REGISTER (host2tgt_p1); REGISTER (host2tgt_p2); REGISTER (tgt2host_p1); REGISTER (tgt2host_p2); +REGISTER (tgt2tgt); REGISTER (run); #undef REGISTER -- 2.30.2