diff options
Diffstat (limited to 'gcc')
119 files changed, 14114 insertions, 1124 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4711947..750c73a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,378 @@ +2015-10-13 Jakub Jelinek <jakub@redhat.com> + Aldy Hernandez <aldyh@redhat.com> + Ilya Verbin <ilya.verbin@intel.com> + + * 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 <gomp_ordered *>::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 <ubizjak@gmail.com> * config/i386/i386.c (classify_argument): Use CEIL where applicable. diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 137cdfe..9effe45 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,8 @@ +2015-10-13 Jakub Jelinek <jakub@redhat.com> + + * gcc-interface/utils.c (DEF_FUNCTION_TYPE_9, DEF_FUNCTION_TYPE_10, + DEF_FUNCTION_TYPE_11): Define. + 2015-10-09 Eric Botcazou <ebotcazou@adacore.com> * 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 0f3087d..917c280 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 9d20dcc..b561436 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 5af62aa..4521a27 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,31 @@ +2015-10-13 Jakub Jelinek <jakub@redhat.com> + Aldy Hernandez <aldyh@redhat.com> + + * 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 <richard.sandiford@arm.com> * 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 4b64a44..1c75921 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 d5fb4998..cf44482 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 e109e82..35d246b 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 cdd2ee8..36f9b66 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 %<parallel%> or %<target%> %<if%> " + "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 3c34800..834a916 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 f6e1090..cec920f 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 f87a29a..a54921a 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,85 @@ +2015-10-13 Jakub Jelinek <jakub@redhat.com> + Aldy Hernandez <aldyh@redhat.com> + + * 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 <polacek@redhat.com> * c-parser.c (c_parser_statement_after_labels): Use diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 2d24c21..704ebc6 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 %<data%>, %<update%>, %<enter%> " + "or %<exit%>"); + 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 %<data%>"); + 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 %<if%> clauses with %qs modifier", + p); + return list; + } + else if (OMP_CLAUSE_IF_MODIFIER (c) == if_modifier) + { + if (!is_omp) + error_at (location, "too many %<if%> clauses"); + else + error_at (location, "too many %<if%> clauses without modifier"); + return list; + } + else if (if_modifier == ERROR_MARK + || OMP_CLAUSE_IF_MODIFIER (c) == ERROR_MARK) + { + error_at (location, "if any %<if%> clause has modifier, then all " + "%<if%> 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, "%<num_tasks%> 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, "%<grainsize%> 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, "%<priority%> 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 %<tofrom%>"); + goto out_err; + } + p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "tofrom") != 0) + { + c_parser_error (parser, "expected %<tofrom%>"); + 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 %<scalar%>"); + goto out_err; + } + p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "scalar") != 0) + { + c_parser_error (parser, "expected %<scalar%>"); + 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) @@ -10989,6 +11437,19 @@ c_parser_omp_clause_schedule (c_parser *parser, tree list) { 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; + const char *p = IDENTIFIER_POINTER (kind); switch (p[0]) { @@ -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<tree, va_gc> *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)); + } - gcc_assert (collapse >= 1); + if (ordered && ordered < collapse) + { + error_at (OMP_CLAUSE_LOCATION (ordered_cl), + "%<ordered%> clause parameter is less than %<collapse%>"); + 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), + "%<linear%> clause may not be specified together " + "with %<ordered%> clause with a parameter"); + *pc = OMP_CLAUSE_CHAIN (*pc); + } + else + pc = &OMP_CLAUSE_CHAIN (*pc); + } + + 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), + "%<ordered%> 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 -static tree -c_parser_omp_ordered (location_t loc, c_parser *parser) + # 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) { - c_parser_skip_to_pragma_eol (parser); - return c_finish_omp_ordered (loc, c_parser_omp_structured_block (parser)); + 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 %<depend> 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; + } + } + + 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 %<for%> 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 %<to%>, %<from%>, %<tofrom%> or %<alloc%> " + "on %<map%> 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 %<map%> 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 %<data%>"); + 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 %<to%> or %<alloc%> on %<map%> 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 %<map%> 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 %<data%>"); + 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 %<from%>, %<release> or %<delete%> on %<map%>" + " 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 " + "%<map%> 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 %<to%>, %<from%>, %<tofrom%> or %<alloc%> " + "on %<map%> 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 %<link%> and %<to%>" + " 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 667529a..bee03d3 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 df3245a4..bc43602 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<tree> &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<tree> &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<tree> &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), + "%<reduction%> 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<tree> &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<tree> &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<tree> &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<tree> &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<tree> &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<tree> types = vNULL; + auto_vec<tree, 10> 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 %<reduction%> 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 %<reduction%> 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 " + "%<reduction%> 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 %<linear%> " + "clause on %<simd%> or %<for%> 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, @@ -12468,7 +12789,10 @@ c_finish_omp_clauses (tree clauses) 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), + "%<simdlen%> clause value is bigger than " + "%<safelen%> 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 607aef7..7c54f24 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 7b3df54..3439c38 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 517ce52..b5951af 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,150 @@ +2015-10-13 Jakub Jelinek <jakub@redhat.com> + Aldy Hernandez <aldyh@redhat.com> + + * 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 <ville.voutilainen@gmail.com> PR c++/58566 diff --git a/gcc/cp/class.c b/gcc/cp/class.c index ef537be..685b7b3 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 9b6ac89..e37cbc7 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 %<firstprivate%> 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 c8572a7..199c3f1 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 f650c76..16db41f 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<tree> &); +extern void restore_omp_privatization_clauses (vec<tree> &); 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 d4ef7f9..435757d 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<tree> 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 %<data%>, %<update%>, %<enter%> " + "or %<exit%>"); + 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 %<data%>"); + 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 %<if%> clauses with %qs modifier", + p); + return list; + } + else if (OMP_CLAUSE_IF_MODIFIER (c) == if_modifier) + { + if (!is_omp) + error_at (location, "too many %<if%> clauses"); + else + error_at (location, "too many %<if%> clauses without modifier"); + return list; + } + else if (if_modifier == ERROR_MARK + || OMP_CLAUSE_IF_MODIFIER (c) == ERROR_MARK) + { + error_at (location, "if any %<if%> clause has modifier, then all " + "%<if%> 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 %<tofrom%>"); + 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 %<tofrom%>"); + 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 %<scalar%>"); + 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 %<scalar%>"); + 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) @@ -30063,6 +30459,19 @@ cp_parser_omp_clause_schedule (cp_parser *parser, tree list, location_t location { 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; + const char *p = IDENTIFIER_POINTER (id); switch (p[0]) { @@ -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; } @@ -30374,14 +30849,104 @@ cp_parser_omp_clause_simdlen (cp_parser *parser, tree 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; + } + + if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)) + break; + + 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<tree, va_gc> *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), + "%<ordered%> clause parameter is less than %<collapse%>"); + 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), + "%<linear%> clause may not be specified together " + "with %<ordered%> 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), + "%<ordered%> 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 " + "%<depend%> 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 %<for%> 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) @@ -32851,17 +33706,57 @@ cp_parser_omp_teams (cp_parser *parser, cp_token *pragma_tok, #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 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 %<to%>, %<from%>, %<tofrom%> or %<alloc%> " + "on %<map%> 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 %<map%> clause"); + return NULL_TREE; + } + tree stmt = make_node (OMP_TARGET_DATA); TREE_TYPE (stmt) = void_type_node; + OMP_TARGET_DATA_CLAUSES (stmt) = clauses; - 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); @@ -32869,6 +33764,180 @@ cp_parser_omp_target_data (cp_parser *parser, cp_token *pragma_tok) return add_stmt (stmt); } +/* OpenMP 4.5: + # pragma omp target enter data target-enter-data-clause[optseq] new-line + structured-block */ + +#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, "data") == 0) + { + cp_lexer_consume_token (parser->lexer); + data_seen = true; + } + } + if (!data_seen) + { + cp_parser_error (parser, "expected %<data%>"); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return NULL_TREE; + } + + if (context == pragma_stmt) + { + 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 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 %<to%> or %<alloc%> on %<map%> 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 %<map%> 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.5: + # pragma omp target exit data target-enter-data-clause[optseq] new-line + structured-block */ + +#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 +cp_parser_omp_target_exit_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, "data") == 0) + { + cp_lexer_consume_token (parser->lexer); + data_seen = true; + } + } + if (!data_seen) + { + cp_parser_error (parser, "expected %<data%>"); + 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 %<from%>, %<release%> or %<delete%> on %<map%>" + " 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 %<map%> 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); +} + /* OpenMP 4.0: # pragma omp target update target-update-clause[optseq] new-line */ @@ -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 %<to%>, %<from%>, %<tofrom%> or %<alloc%> " + "on %<map%> 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 %<link%> and %<to%>" + " 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 6926557..14a5ddd 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<tree> 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 c1f4330..8796b17 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<tree, tree> *omp_private_member_map; +static vec<tree> 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, tree>; + 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<tree, tree>; + 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<tree> &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<tree> &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), + "%<this%> allowed in OpenMP only in %<declare simd%>" + " 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<tree> &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<tree> &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), + "%<reduction%> 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<tree> &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<tree> &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<tree> &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<tree> &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<tree> &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<tree> types; + auto_vec<tree, 10> 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 %<reduction%> 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 %<reduction%>", t); + error ("%qE has const type for %<reduction%>", + 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 %<linear%> " + "clause on %<simd%> or %<for%> 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 ("%<this%> allowed in OpenMP only in %<declare simd%>" + " 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 ("%<this%> allowed in OpenMP only in %<declare simd%>" + " 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 ("%<this%> allowed in OpenMP only in %<declare simd%>" + " 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, + "%<num_threads%> 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, + "%<num_teams%> 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, + "%<thread_limit%> 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 ("%<this%> allowed in OpenMP only in %<declare simd%>" + " 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 %<depend%> clause", t); remove = true; } + else if (t == current_class_ptr) + { + error ("%<this%> allowed in OpenMP only in %<declare simd%>" + " 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 ("%<this%> allowed in OpenMP only in %<declare simd%>" + " 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 ("%<num_tasks%> 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, + "%<num_tasks%> 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 ("%<grainsize%> 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, + "%<grainsize%> 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 ("%<priority%> 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, + "%<priority%> 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 ("%<num_tasks%> 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), + "%<simdlen%> clause value is bigger than " + "%<safelen%> 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<tree> &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<tree> &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 <tree, tree>; + 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 8d21be5..4bd3577 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,27 @@ +2015-10-13 Jakub Jelinek <jakub@redhat.com> + Ilya Verbin <ilya.verbin@intel.com> + + * 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 <vehre@gcc.gnu.org> PR fortran/65889 diff --git a/gcc/fortran/f95-lang.c b/gcc/fortran/f95-lang.c index 0bcfb3f..67b0bac 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 294b6ef..b6284c9 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 c460b59..ca75654 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 f1a7e79..9780220 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 <gomp_ordered *> (gs), spc, + flags); + break; + case GIMPLE_OMP_CRITICAL: dump_gimple_omp_critical (buffer, as_a <gomp_critical *> (gs), spc, flags); diff --git a/gcc/gimple-walk.c b/gcc/gimple-walk.c index e62cf62..b045c67 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 <gomp_ordered *> (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 c3762e1..5312d6e 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 <gomp_critical *> (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 <gomp_ordered *> (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 <gomp_critical *> (stmt))); + t = unshare_expr (gimple_omp_critical_name + (as_a <gomp_critical *> (stmt))); gimple_omp_critical_set_name (as_a <gomp_critical *> (copy), t); + t = unshare_expr (gimple_omp_critical_clauses + (as_a <gomp_critical *> (stmt))); + gimple_omp_critical_set_clauses (as_a <gomp_critical *> (copy), t); + goto copy_omp_body; + + case GIMPLE_OMP_ORDERED: + t = unshare_expr (gimple_omp_ordered_clauses + (as_a <gomp_ordered *> (stmt))); + gimple_omp_ordered_set_clauses (as_a <gomp_ordered *> (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 96602df..d3ca402 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 <BODY> 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 <BODY, CLAUSES, CHILD_FN, DATA_ARG> 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 <BODY, CLAUSES> 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 <PREDICT, OUTCOME> 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 a456f54..02d0db5 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 @@ -1074,6 +1088,14 @@ is_a_helper <gomp_critical *>::test (gimple *gs) template <> template <> inline bool +is_a_helper <gomp_ordered *>::test (gimple *gs) +{ + return gs->code == GIMPLE_OMP_ORDERED; +} + +template <> +template <> +inline bool is_a_helper <gomp_for *>::test (gimple *gs) { return gs->code == GIMPLE_OMP_FOR; @@ -1282,6 +1304,14 @@ is_a_helper <const gomp_critical *>::test (const gimple *gs) template <> template <> inline bool +is_a_helper <const gomp_ordered *>::test (const gimple *gs) +{ + return gs->code == GIMPLE_OMP_ORDERED; +} + +template <> +template <> +inline bool is_a_helper <const gomp_for *>::test (const gimple *gs) { return gs->code == GIMPLE_OMP_FOR; @@ -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 25a81f6..4a9f7fd 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<tree> *privatized_types; + /* Iteration variables in an OMP_FOR. */ + vec<tree> 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<tree, tree> *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) { @@ -6152,6 +6284,12 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, (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 && splay_tree_lookup (outer_ctx->variables, @@ -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), + "%<linear%> clause for variable other than " + "loop iterator specified on construct " + "combined with %<distribute%>"); + 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, tree>; + 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<tree, tree>; + 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 %<if%> 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), + "%<depend%> clause must be closely nested " + "inside a loop with %<ordered%> 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 %<depend(sink)%> " + "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 %<depend(source)%> clause on an " + "%<ordered%> construct"); + failures++; + } + else + source_c = c; + } + if (source_c && sink_c) + { + error_at (OMP_CLAUSE_LOCATION (source_c), + "%<depend(source)%> clause specified together with " + "%<depend(sink:)%> 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 71f811c..f12d3af 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 ba5c2c1..305cf1b 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 05fa9e6..4922bc0 100644 --- a/gcc/jit/ChangeLog +++ b/gcc/jit/ChangeLog @@ -1,3 +1,10 @@ +2015-10-13 Jakub Jelinek <jakub@redhat.com> + + * 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 <thomas@codesourcery.com> Ulrich Drepper <drepper@gmail.com> diff --git a/gcc/jit/jit-builtins.c b/gcc/jit/jit-builtins.c index 4ef80ed..e67c0f8 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 3d76247..97e279e 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 e75b4ea..79cd853 100644 --- a/gcc/lto/ChangeLog +++ b/gcc/lto/ChangeLog @@ -1,3 +1,8 @@ +2015-10-13 Jakub Jelinek <jakub@redhat.com> + + * lto-lang.c (DEF_FUNCTION_TYPE_9, DEF_FUNCTION_TYPE_10, + DEF_FUNCTION_TYPE_11): Define. + 2015-10-10 Jan Hubicka <hubicka@ucw.cz> * lto.c (hash_canonical_type): Honor diff --git a/gcc/lto/lto-lang.c b/gcc/lto/lto-lang.c index 67ccf57..94b54dc 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 d09bdb6..ea9cf0d 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 7e894e4..b444864 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<tree, va_gc> *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,24 +1081,35 @@ 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) { splay_tree_node n; @@ -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 <gomp_for *> ((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 <gomp_for *> ((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 <gomp_ordered *> (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), + "%<depend(%s)%> is only allowed in %<omp ordered%>", + kind == OMP_CLAUSE_DEPEND_SOURCE ? "source" : "sink"); + return false; + } + break; case GIMPLE_OMP_ORDERED: + for (c = gimple_omp_ordered_clauses (as_a <gomp_ordered *> (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), + "%<depend%> 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), + "%<depend%> clause must be closely nested " + "inside a loop with %<ordered%> 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), + "%<depend(%s)%> is only allowed in %<omp ordered%>", + 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,6 +4258,236 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, if (pass != 0) continue; } + /* C/C++ array section reductions. */ + else if (c_kind == OMP_CLAUSE_REDUCTION + && var != OMP_CLAUSE_DECL (c)) + { + if (pass == 0) + continue; + + 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)) + { + 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 @@ -3768,8 +4508,9 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, 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 <gomp_for *> (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 <gomp_parallel *> (entry_stmt), ws_args); else - expand_task_call (new_bb, as_a <gomp_task *> (entry_stmt)); + expand_task_call (region, new_bb, as_a <gomp_task *> (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,6 +7076,386 @@ extract_omp_for_update_vars (struct omp_for_data *fd, basic_block cont_bb, } +/* Expand #pragma omp ordered depend(source). */ + +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); +} + +/* Expand a single depend from #pragma omp ordered depend(sink:...). */ + +static void +expand_omp_ordered_sink (gimple_stmt_iterator *gsi, struct omp_for_data *fd, + tree *counts, tree c, location_t loc) +{ + auto_vec<tree, 10> 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 (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, "%<depend(sink)%> 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; */ + + 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); + + *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, "%<depend(sink)%> 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: @@ -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<constructor_elt, va_gc> *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,11 +7898,29 @@ 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); + 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); + } iend = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, false, GSI_CONTINUE_LINKING); if (endvar) @@ -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, @@ -7984,6 +9815,400 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) 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 <gomp_continue *> (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; + } + else if (fd->collapse > 1) + { + 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; + } + + 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 <gomp_ordered *> (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 <gomp_ordered *> (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 <gomp_for *> (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 <gomp_ordered *> (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 <gomp_ordered *> (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 <gomp_for *> (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) { - struct omp_for_data outer_fd; - extract_omp_for_data (gfor, &outer_fd, NULL); - n2 = fold_convert (TREE_TYPE (n2), outer_fd.loop.n2); + gomp_for *gfor = as_a <gomp_for *> (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) + { + 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 <gomp_target *> (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<tree> *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<tree, 10> 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 <gomp_atomic_load *> (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 <gomp_ordered *> (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 4730815..2fb2028 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<tree, va_gc> *offload_funcs; diff --git a/gcc/passes.def b/gcc/passes.def index 28dea9e..dc3f44c 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 e8ead84..c4fd225 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,78 @@ +2015-10-13 Jakub Jelinek <jakub@redhat.com> + Aldy Hernandez <aldyh@redhat.com> + + * 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 <christophe.lyon@linaro.org> * 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 82c0a0c..ed85a7a 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 6986c55..ef283d4 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 411fb5f..ac614e7 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 d8f7bc1..13de881 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 0000000..2d1c352 --- /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 0000000..6e136ba --- /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 0000000..7e07a81 --- /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 0000000..104b129 --- /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 0000000..a1f1ea7 --- /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 0000000..b9313d8 --- /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 0000000..22fcd8d --- /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 0000000..d40b1fa --- /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 0000000..89c3dd3 --- /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 0000000..4ba708c --- /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 0000000..f1f417e --- /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 0000000..4557e22 --- /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 0000000..101f404 --- /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 0000000..8a14b9c --- /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 711ff8e..61b2f81 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 c39dd49..92ced70 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 0000000..1102259 --- /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 0000000..9644297 --- /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 0000000..1d7ff80 --- /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 9ada58c..dbd621f 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 5533271..804a827 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 0000000..e2eebf9 --- /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 0000000..23e79d9 --- /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 0000000..e6a7bb9 --- /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 0000000..4872a07 --- /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 0000000..e781a6f --- /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 0000000..7cb16ed --- /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 0000000..11b6d99 --- /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 0000000..7c50ff6 --- /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 0000000..f5c3a5d --- /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 76683ec..76ee497 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 1a20440..54f7957 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 0000000..5a444e5 --- /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 0000000..68d58fe --- /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 0000000..cf32b09 --- /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 <typename T> +struct U { U () {}; virtual ~U () {}; T t; }; +template <typename T> +struct V : virtual public U<T> { 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 <typename T> +void +V<T>::foo () +{ +#pragma omp parallel firstprivate (a, U<T>::t) + { + int *q1 = &a; + int *q2 = &this->a; + int q3 = a; + int q4 = this->a; + int *q5 = &(U<T>::t); + int *q6 = &this->U<T>::t; + int q7 = U<T>::t; + int q8 = this->U<T>::t; + int q9 = U<T>::t; + int q10 = this->U<T>::t; + int &q11 = a; + int &q12 = this->a; + int &q13 = U<T>::t; + int &q14 = this->U<T>::t; + int &q15 = V::a; + int &q16 = this->V::a; + int &q17 = U<T>::t; + int &q18 = this->U<T>::t; + } +#pragma omp parallel private (a, U<T>::t) + { + a = 7; + V::a += 9; + U<T>::t = 10; + U<T>::t += 11; + } +#pragma omp parallel + { + #pragma omp sections lastprivate (V::a, U<T>::t) + { + #pragma omp section + { + V::a = 6; + U<T>::t = 8; + } + } + } +#pragma omp parallel + { + #pragma omp for firstprivate (a, U<T>::t) lastprivate (a, U<T>::t) + for (int i = 0; i < 10; i++) + { + int q19 = a + U<T>::t; + if (i == 9) + { + a = i; + U<T>::t = i + 2; + } + } + } +#pragma omp sections lastprivate (a, U<T>::t) + { + #pragma omp section + { + a = 5; + U<T>::t = 6; + } + } +#pragma omp for firstprivate (a, U<T>::t) lastprivate (a, U<T>::t) + for (int i = 0; i < 10; i++) + { + int q20 = a + U<T>::t; + if (i == 9) + { + a = i; + U<T>::t = i + 2; + } + } +#pragma omp parallel sections lastprivate (a, U<T>::t) + { + #pragma omp section + { + a = 5; + U<T>::t = 6; + } + } +#pragma omp parallel + { + #pragma omp task firstprivate (a, U<T>::t) + { + V::a++; + U<T>::t++; + } + } +#pragma omp parallel + { + #pragma omp taskloop firstprivate (a, U<T>::t) lastprivate (U<T>::t) + for (int i = 0; i < a; i++) + U<T>::t++; + } +#pragma omp taskloop firstprivate (a, U<T>::t) lastprivate (U<T>::t) + for (int i = 0; i < a; i++) + U<T>::t++; + a = 1; + U<T>::t = 0; +#pragma omp parallel sections reduction (*: V::a) reduction (+: U<T>::t) + { + { + a = 1; + U<T>::t = 2; + } + #pragma omp section + { + a = 2; + U<T>::t = 3; + } + #pragma omp section + { + a = 3; + U<T>::t = 4; + } + } +} + +void +bar () +{ + V<int> 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 0000000..97c03952 --- /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 0000000..ac4c609 --- /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 <typename T> +extern void bar (T, T, T, T); + +template <typename T> +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<T> (a, b, c, d), d += 2; + #pragma omp parallel private (c) + #pragma omp single copyprivate (c) + bar<T> (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<T> (e, f, g, h), h += 2; + #pragma omp parallel private (g) + #pragma omp single copyprivate (g) + bar<T> (e, f, g, h); +} + +void +baz () +{ + int a = 0, b = 0, c = 0, d = 0; + foo <int> (a, b, c, d); + foo <int &> (a, b, c, d); +} diff --git a/gcc/testsuite/g++.dg/gomp/pr67504.C b/gcc/testsuite/g++.dg/gomp/pr67504.C index 0f1758b..8270b7c 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 84c854a..da8cb74 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 0000000..d53ca93 --- /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 0000000..982d36c --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/sink-1.C @@ -0,0 +1,22 @@ +/* { dg-do compile } */ + +void bar (int, int, int); + +template<typename T> +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<int>(); +} 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 0000000..d1681a7 --- /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 <iostream> +#include <vector> + +/* Test plain iterator. */ +void foo1 () +{ + std::vector<int> v; + for (int i=1; i<=5; i++) v.push_back(i); + + std::vector<int>::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 <int N> +void foo2 () +{ + std::vector<int> v; + for (int i=1; i<=5; i++) v.push_back(i); + + std::vector<int>::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 <typename T> +void foo3 () +{ + std::vector<T> v; + for (int i=1; i<=5; i++) v.push_back(i); + + typename std::vector<T>::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 <int> (); +} 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 0000000..4271d66 --- /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<int N> +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 0000e6f..7f40279 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 0000000..0e2dd8c --- /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 <int N> +struct T +{ + #pragma omp declare simd linear(this) // { dg-error "is not an function argument" } + static void foo (); + void bar (); +}; + +template <int N> +void +T<N>::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 0000000..d03b8a0 --- /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 <int N> +struct T +{ + void bar (int); +}; + +template <int N> +void +T<N>::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 0000000..1a1b982 --- /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 0000000..d082330 --- /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 0000000..1057a7eb5 --- /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 0000000..32bdfd4 --- /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 0000000..2b0244c --- /dev/null +++ b/gcc/testsuite/g++.dg/vect/simd-clone-4.h @@ -0,0 +1,19 @@ +template <int N> +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 <int N> +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 0000000..07ec8a8 --- /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 N> +int +S<N>::f0 (int x) +{ + return x + s; +} + +#pragma omp declare simd notinbranch uniform(this) +template <int N> +int +S<N>::f1 (int x) +{ + return x + s; +} + +#pragma omp declare simd notinbranch linear(this:sizeof(this)/sizeof(this)) +template <int N> +int +S<N>::f2 (int x) +{ + return x + this->S::s; +} + +#pragma omp declare simd uniform(this) aligned(this:32) linear(x) +template <int N> +int +T<N>::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 fc7d72b..c2d1fc6 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 0000000..0aeb21e --- /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 0000000..d166dac --- /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 0000000..f3cdaee --- /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 0000000..d3af18e --- /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 0000000..675ac70 --- /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 1883fd7..6b17da7 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 9b525f3..b8269ef 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 <gomp_ordered *> (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 <gomp_critical *> (stmt))); + gimple_omp_critical_name + (as_a <gomp_critical *> (stmt)), + gimple_omp_critical_clauses + (as_a <gomp_critical *> (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 4af70e9..0f50933 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 ce3f6a8..11f90051 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 0073ddb..a5e1cb7 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 1e4b2a6..3e6fd35 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<simduid_to_vf> *htab) @@ -161,7 +162,7 @@ adjust_simduid_builtins (hash_table<simduid_to_vf> *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<simduid_to_vf> *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<simduid_to_vf> *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<simduid_to_vf> *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 @@ -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 56580af..64e0727 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. */ @@ -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 6e0275f..ff15679 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 <typename T1, typename T2> +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. */ |