+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.
+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
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,
#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
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) \
#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
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,
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,
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,
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)
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)
+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
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,
#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
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) \
#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
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);
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 *);
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])
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);
}
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);
}
/* 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
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;
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
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,
/* 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:
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)
{
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. */
}
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)
{
}
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))
{
/* 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
{
}
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)
= 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;
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)
{
= 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;
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
}
{ "parallel", PRAGMA_OMP_PARALLEL },
{ "simd", PRAGMA_OMP_SIMD },
{ "target", PRAGMA_OMP_TARGET },
+ { "taskloop", PRAGMA_OMP_TASKLOOP },
{ "teams", PRAGMA_OMP_TEAMS },
};
PRAGMA_OACC_PARALLEL,
PRAGMA_OACC_UPDATE,
PRAGMA_OACC_WAIT,
+
PRAGMA_OMP_ATOMIC,
PRAGMA_OMP_BARRIER,
PRAGMA_OMP_CANCEL,
PRAGMA_OMP_TARGET,
PRAGMA_OMP_TASK,
PRAGMA_OMP_TASKGROUP,
+ PRAGMA_OMP_TASKLOOP,
PRAGMA_OMP_TASKWAIT,
PRAGMA_OMP_TASKYIELD,
PRAGMA_OMP_THREADPRIVATE,
};
-/* 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,
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,
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,
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,
+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
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. */
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);
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;
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))
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))
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))
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))
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;
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))
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;
&& !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;
}
&& !TREE_READONLY (length))
{
error_at (clause_loc,
- "%qD is not a constant", length);
+ "%qD is not a constant", length);
t = error_mark_node;
}
}
}
/* 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:
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 ) */
}
/* 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;
}
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)
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)
c = build_omp_clause (loc, OMP_CLAUSE_SCHEDULE);
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ tree kind = c_parser_peek_token (parser)->value;
+ const char *p = IDENTIFIER_POINTER (kind);
+ if (strcmp ("simd", p) == 0
+ && c_parser_peek_2nd_token (parser)->type == CPP_COLON)
+ {
+ OMP_CLAUSE_SCHEDULE_SIMD (c) = 1;
+ c_parser_consume_token (parser);
+ c_parser_consume_token (parser);
+ }
+ }
+
if (c_parser_next_token_is (parser, CPP_NAME))
{
tree kind = c_parser_peek_token (parser)->value;
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 ) */
/* 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);
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 %<)%>");
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)
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;
}
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;
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)
{
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");
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);
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:
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;
}
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:
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";
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";
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:
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";
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;
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;
}
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);
# 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))
{
}
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:
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));
+ }
+
+ 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);
if (code != CILK_FOR
&& !c_parser_next_token_is_keyword (parser, RID_FOR))
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;
}
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
bracecount--;
}
fail = true;
- collapse = 0;
+ count = 0;
break;
}
}
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)
{
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)
{
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:
#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) \
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);
( (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) \
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))
{
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)
{
# pragma omp ordered new-line
structured-block
- LOC is the location of the #pragma itself.
-*/
+ OpenMP 4.5:
+ # pragma omp ordered ordered-clauses new-line
+ structured-block
+
+ # pragma omp ordered depend-clauses new-line */
+
+#define OMP_ORDERED_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREADS) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMD))
+
+#define OMP_ORDERED_DEPEND_CLAUSE_MASK \
+ (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)
+
+static bool
+c_parser_omp_ordered (c_parser *parser, enum pragma_context context)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_pragma (parser);
+
+ if (context != pragma_stmt && context != pragma_compound)
+ {
+ c_parser_error (parser, "expected declaration specifiers");
+ c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
+ return false;
+ }
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+ if (!strcmp ("depend", p))
+ {
+ if (context == pragma_stmt)
+ {
+ error_at (loc,
+ "%<#pragma omp ordered%> with %<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;
+ }
+ }
-static tree
-c_parser_omp_ordered (location_t loc, c_parser *parser)
-{
- c_parser_skip_to_pragma_eol (parser);
- return c_finish_omp_ordered (loc, c_parser_omp_structured_block (parser));
+ tree clauses = c_parser_omp_all_clauses (parser, OMP_ORDERED_CLAUSE_MASK,
+ "#pragma omp ordered");
+ c_finish_omp_ordered (loc, clauses,
+ c_parser_omp_structured_block (parser));
+ return true;
}
/* OpenMP 2.5:
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))
{
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);
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)
}
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);
| (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)
#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));
( (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,
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 */
#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)
{
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 "
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;
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 */
{
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);
}
}
- 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;
}
/* 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
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%>");
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
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);
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);
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 ();
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);
}
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);
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
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))
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;
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
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
}
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++;
}
}
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++;
}
"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
/* 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)
"array section is not contiguous in %qs "
"clause",
omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
- types.release ();
return true;
}
}
{
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);
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,
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);
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;
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)
{
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;
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:
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:
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);
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))
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,
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;
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)
{
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),
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;
}
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
{
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,
remove = true;
else if (!(OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
&& (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER
+ || (OMP_CLAUSE_MAP_KIND (c)
+ == GOMP_MAP_FIRSTPRIVATE_POINTER)
|| (OMP_CLAUSE_MAP_KIND (c)
== GOMP_MAP_FORCE_DEVICEPTR)))
+ && t == OMP_CLAUSE_DECL (c)
&& !lang_hooks.types.omp_mappable_type (TREE_TYPE (t)))
{
error_at (OMP_CLAUSE_LOCATION (c),
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);
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:
}
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)
{
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:
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:
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)
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;
}
{
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
};
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. */
struct gomp_atomic_store;
struct gomp_continue;
struct gomp_critical;
+struct gomp_ordered;
struct gomp_for;
struct gomp_parallel;
struct gomp_task;
+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
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. */
case OMP_FOR:
case OMP_SIMD:
case OMP_DISTRIBUTE:
+ case OMP_TASKLOOP:
ret = cp_gimplify_omp_for (expr_p, pre_p);
break;
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)
{
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)
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);
+}
#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
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)
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 */
(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. */
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);
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);
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);
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);
/* 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;
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();
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;
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))
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;
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))
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;
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;
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;
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))
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)
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;
&& !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;
}
&& !TREE_READONLY (length))
{
error_at (token->location,
- "%qD is not a constant", length);
+ "%qD is not a constant", length);
decl = error_mark_node;
}
}
}
/* 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
/*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;
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 ) */
}
/* 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;
}
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)
c = build_omp_clause (location, OMP_CLAUSE_SCHEDULE);
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ const char *p = IDENTIFIER_POINTER (id);
+ if (strcmp ("simd", p) == 0
+ && cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON))
+ {
+ OMP_CLAUSE_SCHEDULE_SIMD (c) = 1;
+ cp_lexer_consume_token (parser->lexer);
+ cp_lexer_consume_token (parser->lexer);
+ }
+ }
+
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
{
tree id = cp_lexer_peek_token (parser->lexer)->u.value;
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 ) */
/* 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,
{
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)
{
}
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;
}
/*or_comma=*/false,
/*consume_paren=*/true);
- check_no_duplicate_clause (list, OMP_CLAUSE_SIMDLEN, "simdlen", location);
+ check_no_duplicate_clause (list, OMP_CLAUSE_SIMDLEN, "simdlen", location);
+
+ c = build_omp_clause (location, OMP_CLAUSE_SIMDLEN);
+ OMP_CLAUSE_SIMDLEN_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+
+ return c;
+}
+
+/* OpenMP 4.5:
+ vec:
+ identifier [+/- integer]
+ vec , identifier [+/- integer]
+*/
+
+static tree
+cp_parser_omp_clause_depend_sink (cp_parser *parser, location_t clause_loc,
+ tree list)
+{
+ tree vec = NULL;
+
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME))
+ {
+ cp_parser_error (parser, "expected identifier");
+ return list;
+ }
+
+ while (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ location_t id_loc = cp_lexer_peek_token (parser->lexer)->location;
+ tree t, identifier = cp_parser_identifier (parser);
+ tree addend = NULL;
+
+ if (identifier == error_mark_node)
+ t = error_mark_node;
+ else
+ {
+ t = cp_parser_lookup_name_simple
+ (parser, identifier,
+ cp_lexer_peek_token (parser->lexer)->location);
+ if (t == error_mark_node)
+ cp_parser_name_lookup_error (parser, identifier, t, NLE_NULL,
+ id_loc);
+ }
+
+ bool neg = false;
+ if (cp_lexer_next_token_is (parser->lexer, CPP_MINUS))
+ neg = true;
+ else if (!cp_lexer_next_token_is (parser->lexer, CPP_PLUS))
+ {
+ addend = integer_zero_node;
+ goto add_to_vector;
+ }
+ cp_lexer_consume_token (parser->lexer);
+
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_NUMBER))
+ {
+ cp_parser_error (parser, "expected integer");
+ return list;
+ }
+
+ addend = cp_lexer_peek_token (parser->lexer)->u.value;
+ if (TREE_CODE (addend) != INTEGER_CST)
+ {
+ cp_parser_error (parser, "expected integer");
+ return list;
+ }
+ cp_lexer_consume_token (parser->lexer);
+
+ add_to_vector:
+ if (t != error_mark_node)
+ {
+ vec = tree_cons (addend, t, vec);
+ if (neg)
+ OMP_CLAUSE_DEPEND_SINK_NEGATIVE (vec) = 1;
+ }
- c = build_omp_clause (location, OMP_CLAUSE_SIMDLEN);
- OMP_CLAUSE_SIMDLEN_EXPR (c) = t;
- OMP_CLAUSE_CHAIN (c) = list;
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
+ break;
- return c;
+ cp_lexer_consume_token (parser->lexer);
+ }
+
+ if (cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN) && vec)
+ {
+ tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DEPEND);
+ OMP_CLAUSE_DEPEND_KIND (u) = OMP_CLAUSE_DEPEND_SINK;
+ OMP_CLAUSE_DECL (u) = nreverse (vec);
+ OMP_CLAUSE_CHAIN (u) = list;
+ return u;
+ }
+ return list;
}
/* OpenMP 4.0:
depend ( depend-kind : variable-list )
depend-kind:
- in | out | inout */
+ in | out | inout
+
+ OpenMP 4.5:
+ depend ( source )
+
+ depend ( sink : vec ) */
static tree
-cp_parser_omp_clause_depend (cp_parser *parser, tree list)
+cp_parser_omp_clause_depend (cp_parser *parser, tree list, location_t loc)
{
tree nlist, c;
enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_INOUT;
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;
}
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:
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)
{
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");
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);
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:
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;
}
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:
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);
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);
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:
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:
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";
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;
}
/* 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))
{
/*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:
? 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);
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
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);
}
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,
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):
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)
decl, NOP_EXPR,
rhs,
tf_warning_or_error));
- add_private_clause = true;
+ if (!add_private_clause)
+ add_private_clause = decl;
}
else
{
{
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
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)
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);
}
}
}
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;
}
}
}
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
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
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)
{
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:
#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) \
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);
{
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 ();
( (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) \
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))
{
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)
/* 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:
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))
{
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);
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);
}
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);
| (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)
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT))
-static tree
-cp_parser_omp_teams (cp_parser *parser, cp_token *pragma_tok,
- char *p_name, omp_clause_mask mask, tree *cclauses)
-{
- tree clauses, sb, ret;
- unsigned int save;
- location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+static tree
+cp_parser_omp_teams (cp_parser *parser, cp_token *pragma_tok,
+ char *p_name, omp_clause_mask mask, tree *cclauses)
+{
+ tree clauses, sb, ret;
+ unsigned int save;
+ location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+
+ strcat (p_name, " teams");
+ mask |= OMP_TEAMS_CLAUSE_MASK;
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ const char *p = IDENTIFIER_POINTER (id);
+ if (strcmp (p, "distribute") == 0)
+ {
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+
+ cp_lexer_consume_token (parser->lexer);
+ if (!flag_openmp) /* flag_openmp_simd */
+ return cp_parser_omp_distribute (parser, pragma_tok, p_name, mask,
+ cclauses);
+ sb = begin_omp_structured_block ();
+ save = cp_parser_begin_omp_structured_block (parser);
+ ret = cp_parser_omp_distribute (parser, pragma_tok, p_name, mask,
+ cclauses);
+ cp_parser_end_omp_structured_block (parser, save);
+ tree body = finish_omp_structured_block (sb);
+ if (ret == NULL)
+ return ret;
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS];
+ ret = make_node (OMP_TEAMS);
+ TREE_TYPE (ret) = void_type_node;
+ OMP_TEAMS_CLAUSES (ret) = clauses;
+ OMP_TEAMS_BODY (ret) = body;
+ OMP_TEAMS_COMBINED (ret) = 1;
+ return add_stmt (ret);
+ }
+ }
+ if (!flag_openmp) /* flag_openmp_simd */
+ {
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ return NULL_TREE;
+ }
+
+ clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok,
+ cclauses == NULL);
+ if (cclauses)
+ {
+ cp_omp_split_clauses (loc, OMP_TEAMS, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS];
+ }
+
+ tree stmt = make_node (OMP_TEAMS);
+ TREE_TYPE (stmt) = void_type_node;
+ OMP_TEAMS_CLAUSES (stmt) = clauses;
+ OMP_TEAMS_BODY (stmt) = cp_parser_omp_structured_block (parser);
+
+ return add_stmt (stmt);
+}
+
+/* OpenMP 4.0:
+ # pragma omp target data target-data-clause[optseq] new-line
+ structured-block */
+
+#define OMP_TARGET_DATA_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR))
+
+static tree
+cp_parser_omp_target_data (cp_parser *parser, cp_token *pragma_tok)
+{
+ tree clauses
+ = cp_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK,
+ "#pragma omp target data", pragma_tok);
+ int map_seen = 0;
+ for (tree *pc = &clauses; *pc;)
+ {
+ if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP)
+ switch (OMP_CLAUSE_MAP_KIND (*pc))
+ {
+ case GOMP_MAP_TO:
+ case GOMP_MAP_ALWAYS_TO:
+ case GOMP_MAP_FROM:
+ case GOMP_MAP_ALWAYS_FROM:
+ case GOMP_MAP_TOFROM:
+ case GOMP_MAP_ALWAYS_TOFROM:
+ case GOMP_MAP_ALLOC:
+ map_seen = 3;
+ break;
+ case GOMP_MAP_FIRSTPRIVATE_POINTER:
+ break;
+ default:
+ map_seen |= 1;
+ error_at (OMP_CLAUSE_LOCATION (*pc),
+ "%<#pragma omp target data%> with map-type other "
+ "than %<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;
+
+ keep_next_level (true);
+ OMP_TARGET_DATA_BODY (stmt) = cp_parser_omp_structured_block (parser);
+
+ SET_EXPR_LOCATION (stmt, pragma_tok->location);
+ return add_stmt (stmt);
+}
+
+/* OpenMP 4.5:
+ # pragma omp target enter data target-enter-data-clause[optseq] new-line
+ structured-block */
- strcat (p_name, " teams");
- mask |= OMP_TEAMS_CLAUSE_MASK;
+#define OMP_TARGET_ENTER_DATA_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
+static tree
+cp_parser_omp_target_enter_data (cp_parser *parser, cp_token *pragma_tok,
+ enum pragma_context context)
+{
+ bool data_seen = false;
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
{
tree id = cp_lexer_peek_token (parser->lexer)->u.value;
const char *p = IDENTIFIER_POINTER (id);
- if (strcmp (p, "distribute") == 0)
- {
- tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
- if (cclauses == NULL)
- cclauses = cclauses_buf;
+ if (strcmp (p, "data") == 0)
+ {
cp_lexer_consume_token (parser->lexer);
- if (!flag_openmp) /* flag_openmp_simd */
- return cp_parser_omp_distribute (parser, pragma_tok, p_name, mask,
- cclauses);
- sb = begin_omp_structured_block ();
- save = cp_parser_begin_omp_structured_block (parser);
- ret = cp_parser_omp_distribute (parser, pragma_tok, p_name, mask,
- cclauses);
- cp_parser_end_omp_structured_block (parser, save);
- tree body = finish_omp_structured_block (sb);
- if (ret == NULL)
- return ret;
- clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS];
- ret = make_node (OMP_TEAMS);
- TREE_TYPE (ret) = void_type_node;
- OMP_TEAMS_CLAUSES (ret) = clauses;
- OMP_TEAMS_BODY (ret) = body;
- OMP_TEAMS_COMBINED (ret) = 1;
- return add_stmt (ret);
+ data_seen = true;
}
}
- if (!flag_openmp) /* flag_openmp_simd */
+ if (!data_seen)
{
+ cp_parser_error (parser, "expected %<data%>");
cp_parser_skip_to_pragma_eol (parser, pragma_tok);
return NULL_TREE;
}
- clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok,
- cclauses == NULL);
- if (cclauses)
+ if (context == pragma_stmt)
{
- cp_omp_split_clauses (loc, OMP_TEAMS, mask, clauses, cclauses);
- clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS];
+ error_at (pragma_tok->location,
+ "%<#pragma omp target enter data%> may only be "
+ "used in compound statements");
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ return NULL_TREE;
}
- tree stmt = make_node (OMP_TEAMS);
- TREE_TYPE (stmt) = void_type_node;
- OMP_TEAMS_CLAUSES (stmt) = clauses;
- OMP_TEAMS_BODY (stmt) = cp_parser_omp_structured_block (parser);
+ tree clauses
+ = cp_parser_omp_all_clauses (parser, OMP_TARGET_ENTER_DATA_CLAUSE_MASK,
+ "#pragma omp target enter data", pragma_tok);
+ int map_seen = 0;
+ for (tree *pc = &clauses; *pc;)
+ {
+ if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP)
+ switch (OMP_CLAUSE_MAP_KIND (*pc))
+ {
+ case GOMP_MAP_TO:
+ case GOMP_MAP_ALWAYS_TO:
+ case GOMP_MAP_ALLOC:
+ map_seen = 3;
+ break;
+ case GOMP_MAP_FIRSTPRIVATE_POINTER:
+ break;
+ default:
+ map_seen |= 1;
+ error_at (OMP_CLAUSE_LOCATION (*pc),
+ "%<#pragma omp target enter data%> with map-type other "
+ "than %<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.0:
- # pragma omp target data target-data-clause[optseq] new-line
+/* OpenMP 4.5:
+ # pragma omp target exit data target-enter-data-clause[optseq] new-line
structured-block */
-#define OMP_TARGET_DATA_CLAUSE_MASK \
+#define OMP_TARGET_EXIT_DATA_CLAUSE_MASK \
( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF))
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
static tree
-cp_parser_omp_target_data (cp_parser *parser, cp_token *pragma_tok)
+cp_parser_omp_target_exit_data (cp_parser *parser, cp_token *pragma_tok,
+ enum pragma_context context)
{
- tree stmt = make_node (OMP_TARGET_DATA);
- TREE_TYPE (stmt) = void_type_node;
+ bool data_seen = false;
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ const char *p = IDENTIFIER_POINTER (id);
- OMP_TARGET_DATA_CLAUSES (stmt)
- = cp_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK,
- "#pragma omp target data", pragma_tok);
- keep_next_level (true);
- OMP_TARGET_DATA_BODY (stmt) = cp_parser_omp_structured_block (parser);
+ if (strcmp (p, "data") == 0)
+ {
+ cp_lexer_consume_token (parser->lexer);
+ data_seen = true;
+ }
+ }
+ if (!data_seen)
+ {
+ cp_parser_error (parser, "expected %<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);
}
( (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,
#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");
{
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 "
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)
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 */
{
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);
}
}
- 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;
}
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));
/* 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
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
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);
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);
{
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);
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);
"%<#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:
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)
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;
&& 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);
}
/* 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
&& 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))
{
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);
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);
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:
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;
}
#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)
{
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;
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));
}
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;
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:
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)));
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));
}
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));
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 ();
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);
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. */
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
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);
}
/* 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)
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))
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
---------------------------------
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)
{
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);
&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
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
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
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)
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))
{
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;
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
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
}
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++;
}
}
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++;
}
"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
/* 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)
{
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);
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,
{
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);
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),
{
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))
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)
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),
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)));
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);
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)
{
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
*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;
}
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;
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)
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;
}
}
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;
}
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;
}
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;
}
else
bitmap_set_bit (&lastprivate_head, DECL_UID (t));
- break;
+ goto handle_field_decl;
case OMP_CLAUSE_IF:
t = OMP_CLAUSE_IF_EXPR (c);
{
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;
}
}
OMP_CLAUSE_OPERAND (c, 0) = t;
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SAFELEN)
+ safelen = c;
}
break;
{
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;
{
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;
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)
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;
}
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;
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
{
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;
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)
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);
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:
}
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:
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;
{
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;
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)
{
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)
{
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
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
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;
}
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);
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 ();
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,
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));
}
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);
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));
}
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;
}
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)
{
}
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);
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;
}
+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
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,
#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
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], \
#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
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);
}
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);
}
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)
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 {
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
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,
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,
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,
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,
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;
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:
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;
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;
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);
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))
{
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);
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;
/* 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);
/* 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);
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:
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);
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]
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.
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
{
/* [ WORD 1-7 ] : base class */
- /* [ WORD 8 ]
+ /* [ WORD 8 ] */
+ tree clauses;
+
+ /* [ WORD 9 ]
Critical section name. */
tree name;
};
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
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
return gs->code == GIMPLE_OMP_CRITICAL;
}
+template <>
+template <>
+inline bool
+is_a_helper <gomp_ordered *>::test (gimple *gs)
+{
+ return gs->code == GIMPLE_OMP_ORDERED;
+}
+
template <>
template <>
inline bool
return gs->code == GIMPLE_OMP_CRITICAL;
}
+template <>
+template <>
+inline bool
+is_a_helper <const gomp_ordered *>::test (const gimple *gs)
+{
+ return gs->code == GIMPLE_OMP_ORDERED;
+}
+
template <>
template <>
inline bool
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,
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);
}
-/* 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)
}
-/* 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)
}
+/* 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
}
+/* 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
/* 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)
/* 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. */
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;
{
splay_tree_delete (c->variables);
delete c->privatized_types;
+ c->loop_iter_var.release ();
XDELETE (c);
}
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))
{
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);
}
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;
{
splay_tree_node n;
- if (decl == NULL || !DECL_P (decl))
+ if (decl == NULL || !DECL_P (decl) || ctx->region_type == ORT_NONE)
return;
do
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)
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
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. */
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;
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);
}
}
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)
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))
{
}
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
{
{
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);
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)
{
&& splay_tree_lookup (outer_ctx->variables,
(splay_tree_key) decl) == NULL)
omp_add_variable (outer_ctx, decl, GOVD_SHARED | GOVD_SEEN);
+ else if (outer_ctx
+ && (outer_ctx->region_type & ORT_TASK) != 0
+ && outer_ctx->combined_loop
+ && splay_tree_lookup (outer_ctx->variables,
+ (splay_tree_key) decl) == NULL)
+ omp_add_variable (outer_ctx, decl, GOVD_LASTPRIVATE | GOVD_SEEN);
else if (outer_ctx
&& outer_ctx->region_type == ORT_WORKSHARE
&& outer_ctx->combined_loop
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)
}
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. */
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)
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;
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));
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,
}
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 ();
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",
}
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. */
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;
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:
}
gimplify_omp_ctxp = ctx;
+ if (struct_map_to_clause)
+ delete struct_map_to_clause;
}
struct gimplify_adjust_omp_clauses_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,
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;
}
}
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;
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
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:
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:
{
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. */
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 ();
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),
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 ();
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),
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;
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 ();
/* 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);
}
}
- 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
}
}
}
- 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);
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));
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)
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)
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;
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
&& 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);
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);
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))
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 ();
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;
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:
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);
}
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))
{
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);
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
case CILK_SIMD:
case CILK_FOR:
case OMP_DISTRIBUTE:
+ case OMP_TASKLOOP:
case OACC_LOOP:
ret = gimplify_omp_for (expr_p, pre_p);
break;
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;
}
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 ();
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
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)
+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>
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) \
#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
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,
#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
+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
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,
#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
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) \
#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
"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",
"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",
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)
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)
/* 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
{
/* 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
/* 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
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;
};
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;
}
+/* 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);
}
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;
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);
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
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)
? 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;
}
}
+ if (i >= fd->collapse)
+ continue;
+
if (collapse_count && *collapse_count == NULL)
{
t = fold_binary (loop->cond_code, boolean_type_node,
*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);
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
}
+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. */
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);
}
}
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)
{
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
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;
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;
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))
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);
/* 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));
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);
}
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
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);
}
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
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. */
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))
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)
}
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);
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:
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;
&& !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)
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);
}
&& !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))
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:
}
/* 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;
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:
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)))
{
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:
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;
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;
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
}
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);
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)
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);
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)
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)
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)
}
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)
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))
{
}
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)
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 ();
}
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);
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;
}
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;
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
}
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);
if (pass != 0)
continue;
}
- else if (is_variable_sized (var))
+ /* C/C++ array section reductions. */
+ else if (c_kind == OMP_CLAUSE_REDUCTION
+ && var != OMP_CLAUSE_DECL (c))
{
- /* For variable sized types, we need to allocate the
- actual storage here. Call alloca and store the
- result in the pointer decl that we created elsewhere. */
if (pass == 0)
continue;
- if (c_kind != OMP_CLAUSE_FIRSTPRIVATE || !is_task_ctx (ctx))
+ tree orig_var = TREE_OPERAND (OMP_CLAUSE_DECL (c), 0);
+ if (TREE_CODE (orig_var) == INDIRECT_REF
+ || TREE_CODE (orig_var) == ADDR_EXPR)
+ orig_var = TREE_OPERAND (orig_var, 0);
+ tree d = OMP_CLAUSE_DECL (c);
+ tree type = TREE_TYPE (d);
+ gcc_assert (TREE_CODE (type) == ARRAY_TYPE);
+ tree v = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
+ const char *name = get_name (orig_var);
+ if (TREE_CONSTANT (v))
{
- gcall *stmt;
- tree tmp, atmp;
-
- ptr = DECL_VALUE_EXPR (new_var);
- gcc_assert (TREE_CODE (ptr) == INDIRECT_REF);
- ptr = TREE_OPERAND (ptr, 0);
+ x = create_tmp_var_raw (type, name);
+ gimple_add_tmp_var (x);
+ TREE_ADDRESSABLE (x) = 1;
+ x = build_fold_addr_expr_loc (clause_loc, x);
+ }
+ else
+ {
+ tree atmp
+ = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN);
+ tree t = maybe_lookup_decl (v, ctx);
+ if (t)
+ v = t;
+ else
+ v = maybe_lookup_decl_in_outer_ctx (v, ctx);
+ gimplify_expr (&v, ilist, NULL, is_gimple_val, fb_rvalue);
+ t = fold_build2_loc (clause_loc, PLUS_EXPR,
+ TREE_TYPE (v), v,
+ build_int_cst (TREE_TYPE (v), 1));
+ t = fold_build2_loc (clause_loc, MULT_EXPR,
+ TREE_TYPE (v), t,
+ TYPE_SIZE_UNIT (TREE_TYPE (type)));
+ tree al = size_int (TYPE_ALIGN (TREE_TYPE (type)));
+ x = build_call_expr_loc (clause_loc, atmp, 2, t, al);
+ }
+
+ tree ptype = build_pointer_type (TREE_TYPE (type));
+ x = fold_convert_loc (clause_loc, ptype, x);
+ tree y = create_tmp_var (ptype, name);
+ gimplify_assign (y, x, ilist);
+ x = y;
+ if (TREE_CODE (TREE_OPERAND (d, 0)) == ADDR_EXPR)
+ {
+ if (orig_var != var)
+ {
+ gcc_assert (is_variable_sized (orig_var));
+ x = fold_convert_loc (clause_loc, TREE_TYPE (new_var),
+ x);
+ gimplify_assign (new_var, x, ilist);
+ tree new_orig_var = lookup_decl (orig_var, ctx);
+ tree t = build_fold_indirect_ref (new_var);
+ DECL_IGNORED_P (new_var) = 0;
+ TREE_THIS_NOTRAP (t);
+ SET_DECL_VALUE_EXPR (new_orig_var, t);
+ DECL_HAS_VALUE_EXPR_P (new_orig_var) = 1;
+ }
+ else
+ {
+ x = build2 (MEM_REF, TREE_TYPE (new_var), x,
+ build_int_cst (ptype, 0));
+ SET_DECL_VALUE_EXPR (new_var, x);
+ DECL_HAS_VALUE_EXPR_P (new_var) = 1;
+ }
+ }
+ else
+ {
+ gcc_assert (orig_var == var);
+ if (TREE_CODE (TREE_OPERAND (d, 0)) == INDIRECT_REF)
+ {
+ x = create_tmp_var (ptype, name);
+ TREE_ADDRESSABLE (x) = 1;
+ gimplify_assign (x, y, ilist);
+ x = build_fold_addr_expr_loc (clause_loc, x);
+ }
+ x = fold_convert_loc (clause_loc, TREE_TYPE (new_var), x);
+ gimplify_assign (new_var, x, ilist);
+ }
+ tree y1 = create_tmp_var (ptype, NULL);
+ gimplify_assign (y1, y, ilist);
+ tree i2 = NULL_TREE, y2 = NULL_TREE;
+ tree body2 = NULL_TREE, end2 = NULL_TREE;
+ tree y3 = NULL_TREE, y4 = NULL_TREE;
+ if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) || is_simd)
+ {
+ y2 = create_tmp_var (ptype, NULL);
+ gimplify_assign (y2, y, ilist);
+ tree ref = build_outer_var_ref (var, ctx);
+ /* For ref build_outer_var_ref already performs this. */
+ if (TREE_CODE (TREE_OPERAND (d, 0)) == INDIRECT_REF)
+ gcc_assert (is_reference (var));
+ else if (TREE_CODE (TREE_OPERAND (d, 0)) == ADDR_EXPR)
+ ref = build_fold_addr_expr (ref);
+ else if (is_reference (var))
+ ref = build_fold_addr_expr (ref);
+ ref = fold_convert_loc (clause_loc, ptype, ref);
+ if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)
+ && OMP_CLAUSE_REDUCTION_OMP_ORIG_REF (c))
+ {
+ y3 = create_tmp_var (ptype, NULL);
+ gimplify_assign (y3, unshare_expr (ref), ilist);
+ }
+ if (is_simd)
+ {
+ y4 = create_tmp_var (ptype, NULL);
+ gimplify_assign (y4, ref, dlist);
+ }
+ }
+ tree i = create_tmp_var (TREE_TYPE (v), NULL);
+ gimplify_assign (i, build_int_cst (TREE_TYPE (v), 0), ilist);
+ tree body = create_artificial_label (UNKNOWN_LOCATION);
+ tree end = create_artificial_label (UNKNOWN_LOCATION);
+ gimple_seq_add_stmt (ilist, gimple_build_label (body));
+ if (y2)
+ {
+ i2 = create_tmp_var (TREE_TYPE (v), NULL);
+ gimplify_assign (i2, build_int_cst (TREE_TYPE (v), 0), dlist);
+ body2 = create_artificial_label (UNKNOWN_LOCATION);
+ end2 = create_artificial_label (UNKNOWN_LOCATION);
+ gimple_seq_add_stmt (dlist, gimple_build_label (body2));
+ }
+ if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
+ {
+ tree placeholder = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c);
+ tree decl_placeholder
+ = OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c);
+ SET_DECL_VALUE_EXPR (decl_placeholder,
+ build_simple_mem_ref (y1));
+ DECL_HAS_VALUE_EXPR_P (decl_placeholder) = 1;
+ SET_DECL_VALUE_EXPR (placeholder,
+ y3 ? build_simple_mem_ref (y3)
+ : error_mark_node);
+ DECL_HAS_VALUE_EXPR_P (placeholder) = 1;
+ x = lang_hooks.decls.omp_clause_default_ctor
+ (c, build_simple_mem_ref (y1),
+ y3 ? build_simple_mem_ref (y3) : NULL_TREE);
+ if (x)
+ gimplify_and_add (x, ilist);
+ if (OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c))
+ {
+ gimple_seq tseq = OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c);
+ lower_omp (&tseq, ctx);
+ gimple_seq_add_seq (ilist, tseq);
+ }
+ OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c) = NULL;
+ if (is_simd)
+ {
+ SET_DECL_VALUE_EXPR (decl_placeholder,
+ build_simple_mem_ref (y2));
+ SET_DECL_VALUE_EXPR (placeholder,
+ build_simple_mem_ref (y4));
+ gimple_seq tseq = OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c);
+ lower_omp (&tseq, ctx);
+ gimple_seq_add_seq (dlist, tseq);
+ OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c) = NULL;
+ }
+ DECL_HAS_VALUE_EXPR_P (placeholder) = 0;
+ DECL_HAS_VALUE_EXPR_P (decl_placeholder) = 0;
+ x = lang_hooks.decls.omp_clause_dtor
+ (c, build_simple_mem_ref (y2));
+ if (x)
+ {
+ gimple_seq tseq = NULL;
+ dtor = x;
+ gimplify_stmt (&dtor, &tseq);
+ gimple_seq_add_seq (dlist, tseq);
+ }
+ }
+ else
+ {
+ x = omp_reduction_init (c, TREE_TYPE (type));
+ enum tree_code code = OMP_CLAUSE_REDUCTION_CODE (c);
+
+ /* reduction(-:var) sums up the partial results, so it
+ acts identically to reduction(+:var). */
+ if (code == MINUS_EXPR)
+ code = PLUS_EXPR;
+
+ gimplify_assign (build_simple_mem_ref (y1), x, ilist);
+ if (is_simd)
+ {
+ x = build2 (code, TREE_TYPE (type),
+ build_simple_mem_ref (y4),
+ build_simple_mem_ref (y2));
+ gimplify_assign (build_simple_mem_ref (y4), x, dlist);
+ }
+ }
+ gimple *g
+ = gimple_build_assign (y1, POINTER_PLUS_EXPR, y1,
+ TYPE_SIZE_UNIT (TREE_TYPE (type)));
+ gimple_seq_add_stmt (ilist, g);
+ if (y3)
+ {
+ g = gimple_build_assign (y3, POINTER_PLUS_EXPR, y3,
+ TYPE_SIZE_UNIT (TREE_TYPE (type)));
+ gimple_seq_add_stmt (ilist, g);
+ }
+ g = gimple_build_assign (i, PLUS_EXPR, i,
+ build_int_cst (TREE_TYPE (i), 1));
+ gimple_seq_add_stmt (ilist, g);
+ g = gimple_build_cond (LE_EXPR, i, v, body, end);
+ gimple_seq_add_stmt (ilist, g);
+ gimple_seq_add_stmt (ilist, gimple_build_label (end));
+ if (y2)
+ {
+ g = gimple_build_assign (y2, POINTER_PLUS_EXPR, y2,
+ TYPE_SIZE_UNIT (TREE_TYPE (type)));
+ gimple_seq_add_stmt (dlist, g);
+ if (y4)
+ {
+ g = gimple_build_assign
+ (y4, POINTER_PLUS_EXPR, y4,
+ TYPE_SIZE_UNIT (TREE_TYPE (type)));
+ gimple_seq_add_stmt (dlist, g);
+ }
+ g = gimple_build_assign (i2, PLUS_EXPR, i2,
+ build_int_cst (TREE_TYPE (i2), 1));
+ gimple_seq_add_stmt (dlist, g);
+ g = gimple_build_cond (LE_EXPR, i2, v, body2, end2);
+ gimple_seq_add_stmt (dlist, g);
+ gimple_seq_add_stmt (dlist, gimple_build_label (end2));
+ }
+ continue;
+ }
+ else if (is_variable_sized (var))
+ {
+ /* For variable sized types, we need to allocate the
+ actual storage here. Call alloca and store the
+ result in the pointer decl that we created elsewhere. */
+ if (pass == 0)
+ continue;
+
+ if (c_kind != OMP_CLAUSE_FIRSTPRIVATE || !is_task_ctx (ctx))
+ {
+ gcall *stmt;
+ tree tmp, atmp;
+
+ ptr = DECL_VALUE_EXPR (new_var);
+ gcc_assert (TREE_CODE (ptr) == INDIRECT_REF);
+ ptr = TREE_OPERAND (ptr, 0);
gcc_assert (DECL_P (ptr));
x = TYPE_SIZE_UNIT (TREE_TYPE (new_var));
/* void *tmp = __builtin_alloca */
- atmp = builtin_decl_explicit (BUILT_IN_ALLOCA);
- stmt = gimple_build_call (atmp, 1, x);
+ atmp = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN);
+ stmt = gimple_build_call (atmp, 2, x,
+ size_int (DECL_ALIGN (var)));
tmp = create_tmp_var_raw (ptr_type_node);
gimple_add_tmp_var (tmp);
gimple_call_set_lhs (stmt, tmp);
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);
}
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)
/* 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. */
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);
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);
&& !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))
{
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);
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;
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);
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);
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))
{
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);
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:
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;
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;
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);
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
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);
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
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);
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))
{
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);
}
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);
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. */
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)))
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;
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);
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];
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
}
-/* A subroutine of expand_omp_for. Generate code for a parallel
- loop with any schedule. Given parameters:
-
- for (V = N1; V cond N2; V += STEP) BODY;
+/* Expand #pragma omp ordered depend(source). */
- where COND is "<" or ">", we generate pseudocode
+static void
+expand_omp_ordered_source (gimple_stmt_iterator *gsi, struct omp_for_data *fd,
+ tree *counts, location_t loc)
+{
+ enum built_in_function source_ix
+ = fd->iter_type == long_integer_type_node
+ ? BUILT_IN_GOMP_DOACROSS_POST : BUILT_IN_GOMP_DOACROSS_ULL_POST;
+ gimple *g
+ = gimple_build_call (builtin_decl_explicit (source_ix), 1,
+ build_fold_addr_expr (counts[fd->ordered]));
+ gimple_set_location (g, loc);
+ gsi_insert_before (gsi, g, GSI_SAME_STMT);
+}
- more = GOMP_loop_foo_start (N1, N2, STEP, CHUNK, &istart0, &iend0);
- if (more) goto L0; else goto L3;
- L0:
- V = istart0;
- iend = iend0;
- L1:
- BODY;
- V += STEP;
- if (V cond iend) goto L1; else goto L2;
- L2:
- if (GOMP_loop_foo_next (&istart0, &iend0)) goto L0; else goto L3;
- L3:
+/* Expand a single depend from #pragma omp ordered depend(sink:...). */
- If this is a combined omp parallel loop, instead of the call to
- GOMP_loop_foo_start, we call GOMP_loop_foo_next.
- If this is gimple_omp_for_combined_p loop, then instead of assigning
- V and iend in L0 we assign the first two _looptemp_ clause decls of the
- inner GIMPLE_OMP_FOR and V += STEP; and
- if (V cond iend) goto L1; else goto L2; are removed.
+static void
+expand_omp_ordered_sink (gimple_stmt_iterator *gsi, struct omp_for_data *fd,
+ tree *counts, tree c, location_t loc)
+{
+ auto_vec<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 collapsed loops, given parameters:
- collapse(3)
- for (V1 = N11; V1 cond1 N12; V1 += STEP1)
- for (V2 = N21; V2 cond2 N22; V2 += STEP2)
- for (V3 = N31; V3 cond3 N32; V3 += STEP3)
- BODY;
+ for (i = 0; i < fd->ordered; i++)
+ {
+ off = TREE_PURPOSE (deps);
+ if (!integer_zerop (off))
+ {
+ gcc_assert (fd->loops[i].cond_code == LT_EXPR
+ || fd->loops[i].cond_code == GT_EXPR);
+ bool forward = fd->loops[i].cond_code == LT_EXPR;
+ if (forward ^ OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps))
+ warning_at (loc, 0, "%<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; */
- we generate pseudocode
+ deps = OMP_CLAUSE_DECL (c);
+ gsi_prev (&gsi2);
+ edge e1 = split_block (gsi_bb (gsi2), gsi_stmt (gsi2));
+ edge e2 = split_block_after_labels (e1->dest);
- if (__builtin_expect (N32 cond3 N31, 0)) goto Z0;
- if (cond3 is <)
- adj = STEP3 - 1;
- else
- adj = STEP3 + 1;
- count3 = (adj + N32 - N31) / STEP3;
- if (__builtin_expect (N22 cond2 N21, 0)) goto Z0;
- if (cond2 is <)
- adj = STEP2 - 1;
- else
- adj = STEP2 + 1;
+ *gsi = gsi_after_labels (e1->dest);
+ for (i = 0; i < fd->ordered; i++)
+ {
+ tree itype = TREE_TYPE (fd->loops[i].v);
+ if (POINTER_TYPE_P (itype))
+ itype = sizetype;
+ if (i)
+ deps = TREE_CHAIN (deps);
+ off = TREE_PURPOSE (deps);
+ tree s = fold_convert_loc (loc, itype, fd->loops[i].step);
+
+ if (integer_zerop (off))
+ t = boolean_true_node;
+ else
+ {
+ tree a;
+ tree co = fold_convert_loc (loc, itype, off);
+ if (POINTER_TYPE_P (TREE_TYPE (fd->loops[i].v)))
+ {
+ if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps))
+ co = fold_build1_loc (loc, NEGATE_EXPR, itype, co);
+ a = fold_build2_loc (loc, POINTER_PLUS_EXPR,
+ TREE_TYPE (fd->loops[i].v), fd->loops[i].v,
+ co);
+ }
+ else if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps))
+ a = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (fd->loops[i].v),
+ fd->loops[i].v, co);
+ else
+ a = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (fd->loops[i].v),
+ fd->loops[i].v, co);
+ if (fd->loops[i].cond_code == LT_EXPR)
+ {
+ if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps))
+ t = fold_build2_loc (loc, GE_EXPR, boolean_type_node, a,
+ fd->loops[i].n1);
+ else
+ t = fold_build2_loc (loc, LT_EXPR, boolean_type_node, a,
+ fd->loops[i].n2);
+ }
+ else if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps))
+ t = fold_build2_loc (loc, GT_EXPR, boolean_type_node, a,
+ fd->loops[i].n2);
+ else
+ t = fold_build2_loc (loc, LE_EXPR, boolean_type_node, a,
+ fd->loops[i].n1);
+ }
+ if (cond)
+ cond = fold_build2_loc (loc, BIT_AND_EXPR, boolean_type_node, cond, t);
+ else
+ cond = t;
+
+ off = fold_convert_loc (loc, itype, off);
+
+ if (fd->loops[i].cond_code == LT_EXPR
+ ? !integer_onep (fd->loops[i].step)
+ : !integer_minus_onep (fd->loops[i].step))
+ {
+ if (TYPE_UNSIGNED (itype) && fd->loops[i].cond_code == GT_EXPR)
+ t = fold_build2_loc (loc, TRUNC_MOD_EXPR, itype, off,
+ fold_build1_loc (loc, NEGATE_EXPR, itype,
+ s));
+ else
+ t = fold_build2_loc (loc, TRUNC_MOD_EXPR, itype, off, s);
+ t = fold_build2_loc (loc, EQ_EXPR, boolean_type_node, t,
+ build_int_cst (itype, 0));
+ if (integer_zerop (t) && !warned_step)
+ {
+ warning_at (loc, 0, "%<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:
+
+ for (V = N1; V cond N2; V += STEP) BODY;
+
+ where COND is "<" or ">", we generate pseudocode
+
+ more = GOMP_loop_foo_start (N1, N2, STEP, CHUNK, &istart0, &iend0);
+ if (more) goto L0; else goto L3;
+ L0:
+ V = istart0;
+ iend = iend0;
+ L1:
+ BODY;
+ V += STEP;
+ if (V cond iend) goto L1; else goto L2;
+ L2:
+ if (GOMP_loop_foo_next (&istart0, &iend0)) goto L0; else goto L3;
+ L3:
+
+ If this is a combined omp parallel loop, instead of the call to
+ GOMP_loop_foo_start, we call GOMP_loop_foo_next.
+ If this is gimple_omp_for_combined_p loop, then instead of assigning
+ V and iend in L0 we assign the first two _looptemp_ clause decls of the
+ inner GIMPLE_OMP_FOR and V += STEP; and
+ if (V cond iend) goto L1; else goto L2; are removed.
+
+ For collapsed loops, given parameters:
+ collapse(3)
+ for (V1 = N11; V1 cond1 N12; V1 += STEP1)
+ for (V2 = N21; V2 cond2 N22; V2 += STEP2)
+ for (V3 = N31; V3 cond3 N32; V3 += STEP3)
+ BODY;
+
+ we generate pseudocode
+
+ if (__builtin_expect (N32 cond3 N31, 0)) goto Z0;
+ if (cond3 is <)
+ adj = STEP3 - 1;
+ else
+ adj = STEP3 + 1;
+ count3 = (adj + N32 - N31) / STEP3;
+ if (__builtin_expect (N22 cond2 N21, 0)) goto Z0;
+ if (cond2 is <)
+ adj = STEP2 - 1;
+ else
+ adj = STEP2 + 1;
count2 = (adj + N22 - N21) / STEP2;
if (__builtin_expect (N12 cond1 N11, 0)) goto Z0;
if (cond1 is <)
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;
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,
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);
{
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
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;
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),
gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
t = iend0;
- if (bias)
+ if (fd->ordered && fd->collapse == 1)
+ t = fold_build2 (MULT_EXPR, fd->iter_type, t,
+ fold_convert (fd->iter_type, fd->loop.step));
+ else if (bias)
t = fold_build2 (MINUS_EXPR, fd->iter_type, t, bias);
- if (POINTER_TYPE_P (TREE_TYPE (startvar)))
- t = fold_convert (signed_type_for (TREE_TYPE (startvar)), t);
- t = fold_convert (TREE_TYPE (startvar), t);
- iend = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
- false, GSI_CONTINUE_LINKING);
- if (endvar)
+ if (fd->ordered && fd->collapse == 1)
{
- assign_stmt = gimple_build_assign (endvar, iend);
+ if (POINTER_TYPE_P (TREE_TYPE (startvar)))
+ t = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (startvar),
+ fd->loop.n1, fold_convert (sizetype, t));
+ else
+ {
+ t = fold_convert (TREE_TYPE (startvar), t);
+ t = fold_build2 (PLUS_EXPR, TREE_TYPE (startvar),
+ fd->loop.n1, t);
+ }
+ }
+ else
+ {
+ if (POINTER_TYPE_P (TREE_TYPE (startvar)))
+ t = fold_convert (signed_type_for (TREE_TYPE (startvar)), t);
+ t = fold_convert (TREE_TYPE (startvar), t);
+ }
+ iend = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
+ false, GSI_CONTINUE_LINKING);
+ if (endvar)
+ {
+ assign_stmt = gimple_build_assign (endvar, iend);
gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
if (useless_type_conversion_p (TREE_TYPE (fd->loop.v), TREE_TYPE (iend)))
assign_stmt = gimple_build_assign (fd->loop.v, iend);
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
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);
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. */
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))
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);
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))
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);
= 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);
/* 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);
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);
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;
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,
}
if (simduid)
{
- loop->simduid = OMP_CLAUSE__SIMDUID__DECL (simduid);
- cfun->has_simduid_loops = true;
+ loop->simduid = OMP_CLAUSE__SIMDUID__DECL (simduid);
+ cfun->has_simduid_loops = true;
+ }
+ /* If not -fno-tree-loop-vectorize, hint that we want to vectorize
+ the loop. */
+ if ((flag_tree_loop_vectorize
+ || (!global_options_set.x_flag_tree_loop_vectorize
+ && !global_options_set.x_flag_tree_vectorize))
+ && flag_tree_loop_optimize
+ && loop->safelen > 1)
+ {
+ loop->force_vectorize = true;
+ cfun->has_force_vectorize_loops = true;
+ }
+ }
+ else if (simduid)
+ cfun->has_simduid_loops = true;
+}
+
+/* Taskloop construct is represented after gimplification with
+ two GIMPLE_OMP_FOR constructs with GIMPLE_OMP_TASK sandwiched
+ in between them. This routine expands the outer GIMPLE_OMP_FOR,
+ which should just compute all the needed loop temporaries
+ for GIMPLE_OMP_TASK. */
+
+static void
+expand_omp_taskloop_for_outer (struct omp_region *region,
+ struct omp_for_data *fd,
+ gimple *inner_stmt)
+{
+ tree type, bias = NULL_TREE;
+ basic_block entry_bb, cont_bb, exit_bb;
+ gimple_stmt_iterator gsi;
+ gassign *assign_stmt;
+ tree *counts = NULL;
+ int i;
+
+ gcc_assert (inner_stmt);
+ gcc_assert (region->cont);
+ gcc_assert (gimple_code (inner_stmt) == GIMPLE_OMP_TASK
+ && gimple_omp_task_taskloop_p (inner_stmt));
+ type = TREE_TYPE (fd->loop.v);
+
+ /* See if we need to bias by LLONG_MIN. */
+ if (fd->iter_type == long_long_unsigned_type_node
+ && TREE_CODE (type) == INTEGER_TYPE
+ && !TYPE_UNSIGNED (type))
+ {
+ tree n1, n2;
+
+ if (fd->loop.cond_code == LT_EXPR)
+ {
+ n1 = fd->loop.n1;
+ n2 = fold_build2 (PLUS_EXPR, type, fd->loop.n2, fd->loop.step);
+ }
+ else
+ {
+ n1 = fold_build2 (MINUS_EXPR, type, fd->loop.n2, fd->loop.step);
+ n2 = fd->loop.n1;
+ }
+ if (TREE_CODE (n1) != INTEGER_CST
+ || TREE_CODE (n2) != INTEGER_CST
+ || ((tree_int_cst_sgn (n1) < 0) ^ (tree_int_cst_sgn (n2) < 0)))
+ bias = fold_convert (fd->iter_type, TYPE_MIN_VALUE (type));
+ }
+
+ entry_bb = region->entry;
+ cont_bb = region->cont;
+ gcc_assert (EDGE_COUNT (entry_bb->succs) == 2);
+ gcc_assert (BRANCH_EDGE (entry_bb)->dest == FALLTHRU_EDGE (cont_bb)->dest);
+ exit_bb = region->exit;
+
+ gsi = gsi_last_bb (entry_bb);
+ gimple *for_stmt = gsi_stmt (gsi);
+ gcc_assert (gimple_code (for_stmt) == GIMPLE_OMP_FOR);
+ if (fd->collapse > 1)
+ {
+ int first_zero_iter = -1, dummy = -1;
+ basic_block zero_iter_bb = NULL, dummy_bb = NULL, l2_dom_bb = NULL;
+
+ counts = XALLOCAVEC (tree, fd->collapse);
+ expand_omp_for_init_counts (fd, &gsi, entry_bb, counts,
+ zero_iter_bb, first_zero_iter,
+ dummy_bb, dummy, l2_dom_bb);
+
+ if (zero_iter_bb)
+ {
+ /* Some counts[i] vars might be uninitialized if
+ some loop has zero iterations. But the body shouldn't
+ be executed in that case, so just avoid uninit warnings. */
+ for (i = first_zero_iter; i < fd->collapse; i++)
+ if (SSA_VAR_P (counts[i]))
+ TREE_NO_WARNING (counts[i]) = 1;
+ gsi_prev (&gsi);
+ edge e = split_block (entry_bb, gsi_stmt (gsi));
+ entry_bb = e->dest;
+ make_edge (zero_iter_bb, entry_bb, EDGE_FALLTHRU);
+ gsi = gsi_last_bb (entry_bb);
+ set_immediate_dominator (CDI_DOMINATORS, entry_bb,
+ get_immediate_dominator (CDI_DOMINATORS,
+ zero_iter_bb));
+ }
+ }
+
+ tree t0, t1;
+ t1 = fd->loop.n2;
+ t0 = fd->loop.n1;
+ if (POINTER_TYPE_P (TREE_TYPE (t0))
+ && TYPE_PRECISION (TREE_TYPE (t0))
+ != TYPE_PRECISION (fd->iter_type))
+ {
+ /* Avoid casting pointers to integer of a different size. */
+ tree itype = signed_type_for (type);
+ t1 = fold_convert (fd->iter_type, fold_convert (itype, t1));
+ t0 = fold_convert (fd->iter_type, fold_convert (itype, t0));
+ }
+ else
+ {
+ t1 = fold_convert (fd->iter_type, t1);
+ t0 = fold_convert (fd->iter_type, t0);
+ }
+ if (bias)
+ {
+ t1 = fold_build2 (PLUS_EXPR, fd->iter_type, t1, bias);
+ t0 = fold_build2 (PLUS_EXPR, fd->iter_type, t0, bias);
+ }
+
+ tree innerc = find_omp_clause (gimple_omp_task_clauses (inner_stmt),
+ OMP_CLAUSE__LOOPTEMP_);
+ gcc_assert (innerc);
+ tree startvar = OMP_CLAUSE_DECL (innerc);
+ innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc), OMP_CLAUSE__LOOPTEMP_);
+ gcc_assert (innerc);
+ tree endvar = OMP_CLAUSE_DECL (innerc);
+ if (fd->collapse > 1 && TREE_CODE (fd->loop.n2) != INTEGER_CST)
+ {
+ gcc_assert (innerc);
+ for (i = 1; i < fd->collapse; i++)
+ {
+ innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc),
+ OMP_CLAUSE__LOOPTEMP_);
+ gcc_assert (innerc);
+ }
+ innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc),
+ OMP_CLAUSE__LOOPTEMP_);
+ if (innerc)
+ {
+ /* If needed (inner taskloop has lastprivate clause), propagate
+ down the total number of iterations. */
+ tree t = force_gimple_operand_gsi (&gsi, fd->loop.n2, false,
+ NULL_TREE, false,
+ GSI_CONTINUE_LINKING);
+ assign_stmt = gimple_build_assign (OMP_CLAUSE_DECL (innerc), t);
+ gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
+ }
+ }
+
+ t0 = force_gimple_operand_gsi (&gsi, t0, false, NULL_TREE, false,
+ GSI_CONTINUE_LINKING);
+ assign_stmt = gimple_build_assign (startvar, t0);
+ gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
+
+ t1 = force_gimple_operand_gsi (&gsi, t1, false, NULL_TREE, false,
+ GSI_CONTINUE_LINKING);
+ assign_stmt = gimple_build_assign (endvar, t1);
+ gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
+ if (fd->collapse > 1)
+ expand_omp_for_init_vars (fd, &gsi, counts, inner_stmt, startvar);
+
+ /* Remove the GIMPLE_OMP_FOR statement. */
+ gsi = gsi_for_stmt (for_stmt);
+ gsi_remove (&gsi, true);
+
+ gsi = gsi_last_bb (cont_bb);
+ gsi_remove (&gsi, true);
+
+ gsi = gsi_last_bb (exit_bb);
+ gsi_remove (&gsi, true);
+
+ FALLTHRU_EDGE (entry_bb)->probability = REG_BR_PROB_BASE;
+ remove_edge (BRANCH_EDGE (entry_bb));
+ FALLTHRU_EDGE (cont_bb)->probability = REG_BR_PROB_BASE;
+ remove_edge (BRANCH_EDGE (cont_bb));
+ set_immediate_dominator (CDI_DOMINATORS, exit_bb, cont_bb);
+ set_immediate_dominator (CDI_DOMINATORS, region->entry,
+ recompute_dominator (CDI_DOMINATORS, region->entry));
+}
+
+/* Taskloop construct is represented after gimplification with
+ two GIMPLE_OMP_FOR constructs with GIMPLE_OMP_TASK sandwiched
+ in between them. This routine expands the inner GIMPLE_OMP_FOR.
+ GOMP_taskloop{,_ull} function arranges for each task to be given just
+ a single range of iterations. */
+
+static void
+expand_omp_taskloop_for_inner (struct omp_region *region,
+ struct omp_for_data *fd,
+ gimple *inner_stmt)
+{
+ tree e, t, type, itype, vmain, vback, bias = NULL_TREE;
+ basic_block entry_bb, exit_bb, body_bb, cont_bb, collapse_bb = NULL;
+ basic_block fin_bb;
+ gimple_stmt_iterator gsi;
+ edge ep;
+ bool broken_loop = region->cont == NULL;
+ tree *counts = NULL;
+ tree n1, n2, step;
+
+ itype = type = TREE_TYPE (fd->loop.v);
+ if (POINTER_TYPE_P (type))
+ itype = signed_type_for (type);
+
+ /* See if we need to bias by LLONG_MIN. */
+ if (fd->iter_type == long_long_unsigned_type_node
+ && TREE_CODE (type) == INTEGER_TYPE
+ && !TYPE_UNSIGNED (type))
+ {
+ tree n1, n2;
+
+ if (fd->loop.cond_code == LT_EXPR)
+ {
+ n1 = fd->loop.n1;
+ n2 = fold_build2 (PLUS_EXPR, type, fd->loop.n2, fd->loop.step);
+ }
+ else
+ {
+ n1 = fold_build2 (MINUS_EXPR, type, fd->loop.n2, fd->loop.step);
+ n2 = fd->loop.n1;
+ }
+ if (TREE_CODE (n1) != INTEGER_CST
+ || TREE_CODE (n2) != INTEGER_CST
+ || ((tree_int_cst_sgn (n1) < 0) ^ (tree_int_cst_sgn (n2) < 0)))
+ bias = fold_convert (fd->iter_type, TYPE_MIN_VALUE (type));
+ }
+
+ entry_bb = region->entry;
+ cont_bb = region->cont;
+ gcc_assert (EDGE_COUNT (entry_bb->succs) == 2);
+ fin_bb = BRANCH_EDGE (entry_bb)->dest;
+ gcc_assert (broken_loop
+ || (fin_bb == FALLTHRU_EDGE (cont_bb)->dest));
+ body_bb = FALLTHRU_EDGE (entry_bb)->dest;
+ if (!broken_loop)
+ {
+ gcc_assert (BRANCH_EDGE (cont_bb)->dest == body_bb);
+ gcc_assert (EDGE_COUNT (cont_bb->succs) == 2);
+ }
+ exit_bb = region->exit;
+
+ /* Iteration space partitioning goes in ENTRY_BB. */
+ gsi = gsi_last_bb (entry_bb);
+ gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
+
+ if (fd->collapse > 1)
+ {
+ int first_zero_iter = -1, dummy = -1;
+ basic_block l2_dom_bb = NULL, dummy_bb = NULL;
+
+ counts = XALLOCAVEC (tree, fd->collapse);
+ expand_omp_for_init_counts (fd, &gsi, entry_bb, counts,
+ fin_bb, first_zero_iter,
+ dummy_bb, dummy, l2_dom_bb);
+ t = NULL_TREE;
+ }
+ else
+ t = integer_one_node;
+
+ step = fd->loop.step;
+ tree innerc = find_omp_clause (gimple_omp_for_clauses (fd->for_stmt),
+ OMP_CLAUSE__LOOPTEMP_);
+ gcc_assert (innerc);
+ n1 = OMP_CLAUSE_DECL (innerc);
+ innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc), OMP_CLAUSE__LOOPTEMP_);
+ gcc_assert (innerc);
+ n2 = OMP_CLAUSE_DECL (innerc);
+ if (bias)
+ {
+ n1 = fold_build2 (PLUS_EXPR, fd->iter_type, n1, bias);
+ n2 = fold_build2 (PLUS_EXPR, fd->iter_type, n2, bias);
+ }
+ n1 = force_gimple_operand_gsi (&gsi, fold_convert (type, n1),
+ true, NULL_TREE, true, GSI_SAME_STMT);
+ n2 = force_gimple_operand_gsi (&gsi, fold_convert (itype, n2),
+ true, NULL_TREE, true, GSI_SAME_STMT);
+ step = force_gimple_operand_gsi (&gsi, fold_convert (itype, step),
+ true, NULL_TREE, true, GSI_SAME_STMT);
+
+ tree startvar = fd->loop.v;
+ tree endvar = NULL_TREE;
+
+ if (gimple_omp_for_combined_p (fd->for_stmt))
+ {
+ tree clauses = gimple_omp_for_clauses (inner_stmt);
+ tree innerc = find_omp_clause (clauses, OMP_CLAUSE__LOOPTEMP_);
+ gcc_assert (innerc);
+ startvar = OMP_CLAUSE_DECL (innerc);
+ innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc),
+ OMP_CLAUSE__LOOPTEMP_);
+ gcc_assert (innerc);
+ endvar = OMP_CLAUSE_DECL (innerc);
+ }
+ t = fold_convert (TREE_TYPE (startvar), n1);
+ t = force_gimple_operand_gsi (&gsi, t,
+ DECL_P (startvar)
+ && TREE_ADDRESSABLE (startvar),
+ NULL_TREE, false, GSI_CONTINUE_LINKING);
+ gimple *assign_stmt = gimple_build_assign (startvar, t);
+ gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
+
+ t = fold_convert (TREE_TYPE (startvar), n2);
+ e = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
+ false, GSI_CONTINUE_LINKING);
+ if (endvar)
+ {
+ assign_stmt = gimple_build_assign (endvar, e);
+ gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
+ if (useless_type_conversion_p (TREE_TYPE (fd->loop.v), TREE_TYPE (e)))
+ assign_stmt = gimple_build_assign (fd->loop.v, e);
+ else
+ assign_stmt = gimple_build_assign (fd->loop.v, NOP_EXPR, e);
+ gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
+ }
+ if (fd->collapse > 1)
+ expand_omp_for_init_vars (fd, &gsi, counts, inner_stmt, startvar);
+
+ if (!broken_loop)
+ {
+ /* The code controlling the sequential loop replaces the
+ GIMPLE_OMP_CONTINUE. */
+ gsi = gsi_last_bb (cont_bb);
+ gomp_continue *cont_stmt = as_a <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;
}
- /* If not -fno-tree-loop-vectorize, hint that we want to vectorize
- the loop. */
- if ((flag_tree_loop_vectorize
- || (!global_options_set.x_flag_tree_loop_vectorize
- && !global_options_set.x_flag_tree_vectorize))
- && flag_tree_loop_optimize
- && loop->safelen > 1)
+ else if (fd->collapse > 1)
{
- loop->force_vectorize = true;
- cfun->has_force_vectorize_loops = true;
+ remove_edge (ep);
+ ep = make_edge (cont_bb, collapse_bb, EDGE_TRUE_VALUE);
}
+ else
+ ep->flags = EDGE_TRUE_VALUE;
+ find_edge (cont_bb, fin_bb)->flags
+ = ep ? EDGE_FALSE_VALUE : EDGE_FALLTHRU;
}
- else if (simduid)
- cfun->has_simduid_loops = true;
-}
+ set_immediate_dominator (CDI_DOMINATORS, body_bb,
+ recompute_dominator (CDI_DOMINATORS, body_bb));
+ if (!broken_loop)
+ set_immediate_dominator (CDI_DOMINATORS, fin_bb,
+ recompute_dominator (CDI_DOMINATORS, fin_bb));
+
+ if (!broken_loop && !gimple_omp_for_combined_p (fd->for_stmt))
+ {
+ struct loop *loop = alloc_loop ();
+ loop->header = body_bb;
+ if (collapse_bb == NULL)
+ loop->latch = cont_bb;
+ add_loop (loop, body_bb->loop_father);
+ }
+}
/* Expand the OMP loop defined by REGION. */
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)
{
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)
{
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;
/* 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))
{
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;
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);
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);
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);
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:
{
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);
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);
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... */
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;
}
+/* 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
{
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 ();
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);
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));
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)
+ {
+ 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)
{
- struct omp_for_data outer_fd;
- extract_omp_for_data (gfor, &outer_fd, NULL);
- n2 = fold_convert (TREE_TYPE (n2), outer_fd.loop.n2);
+ int i;
+ tree innerc
+ = find_omp_clause (gimple_omp_task_clauses (task_ctx->stmt),
+ OMP_CLAUSE__LOOPTEMP_);
+ gcc_assert (innerc);
+ for (i = 0; i < fd->collapse; i++)
+ {
+ innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc),
+ OMP_CLAUSE__LOOPTEMP_);
+ gcc_assert (innerc);
+ }
+ innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc),
+ OMP_CLAUSE__LOOPTEMP_);
+ if (innerc)
+ n2 = fold_convert (TREE_TYPE (n2),
+ lookup_decl (OMP_CLAUSE_DECL (innerc),
+ task_ctx));
}
}
cond = build2 (cond_code, boolean_type_node, fd->loop.v, n2);
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);
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));
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);
}
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)
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));
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);
{
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)
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:
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)
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;
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;
}
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;
{
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)
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)
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");
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;
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
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
|| 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);
}
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);
= 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;
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;
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);
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. */
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)
{
|| 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:
&& 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);
gsi_replace (gsi_p, gimple_build_nop (), true);
break;
}
- gimple_regimplify_operands (stmt, gsi_p);
+ lower_omp_regimplify_operands (ctx, stmt, gsi_p);
}
break;
}
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;
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;
}
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);
}
}
{
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)
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');
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
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;
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))
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);
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;
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);
+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
#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];
}
# error _OPENMP not defined
#endif
-#if _OPENMP != 201307
+#if _OPENMP != 201511
# error _OPENMP defined to wrong value
#endif
{
#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" } */
}
{
#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" } */
}
{
#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" } */
}
{
#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" } */
}
void
f2 (void)
{
- int i;
+ int i, j = 0;
#pragma omp parallel
{
#pragma omp cancel parallel
#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" } */
#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" } */
}
#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" } */
#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" } */
}
#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" } */
#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" } */
--- /dev/null
+/* { 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++;
+}
--- /dev/null
+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 } */
+}
--- /dev/null
+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;
+}
--- /dev/null
+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" } */
+ ;
+ }
+}
--- /dev/null
+/* { 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)
--- /dev/null
+/* { 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" } */
--- /dev/null
+/* { 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);
+}
--- /dev/null
+/* { 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" } */
+ ;
+}
--- /dev/null
+/* { 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" } */
+ }
+}
--- /dev/null
+/* { 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])
+}
--- /dev/null
+/* { 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." } */
+}
--- /dev/null
+/* { 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;
+}
--- /dev/null
+/* { 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" } */
+ ;
+}
--- /dev/null
+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" } */
+ }
+}
#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
;
#pragma omp target
;
-#pragma omp target data
+#pragma omp target data map(i)
;
#pragma omp target update to(i)
void
f_omp_target_data (void)
{
-#pragma omp target data
+#pragma omp target data map(i)
{
#pragma omp parallel
;
#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
;
#pragma omp target
;
-#pragma omp target data
+#pragma omp target data map(i)
;
#pragma omp target update to(i)
{
#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" } */
{
#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" } */
}
--- /dev/null
+/* { 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;
+}
--- /dev/null
+/* { dg-do run } */
+/* { dg-options "-O0 -fopenmp-simd" } */
+
+#include "ordered-1.c"
--- /dev/null
+/* { 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" } */
+ ;
+}
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;
}
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++)
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) \
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++)
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])
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]) \
#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++)
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]) \
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++)
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) \
--- /dev/null
+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 ();
+}
--- /dev/null
+/* { 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);
+}
--- /dev/null
+/* { 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];
+}
--- /dev/null
+/* { 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)
+ }
+}
--- /dev/null
+/* { 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)
+ }
+}
--- /dev/null
+/* { 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)
+ }
+}
--- /dev/null
+/* { 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" } } */
--- /dev/null
+/* { 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);
+}
--- /dev/null
+/* { 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);
+}
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" }
#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" }
;
#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)
;
#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'" }
;
#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++)
+ ;
}
--- /dev/null
+// { 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;
+}
--- /dev/null
+// { 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;
+}
--- /dev/null
+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 ();
+}
--- /dev/null
+// { 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;
+}
--- /dev/null
+// 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);
+}
#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++)
+ ;
}
#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
--- /dev/null
+// { 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);
+}
--- /dev/null
+/* { 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>();
+}
--- /dev/null
+/* { 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> ();
+}
--- /dev/null
+/* { 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" } } */
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);
}
--- /dev/null
+// { 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>;
--- /dev/null
+// { 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>;
--- /dev/null
+// { 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 ();
+}
--- /dev/null
+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);
+};
--- /dev/null
+// { 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];
+}
--- /dev/null
+// { 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 ();
+}
--- /dev/null
+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);
+};
--- /dev/null
+// { 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>;
#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" } */
;
#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)
;
#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'" } */
;
#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++)
+ ;
}
--- /dev/null
+/* { 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);
+}
--- /dev/null
+/* { 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 *-*-* } } } */
--- /dev/null
+/* { 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)
+ }
+}
--- /dev/null
+/* { 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" } } */
--- /dev/null
+/* { 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;
+}
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). */
/* 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,
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_,
/* OpenMP clause: nowait. */
OMP_CLAUSE_NOWAIT,
- /* OpenMP clause: ordered. */
+ /* OpenMP clause: ordered [(constant-integer-expression)]. */
OMP_CLAUSE_ORDERED,
/* OpenMP clause: default. */
/* 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_,
OMP_CLAUSE_DEPEND_IN,
OMP_CLAUSE_DEPEND_OUT,
OMP_CLAUSE_DEPEND_INOUT,
+ OMP_CLAUSE_DEPEND_SOURCE,
+ OMP_CLAUSE_DEPEND_SINK,
OMP_CLAUSE_DEPEND_LAST
};
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;
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
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:
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:
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},
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
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;
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:
= 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));
&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;
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
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;
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:
= 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));
&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;
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;
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);
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);
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:
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:
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);
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 ();
}
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 ();
}
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)
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),
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;
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;
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);
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:
flags, false);
pp_right_paren (pp);
}
+ dump_omp_clauses (pp, OMP_CRITICAL_CLAUSES (node), spc, flags);
goto dump_omp_body;
case OMP_ATOMIC:
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
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;
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)
{
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;
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)
{
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);
gcc_unreachable ();
}
update_call_from_tree (&i, t);
+ gsi_next (&i);
}
}
}
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);
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
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 */
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 */
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 */
"aligned",
"depend",
"uniform",
+ "to",
+ "link",
"from",
"to",
"map",
+ "use_device_ptr",
+ "is_device_ptr",
"_cache_",
"device_resident",
"use_device",
"parallel",
"sections",
"taskgroup",
+ "priority",
+ "grainsize",
+ "num_tasks",
+ "nogroup",
+ "threads",
+ "simd",
+ "hint",
+ "defaultmap",
"_simduid_",
"_Cilk_for_count_",
"independent",
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_:
case OMP_CLAUSE_INDEPENDENT:
case OMP_CLAUSE_NOWAIT:
- case OMP_CLAUSE_ORDERED:
case OMP_CLAUSE_DEFAULT:
case OMP_CLAUSE_UNTIED:
case OMP_CLAUSE_MERGEABLE:
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));
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));
}
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]
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. */
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). */
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. */
/* 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)
#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)
#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)
#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, \
#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) \
#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) \
#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) \
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) \
#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)
#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) \
(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. */
#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)
#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)
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 &);
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. */
+2015-10-13 Jakub Jelinek <jakub@redhat.com>
+ Ilya Verbin <ilya.verbin@intel.com>
+
+ * gomp-constants.h (GOMP_MAP_FLAG_ALWAYS): Define.
+ (enum gomp_map_kind): Add GOMP_MAP_FIRSTPRIVATE,
+ GOMP_MAP_FIRSTPRIVATE_INT, GOMP_MAP_USE_DEVICE_PTR,
+ GOMP_MAP_ZERO_LEN_ARRAY_SECTION, GOMP_MAP_ALWAYS_TO,
+ GOMP_MAP_ALWAYS_FROM, GOMP_MAP_ALWAYS_TOFROM, GOMP_MAP_STRUCT,
+ GOMP_MAP_DELETE_ZERO_LEN_ARRAY_SECTION, GOMP_MAP_DELETE,
+ GOMP_MAP_RELEASE, GOMP_MAP_FIRSTPRIVATE_POINTER.
+ (GOMP_MAP_ALWAYS_TO_P, GOMP_MAP_ALWAYS_FROM_P): Define.
+ (GOMP_TASK_FLAG_UNTIED, GOMP_TASK_FLAG_FINAL, GOMP_TASK_FLAG_MERGEABLE,
+ GOMP_TASK_FLAG_DEPEND, GOMP_TASK_FLAG_PRIORITY, GOMP_TASK_FLAG_UP,
+ GOMP_TASK_FLAG_GRAINSIZE, GOMP_TASK_FLAG_IF, GOMP_TASK_FLAG_NOGROUP,
+ GOMP_TARGET_FLAG_NOWAIT, GOMP_TARGET_FLAG_EXIT_DATA,
+ GOMP_TARGET_FLAG_UPDATE): Define.
+
2015-09-28 Nathan Sidwell <nathan@codesourcery.com>
* gomp-constants.h (GOMP_VERSION_NVIDIA_PTX): Increment.
#define GOMP_MAP_FLAG_SPECIAL_1 (1 << 3)
#define GOMP_MAP_FLAG_SPECIAL (GOMP_MAP_FLAG_SPECIAL_1 \
| GOMP_MAP_FLAG_SPECIAL_0)
+/* OpenMP always flag. */
+#define GOMP_MAP_FLAG_ALWAYS (1 << 6)
/* Flag to force a specific behavior (or else, trigger a run-time error). */
#define GOMP_MAP_FLAG_FORCE (1 << 7)
/* Is a device pointer. OMP_CLAUSE_SIZE for these is unused; is implicitly
POINTER_SIZE_UNITS. */
GOMP_MAP_FORCE_DEVICEPTR = (GOMP_MAP_FLAG_SPECIAL_1 | 0),
+ /* Do not map, copy bits for firstprivate instead. */
+ GOMP_MAP_FIRSTPRIVATE = (GOMP_MAP_FLAG_SPECIAL | 0),
+ /* Similarly, but store the value in the pointer rather than
+ pointed by the pointer. */
+ GOMP_MAP_FIRSTPRIVATE_INT = (GOMP_MAP_FLAG_SPECIAL | 1),
+ /* Pointer translate host address into device address and copy that
+ back to host. */
+ GOMP_MAP_USE_DEVICE_PTR = (GOMP_MAP_FLAG_SPECIAL | 2),
+ /* Allocate a zero length array section. Prefer next non-zero length
+ mapping over previous non-zero length mapping over zero length mapping
+ at the address. If not already mapped, do nothing (and pointer translate
+ to NULL). */
+ GOMP_MAP_ZERO_LEN_ARRAY_SECTION = (GOMP_MAP_FLAG_SPECIAL | 3),
/* Allocate. */
GOMP_MAP_FORCE_ALLOC = (GOMP_MAP_FLAG_FORCE | GOMP_MAP_ALLOC),
/* ..., and copy to device. */
/* ..., and copy from device. */
GOMP_MAP_FORCE_FROM = (GOMP_MAP_FLAG_FORCE | GOMP_MAP_FROM),
/* ..., and copy to and from device. */
- GOMP_MAP_FORCE_TOFROM = (GOMP_MAP_FLAG_FORCE | GOMP_MAP_TOFROM)
+ GOMP_MAP_FORCE_TOFROM = (GOMP_MAP_FLAG_FORCE | GOMP_MAP_TOFROM),
+ /* If not already present, allocate. And unconditionally copy to
+ device. */
+ GOMP_MAP_ALWAYS_TO = (GOMP_MAP_FLAG_ALWAYS | GOMP_MAP_TO),
+ /* If not already present, allocate. And unconditionally copy from
+ device. */
+ GOMP_MAP_ALWAYS_FROM = (GOMP_MAP_FLAG_ALWAYS | GOMP_MAP_FROM),
+ /* If not already present, allocate. And unconditionally copy to and from
+ device. */
+ GOMP_MAP_ALWAYS_TOFROM = (GOMP_MAP_FLAG_ALWAYS | GOMP_MAP_TOFROM),
+ /* Map a sparse struct; the address is the base of the structure, alignment
+ it's required alignment, and size is the number of adjacent entries
+ that belong to the struct. The adjacent entries should be sorted by
+ increasing address, so it is easy to determine lowest needed address
+ (address of the first adjacent entry) and highest needed address
+ (address of the last adjacent entry plus its size). */
+ GOMP_MAP_STRUCT = (GOMP_MAP_FLAG_ALWAYS
+ | GOMP_MAP_FLAG_SPECIAL | 0),
+ /* Forced deallocation of zero length array section. */
+ GOMP_MAP_DELETE_ZERO_LEN_ARRAY_SECTION
+ = (GOMP_MAP_FLAG_ALWAYS
+ | GOMP_MAP_FLAG_SPECIAL | 3),
+ /* OpenMP 4.1 alias for forced deallocation. */
+ GOMP_MAP_DELETE = GOMP_MAP_FORCE_DEALLOC,
+ /* Decrement usage count and deallocate if zero. */
+ GOMP_MAP_RELEASE = (GOMP_MAP_FLAG_ALWAYS
+ | GOMP_MAP_FORCE_DEALLOC),
+
+ /* Internal to GCC, not used in libgomp. */
+ /* Do not map, but pointer assign a pointer instead. */
+ GOMP_MAP_FIRSTPRIVATE_POINTER = (GOMP_MAP_LAST | 1)
};
#define GOMP_MAP_COPY_TO_P(X) \
#define GOMP_MAP_POINTER_P(X) \
((X) == GOMP_MAP_POINTER)
+#define GOMP_MAP_ALWAYS_TO_P(X) \
+ (((X) == GOMP_MAP_ALWAYS_TO) || ((X) == GOMP_MAP_ALWAYS_TOFROM))
+
+#define GOMP_MAP_ALWAYS_FROM_P(X) \
+ (((X) == GOMP_MAP_ALWAYS_FROM) || ((X) == GOMP_MAP_ALWAYS_TOFROM))
+
/* Asynchronous behavior. Keep in sync with
libgomp/{openacc.h,openacc.f90,openacc_lib.h}:acc_async_t. */
#define GOMP_DEVICE_ICV -1
#define GOMP_DEVICE_HOST_FALLBACK -2
+/* GOMP_task/GOMP_taskloop* flags argument. */
+#define GOMP_TASK_FLAG_UNTIED (1 << 0)
+#define GOMP_TASK_FLAG_FINAL (1 << 1)
+#define GOMP_TASK_FLAG_MERGEABLE (1 << 2)
+#define GOMP_TASK_FLAG_DEPEND (1 << 3)
+#define GOMP_TASK_FLAG_PRIORITY (1 << 4)
+#define GOMP_TASK_FLAG_UP (1 << 8)
+#define GOMP_TASK_FLAG_GRAINSIZE (1 << 9)
+#define GOMP_TASK_FLAG_IF (1 << 10)
+#define GOMP_TASK_FLAG_NOGROUP (1 << 11)
+
+/* GOMP_target{_41,update_41,enter_exit_data} flags argument. */
+#define GOMP_TARGET_FLAG_NOWAIT (1 << 0)
+#define GOMP_TARGET_FLAG_EXIT_DATA (1 << 1)
+/* Internal to libgomp. */
+#define GOMP_TARGET_FLAG_UPDATE (1U << 31)
+
/* Versions of libgomp and device-specific plugins. */
#define GOMP_VERSION 0
#define GOMP_VERSION_NVIDIA_PTX 1
+2015-10-13 Jakub Jelinek <jakub@redhat.com>
+ Aldy Hernandez <aldyh@redhat.com>
+ Ilya Verbin <ilya.verbin@intel.com>
+
+ * config/linux/affinity.c (omp_get_place_num_procs,
+ omp_get_place_proc_ids, gomp_get_place_proc_ids_8): New functions.
+ * config/linux/doacross.h: New file.
+ * config/posix/affinity.c (omp_get_place_num_procs,
+ omp_get_place_proc_ids, gomp_get_place_proc_ids_8): New functions.
+ * config/posix/doacross.h: New file.
+ * env.c: Include gomp-constants.h.
+ (struct gomp_task_icv): Rename run_sched_modifier to
+ run_sched_chunk_size.
+ (gomp_max_task_priority_var): New variable.
+ (parse_schedule): Rename run_sched_modifier to run_sched_chunk_size.
+ (handle_omp_display_env): Change _OPENMP value from 201307 to
+ 201511. Print OMP_MAX_TASK_PRIORITY.
+ (initialize_env): Parse OMP_MAX_TASK_PRIORITY.
+ (omp_set_schedule, omp_get_schedule): Rename modifier argument to
+ chunk_size and run_sched_modifier to run_sched_chunk_size.
+ (omp_get_max_task_priority, omp_get_initial_device,
+ omp_get_num_places, omp_get_place_num, omp_get_partition_num_places,
+ omp_get_partition_place_nums): New functions.
+ * fortran.c (omp_set_schedule_, omp_set_schedule_8_,
+ omp_get_schedule_, omp_get_schedule_8_): Rename modifier argument
+ to chunk_size.
+ (omp_get_num_places_, omp_get_place_num_procs_,
+ omp_get_place_num_procs_8_, omp_get_place_proc_ids_,
+ omp_get_place_proc_ids_8_, omp_get_place_num_,
+ omp_get_partition_num_places_, omp_get_partition_place_nums_,
+ omp_get_partition_place_nums_8_, omp_get_initial_device_,
+ omp_get_max_task_priority_): New functions.
+ * libgomp_g.h (GOMP_loop_doacross_static_start,
+ GOMP_loop_doacross_dynamic_start, GOMP_loop_doacross_guided_start,
+ GOMP_loop_doacross_runtime_start, GOMP_loop_ull_doacross_static_start,
+ GOMP_loop_ull_doacross_dynamic_start,
+ GOMP_loop_ull_doacross_guided_start,
+ GOMP_loop_ull_doacross_runtime_start, GOMP_doacross_post,
+ GOMP_doacross_wait, GOMP_doacross_ull_post, GOMP_doacross_wait,
+ GOMP_taskloop, GOMP_taskloop_ull, GOMP_target_41,
+ GOMP_target_data_41, GOMP_target_update_41,
+ GOMP_target_enter_exit_data): New prototypes.
+ (GOMP_task): Add prototype argument.
+ * libgomp.h (_LIBGOMP_CHECKING_): Define to 0 if not yet defined.
+ (struct gomp_doacross_work_share): New type.
+ (struct gomp_work_share): Add doacross field.
+ (struct gomp_task_icv): Rename run_sched_modifier to
+ run_sched_chunk_size.
+ (enum gomp_task_kind): Rename GOMP_TASK_IFFALSE to
+ GOMP_TASK_UNDEFERRED. Add comments.
+ (struct gomp_task_depend_entry): Add comments.
+ (struct gomp_task): Likewise.
+ (struct gomp_taskgroup): Likewise.
+ (struct gomp_target_task): New type.
+ (struct gomp_team): Add comment.
+ (gomp_get_place_proc_ids_8, gomp_doacross_init,
+ gomp_doacross_ull_init, gomp_task_maybe_wait_for_dependencies,
+ gomp_create_target_task, gomp_target_task_fn): New prototypes.
+ (struct target_var_desc): New type.
+ (struct target_mem_desc): Adjust comment. Use struct
+ target_var_desc instead of splay_tree_key for list.
+ (REFCOUNT_INFINITY): Define.
+ (struct splay_tree_key_s): Remove copy_from field.
+ (struct gomp_device_descr): Add dev2dev_func field.
+ (enum gomp_map_vars_kind): New enum.
+ (gomp_map_vars): Add one argument.
+ * libgomp.map (OMP_4.5): Export omp_get_max_task_priority,
+ omp_get_max_task_priority_, omp_get_num_places, omp_get_num_places_,
+ omp_get_place_num_procs, omp_get_place_num_procs_,
+ omp_get_place_num_procs_8_, omp_get_place_proc_ids,
+ omp_get_place_proc_ids_, omp_get_place_proc_ids_8_, omp_get_place_num,
+ omp_get_place_num_, omp_get_partition_num_places,
+ omp_get_partition_num_places_, omp_get_partition_place_nums,
+ omp_get_partition_place_nums_, omp_get_partition_place_nums_8_,
+ omp_get_initial_device, omp_get_initial_device_, omp_target_alloc,
+ omp_target_free, omp_target_is_present, omp_target_memcpy,
+ omp_target_memcpy_rect, omp_target_associate_ptr and
+ omp_target_disassociate_ptr.
+ (GOMP_4.0.2): Renamed to ...
+ (GOMP_4.5): ... this. Export GOMP_target_41, GOMP_target_data_41,
+ GOMP_target_update_41, GOMP_target_enter_exit_data, GOMP_taskloop,
+ GOMP_taskloop_ull, GOMP_loop_doacross_dynamic_start,
+ GOMP_loop_doacross_guided_start, GOMP_loop_doacross_runtime_start,
+ GOMP_loop_doacross_static_start, GOMP_doacross_post,
+ GOMP_doacross_wait, GOMP_loop_ull_doacross_dynamic_start,
+ GOMP_loop_ull_doacross_guided_start,
+ GOMP_loop_ull_doacross_runtime_start,
+ GOMP_loop_ull_doacross_static_start, GOMP_doacross_ull_post and
+ GOMP_doacross_ull_wait.
+ * libgomp.texi: Document omp_get_max_task_priority.
+ Rename modifier argument to chunk_size for omp_set_schedule and
+ omp_get_schedule. Document OMP_MAX_TASK_PRIORITY env var.
+ * loop.c (GOMP_loop_runtime_start): Adjust for run_sched_modifier
+ to run_sched_chunk_size renaming.
+ (GOMP_loop_ordered_runtime_start): Likewise.
+ (gomp_loop_doacross_static_start, gomp_loop_doacross_dynamic_start,
+ gomp_loop_doacross_guided_start, GOMP_loop_doacross_runtime_start,
+ GOMP_parallel_loop_runtime_start): New functions.
+ (GOMP_parallel_loop_runtime): Adjust for run_sched_modifier
+ to run_sched_chunk_size renaming.
+ (GOMP_loop_doacross_static_start, GOMP_loop_doacross_dynamic_start,
+ GOMP_loop_doacross_guided_start): New functions or aliases.
+ * loop_ull.c (GOMP_loop_ull_runtime_start): Adjust for
+ run_sched_modifier to run_sched_chunk_size renaming.
+ (GOMP_loop_ull_ordered_runtime_start): Likewise.
+ (gomp_loop_ull_doacross_static_start,
+ gomp_loop_ull_doacross_dynamic_start,
+ gomp_loop_ull_doacross_guided_start,
+ GOMP_loop_ull_doacross_runtime_start): New functions.
+ (GOMP_loop_ull_doacross_static_start,
+ GOMP_loop_ull_doacross_dynamic_start,
+ GOMP_loop_ull_doacross_guided_start): New functions or aliases.
+ * oacc-mem.c (acc_map_data, present_create_copy,
+ gomp_acc_insert_pointer): Pass GOMP_MAP_VARS_OPENACC instead of false
+ to gomp_map_vars.
+ (gomp_acc_remove_pointer): Use copy_from from target_var_desc.
+ * oacc-parallel.c (GOACC_data_start): Pass GOMP_MAP_VARS_OPENACC
+ instead of false to gomp_map_vars.
+ (GOACC_parallel_keyed): Likewise. Use copy_from from target_var_desc.
+ * omp.h.in (omp_lock_hint_t): New type.
+ (omp_init_lock_with_hint, omp_init_nest_lock_with_hint,
+ omp_get_num_places, omp_get_place_num_procs, omp_get_place_proc_ids,
+ omp_get_place_num, omp_get_partition_num_places,
+ omp_get_partition_place_nums, omp_get_initial_device,
+ omp_get_max_task_priority, omp_target_alloc, omp_target_free,
+ omp_target_is_present, omp_target_memcpy, omp_target_memcpy_rect,
+ omp_target_associate_ptr, omp_target_disassociate_ptr): New
+ prototypes.
+ * omp_lib.f90.in (omp_lock_hint_kind): New parameter.
+ (omp_lock_hint_none, omp_lock_hint_uncontended,
+ omp_lock_hint_contended, omp_lock_hint_nonspeculative,
+ omp_lock_hint_speculative): New parameters.
+ (omp_init_lock_with_hint, omp_init_nest_lock_with_hint,
+ omp_get_num_places, omp_get_place_num_procs, omp_get_place_proc_ids,
+ omp_get_place_num, omp_get_partition_num_places,
+ omp_get_partition_place_nums, omp_get_initial_device,
+ omp_get_max_task_priority): New interfaces.
+ (omp_set_schedule, omp_get_schedule): Rename modifier argument
+ to chunk_size.
+ * omp_lib.h.in (omp_lock_hint_kind): New parameter.
+ (omp_lock_hint_none, omp_lock_hint_uncontended,
+ omp_lock_hint_contended, omp_lock_hint_nonspeculative,
+ omp_lock_hint_speculative): New parameters.
+ (omp_init_lock_with_hint, omp_init_nest_lock_with_hint,
+ omp_get_num_places, omp_get_place_num_procs, omp_get_place_proc_ids,
+ omp_get_place_num, omp_get_partition_num_places,
+ omp_get_partition_place_nums, omp_get_initial_device,
+ omp_get_max_task_priority): New functions and subroutines.
+ * ordered.c: Include stdarg.h and string.h.
+ (MAX_COLLAPSED_BITS): Define.
+ (gomp_doacross_init, GOMP_doacross_post, GOMP_doacross_wait,
+ gomp_doacross_ull_init, GOMP_doacross_ull_post,
+ GOMP_doacross_ull_wait): New functions.
+ * target.c: Include errno.h.
+ (resolve_device): If device is not initialized, call
+ gomp_init_device on it.
+ (gomp_map_lookup): New function.
+ (gomp_map_vars_existing): Add tgt_var argument, fill it in.
+ Don't bump refcount if REFCOUNT_INFINITY. Handle
+ GOMP_MAP_ALWAYS_TO_P.
+ (get_kind): Rename is_openacc argument to short_mapkind.
+ (gomp_map_pointer): Use gomp_map_lookup.
+ (gomp_map_fields_existing): New function.
+ (gomp_map_vars): Rename is_openacc argument to short_mapkind
+ and is_target to pragma_kind. Handle GOMP_MAP_VARS_ENTER_DATA,
+ handle GOMP_MAP_FIRSTPRIVATE_INT, GOMP_MAP_STRUCT,
+ GOMP_MAP_USE_DEVICE_PTR, GOMP_MAP_ZERO_LEN_ARRAY_SECTION.
+ Adjust for tgt->list changed type and copy_from living in there.
+ (gomp_copy_from_async): Adjust for tgt->list changed type and
+ copy_from living in there.
+ (gomp_unmap_vars): Likewise.
+ (gomp_update): Likewise. Rename is_openacc argument to
+ short_mapkind. Don't fail if object is not mapped.
+ (gomp_load_image_to_device): Initialize refcount to
+ REFCOUNT_INFINITY.
+ (gomp_target_fallback): New function.
+ (gomp_get_target_fn_addr): Likewise.
+ (GOMP_target): Adjust gomp_map_vars caller, use
+ gomp_get_target_fn_addr and gomp_target_fallback.
+ (GOMP_target_41): New function.
+ (gomp_target_data_fallback): New function.
+ (GOMP_target_data): Use it, adjust gomp_map_vars caller.
+ (GOMP_target_data_41): New function.
+ (GOMP_target_update): Adjust gomp_update caller.
+ (GOMP_target_update_41): New function.
+ (gomp_exit_data, GOMP_target_enter_exit_data,
+ gomp_target_task_fn, omp_target_alloc, omp_target_free,
+ omp_target_is_present, omp_target_memcpy,
+ omp_target_memcpy_rect_worker, omp_target_memcpy_rect,
+ omp_target_associate_ptr, omp_target_disassociate_ptr,
+ gomp_load_plugin_for_device): New functions.
+ * task.c: Include gomp-constants.h. Include taskloop.c
+ twice to get GOMP_taskloop and GOMP_taskloop_ull definitions.
+ (gomp_task_handle_depend): New function.
+ (GOMP_task): Use it. Add priority argument. Use
+ gomp-constant.h constants instead of hardcoded numbers.
+ Rename GOMP_TASK_IFFALSE to GOMP_TASK_UNDEFERRED.
+ (gomp_create_target_task): New function.
+ (verify_children_queue, verify_taskgroup_queue,
+ verify_task_queue): New functions.
+ (gomp_task_run_pre): Call verify_*_queue functions.
+ If an upcoming tied task is about to leave the sibling or
+ taskgroup queues in an invalid state, adjust appropriately.
+ Remove taskgroup argument. Add comments.
+ (gomp_task_run_post_handle_dependers): Add comments.
+ (gomp_task_run_post_remove_parent): Likewise.
+ (gomp_barrier_handle_tasks): Adjust gomp_task_run_pre caller.
+ (GOMP_taskwait): Likewise. Add comments.
+ (gomp_task_maybe_wait_for_dependencies): Fix scheduling
+ problem such that the first non parent_depends_on task does not
+ end up at the end of the children queue.
+ (GOMP_taskgroup_start): Rename GOMP_TASK_IFFALSE to
+ GOMP_TASK_UNDEFERRED.
+ (GOMP_taskgroup_end): Adjust gomp_task_run_pre caller.
+ * taskloop.c: New file.
+ * testsuite/lib/libgomp.exp
+ (check_effective_target_offload_device_nonshared_as): New proc.
+ * testsuite/libgomp.c/affinity-2.c: New test.
+ * testsuite/libgomp.c/doacross-1.c: New test.
+ * testsuite/libgomp.c/doacross-2.c: New test.
+ * testsuite/libgomp.c/examples-4/declare_target-1.c (fib_wrapper):
+ Add map clause to target.
+ * testsuite/libgomp.c/examples-4/declare_target-4.c (accum): Likewise.
+ * testsuite/libgomp.c/examples-4/declare_target-5.c (accum): Likewise.
+ * testsuite/libgomp.c/examples-4/device-1.c (main): Likewise.
+ * testsuite/libgomp.c/examples-4/device-3.c (main): Likewise.
+ * testsuite/libgomp.c/examples-4/target_data-3.c (gramSchmidt):
+ Likewise.
+ * testsuite/libgomp.c/examples-4/teams-2.c (dotprod): Likewise.
+ * testsuite/libgomp.c/examples-4/teams-3.c (dotprod): Likewise.
+ * testsuite/libgomp.c/examples-4/teams-4.c (dotprod): Likewise.
+ * testsuite/libgomp.c/for-2.h (OMPTGT, OMPTO, OMPFROM): Define if
+ not defined. Use those where needed.
+ * testsuite/libgomp.c/for-4.c: New test.
+ * testsuite/libgomp.c/for-5.c: New test.
+ * testsuite/libgomp.c/for-6.c: New test.
+ * testsuite/libgomp.c/linear-1.c: New test.
+ * testsuite/libgomp.c/ordered-4.c: New test.
+ * testsuite/libgomp.c/pr66199-2.c (f2): Adjust for linear clause
+ only allowed on the loop iterator.
+ * testsuite/libgomp.c/pr66199-3.c: New test.
+ * testsuite/libgomp.c/pr66199-4.c: New test.
+ * testsuite/libgomp.c/reduction-7.c: New test.
+ * testsuite/libgomp.c/reduction-8.c: New test.
+ * testsuite/libgomp.c/reduction-9.c: New test.
+ * testsuite/libgomp.c/reduction-10.c: New test.
+ * testsuite/libgomp.c/target-1.c (fn2, fn3, fn4): Add
+ map(tofrom:s).
+ * testsuite/libgomp.c/target-2.c (fn2, fn3, fn4): Likewise.
+ * testsuite/libgomp.c/target-7.c (foo): Add map(h) where needed.
+ * testsuite/libgomp.c/target-11.c: New test.
+ * testsuite/libgomp.c/target-12.c: New test.
+ * testsuite/libgomp.c/target-13.c: New test.
+ * testsuite/libgomp.c/target-14.c: New test.
+ * testsuite/libgomp.c/target-15.c: New test.
+ * testsuite/libgomp.c/target-16.c: New test.
+ * testsuite/libgomp.c/target-17.c: New test.
+ * testsuite/libgomp.c/target-18.c: New test.
+ * testsuite/libgomp.c/target-19.c: New test.
+ * testsuite/libgomp.c/target-20.c: New test.
+ * testsuite/libgomp.c/target-21.c: New test.
+ * testsuite/libgomp.c/target-22.c: New test.
+ * testsuite/libgomp.c/target-23.c: New test.
+ * testsuite/libgomp.c/target-24.c: New test.
+ * testsuite/libgomp.c/target-25.c: New test.
+ * testsuite/libgomp.c/target-26.c: New test.
+ * testsuite/libgomp.c/target-27.c: New test.
+ * testsuite/libgomp.c/taskloop-1.c: New test.
+ * testsuite/libgomp.c/taskloop-2.c: New test.
+ * testsuite/libgomp.c/taskloop-3.c: New test.
+ * testsuite/libgomp.c/taskloop-4.c: New test.
+ * testsuite/libgomp.c++/ctor-13.C: New test.
+ * testsuite/libgomp.c++/doacross-1.C: New test.
+ * testsuite/libgomp.c++/examples-4/declare_target-2.C:
+ Replace offload_device with offload_device_nonshared_as.
+ * testsuite/libgomp.c++/for-12.C: New test.
+ * testsuite/libgomp.c++/for-13.C: New test.
+ * testsuite/libgomp.c++/for-14.C: New test.
+ * testsuite/libgomp.c++/linear-1.C: New test.
+ * testsuite/libgomp.c++/member-1.C: New test.
+ * testsuite/libgomp.c++/member-2.C: New test.
+ * testsuite/libgomp.c++/member-3.C: New test.
+ * testsuite/libgomp.c++/member-4.C: New test.
+ * testsuite/libgomp.c++/member-5.C: New test.
+ * testsuite/libgomp.c++/ordered-1.C: New test.
+ * testsuite/libgomp.c++/reduction-5.C: New test.
+ * testsuite/libgomp.c++/reduction-6.C: New test.
+ * testsuite/libgomp.c++/reduction-7.C: New test.
+ * testsuite/libgomp.c++/reduction-8.C: New test.
+ * testsuite/libgomp.c++/reduction-9.C: New test.
+ * testsuite/libgomp.c++/reduction-10.C: New test.
+ * testsuite/libgomp.c++/reference-1.C: New test.
+ * testsuite/libgomp.c++/simd14.C: New test.
+ * testsuite/libgomp.c++/target-2.C (fn2): Add map(tofrom: s) clause.
+ * testsuite/libgomp.c++/target-5.C: New test.
+ * testsuite/libgomp.c++/target-6.C: New test.
+ * testsuite/libgomp.c++/target-7.C: New test.
+ * testsuite/libgomp.c++/target-8.C: New test.
+ * testsuite/libgomp.c++/target-9.C: New test.
+ * testsuite/libgomp.c++/target-10.C: New test.
+ * testsuite/libgomp.c++/target-11.C: New test.
+ * testsuite/libgomp.c++/target-12.C: New test.
+ * testsuite/libgomp.c++/taskloop-1.C: New test.
+ * testsuite/libgomp.c++/taskloop-2.C: New test.
+ * testsuite/libgomp.c++/taskloop-3.C: New test.
+ * testsuite/libgomp.c++/taskloop-4.C: New test.
+ * testsuite/libgomp.c++/taskloop-5.C: New test.
+ * testsuite/libgomp.c++/taskloop-6.C: New test.
+ * testsuite/libgomp.c++/taskloop-7.C: New test.
+ * testsuite/libgomp.c++/taskloop-8.C: New test.
+ * testsuite/libgomp.c++/taskloop-9.C: New test.
+ * testsuite/libgomp.fortran/affinity1.f90: New test.
+ * testsuite/libgomp.fortran/affinity2.f90: New test.
+
2015-10-13 Tom de Vries <tom@codesourcery.com>
PR tree-optimization/67476
fprintf (stderr, ":%lu", len);
}
+int
+omp_get_place_num_procs (int place_num)
+{
+ if (place_num < 0 || place_num >= gomp_places_list_len)
+ return 0;
+
+ cpu_set_t *cpusetp = (cpu_set_t *) gomp_places_list[place_num];
+ return gomp_cpuset_popcount (gomp_cpuset_size, cpusetp);
+}
+
+void
+omp_get_place_proc_ids (int place_num, int *ids)
+{
+ if (place_num < 0 || place_num >= gomp_places_list_len)
+ return;
+
+ cpu_set_t *cpusetp = (cpu_set_t *) gomp_places_list[place_num];
+ unsigned long i, max = 8 * gomp_cpuset_size;
+ for (i = 0; i < max; i++)
+ if (CPU_ISSET_S (i, gomp_cpuset_size, cpusetp))
+ *ids++ = i;
+}
+
+void
+gomp_get_place_proc_ids_8 (int place_num, int64_t *ids)
+{
+ if (place_num < 0 || place_num >= gomp_places_list_len)
+ return;
+
+ cpu_set_t *cpusetp = (cpu_set_t *) gomp_places_list[place_num];
+ unsigned long i, max = 8 * gomp_cpuset_size;
+ for (i = 0; i < max; i++)
+ if (CPU_ISSET_S (i, gomp_cpuset_size, cpusetp))
+ *ids++ = i;
+}
+
+ialias(omp_get_place_num_procs)
+ialias(omp_get_place_proc_ids)
+
#else
#include "../posix/affinity.c"
--- /dev/null
+/* Copyright (C) 2015 Free Software Foundation, Inc.
+ Contributed by Jakub Jelinek <jakub@redhat.com>.
+
+ This file is part of the GNU Offloading and Multi Processing Library
+ (libgomp).
+
+ Libgomp is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This is a Linux specific implementation of doacross spinning. */
+
+#ifndef GOMP_DOACROSS_H
+#define GOMP_DOACROSS_H 1
+
+#include "libgomp.h"
+#include <errno.h>
+#include "wait.h"
+
+#ifdef HAVE_ATTRIBUTE_VISIBILITY
+# pragma GCC visibility push(hidden)
+#endif
+
+static inline void doacross_spin (unsigned long *addr, unsigned long expected,
+ unsigned long cur)
+{
+ /* FIXME: back off depending on how large expected - cur is. */
+ do
+ {
+ cpu_relax ();
+ cur = __atomic_load_n (addr, MEMMODEL_RELAXED);
+ if (expected < cur)
+ return;
+ }
+ while (1);
+}
+
+#ifdef HAVE_ATTRIBUTE_VISIBILITY
+# pragma GCC visibility pop
+#endif
+
+#endif /* GOMP_DOACROSS_H */
{
(void) p;
}
+
+int
+omp_get_place_num_procs (int place_num)
+{
+ (void) place_num;
+ return 0;
+}
+
+void
+omp_get_place_proc_ids (int place_num, int *ids)
+{
+ (void) place_num;
+ (void) ids;
+}
+
+void
+gomp_get_place_proc_ids_8 (int place_num, int64_t *ids)
+{
+ (void) place_num;
+ (void) ids;
+}
+
+ialias(omp_get_place_num_procs)
+ialias(omp_get_place_proc_ids)
--- /dev/null
+/* Copyright (C) 2015 Free Software Foundation, Inc.
+ Contributed by Jakub Jelinek <jakub@redhat.com>.
+
+ This file is part of the GNU Offloading and Multi Processing Library
+ (libgomp).
+
+ Libgomp is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This is a generic implementation of doacross spinning. */
+
+#ifndef GOMP_DOACROSS_H
+#define GOMP_DOACROSS_H 1
+
+#include "libgomp.h"
+#include <errno.h>
+
+#ifdef HAVE_ATTRIBUTE_VISIBILITY
+# pragma GCC visibility push(hidden)
+#endif
+
+static inline void
+cpu_relax (void)
+{
+ __asm volatile ("" : : : "memory");
+}
+
+static inline void doacross_spin (unsigned long *addr, unsigned long expected,
+ unsigned long cur)
+{
+ /* FIXME: back off depending on how large expected - cur is. */
+ do
+ {
+ cpu_relax ();
+ cur = __atomic_load_n (addr, MEMMODEL_RELAXED);
+ if (expected < cur)
+ return;
+ }
+ while (1);
+}
+
+#ifdef HAVE_ATTRIBUTE_VISIBILITY
+# pragma GCC visibility pop
+#endif
+
+#endif /* GOMP_DOACROSS_H */
#include "libgomp.h"
#include "libgomp_f.h"
#include "oacc-int.h"
+#include "gomp-constants.h"
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
.nthreads_var = 1,
.thread_limit_var = UINT_MAX,
.run_sched_var = GFS_DYNAMIC,
- .run_sched_modifier = 1,
+ .run_sched_chunk_size = 1,
.default_device_var = 0,
.dyn_var = false,
.nest_var = false,
unsigned long gomp_max_active_levels_var = INT_MAX;
bool gomp_cancel_var = false;
+int gomp_max_task_priority_var = 0;
#ifndef HAVE_SYNC_BUILTINS
gomp_mutex_t gomp_managed_threads_lock;
#endif
++env;
if (*env == '\0')
{
- gomp_global_icv.run_sched_modifier
+ gomp_global_icv.run_sched_chunk_size
= gomp_global_icv.run_sched_var != GFS_STATIC;
return;
}
if (value == 0 && gomp_global_icv.run_sched_var != GFS_STATIC)
value = 1;
- gomp_global_icv.run_sched_modifier = value;
+ gomp_global_icv.run_sched_chunk_size = value;
return;
unknown:
fputs ("\nOPENMP DISPLAY ENVIRONMENT BEGIN\n", stderr);
- fputs (" _OPENMP = '201307'\n", stderr);
+ fputs (" _OPENMP = '201511'\n", stderr);
fprintf (stderr, " OMP_DYNAMIC = '%s'\n",
gomp_global_icv.dyn_var ? "TRUE" : "FALSE");
fprintf (stderr, " OMP_NESTED = '%s'\n",
gomp_cancel_var ? "TRUE" : "FALSE");
fprintf (stderr, " OMP_DEFAULT_DEVICE = '%d'\n",
gomp_global_icv.default_device_var);
+ fprintf (stderr, " OMP_MAX_TASK_PRIORITY = '%d'\n",
+ gomp_max_task_priority_var);
if (verbose)
{
parse_boolean ("OMP_NESTED", &gomp_global_icv.nest_var);
parse_boolean ("OMP_CANCELLATION", &gomp_cancel_var);
parse_int ("OMP_DEFAULT_DEVICE", &gomp_global_icv.default_device_var, true);
+ parse_int ("OMP_MAX_TASK_PRIORITY", &gomp_max_task_priority_var, true);
parse_unsigned_long ("OMP_MAX_ACTIVE_LEVELS", &gomp_max_active_levels_var,
true);
if (parse_unsigned_long ("OMP_THREAD_LIMIT", &thread_limit_var, false))
}
void
-omp_set_schedule (omp_sched_t kind, int modifier)
+omp_set_schedule (omp_sched_t kind, int chunk_size)
{
struct gomp_task_icv *icv = gomp_icv (true);
switch (kind)
{
case omp_sched_static:
- if (modifier < 1)
- modifier = 0;
- icv->run_sched_modifier = modifier;
+ if (chunk_size < 1)
+ chunk_size = 0;
+ icv->run_sched_chunk_size = chunk_size;
break;
case omp_sched_dynamic:
case omp_sched_guided:
- if (modifier < 1)
- modifier = 1;
- icv->run_sched_modifier = modifier;
+ if (chunk_size < 1)
+ chunk_size = 1;
+ icv->run_sched_chunk_size = chunk_size;
break;
case omp_sched_auto:
break;
}
void
-omp_get_schedule (omp_sched_t *kind, int *modifier)
+omp_get_schedule (omp_sched_t *kind, int *chunk_size)
{
struct gomp_task_icv *icv = gomp_icv (false);
*kind = icv->run_sched_var;
- *modifier = icv->run_sched_modifier;
+ *chunk_size = icv->run_sched_chunk_size;
}
int
return gomp_cancel_var;
}
+int
+omp_get_max_task_priority (void)
+{
+ return gomp_max_task_priority_var;
+}
+
omp_proc_bind_t
omp_get_proc_bind (void)
{
return 1;
}
+int
+omp_get_initial_device (void)
+{
+ return GOMP_DEVICE_HOST_FALLBACK;
+}
+
+int
+omp_get_num_places (void)
+{
+ return gomp_places_list_len;
+}
+
+int
+omp_get_place_num (void)
+{
+ if (gomp_places_list == NULL)
+ return -1;
+
+ struct gomp_thread *thr = gomp_thread ();
+ if (thr->place == 0)
+ gomp_init_affinity ();
+
+ return (int) thr->place - 1;
+}
+
+int
+omp_get_partition_num_places (void)
+{
+ if (gomp_places_list == NULL)
+ return 0;
+
+ struct gomp_thread *thr = gomp_thread ();
+ if (thr->place == 0)
+ gomp_init_affinity ();
+
+ return thr->ts.place_partition_len;
+}
+
+void
+omp_get_partition_place_nums (int *place_nums)
+{
+ if (gomp_places_list == NULL)
+ return;
+
+ struct gomp_thread *thr = gomp_thread ();
+ if (thr->place == 0)
+ gomp_init_affinity ();
+
+ unsigned int i;
+ for (i = 0; i < thr->ts.place_partition_len; i++)
+ *place_nums++ = thr->ts.place_partition_off + i;
+}
+
ialias (omp_set_dynamic)
ialias (omp_set_nested)
ialias (omp_set_num_threads)
ialias (omp_get_num_teams)
ialias (omp_get_team_num)
ialias (omp_is_initial_device)
+ialias (omp_get_initial_device)
+ialias (omp_get_max_task_priority)
+ialias (omp_get_num_places)
+ialias (omp_get_place_num)
+ialias (omp_get_partition_num_places)
+ialias (omp_get_partition_place_nums)
ialias_redirect (omp_in_final)
ialias_redirect (omp_get_cancellation)
ialias_redirect (omp_get_proc_bind)
+ialias_redirect (omp_get_num_places)
+ialias_redirect (omp_get_place_num_procs)
+ialias_redirect (omp_get_place_proc_ids)
+ialias_redirect (omp_get_place_num)
+ialias_redirect (omp_get_partition_num_places)
+ialias_redirect (omp_get_partition_place_nums)
ialias_redirect (omp_set_default_device)
ialias_redirect (omp_get_default_device)
ialias_redirect (omp_get_num_devices)
ialias_redirect (omp_get_num_teams)
ialias_redirect (omp_get_team_num)
ialias_redirect (omp_is_initial_device)
+ialias_redirect (omp_get_initial_device)
+ialias_redirect (omp_get_max_task_priority)
#endif
#ifndef LIBGOMP_GNU_SYMBOL_VERSIONING
}
void
-omp_set_schedule_ (const int32_t *kind, const int32_t *modifier)
+omp_set_schedule_ (const int32_t *kind, const int32_t *chunk_size)
{
- omp_set_schedule (*kind, *modifier);
+ omp_set_schedule (*kind, *chunk_size);
}
void
-omp_set_schedule_8_ (const int32_t *kind, const int64_t *modifier)
+omp_set_schedule_8_ (const int32_t *kind, const int64_t *chunk_size)
{
- omp_set_schedule (*kind, TO_INT (*modifier));
+ omp_set_schedule (*kind, TO_INT (*chunk_size));
}
void
-omp_get_schedule_ (int32_t *kind, int32_t *modifier)
+omp_get_schedule_ (int32_t *kind, int32_t *chunk_size)
{
omp_sched_t k;
- int m;
- omp_get_schedule (&k, &m);
+ int cs;
+ omp_get_schedule (&k, &cs);
*kind = k;
- *modifier = m;
+ *chunk_size = cs;
}
void
-omp_get_schedule_8_ (int32_t *kind, int64_t *modifier)
+omp_get_schedule_8_ (int32_t *kind, int64_t *chunk_size)
{
omp_sched_t k;
- int m;
- omp_get_schedule (&k, &m);
+ int cs;
+ omp_get_schedule (&k, &cs);
*kind = k;
- *modifier = m;
+ *chunk_size = cs;
}
int32_t
return omp_get_proc_bind ();
}
+int32_t
+omp_get_num_places_ (void)
+{
+ return omp_get_num_places ();
+}
+
+int32_t
+omp_get_place_num_procs_ (const int32_t *place_num)
+{
+ return omp_get_place_num_procs (*place_num);
+}
+
+int32_t
+omp_get_place_num_procs_8_ (const int64_t *place_num)
+{
+ return omp_get_place_num_procs (TO_INT (*place_num));
+}
+
+void
+omp_get_place_proc_ids_ (const int32_t *place_num, int32_t *ids)
+{
+ omp_get_place_proc_ids (*place_num, ids);
+}
+
+void
+omp_get_place_proc_ids_8_ (const int64_t *place_num, int64_t *ids)
+{
+ gomp_get_place_proc_ids_8 (TO_INT (*place_num), ids);
+}
+
+int32_t
+omp_get_place_num_ (void)
+{
+ return omp_get_place_num ();
+}
+
+int32_t
+omp_get_partition_num_places_ (void)
+{
+ return omp_get_partition_num_places ();
+}
+
+void
+omp_get_partition_place_nums_ (int32_t *place_nums)
+{
+ omp_get_partition_place_nums (place_nums);
+}
+
+void
+omp_get_partition_place_nums_8_ (int64_t *place_nums)
+{
+ if (gomp_places_list == NULL)
+ return;
+
+ struct gomp_thread *thr = gomp_thread ();
+ if (thr->place == 0)
+ gomp_init_affinity ();
+
+ unsigned int i;
+ for (i = 0; i < thr->ts.place_partition_len; i++)
+ *place_nums++ = (int64_t) thr->ts.place_partition_off + i;
+}
+
void
omp_set_default_device_ (const int32_t *device_num)
{
{
return omp_is_initial_device ();
}
+
+int32_t
+omp_get_initial_device_ (void)
+{
+ return omp_get_initial_device ();
+}
+
+int32_t
+omp_get_max_task_priority_ (void)
+{
+ return omp_get_max_task_priority ();
+}
#ifndef LIBGOMP_H
#define LIBGOMP_H 1
+#ifndef _LIBGOMP_CHECKING_
+/* Define to 1 to perform internal sanity checks. */
+#define _LIBGOMP_CHECKING_ 0
+#endif
+
#include "config.h"
#include "gstdint.h"
#include "libgomp-plugin.h"
GFS_AUTO
};
+struct gomp_doacross_work_share
+{
+ union {
+ /* chunk_size copy, as ws->chunk_size is multiplied by incr for
+ GFS_DYNAMIC. */
+ long chunk_size;
+ /* Likewise, but for ull implementation. */
+ unsigned long long chunk_size_ull;
+ /* For schedule(static,0) this is the number
+ of iterations assigned to the last thread, i.e. number of
+ iterations / number of threads. */
+ long q;
+ /* Likewise, but for ull implementation. */
+ unsigned long long q_ull;
+ };
+ /* Size of each array entry (padded to cache line size). */
+ unsigned long elt_sz;
+ /* Number of dimensions in sink vectors. */
+ unsigned int ncounts;
+ /* True if the iterations can be flattened. */
+ bool flattened;
+ /* Actual array (of elt_sz sized units), aligned to cache line size.
+ This is indexed by team_id for GFS_STATIC and outermost iteration
+ / chunk_size for other schedules. */
+ unsigned char *array;
+ /* These two are only used for schedule(static,0). */
+ /* This one is number of iterations % number of threads. */
+ long t;
+ union {
+ /* And this one is cached t * (q + 1). */
+ long boundary;
+ /* Likewise, but for the ull implementation. */
+ unsigned long long boundary_ull;
+ };
+ /* Array of shift counts for each dimension if they can be flattened. */
+ unsigned int shift_counts[];
+};
+
struct gomp_work_share
{
/* This member records the SCHEDULE clause to be used for this construct.
};
};
- /* This is a circular queue that details which threads will be allowed
- into the ordered region and in which order. When a thread allocates
- iterations on which it is going to work, it also registers itself at
- the end of the array. When a thread reaches the ordered region, it
- checks to see if it is the one at the head of the queue. If not, it
- blocks on its RELEASE semaphore. */
- unsigned *ordered_team_ids;
+ union {
+ /* This is a circular queue that details which threads will be allowed
+ into the ordered region and in which order. When a thread allocates
+ iterations on which it is going to work, it also registers itself at
+ the end of the array. When a thread reaches the ordered region, it
+ checks to see if it is the one at the head of the queue. If not, it
+ blocks on its RELEASE semaphore. */
+ unsigned *ordered_team_ids;
+
+ /* This is a pointer to DOACROSS work share data. */
+ struct gomp_doacross_work_share *doacross;
+ };
/* This is the number of threads that have registered themselves in
the circular queue ordered_team_ids. */
{
unsigned long nthreads_var;
enum gomp_schedule_type run_sched_var;
- int run_sched_modifier;
+ int run_sched_chunk_size;
int default_device_var;
unsigned int thread_limit_var;
bool dyn_var;
enum gomp_task_kind
{
+ /* Implicit task. */
GOMP_TASK_IMPLICIT,
- GOMP_TASK_IFFALSE,
+ /* Undeferred task. */
+ GOMP_TASK_UNDEFERRED,
+ /* Task created by GOMP_task and waiting to be run. */
GOMP_TASK_WAITING,
+ /* Task currently executing or scheduled and about to execute. */
GOMP_TASK_TIED
};
struct gomp_task_depend_entry
{
+ /* Address of dependency. */
void *addr;
struct gomp_task_depend_entry *next;
struct gomp_task_depend_entry *prev;
+ /* Task that provides the dependency in ADDR. */
struct gomp_task *task;
+ /* Depend entry is of type "IN". */
bool is_in;
bool redundant;
bool redundant_out;
struct gomp_task
{
+ /* Parent circular list. See children description below. */
struct gomp_task *parent;
+ /* Circular list representing the children of this task.
+
+ In this list we first have parent_depends_on ready to run tasks,
+ then !parent_depends_on ready to run tasks, and finally already
+ running tasks. */
struct gomp_task *children;
struct gomp_task *next_child;
struct gomp_task *prev_child;
+ /* Circular task_queue in `struct gomp_team'.
+
+ GOMP_TASK_WAITING tasks come before GOMP_TASK_TIED tasks. */
struct gomp_task *next_queue;
struct gomp_task *prev_queue;
+ /* Circular queue in gomp_taskgroup->children.
+
+ GOMP_TASK_WAITING tasks come before GOMP_TASK_TIED tasks. */
struct gomp_task *next_taskgroup;
struct gomp_task *prev_taskgroup;
+ /* Taskgroup this task belongs in. */
struct gomp_taskgroup *taskgroup;
+ /* Tasks that depend on this task. */
struct gomp_dependers_vec *dependers;
struct htab *depend_hash;
struct gomp_taskwait *taskwait;
+ /* Number of items in DEPEND. */
size_t depend_count;
+ /* Number of tasks in the DEPENDERS field above. */
size_t num_dependees;
struct gomp_task_icv icv;
void (*fn) (void *);
bool in_tied_task;
bool final_task;
bool copy_ctors_done;
+ /* Set for undeferred tasks with unsatisfied dependencies which
+ block further execution of their parent until the dependencies
+ are satisfied. */
bool parent_depends_on;
+ /* Dependencies provided and/or needed for this task. DEPEND_COUNT
+ is the number of items available. */
struct gomp_task_depend_entry depend[];
};
struct gomp_taskgroup
{
struct gomp_taskgroup *prev;
+ /* Circular list of tasks that belong in this taskgroup.
+
+ Tasks are chained by next/prev_taskgroup within gomp_task, and
+ are sorted by GOMP_TASK_WAITING tasks, and then GOMP_TASK_TIED
+ tasks. */
struct gomp_task *children;
bool in_taskgroup_wait;
bool cancelled;
size_t num_children;
};
+struct gomp_target_task
+{
+ struct gomp_device_descr *devicep;
+ void (*fn) (void *);
+ size_t mapnum;
+ size_t *sizes;
+ unsigned short *kinds;
+ unsigned int flags;
+ void *hostaddrs[];
+};
+
/* This structure describes a "team" of threads. These are the threads
that are spawned by a PARALLEL constructs, as well as the work sharing
constructs that the team encounters. */
struct gomp_work_share work_shares[8];
gomp_mutex_t task_lock;
+ /* Scheduled tasks. Chain fields are next/prev_queue within a
+ gomp_task. */
struct gomp_task *task_queue;
/* Number of all GOMP_TASK_{WAITING,TIED} tasks in the team. */
unsigned int task_count;
extern bool gomp_affinity_finalize_place_list (bool);
extern bool gomp_affinity_init_level (int, unsigned long, bool);
extern void gomp_affinity_print_place (void *);
+extern void gomp_get_place_proc_ids_8 (int, int64_t *);
/* alloc.c */
extern void gomp_ordered_static_init (void);
extern void gomp_ordered_static_next (void);
extern void gomp_ordered_sync (void);
+extern void gomp_doacross_init (unsigned, long *, long);
+extern void gomp_doacross_ull_init (unsigned, unsigned long long *,
+ unsigned long long);
/* parallel.c */
struct gomp_task_icv *);
extern void gomp_end_task (void);
extern void gomp_barrier_handle_tasks (gomp_barrier_state_t);
+extern void gomp_task_maybe_wait_for_dependencies (void **);
+extern void gomp_create_target_task (struct gomp_device_descr *,
+ void (*) (void *), size_t, void **,
+ size_t *, unsigned short *, unsigned int,
+ void **);
static void inline
gomp_finish_task (struct gomp_task *task)
extern void gomp_init_targets_once (void);
extern int gomp_get_num_devices (void);
+extern void gomp_target_task_fn (void *);
typedef struct splay_tree_node_s *splay_tree_node;
typedef struct splay_tree_s *splay_tree;
typedef struct splay_tree_key_s *splay_tree_key;
+struct target_var_desc {
+ /* Splay key. */
+ splay_tree_key key;
+ /* True if data should be copied from device to host at the end. */
+ bool copy_from;
+ /* True if data always should be copied from device to host at the end. */
+ bool always_copy_from;
+ /* Relative offset against key host_start. */
+ uintptr_t offset;
+ /* Actual length. */
+ uintptr_t length;
+};
+
struct target_mem_desc {
/* Reference count. */
uintptr_t refcount;
/* Corresponding target device descriptor. */
struct gomp_device_descr *device_descr;
- /* List of splay keys to remove (or decrease refcount)
+ /* List of target items to remove (or decrease refcount)
at the end of region. */
- splay_tree_key list[];
+ struct target_var_desc list[];
};
+/* Special value for refcount - infinity. */
+#define REFCOUNT_INFINITY (~(uintptr_t) 0)
+
struct splay_tree_key_s {
/* Address of the host object. */
uintptr_t host_start;
uintptr_t refcount;
/* Asynchronous reference count. */
uintptr_t async_refcount;
- /* True if data should be copied from device to host at the end. */
- bool copy_from;
};
#include "splay-tree.h"
void (*free_func) (int, void *);
void *(*dev2host_func) (int, void *, const void *, size_t);
void *(*host2dev_func) (int, void *, const void *, size_t);
+ void *(*dev2dev_func) (int, void *, const void *, size_t);
void (*run_func) (int, void *, void *);
/* Splay tree containing information about mapped memory regions. */
acc_dispatch_t openacc;
};
+/* Kind of the pragma, for which gomp_map_vars () is called. */
+enum gomp_map_vars_kind
+{
+ GOMP_MAP_VARS_OPENACC,
+ GOMP_MAP_VARS_TARGET,
+ GOMP_MAP_VARS_DATA,
+ GOMP_MAP_VARS_ENTER_DATA
+};
+
extern void gomp_acc_insert_pointer (size_t, void **, size_t *, void *);
extern void gomp_acc_remove_pointer (void *, bool, int, int);
extern struct target_mem_desc *gomp_map_vars (struct gomp_device_descr *,
size_t, void **, void **,
- size_t *, void *, bool, bool);
+ size_t *, void *, bool,
+ enum gomp_map_vars_kind);
extern void gomp_copy_from_async (struct target_mem_desc *);
extern void gomp_unmap_vars (struct target_mem_desc *, bool);
extern void gomp_init_device (struct gomp_device_descr *);
omp_is_initial_device_;
} OMP_3.1;
+OMP_4.5 {
+ global:
+ omp_get_max_task_priority;
+ omp_get_max_task_priority_;
+ omp_get_num_places;
+ omp_get_num_places_;
+ omp_get_place_num_procs;
+ omp_get_place_num_procs_;
+ omp_get_place_num_procs_8_;
+ omp_get_place_proc_ids;
+ omp_get_place_proc_ids_;
+ omp_get_place_proc_ids_8_;
+ omp_get_place_num;
+ omp_get_place_num_;
+ omp_get_partition_num_places;
+ omp_get_partition_num_places_;
+ omp_get_partition_place_nums;
+ omp_get_partition_place_nums_;
+ omp_get_partition_place_nums_8_;
+ omp_get_initial_device;
+ omp_get_initial_device_;
+ omp_target_alloc;
+ omp_target_free;
+ omp_target_is_present;
+ omp_target_memcpy;
+ omp_target_memcpy_rect;
+ omp_target_associate_ptr;
+ omp_target_disassociate_ptr;
+} OMP_4.0;
+
GOMP_1.0 {
global:
GOMP_atomic_end;
GOMP_offload_unregister;
} GOMP_4.0;
-GOMP_4.0.2 {
+GOMP_4.5 {
global:
+ GOMP_target_41;
+ GOMP_target_data_41;
+ GOMP_target_update_41;
+ GOMP_target_enter_exit_data;
+ GOMP_taskloop;
+ GOMP_taskloop_ull;
GOMP_offload_register_ver;
GOMP_offload_unregister_ver;
+ GOMP_loop_doacross_dynamic_start;
+ GOMP_loop_doacross_guided_start;
+ GOMP_loop_doacross_runtime_start;
+ GOMP_loop_doacross_static_start;
+ GOMP_doacross_post;
+ GOMP_doacross_wait;
+ GOMP_loop_ull_doacross_dynamic_start;
+ GOMP_loop_ull_doacross_guided_start;
+ GOMP_loop_ull_doacross_runtime_start;
+ GOMP_loop_ull_doacross_static_start;
+ GOMP_doacross_ull_post;
+ GOMP_doacross_ull_wait;
} GOMP_4.0.1;
OACC_2.0 {
* omp_get_dynamic:: Dynamic teams setting
* omp_get_level:: Number of parallel regions
* omp_get_max_active_levels:: Maximum number of active regions
+* omp_get_max_task_priority:: Maximum task priority value that can be set
* omp_get_max_threads:: Maximum number of threads of parallel region
* omp_get_nested:: Nested parallel regions
* omp_get_num_devices:: Number of target devices
@end table
+@node omp_get_max_task_priority
+@section @code{omp_get_max_task_priority} -- Maximum priority value
+that can be set for tasks.
+@table @asis
+@item @emph{Description}:
+This function obtains the maximum allowed priority number for tasks.
+
+@item @emph{C/C++}
+@multitable @columnfractions .20 .80
+@item @emph{Prototype}: @tab @code{int omp_get_max_task_priority(void);}
+@end multitable
+
+@item @emph{Fortran}:
+@multitable @columnfractions .20 .80
+@item @emph{Interface}: @tab @code{integer function omp_get_max_task_priority()}
+@end multitable
+
+@item @emph{Reference}:
+@uref{http://www.openmp.org/, OpenMP specification v4.5}, Section 3.2.29.
+@end table
+
@node omp_get_max_threads
@section @code{omp_get_max_threads} -- Maximum number of threads of parallel region
Obtain the runtime scheduling method. The @var{kind} argument will be
set to the value @code{omp_sched_static}, @code{omp_sched_dynamic},
@code{omp_sched_guided} or @code{omp_sched_auto}. The second argument,
-@var{modifier}, is set to the chunk size.
+@var{chunk_size}, is set to the chunk size.
@item @emph{C/C++}
@multitable @columnfractions .20 .80
-@item @emph{Prototype}: @tab @code{void omp_get_schedule(omp_sched_t *kind, int *modifier);}
+@item @emph{Prototype}: @tab @code{void omp_get_schedule(omp_sched_t *kind, int *chunk_size);}
@end multitable
@item @emph{Fortran}:
@multitable @columnfractions .20 .80
-@item @emph{Interface}: @tab @code{subroutine omp_get_schedule(kind, modifier)}
+@item @emph{Interface}: @tab @code{subroutine omp_get_schedule(kind, chunk_size)}
@item @tab @code{integer(kind=omp_sched_kind) kind}
-@item @tab @code{integer modifier}
+@item @tab @code{integer chunk_size}
@end multitable
@item @emph{See also}:
value @code{omp_sched_static}, @code{omp_sched_dynamic},
@code{omp_sched_guided} or @code{omp_sched_auto}. Except for
@code{omp_sched_auto}, the chunk size is set to the value of
-@var{modifier} if positive, or to the default value if zero or negative.
-For @code{omp_sched_auto} the @var{modifier} argument is ignored.
+@var{chunk_size} if positive, or to the default value if zero or negative.
+For @code{omp_sched_auto} the @var{chunk_size} argument is ignored.
@item @emph{C/C++}
@multitable @columnfractions .20 .80
-@item @emph{Prototype}: @tab @code{void omp_set_schedule(omp_sched_t kind, int modifier);}
+@item @emph{Prototype}: @tab @code{void omp_set_schedule(omp_sched_t kind, int chunk_size);}
@end multitable
@item @emph{Fortran}:
@multitable @columnfractions .20 .80
-@item @emph{Interface}: @tab @code{subroutine omp_set_schedule(kind, modifier)}
+@item @emph{Interface}: @tab @code{subroutine omp_set_schedule(kind, chunk_size)}
@item @tab @code{integer(kind=omp_sched_kind) kind}
-@item @tab @code{integer modifier}
+@item @tab @code{integer chunk_size}
@end multitable
@item @emph{See also}:
* OMP_DEFAULT_DEVICE:: Set the device used in target regions
* OMP_DYNAMIC:: Dynamic adjustment of threads
* OMP_MAX_ACTIVE_LEVELS:: Set the maximum number of nested parallel regions
+* OMP_MAX_TASK_PRIORITY:: Set the maximum task priority value
* OMP_NESTED:: Nested parallel regions
* OMP_NUM_THREADS:: Specifies the number of threads to use
* OMP_PROC_BIND:: Whether theads may be moved between CPUs
+@node OMP_MAX_TASK_PRIORITY
+@section @env{OMP_MAX_TASK_PRIORITY} -- Set the maximum priority
+number that can be set for a task.
+@cindex Environment Variable
+@table @asis
+@item @emph{Description}:
+Specifies the initial value for the maximum priority value that can be
+set for a task. The value of this variable shall be a non-negative
+integer, and zero is allowed. If undefined, the default priority is
+0.
+
+@item @emph{See also}:
+@ref{omp_get_max_task_priority}
+
+@item @emph{Reference}:
+@uref{http://www.openmp.org/, OpenMP specification v4.5}, Section 4.14
+@end table
+
+
+
@node OMP_NESTED
@section @env{OMP_NESTED} -- Nested parallel regions
@cindex Environment Variable
extern bool GOMP_loop_ordered_guided_next (long *, long *);
extern bool GOMP_loop_ordered_runtime_next (long *, long *);
+extern bool GOMP_loop_doacross_static_start (unsigned, long *, long, long *,
+ long *);
+extern bool GOMP_loop_doacross_dynamic_start (unsigned, long *, long, long *,
+ long *);
+extern bool GOMP_loop_doacross_guided_start (unsigned, long *, long, long *,
+ long *);
+extern bool GOMP_loop_doacross_runtime_start (unsigned, long *, long *,
+ long *);
+
extern void GOMP_parallel_loop_static_start (void (*)(void *), void *,
unsigned, long, long, long, long);
extern void GOMP_parallel_loop_dynamic_start (void (*)(void *), void *,
extern bool GOMP_loop_ull_ordered_runtime_next (unsigned long long *,
unsigned long long *);
+extern bool GOMP_loop_ull_doacross_static_start (unsigned,
+ unsigned long long *,
+ unsigned long long,
+ unsigned long long *,
+ unsigned long long *);
+extern bool GOMP_loop_ull_doacross_dynamic_start (unsigned,
+ unsigned long long *,
+ unsigned long long,
+ unsigned long long *,
+ unsigned long long *);
+extern bool GOMP_loop_ull_doacross_guided_start (unsigned,
+ unsigned long long *,
+ unsigned long long,
+ unsigned long long *,
+ unsigned long long *);
+extern bool GOMP_loop_ull_doacross_runtime_start (unsigned,
+ unsigned long long *,
+ unsigned long long *,
+ unsigned long long *);
+
/* ordered.c */
extern void GOMP_ordered_start (void);
extern void GOMP_ordered_end (void);
+extern void GOMP_doacross_post (long *);
+extern void GOMP_doacross_wait (long, ...);
+extern void GOMP_doacross_ull_post (unsigned long long *);
+extern void GOMP_doacross_ull_wait (unsigned long long, ...);
/* parallel.c */
/* task.c */
extern void GOMP_task (void (*) (void *), void *, void (*) (void *, void *),
- long, long, bool, unsigned, void **);
+ long, long, bool, unsigned, void **, int);
+extern void GOMP_taskloop (void (*) (void *), void *,
+ void (*) (void *, void *), long, long, unsigned,
+ unsigned long, int, long, long, long);
+extern void GOMP_taskloop_ull (void (*) (void *), void *,
+ void (*) (void *, void *), long, long,
+ unsigned, unsigned long, int,
+ unsigned long long, unsigned long long,
+ unsigned long long);
extern void GOMP_taskwait (void);
extern void GOMP_taskyield (void);
extern void GOMP_taskgroup_start (void);
extern void GOMP_target (int, void (*) (void *), const void *,
size_t, void **, size_t *, unsigned char *);
+extern void GOMP_target_41 (int, void (*) (void *), size_t, void **, size_t *,
+ unsigned short *, unsigned int, void **);
extern void GOMP_target_data (int, const void *,
size_t, void **, size_t *, unsigned char *);
+extern void GOMP_target_data_41 (int, size_t, void **, size_t *,
+ unsigned short *);
extern void GOMP_target_end_data (void);
extern void GOMP_target_update (int, const void *,
size_t, void **, size_t *, unsigned char *);
+extern void GOMP_target_update_41 (int, size_t, void **, size_t *,
+ unsigned short *, unsigned int, void **);
+extern void GOMP_target_enter_exit_data (int, size_t, void **, size_t *,
+ unsigned short *, unsigned int,
+ void **);
extern void GOMP_teams (unsigned int, unsigned int);
/* oacc-parallel.c */
switch (icv->run_sched_var)
{
case GFS_STATIC:
- return gomp_loop_static_start (start, end, incr, icv->run_sched_modifier,
+ return gomp_loop_static_start (start, end, incr,
+ icv->run_sched_chunk_size,
istart, iend);
case GFS_DYNAMIC:
- return gomp_loop_dynamic_start (start, end, incr, icv->run_sched_modifier,
+ return gomp_loop_dynamic_start (start, end, incr,
+ icv->run_sched_chunk_size,
istart, iend);
case GFS_GUIDED:
- return gomp_loop_guided_start (start, end, incr, icv->run_sched_modifier,
+ return gomp_loop_guided_start (start, end, incr,
+ icv->run_sched_chunk_size,
istart, iend);
case GFS_AUTO:
/* For now map to schedule(static), later on we could play with feedback
{
case GFS_STATIC:
return gomp_loop_ordered_static_start (start, end, incr,
- icv->run_sched_modifier,
+ icv->run_sched_chunk_size,
istart, iend);
case GFS_DYNAMIC:
return gomp_loop_ordered_dynamic_start (start, end, incr,
- icv->run_sched_modifier,
+ icv->run_sched_chunk_size,
istart, iend);
case GFS_GUIDED:
return gomp_loop_ordered_guided_start (start, end, incr,
- icv->run_sched_modifier,
+ icv->run_sched_chunk_size,
istart, iend);
case GFS_AUTO:
/* For now map to schedule(static), later on we could play with feedback
}
}
+/* The *_doacross_*_start routines are similar. The only difference is that
+ this work-share construct is initialized to expect an ORDERED(N) - DOACROSS
+ section, and the worksharing loop iterates always from 0 to COUNTS[0] - 1
+ and other COUNTS array elements tell the library number of iterations
+ in the ordered inner loops. */
+
+static bool
+gomp_loop_doacross_static_start (unsigned ncounts, long *counts,
+ long chunk_size, long *istart, long *iend)
+{
+ struct gomp_thread *thr = gomp_thread ();
+
+ thr->ts.static_trip = 0;
+ if (gomp_work_share_start (false))
+ {
+ gomp_loop_init (thr->ts.work_share, 0, counts[0], 1,
+ GFS_STATIC, chunk_size);
+ gomp_doacross_init (ncounts, counts, chunk_size);
+ gomp_work_share_init_done ();
+ }
+
+ return !gomp_iter_static_next (istart, iend);
+}
+
+static bool
+gomp_loop_doacross_dynamic_start (unsigned ncounts, long *counts,
+ long chunk_size, long *istart, long *iend)
+{
+ struct gomp_thread *thr = gomp_thread ();
+ bool ret;
+
+ if (gomp_work_share_start (false))
+ {
+ gomp_loop_init (thr->ts.work_share, 0, counts[0], 1,
+ GFS_DYNAMIC, chunk_size);
+ gomp_doacross_init (ncounts, counts, chunk_size);
+ gomp_work_share_init_done ();
+ }
+
+#ifdef HAVE_SYNC_BUILTINS
+ ret = gomp_iter_dynamic_next (istart, iend);
+#else
+ gomp_mutex_lock (&thr->ts.work_share->lock);
+ ret = gomp_iter_dynamic_next_locked (istart, iend);
+ gomp_mutex_unlock (&thr->ts.work_share->lock);
+#endif
+
+ return ret;
+}
+
+static bool
+gomp_loop_doacross_guided_start (unsigned ncounts, long *counts,
+ long chunk_size, long *istart, long *iend)
+{
+ struct gomp_thread *thr = gomp_thread ();
+ bool ret;
+
+ if (gomp_work_share_start (false))
+ {
+ gomp_loop_init (thr->ts.work_share, 0, counts[0], 1,
+ GFS_GUIDED, chunk_size);
+ gomp_doacross_init (ncounts, counts, chunk_size);
+ gomp_work_share_init_done ();
+ }
+
+#ifdef HAVE_SYNC_BUILTINS
+ ret = gomp_iter_guided_next (istart, iend);
+#else
+ gomp_mutex_lock (&thr->ts.work_share->lock);
+ ret = gomp_iter_guided_next_locked (istart, iend);
+ gomp_mutex_unlock (&thr->ts.work_share->lock);
+#endif
+
+ return ret;
+}
+
+bool
+GOMP_loop_doacross_runtime_start (unsigned ncounts, long *counts,
+ long *istart, long *iend)
+{
+ struct gomp_task_icv *icv = gomp_icv (false);
+ switch (icv->run_sched_var)
+ {
+ case GFS_STATIC:
+ return gomp_loop_doacross_static_start (ncounts, counts,
+ icv->run_sched_chunk_size,
+ istart, iend);
+ case GFS_DYNAMIC:
+ return gomp_loop_doacross_dynamic_start (ncounts, counts,
+ icv->run_sched_chunk_size,
+ istart, iend);
+ case GFS_GUIDED:
+ return gomp_loop_doacross_guided_start (ncounts, counts,
+ icv->run_sched_chunk_size,
+ istart, iend);
+ case GFS_AUTO:
+ /* For now map to schedule(static), later on we could play with feedback
+ driven choice. */
+ return gomp_loop_doacross_static_start (ncounts, counts,
+ 0, istart, iend);
+ default:
+ abort ();
+ }
+}
+
/* The *_next routines are called when the thread completes processing of
the iteration block currently assigned to it. If the work-share
construct is bound directly to a parallel construct, then the iteration
{
struct gomp_task_icv *icv = gomp_icv (false);
gomp_parallel_loop_start (fn, data, num_threads, start, end, incr,
- icv->run_sched_var, icv->run_sched_modifier, 0);
+ icv->run_sched_var, icv->run_sched_chunk_size, 0);
}
ialias_redirect (GOMP_parallel_end)
{
struct gomp_task_icv *icv = gomp_icv (false);
gomp_parallel_loop_start (fn, data, num_threads, start, end, incr,
- icv->run_sched_var, icv->run_sched_modifier,
+ icv->run_sched_var, icv->run_sched_chunk_size,
flags);
fn (data);
GOMP_parallel_end ();
extern __typeof(gomp_loop_ordered_guided_start) GOMP_loop_ordered_guided_start
__attribute__((alias ("gomp_loop_ordered_guided_start")));
+extern __typeof(gomp_loop_doacross_static_start) GOMP_loop_doacross_static_start
+ __attribute__((alias ("gomp_loop_doacross_static_start")));
+extern __typeof(gomp_loop_doacross_dynamic_start) GOMP_loop_doacross_dynamic_start
+ __attribute__((alias ("gomp_loop_doacross_dynamic_start")));
+extern __typeof(gomp_loop_doacross_guided_start) GOMP_loop_doacross_guided_start
+ __attribute__((alias ("gomp_loop_doacross_guided_start")));
+
extern __typeof(gomp_loop_static_next) GOMP_loop_static_next
__attribute__((alias ("gomp_loop_static_next")));
extern __typeof(gomp_loop_dynamic_next) GOMP_loop_dynamic_next
istart, iend);
}
+bool
+GOMP_loop_doacross_static_start (unsigned ncounts, long *counts,
+ long chunk_size, long *istart, long *iend)
+{
+ return gomp_loop_doacross_static_start (ncounts, counts, chunk_size,
+ istart, iend);
+}
+
+bool
+GOMP_loop_doacross_dynamic_start (unsigned ncounts, long *counts,
+ long chunk_size, long *istart, long *iend)
+{
+ return gomp_loop_doacross_dynamic_start (ncounts, counts, chunk_size,
+ istart, iend);
+}
+
+bool
+GOMP_loop_doacross_guided_start (unsigned ncounts, long *counts,
+ long chunk_size, long *istart, long *iend)
+{
+ return gomp_loop_doacross_guided_start (ncounts, counts, chunk_size,
+ istart, iend);
+}
+
bool
GOMP_loop_static_next (long *istart, long *iend)
{
{
case GFS_STATIC:
return gomp_loop_ull_static_start (up, start, end, incr,
- icv->run_sched_modifier,
+ icv->run_sched_chunk_size,
istart, iend);
case GFS_DYNAMIC:
return gomp_loop_ull_dynamic_start (up, start, end, incr,
- icv->run_sched_modifier,
+ icv->run_sched_chunk_size,
istart, iend);
case GFS_GUIDED:
return gomp_loop_ull_guided_start (up, start, end, incr,
- icv->run_sched_modifier,
+ icv->run_sched_chunk_size,
istart, iend);
case GFS_AUTO:
/* For now map to schedule(static), later on we could play with feedback
{
case GFS_STATIC:
return gomp_loop_ull_ordered_static_start (up, start, end, incr,
- icv->run_sched_modifier,
+ icv->run_sched_chunk_size,
istart, iend);
case GFS_DYNAMIC:
return gomp_loop_ull_ordered_dynamic_start (up, start, end, incr,
- icv->run_sched_modifier,
+ icv->run_sched_chunk_size,
istart, iend);
case GFS_GUIDED:
return gomp_loop_ull_ordered_guided_start (up, start, end, incr,
- icv->run_sched_modifier,
+ icv->run_sched_chunk_size,
istart, iend);
case GFS_AUTO:
/* For now map to schedule(static), later on we could play with feedback
}
}
+/* The *_doacross_*_start routines are similar. The only difference is that
+ this work-share construct is initialized to expect an ORDERED(N) - DOACROSS
+ section, and the worksharing loop iterates always from 0 to COUNTS[0] - 1
+ and other COUNTS array elements tell the library number of iterations
+ in the ordered inner loops. */
+
+static bool
+gomp_loop_ull_doacross_static_start (unsigned ncounts, gomp_ull *counts,
+ gomp_ull chunk_size, gomp_ull *istart,
+ gomp_ull *iend)
+{
+ struct gomp_thread *thr = gomp_thread ();
+
+ thr->ts.static_trip = 0;
+ if (gomp_work_share_start (false))
+ {
+ gomp_loop_ull_init (thr->ts.work_share, true, 0, counts[0], 1,
+ GFS_STATIC, chunk_size);
+ gomp_doacross_ull_init (ncounts, counts, chunk_size);
+ gomp_work_share_init_done ();
+ }
+
+ return !gomp_iter_ull_static_next (istart, iend);
+}
+
+static bool
+gomp_loop_ull_doacross_dynamic_start (unsigned ncounts, gomp_ull *counts,
+ gomp_ull chunk_size, gomp_ull *istart,
+ gomp_ull *iend)
+{
+ struct gomp_thread *thr = gomp_thread ();
+ bool ret;
+
+ if (gomp_work_share_start (false))
+ {
+ gomp_loop_ull_init (thr->ts.work_share, true, 0, counts[0], 1,
+ GFS_DYNAMIC, chunk_size);
+ gomp_doacross_ull_init (ncounts, counts, chunk_size);
+ gomp_work_share_init_done ();
+ }
+
+#if defined HAVE_SYNC_BUILTINS && defined __LP64__
+ ret = gomp_iter_ull_dynamic_next (istart, iend);
+#else
+ gomp_mutex_lock (&thr->ts.work_share->lock);
+ ret = gomp_iter_ull_dynamic_next_locked (istart, iend);
+ gomp_mutex_unlock (&thr->ts.work_share->lock);
+#endif
+
+ return ret;
+}
+
+static bool
+gomp_loop_ull_doacross_guided_start (unsigned ncounts, gomp_ull *counts,
+ gomp_ull chunk_size, gomp_ull *istart,
+ gomp_ull *iend)
+{
+ struct gomp_thread *thr = gomp_thread ();
+ bool ret;
+
+ if (gomp_work_share_start (false))
+ {
+ gomp_loop_ull_init (thr->ts.work_share, true, 0, counts[0], 1,
+ GFS_GUIDED, chunk_size);
+ gomp_doacross_ull_init (ncounts, counts, chunk_size);
+ gomp_work_share_init_done ();
+ }
+
+#if defined HAVE_SYNC_BUILTINS && defined __LP64__
+ ret = gomp_iter_ull_guided_next (istart, iend);
+#else
+ gomp_mutex_lock (&thr->ts.work_share->lock);
+ ret = gomp_iter_ull_guided_next_locked (istart, iend);
+ gomp_mutex_unlock (&thr->ts.work_share->lock);
+#endif
+
+ return ret;
+}
+
+bool
+GOMP_loop_ull_doacross_runtime_start (unsigned ncounts, gomp_ull *counts,
+ gomp_ull *istart, gomp_ull *iend)
+{
+ struct gomp_task_icv *icv = gomp_icv (false);
+ switch (icv->run_sched_var)
+ {
+ case GFS_STATIC:
+ return gomp_loop_ull_doacross_static_start (ncounts, counts,
+ icv->run_sched_chunk_size,
+ istart, iend);
+ case GFS_DYNAMIC:
+ return gomp_loop_ull_doacross_dynamic_start (ncounts, counts,
+ icv->run_sched_chunk_size,
+ istart, iend);
+ case GFS_GUIDED:
+ return gomp_loop_ull_doacross_guided_start (ncounts, counts,
+ icv->run_sched_chunk_size,
+ istart, iend);
+ case GFS_AUTO:
+ /* For now map to schedule(static), later on we could play with feedback
+ driven choice. */
+ return gomp_loop_ull_doacross_static_start (ncounts, counts,
+ 0, istart, iend);
+ default:
+ abort ();
+ }
+}
+
/* The *_next routines are called when the thread completes processing of
the iteration block currently assigned to it. If the work-share
construct is bound directly to a parallel construct, then the iteration
extern __typeof(gomp_loop_ull_ordered_guided_start) GOMP_loop_ull_ordered_guided_start
__attribute__((alias ("gomp_loop_ull_ordered_guided_start")));
+extern __typeof(gomp_loop_ull_doacross_static_start) GOMP_loop_ull_doacross_static_start
+ __attribute__((alias ("gomp_loop_ull_doacross_static_start")));
+extern __typeof(gomp_loop_ull_doacross_dynamic_start) GOMP_loop_ull_doacross_dynamic_start
+ __attribute__((alias ("gomp_loop_ull_doacross_dynamic_start")));
+extern __typeof(gomp_loop_ull_doacross_guided_start) GOMP_loop_ull_doacross_guided_start
+ __attribute__((alias ("gomp_loop_ull_doacross_guided_start")));
+
extern __typeof(gomp_loop_ull_static_next) GOMP_loop_ull_static_next
__attribute__((alias ("gomp_loop_ull_static_next")));
extern __typeof(gomp_loop_ull_dynamic_next) GOMP_loop_ull_dynamic_next
istart, iend);
}
+bool
+GOMP_loop_ull_doacross_static_start (unsigned ncounts, gomp_ull *counts,
+ gomp_ull chunk_size, gomp_ull *istart,
+ gomp_ull *iend)
+{
+ return gomp_loop_ull_doacross_static_start (ncounts, counts, chunk_size,
+ istart, iend);
+}
+
+bool
+GOMP_loop_ull_doacross_dynamic_start (unsigned ncounts, gomp_ull *counts,
+ gomp_ull chunk_size, gomp_ull *istart,
+ gomp_ull *iend)
+{
+ return gomp_loop_ull_doacross_dynamic_start (ncounts, counts, chunk_size,
+ istart, iend);
+}
+
+bool
+GOMP_loop_ull_doacross_guided_start (unsigned ncounts, gomp_ull *counts,
+ gomp_ull chunk_size, gomp_ull *istart,
+ gomp_ull *iend)
+{
+ return gomp_loop_ull_doacross_guided_start (ncounts, counts, chunk_size,
+ istart, iend);
+}
+
bool
GOMP_loop_ull_static_next (gomp_ull *istart, gomp_ull *iend)
{
if (d != h)
gomp_fatal ("cannot map data on shared-memory system");
- tgt = gomp_map_vars (NULL, 0, NULL, NULL, NULL, NULL, true, false);
+ tgt = gomp_map_vars (NULL, 0, NULL, NULL, NULL, NULL, true,
+ GOMP_MAP_VARS_OPENACC);
}
else
{
gomp_mutex_unlock (&acc_dev->lock);
tgt = gomp_map_vars (acc_dev, mapnum, &hostaddrs, &devaddrs, &sizes,
- &kinds, true, false);
+ &kinds, true, GOMP_MAP_VARS_OPENACC);
}
gomp_mutex_lock (&acc_dev->lock);
gomp_mutex_unlock (&acc_dev->lock);
tgt = gomp_map_vars (acc_dev, mapnum, &hostaddrs, NULL, &s, &kinds, true,
- false);
+ GOMP_MAP_VARS_OPENACC);
gomp_mutex_lock (&acc_dev->lock);
gomp_debug (0, " %s: prepare mappings\n", __FUNCTION__);
tgt = gomp_map_vars (acc_dev, mapnum, hostaddrs,
- NULL, sizes, kinds, true, false);
+ NULL, sizes, kinds, true, GOMP_MAP_VARS_OPENACC);
gomp_debug (0, " %s: mappings prepared\n", __FUNCTION__);
gomp_mutex_lock (&acc_dev->lock);
}
if (force_copyfrom)
- t->list[0]->copy_from = 1;
+ t->list[0].copy_from = 1;
gomp_mutex_unlock (&acc_dev->lock);
tgt_fn = (void (*)) fn;
tgt = gomp_map_vars (acc_dev, mapnum, hostaddrs, NULL, sizes, kinds, true,
- false);
+ GOMP_MAP_VARS_OPENACC);
devaddrs = gomp_alloca (sizeof (void *) * mapnum);
for (i = 0; i < mapnum; i++)
- devaddrs[i] = (void *) (tgt->list[i]->tgt->tgt_start
- + tgt->list[i]->tgt_offset);
+ devaddrs[i] = (void *) (tgt->list[i].key->tgt->tgt_start
+ + tgt->list[i].key->tgt_offset);
acc_dev->openacc.exec_func (tgt_fn, mapnum, hostaddrs, devaddrs, sizes,
kinds, async, dims, tgt);
if ((acc_dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
|| host_fallback)
{
- tgt = gomp_map_vars (NULL, 0, NULL, NULL, NULL, NULL, true, false);
+ tgt = gomp_map_vars (NULL, 0, NULL, NULL, NULL, NULL, true,
+ GOMP_MAP_VARS_OPENACC);
tgt->prev = thr->mapped_data;
thr->mapped_data = tgt;
gomp_debug (0, " %s: prepare mappings\n", __FUNCTION__);
tgt = gomp_map_vars (acc_dev, mapnum, hostaddrs, NULL, sizes, kinds, true,
- false);
+ GOMP_MAP_VARS_OPENACC);
gomp_debug (0, " %s: mappings prepared\n", __FUNCTION__);
tgt->prev = thr->mapped_data;
thr->mapped_data = tgt;
omp_proc_bind_spread = 4
} omp_proc_bind_t;
+typedef enum omp_lock_hint_t
+{
+ omp_lock_hint_none = 0,
+ omp_lock_hint_uncontended = 1,
+ omp_lock_hint_contended = 2,
+ omp_lock_hint_nonspeculative = 4,
+ omp_lock_hint_speculative = 8,
+} omp_lock_hint_t;
+
#ifdef __cplusplus
extern "C" {
# define __GOMP_NOTHROW throw ()
extern int omp_get_nested (void) __GOMP_NOTHROW;
extern void omp_init_lock (omp_lock_t *) __GOMP_NOTHROW;
+extern void omp_init_lock_with_hint (omp_lock_t *, omp_lock_hint_t)
+ __GOMP_NOTHROW;
extern void omp_destroy_lock (omp_lock_t *) __GOMP_NOTHROW;
extern void omp_set_lock (omp_lock_t *) __GOMP_NOTHROW;
extern void omp_unset_lock (omp_lock_t *) __GOMP_NOTHROW;
extern int omp_test_lock (omp_lock_t *) __GOMP_NOTHROW;
extern void omp_init_nest_lock (omp_nest_lock_t *) __GOMP_NOTHROW;
+extern void omp_init_nest_lock_with_hint (omp_lock_t *, omp_lock_hint_t)
+ __GOMP_NOTHROW;
extern void omp_destroy_nest_lock (omp_nest_lock_t *) __GOMP_NOTHROW;
extern void omp_set_nest_lock (omp_nest_lock_t *) __GOMP_NOTHROW;
extern void omp_unset_nest_lock (omp_nest_lock_t *) __GOMP_NOTHROW;
extern int omp_get_cancellation (void) __GOMP_NOTHROW;
extern omp_proc_bind_t omp_get_proc_bind (void) __GOMP_NOTHROW;
+extern int omp_get_num_places (void) __GOMP_NOTHROW;
+extern int omp_get_place_num_procs (int) __GOMP_NOTHROW;
+extern void omp_get_place_proc_ids (int, int *) __GOMP_NOTHROW;
+extern int omp_get_place_num (void) __GOMP_NOTHROW;
+extern int omp_get_partition_num_places (void) __GOMP_NOTHROW;
+extern void omp_get_partition_place_nums (int *) __GOMP_NOTHROW;
extern void omp_set_default_device (int) __GOMP_NOTHROW;
extern int omp_get_default_device (void) __GOMP_NOTHROW;
extern int omp_get_team_num (void) __GOMP_NOTHROW;
extern int omp_is_initial_device (void) __GOMP_NOTHROW;
+extern int omp_get_initial_device (void) __GOMP_NOTHROW;
+extern int omp_get_max_task_priority (void) __GOMP_NOTHROW;
+
+extern void *omp_target_alloc (__SIZE_TYPE__, int) __GOMP_NOTHROW;
+extern void omp_target_free (void *, int) __GOMP_NOTHROW;
+extern int omp_target_is_present (void *, int) __GOMP_NOTHROW;
+extern int omp_target_memcpy (void *, void *, __SIZE_TYPE__, __SIZE_TYPE__,
+ __SIZE_TYPE__, int, int) __GOMP_NOTHROW;
+extern int omp_target_memcpy_rect (void *, void *, __SIZE_TYPE__, int,
+ const __SIZE_TYPE__ *,
+ const __SIZE_TYPE__ *,
+ const __SIZE_TYPE__ *,
+ const __SIZE_TYPE__ *,
+ const __SIZE_TYPE__ *, int, int)
+ __GOMP_NOTHROW;
+extern int omp_target_associate_ptr (void *, void *, __SIZE_TYPE__,
+ __SIZE_TYPE__, int) __GOMP_NOTHROW;
+extern int omp_target_disassociate_ptr (void *, int) __GOMP_NOTHROW;
#ifdef __cplusplus
}
integer, parameter :: omp_nest_lock_kind = @OMP_NEST_LOCK_KIND@
integer, parameter :: omp_sched_kind = 4
integer, parameter :: omp_proc_bind_kind = 4
+ integer, parameter :: omp_lock_hint_kind = 4
integer (omp_sched_kind), parameter :: omp_sched_static = 1
integer (omp_sched_kind), parameter :: omp_sched_dynamic = 2
integer (omp_sched_kind), parameter :: omp_sched_guided = 3
integer (omp_sched_kind), parameter :: omp_sched_auto = 4
- integer (omp_proc_bind_kind), parameter :: omp_proc_bind_false = 0
- integer (omp_proc_bind_kind), parameter :: omp_proc_bind_true = 1
- integer (omp_proc_bind_kind), parameter :: omp_proc_bind_master = 2
- integer (omp_proc_bind_kind), parameter :: omp_proc_bind_close = 3
- integer (omp_proc_bind_kind), parameter :: omp_proc_bind_spread = 4
+ integer (omp_proc_bind_kind), &
+ parameter :: omp_proc_bind_false = 0
+ integer (omp_proc_bind_kind), &
+ parameter :: omp_proc_bind_true = 1
+ integer (omp_proc_bind_kind), &
+ parameter :: omp_proc_bind_master = 2
+ integer (omp_proc_bind_kind), &
+ parameter :: omp_proc_bind_close = 3
+ integer (omp_proc_bind_kind), &
+ parameter :: omp_proc_bind_spread = 4
+ integer (omp_lock_hint_kind), &
+ parameter :: omp_lock_hint_none = 0
+ integer (omp_lock_hint_kind), &
+ parameter :: omp_lock_hint_uncontended = 1
+ integer (omp_lock_hint_kind), &
+ parameter :: omp_lock_hint_contended = 2
+ integer (omp_lock_hint_kind), &
+ parameter :: omp_lock_hint_nonspeculative = 4
+ integer (omp_lock_hint_kind), &
+ parameter :: omp_lock_hint_speculative = 8
end module
module omp_lib
end subroutine omp_init_lock
end interface
+ interface
+ subroutine omp_init_lock_with_hint (svar, hint)
+ use omp_lib_kinds
+ integer (omp_lock_kind), intent (out) :: svar
+ integer (omp_lock_hint_kind), intent (in) :: hint
+ end subroutine omp_init_lock_with_hint
+ end interface
+
interface
subroutine omp_init_nest_lock (nvar)
use omp_lib_kinds
end subroutine omp_init_nest_lock
end interface
+ interface
+ subroutine omp_init_nest_lock_with_hint (nvar, hint)
+ use omp_lib_kinds
+ integer (omp_nest_lock_kind), intent (out) :: nvar
+ integer (omp_lock_hint_kind), intent (in) :: hint
+ end subroutine omp_init_nest_lock_with_hint
+ end interface
+
interface
subroutine omp_destroy_lock (svar)
use omp_lib_kinds
end interface
interface omp_set_schedule
- subroutine omp_set_schedule (kind, modifier)
+ subroutine omp_set_schedule (kind, chunk_size)
use omp_lib_kinds
integer (omp_sched_kind), intent (in) :: kind
- integer (4), intent (in) :: modifier
+ integer (4), intent (in) :: chunk_size
end subroutine omp_set_schedule
- subroutine omp_set_schedule_8 (kind, modifier)
+ subroutine omp_set_schedule_8 (kind, chunk_size)
use omp_lib_kinds
integer (omp_sched_kind), intent (in) :: kind
- integer (8), intent (in) :: modifier
+ integer (8), intent (in) :: chunk_size
end subroutine omp_set_schedule_8
end interface
interface omp_get_schedule
- subroutine omp_get_schedule (kind, modifier)
+ subroutine omp_get_schedule (kind, chunk_size)
use omp_lib_kinds
integer (omp_sched_kind), intent (out) :: kind
- integer (4), intent (out) :: modifier
+ integer (4), intent (out) :: chunk_size
end subroutine omp_get_schedule
- subroutine omp_get_schedule_8 (kind, modifier)
+ subroutine omp_get_schedule_8 (kind, chunk_size)
use omp_lib_kinds
integer (omp_sched_kind), intent (out) :: kind
- integer (8), intent (out) :: modifier
+ integer (8), intent (out) :: chunk_size
end subroutine omp_get_schedule_8
end interface
end function omp_get_proc_bind
end interface
+ interface
+ function omp_get_num_places ()
+ integer (4) :: omp_get_num_places
+ end function omp_get_num_places
+ end interface
+
+ interface omp_get_place_num_procs
+ function omp_get_place_num_procs (place_num)
+ integer (4), intent(in) :: place_num
+ integer (4) :: omp_get_place_num_procs
+ end function omp_get_place_num_procs
+
+ function omp_get_place_num_procs_8 (place_num)
+ integer (8), intent(in) :: place_num
+ integer (4) :: omp_get_place_num_procs_8
+ end function omp_get_place_num_procs_8
+ end interface
+
+ interface omp_get_place_proc_ids
+ subroutine omp_get_place_proc_ids (place_num, ids)
+ integer (4), intent(in) :: place_num
+ integer (4), intent(out) :: ids(*)
+ end subroutine omp_get_place_proc_ids
+
+ subroutine omp_get_place_proc_ids_8 (place_num, ids)
+ integer (8), intent(in) :: place_num
+ integer (8), intent(out) :: ids(*)
+ end subroutine omp_get_place_proc_ids_8
+ end interface
+
+ interface
+ function omp_get_place_num ()
+ integer (4) :: omp_get_place_num
+ end function omp_get_place_num
+ end interface
+
+ interface
+ function omp_get_partition_num_places ()
+ integer (4) :: omp_get_partition_num_places
+ end function omp_get_partition_num_places
+ end interface
+
+ interface omp_get_partition_place_nums
+ subroutine omp_get_partition_place_nums (place_nums)
+ integer (4), intent(out) :: place_nums(*)
+ end subroutine omp_get_partition_place_nums
+
+ subroutine omp_get_partition_place_nums_8 (place_nums)
+ integer (8), intent(out) :: place_nums(*)
+ end subroutine omp_get_partition_place_nums_8
+ end interface
+
interface omp_set_default_device
subroutine omp_set_default_device (device_num)
integer (4), intent (in) :: device_num
end function omp_is_initial_device
end interface
+ interface
+ function omp_get_initial_device ()
+ integer (4) :: omp_get_initial_device
+ end function omp_get_initial_device
+ end interface
+
+ interface
+ function omp_get_max_task_priority ()
+ integer (4) :: omp_get_max_task_priority
+ end function omp_get_max_task_priority
+ end interface
+
end module omp_lib
parameter (omp_proc_bind_master = 2)
parameter (omp_proc_bind_close = 3)
parameter (omp_proc_bind_spread = 4)
+ integer omp_lock_hint_kind
+ parameter (omp_lock_hint_kind = 4)
+ integer (omp_lock_hint_kind) omp_lock_hint_none
+ integer (omp_lock_hint_kind) omp_lock_hint_uncontended
+ integer (omp_lock_hint_kind) omp_lock_hint_contended
+ integer (omp_lock_hint_kind) omp_lock_hint_nonspeculative
+ integer (omp_lock_hint_kind) omp_lock_hint_speculative
+ parameter (omp_lock_hint_none = 0)
+ parameter (omp_lock_hint_uncontended = 1)
+ parameter (omp_lock_hint_contended = 2)
+ parameter (omp_lock_hint_nonspeculative = 4)
+ parameter (omp_lock_hint_speculative = 8)
parameter (openmp_version = 201307)
external omp_init_lock, omp_init_nest_lock
+ external omp_init_lock_with_hint
+ external omp_init_nest_lock_with_hint
external omp_destroy_lock, omp_destroy_nest_lock
external omp_set_lock, omp_set_nest_lock
external omp_unset_lock, omp_unset_nest_lock
external omp_get_proc_bind
integer(omp_proc_bind_kind) omp_get_proc_bind
+ integer(4) omp_get_num_places
+ external omp_get_num_places
+ integer(4) omp_get_place_num_procs
+ external omp_get_place_num_procs
+ external omp_get_place_proc_ids
+ integer(4) omp_get_place_num
+ external omp_get_place_num
+ integer(4) omp_get_partition_num_places
+ external omp_get_partition_num_places
+ external omp_get_partition_place_nums
+
external omp_set_default_device, omp_get_default_device
external omp_get_num_devices, omp_get_num_teams
external omp_get_team_num
external omp_is_initial_device
logical(4) omp_is_initial_device
+ external omp_get_initial_device
+ integer(4) omp_get_initial_device
+
+ external omp_get_max_task_priority
+ integer(4) omp_get_max_task_priority
/* This file handles the ORDERED construct. */
#include "libgomp.h"
+#include <stdarg.h>
+#include <string.h>
+#include "doacross.h"
/* This function is called when first allocating an iteration block. That
GOMP_ordered_end (void)
{
}
+
+/* DOACROSS initialization. */
+
+#define MAX_COLLAPSED_BITS (__SIZEOF_LONG__ * __CHAR_BIT__)
+
+void
+gomp_doacross_init (unsigned ncounts, long *counts, long chunk_size)
+{
+ struct gomp_thread *thr = gomp_thread ();
+ struct gomp_team *team = thr->ts.team;
+ struct gomp_work_share *ws = thr->ts.work_share;
+ unsigned int i, bits[MAX_COLLAPSED_BITS], num_bits = 0;
+ unsigned long ent, num_ents, elt_sz, shift_sz;
+ struct gomp_doacross_work_share *doacross;
+
+ if (team == NULL || team->nthreads == 1)
+ return;
+
+ for (i = 0; i < ncounts; i++)
+ {
+ /* If any count is 0, GOMP_doacross_{post,wait} can't be called. */
+ if (counts[i] == 0)
+ return;
+
+ if (num_bits <= MAX_COLLAPSED_BITS)
+ {
+ unsigned int this_bits;
+ if (counts[i] == 1)
+ this_bits = 1;
+ else
+ this_bits = __SIZEOF_LONG__ * __CHAR_BIT__
+ - __builtin_clzl (counts[i] - 1);
+ if (num_bits + this_bits <= MAX_COLLAPSED_BITS)
+ {
+ bits[i] = this_bits;
+ num_bits += this_bits;
+ }
+ else
+ num_bits = MAX_COLLAPSED_BITS + 1;
+ }
+ }
+
+ if (ws->sched == GFS_STATIC)
+ num_ents = team->nthreads;
+ else
+ num_ents = (counts[0] - 1) / chunk_size + 1;
+ if (num_bits <= MAX_COLLAPSED_BITS)
+ {
+ elt_sz = sizeof (unsigned long);
+ shift_sz = ncounts * sizeof (unsigned int);
+ }
+ else
+ {
+ elt_sz = sizeof (unsigned long) * ncounts;
+ shift_sz = 0;
+ }
+ elt_sz = (elt_sz + 63) & ~63UL;
+
+ doacross = gomp_malloc (sizeof (*doacross) + 63 + num_ents * elt_sz
+ + shift_sz);
+ doacross->chunk_size = chunk_size;
+ doacross->elt_sz = elt_sz;
+ doacross->ncounts = ncounts;
+ doacross->flattened = false;
+ doacross->array = (unsigned char *)
+ ((((uintptr_t) (doacross + 1)) + 63 + shift_sz)
+ & ~(uintptr_t) 63);
+ if (num_bits <= MAX_COLLAPSED_BITS)
+ {
+ unsigned int shift_count = 0;
+ doacross->flattened = true;
+ for (i = ncounts; i > 0; i--)
+ {
+ doacross->shift_counts[i - 1] = shift_count;
+ shift_count += bits[i - 1];
+ }
+ for (ent = 0; ent < num_ents; ent++)
+ *(unsigned long *) (doacross->array + ent * elt_sz) = 0;
+ }
+ else
+ for (ent = 0; ent < num_ents; ent++)
+ memset (doacross->array + ent * elt_sz, '\0',
+ sizeof (unsigned long) * ncounts);
+ if (ws->sched == GFS_STATIC && chunk_size == 0)
+ {
+ unsigned long q = counts[0] / num_ents;
+ unsigned long t = counts[0] % num_ents;
+ doacross->boundary = t * (q + 1);
+ doacross->q = q;
+ doacross->t = t;
+ }
+ ws->doacross = doacross;
+}
+
+/* DOACROSS POST operation. */
+
+void
+GOMP_doacross_post (long *counts)
+{
+ struct gomp_thread *thr = gomp_thread ();
+ struct gomp_work_share *ws = thr->ts.work_share;
+ struct gomp_doacross_work_share *doacross = ws->doacross;
+ unsigned long ent;
+ unsigned int i;
+
+ if (__builtin_expect (doacross == NULL, 0))
+ {
+ __sync_synchronize ();
+ return;
+ }
+
+ if (__builtin_expect (ws->sched == GFS_STATIC, 1))
+ ent = thr->ts.team_id;
+ else
+ ent = counts[0] / doacross->chunk_size;
+ unsigned long *array = (unsigned long *) (doacross->array
+ + ent * doacross->elt_sz);
+
+ if (__builtin_expect (doacross->flattened, 1))
+ {
+ unsigned long flattened
+ = (unsigned long) counts[0] << doacross->shift_counts[0];
+
+ for (i = 1; i < doacross->ncounts; i++)
+ flattened |= (unsigned long) counts[i]
+ << doacross->shift_counts[i];
+ flattened++;
+ if (flattened == __atomic_load_n (array, MEMMODEL_ACQUIRE))
+ __atomic_thread_fence (MEMMODEL_RELEASE);
+ else
+ __atomic_store_n (array, flattened, MEMMODEL_RELEASE);
+ return;
+ }
+
+ __atomic_thread_fence (MEMMODEL_ACQUIRE);
+ for (i = doacross->ncounts; i-- > 0; )
+ {
+ if (counts[i] + 1UL != __atomic_load_n (&array[i], MEMMODEL_RELAXED))
+ __atomic_store_n (&array[i], counts[i] + 1UL, MEMMODEL_RELEASE);
+ }
+}
+
+/* DOACROSS WAIT operation. */
+
+void
+GOMP_doacross_wait (long first, ...)
+{
+ struct gomp_thread *thr = gomp_thread ();
+ struct gomp_work_share *ws = thr->ts.work_share;
+ struct gomp_doacross_work_share *doacross = ws->doacross;
+ va_list ap;
+ unsigned long ent;
+ unsigned int i;
+
+ if (__builtin_expect (doacross == NULL, 0))
+ {
+ __sync_synchronize ();
+ return;
+ }
+
+ if (__builtin_expect (ws->sched == GFS_STATIC, 1))
+ {
+ if (ws->chunk_size == 0)
+ {
+ if (first < doacross->boundary)
+ ent = first / (doacross->q + 1);
+ else
+ ent = (first - doacross->boundary) / doacross->q
+ + doacross->t;
+ }
+ else
+ ent = first / ws->chunk_size % thr->ts.team->nthreads;
+ }
+ else
+ ent = first / doacross->chunk_size;
+ unsigned long *array = (unsigned long *) (doacross->array
+ + ent * doacross->elt_sz);
+
+ if (__builtin_expect (doacross->flattened, 1))
+ {
+ unsigned long flattened
+ = (unsigned long) first << doacross->shift_counts[0];
+ unsigned long cur;
+
+ va_start (ap, first);
+ for (i = 1; i < doacross->ncounts; i++)
+ flattened |= (unsigned long) va_arg (ap, long)
+ << doacross->shift_counts[i];
+ cur = __atomic_load_n (array, MEMMODEL_ACQUIRE);
+ if (flattened < cur)
+ {
+ __atomic_thread_fence (MEMMODEL_RELEASE);
+ va_end (ap);
+ return;
+ }
+ doacross_spin (array, flattened, cur);
+ __atomic_thread_fence (MEMMODEL_RELEASE);
+ va_end (ap);
+ return;
+ }
+
+ do
+ {
+ va_start (ap, first);
+ for (i = 0; i < doacross->ncounts; i++)
+ {
+ unsigned long thisv
+ = (unsigned long) (i ? va_arg (ap, long) : first) + 1;
+ unsigned long cur = __atomic_load_n (&array[i], MEMMODEL_RELAXED);
+ if (thisv < cur)
+ {
+ i = doacross->ncounts;
+ break;
+ }
+ if (thisv > cur)
+ break;
+ }
+ va_end (ap);
+ if (i == doacross->ncounts)
+ break;
+ cpu_relax ();
+ }
+ while (1);
+ __sync_synchronize ();
+}
+
+typedef unsigned long long gomp_ull;
+
+void
+gomp_doacross_ull_init (unsigned ncounts, gomp_ull *counts, gomp_ull chunk_size)
+{
+ struct gomp_thread *thr = gomp_thread ();
+ struct gomp_team *team = thr->ts.team;
+ struct gomp_work_share *ws = thr->ts.work_share;
+ unsigned int i, bits[MAX_COLLAPSED_BITS], num_bits = 0;
+ unsigned long ent, num_ents, elt_sz, shift_sz;
+ struct gomp_doacross_work_share *doacross;
+
+ if (team == NULL || team->nthreads == 1)
+ return;
+
+ for (i = 0; i < ncounts; i++)
+ {
+ /* If any count is 0, GOMP_doacross_{post,wait} can't be called. */
+ if (counts[i] == 0)
+ return;
+
+ if (num_bits <= MAX_COLLAPSED_BITS)
+ {
+ unsigned int this_bits;
+ if (counts[i] == 1)
+ this_bits = 1;
+ else
+ this_bits = __SIZEOF_LONG_LONG__ * __CHAR_BIT__
+ - __builtin_clzll (counts[i] - 1);
+ if (num_bits + this_bits <= MAX_COLLAPSED_BITS)
+ {
+ bits[i] = this_bits;
+ num_bits += this_bits;
+ }
+ else
+ num_bits = MAX_COLLAPSED_BITS + 1;
+ }
+ }
+
+ if (ws->sched == GFS_STATIC)
+ num_ents = team->nthreads;
+ else
+ num_ents = (counts[0] - 1) / chunk_size + 1;
+ if (num_bits <= MAX_COLLAPSED_BITS)
+ {
+ elt_sz = sizeof (unsigned long);
+ shift_sz = ncounts * sizeof (unsigned int);
+ }
+ else
+ {
+ if (sizeof (gomp_ull) == sizeof (unsigned long))
+ elt_sz = sizeof (gomp_ull) * ncounts;
+ else if (sizeof (gomp_ull) == 2 * sizeof (unsigned long))
+ elt_sz = sizeof (unsigned long) * 2 * ncounts;
+ else
+ abort ();
+ shift_sz = 0;
+ }
+ elt_sz = (elt_sz + 63) & ~63UL;
+
+ doacross = gomp_malloc (sizeof (*doacross) + 63 + num_ents * elt_sz
+ + shift_sz);
+ doacross->chunk_size_ull = chunk_size;
+ doacross->elt_sz = elt_sz;
+ doacross->ncounts = ncounts;
+ doacross->flattened = false;
+ doacross->boundary = 0;
+ doacross->array = (unsigned char *)
+ ((((uintptr_t) (doacross + 1)) + 63 + shift_sz)
+ & ~(uintptr_t) 63);
+ if (num_bits <= MAX_COLLAPSED_BITS)
+ {
+ unsigned int shift_count = 0;
+ doacross->flattened = true;
+ for (i = ncounts; i > 0; i--)
+ {
+ doacross->shift_counts[i - 1] = shift_count;
+ shift_count += bits[i - 1];
+ }
+ for (ent = 0; ent < num_ents; ent++)
+ *(unsigned long *) (doacross->array + ent * elt_sz) = 0;
+ }
+ else
+ for (ent = 0; ent < num_ents; ent++)
+ memset (doacross->array + ent * elt_sz, '\0',
+ sizeof (unsigned long) * ncounts);
+ if (ws->sched == GFS_STATIC && chunk_size == 0)
+ {
+ gomp_ull q = counts[0] / num_ents;
+ gomp_ull t = counts[0] % num_ents;
+ doacross->boundary_ull = t * (q + 1);
+ doacross->q_ull = q;
+ doacross->t = t;
+ }
+ ws->doacross = doacross;
+}
+
+/* DOACROSS POST operation. */
+
+void
+GOMP_doacross_ull_post (gomp_ull *counts)
+{
+ struct gomp_thread *thr = gomp_thread ();
+ struct gomp_work_share *ws = thr->ts.work_share;
+ struct gomp_doacross_work_share *doacross = ws->doacross;
+ unsigned long ent;
+ unsigned int i;
+
+ if (__builtin_expect (doacross == NULL, 0))
+ {
+ __sync_synchronize ();
+ return;
+ }
+
+ if (__builtin_expect (ws->sched == GFS_STATIC, 1))
+ ent = thr->ts.team_id;
+ else
+ ent = counts[0] / doacross->chunk_size_ull;
+
+ if (__builtin_expect (doacross->flattened, 1))
+ {
+ unsigned long *array = (unsigned long *) (doacross->array
+ + ent * doacross->elt_sz);
+ gomp_ull flattened
+ = counts[0] << doacross->shift_counts[0];
+
+ for (i = 1; i < doacross->ncounts; i++)
+ flattened |= counts[i] << doacross->shift_counts[i];
+ flattened++;
+ if (flattened == __atomic_load_n (array, MEMMODEL_ACQUIRE))
+ __atomic_thread_fence (MEMMODEL_RELEASE);
+ else
+ __atomic_store_n (array, flattened, MEMMODEL_RELEASE);
+ return;
+ }
+
+ __atomic_thread_fence (MEMMODEL_ACQUIRE);
+ if (sizeof (gomp_ull) == sizeof (unsigned long))
+ {
+ gomp_ull *array = (gomp_ull *) (doacross->array
+ + ent * doacross->elt_sz);
+
+ for (i = doacross->ncounts; i-- > 0; )
+ {
+ if (counts[i] + 1UL != __atomic_load_n (&array[i], MEMMODEL_RELAXED))
+ __atomic_store_n (&array[i], counts[i] + 1UL, MEMMODEL_RELEASE);
+ }
+ }
+ else
+ {
+ unsigned long *array = (unsigned long *) (doacross->array
+ + ent * doacross->elt_sz);
+
+ for (i = doacross->ncounts; i-- > 0; )
+ {
+ gomp_ull cull = counts[i] + 1UL;
+ unsigned long c = (unsigned long) cull;
+ if (c != __atomic_load_n (&array[2 * i + 1], MEMMODEL_RELAXED))
+ __atomic_store_n (&array[2 * i + 1], c, MEMMODEL_RELEASE);
+ c = cull >> (__SIZEOF_LONG_LONG__ * __CHAR_BIT__ / 2);
+ if (c != __atomic_load_n (&array[2 * i], MEMMODEL_RELAXED))
+ __atomic_store_n (&array[2 * i], c, MEMMODEL_RELEASE);
+ }
+ }
+}
+
+/* DOACROSS WAIT operation. */
+
+void
+GOMP_doacross_ull_wait (gomp_ull first, ...)
+{
+ struct gomp_thread *thr = gomp_thread ();
+ struct gomp_work_share *ws = thr->ts.work_share;
+ struct gomp_doacross_work_share *doacross = ws->doacross;
+ va_list ap;
+ unsigned long ent;
+ unsigned int i;
+
+ if (__builtin_expect (doacross == NULL, 0))
+ {
+ __sync_synchronize ();
+ return;
+ }
+
+ if (__builtin_expect (ws->sched == GFS_STATIC, 1))
+ {
+ if (ws->chunk_size_ull == 0)
+ {
+ if (first < doacross->boundary_ull)
+ ent = first / (doacross->q_ull + 1);
+ else
+ ent = (first - doacross->boundary_ull) / doacross->q_ull
+ + doacross->t;
+ }
+ else
+ ent = first / ws->chunk_size_ull % thr->ts.team->nthreads;
+ }
+ else
+ ent = first / doacross->chunk_size_ull;
+
+ if (__builtin_expect (doacross->flattened, 1))
+ {
+ unsigned long *array = (unsigned long *) (doacross->array
+ + ent * doacross->elt_sz);
+ gomp_ull flattened = first << doacross->shift_counts[0];
+ unsigned long cur;
+
+ va_start (ap, first);
+ for (i = 1; i < doacross->ncounts; i++)
+ flattened |= va_arg (ap, gomp_ull)
+ << doacross->shift_counts[i];
+ cur = __atomic_load_n (array, MEMMODEL_ACQUIRE);
+ if (flattened < cur)
+ {
+ __atomic_thread_fence (MEMMODEL_RELEASE);
+ va_end (ap);
+ return;
+ }
+ doacross_spin (array, flattened, cur);
+ __atomic_thread_fence (MEMMODEL_RELEASE);
+ va_end (ap);
+ return;
+ }
+
+ if (sizeof (gomp_ull) == sizeof (unsigned long))
+ {
+ gomp_ull *array = (gomp_ull *) (doacross->array
+ + ent * doacross->elt_sz);
+ do
+ {
+ va_start (ap, first);
+ for (i = 0; i < doacross->ncounts; i++)
+ {
+ gomp_ull thisv
+ = (i ? va_arg (ap, gomp_ull) : first) + 1;
+ gomp_ull cur = __atomic_load_n (&array[i], MEMMODEL_RELAXED);
+ if (thisv < cur)
+ {
+ i = doacross->ncounts;
+ break;
+ }
+ if (thisv > cur)
+ break;
+ }
+ va_end (ap);
+ if (i == doacross->ncounts)
+ break;
+ cpu_relax ();
+ }
+ while (1);
+ }
+ else
+ {
+ unsigned long *array = (unsigned long *) (doacross->array
+ + ent * doacross->elt_sz);
+ do
+ {
+ va_start (ap, first);
+ for (i = 0; i < doacross->ncounts; i++)
+ {
+ gomp_ull thisv
+ = (i ? va_arg (ap, gomp_ull) : first) + 1;
+ unsigned long t
+ = thisv >> (__SIZEOF_LONG_LONG__ * __CHAR_BIT__ / 2);
+ unsigned long cur
+ = __atomic_load_n (&array[2 * i], MEMMODEL_RELAXED);
+ if (t < cur)
+ {
+ i = doacross->ncounts;
+ break;
+ }
+ if (t > cur)
+ break;
+ t = thisv;
+ cur = __atomic_load_n (&array[2 * i + 1], MEMMODEL_RELAXED);
+ if (t < cur)
+ {
+ i = doacross->ncounts;
+ break;
+ }
+ if (t > cur)
+ break;
+ }
+ va_end (ap);
+ if (i == doacross->ncounts)
+ break;
+ cpu_relax ();
+ }
+ while (1);
+ }
+ __sync_synchronize ();
+}
#endif
#include <string.h>
#include <assert.h>
+#include <errno.h>
#ifdef PLUGIN_SUPPORT
#include <dlfcn.h>
if (device_id < 0 || device_id >= gomp_get_num_devices ())
return NULL;
+ gomp_mutex_lock (&devices[device_id].lock);
+ if (!devices[device_id].is_initialized)
+ gomp_init_device (&devices[device_id]);
+ gomp_mutex_unlock (&devices[device_id].lock);
+
return &devices[device_id];
}
-/* Handle the case where splay_tree_lookup found oldn for newn.
+static inline splay_tree_key
+gomp_map_lookup (splay_tree mem_map, splay_tree_key key)
+{
+ if (key->host_start != key->host_end)
+ return splay_tree_lookup (mem_map, key);
+
+ key->host_end++;
+ splay_tree_key n = splay_tree_lookup (mem_map, key);
+ key->host_end--;
+ if (n)
+ return n;
+ key->host_start--;
+ n = splay_tree_lookup (mem_map, key);
+ key->host_start++;
+ if (n)
+ return n;
+ return splay_tree_lookup (mem_map, key);
+}
+
+/* Handle the case where gomp_map_lookup found oldn for newn.
Helper function of gomp_map_vars. */
static inline void
gomp_map_vars_existing (struct gomp_device_descr *devicep, splay_tree_key oldn,
- splay_tree_key newn, unsigned char kind)
+ splay_tree_key newn, struct target_var_desc *tgt_var,
+ unsigned char kind)
{
+ tgt_var->key = oldn;
+ tgt_var->copy_from = GOMP_MAP_COPY_FROM_P (kind);
+ tgt_var->always_copy_from = GOMP_MAP_ALWAYS_FROM_P (kind);
+ tgt_var->offset = newn->host_start - oldn->host_start;
+ tgt_var->length = newn->host_end - newn->host_start;
+
if ((kind & GOMP_MAP_FLAG_FORCE)
|| oldn->host_start > newn->host_start
|| oldn->host_end < newn->host_end)
(void *) newn->host_start, (void *) newn->host_end,
(void *) oldn->host_start, (void *) oldn->host_end);
}
- oldn->refcount++;
+
+ if (GOMP_MAP_ALWAYS_TO_P (kind))
+ devicep->host2dev_func (devicep->target_id,
+ (void *) (oldn->tgt->tgt_start + oldn->tgt_offset
+ + newn->host_start - oldn->host_start),
+ (void *) newn->host_start,
+ newn->host_end - newn->host_start);
+ if (oldn->refcount != REFCOUNT_INFINITY)
+ oldn->refcount++;
}
static int
-get_kind (bool is_openacc, void *kinds, int idx)
+get_kind (bool short_mapkind, void *kinds, int idx)
{
- return is_openacc ? ((unsigned short *) kinds)[idx]
- : ((unsigned char *) kinds)[idx];
+ return short_mapkind ? ((unsigned short *) kinds)[idx]
+ : ((unsigned char *) kinds)[idx];
}
static void
}
/* Add bias to the pointer value. */
cur_node.host_start += bias;
- cur_node.host_end = cur_node.host_start + 1;
- splay_tree_key n = splay_tree_lookup (mem_map, &cur_node);
- if (n == NULL)
- {
- /* Could be possibly zero size array section. */
- cur_node.host_end--;
- n = splay_tree_lookup (mem_map, &cur_node);
- if (n == NULL)
- {
- cur_node.host_start--;
- n = splay_tree_lookup (mem_map, &cur_node);
- cur_node.host_start++;
- }
- }
+ cur_node.host_end = cur_node.host_start;
+ splay_tree_key n = gomp_map_lookup (mem_map, &cur_node);
if (n == NULL)
{
gomp_mutex_unlock (&devicep->lock);
sizeof (void *));
}
+static void
+gomp_map_fields_existing (struct target_mem_desc *tgt, splay_tree_key n,
+ size_t first, size_t i, void **hostaddrs,
+ size_t *sizes, void *kinds)
+{
+ struct gomp_device_descr *devicep = tgt->device_descr;
+ struct splay_tree_s *mem_map = &devicep->mem_map;
+ struct splay_tree_key_s cur_node;
+ int kind;
+ const bool short_mapkind = true;
+ const int typemask = short_mapkind ? 0xff : 0x7;
+
+ cur_node.host_start = (uintptr_t) hostaddrs[i];
+ cur_node.host_end = cur_node.host_start + sizes[i];
+ splay_tree_key n2 = splay_tree_lookup (mem_map, &cur_node);
+ kind = get_kind (short_mapkind, kinds, i);
+ if (n2
+ && n2->tgt == n->tgt
+ && n2->host_start - n->host_start == n2->tgt_offset - n->tgt_offset)
+ {
+ gomp_map_vars_existing (devicep, n2, &cur_node,
+ &tgt->list[i], kind & typemask);
+ return;
+ }
+ if (sizes[i] == 0)
+ {
+ if (cur_node.host_start > (uintptr_t) hostaddrs[first - 1])
+ {
+ cur_node.host_start--;
+ n2 = splay_tree_lookup (mem_map, &cur_node);
+ cur_node.host_start++;
+ if (n2
+ && n2->tgt == n->tgt
+ && n2->host_start - n->host_start
+ == n2->tgt_offset - n->tgt_offset)
+ {
+ gomp_map_vars_existing (devicep, n2, &cur_node, &tgt->list[i],
+ kind & typemask);
+ return;
+ }
+ }
+ cur_node.host_end++;
+ n2 = splay_tree_lookup (mem_map, &cur_node);
+ cur_node.host_end--;
+ if (n2
+ && n2->tgt == n->tgt
+ && n2->host_start - n->host_start == n2->tgt_offset - n->tgt_offset)
+ {
+ gomp_map_vars_existing (devicep, n2, &cur_node, &tgt->list[i],
+ kind & typemask);
+ return;
+ }
+ }
+ gomp_mutex_unlock (&devicep->lock);
+ gomp_fatal ("Trying to map into device [%p..%p) structure element when "
+ "other mapped elements from the same structure weren't mapped "
+ "together with it", (void *) cur_node.host_start,
+ (void *) cur_node.host_end);
+}
+
attribute_hidden struct target_mem_desc *
gomp_map_vars (struct gomp_device_descr *devicep, size_t mapnum,
void **hostaddrs, void **devaddrs, size_t *sizes, void *kinds,
- bool is_openacc, bool is_target)
+ bool short_mapkind, enum gomp_map_vars_kind pragma_kind)
{
size_t i, tgt_align, tgt_size, not_found_cnt = 0;
- const int rshift = is_openacc ? 8 : 3;
- const int typemask = is_openacc ? 0xff : 0x7;
+ bool has_firstprivate = false;
+ const int rshift = short_mapkind ? 8 : 3;
+ const int typemask = short_mapkind ? 0xff : 0x7;
struct splay_tree_s *mem_map = &devicep->mem_map;
struct splay_tree_key_s cur_node;
struct target_mem_desc *tgt
= gomp_malloc (sizeof (*tgt) + sizeof (tgt->list[0]) * mapnum);
tgt->list_count = mapnum;
- tgt->refcount = 1;
+ tgt->refcount = pragma_kind == GOMP_MAP_VARS_ENTER_DATA ? 0 : 1;
tgt->device_descr = devicep;
if (mapnum == 0)
tgt_align = sizeof (void *);
tgt_size = 0;
- if (is_target)
+ if (pragma_kind == GOMP_MAP_VARS_TARGET)
{
size_t align = 4 * sizeof (void *);
tgt_align = align;
for (i = 0; i < mapnum; i++)
{
- int kind = get_kind (is_openacc, kinds, i);
- if (hostaddrs[i] == NULL)
+ int kind = get_kind (short_mapkind, kinds, i);
+ if (hostaddrs[i] == NULL
+ || (kind & typemask) == GOMP_MAP_FIRSTPRIVATE_INT)
{
- tgt->list[i] = NULL;
+ tgt->list[i].key = NULL;
+ tgt->list[i].offset = ~(uintptr_t) 0;
+ continue;
+ }
+ else if ((kind & typemask) == GOMP_MAP_USE_DEVICE_PTR)
+ {
+ cur_node.host_start = (uintptr_t) hostaddrs[i];
+ cur_node.host_end = cur_node.host_start;
+ splay_tree_key n = gomp_map_lookup (mem_map, &cur_node);
+ if (n == NULL)
+ {
+ gomp_mutex_unlock (&devicep->lock);
+ gomp_fatal ("use_device_ptr pointer wasn't mapped");
+ }
+ cur_node.host_start -= n->host_start;
+ hostaddrs[i]
+ = (void *) (n->tgt->tgt_start + n->tgt_offset
+ + cur_node.host_start);
+ tgt->list[i].key = NULL;
+ tgt->list[i].offset = ~(uintptr_t) 0;
+ continue;
+ }
+ else if ((kind & typemask) == GOMP_MAP_STRUCT)
+ {
+ size_t first = i + 1;
+ size_t last = i + sizes[i];
+ cur_node.host_start = (uintptr_t) hostaddrs[i];
+ cur_node.host_end = (uintptr_t) hostaddrs[last]
+ + sizes[last];
+ tgt->list[i].key = NULL;
+ tgt->list[i].offset = ~(uintptr_t) 2;
+ splay_tree_key n = splay_tree_lookup (mem_map, &cur_node);
+ if (n == NULL)
+ {
+ size_t align = (size_t) 1 << (kind >> rshift);
+ if (tgt_align < align)
+ tgt_align = align;
+ tgt_size -= (uintptr_t) hostaddrs[first]
+ - (uintptr_t) hostaddrs[i];
+ tgt_size = (tgt_size + align - 1) & ~(align - 1);
+ tgt_size += cur_node.host_end - (uintptr_t) hostaddrs[i];
+ not_found_cnt += last - i;
+ for (i = first; i <= last; i++)
+ tgt->list[i].key = NULL;
+ i--;
+ continue;
+ }
+ for (i = first; i <= last; i++)
+ gomp_map_fields_existing (tgt, n, first, i, hostaddrs,
+ sizes, kinds);
+ i--;
continue;
}
cur_node.host_start = (uintptr_t) hostaddrs[i];
cur_node.host_end = cur_node.host_start + sizes[i];
else
cur_node.host_end = cur_node.host_start + sizeof (void *);
- splay_tree_key n = splay_tree_lookup (mem_map, &cur_node);
- if (n)
+ if ((kind & typemask) == GOMP_MAP_FIRSTPRIVATE)
+ {
+ tgt->list[i].key = NULL;
+
+ size_t align = (size_t) 1 << (kind >> rshift);
+ if (tgt_align < align)
+ tgt_align = align;
+ tgt_size = (tgt_size + align - 1) & ~(align - 1);
+ tgt_size += cur_node.host_end - cur_node.host_start;
+ has_firstprivate = true;
+ continue;
+ }
+ splay_tree_key n;
+ if ((kind & typemask) == GOMP_MAP_ZERO_LEN_ARRAY_SECTION)
{
- tgt->list[i] = n;
- gomp_map_vars_existing (devicep, n, &cur_node, kind & typemask);
+ n = gomp_map_lookup (mem_map, &cur_node);
+ if (!n)
+ {
+ tgt->list[i].key = NULL;
+ tgt->list[i].offset = ~(uintptr_t) 1;
+ continue;
+ }
}
+ else
+ n = splay_tree_lookup (mem_map, &cur_node);
+ if (n)
+ gomp_map_vars_existing (devicep, n, &cur_node, &tgt->list[i],
+ kind & typemask);
else
{
- tgt->list[i] = NULL;
+ tgt->list[i].key = NULL;
size_t align = (size_t) 1 << (kind >> rshift);
not_found_cnt++;
{
size_t j;
for (j = i + 1; j < mapnum; j++)
- if (!GOMP_MAP_POINTER_P (get_kind (is_openacc, kinds, j)
+ if (!GOMP_MAP_POINTER_P (get_kind (short_mapkind, kinds, j)
& typemask))
break;
else if ((uintptr_t) hostaddrs[j] < cur_node.host_start
break;
else
{
- tgt->list[j] = NULL;
+ tgt->list[j].key = NULL;
i++;
}
}
tgt->tgt_start = (uintptr_t) tgt->to_free;
tgt->tgt_end = tgt->tgt_start + sizes[0];
}
- else if (not_found_cnt || is_target)
+ else if (not_found_cnt || pragma_kind == GOMP_MAP_VARS_TARGET)
{
/* Allocate tgt_align aligned tgt_size block of memory. */
/* FIXME: Perhaps change interface to allocate properly aligned
}
tgt_size = 0;
- if (is_target)
+ if (pragma_kind == GOMP_MAP_VARS_TARGET)
tgt_size = mapnum * sizeof (void *);
tgt->array = NULL;
- if (not_found_cnt)
+ if (not_found_cnt || has_firstprivate)
{
- tgt->array = gomp_malloc (not_found_cnt * sizeof (*tgt->array));
+ if (not_found_cnt)
+ tgt->array = gomp_malloc (not_found_cnt * sizeof (*tgt->array));
splay_tree_node array = tgt->array;
- size_t j;
+ size_t j, field_tgt_offset = 0, field_tgt_clear = ~(size_t) 0;
+ uintptr_t field_tgt_base = 0;
for (i = 0; i < mapnum; i++)
- if (tgt->list[i] == NULL)
+ if (tgt->list[i].key == NULL)
{
- int kind = get_kind (is_openacc, kinds, i);
+ int kind = get_kind (short_mapkind, kinds, i);
if (hostaddrs[i] == NULL)
continue;
+ switch (kind & typemask)
+ {
+ size_t align, len, first, last;
+ splay_tree_key n;
+ case GOMP_MAP_FIRSTPRIVATE:
+ align = (size_t) 1 << (kind >> rshift);
+ tgt_size = (tgt_size + align - 1) & ~(align - 1);
+ tgt->list[i].offset = tgt_size;
+ len = sizes[i];
+ devicep->host2dev_func (devicep->target_id,
+ (void *) (tgt->tgt_start + tgt_size),
+ (void *) hostaddrs[i], len);
+ tgt_size += len;
+ continue;
+ case GOMP_MAP_FIRSTPRIVATE_INT:
+ case GOMP_MAP_USE_DEVICE_PTR:
+ case GOMP_MAP_ZERO_LEN_ARRAY_SECTION:
+ continue;
+ case GOMP_MAP_STRUCT:
+ first = i + 1;
+ last = i + sizes[i];
+ cur_node.host_start = (uintptr_t) hostaddrs[i];
+ cur_node.host_end = (uintptr_t) hostaddrs[last]
+ + sizes[last];
+ if (tgt->list[first].key != NULL)
+ continue;
+ n = splay_tree_lookup (mem_map, &cur_node);
+ if (n == NULL)
+ {
+ size_t align = (size_t) 1 << (kind >> rshift);
+ tgt_size -= (uintptr_t) hostaddrs[first]
+ - (uintptr_t) hostaddrs[i];
+ tgt_size = (tgt_size + align - 1) & ~(align - 1);
+ tgt_size += (uintptr_t) hostaddrs[first]
+ - (uintptr_t) hostaddrs[i];
+ field_tgt_base = (uintptr_t) hostaddrs[first];
+ field_tgt_offset = tgt_size;
+ field_tgt_clear = last;
+ tgt_size += cur_node.host_end
+ - (uintptr_t) hostaddrs[first];
+ continue;
+ }
+ for (i = first; i <= last; i++)
+ gomp_map_fields_existing (tgt, n, first, i, hostaddrs,
+ sizes, kinds);
+ i--;
+ continue;
+ default:
+ break;
+ }
splay_tree_key k = &array->key;
k->host_start = (uintptr_t) hostaddrs[i];
if (!GOMP_MAP_POINTER_P (kind & typemask))
k->host_end = k->host_start + sizeof (void *);
splay_tree_key n = splay_tree_lookup (mem_map, k);
if (n)
- {
- tgt->list[i] = n;
- gomp_map_vars_existing (devicep, n, k, kind & typemask);
- }
+ gomp_map_vars_existing (devicep, n, k, &tgt->list[i],
+ kind & typemask);
else
{
size_t align = (size_t) 1 << (kind >> rshift);
- tgt->list[i] = k;
- tgt_size = (tgt_size + align - 1) & ~(align - 1);
+ tgt->list[i].key = k;
k->tgt = tgt;
- k->tgt_offset = tgt_size;
- tgt_size += k->host_end - k->host_start;
- k->copy_from = GOMP_MAP_COPY_FROM_P (kind & typemask);
+ if (field_tgt_clear != ~(size_t) 0)
+ {
+ k->tgt_offset = k->host_start - field_tgt_base
+ + field_tgt_offset;
+ if (i == field_tgt_clear)
+ field_tgt_clear = ~(size_t) 0;
+ }
+ else
+ {
+ tgt_size = (tgt_size + align - 1) & ~(align - 1);
+ k->tgt_offset = tgt_size;
+ tgt_size += k->host_end - k->host_start;
+ }
+ tgt->list[i].copy_from = GOMP_MAP_COPY_FROM_P (kind & typemask);
+ tgt->list[i].always_copy_from
+ = GOMP_MAP_ALWAYS_FROM_P (kind & typemask);
+ tgt->list[i].offset = 0;
+ tgt->list[i].length = k->host_end - k->host_start;
k->refcount = 1;
k->async_refcount = 0;
tgt->refcount++;
case GOMP_MAP_FROM:
case GOMP_MAP_FORCE_ALLOC:
case GOMP_MAP_FORCE_FROM:
+ case GOMP_MAP_ALWAYS_FROM:
break;
case GOMP_MAP_TO:
case GOMP_MAP_TOFROM:
case GOMP_MAP_FORCE_TO:
case GOMP_MAP_FORCE_TOFROM:
+ case GOMP_MAP_ALWAYS_TO:
+ case GOMP_MAP_ALWAYS_TOFROM:
/* FIXME: Perhaps add some smarts, like if copying
several adjacent fields from host to target, use some
host buffer to avoid sending each var individually. */
k->host_end - k->host_start);
for (j = i + 1; j < mapnum; j++)
- if (!GOMP_MAP_POINTER_P (get_kind (is_openacc, kinds, j)
+ if (!GOMP_MAP_POINTER_P (get_kind (short_mapkind, kinds,
+ j)
& typemask))
break;
else if ((uintptr_t) hostaddrs[j] < k->host_start
break;
else
{
- tgt->list[j] = k;
- k->refcount++;
+ tgt->list[j].key = k;
+ tgt->list[j].copy_from = false;
+ tgt->list[j].always_copy_from = false;
+ if (k->refcount != REFCOUNT_INFINITY)
+ k->refcount++;
gomp_map_pointer (tgt,
(uintptr_t) *(void **) hostaddrs[j],
k->tgt_offset
}
}
- if (is_target)
+ if (pragma_kind == GOMP_MAP_VARS_TARGET)
{
for (i = 0; i < mapnum; i++)
{
- if (tgt->list[i] == NULL)
- cur_node.tgt_offset = (uintptr_t) NULL;
+ if (tgt->list[i].key == NULL)
+ {
+ if (tgt->list[i].offset == ~(uintptr_t) 0)
+ cur_node.tgt_offset = (uintptr_t) hostaddrs[i];
+ else if (tgt->list[i].offset == ~(uintptr_t) 1)
+ cur_node.tgt_offset = 0;
+ else if (tgt->list[i].offset == ~(uintptr_t) 2)
+ cur_node.tgt_offset = tgt->list[i + 1].key->tgt->tgt_start
+ + tgt->list[i + 1].key->tgt_offset
+ + tgt->list[i + 1].offset
+ + (uintptr_t) hostaddrs[i]
+ - (uintptr_t) hostaddrs[i + 1];
+ else
+ cur_node.tgt_offset = tgt->tgt_start
+ + tgt->list[i].offset;
+ }
else
- cur_node.tgt_offset = tgt->list[i]->tgt->tgt_start
- + tgt->list[i]->tgt_offset;
+ cur_node.tgt_offset = tgt->list[i].key->tgt->tgt_start
+ + tgt->list[i].key->tgt_offset
+ + tgt->list[i].offset;
/* FIXME: see above FIXME comment. */
devicep->host2dev_func (devicep->target_id,
(void *) (tgt->tgt_start
}
}
+ /* If the variable from "omp target enter data" map-list was already mapped,
+ tgt is not needed. Otherwise tgt will be freed by gomp_unmap_vars or
+ gomp_exit_data. */
+ if (pragma_kind == GOMP_MAP_VARS_ENTER_DATA && tgt->refcount == 0)
+ {
+ free (tgt);
+ tgt = NULL;
+ }
+
gomp_mutex_unlock (&devicep->lock);
return tgt;
}
gomp_mutex_lock (&devicep->lock);
for (i = 0; i < tgt->list_count; i++)
- if (tgt->list[i] == NULL)
+ if (tgt->list[i].key == NULL)
;
- else if (tgt->list[i]->refcount > 1)
+ else if (tgt->list[i].key->refcount > 1)
{
- tgt->list[i]->refcount--;
- tgt->list[i]->async_refcount++;
+ tgt->list[i].key->refcount--;
+ tgt->list[i].key->async_refcount++;
}
else
{
- splay_tree_key k = tgt->list[i];
- if (k->copy_from)
+ splay_tree_key k = tgt->list[i].key;
+ if (tgt->list[i].copy_from)
devicep->dev2host_func (devicep->target_id, (void *) k->host_start,
(void *) (k->tgt->tgt_start + k->tgt_offset),
k->host_end - k->host_start);
size_t i;
for (i = 0; i < tgt->list_count; i++)
- if (tgt->list[i] == NULL)
- ;
- else if (tgt->list[i]->refcount > 1)
- tgt->list[i]->refcount--;
- else if (tgt->list[i]->async_refcount > 0)
- tgt->list[i]->async_refcount--;
- else
- {
- splay_tree_key k = tgt->list[i];
- if (k->copy_from && do_copyfrom)
- devicep->dev2host_func (devicep->target_id, (void *) k->host_start,
- (void *) (k->tgt->tgt_start + k->tgt_offset),
- k->host_end - k->host_start);
- splay_tree_remove (&devicep->mem_map, k);
- if (k->tgt->refcount > 1)
- k->tgt->refcount--;
- else
- gomp_unmap_tgt (k->tgt);
- }
+ {
+ splay_tree_key k = tgt->list[i].key;
+ if (k == NULL)
+ continue;
+
+ bool do_unmap = false;
+ if (k->refcount > 1 && k->refcount != REFCOUNT_INFINITY)
+ k->refcount--;
+ else if (k->refcount == 1)
+ {
+ if (k->async_refcount > 0)
+ k->async_refcount--;
+ else
+ {
+ k->refcount--;
+ do_unmap = true;
+ }
+ }
+
+ if ((do_unmap && do_copyfrom && tgt->list[i].copy_from)
+ || tgt->list[i].always_copy_from)
+ devicep->dev2host_func (devicep->target_id,
+ (void *) (k->host_start + tgt->list[i].offset),
+ (void *) (k->tgt->tgt_start + k->tgt_offset
+ + tgt->list[i].offset),
+ tgt->list[i].length);
+ if (do_unmap)
+ {
+ splay_tree_remove (&devicep->mem_map, k);
+ if (k->tgt->refcount > 1)
+ k->tgt->refcount--;
+ else
+ gomp_unmap_tgt (k->tgt);
+ }
+ }
if (tgt->refcount > 1)
tgt->refcount--;
static void
gomp_update (struct gomp_device_descr *devicep, size_t mapnum, void **hostaddrs,
- size_t *sizes, void *kinds, bool is_openacc)
+ size_t *sizes, void *kinds, bool short_mapkind)
{
size_t i;
struct splay_tree_key_s cur_node;
- const int typemask = is_openacc ? 0xff : 0x7;
+ const int typemask = short_mapkind ? 0xff : 0x7;
if (!devicep)
return;
splay_tree_key n = splay_tree_lookup (&devicep->mem_map, &cur_node);
if (n)
{
- int kind = get_kind (is_openacc, kinds, i);
+ int kind = get_kind (short_mapkind, kinds, i);
if (n->host_start > cur_node.host_start
|| n->host_end < cur_node.host_end)
{
- n->host_start),
cur_node.host_end - cur_node.host_start);
}
- else
- {
- gomp_mutex_unlock (&devicep->lock);
- gomp_fatal ("Trying to update [%p..%p) object that is not mapped",
- (void *) cur_node.host_start,
- (void *) cur_node.host_end);
- }
}
gomp_mutex_unlock (&devicep->lock);
}
/* Insert host-target address mapping into splay tree. */
struct target_mem_desc *tgt = gomp_malloc (sizeof (*tgt));
tgt->array = gomp_malloc ((num_funcs + num_vars) * sizeof (*tgt->array));
- tgt->refcount = 1;
+ tgt->refcount = REFCOUNT_INFINITY;
tgt->tgt_start = 0;
tgt->tgt_end = 0;
tgt->to_free = NULL;
k->host_end = k->host_start + 1;
k->tgt = tgt;
k->tgt_offset = target_table[i].start;
- k->refcount = 1;
+ k->refcount = REFCOUNT_INFINITY;
k->async_refcount = 0;
- k->copy_from = false;
array->left = NULL;
array->right = NULL;
splay_tree_insert (&devicep->mem_map, array);
k->host_end = k->host_start + (uintptr_t) host_var_table[i * 2 + 1];
k->tgt = tgt;
k->tgt_offset = target_var->start;
- k->refcount = 1;
+ k->refcount = REFCOUNT_INFINITY;
k->async_refcount = 0;
- k->copy_from = false;
array->left = NULL;
array->right = NULL;
splay_tree_insert (&devicep->mem_map, array);
devicep->is_initialized = false;
}
+/* Host fallback for GOMP_target{,_41} routines. */
+
+static void
+gomp_target_fallback (void (*fn) (void *), void **hostaddrs)
+{
+ struct gomp_thread old_thr, *thr = gomp_thread ();
+ old_thr = *thr;
+ memset (thr, '\0', sizeof (*thr));
+ if (gomp_places_list)
+ {
+ thr->place = old_thr.place;
+ thr->ts.place_partition_len = gomp_places_list_len;
+ }
+ fn (hostaddrs);
+ gomp_free_thread (thr);
+ *thr = old_thr;
+}
+
+/* Helper function of GOMP_target{,_41} routines. */
+
+static void *
+gomp_get_target_fn_addr (struct gomp_device_descr *devicep,
+ void (*host_fn) (void *))
+{
+ if (devicep->capabilities & GOMP_OFFLOAD_CAP_NATIVE_EXEC)
+ return (void *) host_fn;
+ else
+ {
+ gomp_mutex_lock (&devicep->lock);
+ struct splay_tree_key_s k;
+ k.host_start = (uintptr_t) host_fn;
+ k.host_end = k.host_start + 1;
+ splay_tree_key tgt_fn = splay_tree_lookup (&devicep->mem_map, &k);
+ gomp_mutex_unlock (&devicep->lock);
+ if (tgt_fn == NULL)
+ gomp_fatal ("Target function wasn't mapped");
+
+ return (void *) tgt_fn->tgt_offset;
+ }
+}
+
/* Called when encountering a target directive. If DEVICE
is GOMP_DEVICE_ICV, it means use device-var ICV. If it is
GOMP_DEVICE_HOST_FALLBACK (or any value
if (devicep == NULL
|| !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400))
+ return gomp_target_fallback (fn, hostaddrs);
+
+ void *fn_addr = gomp_get_target_fn_addr (devicep, fn);
+
+ struct target_mem_desc *tgt_vars
+ = gomp_map_vars (devicep, mapnum, hostaddrs, NULL, sizes, kinds, false,
+ GOMP_MAP_VARS_TARGET);
+ struct gomp_thread old_thr, *thr = gomp_thread ();
+ old_thr = *thr;
+ memset (thr, '\0', sizeof (*thr));
+ if (gomp_places_list)
{
- /* Host fallback. */
- struct gomp_thread old_thr, *thr = gomp_thread ();
- old_thr = *thr;
- memset (thr, '\0', sizeof (*thr));
- if (gomp_places_list)
- {
- thr->place = old_thr.place;
- thr->ts.place_partition_len = gomp_places_list_len;
- }
- fn (hostaddrs);
- gomp_free_thread (thr);
- *thr = old_thr;
- return;
+ thr->place = old_thr.place;
+ thr->ts.place_partition_len = gomp_places_list_len;
}
+ devicep->run_func (devicep->target_id, fn_addr, (void *) tgt_vars->tgt_start);
+ gomp_free_thread (thr);
+ *thr = old_thr;
+ gomp_unmap_vars (tgt_vars, true);
+}
- gomp_mutex_lock (&devicep->lock);
- if (!devicep->is_initialized)
- gomp_init_device (devicep);
- gomp_mutex_unlock (&devicep->lock);
+void
+GOMP_target_41 (int device, void (*fn) (void *), size_t mapnum,
+ void **hostaddrs, size_t *sizes, unsigned short *kinds,
+ unsigned int flags, void **depend)
+{
+ struct gomp_device_descr *devicep = resolve_device (device);
- void *fn_addr;
+ /* If there are depend clauses, but nowait is not present,
+ block the parent task until the dependencies are resolved
+ and then just continue with the rest of the function as if it
+ is a merged task. */
+ if (depend != NULL)
+ {
+ struct gomp_thread *thr = gomp_thread ();
+ if (thr->task && thr->task->depend_hash)
+ gomp_task_maybe_wait_for_dependencies (depend);
+ }
- if (devicep->capabilities & GOMP_OFFLOAD_CAP_NATIVE_EXEC)
- fn_addr = (void *) fn;
- else
+ if (devicep == NULL
+ || !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400))
{
- gomp_mutex_lock (&devicep->lock);
- struct splay_tree_key_s k;
- k.host_start = (uintptr_t) fn;
- k.host_end = k.host_start + 1;
- splay_tree_key tgt_fn = splay_tree_lookup (&devicep->mem_map, &k);
- if (tgt_fn == NULL)
+ size_t i, tgt_align = 0, tgt_size = 0;
+ char *tgt = NULL;
+ for (i = 0; i < mapnum; i++)
+ if ((kinds[i] & 0xff) == GOMP_MAP_FIRSTPRIVATE)
+ {
+ size_t align = (size_t) 1 << (kinds[i] >> 8);
+ if (tgt_align < align)
+ tgt_align = align;
+ tgt_size = (tgt_size + align - 1) & ~(align - 1);
+ tgt_size += sizes[i];
+ }
+ if (tgt_align)
{
- gomp_mutex_unlock (&devicep->lock);
- gomp_fatal ("Target function wasn't mapped");
+ tgt = gomp_alloca (tgt_size + tgt_align - 1);
+ uintptr_t al = (uintptr_t) tgt & (tgt_align - 1);
+ if (al)
+ tgt += tgt_align - al;
+ tgt_size = 0;
+ for (i = 0; i < mapnum; i++)
+ if ((kinds[i] & 0xff) == GOMP_MAP_FIRSTPRIVATE)
+ {
+ size_t align = (size_t) 1 << (kinds[i] >> 8);
+ tgt_size = (tgt_size + align - 1) & ~(align - 1);
+ memcpy (tgt + tgt_size, hostaddrs[i], sizes[i]);
+ hostaddrs[i] = tgt + tgt_size;
+ tgt_size = tgt_size + sizes[i];
+ }
}
- gomp_mutex_unlock (&devicep->lock);
-
- fn_addr = (void *) tgt_fn->tgt_offset;
+ gomp_target_fallback (fn, hostaddrs);
+ return;
}
+ void *fn_addr = gomp_get_target_fn_addr (devicep, fn);
+
struct target_mem_desc *tgt_vars
- = gomp_map_vars (devicep, mapnum, hostaddrs, NULL, sizes, kinds, false,
- true);
+ = gomp_map_vars (devicep, mapnum, hostaddrs, NULL, sizes, kinds, true,
+ GOMP_MAP_VARS_TARGET);
struct gomp_thread old_thr, *thr = gomp_thread ();
old_thr = *thr;
memset (thr, '\0', sizeof (*thr));
gomp_unmap_vars (tgt_vars, true);
}
+/* Host fallback for GOMP_target_data{,_41} routines. */
+
+static void
+gomp_target_data_fallback (void)
+{
+ struct gomp_task_icv *icv = gomp_icv (false);
+ if (icv->target_data)
+ {
+ /* Even when doing a host fallback, if there are any active
+ #pragma omp target data constructs, need to remember the
+ new #pragma omp target data, otherwise GOMP_target_end_data
+ would get out of sync. */
+ struct target_mem_desc *tgt
+ = gomp_map_vars (NULL, 0, NULL, NULL, NULL, NULL, false,
+ GOMP_MAP_VARS_DATA);
+ tgt->prev = icv->target_data;
+ icv->target_data = tgt;
+ }
+}
+
void
GOMP_target_data (int device, const void *unused, size_t mapnum,
void **hostaddrs, size_t *sizes, unsigned char *kinds)
if (devicep == NULL
|| !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400))
- {
- /* Host fallback. */
- struct gomp_task_icv *icv = gomp_icv (false);
- if (icv->target_data)
- {
- /* Even when doing a host fallback, if there are any active
- #pragma omp target data constructs, need to remember the
- new #pragma omp target data, otherwise GOMP_target_end_data
- would get out of sync. */
- struct target_mem_desc *tgt
- = gomp_map_vars (NULL, 0, NULL, NULL, NULL, NULL, false, false);
- tgt->prev = icv->target_data;
- icv->target_data = tgt;
- }
- return;
- }
-
- gomp_mutex_lock (&devicep->lock);
- if (!devicep->is_initialized)
- gomp_init_device (devicep);
- gomp_mutex_unlock (&devicep->lock);
+ return gomp_target_data_fallback ();
struct target_mem_desc *tgt
= gomp_map_vars (devicep, mapnum, hostaddrs, NULL, sizes, kinds, false,
- false);
+ GOMP_MAP_VARS_DATA);
+ struct gomp_task_icv *icv = gomp_icv (true);
+ tgt->prev = icv->target_data;
+ icv->target_data = tgt;
+}
+
+void
+GOMP_target_data_41 (int device, size_t mapnum, void **hostaddrs, size_t *sizes,
+ unsigned short *kinds)
+{
+ struct gomp_device_descr *devicep = resolve_device (device);
+
+ if (devicep == NULL
+ || !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400))
+ return gomp_target_data_fallback ();
+
+ struct target_mem_desc *tgt
+ = gomp_map_vars (devicep, mapnum, hostaddrs, NULL, sizes, kinds, true,
+ GOMP_MAP_VARS_DATA);
struct gomp_task_icv *icv = gomp_icv (true);
tgt->prev = icv->target_data;
icv->target_data = tgt;
|| !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400))
return;
+ gomp_update (devicep, mapnum, hostaddrs, sizes, kinds, false);
+}
+
+void
+GOMP_target_update_41 (int device, size_t mapnum, void **hostaddrs,
+ size_t *sizes, unsigned short *kinds,
+ unsigned int flags, void **depend)
+{
+ struct gomp_device_descr *devicep = resolve_device (device);
+
+ /* If there are depend clauses, but nowait is not present,
+ block the parent task until the dependencies are resolved
+ and then just continue with the rest of the function as if it
+ is a merged task. Until we are able to schedule task during
+ variable mapping or unmapping, ignore nowait if depend clauses
+ are not present. */
+ if (depend != NULL)
+ {
+ struct gomp_thread *thr = gomp_thread ();
+ if (thr->task && thr->task->depend_hash)
+ {
+ if ((flags & GOMP_TARGET_FLAG_NOWAIT)
+ && thr->ts.team
+ && !thr->task->final_task)
+ {
+ gomp_create_target_task (devicep, (void (*) (void *)) NULL,
+ mapnum, hostaddrs, sizes, kinds,
+ flags | GOMP_TARGET_FLAG_UPDATE,
+ depend);
+ return;
+ }
+
+ struct gomp_team *team = thr->ts.team;
+ /* If parallel or taskgroup has been cancelled, don't start new
+ tasks. */
+ if (team
+ && (gomp_team_barrier_cancelled (&team->barrier)
+ || (thr->task->taskgroup
+ && thr->task->taskgroup->cancelled)))
+ return;
+
+ gomp_task_maybe_wait_for_dependencies (depend);
+ }
+ }
+
+ if (devicep == NULL
+ || !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400))
+ return;
+
+ struct gomp_thread *thr = gomp_thread ();
+ struct gomp_team *team = thr->ts.team;
+ /* If parallel or taskgroup has been cancelled, don't start new tasks. */
+ if (team
+ && (gomp_team_barrier_cancelled (&team->barrier)
+ || (thr->task->taskgroup && thr->task->taskgroup->cancelled)))
+ return;
+
+ gomp_update (devicep, mapnum, hostaddrs, sizes, kinds, true);
+}
+
+static void
+gomp_exit_data (struct gomp_device_descr *devicep, size_t mapnum,
+ void **hostaddrs, size_t *sizes, unsigned short *kinds)
+{
+ const int typemask = 0xff;
+ size_t i;
gomp_mutex_lock (&devicep->lock);
- if (!devicep->is_initialized)
- gomp_init_device (devicep);
+ for (i = 0; i < mapnum; i++)
+ {
+ struct splay_tree_key_s cur_node;
+ unsigned char kind = kinds[i] & typemask;
+ switch (kind)
+ {
+ case GOMP_MAP_FROM:
+ case GOMP_MAP_ALWAYS_FROM:
+ case GOMP_MAP_DELETE:
+ case GOMP_MAP_RELEASE:
+ case GOMP_MAP_ZERO_LEN_ARRAY_SECTION:
+ case GOMP_MAP_DELETE_ZERO_LEN_ARRAY_SECTION:
+ cur_node.host_start = (uintptr_t) hostaddrs[i];
+ cur_node.host_end = cur_node.host_start + sizes[i];
+ splay_tree_key k = (kind == GOMP_MAP_DELETE_ZERO_LEN_ARRAY_SECTION
+ || kind == GOMP_MAP_ZERO_LEN_ARRAY_SECTION)
+ ? gomp_map_lookup (&devicep->mem_map, &cur_node)
+ : splay_tree_lookup (&devicep->mem_map, &cur_node);
+ if (!k)
+ continue;
+
+ if (k->refcount > 0 && k->refcount != REFCOUNT_INFINITY)
+ k->refcount--;
+ if ((kind == GOMP_MAP_DELETE
+ || kind == GOMP_MAP_DELETE_ZERO_LEN_ARRAY_SECTION)
+ && k->refcount != REFCOUNT_INFINITY)
+ k->refcount = 0;
+
+ if ((kind == GOMP_MAP_FROM && k->refcount == 0)
+ || kind == GOMP_MAP_ALWAYS_FROM)
+ devicep->dev2host_func (devicep->target_id,
+ (void *) cur_node.host_start,
+ (void *) (k->tgt->tgt_start + k->tgt_offset
+ + cur_node.host_start
+ - k->host_start),
+ cur_node.host_end - cur_node.host_start);
+ if (k->refcount == 0)
+ {
+ splay_tree_remove (&devicep->mem_map, k);
+ if (k->tgt->refcount > 1)
+ k->tgt->refcount--;
+ else
+ gomp_unmap_tgt (k->tgt);
+ }
+
+ break;
+ default:
+ gomp_mutex_unlock (&devicep->lock);
+ gomp_fatal ("GOMP_target_enter_exit_data unhandled kind 0x%.2x",
+ kind);
+ }
+ }
+
gomp_mutex_unlock (&devicep->lock);
+}
- gomp_update (devicep, mapnum, hostaddrs, sizes, kinds, false);
+void
+GOMP_target_enter_exit_data (int device, size_t mapnum, void **hostaddrs,
+ size_t *sizes, unsigned short *kinds,
+ unsigned int flags, void **depend)
+{
+ struct gomp_device_descr *devicep = resolve_device (device);
+
+ /* If there are depend clauses, but nowait is not present,
+ block the parent task until the dependencies are resolved
+ and then just continue with the rest of the function as if it
+ is a merged task. Until we are able to schedule task during
+ variable mapping or unmapping, ignore nowait if depend clauses
+ are not present. */
+ if (depend != NULL)
+ {
+ struct gomp_thread *thr = gomp_thread ();
+ if (thr->task && thr->task->depend_hash)
+ {
+ if ((flags & GOMP_TARGET_FLAG_NOWAIT)
+ && thr->ts.team
+ && !thr->task->final_task)
+ {
+ gomp_create_target_task (devicep, (void (*) (void *)) NULL,
+ mapnum, hostaddrs, sizes, kinds,
+ flags, depend);
+ return;
+ }
+
+ struct gomp_team *team = thr->ts.team;
+ /* If parallel or taskgroup has been cancelled, don't start new
+ tasks. */
+ if (team
+ && (gomp_team_barrier_cancelled (&team->barrier)
+ || (thr->task->taskgroup
+ && thr->task->taskgroup->cancelled)))
+ return;
+
+ gomp_task_maybe_wait_for_dependencies (depend);
+ }
+ }
+
+ if (devicep == NULL
+ || !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400))
+ return;
+
+ struct gomp_thread *thr = gomp_thread ();
+ struct gomp_team *team = thr->ts.team;
+ /* If parallel or taskgroup has been cancelled, don't start new tasks. */
+ if (team
+ && (gomp_team_barrier_cancelled (&team->barrier)
+ || (thr->task->taskgroup && thr->task->taskgroup->cancelled)))
+ return;
+
+ size_t i;
+ if ((flags & GOMP_TARGET_FLAG_EXIT_DATA) == 0)
+ for (i = 0; i < mapnum; i++)
+ if ((kinds[i] & 0xff) == GOMP_MAP_STRUCT)
+ {
+ gomp_map_vars (devicep, sizes[i] + 1, &hostaddrs[i], NULL, &sizes[i],
+ &kinds[i], true, GOMP_MAP_VARS_ENTER_DATA);
+ i += sizes[i];
+ }
+ else
+ gomp_map_vars (devicep, 1, &hostaddrs[i], NULL, &sizes[i], &kinds[i],
+ true, GOMP_MAP_VARS_ENTER_DATA);
+ else
+ gomp_exit_data (devicep, mapnum, hostaddrs, sizes, kinds);
+}
+
+void
+gomp_target_task_fn (void *data)
+{
+ struct gomp_target_task *ttask = (struct gomp_target_task *) data;
+ if (ttask->fn != NULL)
+ {
+ /* GOMP_target_41 */
+ }
+ else if (ttask->devicep == NULL
+ || !(ttask->devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400))
+ return;
+
+ size_t i;
+ if (ttask->flags & GOMP_TARGET_FLAG_UPDATE)
+ gomp_update (ttask->devicep, ttask->mapnum, ttask->hostaddrs, ttask->sizes,
+ ttask->kinds, true);
+ else if ((ttask->flags & GOMP_TARGET_FLAG_EXIT_DATA) == 0)
+ for (i = 0; i < ttask->mapnum; i++)
+ if ((ttask->kinds[i] & 0xff) == GOMP_MAP_STRUCT)
+ {
+ gomp_map_vars (ttask->devicep, ttask->sizes[i] + 1,
+ &ttask->hostaddrs[i], NULL, &ttask->sizes[i],
+ &ttask->kinds[i], true, GOMP_MAP_VARS_ENTER_DATA);
+ i += ttask->sizes[i];
+ }
+ else
+ gomp_map_vars (ttask->devicep, 1, &ttask->hostaddrs[i], NULL,
+ &ttask->sizes[i], &ttask->kinds[i],
+ true, GOMP_MAP_VARS_ENTER_DATA);
+ else
+ gomp_exit_data (ttask->devicep, ttask->mapnum, ttask->hostaddrs,
+ ttask->sizes, ttask->kinds);
}
void
(void) num_teams;
}
+void *
+omp_target_alloc (size_t size, int device_num)
+{
+ if (device_num == GOMP_DEVICE_HOST_FALLBACK)
+ return malloc (size);
+
+ if (device_num < 0)
+ return NULL;
+
+ struct gomp_device_descr *devicep = resolve_device (device_num);
+ if (devicep == NULL)
+ return NULL;
+
+ if (!(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400))
+ return malloc (size);
+
+ gomp_mutex_lock (&devicep->lock);
+ void *ret = devicep->alloc_func (devicep->target_id, size);
+ gomp_mutex_unlock (&devicep->lock);
+ return ret;
+}
+
+void
+omp_target_free (void *device_ptr, int device_num)
+{
+ if (device_ptr == NULL)
+ return;
+
+ if (device_num == GOMP_DEVICE_HOST_FALLBACK)
+ {
+ free (device_ptr);
+ return;
+ }
+
+ if (device_num < 0)
+ return;
+
+ struct gomp_device_descr *devicep = resolve_device (device_num);
+ if (devicep == NULL)
+ return;
+
+ if (!(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400))
+ {
+ free (device_ptr);
+ return;
+ }
+
+ gomp_mutex_lock (&devicep->lock);
+ devicep->free_func (devicep->target_id, device_ptr);
+ gomp_mutex_unlock (&devicep->lock);
+}
+
+int
+omp_target_is_present (void *ptr, int device_num)
+{
+ if (ptr == NULL)
+ return 1;
+
+ if (device_num == GOMP_DEVICE_HOST_FALLBACK)
+ return 1;
+
+ if (device_num < 0)
+ return 0;
+
+ struct gomp_device_descr *devicep = resolve_device (device_num);
+ if (devicep == NULL)
+ return 0;
+
+ if (!(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400))
+ return 1;
+
+ gomp_mutex_lock (&devicep->lock);
+ struct splay_tree_s *mem_map = &devicep->mem_map;
+ struct splay_tree_key_s cur_node;
+
+ cur_node.host_start = (uintptr_t) ptr;
+ cur_node.host_end = cur_node.host_start;
+ splay_tree_key n = gomp_map_lookup (mem_map, &cur_node);
+ int ret = n != NULL;
+ gomp_mutex_unlock (&devicep->lock);
+ return ret;
+}
+
+int
+omp_target_memcpy (void *dst, void *src, size_t length, size_t dst_offset,
+ size_t src_offset, int dst_device_num, int src_device_num)
+{
+ struct gomp_device_descr *dst_devicep = NULL, *src_devicep = NULL;
+
+ if (dst_device_num != GOMP_DEVICE_HOST_FALLBACK)
+ {
+ if (dst_device_num < 0)
+ return EINVAL;
+
+ dst_devicep = resolve_device (dst_device_num);
+ if (dst_devicep == NULL)
+ return EINVAL;
+
+ if (!(dst_devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400))
+ dst_devicep = NULL;
+ }
+ if (src_device_num != GOMP_DEVICE_HOST_FALLBACK)
+ {
+ if (src_device_num < 0)
+ return EINVAL;
+
+ src_devicep = resolve_device (src_device_num);
+ if (src_devicep == NULL)
+ return EINVAL;
+
+ if (!(src_devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400))
+ src_devicep = NULL;
+ }
+ if (src_devicep == NULL && dst_devicep == NULL)
+ {
+ memcpy ((char *) dst + dst_offset, (char *) src + src_offset, length);
+ return 0;
+ }
+ if (src_devicep == NULL)
+ {
+ gomp_mutex_lock (&dst_devicep->lock);
+ dst_devicep->host2dev_func (dst_devicep->target_id,
+ (char *) dst + dst_offset,
+ (char *) src + src_offset, length);
+ gomp_mutex_unlock (&dst_devicep->lock);
+ return 0;
+ }
+ if (dst_devicep == NULL)
+ {
+ gomp_mutex_lock (&src_devicep->lock);
+ src_devicep->dev2host_func (src_devicep->target_id,
+ (char *) dst + dst_offset,
+ (char *) src + src_offset, length);
+ gomp_mutex_unlock (&src_devicep->lock);
+ return 0;
+ }
+ if (src_devicep == dst_devicep)
+ {
+ gomp_mutex_lock (&src_devicep->lock);
+ src_devicep->dev2dev_func (src_devicep->target_id,
+ (char *) dst + dst_offset,
+ (char *) src + src_offset, length);
+ gomp_mutex_unlock (&src_devicep->lock);
+ return 0;
+ }
+ return EINVAL;
+}
+
+static int
+omp_target_memcpy_rect_worker (void *dst, void *src, size_t element_size,
+ int num_dims, const size_t *volume,
+ const size_t *dst_offsets,
+ const size_t *src_offsets,
+ const size_t *dst_dimensions,
+ const size_t *src_dimensions,
+ struct gomp_device_descr *dst_devicep,
+ struct gomp_device_descr *src_devicep)
+{
+ size_t dst_slice = element_size;
+ size_t src_slice = element_size;
+ size_t j, dst_off, src_off, length;
+ int i, ret;
+
+ if (num_dims == 1)
+ {
+ if (__builtin_mul_overflow (element_size, volume[0], &length)
+ || __builtin_mul_overflow (element_size, dst_offsets[0], &dst_off)
+ || __builtin_mul_overflow (element_size, src_offsets[0], &src_off))
+ return EINVAL;
+ if (dst_devicep == NULL && src_devicep == NULL)
+ memcpy ((char *) dst + dst_off, (char *) src + src_off, length);
+ else if (src_devicep == NULL)
+ dst_devicep->host2dev_func (dst_devicep->target_id,
+ (char *) dst + dst_off,
+ (char *) src + src_off, length);
+ else if (dst_devicep == NULL)
+ src_devicep->dev2host_func (src_devicep->target_id,
+ (char *) dst + dst_off,
+ (char *) src + src_off, length);
+ else if (src_devicep == dst_devicep)
+ src_devicep->dev2dev_func (src_devicep->target_id,
+ (char *) dst + dst_off,
+ (char *) src + src_off, length);
+ else
+ return EINVAL;
+ return 0;
+ }
+
+ /* FIXME: it would be nice to have some plugin function to handle
+ num_dims == 2 and num_dims == 3 more efficiently. Larger ones can
+ be handled in the generic recursion below, and for host-host it
+ should be used even for any num_dims >= 2. */
+
+ for (i = 1; i < num_dims; i++)
+ if (__builtin_mul_overflow (dst_slice, dst_dimensions[i], &dst_slice)
+ || __builtin_mul_overflow (src_slice, src_dimensions[i], &src_slice))
+ return EINVAL;
+ if (__builtin_mul_overflow (dst_slice, dst_offsets[0], &dst_off)
+ || __builtin_mul_overflow (src_slice, src_offsets[0], &src_off))
+ return EINVAL;
+ for (j = 0; j < volume[0]; j++)
+ {
+ ret = omp_target_memcpy_rect_worker ((char *) dst + dst_off,
+ (char *) src + src_off,
+ element_size, num_dims - 1,
+ volume + 1, dst_offsets + 1,
+ src_offsets + 1, dst_dimensions + 1,
+ src_dimensions + 1, dst_devicep,
+ src_devicep);
+ if (ret)
+ return ret;
+ dst_off += dst_slice;
+ src_off += src_slice;
+ }
+ return 0;
+}
+
+int
+omp_target_memcpy_rect (void *dst, void *src, size_t element_size,
+ int num_dims, const size_t *volume,
+ const size_t *dst_offsets,
+ const size_t *src_offsets,
+ const size_t *dst_dimensions,
+ const size_t *src_dimensions,
+ int dst_device_num, int src_device_num)
+{
+ struct gomp_device_descr *dst_devicep = NULL, *src_devicep = NULL;
+
+ if (!dst && !src)
+ return INT_MAX;
+
+ if (dst_device_num != GOMP_DEVICE_HOST_FALLBACK)
+ {
+ if (dst_device_num < 0)
+ return EINVAL;
+
+ dst_devicep = resolve_device (dst_device_num);
+ if (dst_devicep == NULL)
+ return EINVAL;
+
+ if (!(dst_devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400))
+ dst_devicep = NULL;
+ }
+ if (src_device_num != GOMP_DEVICE_HOST_FALLBACK)
+ {
+ if (src_device_num < 0)
+ return EINVAL;
+
+ src_devicep = resolve_device (src_device_num);
+ if (src_devicep == NULL)
+ return EINVAL;
+
+ if (!(src_devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400))
+ src_devicep = NULL;
+ }
+
+ if (src_devicep != NULL && dst_devicep != NULL && src_devicep != dst_devicep)
+ return EINVAL;
+
+ if (src_devicep)
+ gomp_mutex_lock (&src_devicep->lock);
+ else if (dst_devicep)
+ gomp_mutex_lock (&dst_devicep->lock);
+ int ret = omp_target_memcpy_rect_worker (dst, src, element_size, num_dims,
+ volume, dst_offsets, src_offsets,
+ dst_dimensions, src_dimensions,
+ dst_devicep, src_devicep);
+ if (src_devicep)
+ gomp_mutex_unlock (&src_devicep->lock);
+ else if (dst_devicep)
+ gomp_mutex_unlock (&dst_devicep->lock);
+ return ret;
+}
+
+int
+omp_target_associate_ptr (void *host_ptr, void *device_ptr, size_t size,
+ size_t device_offset, int device_num)
+{
+ if (device_num == GOMP_DEVICE_HOST_FALLBACK)
+ return EINVAL;
+
+ if (device_num < 0)
+ return EINVAL;
+
+ struct gomp_device_descr *devicep = resolve_device (device_num);
+ if (devicep == NULL)
+ return EINVAL;
+
+ if (!(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400))
+ return EINVAL;
+
+ gomp_mutex_lock (&devicep->lock);
+
+ struct splay_tree_s *mem_map = &devicep->mem_map;
+ struct splay_tree_key_s cur_node;
+ int ret = EINVAL;
+
+ cur_node.host_start = (uintptr_t) host_ptr;
+ cur_node.host_end = cur_node.host_start + size;
+ splay_tree_key n = gomp_map_lookup (mem_map, &cur_node);
+ if (n)
+ {
+ if (n->tgt->tgt_start + n->tgt_offset
+ == (uintptr_t) device_ptr + device_offset
+ && n->host_start <= cur_node.host_start
+ && n->host_end >= cur_node.host_end)
+ ret = 0;
+ }
+ else
+ {
+ struct target_mem_desc *tgt = gomp_malloc (sizeof (*tgt));
+ tgt->array = gomp_malloc (sizeof (*tgt->array));
+ tgt->refcount = 1;
+ tgt->tgt_start = 0;
+ tgt->tgt_end = 0;
+ tgt->to_free = NULL;
+ tgt->prev = NULL;
+ tgt->list_count = 0;
+ tgt->device_descr = devicep;
+ splay_tree_node array = tgt->array;
+ splay_tree_key k = &array->key;
+ k->host_start = cur_node.host_start;
+ k->host_end = cur_node.host_end;
+ k->tgt = tgt;
+ k->tgt_offset = (uintptr_t) device_ptr + device_offset;
+ k->refcount = REFCOUNT_INFINITY;
+ k->async_refcount = 0;
+ array->left = NULL;
+ array->right = NULL;
+ splay_tree_insert (&devicep->mem_map, array);
+ ret = 0;
+ }
+ gomp_mutex_unlock (&devicep->lock);
+ return ret;
+}
+
+int
+omp_target_disassociate_ptr (void *ptr, int device_num)
+{
+ if (device_num == GOMP_DEVICE_HOST_FALLBACK)
+ return EINVAL;
+
+ if (device_num < 0)
+ return EINVAL;
+
+ struct gomp_device_descr *devicep = resolve_device (device_num);
+ if (devicep == NULL)
+ return EINVAL;
+
+ if (!(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400))
+ return EINVAL;
+
+ gomp_mutex_lock (&devicep->lock);
+
+ struct splay_tree_s *mem_map = &devicep->mem_map;
+ struct splay_tree_key_s cur_node;
+ int ret = EINVAL;
+
+ cur_node.host_start = (uintptr_t) ptr;
+ cur_node.host_end = cur_node.host_start;
+ splay_tree_key n = gomp_map_lookup (mem_map, &cur_node);
+ if (n
+ && n->host_start == cur_node.host_start
+ && n->refcount == REFCOUNT_INFINITY
+ && n->tgt->tgt_start == 0
+ && n->tgt->to_free == NULL
+ && n->tgt->refcount == 1
+ && n->tgt->list_count == 0)
+ {
+ splay_tree_remove (&devicep->mem_map, n);
+ gomp_unmap_tgt (n->tgt);
+ ret = 0;
+ }
+
+ gomp_mutex_unlock (&devicep->lock);
+ return ret;
+}
+
#ifdef PLUGIN_SUPPORT
/* This function tries to load a plugin for DEVICE. Name of plugin is passed
DLSYM (host2dev);
device->capabilities = device->get_caps_func ();
if (device->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)
- DLSYM (run);
+ {
+ DLSYM (run);
+ DLSYM (dev2dev);
+ }
if (device->capabilities & GOMP_OFFLOAD_CAP_OPENACC_200)
{
if (!DLSYM_OPT (openacc.exec, openacc_parallel)
#include "libgomp.h"
#include <stdlib.h>
#include <string.h>
+#include "gomp-constants.h"
typedef struct gomp_task_depend_entry *hash_entry_type;
thr->task = task->parent;
}
+/* Orphan the task in CHILDREN and all its siblings. */
+
static inline void
gomp_clear_parent (struct gomp_task *children)
{
while (task != children);
}
-static void gomp_task_maybe_wait_for_dependencies (void **depend);
+/* Helper function for GOMP_task and gomp_create_target_task. Depend clause
+ handling for undeferred task creation. */
+
+static void
+gomp_task_handle_depend (struct gomp_task *task, struct gomp_task *parent,
+ void **depend)
+{
+ size_t ndepend = (uintptr_t) depend[0];
+ size_t nout = (uintptr_t) depend[1];
+ size_t i;
+ hash_entry_type ent;
+
+ task->depend_count = ndepend;
+ task->num_dependees = 0;
+ if (parent->depend_hash == NULL)
+ parent->depend_hash = htab_create (2 * ndepend > 12 ? 2 * ndepend : 12);
+ for (i = 0; i < ndepend; i++)
+ {
+ task->depend[i].addr = depend[2 + i];
+ task->depend[i].next = NULL;
+ task->depend[i].prev = NULL;
+ task->depend[i].task = task;
+ task->depend[i].is_in = i >= nout;
+ task->depend[i].redundant = false;
+ task->depend[i].redundant_out = false;
+
+ hash_entry_type *slot = htab_find_slot (&parent->depend_hash,
+ &task->depend[i], INSERT);
+ hash_entry_type out = NULL, last = NULL;
+ if (*slot)
+ {
+ /* If multiple depends on the same task are the same, all but the
+ first one are redundant. As inout/out come first, if any of them
+ is inout/out, it will win, which is the right semantics. */
+ if ((*slot)->task == task)
+ {
+ task->depend[i].redundant = true;
+ continue;
+ }
+ for (ent = *slot; ent; ent = ent->next)
+ {
+ if (ent->redundant_out)
+ break;
+
+ last = ent;
+
+ /* depend(in:...) doesn't depend on earlier depend(in:...). */
+ if (i >= nout && ent->is_in)
+ continue;
+
+ if (!ent->is_in)
+ out = ent;
+
+ struct gomp_task *tsk = ent->task;
+ if (tsk->dependers == NULL)
+ {
+ tsk->dependers
+ = gomp_malloc (sizeof (struct gomp_dependers_vec)
+ + 6 * sizeof (struct gomp_task *));
+ tsk->dependers->n_elem = 1;
+ tsk->dependers->allocated = 6;
+ tsk->dependers->elem[0] = task;
+ task->num_dependees++;
+ continue;
+ }
+ /* We already have some other dependency on tsk from earlier
+ depend clause. */
+ else if (tsk->dependers->n_elem
+ && (tsk->dependers->elem[tsk->dependers->n_elem - 1]
+ == task))
+ continue;
+ else if (tsk->dependers->n_elem == tsk->dependers->allocated)
+ {
+ tsk->dependers->allocated
+ = tsk->dependers->allocated * 2 + 2;
+ tsk->dependers
+ = gomp_realloc (tsk->dependers,
+ sizeof (struct gomp_dependers_vec)
+ + (tsk->dependers->allocated
+ * sizeof (struct gomp_task *)));
+ }
+ tsk->dependers->elem[tsk->dependers->n_elem++] = task;
+ task->num_dependees++;
+ }
+ task->depend[i].next = *slot;
+ (*slot)->prev = &task->depend[i];
+ }
+ *slot = &task->depend[i];
+
+ /* There is no need to store more than one depend({,in}out:) task per
+ address in the hash table chain for the purpose of creation of
+ deferred tasks, because each out depends on all earlier outs, thus it
+ is enough to record just the last depend({,in}out:). For depend(in:),
+ we need to keep all of the previous ones not terminated yet, because
+ a later depend({,in}out:) might need to depend on all of them. So, if
+ the new task's clause is depend({,in}out:), we know there is at most
+ one other depend({,in}out:) clause in the list (out). For
+ non-deferred tasks we want to see all outs, so they are moved to the
+ end of the chain, after first redundant_out entry all following
+ entries should be redundant_out. */
+ if (!task->depend[i].is_in && out)
+ {
+ if (out != last)
+ {
+ out->next->prev = out->prev;
+ out->prev->next = out->next;
+ out->next = last->next;
+ out->prev = last;
+ last->next = out;
+ if (out->next)
+ out->next->prev = out;
+ }
+ out->redundant_out = true;
+ }
+ }
+}
/* Called when encountering an explicit task directive. If IF_CLAUSE is
false, then we must not delay in executing the task. If UNTIED is true,
- then the task may be executed by any member of the team. */
+ then the task may be executed by any member of the team.
+
+ DEPEND is an array containing:
+ depend[0]: number of depend elements.
+ depend[1]: number of depend elements of type "out".
+ depend[2..N+1]: address of [1..N]th depend element. */
void
GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *),
long arg_size, long arg_align, bool if_clause, unsigned flags,
- void **depend)
+ void **depend, int priority)
{
struct gomp_thread *thr = gomp_thread ();
struct gomp_team *team = thr->ts.team;
might be running on different thread than FN. */
if (cpyfn)
if_clause = false;
- if (flags & 1)
- flags &= ~1;
+ flags &= ~GOMP_TASK_FLAG_UNTIED;
#endif
/* If parallel or taskgroup has been cancelled, don't start new tasks. */
|| (thr->task->taskgroup && thr->task->taskgroup->cancelled)))
return;
+ if ((flags & GOMP_TASK_FLAG_PRIORITY) == 0)
+ priority = 0;
+ /* FIXME, use priority. */
+ (void) priority;
+
if (!if_clause || team == NULL
|| (thr->task && thr->task->final_task)
|| team->task_count > 64 * team->nthreads)
depend clauses for non-deferred tasks other than this, because
the parent task is suspended until the child task finishes and thus
it can't start further child tasks. */
- if ((flags & 8) && thr->task && thr->task->depend_hash)
+ if ((flags & GOMP_TASK_FLAG_DEPEND)
+ && thr->task && thr->task->depend_hash)
gomp_task_maybe_wait_for_dependencies (depend);
gomp_init_task (&task, thr->task, gomp_icv (false));
- task.kind = GOMP_TASK_IFFALSE;
- task.final_task = (thr->task && thr->task->final_task) || (flags & 2);
+ task.kind = GOMP_TASK_UNDEFERRED;
+ task.final_task = (thr->task && thr->task->final_task)
+ || (flags & GOMP_TASK_FLAG_FINAL);
if (thr->task)
{
task.in_tied_task = thr->task->in_tied_task;
bool do_wake;
size_t depend_size = 0;
- if (flags & 8)
+ if (flags & GOMP_TASK_FLAG_DEPEND)
depend_size = ((uintptr_t) depend[0]
* sizeof (struct gomp_task_depend_entry));
task = gomp_malloc (sizeof (*task) + depend_size
arg = (char *) (((uintptr_t) (task + 1) + depend_size + arg_align - 1)
& ~(uintptr_t) (arg_align - 1));
gomp_init_task (task, parent, gomp_icv (false));
- task->kind = GOMP_TASK_IFFALSE;
+ task->kind = GOMP_TASK_UNDEFERRED;
task->in_tied_task = parent->in_tied_task;
task->taskgroup = taskgroup;
thr->task = task;
task->kind = GOMP_TASK_WAITING;
task->fn = fn;
task->fn_data = arg;
- task->final_task = (flags & 2) >> 1;
+ task->final_task = (flags & GOMP_TASK_FLAG_FINAL) >> 1;
gomp_mutex_lock (&team->task_lock);
/* If parallel or taskgroup has been cancelled, don't start new
tasks. */
taskgroup->num_children++;
if (depend_size)
{
- size_t ndepend = (uintptr_t) depend[0];
- size_t nout = (uintptr_t) depend[1];
- size_t i;
- hash_entry_type ent;
-
- task->depend_count = ndepend;
- task->num_dependees = 0;
- if (parent->depend_hash == NULL)
- parent->depend_hash
- = htab_create (2 * ndepend > 12 ? 2 * ndepend : 12);
- for (i = 0; i < ndepend; i++)
- {
- task->depend[i].addr = depend[2 + i];
- task->depend[i].next = NULL;
- task->depend[i].prev = NULL;
- task->depend[i].task = task;
- task->depend[i].is_in = i >= nout;
- task->depend[i].redundant = false;
- task->depend[i].redundant_out = false;
-
- hash_entry_type *slot
- = htab_find_slot (&parent->depend_hash, &task->depend[i],
- INSERT);
- hash_entry_type out = NULL, last = NULL;
- if (*slot)
- {
- /* If multiple depends on the same task are the
- same, all but the first one are redundant.
- As inout/out come first, if any of them is
- inout/out, it will win, which is the right
- semantics. */
- if ((*slot)->task == task)
- {
- task->depend[i].redundant = true;
- continue;
- }
- for (ent = *slot; ent; ent = ent->next)
- {
- if (ent->redundant_out)
- break;
-
- last = ent;
-
- /* depend(in:...) doesn't depend on earlier
- depend(in:...). */
- if (i >= nout && ent->is_in)
- continue;
-
- if (!ent->is_in)
- out = ent;
-
- struct gomp_task *tsk = ent->task;
- if (tsk->dependers == NULL)
- {
- tsk->dependers
- = gomp_malloc (sizeof (struct gomp_dependers_vec)
- + 6 * sizeof (struct gomp_task *));
- tsk->dependers->n_elem = 1;
- tsk->dependers->allocated = 6;
- tsk->dependers->elem[0] = task;
- task->num_dependees++;
- continue;
- }
- /* We already have some other dependency on tsk
- from earlier depend clause. */
- else if (tsk->dependers->n_elem
- && (tsk->dependers->elem[tsk->dependers->n_elem
- - 1]
- == task))
- continue;
- else if (tsk->dependers->n_elem
- == tsk->dependers->allocated)
- {
- tsk->dependers->allocated
- = tsk->dependers->allocated * 2 + 2;
- tsk->dependers
- = gomp_realloc (tsk->dependers,
- sizeof (struct gomp_dependers_vec)
- + (tsk->dependers->allocated
- * sizeof (struct gomp_task *)));
- }
- tsk->dependers->elem[tsk->dependers->n_elem++] = task;
- task->num_dependees++;
- }
- task->depend[i].next = *slot;
- (*slot)->prev = &task->depend[i];
- }
- *slot = &task->depend[i];
-
- /* There is no need to store more than one depend({,in}out:)
- task per address in the hash table chain for the purpose
- of creation of deferred tasks, because each out
- depends on all earlier outs, thus it is enough to record
- just the last depend({,in}out:). For depend(in:), we need
- to keep all of the previous ones not terminated yet, because
- a later depend({,in}out:) might need to depend on all of
- them. So, if the new task's clause is depend({,in}out:),
- we know there is at most one other depend({,in}out:) clause
- in the list (out). For non-deferred tasks we want to see
- all outs, so they are moved to the end of the chain,
- after first redundant_out entry all following entries
- should be redundant_out. */
- if (!task->depend[i].is_in && out)
- {
- if (out != last)
- {
- out->next->prev = out->prev;
- out->prev->next = out->next;
- out->next = last->next;
- out->prev = last;
- last->next = out;
- if (out->next)
- out->next->prev = out;
- }
- out->redundant_out = true;
- }
- }
+ gomp_task_handle_depend (task, parent, depend);
if (task->num_dependees)
{
gomp_mutex_unlock (&team->task_lock);
parent->children = task;
if (taskgroup)
{
+ /* If applicable, place task into its taskgroup. */
if (taskgroup->children)
{
task->next_taskgroup = taskgroup->children;
}
}
+ialias (GOMP_taskgroup_start)
+ialias (GOMP_taskgroup_end)
+
+#define TYPE long
+#define UTYPE unsigned long
+#define TYPE_is_long 1
+#include "taskloop.c"
+#undef TYPE
+#undef UTYPE
+#undef TYPE_is_long
+
+#define TYPE unsigned long long
+#define UTYPE TYPE
+#define GOMP_taskloop GOMP_taskloop_ull
+#include "taskloop.c"
+#undef TYPE
+#undef UTYPE
+#undef GOMP_taskloop
+
+/* Called for nowait target tasks. */
+
+void
+gomp_create_target_task (struct gomp_device_descr *devicep,
+ void (*fn) (void *), size_t mapnum, void **hostaddrs,
+ size_t *sizes, unsigned short *kinds,
+ unsigned int flags, void **depend)
+{
+ struct gomp_thread *thr = gomp_thread ();
+ struct gomp_team *team = thr->ts.team;
+
+ /* If parallel or taskgroup has been cancelled, don't start new tasks. */
+ if (team
+ && (gomp_team_barrier_cancelled (&team->barrier)
+ || (thr->task->taskgroup && thr->task->taskgroup->cancelled)))
+ return;
+
+ struct gomp_target_task *ttask;
+ struct gomp_task *task;
+ struct gomp_task *parent = thr->task;
+ struct gomp_taskgroup *taskgroup = parent->taskgroup;
+ bool do_wake;
+ size_t depend_size = 0;
+
+ if (depend != NULL)
+ depend_size = ((uintptr_t) depend[0]
+ * sizeof (struct gomp_task_depend_entry));
+ task = gomp_malloc (sizeof (*task) + depend_size
+ + sizeof (*ttask)
+ + mapnum * (sizeof (void *) + sizeof (size_t)
+ + sizeof (unsigned short)));
+ gomp_init_task (task, parent, gomp_icv (false));
+ task->kind = GOMP_TASK_WAITING;
+ task->in_tied_task = parent->in_tied_task;
+ task->taskgroup = taskgroup;
+ ttask = (struct gomp_target_task *) &task->depend[(uintptr_t) depend[0]];
+ ttask->devicep = devicep;
+ ttask->fn = fn;
+ ttask->mapnum = mapnum;
+ memcpy (ttask->hostaddrs, hostaddrs, mapnum * sizeof (void *));
+ ttask->sizes = (size_t *) &ttask->hostaddrs[mapnum];
+ memcpy (ttask->sizes, sizes, mapnum * sizeof (size_t));
+ ttask->kinds = (unsigned short *) &ttask->sizes[mapnum];
+ memcpy (ttask->kinds, kinds, mapnum * sizeof (unsigned short));
+ ttask->flags = flags;
+ task->fn = gomp_target_task_fn;
+ task->fn_data = ttask;
+ task->final_task = 0;
+ gomp_mutex_lock (&team->task_lock);
+ /* If parallel or taskgroup has been cancelled, don't start new tasks. */
+ if (__builtin_expect (gomp_team_barrier_cancelled (&team->barrier)
+ || (taskgroup && taskgroup->cancelled), 0))
+ {
+ gomp_mutex_unlock (&team->task_lock);
+ gomp_finish_task (task);
+ free (task);
+ return;
+ }
+ if (taskgroup)
+ taskgroup->num_children++;
+ if (depend_size)
+ {
+ gomp_task_handle_depend (task, parent, depend);
+ if (task->num_dependees)
+ {
+ gomp_mutex_unlock (&team->task_lock);
+ return;
+ }
+ }
+ if (parent->children)
+ {
+ task->next_child = parent->children;
+ task->prev_child = parent->children->prev_child;
+ task->next_child->prev_child = task;
+ task->prev_child->next_child = task;
+ }
+ else
+ {
+ task->next_child = task;
+ task->prev_child = task;
+ }
+ parent->children = task;
+ if (taskgroup)
+ {
+ /* If applicable, place task into its taskgroup. */
+ if (taskgroup->children)
+ {
+ task->next_taskgroup = taskgroup->children;
+ task->prev_taskgroup = taskgroup->children->prev_taskgroup;
+ task->next_taskgroup->prev_taskgroup = task;
+ task->prev_taskgroup->next_taskgroup = task;
+ }
+ else
+ {
+ task->next_taskgroup = task;
+ task->prev_taskgroup = task;
+ }
+ taskgroup->children = task;
+ }
+ if (team->task_queue)
+ {
+ task->next_queue = team->task_queue;
+ task->prev_queue = team->task_queue->prev_queue;
+ task->next_queue->prev_queue = task;
+ task->prev_queue->next_queue = task;
+ }
+ else
+ {
+ task->next_queue = task;
+ task->prev_queue = task;
+ team->task_queue = task;
+ }
+ ++team->task_count;
+ ++team->task_queued_count;
+ gomp_team_barrier_set_task_pending (&team->barrier);
+ do_wake = team->task_running_count + !parent->in_tied_task
+ < team->nthreads;
+ gomp_mutex_unlock (&team->task_lock);
+ if (do_wake)
+ gomp_team_barrier_wake (&team->barrier, 1);
+}
+
+#if _LIBGOMP_CHECKING
+/* Sanity check TASK to make sure it is in its parent's children
+ queue, and that the tasks therein are in the right order.
+
+ The expected order is:
+ parent_depends_on WAITING tasks
+ !parent_depends_on WAITING tasks
+ TIED tasks
+
+ PARENT is the alleged parent of TASK. */
+
+static void
+verify_children_queue (struct gomp_task *task, struct gomp_task *parent)
+{
+ if (task->parent != parent)
+ gomp_fatal ("verify_children_queue: incompatible parents");
+ /* It's OK, Annie was an orphan and she turned out all right. */
+ if (!parent)
+ return;
+
+ bool seen_tied = false;
+ bool seen_plain_waiting = false;
+ bool found = false;
+ struct gomp_task *t = parent->children;
+ while (1)
+ {
+ if (t == task)
+ found = true;
+ if (seen_tied && t->kind == GOMP_TASK_WAITING)
+ gomp_fatal ("verify_children_queue: WAITING task after TIED");
+ if (t->kind == GOMP_TASK_TIED)
+ seen_tied = true;
+ else if (t->kind == GOMP_TASK_WAITING)
+ {
+ if (t->parent_depends_on)
+ {
+ if (seen_plain_waiting)
+ gomp_fatal ("verify_children_queue: parent_depends_on after "
+ "!parent_depends_on");
+ }
+ else
+ seen_plain_waiting = true;
+ }
+ t = t->next_child;
+ if (t == parent->children)
+ break;
+ }
+ if (!found)
+ gomp_fatal ("verify_children_queue: child not found in parent queue");
+}
+
+/* Sanity check TASK to make sure it is in its taskgroup queue (if
+ applicable), and that the tasks therein are in the right order.
+
+ The expected order is that GOMP_TASK_WAITING tasks must come before
+ GOMP_TASK_TIED tasks.
+
+ TASK is the task. */
+
+static void
+verify_taskgroup_queue (struct gomp_task *task)
+{
+ struct gomp_taskgroup *taskgroup = task->taskgroup;
+ if (!taskgroup)
+ return;
+
+ bool seen_tied = false;
+ bool found = false;
+ struct gomp_task *t = taskgroup->children;
+ while (1)
+ {
+ if (t == task)
+ found = true;
+ if (t->kind == GOMP_TASK_WAITING && seen_tied)
+ gomp_fatal ("verify_taskgroup_queue: WAITING task after TIED");
+ if (t->kind == GOMP_TASK_TIED)
+ seen_tied = true;
+ t = t->next_taskgroup;
+ if (t == taskgroup->children)
+ break;
+ }
+ if (!found)
+ gomp_fatal ("verify_taskgroup_queue: child not found in parent queue");
+}
+
+/* Verify that TASK is in the team's task queue. */
+
+static void
+verify_task_queue (struct gomp_task *task, struct gomp_team *team)
+{
+ struct gomp_task *t = team->task_queue;
+ if (team)
+ while (1)
+ {
+ if (t == task)
+ return;
+ t = t->next_queue;
+ if (t == team->task_queue)
+ break;
+ }
+ gomp_fatal ("verify_team_queue: child not in team");
+}
+#endif
+
static inline bool
gomp_task_run_pre (struct gomp_task *child_task, struct gomp_task *parent,
- struct gomp_taskgroup *taskgroup, struct gomp_team *team)
+ struct gomp_team *team)
{
+#if _LIBGOMP_CHECKING
+ verify_children_queue (child_task, parent);
+ verify_taskgroup_queue (child_task);
+ verify_task_queue (child_task, team);
+#endif
+
if (parent)
{
+ /* Adjust children such that it will point to a next child,
+ while the current one is scheduled to be executed. This way,
+ GOMP_taskwait (and others) can schedule a next task while
+ waiting.
+
+ Do not remove it entirely from the circular list, as it is
+ still a child, though not one we should consider first (say
+ by GOMP_taskwait). */
if (parent->children == child_task)
parent->children = child_task->next_child;
+ /* TIED tasks cannot come before WAITING tasks. If we're about
+ to make this task TIED, rewire things appropriately.
+ However, a TIED task at the end is perfectly fine. */
+ else if (child_task->next_child->kind == GOMP_TASK_WAITING
+ && child_task->next_child != parent->children)
+ {
+ /* Remove from the list. */
+ child_task->prev_child->next_child = child_task->next_child;
+ child_task->next_child->prev_child = child_task->prev_child;
+ /* Rewire at the end of its siblings. */
+ child_task->next_child = parent->children;
+ child_task->prev_child = parent->children->prev_child;
+ parent->children->prev_child->next_child = child_task;
+ parent->children->prev_child = child_task;
+ }
+
+ /* If the current task (child_task) is at the top of the
+ parent's last_parent_depends_on, it's about to be removed
+ from it. Adjust last_parent_depends_on appropriately. */
if (__builtin_expect (child_task->parent_depends_on, 0)
&& parent->taskwait->last_parent_depends_on == child_task)
{
+ /* The last_parent_depends_on list was built with all
+ parent_depends_on entries linked to the prev_child. Grab
+ the next last_parent_depends_on head from this prev_child if
+ available... */
if (child_task->prev_child->kind == GOMP_TASK_WAITING
&& child_task->prev_child->parent_depends_on)
parent->taskwait->last_parent_depends_on = child_task->prev_child;
else
- parent->taskwait->last_parent_depends_on = NULL;
+ {
+ /* ...otherwise, there are no more parent_depends_on
+ entries waiting to run. In which case, clear the
+ list. */
+ parent->taskwait->last_parent_depends_on = NULL;
+ }
}
}
- if (taskgroup && taskgroup->children == child_task)
- taskgroup->children = child_task->next_taskgroup;
+
+ /* Adjust taskgroup to point to the next taskgroup. See note above
+ regarding adjustment of children as to why the child_task is not
+ removed entirely from the circular list. */
+ struct gomp_taskgroup *taskgroup = child_task->taskgroup;
+ if (taskgroup)
+ {
+ if (taskgroup->children == child_task)
+ taskgroup->children = child_task->next_taskgroup;
+ /* TIED tasks cannot come before WAITING tasks. If we're about
+ to make this task TIED, rewire things appropriately.
+ However, a TIED task at the end is perfectly fine. */
+ else if (child_task->next_taskgroup->kind == GOMP_TASK_WAITING
+ && child_task->next_taskgroup != taskgroup->children)
+ {
+ /* Remove from the list. */
+ child_task->prev_taskgroup->next_taskgroup
+ = child_task->next_taskgroup;
+ child_task->next_taskgroup->prev_taskgroup
+ = child_task->prev_taskgroup;
+ /* Rewire at the end of its taskgroup. */
+ child_task->next_taskgroup = taskgroup->children;
+ child_task->prev_taskgroup = taskgroup->children->prev_taskgroup;
+ taskgroup->children->prev_taskgroup->next_taskgroup = child_task;
+ taskgroup->children->prev_taskgroup = child_task;
+ }
+ }
+
+ /* Remove child_task from the task_queue. */
child_task->prev_queue->next_queue = child_task->next_queue;
child_task->next_queue->prev_queue = child_task->prev_queue;
if (team->task_queue == child_task)
team->task_queue = NULL;
}
child_task->kind = GOMP_TASK_TIED;
+
if (--team->task_queued_count == 0)
gomp_team_barrier_clear_task_pending (&team->barrier);
if ((gomp_team_barrier_cancelled (&team->barrier)
}
}
+/* After CHILD_TASK has been run, adjust the various task queues to
+ give higher priority to the tasks that depend on CHILD_TASK.
+
+ TEAM is the team to which CHILD_TASK belongs to. */
+
static size_t
gomp_task_run_post_handle_dependers (struct gomp_task *child_task,
struct gomp_team *team)
if (parent->taskwait && parent->taskwait->last_parent_depends_on
&& !task->parent_depends_on)
{
+ /* Put depender in last_parent_depends_on. */
struct gomp_task *last_parent_depends_on
= parent->taskwait->last_parent_depends_on;
task->next_child = last_parent_depends_on->next_child;
}
else
{
+ /* Make depender a sibling of child_task, and place
+ it at the top of said sibling list. */
task->next_child = parent->children;
task->prev_child = parent->children->prev_child;
parent->children = task;
}
else
{
+ /* Make depender a sibling of child_task. */
task->next_child = task;
task->prev_child = task;
parent->children = task;
parent->taskwait->last_parent_depends_on = task;
}
}
+ /* If depender is in a taskgroup, put it at the TOP of its
+ taskgroup. */
if (taskgroup)
{
if (taskgroup->children)
gomp_sem_post (&taskgroup->taskgroup_sem);
}
}
+ /* Put depender of child_task at the END of the team's
+ task_queue. */
if (team->task_queue)
{
task->next_queue = team->task_queue;
return gomp_task_run_post_handle_dependers (child_task, team);
}
+/* Remove CHILD_TASK from its parent. */
+
static inline void
gomp_task_run_post_remove_parent (struct gomp_task *child_task)
{
struct gomp_task *parent = child_task->parent;
if (parent == NULL)
return;
+
+ /* If this was the last task the parent was depending on,
+ synchronize with gomp_task_maybe_wait_for_dependencies so it can
+ clean up and return. */
if (__builtin_expect (child_task->parent_depends_on, 0)
&& --parent->taskwait->n_depend == 0
&& parent->taskwait->in_depend_wait)
parent->taskwait->in_depend_wait = false;
gomp_sem_post (&parent->taskwait->taskwait_sem);
}
+
+ /* Remove CHILD_TASK from its sibling list. */
child_task->prev_child->next_child = child_task->next_child;
child_task->next_child->prev_child = child_task->prev_child;
if (parent->children != child_task)
}
}
+/* Remove CHILD_TASK from its taskgroup. */
+
static inline void
gomp_task_run_post_remove_taskgroup (struct gomp_task *child_task)
{
{
child_task = team->task_queue;
cancelled = gomp_task_run_pre (child_task, child_task->parent,
- child_task->taskgroup, team);
+ team);
if (__builtin_expect (cancelled, 0))
{
if (to_free)
}
}
-/* Called when encountering a taskwait directive. */
+/* Called when encountering a taskwait directive.
+
+ Wait for all children of the current task. */
void
GOMP_taskwait (void)
{
child_task = task->children;
cancelled
- = gomp_task_run_pre (child_task, task, child_task->taskgroup,
- team);
+ = gomp_task_run_pre (child_task, task, team);
if (__builtin_expect (cancelled, 0))
{
if (to_free)
finish_cancelled:;
size_t new_tasks
= gomp_task_run_post_handle_depend (child_task, team);
+
+ /* Remove child_task from children list, and set up the next
+ sibling to be run. */
child_task->prev_child->next_child = child_task->next_child;
child_task->next_child->prev_child = child_task->prev_child;
if (task->children == child_task)
else
task->children = NULL;
}
+ /* Orphan all the children of CHILD_TASK. */
gomp_clear_parent (child_task->children);
+
+ /* Remove CHILD_TASK from its taskgroup. */
gomp_task_run_post_remove_taskgroup (child_task);
+
to_free = child_task;
child_task = NULL;
team->task_count--;
}
/* This is like GOMP_taskwait, but we only wait for tasks that the
- upcoming task depends on. */
+ upcoming task depends on.
-static void
+ DEPEND is as in GOMP_task. */
+
+void
gomp_task_maybe_wait_for_dependencies (void **depend)
{
struct gomp_thread *thr = gomp_thread ();
{
tsk->parent_depends_on = true;
++num_awaited;
+ /* If a task we need to wait for is not already
+ running and is ready to be scheduled, move it to
+ front, so that we run it as soon as possible.
+
+ We rearrange the children queue such that all
+ parent_depends_on tasks are first, and
+ last_parent_depends_on points to the last such task
+ we rearranged. For example, given the following
+ children where PD[123] are the parent_depends_on
+ tasks:
+
+ task->children
+ |
+ V
+ C1 -> C2 -> C3 -> PD1 -> PD2 -> PD3 -> C4
+
+ We rearrange such that:
+
+ task->children
+ | +--- last_parent_depends_on
+ | |
+ V V
+ PD1 -> PD2 -> PD3 -> C1 -> C2 -> C3 -> C4
+ */
+
if (tsk->num_dependees == 0 && tsk->kind == GOMP_TASK_WAITING)
{
- /* If a task we need to wait for is not already
- running and is ready to be scheduled, move it
- to front, so that we run it as soon as possible. */
if (last_parent_depends_on)
{
tsk->prev_child->next_child = tsk->next_child;
{
tsk->prev_child->next_child = tsk->next_child;
tsk->next_child->prev_child = tsk->prev_child;
- tsk->prev_child = task->children;
- tsk->next_child = task->children->next_child;
+ tsk->prev_child = task->children->prev_child;
+ tsk->next_child = task->children;
task->children = tsk;
tsk->prev_child->next_child = tsk;
tsk->next_child->prev_child = tsk;
{
child_task = task->children;
cancelled
- = gomp_task_run_pre (child_task, task, child_task->taskgroup,
- team);
+ = gomp_task_run_pre (child_task, task, team);
if (__builtin_expect (cancelled, 0))
{
if (to_free)
= gomp_task_run_post_handle_depend (child_task, team);
if (child_task->parent_depends_on)
--taskwait.n_depend;
+
+ /* Remove child_task from sibling list. */
child_task->prev_child->next_child = child_task->next_child;
child_task->next_child->prev_child = child_task->prev_child;
if (task->children == child_task)
else
task->children = NULL;
}
+
gomp_clear_parent (child_task->children);
gomp_task_run_post_remove_taskgroup (child_task);
to_free = child_task;
struct gomp_taskgroup *taskgroup;
/* If team is NULL, all tasks are executed as
- GOMP_TASK_IFFALSE tasks and thus all children tasks of
+ GOMP_TASK_UNDEFERRED tasks and thus all children tasks of
taskgroup and their descendant tasks will be finished
by the time GOMP_taskgroup_end is called. */
if (team == NULL)
if (child_task->kind == GOMP_TASK_WAITING)
{
cancelled
- = gomp_task_run_pre (child_task, child_task->parent, taskgroup,
- team);
+ = gomp_task_run_pre (child_task, child_task->parent, team);
if (__builtin_expect (cancelled, 0))
{
if (to_free)
--- /dev/null
+/* Copyright (C) 2015 Free Software Foundation, Inc.
+ Contributed by Jakub Jelinek <jakub@redhat.com>.
+
+ This file is part of the GNU Offloading and Multi Processing Library
+ (libgomp).
+
+ Libgomp is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This file handles the taskloop construct. It is included twice, once
+ for the long and once for unsigned long long variant. */
+
+/* Called when encountering an explicit task directive. If IF_CLAUSE is
+ false, then we must not delay in executing the task. If UNTIED is true,
+ then the task may be executed by any member of the team. */
+
+void
+GOMP_taskloop (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *),
+ long arg_size, long arg_align, unsigned flags,
+ unsigned long num_tasks, int priority,
+ TYPE start, TYPE end, TYPE step)
+{
+ struct gomp_thread *thr = gomp_thread ();
+ struct gomp_team *team = thr->ts.team;
+
+#ifdef HAVE_BROKEN_POSIX_SEMAPHORES
+ /* If pthread_mutex_* is used for omp_*lock*, then each task must be
+ tied to one thread all the time. This means UNTIED tasks must be
+ tied and if CPYFN is non-NULL IF(0) must be forced, as CPYFN
+ might be running on different thread than FN. */
+ if (cpyfn)
+ flags &= ~GOMP_TASK_FLAG_IF;
+ flags &= ~GOMP_TASK_FLAG_UNTIED;
+#endif
+
+ /* If parallel or taskgroup has been cancelled, don't start new tasks. */
+ if (team && gomp_team_barrier_cancelled (&team->barrier))
+ return;
+
+#ifdef TYPE_is_long
+ TYPE s = step;
+ if (step > 0)
+ {
+ if (start >= end)
+ return;
+ s--;
+ }
+ else
+ {
+ if (start <= end)
+ return;
+ s++;
+ }
+ UTYPE n = (end - start + s) / step;
+#else
+ UTYPE n;
+ if (flags & GOMP_TASK_FLAG_UP)
+ {
+ if (start >= end)
+ return;
+ n = (end - start + step - 1) / step;
+ }
+ else
+ {
+ if (start <= end)
+ return;
+ n = (start - end - step - 1) / -step;
+ }
+#endif
+
+ TYPE task_step = step;
+ unsigned long nfirst = n;
+ if (flags & GOMP_TASK_FLAG_GRAINSIZE)
+ {
+ unsigned long grainsize = num_tasks;
+#ifdef TYPE_is_long
+ num_tasks = n / grainsize;
+#else
+ UTYPE ndiv = n / grainsize;
+ num_tasks = ndiv;
+ if (num_tasks != ndiv)
+ num_tasks = ~0UL;
+#endif
+ if (num_tasks <= 1)
+ {
+ num_tasks = 1;
+ task_step = end - start;
+ }
+ else if (num_tasks >= grainsize
+#ifndef TYPE_is_long
+ && num_tasks != ~0UL
+#endif
+ )
+ {
+ UTYPE mul = num_tasks * grainsize;
+ task_step = (TYPE) grainsize * step;
+ if (mul != n)
+ {
+ task_step += step;
+ nfirst = n - mul - 1;
+ }
+ }
+ else
+ {
+ UTYPE div = n / num_tasks;
+ UTYPE mod = n % num_tasks;
+ task_step = (TYPE) div * step;
+ if (mod)
+ {
+ task_step += step;
+ nfirst = mod - 1;
+ }
+ }
+ }
+ else
+ {
+ if (num_tasks == 0)
+ num_tasks = team ? team->nthreads : 1;
+ if (num_tasks >= n)
+ num_tasks = n;
+ else
+ {
+ UTYPE div = n / num_tasks;
+ UTYPE mod = n % num_tasks;
+ task_step = (TYPE) div * step;
+ if (mod)
+ {
+ task_step += step;
+ nfirst = mod - 1;
+ }
+ }
+ }
+
+ if (flags & GOMP_TASK_FLAG_NOGROUP)
+ {
+ if (thr->task && thr->task->taskgroup && thr->task->taskgroup->cancelled)
+ return;
+ }
+ else
+ ialias_call (GOMP_taskgroup_start) ();
+
+ /* FIXME, use priority. */
+ (void) priority;
+
+ if ((flags & GOMP_TASK_FLAG_IF) == 0 || team == NULL
+ || (thr->task && thr->task->final_task)
+ || team->task_count + num_tasks > 64 * team->nthreads)
+ {
+ unsigned long i;
+ if (__builtin_expect (cpyfn != NULL, 0))
+ {
+ struct gomp_task task[num_tasks];
+ struct gomp_task *parent = thr->task;
+ arg_size = (arg_size + arg_align - 1) & ~(arg_align - 1);
+ char buf[num_tasks * arg_size + arg_align - 1];
+ char *arg = (char *) (((uintptr_t) buf + arg_align - 1)
+ & ~(uintptr_t) (arg_align - 1));
+ char *orig_arg = arg;
+ for (i = 0; i < num_tasks; i++)
+ {
+ gomp_init_task (&task[i], parent, gomp_icv (false));
+ task[i].kind = GOMP_TASK_UNDEFERRED;
+ task[i].final_task = (thr->task && thr->task->final_task)
+ || (flags & GOMP_TASK_FLAG_FINAL);
+ if (thr->task)
+ {
+ task[i].in_tied_task = thr->task->in_tied_task;
+ task[i].taskgroup = thr->task->taskgroup;
+ }
+ thr->task = &task[i];
+ cpyfn (arg, data);
+ arg += arg_size;
+ }
+ arg = orig_arg;
+ for (i = 0; i < num_tasks; i++)
+ {
+ thr->task = &task[i];
+ ((TYPE *)arg)[0] = start;
+ start += task_step;
+ ((TYPE *)arg)[1] = start;
+ if (i == nfirst)
+ task_step -= step;
+ fn (arg);
+ arg += arg_size;
+ if (task[i].children != NULL)
+ {
+ gomp_mutex_lock (&team->task_lock);
+ gomp_clear_parent (task[i].children);
+ gomp_mutex_unlock (&team->task_lock);
+ }
+ gomp_end_task ();
+ }
+ }
+ else
+ for (i = 0; i < num_tasks; i++)
+ {
+ struct gomp_task task;
+
+ gomp_init_task (&task, thr->task, gomp_icv (false));
+ task.kind = GOMP_TASK_UNDEFERRED;
+ task.final_task = (thr->task && thr->task->final_task)
+ || (flags & GOMP_TASK_FLAG_FINAL);
+ if (thr->task)
+ {
+ task.in_tied_task = thr->task->in_tied_task;
+ task.taskgroup = thr->task->taskgroup;
+ }
+ thr->task = &task;
+ ((TYPE *)data)[0] = start;
+ start += task_step;
+ ((TYPE *)data)[1] = start;
+ if (i == nfirst)
+ task_step -= step;
+ fn (data);
+ if (task.children != NULL)
+ {
+ gomp_mutex_lock (&team->task_lock);
+ gomp_clear_parent (task.children);
+ gomp_mutex_unlock (&team->task_lock);
+ }
+ gomp_end_task ();
+ }
+ }
+ else
+ {
+ struct gomp_task *tasks[num_tasks];
+ struct gomp_task *parent = thr->task;
+ struct gomp_taskgroup *taskgroup = parent->taskgroup;
+ char *arg;
+ int do_wake;
+ unsigned long i;
+
+ for (i = 0; i < num_tasks; i++)
+ {
+ struct gomp_task *task
+ = gomp_malloc (sizeof (*task) + arg_size + arg_align - 1);
+ tasks[i] = task;
+ arg = (char *) (((uintptr_t) (task + 1) + arg_align - 1)
+ & ~(uintptr_t) (arg_align - 1));
+ gomp_init_task (task, parent, gomp_icv (false));
+ task->kind = GOMP_TASK_UNDEFERRED;
+ task->in_tied_task = parent->in_tied_task;
+ task->taskgroup = taskgroup;
+ thr->task = task;
+ if (cpyfn)
+ {
+ cpyfn (arg, data);
+ task->copy_ctors_done = true;
+ }
+ else
+ memcpy (arg, data, arg_size);
+ ((TYPE *)arg)[0] = start;
+ start += task_step;
+ ((TYPE *)arg)[1] = start;
+ if (i == nfirst)
+ task_step -= step;
+ thr->task = parent;
+ task->kind = GOMP_TASK_WAITING;
+ task->fn = fn;
+ task->fn_data = arg;
+ task->final_task = (flags & GOMP_TASK_FLAG_FINAL) >> 1;
+ }
+ gomp_mutex_lock (&team->task_lock);
+ /* If parallel or taskgroup has been cancelled, don't start new
+ tasks. */
+ if (__builtin_expect ((gomp_team_barrier_cancelled (&team->barrier)
+ || (taskgroup && taskgroup->cancelled))
+ && cpyfn == NULL, 0))
+ {
+ gomp_mutex_unlock (&team->task_lock);
+ for (i = 0; i < num_tasks; i++)
+ {
+ gomp_finish_task (tasks[i]);
+ free (tasks[i]);
+ }
+ if ((flags & GOMP_TASK_FLAG_NOGROUP) == 0)
+ ialias_call (GOMP_taskgroup_end) ();
+ return;
+ }
+ if (taskgroup)
+ taskgroup->num_children += num_tasks;
+ for (i = 0; i < num_tasks; i++)
+ {
+ struct gomp_task *task = tasks[i];
+ if (parent->children)
+ {
+ task->next_child = parent->children;
+ task->prev_child = parent->children->prev_child;
+ task->next_child->prev_child = task;
+ task->prev_child->next_child = task;
+ }
+ else
+ {
+ task->next_child = task;
+ task->prev_child = task;
+ }
+ parent->children = task;
+ if (taskgroup)
+ {
+ if (taskgroup->children)
+ {
+ task->next_taskgroup = taskgroup->children;
+ task->prev_taskgroup = taskgroup->children->prev_taskgroup;
+ task->next_taskgroup->prev_taskgroup = task;
+ task->prev_taskgroup->next_taskgroup = task;
+ }
+ else
+ {
+ task->next_taskgroup = task;
+ task->prev_taskgroup = task;
+ }
+ taskgroup->children = task;
+ }
+ if (team->task_queue)
+ {
+ task->next_queue = team->task_queue;
+ task->prev_queue = team->task_queue->prev_queue;
+ task->next_queue->prev_queue = task;
+ task->prev_queue->next_queue = task;
+ }
+ else
+ {
+ task->next_queue = task;
+ task->prev_queue = task;
+ team->task_queue = task;
+ }
+ ++team->task_count;
+ ++team->task_queued_count;
+ }
+ gomp_team_barrier_set_task_pending (&team->barrier);
+ if (team->task_running_count + !parent->in_tied_task
+ < team->nthreads)
+ {
+ do_wake = team->nthreads - team->task_running_count
+ - !parent->in_tied_task;
+ if ((unsigned long) do_wake > num_tasks)
+ do_wake = num_tasks;
+ }
+ else
+ do_wake = 0;
+ gomp_mutex_unlock (&team->task_lock);
+ if (do_wake)
+ gomp_team_barrier_wake (&team->barrier, do_wake);
+ }
+ if ((flags & GOMP_TASK_FLAG_NOGROUP) == 0)
+ ialias_call (GOMP_taskgroup_end) ();
+}
} ]
}
+# Return 1 if offload device is available and it has non-shared address space.
+proc check_effective_target_offload_device_nonshared_as { } {
+ return [check_runtime_nocache offload_device_nonshared_as {
+ int main ()
+ {
+ int a = 8;
+ #pragma omp target map(to: a)
+ a++;
+ return a != 8;
+ }
+ } ]
+}
+
# Return 1 if at least one nvidia board is present.
proc check_effective_target_openacc_nvidia_accel_present { } {
--- /dev/null
+// { dg-do run }
+
+#include <omp.h>
+#include <assert.h>
+
+struct B
+{
+ static int ic, dc, xc, ac, cc;
+
+ B();
+ B(const B &);
+ ~B();
+ B& operator=(const B &);
+ void doit();
+ static void clear();
+};
+
+int B::ic;
+int B::dc;
+int B::xc;
+int B::cc;
+int B::ac;
+
+B::B()
+{
+ #pragma omp atomic
+ ic++;
+}
+
+B::~B()
+{
+ #pragma omp atomic
+ dc++;
+}
+
+B::B(const B &)
+{
+ #pragma omp atomic
+ cc++;
+}
+
+B& B::operator=(const B &)
+{
+ #pragma omp atomic
+ ac++;
+ return *this;
+}
+
+void B::doit()
+{
+ #pragma omp atomic
+ xc++;
+}
+
+void B::clear()
+{
+ ic = 0;
+ dc = 0;
+ cc = 0;
+ ac = 0;
+ xc = 0;
+}
+
+static int n;
+
+void f1(B &a)
+{
+ B b;
+ B &c = b;
+ #pragma omp parallel default(none) private(a, c) shared (n)
+ {
+ #pragma omp master
+ n = omp_get_num_threads ();
+ a.doit();
+ c.doit();
+ }
+}
+
+void f2(B &a)
+{
+ B b;
+ B &c = b;
+ #pragma omp parallel default(none) firstprivate(a, c) shared(n)
+ {
+ #pragma omp master
+ n = omp_get_num_threads ();
+ a.doit();
+ c.doit();
+ }
+}
+
+void f3(B &a)
+{
+ B b;
+ B &c = b;
+ #pragma omp parallel default(none) shared(n, a, c)
+ {
+ #pragma omp master
+ n = omp_get_num_threads ();
+ #pragma omp for lastprivate (a, c)
+ for (int i = 0; i < omp_get_num_threads (); i++)
+ {
+ a.doit();
+ c.doit();
+ }
+ }
+}
+
+void f4()
+{
+ B b;
+ B &c = b;
+ #pragma omp parallel default(none) private (c) shared (n)
+ {
+ B d;
+ B &e = d;
+ #pragma omp single copyprivate (c, e)
+ {
+ c.doit();
+ e.doit();
+ }
+ c.doit();
+ e.doit();
+ }
+}
+
+void f5(B (&a)[2])
+{
+ B b[2];
+ B (&c)[2] = b;
+ #pragma omp parallel default(none) private(a, c) shared (n)
+ {
+ #pragma omp master
+ n = omp_get_num_threads ();
+ a[0].doit();
+ a[1].doit();
+ c[0].doit();
+ c[1].doit();
+ }
+}
+
+void f6(B (&a)[2])
+{
+ B b[2];
+ B (&c)[2] = b;
+ #pragma omp parallel default(none) firstprivate(a, c) shared (n)
+ {
+ #pragma omp master
+ n = omp_get_num_threads ();
+ a[0].doit();
+ a[1].doit();
+ c[0].doit();
+ c[1].doit();
+ }
+}
+
+void f7(B (&a)[2])
+{
+ B b[2];
+ B (&c)[2] = b;
+ #pragma omp parallel default(none) shared(n, a, c)
+ {
+ #pragma omp master
+ n = omp_get_num_threads ();
+ #pragma omp for lastprivate (a, c)
+ for (int i = 0; i < omp_get_num_threads (); i++)
+ {
+ a[0].doit();
+ a[1].doit();
+ c[0].doit();
+ c[1].doit();
+ }
+ }
+}
+
+void f8()
+{
+ B b[2];
+ B (&c)[2] = b;
+ #pragma omp parallel default(none) private (c) shared (n)
+ {
+ B d[2];
+ B (&e)[2] = d;
+ #pragma omp single copyprivate (c, e)
+ {
+ c[0].doit();
+ c[1].doit();
+ e[0].doit();
+ e[1].doit();
+ }
+ c[0].doit();
+ c[1].doit();
+ e[0].doit();
+ e[1].doit();
+ }
+}
+
+int main()
+{
+ {
+ B a;
+ f1(a);
+ }
+ assert (B::xc == 2*n && B::ic == 2*n+2 && B::dc == 2*n+2 && B::ac == 0 && B::cc == 0);
+ B::clear();
+ {
+ B a;
+ f2(a);
+ }
+ assert (B::xc == 2*n && B::ic == 2 && B::dc == 2*n+2 && B::ac == 0 && B::cc == 2*n);
+ B::clear();
+ {
+ B a;
+ f3(a);
+ }
+ assert (B::xc == 2*n && B::ic == 2*n+2 && B::dc == 2*n+2 && B::ac == 2 && B::cc == 0);
+ B::clear();
+ f4();
+ assert (B::xc == 2*n+2 && B::ic == 2*n+1 && B::dc == 2*n+1 && B::ac == 2*n-2 && B::cc == 0);
+ B::clear();
+ {
+ B a[2];
+ f5(a);
+ }
+ assert (B::xc == 4*n && B::ic == 4*n+4 && B::dc == 4*n+4 && B::ac == 0 && B::cc == 0);
+ B::clear();
+ {
+ B a[2];
+ f6(a);
+ }
+ assert (B::xc == 4*n && B::ic == 4 && B::dc == 4*n+4 && B::ac == 0 && B::cc == 4*n);
+ B::clear();
+ {
+ B a[2];
+ f7(a);
+ }
+ assert (B::xc == 4*n && B::ic == 4*n+4 && B::dc == 4*n+4 && B::ac == 4 && B::cc == 0);
+ B::clear();
+ f8();
+ assert (B::xc == 4*n+4 && B::ic == 4*n+2 && B::dc == 4*n+2 && B::ac == 4*n-4 && B::cc == 0);
+ return 0;
+}
--- /dev/null
+// { dg-do run }
+
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+extern "C" void abort ();
+
+template <typename T>
+class I
+{
+public:
+ typedef ptrdiff_t difference_type;
+ I ();
+ ~I ();
+ I (T *);
+ I (const I &);
+ T &operator * ();
+ T *operator -> ();
+ T &operator [] (const difference_type &) const;
+ I &operator = (const I &);
+ I &operator ++ ();
+ I operator ++ (int);
+ I &operator -- ();
+ I operator -- (int);
+ I &operator += (const difference_type &);
+ I &operator -= (const difference_type &);
+ I operator + (const difference_type &) const;
+ I operator - (const difference_type &) const;
+ template <typename S> friend bool operator == (I<S> &, I<S> &);
+ template <typename S> friend bool operator == (const I<S> &, const I<S> &);
+ template <typename S> friend bool operator < (I<S> &, I<S> &);
+ template <typename S> friend bool operator < (const I<S> &, const I<S> &);
+ template <typename S> friend bool operator <= (I<S> &, I<S> &);
+ template <typename S> friend bool operator <= (const I<S> &, const I<S> &);
+ template <typename S> friend bool operator > (I<S> &, I<S> &);
+ template <typename S> friend bool operator > (const I<S> &, const I<S> &);
+ template <typename S> friend bool operator >= (I<S> &, I<S> &);
+ template <typename S> friend bool operator >= (const I<S> &, const I<S> &);
+ template <typename S> friend typename I<S>::difference_type operator - (I<S> &, I<S> &);
+ template <typename S> friend typename I<S>::difference_type operator - (const I<S> &, const I<S> &);
+ template <typename S> friend I<S> operator + (typename I<S>::difference_type , const I<S> &);
+private:
+ T *p;
+};
+template <typename T> I<T>::I () : p (0) {}
+template <typename T> I<T>::~I () {}
+template <typename T> I<T>::I (T *x) : p (x) {}
+template <typename T> I<T>::I (const I &x) : p (x.p) {}
+template <typename T> T &I<T>::operator * () { return *p; }
+template <typename T> T *I<T>::operator -> () { return p; }
+template <typename T> T &I<T>::operator [] (const difference_type &x) const { return p[x]; }
+template <typename T> I<T> &I<T>::operator = (const I &x) { p = x.p; return *this; }
+template <typename T> I<T> &I<T>::operator ++ () { ++p; return *this; }
+template <typename T> I<T> I<T>::operator ++ (int) { return I (p++); }
+template <typename T> I<T> &I<T>::operator -- () { --p; return *this; }
+template <typename T> I<T> I<T>::operator -- (int) { return I (p--); }
+template <typename T> I<T> &I<T>::operator += (const difference_type &x) { p += x; return *this; }
+template <typename T> I<T> &I<T>::operator -= (const difference_type &x) { p -= x; return *this; }
+template <typename T> I<T> I<T>::operator + (const difference_type &x) const { return I (p + x); }
+template <typename T> I<T> I<T>::operator - (const difference_type &x) const { return I (p - x); }
+template <typename T> bool operator == (I<T> &x, I<T> &y) { return x.p == y.p; }
+template <typename T> bool operator == (const I<T> &x, const I<T> &y) { return x.p == y.p; }
+template <typename T> bool operator != (I<T> &x, I<T> &y) { return !(x == y); }
+template <typename T> bool operator != (const I<T> &x, const I<T> &y) { return !(x == y); }
+template <typename T> bool operator < (I<T> &x, I<T> &y) { return x.p < y.p; }
+template <typename T> bool operator < (const I<T> &x, const I<T> &y) { return x.p < y.p; }
+template <typename T> bool operator <= (I<T> &x, I<T> &y) { return x.p <= y.p; }
+template <typename T> bool operator <= (const I<T> &x, const I<T> &y) { return x.p <= y.p; }
+template <typename T> bool operator > (I<T> &x, I<T> &y) { return x.p > y.p; }
+template <typename T> bool operator > (const I<T> &x, const I<T> &y) { return x.p > y.p; }
+template <typename T> bool operator >= (I<T> &x, I<T> &y) { return x.p >= y.p; }
+template <typename T> bool operator >= (const I<T> &x, const I<T> &y) { return x.p >= y.p; }
+template <typename T> typename I<T>::difference_type operator - (I<T> &x, I<T> &y) { return x.p - y.p; }
+template <typename T> typename I<T>::difference_type operator - (const I<T> &x, const I<T> &y) { return x.p - y.p; }
+template <typename T> I<T> operator + (typename I<T>::difference_type x, const I<T> &y) { return I<T> (x + y.p); }
+
+int results[2048];
+
+template <typename T>
+void
+baz (I<T> &i, I<T> &j, I<T> &k, T &l)
+{
+ if (*i < 0 || *i >= 16)
+ abort ();
+ if (*j < 0 || *j >= 16)
+ abort ();
+ if (*k < 0 || *k >= 16)
+ abort ();
+ if (l < 0 || l >= 16)
+ abort ();
+ #pragma omp atomic
+ results[512 * *i + 64 * *j + 8 * *k + l]++;
+}
+
+template <typename T>
+void
+baz (T &i, T &j, T &k, T &l)
+{
+ if (i < 0 || i >= 16)
+ abort ();
+ if (j < 0 || j >= 16)
+ abort ();
+ if (k < 0 || k >= 16)
+ abort ();
+ if (l < 0 || l >= 16)
+ abort ();
+ #pragma omp atomic
+ results[512 * i + 64 * j + 8 * k + l]++;
+}
+
+void
+f1 (const I<int> &a, const I<int> &b, const I<int> &c, const I<int> &d,
+ const I<int> &e, const I<int> &f, int g, int h,
+ I<int> &r1, I<int> &r2, I<int> &r3)
+{
+ I<int> i, j, k;
+ int l;
+#pragma omp parallel for ordered(4) lastprivate (i, j, k) schedule(static, 1)
+ for (i = a; i <= b; i++)
+ for (j = c; j < d; j++)
+ for (k = e; k < f; k++)
+ for (l = g; l < h; l++)
+ {
+ #pragma omp ordered depend(sink: i - 1, j, k + 1, l - 2)
+ baz (i, j, k, l);
+ if (i > a && k < f - 1 && l > g + 1)
+ {
+ int m;
+ #pragma omp atomic read
+ m = results[512 * *(i - 1) + 64 * *j + 8 * *(k + 1) + l - 2];
+ if (m == 0)
+ abort ();
+ }
+ #pragma omp ordered depend(source)
+ }
+ r1 = i;
+ r2 = j;
+ r3 = k;
+}
+
+void
+f2 (int a, int b, int c, int d, int e, int f, int g, int h, int &r1, int &r2, int &r3)
+{
+ int i, j, k, l;
+#pragma omp parallel for collapse (1) ordered(4) lastprivate (i, j, k) schedule(static, 2)
+ for (i = a; i <= b; i++)
+ for (j = c; j < d; j++)
+ for (k = e; k < f; k++)
+ for (l = g; l < h; l++)
+ {
+ #pragma omp ordered depend(sink: i - 1, j, k + 1, l - 2)
+ baz (i, j, k, l);
+ if (i > a && k < f - 1 && l > g + 1)
+ {
+ int m;
+ #pragma omp atomic read
+ m = results[512 * (i - 1) + 64 * j + 8 * (k + 1) + l - 2];
+ if (m == 0)
+ abort ();
+ }
+ #pragma omp ordered depend(source)
+ }
+ r1 = i;
+ r2 = j;
+ r3 = k;
+}
+
+void
+f3 (const I<int> &a, const I<int> &b, const I<int> &c, const I<int> &d,
+ const I<int> &e, const I<int> &f, int g, int h,
+ I<int> &r1, I<int> &r2, I<int> &r3)
+{
+ I<int> i, j, k;
+ int l;
+#pragma omp parallel for collapse (2) ordered(4) lastprivate (i, j, k) schedule(static, 1)
+ for (i = a; i <= b; i++)
+ for (j = c; j < d; j++)
+ for (k = e; k < f; k++)
+ for (l = g; l < h; l++)
+ {
+ #pragma omp ordered depend(sink: i - 1, j, k + 1, l - 2)
+ baz (i, j, k, l);
+ if (i > a && k < f - 1 && l > g + 1)
+ {
+ int m;
+ #pragma omp atomic read
+ m = results[512 * *(i - 1) + 64 * *j + 8 * *(k + 1) + l - 2];
+ if (m == 0)
+ abort ();
+ }
+ #pragma omp ordered depend(source)
+ }
+ r1 = i;
+ r2 = j;
+ r3 = k;
+}
+
+void
+f4 (int a, int b, int c, int d, int e, int f, int g, int h, int &r1, int &r2, int &r3)
+{
+ int i, j, k, l;
+#pragma omp parallel for collapse (2) ordered(4) lastprivate (i, j, k) schedule(static, 2)
+ for (i = a; i <= b; i++)
+ for (j = c; j < d; j++)
+ for (k = e; k < f; k++)
+ for (l = g; l < h; l++)
+ {
+ #pragma omp ordered depend(sink: i - 1, j, k + 1, l - 2)
+ baz (i, j, k, l);
+ if (i > a && k < f - 1 && l > g + 1)
+ {
+ int m;
+ #pragma omp atomic read
+ m = results[512 * (i - 1) + 64 * j + 8 * (k + 1) + l - 2];
+ if (m == 0)
+ abort ();
+ }
+ #pragma omp ordered depend(source)
+ }
+ r1 = i;
+ r2 = j;
+ r3 = k;
+}
+
+#define check(expr) \
+ for (int i = 0; i < 2048; i++) \
+ if (expr) \
+ { \
+ if (results[i] != 1) \
+ abort (); \
+ results[i] = 0; \
+ } \
+ else if (results[i]) \
+ abort ()
+
+int
+main ()
+{
+ int a[16], s1, s2, s3;
+ I<int> r1, r2, r3;
+ for (int i = 0; i < 16; i++)
+ a[i] = i;
+ r1 = &a[15]; r2 = &a[15]; r3 = &a[15];
+ f1 (&a[1], &a[3], &a[2], &a[5], &a[1], &a[3], 0, 5, r1, r2, r3);
+ if (*r1 != 4 || *r2 != 5 || *r3 != 3)
+ abort ();
+ check ((i / 512) - 1U < 3U && ((i / 64) & 7) - 2U < 3U && ((i / 8) & 7) - 1U < 2U && (i & 7) < 5);
+ r1 = &a[15]; r2 = &a[15]; r3 = &a[15];
+ f1 (&a[1], &a[3], &a[1], &a[4], &a[1], &a[5], 1, 0, r1, r2, r3);
+ if (*r1 != 4 || *r2 != 4 || *r3 != 5)
+ abort ();
+ r1 = &a[15]; r2 = &a[15]; r3 = &a[15];
+ f1 (&a[1], &a[3], &a[1], &a[9], &a[7], &a[2], 0, 7, r1, r2, r3);
+ if (*r1 != 4 || *r2 != 9 || *r3 != 7)
+ abort ();
+ s1 = 15; s2 = 15; s3 = 15;
+ f2 (1, 3, 2, 5, 1, 3, 0, 5, s1, s2, s3);
+ if (s1 != 4 || s2 != 5 || s3 != 3)
+ abort ();
+ check ((i / 512) - 1U < 3U && ((i / 64) & 7) - 2U < 3U && ((i / 8) & 7) - 1U < 2U && (i & 7) < 5);
+ s1 = 15; s2 = 15; s3 = 15;
+ f2 (1, 3, 1, 4, 1, 5, 1, 0, s1, s2, s3);
+ if (s1 != 4 || s2 != 4 || s3 != 5)
+ abort ();
+ s1 = 15; s2 = 15; s3 = 15;
+ f2 (1, 3, 1, 9, 7, 2, 0, 7, s1, s2, s3);
+ if (s1 != 4 || s2 != 9 || s3 != 7)
+ abort ();
+ r1 = &a[15]; r2 = &a[15]; r3 = &a[15];
+ f3 (&a[1], &a[3], &a[2], &a[5], &a[1], &a[3], 0, 5, r1, r2, r3);
+ if (*r1 != 4 || *r2 != 5 || *r3 != 3)
+ abort ();
+ check ((i / 512) - 1U < 3U && ((i / 64) & 7) - 2U < 3U && ((i / 8) & 7) - 1U < 2U && (i & 7) < 5);
+ r1 = &a[15]; r2 = &a[15]; r3 = &a[15];
+ f3 (&a[1], &a[3], &a[1], &a[4], &a[1], &a[5], 1, 0, r1, r2, r3);
+ if (*r1 != 4 || *r2 != 4 || *r3 != 5)
+ abort ();
+ r1 = &a[15]; r2 = &a[15]; r3 = &a[15];
+ f3 (&a[1], &a[3], &a[1], &a[9], &a[7], &a[2], 0, 7, r1, r2, r3);
+ if (*r1 != 4 || *r2 != 9 || *r3 != 7)
+ abort ();
+ s1 = 15; s2 = 15; s3 = 15;
+ f4 (1, 3, 2, 5, 1, 3, 0, 5, s1, s2, s3);
+ if (s1 != 4 || s2 != 5 || s3 != 3)
+ abort ();
+ check ((i / 512) - 1U < 3U && ((i / 64) & 7) - 2U < 3U && ((i / 8) & 7) - 1U < 2U && (i & 7) < 5);
+ s1 = 15; s2 = 15; s3 = 15;
+ f4 (1, 3, 1, 4, 1, 5, 1, 0, s1, s2, s3);
+ if (s1 != 4 || s2 != 4 || s3 != 5)
+ abort ();
+ s1 = 15; s2 = 15; s3 = 15;
+ f4 (1, 3, 1, 9, 7, 2, 0, 7, s1, s2, s3);
+ if (s1 != 4 || s2 != 9 || s3 != 7)
+ abort ();
+ return 0;
+}
// { dg-do run }
-// { dg-require-effective-target offload_device }
+// { dg-require-effective-target offload_device_nonshared_as }
#include <stdlib.h>
--- /dev/null
+/* { dg-options "-fopenmp" } */
+
+extern "C" void abort (void);
+
+#define M(x, y, z) O(x, y, z)
+#define O(x, y, z) x ## _ ## y ## _ ## z
+
+#define F taskloop
+#define G taskloop
+#define S
+#define N(x) M(x, G, normal)
+#include "../libgomp.c/for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#define F taskloop simd
+#define G taskloop_simd
+#define S
+#define N(x) M(x, G, normal)
+#include "../libgomp.c/for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+int
+main ()
+{
+ int err = 0;
+ #pragma omp parallel reduction(|:err)
+ #pragma omp single
+ {
+ if (test_taskloop_normal ()
+ || test_taskloop_simd_normal ())
+ err = 1;
+ }
+ if (err)
+ abort ();
+ return 0;
+}
--- /dev/null
+extern "C" void abort ();
+
+#define M(x, y, z) O(x, y, z)
+#define O(x, y, z) x ## _ ## y ## _ ## z
+
+#pragma omp declare target
+
+#define F for
+#define G f
+#define S
+#define N(x) M(x, G, normal)
+#include "../libgomp.c/for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#pragma omp end declare target
+
+#undef OMPFROM
+#undef OMPTO
+#define DO_PRAGMA(x) _Pragma (#x)
+#define OMPFROM(v) DO_PRAGMA (omp target update from(v))
+#define OMPTO(v) DO_PRAGMA (omp target update to(v))
+
+#define F target parallel for
+#define G tpf
+#include "../libgomp.c/for-1.h"
+#undef F
+#undef G
+
+#define F target simd
+#define G t_simd
+#define S
+#define N(x) M(x, G, normal)
+#include "../libgomp.c/for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#define F target parallel for simd
+#define G tpf_simd
+#include "../libgomp.c/for-1.h"
+#undef F
+#undef G
+
+#define F target teams distribute
+#define G ttd
+#define S
+#define N(x) M(x, G, normal)
+#include "../libgomp.c/for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#define F target teams distribute
+#define G ttd_ds128
+#define S dist_schedule(static, 128)
+#define N(x) M(x, G, normal)
+#include "../libgomp.c/for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#define F target teams distribute simd
+#define G ttds
+#define S
+#define N(x) M(x, G, normal)
+#include "../libgomp.c/for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#define F target teams distribute simd
+#define G ttds_ds128
+#define S dist_schedule(static, 128)
+#define N(x) M(x, G, normal)
+#include "../libgomp.c/for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#define F target teams distribute parallel for
+#define G ttdpf
+#include "../libgomp.c/for-1.h"
+#undef F
+#undef G
+
+#define F target teams distribute parallel for dist_schedule(static, 128)
+#define G ttdpf_ds128
+#include "../libgomp.c/for-1.h"
+#undef F
+#undef G
+
+#define F target teams distribute parallel for simd
+#define G ttdpfs
+#include "../libgomp.c/for-1.h"
+#undef F
+#undef G
+
+#define F target teams distribute parallel for simd dist_schedule(static, 128)
+#define G ttdpfs_ds128
+#include "../libgomp.c/for-1.h"
+#undef F
+#undef G
+
+int
+main ()
+{
+ if (test_tpf_static ()
+ || test_tpf_static32 ()
+ || test_tpf_auto ()
+ || test_tpf_guided32 ()
+ || test_tpf_runtime ()
+ || test_t_simd_normal ()
+ || test_tpf_simd_static ()
+ || test_tpf_simd_static32 ()
+ || test_tpf_simd_auto ()
+ || test_tpf_simd_guided32 ()
+ || test_tpf_simd_runtime ()
+ || test_ttd_normal ()
+ || test_ttd_ds128_normal ()
+ || test_ttds_normal ()
+ || test_ttds_ds128_normal ()
+ || test_ttdpf_static ()
+ || test_ttdpf_static32 ()
+ || test_ttdpf_auto ()
+ || test_ttdpf_guided32 ()
+ || test_ttdpf_runtime ()
+ || test_ttdpf_ds128_static ()
+ || test_ttdpf_ds128_static32 ()
+ || test_ttdpf_ds128_auto ()
+ || test_ttdpf_ds128_guided32 ()
+ || test_ttdpf_ds128_runtime ()
+ || test_ttdpfs_static ()
+ || test_ttdpfs_static32 ()
+ || test_ttdpfs_auto ()
+ || test_ttdpfs_guided32 ()
+ || test_ttdpfs_runtime ()
+ || test_ttdpfs_ds128_static ()
+ || test_ttdpfs_ds128_static32 ()
+ || test_ttdpfs_ds128_auto ()
+ || test_ttdpfs_ds128_guided32 ()
+ || test_ttdpfs_ds128_runtime ())
+ abort ();
+}
--- /dev/null
+extern "C" void abort ();
+
+#define M(x, y, z) O(x, y, z)
+#define O(x, y, z) x ## _ ## y ## _ ## z
+
+#pragma omp declare target
+
+#define F for
+#define G f
+#define S
+#define N(x) M(x, G, normal)
+#include "../libgomp.c/for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#pragma omp end declare target
+
+#undef OMPTGT
+#undef OMPFROM
+#undef OMPTO
+#define DO_PRAGMA(x) _Pragma (#x)
+#define OMPTGT DO_PRAGMA (omp target)
+#define OMPFROM(v) DO_PRAGMA (omp target update from(v))
+#define OMPTO(v) DO_PRAGMA (omp target update to(v))
+
+#define F teams distribute
+#define G td
+#define S
+#define N(x) M(x, G, normal)
+#include "../libgomp.c/for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#define F teams distribute
+#define G td_ds128
+#define S dist_schedule(static, 128)
+#define N(x) M(x, G, normal)
+#include "../libgomp.c/for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#define F teams distribute simd
+#define G tds
+#define S
+#define N(x) M(x, G, normal)
+#include "../libgomp.c/for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#define F teams distribute simd
+#define G tds_ds128
+#define S dist_schedule(static, 128)
+#define N(x) M(x, G, normal)
+#include "../libgomp.c/for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#define F teams distribute parallel for
+#define G tdpf
+#include "../libgomp.c/for-1.h"
+#undef F
+#undef G
+
+#define F teams distribute parallel for dist_schedule(static, 128)
+#define G tdpf_ds128
+#include "../libgomp.c/for-1.h"
+#undef F
+#undef G
+
+#define F teams distribute parallel for simd
+#define G tdpfs
+#include "../libgomp.c/for-1.h"
+#undef F
+#undef G
+
+#define F teams distribute parallel for simd dist_schedule(static, 128)
+#define G tdpfs_ds128
+#include "../libgomp.c/for-1.h"
+#undef F
+#undef G
+
+int
+main ()
+{
+ if (test_td_normal ()
+ || test_td_ds128_normal ()
+ || test_tds_normal ()
+ || test_tds_ds128_normal ()
+ || test_tdpf_static ()
+ || test_tdpf_static32 ()
+ || test_tdpf_auto ()
+ || test_tdpf_guided32 ()
+ || test_tdpf_runtime ()
+ || test_tdpf_ds128_static ()
+ || test_tdpf_ds128_static32 ()
+ || test_tdpf_ds128_auto ()
+ || test_tdpf_ds128_guided32 ()
+ || test_tdpf_ds128_runtime ()
+ || test_tdpfs_static ()
+ || test_tdpfs_static32 ()
+ || test_tdpfs_auto ()
+ || test_tdpfs_guided32 ()
+ || test_tdpfs_runtime ()
+ || test_tdpfs_ds128_static ()
+ || test_tdpfs_ds128_static32 ()
+ || test_tdpfs_ds128_auto ()
+ || test_tdpfs_ds128_guided32 ()
+ || test_tdpfs_ds128_runtime ())
+ abort ();
+}
--- /dev/null
+int a[256];
+
+__attribute__((noinline, noclone)) int
+f1 (int i)
+{
+ #pragma omp parallel for linear (i: 4)
+ for (int j = 16; j < 64; j++)
+ {
+ a[i] = j;
+ i += 4;
+ }
+ return i;
+}
+
+__attribute__((noinline, noclone)) short int &
+f2 (short int &i, char k)
+{
+ #pragma omp parallel for linear (i: k + 1)
+ for (long j = 16; j < 64; j++)
+ {
+ a[i] = j;
+ i += 4;
+ }
+ return i;
+}
+
+template <typename T>
+__attribute__((noinline, noclone)) T
+f3 (T i, T k)
+{
+ #pragma omp parallel for linear (i: k)
+ for (short j = 16; j < 64; j++)
+ {
+ a[i] = j;
+ i += 4;
+ }
+ return i;
+}
+
+template <typename T>
+__attribute__((noinline, noclone)) T &
+f4 (T &i)
+{
+ #pragma omp parallel for linear (i: 4) schedule(static, 3)
+ for (int j = 16; j < 64; j++)
+ {
+ a[i] = j;
+ i += 4;
+ }
+ return i;
+}
+
+__attribute__((noinline, noclone)) short int
+f5 (short int i, char &k)
+{
+ #pragma omp parallel for linear (i: k + 1) schedule(static, 5)
+ for (long j = 16; j < 64; j++)
+ {
+ a[i] = j;
+ i += 4;
+ }
+ return i;
+}
+
+template <int N>
+__attribute__((noinline, noclone)) long long int
+f6 (long long int i, long long int k)
+{
+ #pragma omp parallel for linear (i: k) schedule(static, 7)
+ for (short j = 16; j < 64; j++)
+ {
+ a[i] = j;
+ i += 4;
+ }
+ return i;
+}
+
+__attribute__((noinline, noclone)) int
+f7 (int &i)
+{
+ #pragma omp parallel for linear (i: 4) schedule(dynamic, 3)
+ for (int j = 16; j < 64; j++)
+ {
+ a[i] = j;
+ i += 4;
+ }
+ return i;
+}
+
+__attribute__((noinline, noclone)) short int
+f8 (short int i, char k)
+{
+ #pragma omp parallel for linear (i: k + 1) schedule(dynamic, 5)
+ for (long j = 16; j < 64; j++)
+ {
+ a[i] = j;
+ i += 4;
+ }
+ return i;
+}
+
+__attribute__((noinline, noclone)) long long int
+f9 (long long int i, long long int k)
+{
+ #pragma omp parallel for linear (i: k) schedule(dynamic, 7)
+ for (short j = 16; j < 64; j++)
+ {
+ a[i] = j;
+ i += 4;
+ }
+ return i;
+}
+
+template <typename T>
+__attribute__((noinline, noclone)) T &
+f10 (T &i, long &step)
+{
+ #pragma omp parallel for linear (i: 4)
+ for (int j = 16; j < 112; j += step)
+ {
+ a[i] = j / 2 + 8;
+ i += 4;
+ }
+ return i;
+}
+
+__attribute__((noinline, noclone)) short int
+f11 (short int i, char k, char step)
+{
+ #pragma omp parallel for linear (i: k + 1)
+ for (long j = 16; j < 112; j += step)
+ {
+ a[i] = j / 2 + 8;
+ i += 4;
+ }
+ return i;
+}
+
+__attribute__((noinline, noclone)) long long int
+f12 (long long int i, long long int k, int step)
+{
+ #pragma omp parallel for linear (i: k)
+ for (short j = 16; j < 112; j += step)
+ {
+ a[i] = j / 2 + 8;
+ i += 4;
+ }
+ return i;
+}
+
+__attribute__((noinline, noclone)) int
+f13 (int &i, long long int step)
+{
+ #pragma omp parallel for linear (i: 4) schedule(static, 3)
+ for (int j = 16; j < 112; j += step)
+ {
+ a[i] = j / 2 + 8;
+ i += 4;
+ }
+ return i;
+}
+
+__attribute__((noinline, noclone)) short int
+f14 (short int &i, char &k, int &step)
+{
+ #pragma omp parallel for linear (i: k + 1) schedule(static, 5)
+ for (long j = 16; j < 112; j += step)
+ {
+ a[i] = j / 2 + 8;
+ i += 4;
+ }
+ return i;
+}
+
+template <int N>
+__attribute__((noinline, noclone)) long long int
+f15 (long long int i, long long int k, long int step)
+{
+ #pragma omp parallel for linear (i: k) schedule(static, 7)
+ for (short j = 16; j < 112; j += step)
+ {
+ a[i] = j / 2 + 8;
+ i += 4;
+ }
+ return i;
+}
+
+__attribute__((noinline, noclone)) int
+f16 (int i, long long int step)
+{
+ #pragma omp parallel for linear (i: 4) schedule(dynamic, 3)
+ for (int j = 16; j < 112; j += step)
+ {
+ a[i] = j / 2 + 8;
+ i += 4;
+ }
+ return i;
+}
+
+__attribute__((noinline, noclone)) short int
+f17 (short int i, char k, int step)
+{
+ #pragma omp parallel for linear (i: k + 1) schedule(dynamic, 5)
+ for (long j = 16; j < 112; j += step)
+ {
+ a[i] = j / 2 + 8;
+ i += 4;
+ }
+ return i;
+}
+
+template <typename T>
+__attribute__((noinline, noclone)) T
+f18 (T i, T k, long int step)
+{
+ #pragma omp parallel for linear (i: k) schedule(dynamic, 7)
+ for (short j = 16; j < 112; j += step)
+ {
+ a[i] = j / 2 + 8;
+ i += 4;
+ }
+ return i;
+}
+
+int
+main ()
+{
+#define TEST(x) \
+ if (x != 8 + 48 * 4) \
+ __builtin_abort (); \
+ for (int i = 0; i < 256; i++) \
+ if (a[i] != (((i & 3) == 0 && i >= 8 \
+ && i < 8 + 48 * 4) \
+ ? ((i - 8) / 4) + 16 : 0)) \
+ __builtin_abort (); \
+ __builtin_memset (a, 0, sizeof (a))
+ TEST (f1 (8));
+ short int vs = 8;
+ TEST (f2 (vs, 3));
+ TEST (f3 (8LL, 4LL));
+ int vi = 8;
+ TEST (f4 (vi));
+ char vk = 3;
+ TEST (f5 (8, vk));
+ TEST (f6<7> (8LL, 4LL));
+ vi = 8;
+ TEST (f7 (vi));
+ TEST (f8 (8, 3));
+ TEST (f9 (8LL, 4LL));
+ vi = 8;
+ long vl = 2;
+ TEST (f10 (vi, vl));
+ TEST (f11 (8, 3, 2));
+ TEST (f12 (8LL, 4LL, 2));
+ vi = 8;
+ TEST (f13 (vi, 2));
+ vs = 8;
+ vk = 3;
+ vi = 2;
+ TEST (f14 (vs, vk, vi));
+ TEST (f15<9> (8LL, 4LL, 2));
+ TEST (f16 (8, 2));
+ TEST (f17 (8, 3, 2));
+ long long int vll1 = 8LL;
+ long long int vll2 = 4LL;
+ TEST (f18<long long int &> (vll1, vll2, 2));
+ return 0;
+}
--- /dev/null
+// { dg-do run }
+
+#include <omp.h>
+
+struct R { R () {}; ~R () {}; int r; };
+struct T { T () {}; virtual ~T () {}; int t; };
+int c;
+struct A : public R, virtual public T { A () : b(c) {} int a; int &b; void m1 (); };
+
+void
+take (int &a, int &b, int &c, int &d)
+{
+ asm volatile ("" : : "g" (&a), "g" (&b), "g" (&c), "g" (&d) : "memory");
+}
+
+void
+A::m1 ()
+{
+ #pragma omp parallel private (a, r, T::t, A::b)
+ {
+ int q = omp_get_thread_num ();
+ a = q;
+ r = 2 * q;
+ t = 3 * q;
+ b = 4 * q;
+ take (a, r, t, b);
+ #pragma omp barrier
+ if (A::a != q || R::r != 2 * q || T::t != 3 * q || A::b != 4 * q)
+ __builtin_abort ();
+ }
+ a = 7;
+ r = 8;
+ t = 9;
+ b = 10;
+ #pragma omp parallel firstprivate (A::a, R::r, t, b)
+ {
+ int q = omp_get_thread_num ();
+ take (A::a, R::r, T::t, A::b);
+ if (a != 7 || r != 8 || t != 9 || b != 10)
+ __builtin_abort ();
+ A::a = 5 * q;
+ R::r = 6 * q;
+ T::t = 7 * q;
+ A::b = 8 * q;
+ take (a, r, t, b);
+ #pragma omp barrier
+ if (a != 5 * q || r != 6 * q || t != 7 * q || b != 8 * q)
+ __builtin_abort ();
+ }
+ bool f = false;
+ a = -5;
+ b = -4;
+ r = -3;
+ t = -2;
+ int n;
+ #pragma omp parallel for firstprivate (a, T::t, b, f) lastprivate (A::a, r, t, n)
+ for (int i = 0; i < omp_get_num_threads (); i++)
+ {
+ int q = omp_get_thread_num ();
+ if (!f)
+ {
+ if (A::a != -5 || A::b != -4 || T::t != -2)
+ __builtin_abort ();
+ }
+ else if (a != q || b != 2 * q || r != 3 * q || t != 4 * q)
+ __builtin_abort ();
+ take (a, r, t, b);
+ A::a = q;
+ A::b = 2 * q;
+ R::r = 3 * q;
+ T::t = 4 * q;
+ n = q;
+ f = true;
+ }
+ if (a != n || r != 3 * n || T::t != 4 * n)
+ __builtin_abort ();
+ b = 8;
+ #pragma omp parallel
+ #pragma omp single
+ for (int i = 0; i < 5; i++)
+ #pragma omp task firstprivate (t, b, n) private (a, R::r)
+ {
+ if (t != 4 * n || b != 8)
+ __builtin_abort ();
+ a = 9;
+ r = 8;
+ t = 12;
+ b = 18;
+ take (a, r, t, b);
+ if (a != 9 || r != 8 || t != 12 || b != 18)
+ __builtin_abort ();
+ }
+ a = 1;
+ b = 2;
+ R::r = 3;
+ t = 4;
+ #pragma omp parallel private (f)
+ {
+ f = false;
+ #pragma omp single
+ #pragma omp taskloop firstprivate (r, T::t, b, f) lastprivate (a, t, b, n)
+ for (int i = 0; i < 30; i++)
+ {
+ int q = omp_get_thread_num ();
+ if (!f)
+ {
+ if (R::r != 3 || A::b != 2 || T::t != 4)
+ __builtin_abort ();
+ }
+ else if (a != 7 * q || b != 8 * q || r != 9 * q || t != 10 * q)
+ __builtin_abort ();
+ take (a, r, t, b);
+ A::a = 7 * q;
+ A::b = 8 * q;
+ R::r = 9 * q;
+ T::t = 10 * q;
+ n = q;
+ f = true;
+ }
+ }
+ if (a != 7 * n || b != 8 * n || t != 10 * n)
+ __builtin_abort ();
+ a = 1;
+ b = 2;
+ R::r = 3;
+ t = 4;
+ #pragma omp parallel private (f)
+ {
+ f = false;
+ #pragma omp single
+ #pragma omp taskloop firstprivate (r, T::t, b, A::a, f)
+ for (int i = 0; i < 30; i++)
+ {
+ int q = omp_get_thread_num ();
+ if (!f)
+ {
+ if (A::a != 1 || R::r != 3 || A::b != 2 || T::t != 4)
+ __builtin_abort ();
+ }
+ else if (a != 7 * q || b != 8 * q || r != 9 * q || t != 10 * q)
+ __builtin_abort ();
+ take (a, r, t, b);
+ A::a = 7 * q;
+ A::b = 8 * q;
+ R::r = 9 * q;
+ T::t = 10 * q;
+ f = true;
+ }
+ }
+ #pragma omp parallel private (f)
+ {
+ f = false;
+ #pragma omp single
+ #pragma omp taskloop lastprivate (a, t, b, n)
+ for (int i = 0; i < 30; i++)
+ {
+ int q = omp_get_thread_num ();
+ if (f && (a != 7 * q || b != 8 * q || r != 9 * q || t != 10 * q))
+ __builtin_abort ();
+ take (a, r, t, b);
+ A::a = 7 * q;
+ A::b = 8 * q;
+ R::r = 9 * q;
+ T::t = 10 * q;
+ n = q;
+ f = true;
+ }
+ }
+ if (a != 7 * n || b != 8 * n || t != 10 * n)
+ __builtin_abort ();
+ #pragma omp parallel private (a, T::t, A::b, r)
+ {
+ int q = omp_get_thread_num ();
+ a = q;
+ b = 2 * q;
+ r = 3 * q;
+ t = 4 * q;
+ take (a, b, r, t);
+ #pragma omp single copyprivate (A::a, t, b, R::r)
+ n = q;
+ if (a != n || b != 2 * n || r != 3 * n || t != 4 * n)
+ __builtin_abort ();
+ }
+ a = 0;
+ b = 0;
+ R::r = 0;
+ t = 0;
+ #pragma omp parallel for reduction (+: A::a, t, b, R::r)
+ for (int i = 0; i < 30; i++)
+ {
+ a += i;
+ A::b += 2 * i;
+ r += 3 * i;
+ T::t += 4 * i;
+ take (a, b, r, t);
+ }
+ if (A::a != 435 || b != 2 * 435 || R::r != 3 * 435 || t != 4 * 435)
+ __builtin_abort ();
+}
+
+int
+main ()
+{
+ A a;
+ a.m1 ();
+}
--- /dev/null
+// { dg-do run }
+
+#include <omp.h>
+
+int c, d, e;
+struct R { R () {}; ~R () {}; int r; };
+template <typename Q>
+struct T { T () : t(d) {}; virtual ~T () {}; Q t; };
+template <typename Q>
+struct A : public R, virtual public T<Q> { A () : b(c), a(e) {} Q a; int &b; void m1 (); };
+
+void
+take (int &a, int &b, int &c, int &d)
+{
+ asm volatile ("" : : "g" (&a), "g" (&b), "g" (&c), "g" (&d) : "memory");
+}
+
+template <typename Q>
+void
+A<Q>::m1 ()
+{
+ #pragma omp parallel private (a, r, T<Q>::t, A::b)
+ {
+ int q = omp_get_thread_num ();
+ a = q;
+ r = 2 * q;
+ T<Q>::t = 3 * q;
+ b = 4 * q;
+ take (a, r, T<Q>::t, b);
+ #pragma omp barrier
+ if (A::a != q || R::r != 2 * q || T<Q>::t != 3 * q || A::b != 4 * q)
+ __builtin_abort ();
+ }
+ a = 7;
+ r = 8;
+ T<Q>::t = 9;
+ b = 10;
+ #pragma omp parallel firstprivate (A::a, R::r, T<Q>::t, b)
+ {
+ int q = omp_get_thread_num ();
+ take (A::a, R::r, T<Q>::t, A::b);
+ if (a != 7 || r != 8 || T<Q>::t != 9 || b != 10)
+ __builtin_abort ();
+ A::a = 5 * q;
+ R::r = 6 * q;
+ T<Q>::t = 7 * q;
+ A::b = 8 * q;
+ take (a, r, T<Q>::t, b);
+ #pragma omp barrier
+ if (a != 5 * q || r != 6 * q || T<Q>::t != 7 * q || b != 8 * q)
+ __builtin_abort ();
+ }
+ bool f = false;
+ a = -5;
+ b = -4;
+ r = -3;
+ T<Q>::t = -2;
+ int n;
+ #pragma omp parallel for firstprivate (a, T<Q>::t, b, f) lastprivate (A::a, r, T<Q>::t, n)
+ for (int i = 0; i < omp_get_num_threads (); i++)
+ {
+ int q = omp_get_thread_num ();
+ if (!f)
+ {
+ if (A::a != -5 || A::b != -4 || T<Q>::t != -2)
+ __builtin_abort ();
+ }
+ else if (a != q || b != 2 * q || r != 3 * q || T<Q>::t != 4 * q)
+ __builtin_abort ();
+ take (a, r, T<Q>::t, b);
+ A::a = q;
+ A::b = 2 * q;
+ R::r = 3 * q;
+ T<Q>::t = 4 * q;
+ n = q;
+ f = true;
+ }
+ if (a != n || r != 3 * n || T<Q>::t != 4 * n)
+ __builtin_abort ();
+ b = 8;
+ #pragma omp parallel
+ #pragma omp single
+ for (int i = 0; i < 5; i++)
+ #pragma omp task firstprivate (T<Q>::t, b, n) private (a, R::r)
+ {
+ if (T<Q>::t != 4 * n || b != 8)
+ __builtin_abort ();
+ a = 9;
+ r = 8;
+ T<Q>::t = 12;
+ b = 18;
+ take (a, r, T<Q>::t, b);
+ if (a != 9 || r != 8 || T<Q>::t != 12 || b != 18)
+ __builtin_abort ();
+ }
+ a = 1;
+ b = 2;
+ R::r = 3;
+ T<Q>::t = 4;
+ #pragma omp parallel private (f)
+ {
+ f = false;
+ #pragma omp single
+ #pragma omp taskloop firstprivate (r, T<Q>::t, b, f) lastprivate (a, T<Q>::t, b, n)
+ for (int i = 0; i < 30; i++)
+ {
+ int q = omp_get_thread_num ();
+ if (!f)
+ {
+ if (R::r != 3 || A::b != 2 || T<Q>::t != 4)
+ __builtin_abort ();
+ }
+ else if (a != 7 * q || b != 8 * q || r != 9 * q || T<Q>::t != 10 * q)
+ __builtin_abort ();
+ take (a, r, T<Q>::t, b);
+ A::a = 7 * q;
+ A::b = 8 * q;
+ R::r = 9 * q;
+ T<Q>::t = 10 * q;
+ n = q;
+ f = true;
+ }
+ }
+ if (a != 7 * n || b != 8 * n || T<Q>::t != 10 * n)
+ __builtin_abort ();
+ a = 1;
+ b = 2;
+ R::r = 3;
+ T<Q>::t = 4;
+ #pragma omp parallel private (f)
+ {
+ f = false;
+ #pragma omp single
+ #pragma omp taskloop firstprivate (r, T<Q>::t, b, A::a, f)
+ for (int i = 0; i < 30; i++)
+ {
+ int q = omp_get_thread_num ();
+ if (!f)
+ {
+ if (A::a != 1 || R::r != 3 || A::b != 2 || T<Q>::t != 4)
+ __builtin_abort ();
+ }
+ else if (a != 7 * q || b != 8 * q || r != 9 * q || T<Q>::t != 10 * q)
+ __builtin_abort ();
+ take (a, r, T<Q>::t, b);
+ A::a = 7 * q;
+ A::b = 8 * q;
+ R::r = 9 * q;
+ T<Q>::t = 10 * q;
+ f = true;
+ }
+ }
+ #pragma omp parallel private (f)
+ {
+ f = false;
+ #pragma omp single
+ #pragma omp taskloop lastprivate (a, T<Q>::t, b, n)
+ for (int i = 0; i < 30; i++)
+ {
+ int q = omp_get_thread_num ();
+ if (f && (a != 7 * q || b != 8 * q || r != 9 * q || T<Q>::t != 10 * q))
+ __builtin_abort ();
+ take (a, r, T<Q>::t, b);
+ A::a = 7 * q;
+ A::b = 8 * q;
+ R::r = 9 * q;
+ T<Q>::t = 10 * q;
+ n = q;
+ f = true;
+ }
+ }
+ if (a != 7 * n || b != 8 * n || T<Q>::t != 10 * n)
+ __builtin_abort ();
+ #pragma omp parallel private (a, T<Q>::t, A::b, r)
+ {
+ int q = omp_get_thread_num ();
+ a = q;
+ b = 2 * q;
+ r = 3 * q;
+ T<Q>::t = 4 * q;
+ take (a, b, r, T<Q>::t);
+ #pragma omp single copyprivate (A::a, T<Q>::t, b, R::r)
+ n = q;
+ if (a != n || b != 2 * n || r != 3 * n || T<Q>::t != 4 * n)
+ __builtin_abort ();
+ }
+ a = 0;
+ b = 0;
+ R::r = 0;
+ T<Q>::t = 0;
+ #pragma omp parallel for reduction (+: A::a, T<Q>::t, b, R::r)
+ for (int i = 0; i < 30; i++)
+ {
+ a += i;
+ A::b += 2 * i;
+ r += 3 * i;
+ T<Q>::t += 4 * i;
+ take (a, b, r, T<Q>::t);
+ }
+ if (A::a != 435 || b != 2 * 435 || R::r != 3 * 435 || T<Q>::t != 4 * 435)
+ __builtin_abort ();
+}
+
+int
+main ()
+{
+ A<int> a;
+ a.m1 ();
+ A<int &> b;
+ b.m1 ();
+}
--- /dev/null
+// { dg-do run }
+
+struct R { R () {}; ~R () {}; int r; };
+struct T { T () {}; virtual ~T () {}; int t; };
+int c;
+struct A : public R, virtual public T { A () : b(c) {} int a; int &b; void m1 (); };
+int d[64];
+
+void
+A::m1 ()
+{
+ r = 0;
+ #pragma omp parallel for private (a) reduction(|:R::r)
+ for (a = 0; A::a < 31; a += 2)
+ r |= (1 << A::a);
+ if (r != 0x55555555)
+ __builtin_abort ();
+ #pragma omp parallel for simd linear (R::r)
+ for (R::r = 0; r < 32; R::r++)
+ d[r + 8] |= 1;
+ for (int i = 0; i < 64; i++)
+ if (d[i] != ((i >= 8 && i < 32 + 8) ? 1 : 0))
+ __builtin_abort ();
+ #pragma omp parallel for lastprivate (t)
+ for (T::t = 0; t < 32; t += 3)
+ d[T::t + 2] |= 2;
+ if (T::t != 33)
+ __builtin_abort ();
+ for (int i = 0; i < 64; i++)
+ if (d[i] != (((i >= 8 && i < 32 + 8) ? 1 : 0)
+ | ((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 2 : 0)))
+ __builtin_abort ();
+ #pragma omp simd linear (t)
+ for (t = 0; t < 32; t++)
+ d[T::t + 9] |= 4;
+ if (t != 32)
+ __builtin_abort ();
+ for (int i = 0; i < 64; i++)
+ if (d[i] != (((i >= 8 && i < 32 + 8) ? 1 : 0)
+ | ((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 2 : 0)
+ | ((i >= 9 && i < 32 + 9) ? 4 : 0)))
+ __builtin_abort ();
+ r = 0;
+ #pragma omp parallel for reduction(|:r)
+ for (a = 0; A::a < 31; a += 2)
+ r |= (1 << A::a);
+ if (r != 0x55555555)
+ __builtin_abort ();
+ #pragma omp parallel for simd
+ for (R::r = 0; r < 32; R::r += 2)
+ d[r + 8] |= 8;
+ for (int i = 0; i < 64; i++)
+ if (d[i] != (((i >= 8 && i < 32 + 8) ? ((i & 1) ? 1 : (8 | 1)) : 0)
+ | ((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 2 : 0)
+ | ((i >= 9 && i < 32 + 9) ? 4 : 0)))
+ __builtin_abort ();
+ #pragma omp simd collapse(2)
+ for (T::t = 0; t < 7; t += 2)
+ for (a = 0; A::a < 8; a++)
+ d[((t << 2) | a) + 3] |= 16;
+ if (t != 8 || A::a != 8)
+ __builtin_abort ();
+ for (int i = 0; i < 64; i++)
+ if (d[i] != (((i >= 8 && i < 32 + 8) ? ((i & 1) ? 1 : (8 | 1)) : 0)
+ | ((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 2 : 0)
+ | ((i >= 9 && i < 32 + 9) ? 4 : 0)
+ | ((i >= 3 && i < 32 + 3) ? 16 : 0)))
+ __builtin_abort ();
+ T::t = 32;
+ a = 16;
+ #pragma omp parallel
+ #pragma omp single
+ #pragma omp taskloop simd collapse(2)
+ for (t = 0; T::t < 7; T::t += 2)
+ for (A::a = 0; a < 8; A::a++)
+ d[((t << 2) | A::a) + 3] |= 32;
+ if (T::t != 8 || a != 8)
+ __builtin_abort ();
+ for (int i = 0; i < 64; i++)
+ if (d[i] != (((i >= 8 && i < 32 + 8) ? ((i & 1) ? 1 : (8 | 1)) : 0)
+ | ((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 2 : 0)
+ | ((i >= 9 && i < 32 + 9) ? 4 : 0)
+ | ((i >= 3 && i < 32 + 3) ? (16 | 32) : 0)))
+ __builtin_abort ();
+ #pragma omp parallel
+ #pragma omp single
+ #pragma omp taskloop simd
+ for (R::r = 0; r < 31; R::r += 2)
+ d[r + 8] |= 64;
+ if (r != 32)
+ __builtin_abort ();
+ for (int i = 0; i < 64; i++)
+ if (d[i] != (((i >= 8 && i < 32 + 8) ? ((i & 1) ? 1 : (64 | 8 | 1)) : 0)
+ | ((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 2 : 0)
+ | ((i >= 9 && i < 32 + 9) ? 4 : 0)
+ | ((i >= 3 && i < 32 + 3) ? (16 | 32) : 0)))
+ __builtin_abort ();
+}
+
+int
+main ()
+{
+ A a;
+ a.m1 ();
+}
--- /dev/null
+// { dg-do run }
+
+int c, d, e;
+struct R { R () {}; ~R () {}; int r; };
+template <typename Q>
+struct T { T () : t(d) {}; virtual ~T () {}; Q t; };
+template <typename Q>
+struct A : public R, virtual public T<Q> { A () : b(c), a(e) {} Q a; int &b; void m1 (); };
+int f[64];
+
+template <typename Q>
+void
+A<Q>::m1 ()
+{
+ r = 0;
+ #pragma omp parallel for private (a) reduction(|:R::r)
+ for (a = 0; A::a < 31; a += 2)
+ r |= (1 << A::a);
+ if (r != 0x55555555)
+ __builtin_abort ();
+ #pragma omp parallel for simd linear (R::r)
+ for (R::r = 0; r < 32; R::r++)
+ f[r + 8] |= 1;
+ for (int i = 0; i < 64; i++)
+ if (f[i] != ((i >= 8 && i < 32 + 8) ? 1 : 0))
+ __builtin_abort ();
+ #pragma omp parallel for lastprivate (T<Q>::t)
+ for (T<Q>::t = 0; T<Q>::t < 32; T<Q>::t += 3)
+ f[T<Q>::t + 2] |= 2;
+ if (T<Q>::t != 33)
+ __builtin_abort ();
+ for (int i = 0; i < 64; i++)
+ if (f[i] != (((i >= 8 && i < 32 + 8) ? 1 : 0)
+ | ((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 2 : 0)))
+ __builtin_abort ();
+ #pragma omp simd linear (T<Q>::t)
+ for (T<Q>::t = 0; T<Q>::t < 32; T<Q>::t++)
+ f[T<Q>::t + 9] |= 4;
+ if (T<Q>::t != 32)
+ __builtin_abort ();
+ for (int i = 0; i < 64; i++)
+ if (f[i] != (((i >= 8 && i < 32 + 8) ? 1 : 0)
+ | ((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 2 : 0)
+ | ((i >= 9 && i < 32 + 9) ? 4 : 0)))
+ __builtin_abort ();
+ r = 0;
+ #pragma omp parallel for reduction(|:r)
+ for (a = 0; A::a < 31; a += 2)
+ r |= (1 << A::a);
+ if (r != 0x55555555)
+ __builtin_abort ();
+ #pragma omp parallel for simd
+ for (R::r = 0; r < 32; R::r += 2)
+ f[r + 8] |= 8;
+ for (int i = 0; i < 64; i++)
+ if (f[i] != (((i >= 8 && i < 32 + 8) ? ((i & 1) ? 1 : (8 | 1)) : 0)
+ | ((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 2 : 0)
+ | ((i >= 9 && i < 32 + 9) ? 4 : 0)))
+ __builtin_abort ();
+ #pragma omp simd collapse(2)
+ for (T<Q>::t = 0; T<Q>::t < 7; T<Q>::t += 2)
+ for (a = 0; A::a < 8; a++)
+ f[((T<Q>::t << 2) | a) + 3] |= 16;
+ if (T<Q>::t != 8 || A::a != 8)
+ __builtin_abort ();
+ for (int i = 0; i < 64; i++)
+ if (f[i] != (((i >= 8 && i < 32 + 8) ? ((i & 1) ? 1 : (8 | 1)) : 0)
+ | ((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 2 : 0)
+ | ((i >= 9 && i < 32 + 9) ? 4 : 0)
+ | ((i >= 3 && i < 32 + 3) ? 16 : 0)))
+ __builtin_abort ();
+ T<Q>::t = 32;
+ a = 16;
+ #pragma omp parallel
+ #pragma omp single
+ #pragma omp taskloop simd collapse(2)
+ for (T<Q>::t = 0; T<Q>::t < 7; T<Q>::t += 2)
+ for (A::a = 0; a < 8; A::a++)
+ f[((T<Q>::t << 2) | A::a) + 3] |= 32;
+ if (T<Q>::t != 8 || a != 8)
+ __builtin_abort ();
+ for (int i = 0; i < 64; i++)
+ if (f[i] != (((i >= 8 && i < 32 + 8) ? ((i & 1) ? 1 : (8 | 1)) : 0)
+ | ((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 2 : 0)
+ | ((i >= 9 && i < 32 + 9) ? 4 : 0)
+ | ((i >= 3 && i < 32 + 3) ? (16 | 32) : 0)))
+ __builtin_abort ();
+ #pragma omp parallel
+ #pragma omp single
+ #pragma omp taskloop simd
+ for (R::r = 0; r < 31; R::r += 2)
+ f[r + 8] |= 64;
+ if (r != 32)
+ __builtin_abort ();
+ for (int i = 0; i < 64; i++)
+ if (f[i] != (((i >= 8 && i < 32 + 8) ? ((i & 1) ? 1 : (64 | 8 | 1)) : 0)
+ | ((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 2 : 0)
+ | ((i >= 9 && i < 32 + 9) ? 4 : 0)
+ | ((i >= 3 && i < 32 + 3) ? (16 | 32) : 0)))
+ __builtin_abort ();
+}
+
+int
+main ()
+{
+ A<int> a;
+ a.m1 ();
+}
--- /dev/null
+// { dg-do run }
+
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+
+template <typename T>
+class I
+{
+public:
+ typedef ptrdiff_t difference_type;
+ I ();
+ ~I ();
+ I (T *);
+ I (const I &);
+ T &operator * ();
+ T *operator -> ();
+ T &operator [] (const difference_type &) const;
+ I &operator = (const I &);
+ I &operator ++ ();
+ I operator ++ (int);
+ I &operator -- ();
+ I operator -- (int);
+ I &operator += (const difference_type &);
+ I &operator -= (const difference_type &);
+ I operator + (const difference_type &) const;
+ I operator - (const difference_type &) const;
+ template <typename S> friend bool operator == (I<S> &, I<S> &);
+ template <typename S> friend bool operator == (const I<S> &, const I<S> &);
+ template <typename S> friend bool operator < (I<S> &, I<S> &);
+ template <typename S> friend bool operator < (const I<S> &, const I<S> &);
+ template <typename S> friend bool operator <= (I<S> &, I<S> &);
+ template <typename S> friend bool operator <= (const I<S> &, const I<S> &);
+ template <typename S> friend bool operator > (I<S> &, I<S> &);
+ template <typename S> friend bool operator > (const I<S> &, const I<S> &);
+ template <typename S> friend bool operator >= (I<S> &, I<S> &);
+ template <typename S> friend bool operator >= (const I<S> &, const I<S> &);
+ template <typename S> friend typename I<S>::difference_type operator - (I<S> &, I<S> &);
+ template <typename S> friend typename I<S>::difference_type operator - (const I<S> &, const I<S> &);
+ template <typename S> friend I<S> operator + (typename I<S>::difference_type , const I<S> &);
+private:
+ T *p;
+};
+template <typename T> I<T>::I () : p (0) {}
+template <typename T> I<T>::~I () {}
+template <typename T> I<T>::I (T *x) : p (x) {}
+template <typename T> I<T>::I (const I &x) : p (x.p) {}
+template <typename T> T &I<T>::operator * () { return *p; }
+template <typename T> T *I<T>::operator -> () { return p; }
+template <typename T> T &I<T>::operator [] (const difference_type &x) const { return p[x]; }
+template <typename T> I<T> &I<T>::operator = (const I &x) { p = x.p; return *this; }
+template <typename T> I<T> &I<T>::operator ++ () { ++p; return *this; }
+template <typename T> I<T> I<T>::operator ++ (int) { return I (p++); }
+template <typename T> I<T> &I<T>::operator -- () { --p; return *this; }
+template <typename T> I<T> I<T>::operator -- (int) { return I (p--); }
+template <typename T> I<T> &I<T>::operator += (const difference_type &x) { p += x; return *this; }
+template <typename T> I<T> &I<T>::operator -= (const difference_type &x) { p -= x; return *this; }
+template <typename T> I<T> I<T>::operator + (const difference_type &x) const { return I (p + x); }
+template <typename T> I<T> I<T>::operator - (const difference_type &x) const { return I (p - x); }
+template <typename T> bool operator == (I<T> &x, I<T> &y) { return x.p == y.p; }
+template <typename T> bool operator == (const I<T> &x, const I<T> &y) { return x.p == y.p; }
+template <typename T> bool operator != (I<T> &x, I<T> &y) { return !(x == y); }
+template <typename T> bool operator != (const I<T> &x, const I<T> &y) { return !(x == y); }
+template <typename T> bool operator < (I<T> &x, I<T> &y) { return x.p < y.p; }
+template <typename T> bool operator < (const I<T> &x, const I<T> &y) { return x.p < y.p; }
+template <typename T> bool operator <= (I<T> &x, I<T> &y) { return x.p <= y.p; }
+template <typename T> bool operator <= (const I<T> &x, const I<T> &y) { return x.p <= y.p; }
+template <typename T> bool operator > (I<T> &x, I<T> &y) { return x.p > y.p; }
+template <typename T> bool operator > (const I<T> &x, const I<T> &y) { return x.p > y.p; }
+template <typename T> bool operator >= (I<T> &x, I<T> &y) { return x.p >= y.p; }
+template <typename T> bool operator >= (const I<T> &x, const I<T> &y) { return x.p >= y.p; }
+template <typename T> typename I<T>::difference_type operator - (I<T> &x, I<T> &y) { return x.p - y.p; }
+template <typename T> typename I<T>::difference_type operator - (const I<T> &x, const I<T> &y) { return x.p - y.p; }
+template <typename T> I<T> operator + (typename I<T>::difference_type x, const I<T> &y) { return I<T> (x + y.p); }
+
+struct R { R () {}; ~R () {}; I<int> r; };
+struct T { T () {}; virtual ~T () {}; I<int> t; };
+struct A : public R, virtual public T { A () {} I<int> a; void m1 (const I<int> &, const I<int> &); };
+template <typename Q>
+struct U { U () {}; virtual ~U () {}; Q t; };
+template <typename Q>
+struct B : public R, virtual public U<Q> { B () {} Q a; void m2 (const Q &, const Q &, const I<int> &, const I<int> &); };
+
+int d[64];
+
+void
+A::m1 (const I<int> &x, const I<int> &y)
+{
+ int w = 0;
+ #pragma omp parallel for private (a) reduction(|:w)
+ for (a = x; A::a < y - 33; a += 2)
+ w |= (1 << *A::a);
+ if (w != 0x55555555)
+ __builtin_abort ();
+ #pragma omp parallel for lastprivate (t)
+ for (T::t = x; t < y - 32; t += 3)
+ d[*T::t + 2] |= 1;
+ if (*T::t != 33)
+ __builtin_abort ();
+ for (int i = 0; i < 64; i++)
+ if (d[i] != ((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 1 : 0))
+ __builtin_abort ();
+ w = 0;
+ #pragma omp parallel for reduction(|:w)
+ for (a = x; A::a < y - 33; a += 2)
+ w |= (1 << *A::a);
+ if (w != 0x55555555)
+ __builtin_abort ();
+ #pragma omp taskloop
+ for (R::r = x; r < y - 32; R::r += 2)
+ d[*r + 8] |= 2;
+ for (int i = 0; i < 64; i++)
+ if (d[i] != (((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 1 : 0)
+ | ((i >= 8 && i < 32 + 8 && (i & 1) == 0) ? 2 : 0)))
+ __builtin_abort ();
+ #pragma omp taskloop collapse(2)
+ for (T::t = x; t < y - 57; t += 2)
+ for (a = x; A::a < y - 56; a++)
+ d[((*t << 2) | *a) + 3] |= 4;
+ for (int i = 0; i < 64; i++)
+ if (d[i] != (((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 1 : 0)
+ | ((i >= 8 && i < 32 + 8 && (i & 1) == 0) ? 2 : 0)
+ | ((i >= 3 && i < 32 + 3) ? 4 : 0)))
+ __builtin_abort ();
+}
+
+template <typename Q>
+void
+B<Q>::m2 (const Q &u, const Q &v, const I<int> &x, const I<int> &y)
+{
+ int w = 0;
+ #pragma omp parallel for private (a) reduction(|:w)
+ for (a = u; B::a < v - 33; a += 2)
+ w |= (1 << *B::a);
+ if (w != 0x55555555)
+ __builtin_abort ();
+ #pragma omp parallel for lastprivate (U<Q>::t)
+ for (U<Q>::t = u; U<Q>::t < v - 32; U<Q>::t += 3)
+ d[*U<Q>::t + 2] |= 1;
+ if (*U<Q>::t != 33)
+ __builtin_abort ();
+ for (int i = 0; i < 64; i++)
+ if (d[i] != ((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 1 : 0))
+ __builtin_abort ();
+ w = 0;
+ #pragma omp parallel for reduction(|:w)
+ for (a = u; B::a < v - 33; a += 2)
+ w |= (1 << *B::a);
+ if (w != 0x55555555)
+ __builtin_abort ();
+ #pragma omp taskloop
+ for (R::r = x; r < y - 32; R::r += 2)
+ d[*r + 8] |= 2;
+ for (int i = 0; i < 64; i++)
+ if (d[i] != (((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 1 : 0)
+ | ((i >= 8 && i < 32 + 8 && (i & 1) == 0) ? 2 : 0)))
+ __builtin_abort ();
+ #pragma omp taskloop collapse(2)
+ for (U<Q>::t = u; U<Q>::t < v - 57; U<Q>::t += 2)
+ for (a = u; B::a < v - 56; a++)
+ d[((*U<Q>::t << 2) | *a) + 3] |= 4;
+ for (int i = 0; i < 64; i++)
+ if (d[i] != (((i >= 2 && i < 32 + 2 && (i - 2) % 3 == 0) ? 1 : 0)
+ | ((i >= 8 && i < 32 + 8 && (i & 1) == 0) ? 2 : 0)
+ | ((i >= 3 && i < 32 + 3) ? 4 : 0)))
+ __builtin_abort ();
+}
+
+int
+main ()
+{
+ A a;
+ int b[128];
+ for (int i = 0; i < 128; i++)
+ b[i] = i - 32;
+ a.m1 (&b[32], &b[96]);
+ for (int i = 0; i < 64; i++)
+ d[i] = 0;
+ B<I<int> > c;
+ c.m2 (&b[32], &b[96], &b[32], &b[96]);
+ for (int i = 0; i < 64; i++)
+ d[i] = 0;
+ B<int *> d;
+ d.m2 (&b[32], &b[96], &b[32], &b[96]);
+}
--- /dev/null
+#include "../libgomp.c/ordered-4.c"
--- /dev/null
+template <typename T>
+struct A
+{
+ A () { t = 0; }
+ A (T x) { t = x; }
+ A (const A &x) { t = x.t; }
+ ~A () {}
+ T t;
+};
+template <typename T>
+struct M
+{
+ M () { t = 1; }
+ M (T x) { t = x; }
+ M (const M &x) { t = x.t; }
+ ~M () {}
+ T t;
+};
+template <typename T>
+struct B
+{
+ B () { t = ~(T) 0; }
+ B (T x) { t = x; }
+ B (const B &x) { t = x.t; }
+ ~B () {}
+ T t;
+};
+template <typename T>
+void
+add (T &x, T &y)
+{
+ x.t += y.t;
+}
+template <typename T>
+void
+zero (T &x)
+{
+ x.t = 0;
+}
+template <typename T>
+void
+orit (T *x, T *y)
+{
+ y->t |= x->t;
+}
+B<long> bb;
+#pragma omp declare reduction(+:A<int>:omp_out.t += omp_in.t)
+#pragma omp declare reduction(+:A<char>:add (omp_out, omp_in)) initializer(zero (omp_priv))
+#pragma omp declare reduction(*:M<int>:omp_out.t *= omp_in.t) initializer(omp_priv = 1)
+#pragma omp declare reduction(|:A<unsigned long long>:orit (&omp_in, &omp_out))
+#pragma omp declare reduction(&:B<long>:omp_out.t = omp_out.t & omp_in.t) initializer(orit (&omp_priv, &omp_orig))
+#pragma omp declare reduction(maxb:short:omp_out = omp_in > omp_out ? omp_in : omp_out) initializer(omp_priv = -6)
+
+A<char> z[10];
+
+template <int N>
+__attribute__((noinline, noclone)) void
+foo (A<int> (*&x)[3][N], M<int> *y, B<long> (&w)[1][N], int p1, long p2, long p3, int p4,
+ int p5, long p6, short p7)
+{
+ A<unsigned long long> a[p7 + 4];
+ short bb[p7];
+ short (&b)[p7] = bb;
+ for (int i = 0; i < p7; i++)
+ bb[i] = -6;
+ #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2 + N - 2], z[:p3]) \
+ reduction(*:y[:p4]) reduction(|:a[:p5 - N + 2]) \
+ reduction(&:w[0:p6 - 3 + N][:p6]) reduction(maxb:b)
+ for (int i = 0; i < 128; i++)
+ {
+ x[i / 64][i % 3][(i / 4) & 1].t += i;
+ if ((i & 15) == 1)
+ y[0].t *= 3;
+ if ((i & 31) == N)
+ y[1].t *= 7;
+ if ((i & 63) == 3)
+ y[N].t *= 17;
+ z[i / 32].t += (i & 3);
+ if (i < 4)
+ z[i].t += i;
+ a[i / 32].t |= 1ULL << (i & 30);
+ w[0][i & 1].t &= ~(1L << (i / 17 * 3));
+ if ((i % 79) > b[0])
+ b[0] = i % 79;
+ if ((i % 13) > b[1])
+ b[1] = i % 13;
+ if ((i % 23) > b[N])
+ b[N] = i % 23;
+ if ((i % 85) > b[3])
+ b[3] = i % 85;
+ if ((i % 192) > b[4])
+ b[4] = i % 192;
+ }
+ for (int i = 0; i < 9; i++)
+ if (a[i].t != (i < 4 ? 0x55555555ULL : 0))
+ __builtin_abort ();
+ if (bb[0] != 78 || bb[1] != 12 || bb[N] != 22 || bb[3] != 84 || bb[4] != 127)
+ __builtin_abort ();
+}
+
+A<int> a3[4][3][2];
+A<int> (*p3)[3][2] = &a3[1];
+M<int> y3[5] = { 0, 1, 1, 1, 0 };
+B<long> w3[1][2];
+
+template <int N>
+struct S
+{
+ A<int> (*&x)[3][N];
+ M<int> *y;
+ B<long> (&w)[1][N];
+ A<char> z[10];
+ short b[5];
+ A<unsigned long long> a[9];
+ S() : x(p3), y(y3+1), w(w3), z(), a(), b() {}
+ __attribute__((noinline, noclone)) void foo (int, long, long, int, int, long, short);
+};
+
+template <int N>
+void
+S<N>::foo (int p1, long p2, long p3, int p4, int p5, long p6, short p7)
+{
+ #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2][0:N], z[:p3 + N - 2]) \
+ reduction(*:y[:p4]) reduction(|:a[:p5]) \
+ reduction(&:w[0:p6 - 3 + N][:p6]) reduction(maxb:b)
+ for (int i = 0; i < 128; i++)
+ {
+ x[i / 64][i % 3][(i / 4) & 1].t += i;
+ if ((i & 15) == 1)
+ y[0].t *= 3;
+ if ((i & 31) == N)
+ y[1].t *= 7;
+ if ((i & 63) == 3)
+ y[N].t *= 17;
+ z[i / 32].t += (i & 3);
+ if (i < 4)
+ z[i].t += i;
+ a[i / 32].t |= 1ULL << (i & 30);
+ w[0][i & 1].t &= ~(1L << (i / 17 * 3));
+ if ((i % 79) > b[0])
+ b[0] = i % 79;
+ if ((i % 13) > b[1])
+ b[1] = i % 13;
+ if ((i % 23) > b[N])
+ b[N] = i % 23;
+ if ((i % 85) > b[3])
+ b[3] = i % 85;
+ if ((i % 192) > b[4])
+ b[4] = i % 192;
+ }
+}
+
+int
+main ()
+{
+ A<int> a[4][3][2];
+ static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }},
+ {{ 312, 381 }, { 295, 356 }, { 337, 335 }},
+ {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }},
+ {{ 0, 0 }, { 0, 0 }, { 0, 0 }}};
+ A<int> (*p)[3][2] = &a[1];
+ M<int> y[5] = { 0, 1, 1, 1, 0 };
+ int y2[5] = { 0, 6561, 2401, 289, 0 };
+ char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 };
+ B<long> w[1][2];
+ foo<2> (p, y + 1, w, 1, 3L, 4L, 3, 4, 2L, 5);
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 3; j++)
+ for (int k = 0; k < 2; k++)
+ if (a[i][j][k].t != a2[i][j][k])
+ __builtin_abort ();
+ for (int i = 0; i < 5; i++)
+ if (y[i].t != y2[i])
+ __builtin_abort ();
+ for (int i = 0; i < 10; i++)
+ if (z[i].t != z2[i])
+ __builtin_abort ();
+ if (w[0][0].t != ~0x249249L || w[0][1].t != ~0x249249L)
+ __builtin_abort ();
+ S<2> s;
+ s.foo (1, 3L, 4L, 3, 4, 2L, 5);
+ for (int i = 0; i < 9; i++)
+ if (s.a[i].t != (i < 4 ? 0x55555555ULL : 0))
+ __builtin_abort ();
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 3; j++)
+ for (int k = 0; k < 2; k++)
+ if (a3[i][j][k].t != a2[i][j][k])
+ __builtin_abort ();
+ for (int i = 0; i < 5; i++)
+ if (y3[i].t != y2[i])
+ __builtin_abort ();
+ for (int i = 0; i < 10; i++)
+ if (s.z[i].t != z2[i])
+ __builtin_abort ();
+ if (w3[0][0].t != ~0x249249L || w3[0][1].t != ~0x249249L)
+ __builtin_abort ();
+ if (s.b[0] != 78 || s.b[1] != 12 || s.b[2] != 22
+ || s.b[3] != 84 || s.b[4] != 127)
+ __builtin_abort ();
+}
--- /dev/null
+char z[10] = { 0 };
+
+__attribute__((noinline, noclone)) void
+foo (int (*&x)[3][2], int *y, long (&w)[1][2])
+{
+ unsigned long long a[9] = {};
+ short b[5] = {};
+ #pragma omp parallel for reduction(+:x[0:2][:][0:2], z[:4]) \
+ reduction(*:y[:3]) reduction(|:a[:4]) \
+ reduction(&:w[0:][:2]) reduction(max:b)
+ for (int i = 0; i < 128; i++)
+ {
+ x[i / 64][i % 3][(i / 4) & 1] += i;
+ if ((i & 15) == 1)
+ y[0] *= 3;
+ if ((i & 31) == 2)
+ y[1] *= 7;
+ if ((i & 63) == 3)
+ y[2] *= 17;
+ z[i / 32] += (i & 3);
+ if (i < 4)
+ z[i] += i;
+ a[i / 32] |= 1ULL << (i & 30);
+ w[0][i & 1] &= ~(1L << (i / 17 * 3));
+ if ((i % 79) > b[0])
+ b[0] = i % 79;
+ if ((i % 13) > b[1])
+ b[1] = i % 13;
+ if ((i % 23) > b[2])
+ b[2] = i % 23;
+ if ((i % 85) > b[3])
+ b[3] = i % 85;
+ if ((i % 192) > b[4])
+ b[4] = i % 192;
+ }
+ for (int i = 0; i < 9; i++)
+ if (a[i] != (i < 4 ? 0x55555555ULL : 0))
+ __builtin_abort ();
+ if (b[0] != 78 || b[1] != 12 || b[2] != 22 || b[3] != 84 || b[4] != 127)
+ __builtin_abort ();
+}
+
+int a3[4][3][2];
+int (*p3)[3][2] = &a3[1];
+int y3[5] = { 0, 1, 1, 1, 0 };
+long w3[1][2] = { ~0L, ~0L };
+short bb[5];
+
+struct S
+{
+ int (*&x)[3][2];
+ int *y;
+ long (&w)[1][2];
+ char z[10];
+ short (&b)[5];
+ unsigned long long a[9];
+ S() : x(p3), y(y3+1), w(w3), z(), a(), b(bb) {}
+ __attribute__((noinline, noclone)) void foo ();
+};
+
+void
+S::foo ()
+{
+ #pragma omp parallel for reduction(+:x[0:2][:][0:2], z[:4]) \
+ reduction(*:y[:3]) reduction(|:a[:4]) \
+ reduction(&:w[0:][:2]) reduction(max:b)
+ for (int i = 0; i < 128; i++)
+ {
+ x[i / 64][i % 3][(i / 4) & 1] += i;
+ if ((i & 15) == 1)
+ y[0] *= 3;
+ if ((i & 31) == 2)
+ y[1] *= 7;
+ if ((i & 63) == 3)
+ y[2] *= 17;
+ z[i / 32] += (i & 3);
+ if (i < 4)
+ z[i] += i;
+ a[i / 32] |= 1ULL << (i & 30);
+ w[0][i & 1] &= ~(1L << (i / 17 * 3));
+ if ((i % 79) > b[0])
+ b[0] = i % 79;
+ if ((i % 13) > b[1])
+ b[1] = i % 13;
+ if ((i % 23) > b[2])
+ b[2] = i % 23;
+ if ((i % 85) > b[3])
+ b[3] = i % 85;
+ if ((i % 192) > b[4])
+ b[4] = i % 192;
+ }
+}
+
+int
+main ()
+{
+ int a[4][3][2] = {};
+ static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }},
+ {{ 312, 381 }, { 295, 356 }, { 337, 335 }},
+ {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }},
+ {{ 0, 0 }, { 0, 0 }, { 0, 0 }}};
+ int (*p)[3][2] = &a[1];
+ int y[5] = { 0, 1, 1, 1, 0 };
+ int y2[5] = { 0, 6561, 2401, 289, 0 };
+ char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 };
+ long w[1][2] = { ~0L, ~0L };
+ foo (p, y + 1, w);
+ if (__builtin_memcmp (a, a2, sizeof (a))
+ || __builtin_memcmp (y, y2, sizeof (y))
+ || __builtin_memcmp (z, z2, sizeof (z))
+ || w[0][0] != ~0x249249L
+ || w[0][1] != ~0x249249L)
+ __builtin_abort ();
+ S s;
+ s.foo ();
+ for (int i = 0; i < 9; i++)
+ if (s.a[i] != (i < 4 ? 0x55555555ULL : 0))
+ __builtin_abort ();
+ if (__builtin_memcmp (a3, a2, sizeof (a3))
+ || __builtin_memcmp (y3, y2, sizeof (y3))
+ || __builtin_memcmp (s.z, z2, sizeof (s.z))
+ || w3[0][0] != ~0x249249L
+ || w3[0][1] != ~0x249249L)
+ __builtin_abort ();
+ if (bb[0] != 78 || bb[1] != 12 || bb[2] != 22 || bb[3] != 84 || bb[4] != 127)
+ __builtin_abort ();
+}
--- /dev/null
+template <typename T>
+struct A
+{
+ A () { t = 0; }
+ A (T x) { t = x; }
+ A (const A &x) { t = x.t; }
+ ~A () {}
+ T t;
+};
+template <typename T>
+struct M
+{
+ M () { t = 1; }
+ M (T x) { t = x; }
+ M (const M &x) { t = x.t; }
+ ~M () {}
+ T t;
+};
+template <typename T>
+struct B
+{
+ B () { t = ~(T) 0; }
+ B (T x) { t = x; }
+ B (const B &x) { t = x.t; }
+ ~B () {}
+ T t;
+};
+template <typename T>
+void
+add (T &x, T &y)
+{
+ x.t += y.t;
+}
+template <typename T>
+void
+zero (T &x)
+{
+ x.t = 0;
+}
+template <typename T>
+void
+orit (T *x, T *y)
+{
+ y->t |= x->t;
+}
+B<long> bb;
+#pragma omp declare reduction(+:A<int>:omp_out.t += omp_in.t)
+#pragma omp declare reduction(+:A<char>:add (omp_out, omp_in)) initializer(zero (omp_priv))
+#pragma omp declare reduction(*:M<int>:omp_out.t *= omp_in.t) initializer(omp_priv = 1)
+#pragma omp declare reduction(|:A<unsigned long long>:orit (&omp_in, &omp_out))
+#pragma omp declare reduction(&:B<long>:omp_out.t = omp_out.t & omp_in.t) initializer(orit (&omp_priv, &omp_orig))
+#pragma omp declare reduction(maxb:short:omp_out = omp_in > omp_out ? omp_in : omp_out) initializer(omp_priv = -6)
+
+A<char> z[10];
+
+__attribute__((noinline, noclone)) void
+foo (A<int> (*&x)[3][2], M<int> *y, B<long> (&w)[1][2])
+{
+ A<unsigned long long> a[9];
+ short bb[5] = {};
+ short (&b)[5] = bb;
+ #pragma omp parallel for reduction(+:x[0:2][:][0:2], z[:4]) \
+ reduction(*:y[:3]) reduction(|:a[:4]) \
+ reduction(&:w[0:][:2]) reduction(maxb:b)
+ for (int i = 0; i < 128; i++)
+ {
+ x[i / 64][i % 3][(i / 4) & 1].t += i;
+ if ((i & 15) == 1)
+ y[0].t *= 3;
+ if ((i & 31) == 2)
+ y[1].t *= 7;
+ if ((i & 63) == 3)
+ y[2].t *= 17;
+ z[i / 32].t += (i & 3);
+ if (i < 4)
+ z[i].t += i;
+ a[i / 32].t |= 1ULL << (i & 30);
+ w[0][i & 1].t &= ~(1L << (i / 17 * 3));
+ if ((i % 79) > b[0])
+ b[0] = i % 79;
+ if ((i % 13) > b[1])
+ b[1] = i % 13;
+ if ((i % 23) > b[2])
+ b[2] = i % 23;
+ if ((i % 85) > b[3])
+ b[3] = i % 85;
+ if ((i % 192) > b[4])
+ b[4] = i % 192;
+ }
+ for (int i = 0; i < 9; i++)
+ if (a[i].t != (i < 4 ? 0x55555555ULL : 0))
+ __builtin_abort ();
+ if (bb[0] != 78 || bb[1] != 12 || bb[2] != 22 || bb[3] != 84 || bb[4] != 127)
+ __builtin_abort ();
+}
+
+A<int> a3[4][3][2];
+A<int> (*p3)[3][2] = &a3[1];
+M<int> y3[5] = { 0, 1, 1, 1, 0 };
+B<long> w3[1][2];
+
+struct S
+{
+ A<int> (*&x)[3][2];
+ M<int> *y;
+ B<long> (&w)[1][2];
+ A<char> z[10];
+ short b[5];
+ A<unsigned long long> a[9];
+ S() : x(p3), y(y3+1), w(w3), z(), a(), b() {}
+ __attribute__((noinline, noclone)) void foo ();
+};
+
+void
+S::foo ()
+{
+ #pragma omp parallel for reduction(+:x[0:2][:][0:2], z[:4]) \
+ reduction(*:y[:3]) reduction(|:a[:4]) \
+ reduction(&:w[0:][:2]) reduction(maxb:b)
+ for (int i = 0; i < 128; i++)
+ {
+ x[i / 64][i % 3][(i / 4) & 1].t += i;
+ if ((i & 15) == 1)
+ y[0].t *= 3;
+ if ((i & 31) == 2)
+ y[1].t *= 7;
+ if ((i & 63) == 3)
+ y[2].t *= 17;
+ z[i / 32].t += (i & 3);
+ if (i < 4)
+ z[i].t += i;
+ a[i / 32].t |= 1ULL << (i & 30);
+ w[0][i & 1].t &= ~(1L << (i / 17 * 3));
+ if ((i % 79) > b[0])
+ b[0] = i % 79;
+ if ((i % 13) > b[1])
+ b[1] = i % 13;
+ if ((i % 23) > b[2])
+ b[2] = i % 23;
+ if ((i % 85) > b[3])
+ b[3] = i % 85;
+ if ((i % 192) > b[4])
+ b[4] = i % 192;
+ }
+}
+
+int
+main ()
+{
+ A<int> a[4][3][2];
+ static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }},
+ {{ 312, 381 }, { 295, 356 }, { 337, 335 }},
+ {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }},
+ {{ 0, 0 }, { 0, 0 }, { 0, 0 }}};
+ A<int> (*p)[3][2] = &a[1];
+ M<int> y[5] = { 0, 1, 1, 1, 0 };
+ int y2[5] = { 0, 6561, 2401, 289, 0 };
+ char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 };
+ B<long> w[1][2];
+ foo (p, y + 1, w);
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 3; j++)
+ for (int k = 0; k < 2; k++)
+ if (a[i][j][k].t != a2[i][j][k])
+ __builtin_abort ();
+ for (int i = 0; i < 5; i++)
+ if (y[i].t != y2[i])
+ __builtin_abort ();
+ for (int i = 0; i < 10; i++)
+ if (z[i].t != z2[i])
+ __builtin_abort ();
+ if (w[0][0].t != ~0x249249L || w[0][1].t != ~0x249249L)
+ __builtin_abort ();
+ S s;
+ s.foo ();
+ for (int i = 0; i < 9; i++)
+ if (s.a[i].t != (i < 4 ? 0x55555555ULL : 0))
+ __builtin_abort ();
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 3; j++)
+ for (int k = 0; k < 2; k++)
+ if (a3[i][j][k].t != a2[i][j][k])
+ __builtin_abort ();
+ for (int i = 0; i < 5; i++)
+ if (y3[i].t != y2[i])
+ __builtin_abort ();
+ for (int i = 0; i < 10; i++)
+ if (s.z[i].t != z2[i])
+ __builtin_abort ();
+ if (w3[0][0].t != ~0x249249L || w3[0][1].t != ~0x249249L)
+ __builtin_abort ();
+ if (s.b[0] != 78 || s.b[1] != 12 || s.b[2] != 22
+ || s.b[3] != 84 || s.b[4] != 127)
+ __builtin_abort ();
+}
--- /dev/null
+char z[10] = { 0 };
+
+__attribute__((noinline, noclone)) void
+foo (int (*&x)[3][2], int *y, long (&w)[1][2], int p1, long p2, long p3, int p4,
+ int p5, long p6, short p7)
+{
+ unsigned long long a[p7 + 4];
+ short b[p7];
+ for (int i = 0; i < p7 + 4; i++)
+ {
+ if (i < p7)
+ b[i] = -6;
+ a[i] = 0;
+ }
+ #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2], z[:p3]) \
+ reduction(*:y[:p4]) reduction(|:a[:p5]) \
+ reduction(&:w[0:p6 - 1][:p6]) reduction(max:b)
+ for (int i = 0; i < 128; i++)
+ {
+ x[i / 64][i % 3][(i / 4) & 1] += i;
+ if ((i & 15) == 1)
+ y[0] *= 3;
+ if ((i & 31) == 2)
+ y[1] *= 7;
+ if ((i & 63) == 3)
+ y[2] *= 17;
+ z[i / 32] += (i & 3);
+ if (i < 4)
+ z[i] += i;
+ a[i / 32] |= 1ULL << (i & 30);
+ w[0][i & 1] &= ~(1L << (i / 17 * 3));
+ if ((i % 79) > b[0])
+ b[0] = i % 79;
+ if ((i % 13) > b[1])
+ b[1] = i % 13;
+ if ((i % 23) > b[2])
+ b[2] = i % 23;
+ if ((i % 85) > b[3])
+ b[3] = i % 85;
+ if ((i % 192) > b[4])
+ b[4] = i % 192;
+ }
+ for (int i = 0; i < 9; i++)
+ if (a[i] != (i < 4 ? 0x55555555ULL : 0))
+ __builtin_abort ();
+ if (b[0] != 78 || b[1] != 12 || b[2] != 22 || b[3] != 84 || b[4] != 127)
+ __builtin_abort ();
+}
+
+int a3[4][3][2];
+int (*p3)[3][2] = &a3[1];
+int y3[5] = { 0, 1, 1, 1, 0 };
+long w3[1][2] = { ~0L, ~0L };
+short bb[5];
+
+struct S
+{
+ int (*&x)[3][2];
+ int *y;
+ long (&w)[1][2];
+ char z[10];
+ short (&b)[5];
+ unsigned long long a[9];
+ S() : x(p3), y(y3+1), w(w3), z(), a(), b(bb) {}
+ __attribute__((noinline, noclone)) void foo (int, long, long, int, int, long, short);
+};
+
+void
+S::foo (int p1, long p2, long p3, int p4, int p5, long p6, short p7)
+{
+ #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2], z[:p3]) \
+ reduction(*:y[:p4]) reduction(|:a[:p5]) \
+ reduction(&:w[0:p6 - 1][:p6]) reduction(max:b[0:p7])
+ for (int i = 0; i < 128; i++)
+ {
+ x[i / 64][i % 3][(i / 4) & 1] += i;
+ if ((i & 15) == 1)
+ y[0] *= 3;
+ if ((i & 31) == 2)
+ y[1] *= 7;
+ if ((i & 63) == 3)
+ y[2] *= 17;
+ z[i / 32] += (i & 3);
+ if (i < 4)
+ z[i] += i;
+ a[i / 32] |= 1ULL << (i & 30);
+ w[0][i & 1] &= ~(1L << (i / 17 * 3));
+ if ((i % 79) > b[0])
+ b[0] = i % 79;
+ if ((i % 13) > b[1])
+ b[1] = i % 13;
+ if ((i % 23) > b[2])
+ b[2] = i % 23;
+ if ((i % 85) > b[3])
+ b[3] = i % 85;
+ if ((i % 192) > b[4])
+ b[4] = i % 192;
+ }
+}
+
+int
+main ()
+{
+ int a[4][3][2] = {};
+ static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }},
+ {{ 312, 381 }, { 295, 356 }, { 337, 335 }},
+ {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }},
+ {{ 0, 0 }, { 0, 0 }, { 0, 0 }}};
+ int (*p)[3][2] = &a[1];
+ int y[5] = { 0, 1, 1, 1, 0 };
+ int y2[5] = { 0, 6561, 2401, 289, 0 };
+ char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 };
+ long w[1][2] = { ~0L, ~0L };
+ foo (p, y + 1, w, 1, 3L, 4L, 3, 4, 2L, 5);
+ if (__builtin_memcmp (a, a2, sizeof (a))
+ || __builtin_memcmp (y, y2, sizeof (y))
+ || __builtin_memcmp (z, z2, sizeof (z))
+ || w[0][0] != ~0x249249L
+ || w[0][1] != ~0x249249L)
+ __builtin_abort ();
+ S s;
+ s.foo (1, 3L, 4L, 3, 4, 2L, 5);
+ for (int i = 0; i < 9; i++)
+ if (s.a[i] != (i < 4 ? 0x55555555ULL : 0))
+ __builtin_abort ();
+ if (__builtin_memcmp (a3, a2, sizeof (a3))
+ || __builtin_memcmp (y3, y2, sizeof (y3))
+ || __builtin_memcmp (s.z, z2, sizeof (s.z))
+ || w3[0][0] != ~0x249249L
+ || w3[0][1] != ~0x249249L)
+ __builtin_abort ();
+ if (bb[0] != 78 || bb[1] != 12 || bb[2] != 22 || bb[3] != 84 || bb[4] != 127)
+ __builtin_abort ();
+}
--- /dev/null
+template <typename T>
+struct A
+{
+ A () { t = 0; }
+ A (T x) { t = x; }
+ A (const A &x) { t = x.t; }
+ ~A () {}
+ T t;
+};
+template <typename T>
+struct M
+{
+ M () { t = 1; }
+ M (T x) { t = x; }
+ M (const M &x) { t = x.t; }
+ ~M () {}
+ T t;
+};
+template <typename T>
+struct B
+{
+ B () { t = ~(T) 0; }
+ B (T x) { t = x; }
+ B (const B &x) { t = x.t; }
+ ~B () {}
+ T t;
+};
+template <typename T>
+void
+add (T &x, T &y)
+{
+ x.t += y.t;
+}
+template <typename T>
+void
+zero (T &x)
+{
+ x.t = 0;
+}
+template <typename T>
+void
+orit (T *x, T *y)
+{
+ y->t |= x->t;
+}
+B<long> bb;
+#pragma omp declare reduction(+:A<int>:omp_out.t += omp_in.t)
+#pragma omp declare reduction(+:A<char>:add (omp_out, omp_in)) initializer(zero (omp_priv))
+#pragma omp declare reduction(*:M<int>:omp_out.t *= omp_in.t) initializer(omp_priv = 1)
+#pragma omp declare reduction(|:A<unsigned long long>:orit (&omp_in, &omp_out))
+#pragma omp declare reduction(&:B<long>:omp_out.t = omp_out.t & omp_in.t) initializer(orit (&omp_priv, &omp_orig))
+#pragma omp declare reduction(maxb:short:omp_out = omp_in > omp_out ? omp_in : omp_out) initializer(omp_priv = -6)
+
+A<char> z[10];
+
+__attribute__((noinline, noclone)) void
+foo (A<int> (*&x)[3][2], M<int> *y, B<long> (&w)[1][2], int p1, long p2, long p3, int p4,
+ int p5, long p6, short p7)
+{
+ A<unsigned long long> a[p7 + 4];
+ short bb[p7];
+ short (&b)[p7] = bb;
+ for (int i = 0; i < p7; i++)
+ bb[i] = -6;
+ #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2], z[:p3]) \
+ reduction(*:y[:p4]) reduction(|:a[:p5]) \
+ reduction(&:w[0:p6 - 1][:p6]) reduction(maxb:b)
+ for (int i = 0; i < 128; i++)
+ {
+ x[i / 64][i % 3][(i / 4) & 1].t += i;
+ if ((i & 15) == 1)
+ y[0].t *= 3;
+ if ((i & 31) == 2)
+ y[1].t *= 7;
+ if ((i & 63) == 3)
+ y[2].t *= 17;
+ z[i / 32].t += (i & 3);
+ if (i < 4)
+ z[i].t += i;
+ a[i / 32].t |= 1ULL << (i & 30);
+ w[0][i & 1].t &= ~(1L << (i / 17 * 3));
+ if ((i % 79) > b[0])
+ b[0] = i % 79;
+ if ((i % 13) > b[1])
+ b[1] = i % 13;
+ if ((i % 23) > b[2])
+ b[2] = i % 23;
+ if ((i % 85) > b[3])
+ b[3] = i % 85;
+ if ((i % 192) > b[4])
+ b[4] = i % 192;
+ }
+ for (int i = 0; i < 9; i++)
+ if (a[i].t != (i < 4 ? 0x55555555ULL : 0))
+ __builtin_abort ();
+ if (bb[0] != 78 || bb[1] != 12 || bb[2] != 22 || bb[3] != 84 || bb[4] != 127)
+ __builtin_abort ();
+}
+
+A<int> a3[4][3][2];
+A<int> (*p3)[3][2] = &a3[1];
+M<int> y3[5] = { 0, 1, 1, 1, 0 };
+B<long> w3[1][2];
+
+struct S
+{
+ A<int> (*&x)[3][2];
+ M<int> *y;
+ B<long> (&w)[1][2];
+ A<char> z[10];
+ short b[5];
+ A<unsigned long long> a[9];
+ S() : x(p3), y(y3+1), w(w3), z(), a(), b() {}
+ __attribute__((noinline, noclone)) void foo (int, long, long, int, int, long, short);
+};
+
+void
+S::foo (int p1, long p2, long p3, int p4, int p5, long p6, short p7)
+{
+ #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2][0:2], z[:p3]) \
+ reduction(*:y[:p4]) reduction(|:a[:p5]) \
+ reduction(&:w[0:p6 - 1][:p6]) reduction(maxb:b)
+ for (int i = 0; i < 128; i++)
+ {
+ x[i / 64][i % 3][(i / 4) & 1].t += i;
+ if ((i & 15) == 1)
+ y[0].t *= 3;
+ if ((i & 31) == 2)
+ y[1].t *= 7;
+ if ((i & 63) == 3)
+ y[2].t *= 17;
+ z[i / 32].t += (i & 3);
+ if (i < 4)
+ z[i].t += i;
+ a[i / 32].t |= 1ULL << (i & 30);
+ w[0][i & 1].t &= ~(1L << (i / 17 * 3));
+ if ((i % 79) > b[0])
+ b[0] = i % 79;
+ if ((i % 13) > b[1])
+ b[1] = i % 13;
+ if ((i % 23) > b[2])
+ b[2] = i % 23;
+ if ((i % 85) > b[3])
+ b[3] = i % 85;
+ if ((i % 192) > b[4])
+ b[4] = i % 192;
+ }
+}
+
+int
+main ()
+{
+ A<int> a[4][3][2];
+ static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }},
+ {{ 312, 381 }, { 295, 356 }, { 337, 335 }},
+ {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }},
+ {{ 0, 0 }, { 0, 0 }, { 0, 0 }}};
+ A<int> (*p)[3][2] = &a[1];
+ M<int> y[5] = { 0, 1, 1, 1, 0 };
+ int y2[5] = { 0, 6561, 2401, 289, 0 };
+ char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 };
+ B<long> w[1][2];
+ foo (p, y + 1, w, 1, 3L, 4L, 3, 4, 2L, 5);
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 3; j++)
+ for (int k = 0; k < 2; k++)
+ if (a[i][j][k].t != a2[i][j][k])
+ __builtin_abort ();
+ for (int i = 0; i < 5; i++)
+ if (y[i].t != y2[i])
+ __builtin_abort ();
+ for (int i = 0; i < 10; i++)
+ if (z[i].t != z2[i])
+ __builtin_abort ();
+ if (w[0][0].t != ~0x249249L || w[0][1].t != ~0x249249L)
+ __builtin_abort ();
+ S s;
+ s.foo (1, 3L, 4L, 3, 4, 2L, 5);
+ for (int i = 0; i < 9; i++)
+ if (s.a[i].t != (i < 4 ? 0x55555555ULL : 0))
+ __builtin_abort ();
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 3; j++)
+ for (int k = 0; k < 2; k++)
+ if (a3[i][j][k].t != a2[i][j][k])
+ __builtin_abort ();
+ for (int i = 0; i < 5; i++)
+ if (y3[i].t != y2[i])
+ __builtin_abort ();
+ for (int i = 0; i < 10; i++)
+ if (s.z[i].t != z2[i])
+ __builtin_abort ();
+ if (w3[0][0].t != ~0x249249L || w3[0][1].t != ~0x249249L)
+ __builtin_abort ();
+ if (s.b[0] != 78 || s.b[1] != 12 || s.b[2] != 22
+ || s.b[3] != 84 || s.b[4] != 127)
+ __builtin_abort ();
+}
--- /dev/null
+char z[10] = { 0 };
+
+template <int N>
+__attribute__((noinline, noclone)) void
+foo (int (*&x)[3][N], int *y, long (&w)[1][N])
+{
+ unsigned long long a[9] = {};
+ short b[5] = {};
+ #pragma omp parallel for reduction(+:x[0:N][:][0:N], z[:4]) \
+ reduction(*:y[:3]) reduction(|:a[:4]) \
+ reduction(&:w[0:][:N]) reduction(max:b)
+ for (int i = 0; i < 128; i++)
+ {
+ x[i / 64][i % 3][(i / 4) & 1] += i;
+ if ((i & 15) == 1)
+ y[0] *= 3;
+ if ((i & 31) == N)
+ y[1] *= 7;
+ if ((i & 63) == 3)
+ y[N] *= 17;
+ z[i / 32] += (i & 3);
+ if (i < 4)
+ z[i] += i;
+ a[i / 32] |= 1ULL << (i & 30);
+ w[0][i & 1] &= ~(1L << (i / 17 * 3));
+ if ((i % 79) > b[0])
+ b[0] = i % 79;
+ if ((i % 13) > b[1])
+ b[1] = i % 13;
+ if ((i % 23) > b[N])
+ b[N] = i % 23;
+ if ((i % 85) > b[3])
+ b[3] = i % 85;
+ if ((i % 192) > b[4])
+ b[4] = i % 192;
+ }
+ for (int i = 0; i < 9; i++)
+ if (a[i] != (i < 4 ? 0x55555555ULL : 0))
+ __builtin_abort ();
+ if (b[0] != 78 || b[1] != 12 || b[N] != 22 || b[3] != 84 || b[4] != 127)
+ __builtin_abort ();
+}
+
+int a3[4][3][2];
+int (*p3)[3][2] = &a3[1];
+int y3[5] = { 0, 1, 1, 1, 0 };
+long w3[1][2] = { ~0L, ~0L };
+short bb[5];
+
+template <int N>
+struct S
+{
+ int (*&x)[3][N];
+ int *y;
+ long (&w)[1][N];
+ char z[10];
+ short (&b)[5];
+ unsigned long long a[9];
+ S() : x(p3), y(y3+1), w(w3), z(), a(), b(bb) {}
+ __attribute__((noinline, noclone)) void foo ();
+};
+
+template <int N>
+void
+S<N>::foo ()
+{
+ #pragma omp parallel for reduction(+:x[0:N][:][0:N], z[:4]) \
+ reduction(*:y[:3]) reduction(|:a[:4]) \
+ reduction(&:w[0:][:N]) reduction(max:b)
+ for (int i = 0; i < 128; i++)
+ {
+ x[i / 64][i % 3][(i / 4) & 1] += i;
+ if ((i & 15) == 1)
+ y[0] *= 3;
+ if ((i & 31) == N)
+ y[1] *= 7;
+ if ((i & 63) == 3)
+ y[N] *= 17;
+ z[i / 32] += (i & 3);
+ if (i < 4)
+ z[i] += i;
+ a[i / 32] |= 1ULL << (i & 30);
+ w[0][i & 1] &= ~(1L << (i / 17 * 3));
+ if ((i % 79) > b[0])
+ b[0] = i % 79;
+ if ((i % 13) > b[1])
+ b[1] = i % 13;
+ if ((i % 23) > b[N])
+ b[N] = i % 23;
+ if ((i % 85) > b[3])
+ b[3] = i % 85;
+ if ((i % 192) > b[4])
+ b[4] = i % 192;
+ }
+}
+
+int
+main ()
+{
+ int a[4][3][2] = {};
+ static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }},
+ {{ 312, 381 }, { 295, 356 }, { 337, 335 }},
+ {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }},
+ {{ 0, 0 }, { 0, 0 }, { 0, 0 }}};
+ int (*p)[3][2] = &a[1];
+ int y[5] = { 0, 1, 1, 1, 0 };
+ int y2[5] = { 0, 6561, 2401, 289, 0 };
+ char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 };
+ long w[1][2] = { ~0L, ~0L };
+ foo<2> (p, y + 1, w);
+ if (__builtin_memcmp (a, a2, sizeof (a))
+ || __builtin_memcmp (y, y2, sizeof (y))
+ || __builtin_memcmp (z, z2, sizeof (z))
+ || w[0][0] != ~0x249249L
+ || w[0][1] != ~0x249249L)
+ __builtin_abort ();
+ S<2> s;
+ s.foo ();
+ for (int i = 0; i < 9; i++)
+ if (s.a[i] != (i < 4 ? 0x55555555ULL : 0))
+ __builtin_abort ();
+ if (__builtin_memcmp (a3, a2, sizeof (a3))
+ || __builtin_memcmp (y3, y2, sizeof (y3))
+ || __builtin_memcmp (s.z, z2, sizeof (s.z))
+ || w3[0][0] != ~0x249249L
+ || w3[0][1] != ~0x249249L)
+ __builtin_abort ();
+ if (bb[0] != 78 || bb[1] != 12 || bb[2] != 22 || bb[3] != 84 || bb[4] != 127)
+ __builtin_abort ();
+}
--- /dev/null
+// { dg-do run }
+
+#include <omp.h>
+
+__attribute__((noinline, noclone)) void
+foo (int &a, short &d, char &g)
+{
+ unsigned long b = 12;
+ unsigned long &c = b;
+ long long e = 21;
+ long long &f = e;
+ unsigned int h = 12;
+ unsigned int &k = h;
+ #pragma omp parallel default(none) private(a, c) firstprivate(d, f) shared(g, k)
+ {
+ int i = omp_get_thread_num ();
+ a = i;
+ c = 2 * i;
+ if (d != 27 || f != 21)
+ __builtin_abort ();
+ d = 3 * (i & 0xfff);
+ f = 4 * i;
+ #pragma omp barrier
+ if (a != i || c != 2 * i || d != 3 * (i & 0xfff) || f != 4 * i)
+ __builtin_abort ();
+ #pragma omp for lastprivate(g, k)
+ for (int j = 0; j < 32; j++)
+ {
+ g = j;
+ k = 3 * j;
+ }
+ }
+ if (g != 31 || k != 31 * 3)
+ __builtin_abort ();
+ #pragma omp parallel for firstprivate (g, k) lastprivate (g, k)
+ for (int j = 0; j < 32; j++)
+ {
+ if (g != 31 || k != 31 * 3)
+ __builtin_abort ();
+ if (j == 31)
+ {
+ g = 29;
+ k = 138;
+ }
+ }
+ if (g != 29 || k != 138)
+ __builtin_abort ();
+}
+
+int
+main ()
+{
+ int a = 5;
+ short d = 27;
+ char g = ' ';
+ foo (a, d, g);
+}
--- /dev/null
+// { dg-do run }
+// { dg-options "-O2" }
+// { dg-additional-options "-msse2" { target sse2_runtime } }
+// { dg-additional-options "-mavx" { target avx_runtime } }
+
+int a[1024];
+short b[2048];
+
+static inline void
+bar (int &x, unsigned long long &y, short *&z)
+{
+ a[x] = x + y + *z;
+ x++;
+ y += 17;
+ z += 2;
+}
+
+__attribute__((noinline, noclone)) int
+foo (unsigned long long &s, short *&t)
+{
+ int i, j = 0;
+ int &r = j;
+#pragma omp parallel for simd linear(r) linear(s:17ULL) linear(t:2)
+ for (i = 0; i < 1024; i++)
+ bar (r, s, t);
+ return j;
+}
+
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 2048; i++)
+ b[i] = 3 * i;
+ unsigned long long s = 12;
+ short *t = b;
+ int j = foo (s, t);
+ for (i = 0; i < 1024; i++)
+ if (a[i] != 12 + 24 * i)
+ __builtin_abort ();
+ if (j != 1024 || s != 12 + 1024 * 17ULL || t != &b[2048])
+ __builtin_abort ();
+}
--- /dev/null
+extern "C" void abort (void);
+union U { int x; long long y; };
+struct T { int a; union U b; int c; };
+struct S { int s; int u; T v; int x[10]; union U w; int y[10]; int z[10]; };
+volatile int z;
+
+template <typename R>
+void
+foo ()
+{
+ R s;
+ s.template s = 0;
+ s.u = 1;
+ s.v.a = 2;
+ s.v.b.y = 3LL;
+ s.v.c = 19;
+ s.w.x = 4;
+ s.template x[0] = 7;
+ s.x[1] = 8;
+ s.y[3] = 9;
+ s.y[4] = 10;
+ s.y[5] = 11;
+ int err = 0;
+ #pragma omp target map (to:s.template v.template b, s.u, s.x[0:z + 2]) \
+ map (tofrom:s.y[3:3]) \
+ map (from: s.w, s.template z[z + 1:z + 3], err)
+ {
+ err = 0;
+ if (s.u != 1 || s.v.b.y != 3LL || s.x[0] != 7 || s.x[1] != 8
+ || s.y[3] != 9 || s.y[4] != 10 || s.y[5] != 11)
+ err = 1;
+ s.w.x = 6;
+ s.y[3] = 12;
+ s.y[4] = 13;
+ s.y[5] = 14;
+ s.z[1] = 15;
+ s.z[2] = 16;
+ s.z[3] = 17;
+ }
+ if (err || s.w.x != 6 || s.y[3] != 12 || s.y[4] != 13 || s.y[5] != 14
+ || s.z[1] != 15 || s.z[2] != 16 || s.z[3] != 17)
+ abort ();
+ s.u++;
+ s.v.a++;
+ s.v.b.y++;
+ s.w.x++;
+ s.x[1] = 18;
+ s.z[0] = 19;
+ #pragma omp target data map (tofrom: s)
+ #pragma omp target map (always to: s.template w, s.x[1], err) map (alloc:s.u, s. template v.template b, s.z[z:z + 1])
+ {
+ err = 0;
+ if (s.u != 2 || s.v.b.y != 4LL || s.w.x != 7 || s.x[1] != 18 || s.z[0] != 19)
+ err = 1;
+ s.w.x = 8;
+ s.x[1] = 20;
+ s.z[0] = 21;
+ }
+ if (err || s.w.x != 8 || s.x[1] != 20 || s.z[0] != 21)
+ abort ();
+ s.u++;
+ s.v.a++;
+ s.v.b.y++;
+ s.w.x++;
+ s.x[0] = 22;
+ s.x[1] = 23;
+ #pragma omp target data map (from: s.w, s.x[0:2]) map (to: s.v.b, s.u)
+ #pragma omp target map (always to: s.w, s.x[0:2], err) map (alloc:s.u, s.v.b)
+ {
+ err = 0;
+ if (s.u != 3 || s.v.b.y != 5LL || s.w.x != 9 || s.x[0] != 22 || s.x[1] != 23)
+ err = 1;
+ s.w.x = 11;
+ s.x[0] = 24;
+ s.x[1] = 25;
+ }
+ if (err || s.w.x != 11 || s.x[0] != 24 || s.x[1] != 25)
+ abort ();
+}
+
+int
+main ()
+{
+ S s;
+ s.s = 0;
+ s.u = 1;
+ s.v.a = 2;
+ s.v.b.y = 3LL;
+ s.v.c = 19;
+ s.w.x = 4;
+ s.x[0] = 7;
+ s.x[1] = 8;
+ s.y[3] = 9;
+ s.y[4] = 10;
+ s.y[5] = 11;
+ int err = 0;
+ #pragma omp target map (to:s.v.b, s.u, s.x[0:z + 2]) \
+ map (tofrom:s.y[3:3]) \
+ map (from: s.w, s.z[z + 1:z + 3], err)
+ {
+ err = 0;
+ if (s.u != 1 || s.v.b.y != 3LL || s.x[0] != 7 || s.x[1] != 8
+ || s.y[3] != 9 || s.y[4] != 10 || s.y[5] != 11)
+ err = 1;
+ s.w.x = 6;
+ s.y[3] = 12;
+ s.y[4] = 13;
+ s.y[5] = 14;
+ s.z[1] = 15;
+ s.z[2] = 16;
+ s.z[3] = 17;
+ }
+ if (err || s.w.x != 6 || s.y[3] != 12 || s.y[4] != 13 || s.y[5] != 14
+ || s.z[1] != 15 || s.z[2] != 16 || s.z[3] != 17)
+ abort ();
+ s.u++;
+ s.v.a++;
+ s.v.b.y++;
+ s.w.x++;
+ s.x[1] = 18;
+ s.z[0] = 19;
+ #pragma omp target data map (tofrom: s)
+ #pragma omp target map (always to: s.w, s.x[1], err) map (alloc:s.u, s.v.b, s.z[z:z + 1])
+ {
+ err = 0;
+ if (s.u != 2 || s.v.b.y != 4LL || s.w.x != 7 || s.x[1] != 18 || s.z[0] != 19)
+ err = 1;
+ s.w.x = 8;
+ s.x[1] = 20;
+ s.z[0] = 21;
+ }
+ if (err || s.w.x != 8 || s.x[1] != 20 || s.z[0] != 21)
+ abort ();
+ s.u++;
+ s.v.a++;
+ s.v.b.y++;
+ s.w.x++;
+ s.x[0] = 22;
+ s.x[1] = 23;
+ #pragma omp target data map (from: s.w, s.x[0:2]) map (to: s.v.b, s.u)
+ #pragma omp target map (always to: s.w, s.x[0:2], err) map (alloc:s.u, s.v.b)
+ {
+ err = 0;
+ if (s.u != 3 || s.v.b.y != 5LL || s.w.x != 9 || s.x[0] != 22 || s.x[1] != 23)
+ err = 1;
+ s.w.x = 11;
+ s.x[0] = 24;
+ s.x[1] = 25;
+ }
+ if (err || s.w.x != 11 || s.x[0] != 24 || s.x[1] != 25)
+ abort ();
+ foo <S> ();
+ return 0;
+}
--- /dev/null
+extern "C" void abort ();
+struct T { int a; int *b; int c; char (&d)[10]; };
+struct S { int *s; char *u; T v; short *w; short *&x; };
+volatile int z;
+
+template <typename A, typename B, typename C, typename D>
+void
+foo ()
+{
+ A d[10];
+ B *e;
+ C a[32], i;
+ A b[32];
+ B c[32];
+ for (i = 0; i < 32; i++)
+ {
+ a[i] = i;
+ b[i] = 32 + i;
+ c[i] = 64 + i;
+ }
+ for (i = 0; i < 10; i++)
+ d[i] = 17 + i;
+ e = c + 18;
+ D s = { a, b + 2, { 0, a + 16, 0, d }, c + 3, e };
+ int err = 0;
+ #pragma omp target map (to:s.v.b[0:z + 7], s.template u[z + 1:z + 4]) \
+ map (tofrom:s.s[3:3], s. template v. template d[z + 1:z + 3]) \
+ map (from: s.w[z:4], s.x[1:3], err) private (i)
+ {
+ err = 0;
+ for (i = 0; i < 7; i++)
+ if (s.v.b[i] != 16 + i)
+ err = 1;
+ for (i = 1; i < 5; i++)
+ if (s.u[i] != 34 + i)
+ err = 1;
+ for (i = 3; i < 6; i++)
+ if (s.s[i] != i)
+ err = 1;
+ else
+ s.s[i] = 128 + i;
+ for (i = 1; i < 4; i++)
+ if (s.v.d[i] != 17 + i)
+ err = 1;
+ else
+ s.v.d[i] = 23 + i;
+ for (i = 0; i < 4; i++)
+ s.w[i] = 96 + i;
+ for (i = 1; i < 4; i++)
+ s.x[i] = 173 + i;
+ }
+ if (err)
+ abort ();
+ for (i = 0; i < 32; i++)
+ if (a[i] != ((i >= 3 && i < 6) ? 128 + i : i)
+ || b[i] != 32 + i
+ || c[i] != ((i >= 3 && i < 7) ? 93 + i : ((i >= 19 && i < 22) ? 155 + i : 64 + i)))
+ abort ();
+ for (i = 0; i < 10; i++)
+ if (d[i] != ((i >= 1 && i < 4) ? 23 + i : 17 + i))
+ abort ();
+}
+
+int
+main ()
+{
+ char d[10];
+ short *e;
+ int a[32], i;
+ char b[32];
+ short c[32];
+ for (i = 0; i < 32; i++)
+ {
+ a[i] = i;
+ b[i] = 32 + i;
+ c[i] = 64 + i;
+ }
+ for (i = 0; i < 10; i++)
+ d[i] = 17 + i;
+ e = c + 18;
+ S s = { a, b + 2, { 0, a + 16, 0, d }, c + 3, e };
+ int err = 0;
+ #pragma omp target map (to:s.v.b[0:z + 7], s.u[z + 1:z + 4]) \
+ map (tofrom:s.s[3:3], s.v.d[z + 1:z + 3]) \
+ map (from: s.w[z:4], s.x[1:3], err) private (i)
+ {
+ err = 0;
+ for (i = 0; i < 7; i++)
+ if (s.v.b[i] != 16 + i)
+ err = 1;
+ for (i = 1; i < 5; i++)
+ if (s.u[i] != 34 + i)
+ err = 1;
+ for (i = 3; i < 6; i++)
+ if (s.s[i] != i)
+ err = 1;
+ else
+ s.s[i] = 128 + i;
+ for (i = 1; i < 4; i++)
+ if (s.v.d[i] != 17 + i)
+ err = 1;
+ else
+ s.v.d[i] = 23 + i;
+ for (i = 0; i < 4; i++)
+ s.w[i] = 96 + i;
+ for (i = 1; i < 4; i++)
+ s.x[i] = 173 + i;
+ }
+ if (err)
+ abort ();
+ for (i = 0; i < 32; i++)
+ if (a[i] != ((i >= 3 && i < 6) ? 128 + i : i)
+ || b[i] != 32 + i
+ || c[i] != ((i >= 3 && i < 7) ? 93 + i : ((i >= 19 && i < 22) ? 155 + i : 64 + i)))
+ abort ();
+ for (i = 0; i < 10; i++)
+ if (d[i] != ((i >= 1 && i < 4) ? 23 + i : 17 + i))
+ abort ();
+ foo <char, short, int, S> ();
+ return 0;
+}
--- /dev/null
+extern "C" void abort (void);
+struct S { int s; int *u; int v[5]; };
+volatile int z;
+
+template <typename T>
+void
+foo ()
+{
+ int u[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, err = 0;
+ T s = { 9, u + 3, { 10, 11, 12, 13, 14 } };
+ int *v = u + 4;
+ #pragma omp target enter data map (to: s.s, s.template u[0:5]) map (alloc: s.template v[1:3])
+ s.s++;
+ u[3]++;
+ s.v[1]++;
+ #pragma omp target update to (s.template s) to (s.u[0:2], s.v[1:3])
+ #pragma omp target map (alloc: s.s, s.v[1:3]) map (from: err)
+ {
+ err = 0;
+ if (s.s != 10 || s.v[1] != 12 || s.v[2] != 12 || s.v[3] != 13)
+ err = 1;
+ if (v[-1] != 4 || v[0] != 4 || v[1] != 5 || v[2] != 6 || v[3] != 7)
+ err = 1;
+ s.s++;
+ s.v[2] += 2;
+ v[-1] = 5;
+ v[3] = 9;
+ }
+ if (err)
+ abort ();
+ #pragma omp target map (alloc: s.u[0:5])
+ {
+ err = 0;
+ if (s.u[0] != 5 || s.u[1] != 4 || s.u[2] != 5 || s.u[3] != 6 || s.u[4] != 9)
+ err = 1;
+ s.u[1] = 12;
+ }
+ #pragma omp target update from (s.s, s.u[0:5]) from (s.v[1:3])
+ if (err || s.s != 11 || u[0] != 0 || u[1] != 1 || u[2] != 2 || u[3] != 5
+ || u[4] != 12 || u[5] != 5 || u[6] != 6 || u[7] != 9 || u[8] != 8
+ || u[9] != 9 || s.v[0] != 10 || s.v[1] != 12 || s.v[2] != 14
+ || s.v[3] != 13 || s.v[4] != 14)
+ abort ();
+ #pragma omp target exit data map (release: s.s)
+ #pragma omp target exit data map (release: s.u[0:5])
+ #pragma omp target exit data map (delete: s.v[1:3])
+ #pragma omp target exit data map (release: s.s)
+}
+
+int
+main ()
+{
+ int u[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, err = 0;
+ S s = { 9, u + 3, { 10, 11, 12, 13, 14 } };
+ int *v = u + 4;
+ #pragma omp target enter data map (to: s.s, s.u[0:5]) map (alloc: s.v[1:3])
+ s.s++;
+ u[3]++;
+ s.v[1]++;
+ #pragma omp target update to (s.s) to (s.u[0:2], s.v[1:3])
+ #pragma omp target map (alloc: s.s, s.v[1:3]) map (from: err)
+ {
+ err = 0;
+ if (s.s != 10 || s.v[1] != 12 || s.v[2] != 12 || s.v[3] != 13)
+ err = 1;
+ if (v[-1] != 4 || v[0] != 4 || v[1] != 5 || v[2] != 6 || v[3] != 7)
+ err = 1;
+ s.s++;
+ s.v[2] += 2;
+ v[-1] = 5;
+ v[3] = 9;
+ }
+ if (err)
+ abort ();
+ #pragma omp target map (alloc: s.u[0:5])
+ {
+ err = 0;
+ if (s.u[0] != 5 || s.u[1] != 4 || s.u[2] != 5 || s.u[3] != 6 || s.u[4] != 9)
+ err = 1;
+ s.u[1] = 12;
+ }
+ #pragma omp target update from (s.s, s.u[0:5]) from (s.v[1:3])
+ if (err || s.s != 11 || u[0] != 0 || u[1] != 1 || u[2] != 2 || u[3] != 5
+ || u[4] != 12 || u[5] != 5 || u[6] != 6 || u[7] != 9 || u[8] != 8
+ || u[9] != 9 || s.v[0] != 10 || s.v[1] != 12 || s.v[2] != 14
+ || s.v[3] != 13 || s.v[4] != 14)
+ abort ();
+ #pragma omp target exit data map (release: s.s)
+ #pragma omp target exit data map (release: s.u[0:5])
+ #pragma omp target exit data map (always, delete: s.v[1:3])
+ #pragma omp target exit data map (release: s.s)
+ #pragma omp target exit data map (always delete : s.v[1:3])
+}
int j;
fn1 (hr + 2 * x, ir + 2 * x, x);
#pragma omp target map(to: br[:x], cr[0:x], dr[x:x], er[x:x]) \
- map(to: fr[0:x], gr[0:x], hr[2 * x:x], ir[2 * x:x])
+ map(to: fr[0:x], gr[0:x], hr[2 * x:x], ir[2 * x:x]) \
+ map(tofrom: s)
#pragma omp parallel for reduction(+:s)
for (j = 0; j < x; j++)
s += br[j] * cr[j] + dr[x + j] + er[x + j]
--- /dev/null
+#include "../libgomp.c/target-13.c"
--- /dev/null
+extern "C" void abort (void);
+struct S { int s, t; };
+
+void
+foo (int &x, int &y, S &u, S &v, double &s, double &t)
+{
+ int err = 0, i;
+ int a[y - 2], b[y - 2];
+ int (&c)[y - 2] = a, (&d)[y - 2] = b;
+ for (i = 0; i < y - 2; i++)
+ {
+ c[i] = i;
+ d[i] = 3 + i;
+ }
+ #pragma omp target private (x, u, s, c, i) firstprivate (y, v, t, d) map(from:err)
+ {
+ x = y;
+ u = v;
+ s = t;
+ for (i = 0; i < y - 2; i++)
+ c[i] = d[i];
+ err = (x != 6 || y != 6
+ || u.s != 9 || u.t != 10 || v.s != 9 || v.t != 10
+ || s != 12.5 || t != 12.5);
+ for (i = 0; i < y - 2; i++)
+ if (d[i] != 3 + i || c[i] != 3 + i)
+ err = 1;
+ else
+ {
+ c[i] += 2 * i;
+ d[i] += i;
+ }
+ x += 1;
+ y += 2;
+ u.s += 3;
+ v.t += 4;
+ s += 2.5;
+ t += 3.0;
+ if (x != 7 || y != 8
+ || u.s != 12 || u.t != 10 || v.s != 9 || v.t != 14
+ || s != 15.0 || t != 15.5)
+ err = 1;
+ for (i = 0; i < y - 4; i++)
+ if (d[i] != 3 + 2 * i || c[i] != 3 + 3 * i)
+ err = 1;
+ }
+ if (err || x != 5 || y != 6
+ || u.s != 7 || u.t != 8 || v.s != 9 || v.t != 10
+ || s != 11.5 || t != 12.5)
+ abort ();
+ for (i = 0; i < y - 2; i++)
+ if (d[i] != 3 + i || c[i] != i)
+ abort ();
+}
+
+int
+main ()
+{
+ int x = 5, y = 6;
+ S u = { 7, 8 }, v = { 9, 10 };
+ double s = 11.5, t = 12.5;
+ foo (x, y, u, v, s, t);
+ return 0;
+}
--- /dev/null
+extern "C" void abort ();
+
+void
+foo (int *x, int *&y, int (&z)[15])
+{
+ int a[10], b[15], err, i;
+ for (i = 0; i < 10; i++)
+ a[i] = 7 * i;
+ for (i = 0; i < 15; i++)
+ b[i] = 8 * i;
+ #pragma omp target map(to:x[5:10], y[5:10], z[5:10], a[0:10], b[5:10]) map(from:err)
+ {
+ err = 0;
+ for (i = 0; i < 10; i++)
+ if (x[5 + i] != 20 + 4 * i
+ || y[5 + i] != 25 + 5 * i
+ || z[5 + i] != 30 + 6 * i
+ || a[i] != 7 * i
+ || b[5 + i] != 40 + 8 * i)
+ err = 1;
+ }
+ if (err)
+ abort ();
+}
+
+void
+bar (int n, int v)
+{
+ int a[n], b[n], c[n], d[n], e[n], err, i;
+ int (*x)[n] = &c;
+ int (*y2)[n] = &d;
+ int (*&y)[n] = y2;
+ int (&z)[n] = e;
+ for (i = 0; i < n; i++)
+ {
+ (*x)[i] = 4 * i;
+ (*y)[i] = 5 * i;
+ z[i] = 6 * i;
+ a[i] = 7 * i;
+ b[i] = 8 * i;
+ }
+ #pragma omp target map(to:x[0][5:10], y[0][5:10], z[5:10], a[0:10], b[5:10]) map(from:err)
+ {
+ err = 0;
+ for (i = 0; i < 10; i++)
+ if ((*x)[5 + i] != 20 + 4 * i
+ || (*y)[5 + i] != 25 + 5 * i
+ || z[5 + i] != 30 + 6 * i
+ || a[i] != 7 * i
+ || b[5 + i] != 40 + 8 * i)
+ err = 1;
+ }
+ if (err)
+ abort ();
+ for (i = 0; i < n; i++)
+ {
+ (*x)[i] = 9 * i;
+ (*y)[i] = 10 * i;
+ z[i] = 11 * i;
+ a[i] = 12 * i;
+ b[i] = 13 * i;
+ }
+ #pragma omp target map(to:x[0][v:v+5], y[0][v:v+5], z[v:v+5], a[v-5:v+5], b[v:v+5]) map(from:err)
+ {
+ err = 0;
+ for (i = 0; i < 10; i++)
+ if ((*x)[5 + i] != 45 + 9 * i
+ || (*y)[5 + i] != 50 + 10 * i
+ || z[5 + i] != 55 + 11 * i
+ || a[i] != 12 * i
+ || b[5 + i] != 65 + 13 * i)
+ err = 1;
+ }
+ if (err)
+ abort ();
+}
+
+int
+main ()
+{
+ int x[15], y2[15], z[15], *y = y2, i;
+ for (i = 0; i < 15; i++)
+ {
+ x[i] = 4 * i;
+ y[i] = 5 * i;
+ z[i] = 6 * i;
+ }
+ foo (x, y, z);
+ bar (15, 5);
+}
--- /dev/null
+extern "C" void abort ();
+struct S { int a; };
+#ifdef __SIZEOF_INT128__
+typedef __int128 T;
+#else
+typedef long long int T;
+#endif
+
+void
+foo (T a, int b, struct S c)
+{
+ int err;
+ #pragma omp target firstprivate (a, b, c) map(from:err)
+ {
+ err = 0;
+ if (a != 131 || b != 276 || c.a != 59)
+ err = 1;
+ a = 936;
+ b = 27;
+ c.a = 98;
+ if (a != 936 || b != 27 || c.a != 98)
+ err = 1;
+ }
+ if (err || a != 131 || b != 276 || c.a != 59)
+ abort ();
+}
+
+void
+bar (T &a, int &b, struct S &c)
+{
+ int err;
+ #pragma omp target firstprivate (a, b, c) map(from:err)
+ {
+ err = 0;
+ if (a != 131 || b != 276 || c.a != 59)
+ err = 1;
+ a = 936;
+ b = 27;
+ c.a = 98;
+ if (a != 936 || b != 27 || c.a != 98)
+ err = 1;
+ }
+ if (err || a != 131 || b != 276 || c.a != 59)
+ abort ();
+}
+
+int
+main ()
+{
+ T a = 131;
+ int b = 276;
+ struct S c;
+ c.a = 59;
+ foo (a, b, c);
+ bar (a, b, c);
+ if (a != 131 || b != 276 || c.a != 59)
+ abort ();
+}
--- /dev/null
+extern "C" void abort (void);
+
+void
+foo (int *&p, int (&s)[5], int n)
+{
+ int a[4] = { 7, 8, 9, 10 }, b[n], c[3] = { 20, 21, 22 };
+ int *r = a + 1, *q = p - 1, i, err;
+ for (i = 0; i < n; i++)
+ b[i] = 9 + i;
+ #pragma omp target data map(to:a)
+ #pragma omp target data use_device_ptr(r) map(from:err)
+ #pragma omp target is_device_ptr(r) private(i) map(from:err)
+ {
+ err = 0;
+ for (i = 0; i < 4; i++)
+ if (r[i - 1] != 7 + i)
+ err = 1;
+ }
+ if (err)
+ abort ();
+ #pragma omp target data map(to:q[:4])
+ #pragma omp target data use_device_ptr(p) map(from:err)
+ #pragma omp target is_device_ptr(p) private(i) map(from:err)
+ {
+ err = 0;
+ for (i = 0; i < 4; i++)
+ if (p[i - 1] != i)
+ err = 1;
+ }
+ if (err)
+ abort ();
+ #pragma omp target data map(to:b)
+ #pragma omp target data use_device_ptr(b) map(from:err)
+ #pragma omp target is_device_ptr(b) private(i) map(from:err)
+ {
+ err = 0;
+ for (i = 0; i < n; i++)
+ if (b[i] != 9 + i)
+ err = 1;
+ }
+ if (err)
+ abort ();
+ #pragma omp target data map(to:c)
+ #pragma omp target data use_device_ptr(c) map(from:err)
+ #pragma omp target is_device_ptr(c) private(i) map(from:err)
+ {
+ err = 0;
+ for (i = 0; i < 3; i++)
+ if (c[i] != 20 + i)
+ err = 1;
+ }
+ if (err)
+ abort ();
+ #pragma omp target data map(to:s[:5])
+ #pragma omp target data use_device_ptr(s) map(from:err)
+ #pragma omp target is_device_ptr(s) private(i) map(from:err)
+ {
+ err = 0;
+ for (i = 0; i < 5; i++)
+ if (s[i] != 17 + i)
+ err = 1;
+ }
+ if (err)
+ abort ();
+}
+
+int
+main ()
+{
+ int a[4] = { 0, 1, 2, 3 }, b[5] = { 17, 18, 19, 20, 21 };
+ int *p = a + 1;
+ foo (p, b, 9);
+}
--- /dev/null
+// { dg-do run }
+// { dg-options "-O2 -fopenmp" }
+
+#include "../libgomp.c/taskloop-1.c"
--- /dev/null
+// { dg-do run }
+// { dg-options "-O2" }
+// { dg-additional-options "-msse2" { target sse2_runtime } }
+// { dg-additional-options "-mavx" { target avx_runtime } }
+
+#include "../libgomp.c/taskloop-2.c"
--- /dev/null
+// { dg-do run }
+// { dg-options "-O2 -fopenmp" }
+
+#include "../libgomp.c/taskloop-3.c"
--- /dev/null
+// { dg-do run }
+// { dg-options "-O2 -fopenmp" }
+
+#include "../libgomp.c/taskloop-4.c"
--- /dev/null
+#include <omp.h>
+
+__attribute__((noinline, noclone)) void
+foo (int &b)
+{
+#pragma omp parallel
+#pragma omp single
+ {
+ bool f = false;
+ #pragma omp taskloop firstprivate (b, f)
+ for (int i = 0; i < 30; i++)
+ {
+ int q = omp_get_thread_num ();
+ if (!f)
+ {
+ if (b != 2)
+ __builtin_abort ();
+ }
+ else if (b != 8 * q)
+ __builtin_abort ();
+ b = 8 * q;
+ f = true;
+ }
+ }
+ int n;
+#pragma omp parallel
+#pragma omp single
+ {
+ bool f = false;
+ #pragma omp taskloop firstprivate (f) lastprivate (b, n)
+ for (int i = 0; i < 30; i++)
+ {
+ int q = omp_get_thread_num ();
+ if (f && b != 8 * q)
+ __builtin_abort ();
+ b = 8 * q;
+ n = q;
+ f = true;
+ }
+ }
+ if (b != 8 * n)
+ __builtin_abort ();
+ b = 9;
+#pragma omp parallel
+#pragma omp single
+ {
+ bool f = false;
+ #pragma omp taskloop firstprivate (b, f) lastprivate (b, n)
+ for (int i = 0; i < 30; i++)
+ {
+ int q = omp_get_thread_num ();
+ if (!f)
+ {
+ if (b != 9)
+ __builtin_abort ();
+ }
+ else if (b != 11 * q)
+ __builtin_abort ();
+ b = 11 * q;
+ n = q;
+ f = true;
+ }
+ }
+ if (b != 11 * n)
+ __builtin_abort ();
+}
+
+int
+main ()
+{
+ int b = 2;
+ foo (b);
+}
--- /dev/null
+// { dg-do run }
+
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+extern "C" void abort ();
+
+template <typename T>
+class I
+{
+public:
+ typedef ptrdiff_t difference_type;
+ I ();
+ ~I ();
+ I (T *);
+ I (const I &);
+ T &operator * ();
+ T *operator -> ();
+ T &operator [] (const difference_type &) const;
+ I &operator = (const I &);
+ I &operator ++ ();
+ I operator ++ (int);
+ I &operator -- ();
+ I operator -- (int);
+ I &operator += (const difference_type &);
+ I &operator -= (const difference_type &);
+ I operator + (const difference_type &) const;
+ I operator - (const difference_type &) const;
+ template <typename S> friend bool operator == (I<S> &, I<S> &);
+ template <typename S> friend bool operator == (const I<S> &, const I<S> &);
+ template <typename S> friend bool operator < (I<S> &, I<S> &);
+ template <typename S> friend bool operator < (const I<S> &, const I<S> &);
+ template <typename S> friend bool operator <= (I<S> &, I<S> &);
+ template <typename S> friend bool operator <= (const I<S> &, const I<S> &);
+ template <typename S> friend bool operator > (I<S> &, I<S> &);
+ template <typename S> friend bool operator > (const I<S> &, const I<S> &);
+ template <typename S> friend bool operator >= (I<S> &, I<S> &);
+ template <typename S> friend bool operator >= (const I<S> &, const I<S> &);
+ template <typename S> friend typename I<S>::difference_type operator - (I<S> &, I<S> &);
+ template <typename S> friend typename I<S>::difference_type operator - (const I<S> &, const I<S> &);
+ template <typename S> friend I<S> operator + (typename I<S>::difference_type , const I<S> &);
+private:
+ T *p;
+};
+template <typename T> I<T>::I () : p (0) {}
+template <typename T> I<T>::~I () {}
+template <typename T> I<T>::I (T *x) : p (x) {}
+template <typename T> I<T>::I (const I &x) : p (x.p) {}
+template <typename T> T &I<T>::operator * () { return *p; }
+template <typename T> T *I<T>::operator -> () { return p; }
+template <typename T> T &I<T>::operator [] (const difference_type &x) const { return p[x]; }
+template <typename T> I<T> &I<T>::operator = (const I &x) { p = x.p; return *this; }
+template <typename T> I<T> &I<T>::operator ++ () { ++p; return *this; }
+template <typename T> I<T> I<T>::operator ++ (int) { return I (p++); }
+template <typename T> I<T> &I<T>::operator -- () { --p; return *this; }
+template <typename T> I<T> I<T>::operator -- (int) { return I (p--); }
+template <typename T> I<T> &I<T>::operator += (const difference_type &x) { p += x; return *this; }
+template <typename T> I<T> &I<T>::operator -= (const difference_type &x) { p -= x; return *this; }
+template <typename T> I<T> I<T>::operator + (const difference_type &x) const { return I (p + x); }
+template <typename T> I<T> I<T>::operator - (const difference_type &x) const { return I (p - x); }
+template <typename T> bool operator == (I<T> &x, I<T> &y) { return x.p == y.p; }
+template <typename T> bool operator == (const I<T> &x, const I<T> &y) { return x.p == y.p; }
+template <typename T> bool operator != (I<T> &x, I<T> &y) { return !(x == y); }
+template <typename T> bool operator != (const I<T> &x, const I<T> &y) { return !(x == y); }
+template <typename T> bool operator < (I<T> &x, I<T> &y) { return x.p < y.p; }
+template <typename T> bool operator < (const I<T> &x, const I<T> &y) { return x.p < y.p; }
+template <typename T> bool operator <= (I<T> &x, I<T> &y) { return x.p <= y.p; }
+template <typename T> bool operator <= (const I<T> &x, const I<T> &y) { return x.p <= y.p; }
+template <typename T> bool operator > (I<T> &x, I<T> &y) { return x.p > y.p; }
+template <typename T> bool operator > (const I<T> &x, const I<T> &y) { return x.p > y.p; }
+template <typename T> bool operator >= (I<T> &x, I<T> &y) { return x.p >= y.p; }
+template <typename T> bool operator >= (const I<T> &x, const I<T> &y) { return x.p >= y.p; }
+template <typename T> typename I<T>::difference_type operator - (I<T> &x, I<T> &y) { return x.p - y.p; }
+template <typename T> typename I<T>::difference_type operator - (const I<T> &x, const I<T> &y) { return x.p - y.p; }
+template <typename T> I<T> operator + (typename I<T>::difference_type x, const I<T> &y) { return I<T> (x + y.p); }
+
+template <typename T>
+class J
+{
+public:
+ J(const I<T> &x, const I<T> &y) : b (x), e (y) {}
+ const I<T> &begin ();
+ const I<T> &end ();
+private:
+ I<T> b, e;
+};
+
+template <typename T> const I<T> &J<T>::begin () { return b; }
+template <typename T> const I<T> &J<T>::end () { return e; }
+
+int results[2000];
+
+template <typename T>
+void
+baz (I<T> &i)
+{
+ if (*i < 0 || *i >= 2000)
+ abort ();
+ results[*i]++;
+}
+
+void
+f1 (const I<int> &x, const I<int> &y)
+{
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop num_tasks(22)
+ for (I<int> i = x; i <= y; i += 6)
+ baz (i);
+}
+
+void
+f2 (const I<int> &x, const I<int> &y)
+{
+ I<int> i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop grainsize(384) private(i)
+ for (i = x; i < y - 1; i = 1 - 6 + 7 + i)
+ baz (i);
+}
+
+template <typename T>
+void
+f3 (const I<int> &x, const I<int> &y)
+{
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop default(none) firstprivate (x, y)
+ for (I<int> i = x; i <= y; i = i + 9 - 8)
+ baz (i);
+}
+
+template <typename T>
+void
+f4 (const I<int> &x, const I<int> &y)
+{
+ I<int> i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop lastprivate(i)
+ for (i = x + 2000 - 64; i > y + 10; --i)
+ baz (i);
+}
+
+void
+f5 (const I<int> &x, const I<int> &y)
+{
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop
+ for (I<int> i = x + 2000 - 64; i > y + 10; i -= 10)
+ baz (i);
+}
+
+template <int N>
+void
+f6 (const I<int> &x, const I<int> &y)
+{
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop
+ for (I<int> i = x + 2000 - 64; i > y + 10; i = i - 12 + 2)
+ {
+ I<int> j = i + N;
+ baz (j);
+ }
+}
+
+template <int N>
+void
+f7 (I<int> i, const I<int> &x, const I<int> &y)
+{
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop default(none) firstprivate (x, y)
+ for (i = x - 10; i <= y + 10; i += N)
+ baz (i);
+}
+
+template <int N>
+void
+f8 (J<int> j)
+{
+ I<int> i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop default(none) num_tasks(*I<int> (j.begin ())) firstprivate (j)
+ for (i = j.begin (); i <= j.end () + N; i += 2)
+ baz (i);
+}
+
+template <typename T, int N>
+void
+f9 (const I<T> &x, const I<T> &y)
+{
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop grainsize(163)
+ for (I<T> i = x; i <= y; i = i + N)
+ baz (i);
+}
+
+template <typename T, int N>
+void
+f10 (const I<T> &x, const I<T> &y)
+{
+ I<T> i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop
+ for (i = x; i > y; i = i + N)
+ baz (i);
+}
+
+template <typename T>
+void
+f11 (const T &x, const T &y)
+{
+#pragma omp parallel
+ {
+#pragma omp single nowait
+#pragma omp taskloop nogroup
+ for (T i = x; i <= y; i += 3)
+ baz (i);
+#pragma omp single nowait
+ {
+ T j = y + 3;
+ baz (j);
+ }
+ }
+}
+
+template <typename T>
+void
+f12 (const T &x, const T &y)
+{
+ T i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop
+ for (i = x; i > y; --i)
+ baz (i);
+}
+
+template <int N>
+struct K
+{
+ template <typename T>
+ static void
+ f13 (const T &x, const T &y)
+ {
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop
+ for (T i = x; i <= y + N; i += N)
+ baz (i);
+ }
+};
+
+I<int>
+f14 (const I<int> &x, const I<int> &y)
+{
+ I<int> i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop lastprivate(i)
+ for (i = x; i < y - 1; i = 1 - 6 + 7 + i)
+ baz (i);
+ return i;
+}
+
+template <typename T>
+I<int>
+f15 (const I<int> &x, const I<int> &y)
+{
+ I<int> i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop lastprivate(i)
+ for (i = x + 2000 - 64; i > y + 10; --i)
+ baz (i);
+ return i;
+}
+
+template <int N>
+I<int>
+f16 (I<int> i, const I<int> &x, const I<int> &y)
+{
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop lastprivate(i)
+ for (i = x - 10; i <= y + 10; i += N)
+ baz (i);
+ return i;
+}
+
+template <int N>
+I<int>
+f17 (J<int> j)
+{
+ static I<int> i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop lastprivate(i)
+ for (i = j.begin (); i <= j.end () + N; i += 2)
+ baz (i);
+ return i;
+}
+
+template <typename T, int N>
+I<T>
+f18 (const I<T> &x, const I<T> &y)
+{
+ static I<T> i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop lastprivate(i)
+ for (i = x; i > y; i = i + N)
+ baz (i);
+ return i;
+}
+
+template <typename T>
+T
+f19 (const T &x, const T &y)
+{
+ T i;
+#pragma omp parallel
+ {
+#pragma omp single nowait
+#pragma omp taskloop nogroup lastprivate(i)
+ for (i = x; i <= y; i += 3)
+ baz (i);
+#pragma omp single nowait
+ {
+ T j = y + 3;
+ baz (j);
+ }
+ }
+ return i;
+}
+
+template <typename T>
+T
+f20 (const T &x, const T &y)
+{
+ T i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop lastprivate(i)
+ for (i = x; i > y; --i)
+ baz (i);
+ return i;
+}
+
+#define check(expr) \
+ for (int i = 0; i < 2000; i++) \
+ if (expr) \
+ { \
+ if (results[i] != 1) \
+ abort (); \
+ results[i] = 0; \
+ } \
+ else if (results[i]) \
+ abort ()
+
+int
+main ()
+{
+ int a[2000];
+ long b[2000];
+ for (int i = 0; i < 2000; i++)
+ {
+ a[i] = i;
+ b[i] = i;
+ }
+ f1 (&a[10], &a[1990]);
+ check (i >= 10 && i <= 1990 && (i - 10) % 6 == 0);
+ f2 (&a[0], &a[1999]);
+ check (i < 1998 && (i & 1) == 0);
+ f3<char> (&a[20], &a[1837]);
+ check (i >= 20 && i <= 1837);
+ f4<int> (&a[0], &a[30]);
+ check (i > 40 && i <= 2000 - 64);
+ f5 (&a[0], &a[100]);
+ check (i >= 116 && i <= 2000 - 64 && (i - 116) % 10 == 0);
+ f6<-10> (&a[10], &a[110]);
+ check (i >= 116 && i <= 2000 - 64 && (i - 116) % 10 == 0);
+ f7<6> (I<int> (), &a[12], &a[1800]);
+ check (i >= 2 && i <= 1808 && (i - 2) % 6 == 0);
+ f8<121> (J<int> (&a[14], &a[1803]));
+ check (i >= 14 && i <= 1924 && (i & 1) == 0);
+ f9<int, 7> (&a[33], &a[1967]);
+ check (i >= 33 && i <= 1967 && (i - 33) % 7 == 0);
+ f10<int, -7> (&a[1939], &a[17]);
+ check (i >= 21 && i <= 1939 && (i - 21) % 7 == 0);
+ f11<I<int> > (&a[16], &a[1981]);
+ check (i >= 16 && i <= 1984 && (i - 16) % 3 == 0);
+ f12<I<int> > (&a[1761], &a[37]);
+ check (i > 37 && i <= 1761);
+ K<5>::f13<I<int> > (&a[1], &a[1935]);
+ check (i >= 1 && i <= 1936 && (i - 1) % 5 == 0);
+ if (f14 (&a[0], &a[1999]) != I<int>(&a[1998]))
+ abort ();
+ check (i < 1998 && (i & 1) == 0);
+ if (f15<int> (&a[0], &a[30]) != I<int>(&a[40]))
+ abort ();
+ check (i > 40 && i <= 2000 - 64);
+ if (f16<6> (I<int> (), &a[12], &a[1800]) != I<int>(&a[1814]))
+ abort ();
+ check (i >= 2 && i <= 1808 && (i - 2) % 6 == 0);
+ if (f17<121> (J<int> (&a[14], &a[1803])) != I<int>(&a[1926]))
+ abort ();
+ check (i >= 14 && i <= 1924 && (i & 1) == 0);
+ if (f18<int, -7> (&a[1939], &a[17]) != I<int>(&a[14]))
+ abort ();
+ check (i >= 21 && i <= 1939 && (i - 21) % 7 == 0);
+ if (f19<I<int> > (&a[16], &a[1981]) != I<int>(&a[1984]))
+ abort ();
+ check (i >= 16 && i <= 1984 && (i - 16) % 3 == 0);
+ if (f20<I<int> > (&a[1761], &a[37]) != I<int>(&a[37]))
+ abort ();
+ check (i > 37 && i <= 1761);
+ f9<long, 7> (&b[33], &b[1967]);
+ check (i >= 33 && i <= 1967 && (i - 33) % 7 == 0);
+ f10<long, -7> (&b[1939], &b[17]);
+ check (i >= 21 && i <= 1939 && (i - 21) % 7 == 0);
+ f11<I<long> > (&b[16], &b[1981]);
+ check (i >= 16 && i <= 1984 && (i - 16) % 3 == 0);
+ f12<I<long> > (&b[1761], &b[37]);
+ check (i > 37 && i <= 1761);
+ K<5>::f13<I<long> > (&b[1], &b[1935]);
+ check (i >= 1 && i <= 1936 && (i - 1) % 5 == 0);
+ if (f18<long, -7> (&b[1939], &b[17]) != I<long>(&b[14]))
+ abort ();
+ check (i >= 21 && i <= 1939 && (i - 21) % 7 == 0);
+ if (f19<I<long> > (&b[16], &b[1981]) != I<long>(&b[1984]))
+ abort ();
+ check (i >= 16 && i <= 1984 && (i - 16) % 3 == 0);
+ if (f20<I<long> > (&b[1761], &b[37]) != I<long>(&b[37]))
+ abort ();
+ check (i > 37 && i <= 1761);
+}
--- /dev/null
+// { dg-do run }
+
+#include <vector>
+#include <cstdlib>
+
+template <typename T>
+class J
+{
+public:
+ typedef typename std::vector<T>::const_iterator const_iterator;
+ J(const const_iterator &x, const const_iterator &y) : b (x), e (y) {}
+ const const_iterator &begin ();
+ const const_iterator &end ();
+private:
+ const_iterator b, e;
+};
+
+template <typename T>
+const typename std::vector<T>::const_iterator &J<T>::begin () { return b; }
+template <typename T>
+const typename std::vector<T>::const_iterator &J<T>::end () { return e; }
+
+int results[2000];
+
+template <typename T>
+void
+baz (T &i)
+{
+ if (*i < 0 || *i >= 2000)
+ std::abort ();
+ results[*i]++;
+}
+
+void
+f1 (const std::vector<int>::const_iterator &x,
+ const std::vector<int>::const_iterator &y)
+{
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop
+ for (std::vector<int>::const_iterator i = x; i <= y; i += 6)
+ baz (i);
+}
+
+void
+f2 (const std::vector<int>::const_iterator &x,
+ const std::vector<int>::const_iterator &y)
+{
+ std::vector<int>::const_iterator i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop private(i)
+ for (i = x; i < y - 1; i = 1 - 6 + 7 + i)
+ baz (i);
+}
+
+template <typename T>
+void
+f3 (const std::vector<int>::const_iterator &x,
+ const std::vector<int>::const_iterator &y)
+{
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop
+ for (std::vector<int>::const_iterator i = x; i <= y; i = i + 9 - 8)
+ baz (i);
+}
+
+template <typename T>
+void
+f4 (const std::vector<int>::const_iterator &x,
+ const std::vector<int>::const_iterator &y)
+{
+ std::vector<int>::const_iterator i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop lastprivate(i)
+ for (i = x + 2000 - 64; i > y + 10; --i)
+ baz (i);
+}
+
+void
+f5 (const std::vector<int>::const_iterator &x,
+ const std::vector<int>::const_iterator &y)
+{
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop
+ for (std::vector<int>::const_iterator i = x + 2000 - 64; i > y + 10; i -= 10)
+ baz (i);
+}
+
+template <int N>
+void
+f6 (const std::vector<int>::const_iterator &x,
+ const std::vector<int>::const_iterator &y)
+{
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop
+ for (std::vector<int>::const_iterator i = x + 2000 - 64;
+ i > y + 10; i = i - 12 + 2)
+ {
+ std::vector<int>::const_iterator j = i + N;
+ baz (j);
+ }
+}
+
+template <int N>
+void
+f7 (std::vector<int>::const_iterator i,
+ const std::vector<int>::const_iterator &x,
+ const std::vector<int>::const_iterator &y)
+{
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop
+ for (i = x - 10; i <= y + 10; i += N)
+ baz (i);
+}
+
+template <int N>
+void
+f8 (J<int> j)
+{
+ std::vector<int>::const_iterator i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop
+ for (i = j.begin (); i <= j.end () + N; i += 2)
+ baz (i);
+}
+
+template <typename T, int N>
+void
+f9 (const typename std::vector<T>::const_iterator &x,
+ const typename std::vector<T>::const_iterator &y)
+{
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop
+ for (typename std::vector<T>::const_iterator i = x; i <= y; i = i + N)
+ baz (i);
+}
+
+template <typename T, int N>
+void
+f10 (const typename std::vector<T>::const_iterator &x,
+ const typename std::vector<T>::const_iterator &y)
+{
+ typename std::vector<T>::const_iterator i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop
+ for (i = x; i > y; i = i + N)
+ baz (i);
+}
+
+template <typename T>
+void
+f11 (const T &x, const T &y)
+{
+#pragma omp parallel
+ {
+#pragma omp single nowait
+#pragma omp taskloop nogroup
+ for (T i = x; i <= y; i += 3)
+ baz (i);
+#pragma omp single nowait
+ {
+ T j = y + 3;
+ baz (j);
+ }
+ }
+}
+
+template <typename T>
+void
+f12 (const T &x, const T &y)
+{
+ T i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop
+ for (i = x; i > y; --i)
+ baz (i);
+}
+
+template <int N>
+struct K
+{
+ template <typename T>
+ static void
+ f13 (const T &x, const T &y)
+ {
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop
+ for (T i = x; i <= y + N; i += N)
+ baz (i);
+ }
+};
+
+std::vector<int>::const_iterator
+f14 (const std::vector<int>::const_iterator &x,
+ const std::vector<int>::const_iterator &y)
+{
+ std::vector<int>::const_iterator i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop lastprivate(i)
+ for (i = x; i < y - 1; i = 1 - 6 + 7 + i)
+ baz (i);
+ return i;
+}
+
+template <typename T>
+std::vector<int>::const_iterator
+f15 (const std::vector<int>::const_iterator &x,
+ const std::vector<int>::const_iterator &y)
+{
+ std::vector<int>::const_iterator i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop lastprivate(i)
+ for (i = x + 2000 - 64; i > y + 10; --i)
+ baz (i);
+ return i;
+}
+
+template <int N>
+std::vector<int>::const_iterator
+f16 (std::vector<int>::const_iterator i,
+ const std::vector<int>::const_iterator &x,
+ const std::vector<int>::const_iterator &y)
+{
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop lastprivate(i)
+ for (i = x - 10; i <= y + 10; i += N)
+ baz (i);
+ return i;
+}
+
+template <int N>
+std::vector<int>::const_iterator
+f17 (J<int> j)
+{
+ static std::vector<int>::const_iterator i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop lastprivate(i)
+ for (i = j.begin (); i <= j.end () + N; i += 2)
+ baz (i);
+ return i;
+}
+
+template <typename T, int N>
+typename std::vector<T>::const_iterator
+f18 (const typename std::vector<T>::const_iterator &x,
+ const typename std::vector<T>::const_iterator &y)
+{
+ static typename std::vector<T>::const_iterator i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop lastprivate(i)
+ for (i = x; i > y; i = i + N)
+ baz (i);
+ return i;
+}
+
+template <typename T>
+T
+f19 (const T &x, const T &y)
+{
+ T i;
+#pragma omp parallel
+ {
+#pragma omp single nowait
+#pragma omp taskloop nogroup lastprivate(i)
+ for (i = x; i <= y; i += 3)
+ baz (i);
+#pragma omp single nowait
+ {
+ T j = y + 3;
+ baz (j);
+ }
+ }
+ return i;
+}
+
+template <typename T>
+T
+f20 (const T &x, const T &y)
+{
+ T i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop lastprivate(i)
+ for (i = x; i > y; --i)
+ baz (i);
+ return i;
+}
+
+#define check(expr) \
+ for (int i = 0; i < 2000; i++) \
+ if (expr) \
+ { \
+ if (results[i] != 1) \
+ std::abort (); \
+ results[i] = 0; \
+ } \
+ else if (results[i]) \
+ std::abort ()
+
+int
+main ()
+{
+ std::vector<int> a(2000);
+ std::vector<long> b(2000);
+ for (int i = 0; i < 2000; i++)
+ {
+ a[i] = i;
+ b[i] = i;
+ }
+ f1 (a.begin () + 10, a.begin () + 1990);
+ check (i >= 10 && i <= 1990 && (i - 10) % 6 == 0);
+ f2 (a.begin () + 0, a.begin () + 1999);
+ check (i < 1998 && (i & 1) == 0);
+ f3<char> (a.begin () + 20, a.begin () + 1837);
+ check (i >= 20 && i <= 1837);
+ f4<int> (a.begin () + 0, a.begin () + 30);
+ check (i > 40 && i <= 2000 - 64);
+ f5 (a.begin () + 0, a.begin () + 100);
+ check (i >= 116 && i <= 2000 - 64 && (i - 116) % 10 == 0);
+ f6<-10> (a.begin () + 10, a.begin () + 110);
+ check (i >= 116 && i <= 2000 - 64 && (i - 116) % 10 == 0);
+ f7<6> (std::vector<int>::const_iterator (), a.begin () + 12,
+ a.begin () + 1800);
+ check (i >= 2 && i <= 1808 && (i - 2) % 6 == 0);
+ f8<121> (J<int> (a.begin () + 14, a.begin () + 1803));
+ check (i >= 14 && i <= 1924 && (i & 1) == 0);
+ f9<int, 7> (a.begin () + 33, a.begin () + 1967);
+ check (i >= 33 && i <= 1967 && (i - 33) % 7 == 0);
+ f10<int, -7> (a.begin () + 1939, a.begin () + 17);
+ check (i >= 21 && i <= 1939 && (i - 21) % 7 == 0);
+ f11<std::vector<int>::const_iterator > (a.begin () + 16, a.begin () + 1981);
+ check (i >= 16 && i <= 1984 && (i - 16) % 3 == 0);
+ f12<std::vector<int>::const_iterator > (a.begin () + 1761, a.begin () + 37);
+ check (i > 37 && i <= 1761);
+ K<5>::f13<std::vector<int>::const_iterator > (a.begin () + 1,
+ a.begin () + 1935);
+ check (i >= 1 && i <= 1936 && (i - 1) % 5 == 0);
+ if (f14 (a.begin () + 0, a.begin () + 1999) != a.begin () + 1998)
+ std::abort ();
+ check (i < 1998 && (i & 1) == 0);
+ if (f15<int> (a.begin () + 0, a.begin () + 30) != a.begin () + 40)
+ std::abort ();
+ check (i > 40 && i <= 2000 - 64);
+ if (f16<6> (std::vector<int>::const_iterator (), a.begin () + 12,
+ a.begin () + 1800) != a.begin () + 1814)
+ std::abort ();
+ check (i >= 2 && i <= 1808 && (i - 2) % 6 == 0);
+ if (f17<121> (J<int> (a.begin () + 14, a.begin () + 1803)) != a.begin () + 1926)
+ std::abort ();
+ check (i >= 14 && i <= 1924 && (i & 1) == 0);
+ if (f18<int, -7> (a.begin () + 1939, a.begin () + 17) != a.begin () + 14)
+ std::abort ();
+ check (i >= 21 && i <= 1939 && (i - 21) % 7 == 0);
+ if (f19<std::vector<int>::const_iterator > (a.begin () + 16, a.begin () + 1981)
+ != a.begin () + 1984)
+ std::abort ();
+ check (i >= 16 && i <= 1984 && (i - 16) % 3 == 0);
+ if (f20<std::vector<int>::const_iterator > (a.begin () + 1761, a.begin () + 37)
+ != a.begin () + 37)
+ std::abort ();
+ check (i > 37 && i <= 1761);
+ f9<long, 7> (b.begin () + 33, b.begin () + 1967);
+ check (i >= 33 && i <= 1967 && (i - 33) % 7 == 0);
+ f10<long, -7> (b.begin () + 1939, b.begin () + 17);
+ check (i >= 21 && i <= 1939 && (i - 21) % 7 == 0);
+ f11<std::vector<long>::const_iterator > (b.begin () + 16, b.begin () + 1981);
+ check (i >= 16 && i <= 1984 && (i - 16) % 3 == 0);
+ f12<std::vector<long>::const_iterator > (b.begin () + 1761, b.begin () + 37);
+ check (i > 37 && i <= 1761);
+ K<5>::f13<std::vector<long>::const_iterator > (b.begin () + 1,
+ b.begin () + 1935);
+ check (i >= 1 && i <= 1936 && (i - 1) % 5 == 0);
+ if (f18<long, -7> (b.begin () + 1939, b.begin () + 17) != b.begin () + 14)
+ std::abort ();
+ check (i >= 21 && i <= 1939 && (i - 21) % 7 == 0);
+ if (f19<std::vector<long>::const_iterator > (b.begin () + 16, b.begin () + 1981)
+ != b.begin () + 1984)
+ std::abort ();
+ check (i >= 16 && i <= 1984 && (i - 16) % 3 == 0);
+ if (f20<std::vector<long>::const_iterator > (b.begin () + 1761, b.begin () + 37)
+ != b.begin () + 37)
+ std::abort ();
+ check (i > 37 && i <= 1761);
+}
--- /dev/null
+// { dg-do run }
+
+#include <string>
+#include <cstdlib>
+
+template <typename T>
+class J
+{
+public:
+ typedef typename std::basic_string<T>::iterator iterator;
+ J(const iterator &x, const iterator &y) : b (x), e (y) {}
+ const iterator &begin ();
+ const iterator &end ();
+private:
+ iterator b, e;
+};
+
+template <typename T>
+const typename std::basic_string<T>::iterator &J<T>::begin () { return b; }
+template <typename T>
+const typename std::basic_string<T>::iterator &J<T>::end () { return e; }
+
+template <typename T>
+void
+baz (T &i)
+{
+ if (*i < L'a' || *i >= L'a' + 2000)
+ std::abort ();
+ (*i)++;
+}
+
+void
+f1 (const std::basic_string<wchar_t>::iterator &x,
+ const std::basic_string<wchar_t>::iterator &y)
+{
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop
+ for (std::basic_string<wchar_t>::iterator i = x; i <= y; i += 6)
+ baz (i);
+}
+
+void
+f2 (const std::basic_string<wchar_t>::iterator &x,
+ const std::basic_string<wchar_t>::iterator &y)
+{
+ std::basic_string<wchar_t>::iterator i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop private(i)
+ for (i = x; i < y - 1; i = 1 - 6 + 7 + i)
+ baz (i);
+}
+
+template <typename T>
+void
+f3 (const std::basic_string<wchar_t>::iterator &x,
+ const std::basic_string<wchar_t>::iterator &y)
+{
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop
+ for (std::basic_string<wchar_t>::iterator i = x; i <= y; i = i + 9 - 8)
+ baz (i);
+}
+
+template <typename T>
+void
+f4 (const std::basic_string<wchar_t>::iterator &x,
+ const std::basic_string<wchar_t>::iterator &y)
+{
+ std::basic_string<wchar_t>::iterator i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop lastprivate(i)
+ for (i = x + 2000 - 64; i > y + 10; --i)
+ baz (i);
+}
+
+void
+f5 (const std::basic_string<wchar_t>::iterator &x,
+ const std::basic_string<wchar_t>::iterator &y)
+{
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop
+ for (std::basic_string<wchar_t>::iterator i = x + 2000 - 64;
+ i > y + 10; i -= 10)
+ baz (i);
+}
+
+template <int N>
+void
+f6 (const std::basic_string<wchar_t>::iterator &x,
+ const std::basic_string<wchar_t>::iterator &y)
+{
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop
+ for (std::basic_string<wchar_t>::iterator i = x + 2000 - 64;
+ i > y + 10; i = i - 12 + 2)
+ {
+ std::basic_string<wchar_t>::iterator j = i + N;
+ baz (j);
+ }
+}
+
+template <int N>
+void
+f7 (std::basic_string<wchar_t>::iterator i,
+ const std::basic_string<wchar_t>::iterator &x,
+ const std::basic_string<wchar_t>::iterator &y)
+{
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop
+ for (i = x - 10; i <= y + 10; i += N)
+ baz (i);
+}
+
+template <wchar_t N>
+void
+f8 (J<wchar_t> j)
+{
+ std::basic_string<wchar_t>::iterator i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop
+ for (i = j.begin (); i <= j.end () + N; i += 2)
+ baz (i);
+}
+
+template <typename T, int N>
+void
+f9 (const typename std::basic_string<T>::iterator &x,
+ const typename std::basic_string<T>::iterator &y)
+{
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop
+ for (typename std::basic_string<T>::iterator i = x; i <= y; i = i + N)
+ baz (i);
+}
+
+template <typename T, int N>
+void
+f10 (const typename std::basic_string<T>::iterator &x,
+ const typename std::basic_string<T>::iterator &y)
+{
+ typename std::basic_string<T>::iterator i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop
+ for (i = x; i > y; i = i + N)
+ baz (i);
+}
+
+template <typename T>
+void
+f11 (const T &x, const T &y)
+{
+#pragma omp parallel
+ {
+#pragma omp single nowait
+#pragma omp taskloop nogroup
+ for (T i = x; i <= y; i += 3)
+ baz (i);
+#pragma omp single nowait
+ {
+ T j = y + 3;
+ baz (j);
+ }
+ }
+}
+
+template <typename T>
+void
+f12 (const T &x, const T &y)
+{
+ T i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop private(i)
+ for (i = x; i > y; --i)
+ baz (i);
+}
+
+template <int N>
+struct K
+{
+ template <typename T>
+ static void
+ f13 (const T &x, const T &y)
+ {
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop
+ for (T i = x; i <= y + N; i += N)
+ baz (i);
+ }
+};
+
+#define check(expr) \
+ for (int i = 0; i < 2000; i++) \
+ if (expr) \
+ { \
+ if (a[i] != L'a' + i + 1) \
+ std::abort (); \
+ a[i] = L'a' + i; \
+ } \
+ else if (a[i] != L'a' + i) \
+ std::abort ()
+
+int
+main ()
+{
+ std::basic_string<wchar_t> a = L"";
+ for (int i = 0; i < 2000; i++)
+ a += L'a' + i;
+ f1 (a.begin () + 10, a.begin () + 1990);
+ check (i >= 10 && i <= 1990 && (i - 10) % 6 == 0);
+ f2 (a.begin () + 0, a.begin () + 1999);
+ check (i < 1998 && (i & 1) == 0);
+ f3<char> (a.begin () + 20, a.begin () + 1837);
+ check (i >= 20 && i <= 1837);
+ f4<int> (a.begin () + 0, a.begin () + 30);
+ check (i > 40 && i <= 2000 - 64);
+ f5 (a.begin () + 0, a.begin () + 100);
+ check (i >= 116 && i <= 2000 - 64 && (i - 116) % 10 == 0);
+ f6<-10> (a.begin () + 10, a.begin () + 110);
+ check (i >= 116 && i <= 2000 - 64 && (i - 116) % 10 == 0);
+ f7<6> (std::basic_string<wchar_t>::iterator (), a.begin () + 12,
+ a.begin () + 1800);
+ check (i >= 2 && i <= 1808 && (i - 2) % 6 == 0);
+ f8<121> (J<wchar_t> (a.begin () + 14, a.begin () + 1803));
+ check (i >= 14 && i <= 1924 && (i & 1) == 0);
+ f9<wchar_t, 7> (a.begin () + 33, a.begin () + 1967);
+ check (i >= 33 && i <= 1967 && (i - 33) % 7 == 0);
+ f10<wchar_t, -7> (a.begin () + 1939, a.begin () + 17);
+ check (i >= 21 && i <= 1939 && (i - 21) % 7 == 0);
+ f11<std::basic_string<wchar_t>::iterator > (a.begin () + 16,
+ a.begin () + 1981);
+ check (i >= 16 && i <= 1984 && (i - 16) % 3 == 0);
+ f12<std::basic_string<wchar_t>::iterator > (a.begin () + 1761,
+ a.begin () + 37);
+ check (i > 37 && i <= 1761);
+ K<5>::f13<std::basic_string<wchar_t>::iterator > (a.begin () + 1,
+ a.begin () + 1935);
+ check (i >= 1 && i <= 1936 && (i - 1) % 5 == 0);
+}
--- /dev/null
+// { dg-do run }
+
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+extern "C" void abort ();
+
+template <typename T>
+class I
+{
+public:
+ typedef ptrdiff_t difference_type;
+ I ();
+ ~I ();
+ I (T *);
+ I (const I &);
+ T &operator * ();
+ T *operator -> ();
+ T &operator [] (const difference_type &) const;
+ I &operator = (const I &);
+ I &operator ++ ();
+ I operator ++ (int);
+ I &operator -- ();
+ I operator -- (int);
+ I &operator += (const difference_type &);
+ I &operator -= (const difference_type &);
+ I operator + (const difference_type &) const;
+ I operator - (const difference_type &) const;
+ template <typename S> friend bool operator == (I<S> &, I<S> &);
+ template <typename S> friend bool operator == (const I<S> &, const I<S> &);
+ template <typename S> friend bool operator < (I<S> &, I<S> &);
+ template <typename S> friend bool operator < (const I<S> &, const I<S> &);
+ template <typename S> friend bool operator <= (I<S> &, I<S> &);
+ template <typename S> friend bool operator <= (const I<S> &, const I<S> &);
+ template <typename S> friend bool operator > (I<S> &, I<S> &);
+ template <typename S> friend bool operator > (const I<S> &, const I<S> &);
+ template <typename S> friend bool operator >= (I<S> &, I<S> &);
+ template <typename S> friend bool operator >= (const I<S> &, const I<S> &);
+ template <typename S> friend typename I<S>::difference_type operator - (I<S> &, I<S> &);
+ template <typename S> friend typename I<S>::difference_type operator - (const I<S> &, const I<S> &);
+ template <typename S> friend I<S> operator + (typename I<S>::difference_type , const I<S> &);
+private:
+ T *p;
+};
+template <typename T> I<T>::I () : p (0) {}
+template <typename T> I<T>::~I () { p = (T *) 0; }
+template <typename T> I<T>::I (T *x) : p (x) {}
+template <typename T> I<T>::I (const I &x) : p (x.p) {}
+template <typename T> T &I<T>::operator * () { return *p; }
+template <typename T> T *I<T>::operator -> () { return p; }
+template <typename T> T &I<T>::operator [] (const difference_type &x) const { return p[x]; }
+template <typename T> I<T> &I<T>::operator = (const I &x) { p = x.p; return *this; }
+template <typename T> I<T> &I<T>::operator ++ () { ++p; return *this; }
+template <typename T> I<T> I<T>::operator ++ (int) { return I (p++); }
+template <typename T> I<T> &I<T>::operator -- () { --p; return *this; }
+template <typename T> I<T> I<T>::operator -- (int) { return I (p--); }
+template <typename T> I<T> &I<T>::operator += (const difference_type &x) { p += x; return *this; }
+template <typename T> I<T> &I<T>::operator -= (const difference_type &x) { p -= x; return *this; }
+template <typename T> I<T> I<T>::operator + (const difference_type &x) const { return I (p + x); }
+template <typename T> I<T> I<T>::operator - (const difference_type &x) const { return I (p - x); }
+template <typename T> bool operator == (I<T> &x, I<T> &y) { return x.p == y.p; }
+template <typename T> bool operator == (const I<T> &x, const I<T> &y) { return x.p == y.p; }
+template <typename T> bool operator != (I<T> &x, I<T> &y) { return !(x == y); }
+template <typename T> bool operator != (const I<T> &x, const I<T> &y) { return !(x == y); }
+template <typename T> bool operator < (I<T> &x, I<T> &y) { return x.p < y.p; }
+template <typename T> bool operator < (const I<T> &x, const I<T> &y) { return x.p < y.p; }
+template <typename T> bool operator <= (I<T> &x, I<T> &y) { return x.p <= y.p; }
+template <typename T> bool operator <= (const I<T> &x, const I<T> &y) { return x.p <= y.p; }
+template <typename T> bool operator > (I<T> &x, I<T> &y) { return x.p > y.p; }
+template <typename T> bool operator > (const I<T> &x, const I<T> &y) { return x.p > y.p; }
+template <typename T> bool operator >= (I<T> &x, I<T> &y) { return x.p >= y.p; }
+template <typename T> bool operator >= (const I<T> &x, const I<T> &y) { return x.p >= y.p; }
+template <typename T> typename I<T>::difference_type operator - (I<T> &x, I<T> &y) { return x.p - y.p; }
+template <typename T> typename I<T>::difference_type operator - (const I<T> &x, const I<T> &y) { return x.p - y.p; }
+template <typename T> I<T> operator + (typename I<T>::difference_type x, const I<T> &y) { return I<T> (x + y.p); }
+
+template <typename T>
+class J
+{
+public:
+ J(const I<T> &x, const I<T> &y) : b (x), e (y) {}
+ const I<T> &begin ();
+ const I<T> &end ();
+private:
+ I<T> b, e;
+};
+
+template <typename T> const I<T> &J<T>::begin () { return b; }
+template <typename T> const I<T> &J<T>::end () { return e; }
+
+int results[2000];
+
+template <typename T>
+void
+baz (I<T> &i)
+{
+ if (*i < 0 || *i >= 2000)
+ abort ();
+ results[*i]++;
+}
+
+I<int>
+f1 (const I<int> &x, const I<int> &y)
+{
+ I<int> i;
+#pragma omp parallel shared (i)
+ {
+ #pragma omp single
+ #pragma omp taskloop lastprivate (i)
+ for (i = x; i < y - 1; ++i)
+ baz (i);
+ #pragma omp single
+ i += 3;
+ }
+ return I<int> (i);
+}
+
+I<int>
+f2 (const I<int> &x, const I<int> &y)
+{
+ I<int> i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop lastprivate (i)
+ for (i = x; i < y - 1; i = 1 - 6 + 7 + i)
+ baz (i);
+ return I<int> (i);
+}
+
+template <typename T>
+I<int>
+f3 (const I<int> &x, const I<int> &y)
+{
+ I<int> i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop lastprivate (i)
+ for (i = x + 1000 - 64; i <= y - 10; i++)
+ baz (i);
+ return i;
+}
+
+template <typename T>
+I<int>
+f4 (const I<int> &x, const I<int> &y)
+{
+ I<int> i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop lastprivate (i)
+ for (i = x + 2000 - 64; i > y + 10; --i)
+ baz (i);
+ return I<int> (i);
+}
+
+template <typename T>
+I<int>
+f5 (const I<int> &x, const I<int> &y)
+{
+ I<int> i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop lastprivate (i)
+ for (i = x; i > y + T (6); i--)
+ baz (i);
+ return i;
+}
+
+template <typename T>
+I<int>
+f6 (const I<int> &x, const I<int> &y)
+{
+ I<int> i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop lastprivate (i)
+ for (i = x - T (7); i > y; i -= T (2))
+ baz (i);
+ return I<int> (i);
+}
+
+template <int N>
+I<int>
+f7 (I<int> i, const I<int> &x, const I<int> &y)
+{
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop lastprivate (i)
+ for (i = x - 10; i <= y + 10; i += N)
+ baz (i);
+ return I<int> (i);
+}
+
+template <int N>
+I<int>
+f8 (J<int> j)
+{
+ I<int> i;
+#pragma omp parallel shared (i)
+ #pragma omp single
+ #pragma omp taskloop lastprivate (i)
+ for (i = j.begin (); i <= j.end () + N; i += 2)
+ baz (i);
+ return i;
+}
+
+I<int> i9;
+
+template <long N>
+I<int> &
+f9 (J<int> j)
+{
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop lastprivate (i9)
+ for (i9 = j.begin () + N; i9 <= j.end () - N; i9 = i9 - N)
+ baz (i9);
+ return i9;
+}
+
+template <typename T, int N>
+I<T>
+f10 (const I<T> &x, const I<T> &y)
+{
+ I<T> i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop lastprivate (i)
+ for (i = x; i > y; i = i + N)
+ baz (i);
+ return i;
+}
+
+template <typename T, typename U>
+T
+f11 (T i, const T &x, const T &y)
+{
+#pragma omp parallel
+ #pragma omp single
+ #pragma omp taskloop lastprivate (i)
+ for (i = x + U (2); i <= y + U (1); i = U (2) + U (3) + i)
+ baz (i);
+ return T (i);
+}
+
+template <typename T>
+T
+f12 (const T &x, const T &y)
+{
+ T i;
+#pragma omp parallel
+#pragma omp single
+#pragma omp taskloop lastprivate (i)
+ for (i = x; i > y; --i)
+ baz (i);
+ return i;
+}
+
+#define check(expr) \
+ for (int i = 0; i < 2000; i++) \
+ if (expr) \
+ { \
+ if (results[i] != 1) \
+ abort (); \
+ results[i] = 0; \
+ } \
+ else if (results[i]) \
+ abort ()
+
+int
+main ()
+{
+ int a[2000];
+ long b[2000];
+ for (int i = 0; i < 2000; i++)
+ {
+ a[i] = i;
+ b[i] = i;
+ }
+ if (*f1 (&a[10], &a[1873]) != 1875)
+ abort ();
+ check (i >= 10 && i < 1872);
+ if (*f2 (&a[0], &a[1998]) != 1998)
+ abort ();
+ check (i < 1997 && (i & 1) == 0);
+ if (*f3<int> (&a[10], &a[1971]) != 1962)
+ abort ();
+ check (i >= 946 && i <= 1961);
+ if (*f4<int> (&a[0], &a[30]) != 40)
+ abort ();
+ check (i > 40 && i <= 2000 - 64);
+ if (*f5<short> (&a[1931], &a[17]) != 23)
+ abort ();
+ check (i > 23 && i <= 1931);
+ if (*f6<long> (&a[1931], &a[17]) != 16)
+ abort ();
+ check (i > 17 && i <= 1924 && (i & 1) == 0);
+ if (*f7<6> (I<int> (), &a[12], &a[1800]) != 1814)
+ abort ();
+ check (i >= 2 && i <= 1808 && (i - 2) % 6 == 0);
+ if (*f8<121> (J<int> (&a[14], &a[1803])) != 1926)
+ abort ();
+ check (i >= 14 && i <= 1924 && (i & 1) == 0);
+ if (*f9<-3L> (J<int> (&a[27], &a[1761])) != 1767)
+ abort ();
+ check (i >= 24 && i <= 1764 && (i % 3) == 0);
+ if (*f10<int, -7> (&a[1939], &a[17]) != 14)
+ abort ();
+ check (i >= 21 && i <= 1939 && i % 7 == 0);
+ if (*f11<I<int>, short> (I<int> (), &a[71], &a[1941]) != 1943)
+ abort ();
+ check (i >= 73 && i <= 1938 && (i - 73) % 5 == 0);
+ if (*f12<I<int> > (&a[1761], &a[37]) != 37)
+ abort ();
+ check (i > 37 && i <= 1761);
+ if (*f10<long, -7> (&b[1939], &b[17]) != 14)
+ abort ();
+ check (i >= 21 && i <= 1939 && i % 7 == 0);
+ if (*f11<I<long>, short> (I<long> (), &b[71], &b[1941]) != 1943)
+ abort ();
+ check (i >= 73 && i <= 1938 && (i - 73) % 5 == 0);
+ if (*f12<I<long> > (&b[1761], &b[37]) != 37)
+ abort ();
+ check (i > 37 && i <= 1761);
+}
--- /dev/null
+/* { dg-do run } */
+/* { dg-set-target-env-var OMP_PROC_BIND "spread,close" } */
+/* { dg-set-target-env-var OMP_PLACES "{6,7}:4:-2,!{2,3}" } */
+/* { dg-set-target-env-var OMP_NUM_THREADS "2" } */
+
+#include <omp.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int *
+get_buf (int nump)
+{
+ static int *buf;
+ static size_t buf_size;
+ if ((size_t) nump > buf_size)
+ {
+ buf_size *= 2;
+ if (nump > buf_size)
+ buf_size = nump + 64;
+ int *bufn = realloc (buf, buf_size * sizeof (int));
+ if (bufn == NULL)
+ {
+ fprintf (stderr, "memory allocation error\n");
+ exit (1);
+ }
+ buf = bufn;
+ }
+ return buf;
+}
+
+void
+print_place (int count, int *ids)
+{
+ int i, j;
+ printf ("{");
+ for (i = 0; i < count; i++)
+ {
+ for (j = i + 1; j < count; j++)
+ if (ids[j] != ids[i] + (j - i))
+ break;
+ if (i)
+ printf (",");
+ if (j == i + 1)
+ printf ("%d", ids[i]);
+ else
+ {
+ printf ("%d:%d", ids[i], j - i);
+ i = j - 1;
+ }
+ }
+ printf ("}\n");
+}
+
+void
+print_place_var (void)
+{
+ int place = omp_get_place_num ();
+ int num_places = omp_get_partition_num_places ();
+ int *ids = get_buf (num_places);
+ omp_get_partition_place_nums (ids);
+ printf ("place %d\n", place);
+ if (num_places)
+ printf ("partition %d-%d\n", ids[0], ids[num_places - 1]);
+}
+
+int
+main ()
+{
+ int i, num = omp_get_num_places (), nump, *ids;
+ printf ("omp_get_num_places () == %d\n", num);
+ for (i = 0; i < num; i++)
+ {
+ printf ("place %d ", i);
+ nump = omp_get_place_num_procs (i);
+ ids = get_buf (nump);
+ omp_get_place_proc_ids (i, ids);
+ print_place (nump, ids);
+ }
+ print_place_var ();
+ omp_set_nested (1);
+ #pragma omp parallel
+ if (omp_get_thread_num () == omp_get_num_threads () - 1)
+ {
+ #pragma omp parallel
+ if (omp_get_thread_num () == omp_get_num_threads () - 1)
+ print_place_var ();
+ }
+ return 0;
+}
--- /dev/null
+extern void abort (void);
+
+#define N 256
+int a[N], b[N / 16][8][4], c[N / 32][8][8];
+volatile int d, e;
+
+int
+main ()
+{
+ int i, j, k, l, m;
+ #pragma omp parallel private (l)
+ {
+ #pragma omp for schedule(static, 1) ordered (1) nowait
+ for (i = 0; i < N; i++)
+ {
+ #pragma omp atomic write
+ a[i] = 1;
+ #pragma omp ordered depend(sink: i - 1)
+ if (i)
+ {
+ #pragma omp atomic read
+ l = a[i - 1];
+ if (l < 2)
+ abort ();
+ }
+ #pragma omp atomic write
+ a[i] = 2;
+ if (i < N - 1)
+ {
+ #pragma omp atomic read
+ l = a[i + 1];
+ if (l == 3)
+ abort ();
+ }
+ #pragma omp ordered depend(source)
+ #pragma omp atomic write
+ a[i] = 3;
+ }
+ #pragma omp for schedule(static, 0) ordered (3) nowait
+ for (i = 2; i < N / 16 - 1; i++)
+ for (j = 0; j < 8; j += 2)
+ for (k = 1; k <= 3; k++)
+ {
+ #pragma omp atomic write
+ b[i][j][k] = 1;
+ #pragma omp ordered depend(sink: i, j - 2, k - 1) \
+ depend(sink: i - 2, j - 2, k + 1)
+ #pragma omp ordered depend(sink: i - 3, j + 2, k - 2)
+ if (j >= 2 && k > 1)
+ {
+ #pragma omp atomic read
+ l = b[i][j - 2][k - 1];
+ if (l < 2)
+ abort ();
+ }
+ #pragma omp atomic write
+ b[i][j][k] = 2;
+ if (i >= 4 && j >= 2 && k < 3)
+ {
+ #pragma omp atomic read
+ l = b[i - 2][j - 2][k + 1];
+ if (l < 2)
+ abort ();
+ }
+ if (i >= 5 && j < N / 16 - 3 && k == 3)
+ {
+ #pragma omp atomic read
+ l = b[i - 3][j + 2][k - 2];
+ if (l < 2)
+ abort ();
+ }
+ #pragma omp ordered depend(source)
+ #pragma omp atomic write
+ b[i][j][k] = 3;
+ }
+#define A(n) int n;
+#define B(n) A(n##0) A(n##1) A(n##2) A(n##3)
+#define C(n) B(n##0) B(n##1) B(n##2) B(n##3)
+#define D(n) C(n##0) C(n##1) C(n##2) C(n##3)
+ D(m)
+#undef A
+ #pragma omp for collapse (2) ordered(61) schedule(dynamic, 15)
+ for (i = 0; i < N / 32; i++)
+ for (j = 7; j > 1; j--)
+ for (k = 6; k >= 0; k -= 2)
+#define A(n) for (n = 4; n < 5; n++)
+ D(m)
+#undef A
+ {
+ #pragma omp atomic write
+ c[i][j][k] = 1;
+#define A(n) ,n
+#define E(n) C(n##0) C(n##1) C(n##2) B(n##30) B(n##31) A(n##320) A(n##321)
+ #pragma omp ordered depend (sink: i, j, k + 2 E(m)) \
+ depend (sink:i - 2, j + 1, k - 4 E(m)) \
+ depend(sink: i - 1, j - 2, k - 2 E(m))
+ if (k <= 4)
+ {
+ l = c[i][j][k + 2];
+ if (l < 2)
+ abort ();
+ }
+ #pragma omp atomic write
+ c[i][j][k] = 2;
+ if (i >= 2 && j < 7 && k >= 4)
+ {
+ l = c[i - 2][j + 1][k - 4];
+ if (l < 2)
+ abort ();
+ }
+ if (i >= 1 && j >= 4 && k >= 2)
+ {
+ l = c[i - 1][j - 2][k - 2];
+ if (l < 2)
+ abort ();
+ }
+ #pragma omp ordered depend (source)
+ #pragma omp atomic write
+ c[i][j][k] = 3;
+ }
+
+ #pragma omp for collapse(2) ordered(4) lastprivate (i, j, k)
+ for (i = 0; i < d + 1; i++)
+ for (j = d + 1; j >= 0; j--)
+ for (k = 0; k < d; k++)
+ for (l = 0; l < d + 2; l++)
+ {
+ #pragma omp ordered depend (source)
+ #pragma omp ordered depend (sink:i - 2, j + 2, k - 2, l)
+ if (!e)
+ abort ();
+ }
+ #pragma omp single
+ {
+ if (i != 1 || j != -1 || k != 0)
+ abort ();
+ i = 8; j = 9; k = 10;
+ }
+ #pragma omp for collapse(2) ordered(4) lastprivate (i, j, k, m)
+ for (i = 0; i < d + 1; i++)
+ for (j = d + 1; j >= 0; j--)
+ for (k = 0; k < d + 2; k++)
+ for (m = 0; m < d; m++)
+ {
+ #pragma omp ordered depend (source)
+ #pragma omp ordered depend (sink:i - 2, j + 2, k - 2, m)
+ abort ();
+ }
+ #pragma omp single
+ if (i != 1 || j != -1 || k != 2 || m != 0)
+ abort ();
+ #pragma omp for collapse(2) ordered(4) nowait
+ for (i = 0; i < d + 1; i++)
+ for (j = d; j > 0; j--)
+ for (k = 0; k < d + 2; k++)
+ for (l = 0; l < d + 4; l++)
+ {
+ #pragma omp ordered depend (source)
+ #pragma omp ordered depend (sink:i - 2, j + 2, k - 2, l)
+ if (!e)
+ abort ();
+ }
+ #pragma omp for nowait
+ for (i = 0; i < N; i++)
+ if (a[i] != 3)
+ abort ();
+ #pragma omp for collapse(2) private(k) nowait
+ for (i = 0; i < N / 16; i++)
+ for (j = 0; j < 8; j++)
+ for (k = 0; k < 4; k++)
+ if (b[i][j][k] != 3 * (i >= 2 && i < N / 16 - 1 && (j & 1) == 0 && k >= 1))
+ abort ();
+ #pragma omp for collapse(3) nowait
+ for (i = 0; i < N / 32; i++)
+ for (j = 0; j < 8; j++)
+ for (k = 0; k < 8; k++)
+ if (c[i][j][k] != 3 * (j >= 2 && (k & 1) == 0))
+ abort ();
+ }
+ return 0;
+}
--- /dev/null
+extern void abort (void);
+
+#define N 256
+int a[N], b[N / 16][8][4], c[N / 32][8][8], g[N / 16][8][6];
+volatile int d, e;
+volatile unsigned long long f;
+
+int
+main ()
+{
+ unsigned long long i;
+ int j, k, l, m;
+ #pragma omp parallel private (l)
+ {
+ #pragma omp for schedule(static, 1) ordered (1) nowait
+ for (i = 1; i < N + f; i++)
+ {
+ #pragma omp atomic write
+ a[i] = 1;
+ #pragma omp ordered depend(sink: i - 1)
+ if (i > 1)
+ {
+ #pragma omp atomic read
+ l = a[i - 1];
+ if (l < 2)
+ abort ();
+ }
+ #pragma omp atomic write
+ a[i] = 2;
+ if (i < N - 1)
+ {
+ #pragma omp atomic read
+ l = a[i + 1];
+ if (l == 3)
+ abort ();
+ }
+ #pragma omp ordered depend(source)
+ #pragma omp atomic write
+ a[i] = 3;
+ }
+ #pragma omp for schedule(static, 0) ordered (3) nowait
+ for (i = 3; i < N / 16 - 1 + f; i++)
+ for (j = 0; j < 8; j += 2)
+ for (k = 1; k <= 3; k++)
+ {
+ #pragma omp atomic write
+ b[i][j][k] = 1;
+ #pragma omp ordered depend(sink: i, j - 2, k - 1) \
+ depend(sink: i - 2, j - 2, k + 1)
+ #pragma omp ordered depend(sink: i - 3, j + 2, k - 2)
+ if (j >= 2 && k > 1)
+ {
+ #pragma omp atomic read
+ l = b[i][j - 2][k - 1];
+ if (l < 2)
+ abort ();
+ }
+ #pragma omp atomic write
+ b[i][j][k] = 2;
+ if (i >= 5 && j >= 2 && k < 3)
+ {
+ #pragma omp atomic read
+ l = b[i - 2][j - 2][k + 1];
+ if (l < 2)
+ abort ();
+ }
+ if (i >= 6 && j < N / 16 - 3 && k == 3)
+ {
+ #pragma omp atomic read
+ l = b[i - 3][j + 2][k - 2];
+ if (l < 2)
+ abort ();
+ }
+ #pragma omp ordered depend(source)
+ #pragma omp atomic write
+ b[i][j][k] = 3;
+ }
+#define A(n) int n;
+#define B(n) A(n##0) A(n##1) A(n##2) A(n##3)
+#define C(n) B(n##0) B(n##1) B(n##2) B(n##3)
+#define D(n) C(n##0) C(n##1) C(n##2) C(n##3)
+ D(m)
+#undef A
+ #pragma omp for collapse (2) ordered(61) schedule(dynamic, 15)
+ for (i = 2; i < N / 32 + f; i++)
+ for (j = 7; j > 1; j--)
+ for (k = 6; k >= 0; k -= 2)
+#define A(n) for (n = 4; n < 5; n++)
+ D(m)
+#undef A
+ {
+ #pragma omp atomic write
+ c[i][j][k] = 1;
+#define A(n) ,n
+#define E(n) C(n##0) C(n##1) C(n##2) B(n##30) B(n##31) A(n##320) A(n##321)
+ #pragma omp ordered depend (sink: i, j, k + 2 E(m)) \
+ depend (sink:i - 2, j + 1, k - 4 E(m)) \
+ depend(sink: i - 1, j - 2, k - 2 E(m))
+ if (k <= 4)
+ {
+ l = c[i][j][k + 2];
+ if (l < 2)
+ abort ();
+ }
+ #pragma omp atomic write
+ c[i][j][k] = 2;
+ if (i >= 4 && j < 7 && k >= 4)
+ {
+ l = c[i - 2][j + 1][k - 4];
+ if (l < 2)
+ abort ();
+ }
+ if (i >= 3 && j >= 4 && k >= 2)
+ {
+ l = c[i - 1][j - 2][k - 2];
+ if (l < 2)
+ abort ();
+ }
+ #pragma omp ordered depend (source)
+ #pragma omp atomic write
+ c[i][j][k] = 3;
+ }
+ #pragma omp for schedule(static, 0) ordered (3) nowait
+ for (j = 0; j < N / 16 - 1; j++)
+ for (k = 0; k < 8; k += 2)
+ for (i = 3; i <= 5 + f; i++)
+ {
+ #pragma omp atomic write
+ g[j][k][i] = 1;
+ #pragma omp ordered depend(sink: j, k - 2, i - 1) \
+ depend(sink: j - 2, k - 2, i + 1)
+ #pragma omp ordered depend(sink: j - 3, k + 2, i - 2)
+ if (k >= 2 && i > 3)
+ {
+ #pragma omp atomic read
+ l = g[j][k - 2][i - 1];
+ if (l < 2)
+ abort ();
+ }
+ #pragma omp atomic write
+ g[j][k][i] = 2;
+ if (j >= 2 && k >= 2 && i < 5)
+ {
+ #pragma omp atomic read
+ l = g[j - 2][k - 2][i + 1];
+ if (l < 2)
+ abort ();
+ }
+ if (j >= 3 && k < N / 16 - 3 && i == 5)
+ {
+ #pragma omp atomic read
+ l = g[j - 3][k + 2][i - 2];
+ if (l < 2)
+ abort ();
+ }
+ #pragma omp ordered depend(source)
+ #pragma omp atomic write
+ g[j][k][i] = 3;
+ }
+ #pragma omp for collapse(2) ordered(4) lastprivate (i, j, k)
+ for (i = 2; i < f + 3; i++)
+ for (j = d + 1; j >= 0; j--)
+ for (k = 0; k < d; k++)
+ for (l = 0; l < d + 2; l++)
+ {
+ #pragma omp ordered depend (source)
+ #pragma omp ordered depend (sink:i - 2, j + 2, k - 2, l)
+ if (!e)
+ abort ();
+ }
+ #pragma omp single
+ {
+ if (i != 3 || j != -1 || k != 0)
+ abort ();
+ i = 8; j = 9; k = 10;
+ }
+ #pragma omp for collapse(2) ordered(4) lastprivate (i, j, k, m)
+ for (i = 2; i < f + 3; i++)
+ for (j = d + 1; j >= 0; j--)
+ for (k = 0; k < d + 2; k++)
+ for (m = 0; m < d; m++)
+ {
+ #pragma omp ordered depend (source)
+ #pragma omp ordered depend (sink:i - 2, j + 2, k - 2, m)
+ abort ();
+ }
+ #pragma omp single
+ if (i != 3 || j != -1 || k != 2 || m != 0)
+ abort ();
+ #pragma omp for collapse(2) ordered(4) nowait
+ for (i = 2; i < f + 3; i++)
+ for (j = d; j > 0; j--)
+ for (k = 0; k < d + 2; k++)
+ for (l = 0; l < d + 4; l++)
+ {
+ #pragma omp ordered depend (source)
+ #pragma omp ordered depend (sink:i - 2, j + 2, k - 2, l)
+ if (!e)
+ abort ();
+ }
+ #pragma omp for nowait
+ for (i = 0; i < N; i++)
+ if (a[i] != 3 * (i >= 1))
+ abort ();
+ #pragma omp for collapse(2) private(k) nowait
+ for (i = 0; i < N / 16; i++)
+ for (j = 0; j < 8; j++)
+ for (k = 0; k < 4; k++)
+ if (b[i][j][k] != 3 * (i >= 3 && i < N / 16 - 1 && (j & 1) == 0 && k >= 1))
+ abort ();
+ #pragma omp for collapse(3) nowait
+ for (i = 0; i < N / 32; i++)
+ for (j = 0; j < 8; j++)
+ for (k = 0; k < 8; k++)
+ if (c[i][j][k] != 3 * (i >= 2 && j >= 2 && (k & 1) == 0))
+ abort ();
+ #pragma omp for collapse(2) private(k) nowait
+ for (i = 0; i < N / 16; i++)
+ for (j = 0; j < 8; j++)
+ for (k = 0; k < 6; k++)
+ if (g[i][j][k] != 3 * (i < N / 16 - 1 && (j & 1) == 0 && k >= 3))
+ abort ();
+ }
+ return 0;
+}
{
int x = 0;
- #pragma omp target if(n > THRESHOLD)
+ #pragma omp target if(n > THRESHOLD) map(from:x)
x = fib (n);
return x;
int i;
float tmp = 0.0;
- #pragma omp target
+ #pragma omp target map(tofrom:tmp)
#pragma omp parallel for reduction(+:tmp)
for (i = 0; i < N; i++)
tmp += Pfun (i, k);
int i, k;
float tmp = 0.0;
- #pragma omp target
+ #pragma omp target map(tofrom:tmp)
#pragma omp parallel for reduction(+:tmp)
for (i = 0; i < N; i++)
{
int b = 0;
int c, d;
- #pragma omp target if(a > 200 && a < 400)
+ #pragma omp target if(a > 200 && a < 400) map(from: c)
c = omp_is_initial_device ();
#pragma omp target data map(to: b) if(a > 200 && a < 400)
- #pragma omp target
+ #pragma omp target map(from: b, d)
{
b = 100;
d = omp_is_initial_device ();
a += 200;
b = 0;
- #pragma omp target if(a > 200 && a < 400)
+ #pragma omp target if(a > 200 && a < 400) map(from: c)
c = omp_is_initial_device ();
#pragma omp target data map(to: b) if(a > 200 && a < 400)
- #pragma omp target
+ #pragma omp target map(from: b, d)
{
b = 100;
d = omp_is_initial_device ();
a += 200;
b = 0;
- #pragma omp target if(a > 200 && a < 400)
+ #pragma omp target if(a > 200 && a < 400) map(from: c)
c = omp_is_initial_device ();
#pragma omp target data map(to: b) if(a > 200 && a < 400)
- #pragma omp target
+ #pragma omp target map(from: b, d)
{
b = 100;
d = omp_is_initial_device ();
int res;
int default_device = omp_get_default_device ();
- #pragma omp target
+ #pragma omp target map(from: res)
res = omp_is_initial_device ();
if (res)
omp_set_default_device (omp_get_num_devices ());
- #pragma omp target
+ #pragma omp target map(from: res)
res = omp_is_initial_device ();
if (!res)
{
int tmp = 0;
- #pragma omp target
+ #pragma omp target map(tofrom:tmp)
#pragma omp parallel for reduction(+:tmp)
for (i = 0; i < rows; i++)
tmp += (Q[i][k] * Q[i][k]);
int i, i0;
float sum = 0;
- #pragma omp target map(to: B[0:n], C[0:n])
+ #pragma omp target map(to: B[0:n], C[0:n]) map(tofrom: sum)
#pragma omp teams num_teams(num_teams) thread_limit(block_threads) \
reduction(+:sum)
#pragma omp distribute
int i;
float sum = 0;
- #pragma omp target teams map(to: B[0:n], C[0:n])
+ #pragma omp target teams map(to: B[0:n], C[0:n]) map(tofrom: sum)
#pragma omp distribute parallel for reduction(+:sum)
for (i = 0; i < n; i++)
sum += B[i] * C[i];
int i;
float sum = 0;
- #pragma omp target map(to: B[0:n], C[0:n])
+ #pragma omp target map(to: B[0:n], C[0:n]) map(tofrom:sum)
#pragma omp teams num_teams(8) thread_limit(16)
#pragma omp distribute parallel for reduction(+:sum) \
dist_schedule(static, 1024) \
#ifndef SC
#define SC
#endif
+#ifndef OMPTGT
+#define OMPTGT
+#endif
+#ifndef OMPTO
+#define OMPTO(v) do {} while (0)
+#endif
+#ifndef OMPFROM
+#define OMPFROM(v) do {} while (0)
+#endif
__attribute__((noinline, noclone)) void
N(f0) (void)
{
int i;
+ OMPTGT
#pragma omp F S
for (i = 0; i < 1500; i++)
a[i] += 2;
__attribute__((noinline, noclone)) void
N(f1) (void)
{
+ OMPTGT
#pragma omp F S
for (unsigned int i = __INT_MAX__; i < 3000U + __INT_MAX__; i += 2)
a[(i - __INT_MAX__) >> 1] -= 2;
N(f2) (void)
{
unsigned long long i;
+ OMPTGT
#pragma omp F S
for (i = __LONG_LONG_MAX__ + 4500ULL - 27;
i > __LONG_LONG_MAX__ - 27ULL; i -= 3)
__attribute__((noinline, noclone)) void
N(f3) (long long n1, long long n2, long long s3)
{
+ OMPTGT
#pragma omp F S
for (long long i = n1 + 23; i > n2 - 25; i -= s3)
a[i + 48] += 7;
N(f4) (void)
{
unsigned int i;
+ OMPTGT
#pragma omp F S
for (i = 30; i < 20; i += 2)
a[i] += 10;
int s1, int s2, int s3)
{
SC int v1, v2, v3;
+ OMPTGT
#pragma omp F S collapse(3)
for (v1 = n11; v1 < n12; v1 += s1)
for (v2 = n21; v2 < n22; v2 += s2)
{
SC int v1, v2;
SC long long v3;
+ OMPTGT
#pragma omp F S collapse(3)
for (v1 = n11; v1 > n12; v1 += s1)
for (v2 = n21; v2 > n22; v2 += s2)
{
SC unsigned int v1, v3;
SC unsigned long long v2;
+ OMPTGT
#pragma omp F S collapse(3)
for (v1 = 0; v1 < 20; v1 += 2)
for (v2 = __LONG_LONG_MAX__ + 16ULL;
N(f8) (void)
{
SC long long v1, v2, v3;
+ OMPTGT
#pragma omp F S collapse(3)
for (v1 = 0; v1 < 20; v1 += 2)
for (v2 = 30; v2 < 20; v2++)
N(f9) (void)
{
int i;
+ OMPTGT
#pragma omp F S
for (i = 20; i < 10; i++)
{
N(f10) (void)
{
SC int i;
+ OMPTGT
#pragma omp F S collapse(3)
for (i = 0; i < 10; i++)
for (int j = 10; j < 8; j++)
N(f11) (int n)
{
int i;
+ OMPTGT
#pragma omp F S
for (i = 20; i < n; i++)
{
N(f12) (int n)
{
SC int i;
+ OMPTGT
#pragma omp F S collapse(3)
for (i = 0; i < 10; i++)
for (int j = n; j < 8; j++)
N(f13) (void)
{
int *i;
+ OMPTGT
#pragma omp F S
for (i = a; i < &a[1500]; i++)
i[0] += 2;
N(f14) (void)
{
SC float *i;
+ OMPTGT
#pragma omp F S collapse(3)
for (i = &b[0][0][0]; i < &b[0][0][10]; i++)
for (float *j = &b[0][15][0]; j > &b[0][0][0]; j -= 10)
int i, j, k;
for (i = 0; i < 1500; i++)
a[i] = i - 25;
+ OMPTO (a);
N(f0) ();
+ OMPFROM (a);
for (i = 0; i < 1500; i++)
if (a[i] != i - 23)
return 1;
N(f1) ();
+ OMPFROM (a);
for (i = 0; i < 1500; i++)
if (a[i] != i - 25)
return 1;
N(f2) ();
+ OMPFROM (a);
for (i = 0; i < 1500; i++)
if (a[i] != i - 29)
return 1;
N(f3) (1500LL - 1 - 23 - 48, -1LL + 25 - 48, 1LL);
+ OMPFROM (a);
for (i = 0; i < 1500; i++)
if (a[i] != i - 22)
return 1;
N(f3) (1500LL - 1 - 23 - 48, 1500LL - 1, 7LL);
+ OMPFROM (a);
for (i = 0; i < 1500; i++)
if (a[i] != i - 22)
return 1;
N(f4) ();
+ OMPFROM (a);
for (i = 0; i < 1500; i++)
if (a[i] != i - 22)
return 1;
for (j = 0; j < 15; j++)
for (k = 0; k < 10; k++)
b[i][j][k] = i - 2.5 + 1.5 * j - 1.5 * k;
+ OMPTO (b);
N(f5) (0, 10, 0, 15, 0, 10, 1, 1, 1);
+ OMPFROM (b);
for (i = 0; i < 10; i++)
for (j = 0; j < 15; j++)
for (k = 0; k < 10; k++)
if (b[i][j][k] != i + 1.5 * j - 1.5 * k)
return 1;
N(f5) (0, 10, 30, 15, 0, 10, 4, 5, 6);
+ OMPFROM (b);
for (i = 0; i < 10; i++)
for (j = 0; j < 15; j++)
for (k = 0; k < 10; k++)
if (b[i][j][k] != i + 1.5 * j - 1.5 * k)
return 1;
N(f6) (9, -1, 29, 0, 9, -1, -1, -2, -1);
+ OMPFROM (b);
for (i = 0; i < 10; i++)
for (j = 0; j < 15; j++)
for (k = 0; k < 10; k++)
if (b[i][j][k] != i - 4.5 + 1.5 * j - 1.5 * k)
return 1;
N(f7) ();
+ OMPFROM (b);
for (i = 0; i < 10; i++)
for (j = 0; j < 15; j++)
for (k = 0; k < 10; k++)
if (b[i][j][k] != i + 1.0 + 1.5 * j - 1.5 * k)
return 1;
N(f8) ();
+ OMPFROM (b);
for (i = 0; i < 10; i++)
for (j = 0; j < 15; j++)
for (k = 0; k < 10; k++)
N(f10) ();
N(f11) (10);
N(f12) (12);
+ OMPFROM (a);
+ OMPFROM (b);
for (i = 0; i < 1500; i++)
if (a[i] != i - 22)
return 1;
return 1;
N(f13) ();
N(f14) ();
+ OMPFROM (a);
+ OMPFROM (b);
for (i = 0; i < 1500; i++)
if (a[i] != i - 20)
return 1;
--- /dev/null
+/* { dg-options "-std=gnu99 -fopenmp" } */
+
+extern void abort (void);
+
+#define M(x, y, z) O(x, y, z)
+#define O(x, y, z) x ## _ ## y ## _ ## z
+
+#define F taskloop
+#define G taskloop
+#define S
+#define N(x) M(x, G, normal)
+#include "for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#define F taskloop simd
+#define G taskloop_simd
+#define S
+#define N(x) M(x, G, normal)
+#include "for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+int
+main ()
+{
+ int err = 0;
+ #pragma omp parallel reduction(|:err)
+ #pragma omp single
+ {
+ if (test_taskloop_normal ()
+ || test_taskloop_simd_normal ())
+ err = 1;
+ }
+ if (err)
+ abort ();
+ return 0;
+}
--- /dev/null
+/* { dg-additional-options "-std=gnu99" } */
+
+extern void abort ();
+
+#define M(x, y, z) O(x, y, z)
+#define O(x, y, z) x ## _ ## y ## _ ## z
+
+#pragma omp declare target
+
+#define F for
+#define G f
+#define S
+#define N(x) M(x, G, normal)
+#include "for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#pragma omp end declare target
+
+#undef OMPFROM
+#undef OMPTO
+#define DO_PRAGMA(x) _Pragma (#x)
+#define OMPFROM(v) DO_PRAGMA (omp target update from(v))
+#define OMPTO(v) DO_PRAGMA (omp target update to(v))
+
+#define F target parallel for
+#define G tpf
+#include "for-1.h"
+#undef F
+#undef G
+
+#define F target simd
+#define G t_simd
+#define S
+#define N(x) M(x, G, normal)
+#include "for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#define F target parallel for simd
+#define G tpf_simd
+#include "for-1.h"
+#undef F
+#undef G
+
+#define F target teams distribute
+#define G ttd
+#define S
+#define N(x) M(x, G, normal)
+#include "for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#define F target teams distribute
+#define G ttd_ds128
+#define S dist_schedule(static, 128)
+#define N(x) M(x, G, normal)
+#include "for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#define F target teams distribute simd
+#define G ttds
+#define S
+#define N(x) M(x, G, normal)
+#include "for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#define F target teams distribute simd
+#define G ttds_ds128
+#define S dist_schedule(static, 128)
+#define N(x) M(x, G, normal)
+#include "for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#define F target teams distribute parallel for
+#define G ttdpf
+#include "for-1.h"
+#undef F
+#undef G
+
+#define F target teams distribute parallel for dist_schedule(static, 128)
+#define G ttdpf_ds128
+#include "for-1.h"
+#undef F
+#undef G
+
+#define F target teams distribute parallel for simd
+#define G ttdpfs
+#include "for-1.h"
+#undef F
+#undef G
+
+#define F target teams distribute parallel for simd dist_schedule(static, 128)
+#define G ttdpfs_ds128
+#include "for-1.h"
+#undef F
+#undef G
+
+int
+main ()
+{
+ if (test_tpf_static ()
+ || test_tpf_static32 ()
+ || test_tpf_auto ()
+ || test_tpf_guided32 ()
+ || test_tpf_runtime ()
+ || test_t_simd_normal ()
+ || test_tpf_simd_static ()
+ || test_tpf_simd_static32 ()
+ || test_tpf_simd_auto ()
+ || test_tpf_simd_guided32 ()
+ || test_tpf_simd_runtime ()
+ || test_ttd_normal ()
+ || test_ttd_ds128_normal ()
+ || test_ttds_normal ()
+ || test_ttds_ds128_normal ()
+ || test_ttdpf_static ()
+ || test_ttdpf_static32 ()
+ || test_ttdpf_auto ()
+ || test_ttdpf_guided32 ()
+ || test_ttdpf_runtime ()
+ || test_ttdpf_ds128_static ()
+ || test_ttdpf_ds128_static32 ()
+ || test_ttdpf_ds128_auto ()
+ || test_ttdpf_ds128_guided32 ()
+ || test_ttdpf_ds128_runtime ()
+ || test_ttdpfs_static ()
+ || test_ttdpfs_static32 ()
+ || test_ttdpfs_auto ()
+ || test_ttdpfs_guided32 ()
+ || test_ttdpfs_runtime ()
+ || test_ttdpfs_ds128_static ()
+ || test_ttdpfs_ds128_static32 ()
+ || test_ttdpfs_ds128_auto ()
+ || test_ttdpfs_ds128_guided32 ()
+ || test_ttdpfs_ds128_runtime ())
+ abort ();
+ return 0;
+}
--- /dev/null
+/* { dg-additional-options "-std=gnu99" } */
+
+extern void abort ();
+
+#define M(x, y, z) O(x, y, z)
+#define O(x, y, z) x ## _ ## y ## _ ## z
+
+#pragma omp declare target
+
+#define F for
+#define G f
+#define S
+#define N(x) M(x, G, normal)
+#include "for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#pragma omp end declare target
+
+#undef OMPTGT
+#undef OMPFROM
+#undef OMPTO
+#define DO_PRAGMA(x) _Pragma (#x)
+#define OMPTGT DO_PRAGMA (omp target)
+#define OMPFROM(v) DO_PRAGMA (omp target update from(v))
+#define OMPTO(v) DO_PRAGMA (omp target update to(v))
+
+#define F teams distribute
+#define G td
+#define S
+#define N(x) M(x, G, normal)
+#include "for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#define F teams distribute
+#define G td_ds128
+#define S dist_schedule(static, 128)
+#define N(x) M(x, G, normal)
+#include "for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#define F teams distribute simd
+#define G tds
+#define S
+#define N(x) M(x, G, normal)
+#include "for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#define F teams distribute simd
+#define G tds_ds128
+#define S dist_schedule(static, 128)
+#define N(x) M(x, G, normal)
+#include "for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#define F teams distribute parallel for
+#define G tdpf
+#include "for-1.h"
+#undef F
+#undef G
+
+#define F teams distribute parallel for dist_schedule(static, 128)
+#define G tdpf_ds128
+#include "for-1.h"
+#undef F
+#undef G
+
+#define F teams distribute parallel for simd
+#define G tdpfs
+#include "for-1.h"
+#undef F
+#undef G
+
+#define F teams distribute parallel for simd dist_schedule(static, 128)
+#define G tdpfs_ds128
+#include "for-1.h"
+#undef F
+#undef G
+
+int
+main ()
+{
+ if (test_td_normal ()
+ || test_td_ds128_normal ()
+ || test_tds_normal ()
+ || test_tds_ds128_normal ()
+ || test_tdpf_static ()
+ || test_tdpf_static32 ()
+ || test_tdpf_auto ()
+ || test_tdpf_guided32 ()
+ || test_tdpf_runtime ()
+ || test_tdpf_ds128_static ()
+ || test_tdpf_ds128_static32 ()
+ || test_tdpf_ds128_auto ()
+ || test_tdpf_ds128_guided32 ()
+ || test_tdpf_ds128_runtime ()
+ || test_tdpfs_static ()
+ || test_tdpfs_static32 ()
+ || test_tdpfs_auto ()
+ || test_tdpfs_guided32 ()
+ || test_tdpfs_runtime ()
+ || test_tdpfs_ds128_static ()
+ || test_tdpfs_ds128_static32 ()
+ || test_tdpfs_ds128_auto ()
+ || test_tdpfs_ds128_guided32 ()
+ || test_tdpfs_ds128_runtime ())
+ abort ();
+ return 0;
+}
--- /dev/null
+int a[256];
+
+__attribute__((noinline, noclone)) int
+f1 (int i)
+{
+ #pragma omp parallel for linear (i: 4)
+ for (int j = 16; j < 64; j++)
+ {
+ a[i] = j;
+ i += 4;
+ }
+ return i;
+}
+
+__attribute__((noinline, noclone)) short int
+f2 (short int i, char k)
+{
+ #pragma omp parallel for linear (i: k + 1)
+ for (long j = 16; j < 64; j++)
+ {
+ a[i] = j;
+ i += 4;
+ }
+ return i;
+}
+
+__attribute__((noinline, noclone)) long long int
+f3 (long long int i, long long int k)
+{
+ #pragma omp parallel for linear (i: k)
+ for (short j = 16; j < 64; j++)
+ {
+ a[i] = j;
+ i += 4;
+ }
+ return i;
+}
+
+__attribute__((noinline, noclone)) int
+f4 (int i)
+{
+ #pragma omp parallel for linear (i: 4) schedule(static, 3)
+ for (int j = 16; j < 64; j++)
+ {
+ a[i] = j;
+ i += 4;
+ }
+ return i;
+}
+
+__attribute__((noinline, noclone)) short int
+f5 (short int i, char k)
+{
+ #pragma omp parallel for linear (i: k + 1) schedule(static, 5)
+ for (long j = 16; j < 64; j++)
+ {
+ a[i] = j;
+ i += 4;
+ }
+ return i;
+}
+
+__attribute__((noinline, noclone)) long long int
+f6 (long long int i, long long int k)
+{
+ #pragma omp parallel for linear (i: k) schedule(static, 7)
+ for (short j = 16; j < 64; j++)
+ {
+ a[i] = j;
+ i += 4;
+ }
+ return i;
+}
+
+__attribute__((noinline, noclone)) int
+f7 (int i)
+{
+ #pragma omp parallel for linear (i: 4) schedule(dynamic, 3)
+ for (int j = 16; j < 64; j++)
+ {
+ a[i] = j;
+ i += 4;
+ }
+ return i;
+}
+
+__attribute__((noinline, noclone)) short int
+f8 (short int i, char k)
+{
+ #pragma omp parallel for linear (i: k + 1) schedule(dynamic, 5)
+ for (long j = 16; j < 64; j++)
+ {
+ a[i] = j;
+ i += 4;
+ }
+ return i;
+}
+
+__attribute__((noinline, noclone)) long long int
+f9 (long long int i, long long int k)
+{
+ #pragma omp parallel for linear (i: k) schedule(dynamic, 7)
+ for (short j = 16; j < 64; j++)
+ {
+ a[i] = j;
+ i += 4;
+ }
+ return i;
+}
+
+__attribute__((noinline, noclone)) int
+f10 (int i, long step)
+{
+ #pragma omp parallel for linear (i: 4)
+ for (int j = 16; j < 112; j += step)
+ {
+ a[i] = j / 2 + 8;
+ i += 4;
+ }
+ return i;
+}
+
+__attribute__((noinline, noclone)) short int
+f11 (short int i, char k, char step)
+{
+ #pragma omp parallel for linear (i: k + 1)
+ for (long j = 16; j < 112; j += step)
+ {
+ a[i] = j / 2 + 8;
+ i += 4;
+ }
+ return i;
+}
+
+__attribute__((noinline, noclone)) long long int
+f12 (long long int i, long long int k, int step)
+{
+ #pragma omp parallel for linear (i: k)
+ for (short j = 16; j < 112; j += step)
+ {
+ a[i] = j / 2 + 8;
+ i += 4;
+ }
+ return i;
+}
+
+__attribute__((noinline, noclone)) int
+f13 (int i, long long int step)
+{
+ #pragma omp parallel for linear (i: 4) schedule(static, 3)
+ for (int j = 16; j < 112; j += step)
+ {
+ a[i] = j / 2 + 8;
+ i += 4;
+ }
+ return i;
+}
+
+__attribute__((noinline, noclone)) short int
+f14 (short int i, char k, int step)
+{
+ #pragma omp parallel for linear (i: k + 1) schedule(static, 5)
+ for (long j = 16; j < 112; j += step)
+ {
+ a[i] = j / 2 + 8;
+ i += 4;
+ }
+ return i;
+}
+
+__attribute__((noinline, noclone)) long long int
+f15 (long long int i, long long int k, long int step)
+{
+ #pragma omp parallel for linear (i: k) schedule(static, 7)
+ for (short j = 16; j < 112; j += step)
+ {
+ a[i] = j / 2 + 8;
+ i += 4;
+ }
+ return i;
+}
+
+__attribute__((noinline, noclone)) int
+f16 (int i, long long int step)
+{
+ #pragma omp parallel for linear (i: 4) schedule(dynamic, 3)
+ for (int j = 16; j < 112; j += step)
+ {
+ a[i] = j / 2 + 8;
+ i += 4;
+ }
+ return i;
+}
+
+__attribute__((noinline, noclone)) short int
+f17 (short int i, char k, int step)
+{
+ #pragma omp parallel for linear (i: k + 1) schedule(dynamic, 5)
+ for (long j = 16; j < 112; j += step)
+ {
+ a[i] = j / 2 + 8;
+ i += 4;
+ }
+ return i;
+}
+
+__attribute__((noinline, noclone)) long long int
+f18 (long long int i, long long int k, long int step)
+{
+ #pragma omp parallel for linear (i: k) schedule(dynamic, 7)
+ for (short j = 16; j < 112; j += step)
+ {
+ a[i] = j / 2 + 8;
+ i += 4;
+ }
+ return i;
+}
+
+int
+main ()
+{
+#define TEST(x) \
+ if (x != 8 + 48 * 4) \
+ __builtin_abort (); \
+ for (int i = 0; i < 256; i++) \
+ if (a[i] != (((i & 3) == 0 && i >= 8 \
+ && i < 8 + 48 * 4) \
+ ? ((i - 8) / 4) + 16 : 0)) \
+ __builtin_abort (); \
+ __builtin_memset (a, 0, sizeof (a))
+ TEST (f1 (8));
+ TEST (f2 (8, 3));
+ TEST (f3 (8LL, 4LL));
+ TEST (f4 (8));
+ TEST (f5 (8, 3));
+ TEST (f6 (8LL, 4LL));
+ TEST (f7 (8));
+ TEST (f8 (8, 3));
+ TEST (f9 (8LL, 4LL));
+ TEST (f10 (8, 2));
+ TEST (f11 (8, 3, 2));
+ TEST (f12 (8LL, 4LL, 2));
+ TEST (f13 (8, 2));
+ TEST (f14 (8, 3, 2));
+ TEST (f15 (8LL, 4LL, 2));
+ TEST (f16 (8, 2));
+ TEST (f17 (8, 3, 2));
+ TEST (f18 (8LL, 4LL, 2));
+ return 0;
+}
--- /dev/null
+extern
+#ifdef __cplusplus
+"C"
+#endif
+void abort (void);
+
+void
+foo (int i, char *j)
+{
+ #pragma omp atomic
+ j[i]++;
+ #pragma omp ordered threads
+ {
+ int t;
+ #pragma omp atomic read
+ t = j[i];
+ if (t != 3)
+ abort ();
+ if (i > 1)
+ {
+ #pragma omp atomic read
+ t = j[i - 1];
+ if (t == 2)
+ abort ();
+ }
+ if (i < 127)
+ {
+ #pragma omp atomic read
+ t = j[i + 1];
+ if (t == 4)
+ abort ();
+ }
+ }
+ #pragma omp atomic
+ j[i]++;
+}
+
+int
+main ()
+{
+ int i;
+ char j[128];
+ #pragma omp parallel
+ {
+ #pragma omp for
+ for (i = 0; i < 128; i++)
+ j[i] = 0;
+ #pragma omp for ordered schedule(dynamic, 1)
+ for (i = 0; i < 128; i++)
+ {
+ #pragma omp atomic
+ j[i]++;
+ #pragma omp ordered threads
+ {
+ int t;
+ #pragma omp atomic read
+ t = j[i];
+ if (t != 1)
+ abort ();
+ if (i > 1)
+ {
+ #pragma omp atomic read
+ t = j[i - 1];
+ if (t == 0)
+ abort ();
+ }
+ if (i < 127)
+ {
+ #pragma omp atomic read
+ t = j[i + 1];
+ if (t == 2)
+ abort ();
+ }
+ }
+ #pragma omp atomic
+ j[i]++;
+ }
+ #pragma omp for ordered schedule(static, 1)
+ for (i = 0; i < 128; i++)
+ foo (i, j);
+ }
+ return 0;
+}
f2 (long a, long b, long c)
{
long d, e;
- #pragma omp target teams distribute parallel for simd default(none) firstprivate (a, b) shared(u, v, w) linear(d) linear(c:5) lastprivate(e)
+ #pragma omp target teams distribute parallel for simd default(none) firstprivate (a, b, c) shared(u, v, w) linear(d) lastprivate(e)
for (d = a; d < b; d++)
{
u[d] = v[d] + w[d];
- c += 5;
- e = c;
+ e = c + d * 5;
}
}
--- /dev/null
+/* PR middle-end/66199 */
+/* { dg-do run } */
+/* { dg-options "-O2 -fopenmp" } */
+
+int u[1024], v[1024], w[1024];
+
+__attribute__((noinline, noclone)) long
+f1 (long a, long b)
+{
+ long d;
+ #pragma omp parallel for lastprivate (d) default(none) firstprivate (a, b) shared(u, v, w)
+ for (d = a; d < b; d++)
+ u[d] = v[d] + w[d];
+ return d;
+}
+
+__attribute__((noinline, noclone)) long
+f2 (long a, long b, long c)
+{
+ long d, e;
+ #pragma omp parallel for lastprivate (d) default(none) firstprivate (a, b) shared(u, v, w) linear(c:5) lastprivate(e)
+ for (d = a; d < b; d++)
+ {
+ u[d] = v[d] + w[d];
+ c += 5;
+ e = c;
+ }
+ return d + c + e;
+}
+
+__attribute__((noinline, noclone)) long
+f3 (long a1, long b1, long a2, long b2)
+{
+ long d1, d2;
+ #pragma omp parallel for default(none) firstprivate (a1, b1, a2, b2) shared(u, v, w) lastprivate(d1, d2) collapse(2)
+ for (d1 = a1; d1 < b1; d1++)
+ for (d2 = a2; d2 < b2; d2++)
+ u[d1 * 32 + d2] = v[d1 * 32 + d2] + w[d1 * 32 + d2];
+ return d1 + d2;
+}
+
+int
+main ()
+{
+ if (f1 (0, 1024) != 1024
+ || f2 (0, 1024, 17) != 1024 + 2 * (17 + 5 * 1024)
+ || f3 (0, 32, 0, 32) != 64)
+ __builtin_abort ();
+ return 0;
+}
--- /dev/null
+/* PR middle-end/66199 */
+/* { dg-do run } */
+/* { dg-options "-O2 -fopenmp" } */
+
+#pragma omp declare target
+int u[1024], v[1024], w[1024];
+#pragma omp end declare target
+
+__attribute__((noinline, noclone)) void
+f1 (long a, long b)
+{
+ long d;
+ #pragma omp target teams distribute parallel for default(none) firstprivate (a, b) shared(u, v, w)
+ for (d = a; d < b; d++)
+ u[d] = v[d] + w[d];
+}
+
+__attribute__((noinline, noclone)) void
+f2 (long a, long b, long c)
+{
+ long d, e;
+ #pragma omp target teams distribute parallel for default(none) firstprivate (a, b, c) shared(u, v, w) lastprivate(d, e)
+ for (d = a; d < b; d++)
+ {
+ u[d] = v[d] + w[d];
+ e = c + d * 5;
+ }
+}
+
+__attribute__((noinline, noclone)) void
+f3 (long a1, long b1, long a2, long b2)
+{
+ long d1, d2;
+ #pragma omp target teams distribute parallel for default(none) firstprivate (a1, b1, a2, b2) shared(u, v, w) lastprivate(d1, d2) collapse(2)
+ for (d1 = a1; d1 < b1; d1++)
+ for (d2 = a2; d2 < b2; d2++)
+ u[d1 * 32 + d2] = v[d1 * 32 + d2] + w[d1 * 32 + d2];
+}
+
+__attribute__((noinline, noclone)) void
+f4 (long a1, long b1, long a2, long b2)
+{
+ long d1, d2;
+ #pragma omp target teams distribute parallel for default(none) firstprivate (a1, b1, a2, b2) shared(u, v, w) collapse(2)
+ for (d1 = a1; d1 < b1; d1++)
+ for (d2 = a2; d2 < b2; d2++)
+ u[d1 * 32 + d2] = v[d1 * 32 + d2] + w[d1 * 32 + d2];
+}
+
+int
+main ()
+{
+ f1 (0, 1024);
+ f2 (0, 1024, 17);
+ f3 (0, 32, 0, 32);
+ f4 (0, 32, 0, 32);
+ return 0;
+}
--- /dev/null
+struct A { int t; };
+struct B { char t; };
+struct C { unsigned long long t; };
+struct D { long t; };
+void
+add (struct B *x, struct B *y)
+{
+ x->t += y->t;
+}
+void
+zero (struct B *x)
+{
+ x->t = 0;
+}
+void
+orit (struct C *x, struct C *y)
+{
+ y->t |= x->t;
+}
+#pragma omp declare reduction(+:struct A:omp_out.t += omp_in.t)
+#pragma omp declare reduction(+:struct B:add (&omp_out, &omp_in)) initializer(zero (&omp_priv))
+#pragma omp declare reduction(*:struct A:omp_out.t *= omp_in.t) initializer(omp_priv = { 1 })
+#pragma omp declare reduction(|:struct C:orit (&omp_in, &omp_out))
+#pragma omp declare reduction(&:struct D:omp_out.t = omp_out.t & omp_in.t) initializer(omp_priv = { ~0L })
+#pragma omp declare reduction(maxb:short:omp_out = omp_in > omp_out ? omp_in : omp_out) initializer(omp_priv = -6)
+
+struct B z[10];
+
+__attribute__((noinline, noclone)) void
+foo (struct A (*x)[3][2], struct A *y, struct D w[1][2], int p1, long p2, long p3, int p4,
+ int p5, long p6, short p7)
+{
+ struct C a[p7 + 4];
+ short b[p7];
+ int i;
+ for (i = 0; i < p7 + 4; i++)
+ {
+ if (i < p7)
+ b[i] = -6;
+ a[i].t = 0;
+ }
+ #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2], z[:p3]) \
+ reduction(*:y[:p4]) reduction(|:a[:p5]) \
+ reduction(&:w[0:p6 - 1][:p6]) reduction(maxb:b)
+ for (i = 0; i < 128; i++)
+ {
+ x[i / 64][i % 3][(i / 4) & 1].t += i;
+ if ((i & 15) == 1)
+ y[0].t *= 3;
+ if ((i & 31) == 2)
+ y[1].t *= 7;
+ if ((i & 63) == 3)
+ y[2].t *= 17;
+ z[i / 32].t += (i & 3);
+ if (i < 4)
+ z[i].t += i;
+ a[i / 32].t |= 1ULL << (i & 30);
+ w[0][i & 1].t &= ~(1L << (i / 17 * 3));
+ if ((i % 79) > b[0])
+ b[0] = i % 79;
+ if ((i % 13) > b[1])
+ b[1] = i % 13;
+ if ((i % 23) > b[2])
+ b[2] = i % 23;
+ if ((i % 85) > b[3])
+ b[3] = i % 85;
+ if ((i % 192) > b[4])
+ b[4] = i % 192;
+ }
+ for (i = 0; i < 9; i++)
+ if (a[i].t != (i < 4 ? 0x55555555ULL : 0))
+ __builtin_abort ();
+ if (b[0] != 78 || b[1] != 12 || b[2] != 22 || b[3] != 84 || b[4] != 127)
+ __builtin_abort ();
+}
+
+int
+main ()
+{
+ struct A a[4][3][2] = {};
+ static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }},
+ {{ 312, 381 }, { 295, 356 }, { 337, 335 }},
+ {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }},
+ {{ 0, 0 }, { 0, 0 }, { 0, 0 }}};
+ struct A y[5] = { { 0 }, { 1 }, { 1 }, { 1 }, { 0 } };
+ int y2[5] = { 0, 6561, 2401, 289, 0 };
+ char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 };
+ struct D w[1][2] = { { { ~0L }, { ~0L } } };
+ foo (&a[1], y + 1, w, 1, 3L, 4L, 3, 4, 2L, 5);
+ int i, j, k;
+ for (i = 0; i < 4; i++)
+ for (j = 0; j < 3; j++)
+ for (k = 0; k < 2; k++)
+ if (a[i][j][k].t != a2[i][j][k])
+ __builtin_abort ();
+ for (i = 0; i < 5; i++)
+ if (y[i].t != y2[i])
+ __builtin_abort ();
+ for (i = 0; i < 10; i++)
+ if (z[i].t != z2[i])
+ __builtin_abort ();
+ if (w[0][0].t != ~0x249249L || w[0][1].t != ~0x249249L)
+ __builtin_abort ();
+ return 0;
+}
--- /dev/null
+char z[10] = { 0 };
+
+__attribute__((noinline, noclone)) void
+foo (int (*x)[3][2], int *y, long w[1][2])
+{
+ unsigned long long a[9] = {};
+ short b[5] = {};
+ int i;
+ #pragma omp parallel for reduction(+:x[0:2][:][0:2], z[:4]) \
+ reduction(*:y[:3]) reduction(|:a[:4]) \
+ reduction(&:w[0:1][:2]) reduction(max:b)
+ for (i = 0; i < 128; i++)
+ {
+ x[i / 64][i % 3][(i / 4) & 1] += i;
+ if ((i & 15) == 1)
+ y[0] *= 3;
+ if ((i & 31) == 2)
+ y[1] *= 7;
+ if ((i & 63) == 3)
+ y[2] *= 17;
+ z[i / 32] += (i & 3);
+ if (i < 4)
+ z[i] += i;
+ a[i / 32] |= 1ULL << (i & 30);
+ w[0][i & 1] &= ~(1L << (i / 17 * 3));
+ if ((i % 79) > b[0])
+ b[0] = i % 79;
+ if ((i % 13) > b[1])
+ b[1] = i % 13;
+ if ((i % 23) > b[2])
+ b[2] = i % 23;
+ if ((i % 85) > b[3])
+ b[3] = i % 85;
+ if ((i % 192) > b[4])
+ b[4] = i % 192;
+ }
+ for (i = 0; i < 9; i++)
+ if (a[i] != (i < 4 ? 0x55555555ULL : 0))
+ __builtin_abort ();
+ if (b[0] != 78 || b[1] != 12 || b[2] != 22 || b[3] != 84 || b[4] != 127)
+ __builtin_abort ();
+}
+
+int
+main ()
+{
+ int a[4][3][2] = {};
+ static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }},
+ {{ 312, 381 }, { 295, 356 }, { 337, 335 }},
+ {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }},
+ {{ 0, 0 }, { 0, 0 }, { 0, 0 }}};
+ int y[5] = { 0, 1, 1, 1, 0 };
+ int y2[5] = { 0, 6561, 2401, 289, 0 };
+ char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 };
+ long w[1][2] = { ~0L, ~0L };
+ foo (&a[1], y + 1, w);
+ if (__builtin_memcmp (a, a2, sizeof (a))
+ || __builtin_memcmp (y, y2, sizeof (y))
+ || __builtin_memcmp (z, z2, sizeof (z))
+ || w[0][0] != ~0x249249L
+ || w[0][1] != ~0x249249L)
+ __builtin_abort ();
+ return 0;
+}
--- /dev/null
+struct A { int t; };
+struct B { char t; };
+struct C { unsigned long long t; };
+struct D { long t; };
+void
+add (struct B *x, struct B *y)
+{
+ x->t += y->t;
+}
+void
+zero (struct B *x)
+{
+ x->t = 0;
+}
+void
+orit (struct C *x, struct C *y)
+{
+ y->t |= x->t;
+}
+#pragma omp declare reduction(+:struct A:omp_out.t += omp_in.t)
+#pragma omp declare reduction(+:struct B:add (&omp_out, &omp_in)) initializer(zero (&omp_priv))
+#pragma omp declare reduction(*:struct A:omp_out.t *= omp_in.t) initializer(omp_priv = { 1 })
+#pragma omp declare reduction(|:struct C:orit (&omp_in, &omp_out))
+#pragma omp declare reduction(&:struct D:omp_out.t = omp_out.t & omp_in.t) initializer(omp_priv = { ~0L })
+#pragma omp declare reduction(maxb:short:omp_out = omp_in > omp_out ? omp_in : omp_out) initializer(omp_priv = -6)
+
+struct B z[10];
+
+__attribute__((noinline, noclone)) void
+foo (struct A (*x)[3][2], struct A *y, struct D w[1][2])
+{
+ struct C a[9] = {};
+ short b[5] = {};
+ int i;
+ #pragma omp parallel for reduction(+:x[0:2][:][0:2], z[:4]) \
+ reduction(*:y[:3]) reduction(|:a[:4]) \
+ reduction(&:w[0:1][:2]) reduction(maxb:b)
+ for (i = 0; i < 128; i++)
+ {
+ x[i / 64][i % 3][(i / 4) & 1].t += i;
+ if ((i & 15) == 1)
+ y[0].t *= 3;
+ if ((i & 31) == 2)
+ y[1].t *= 7;
+ if ((i & 63) == 3)
+ y[2].t *= 17;
+ z[i / 32].t += (i & 3);
+ if (i < 4)
+ z[i].t += i;
+ a[i / 32].t |= 1ULL << (i & 30);
+ w[0][i & 1].t &= ~(1L << (i / 17 * 3));
+ if ((i % 79) > b[0])
+ b[0] = i % 79;
+ if ((i % 13) > b[1])
+ b[1] = i % 13;
+ if ((i % 23) > b[2])
+ b[2] = i % 23;
+ if ((i % 85) > b[3])
+ b[3] = i % 85;
+ if ((i % 192) > b[4])
+ b[4] = i % 192;
+ }
+ for (i = 0; i < 9; i++)
+ if (a[i].t != (i < 4 ? 0x55555555ULL : 0))
+ __builtin_abort ();
+ if (b[0] != 78 || b[1] != 12 || b[2] != 22 || b[3] != 84 || b[4] != 127)
+ __builtin_abort ();
+}
+
+int
+main ()
+{
+ struct A a[4][3][2] = {};
+ static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }},
+ {{ 312, 381 }, { 295, 356 }, { 337, 335 }},
+ {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }},
+ {{ 0, 0 }, { 0, 0 }, { 0, 0 }}};
+ struct A y[5] = { { 0 }, { 1 }, { 1 }, { 1 }, { 0 } };
+ int y2[5] = { 0, 6561, 2401, 289, 0 };
+ char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 };
+ struct D w[1][2] = { { { ~0L }, { ~0L } } };
+ foo (&a[1], y + 1, w);
+ int i, j, k;
+ for (i = 0; i < 4; i++)
+ for (j = 0; j < 3; j++)
+ for (k = 0; k < 2; k++)
+ if (a[i][j][k].t != a2[i][j][k])
+ __builtin_abort ();
+ for (i = 0; i < 5; i++)
+ if (y[i].t != y2[i])
+ __builtin_abort ();
+ for (i = 0; i < 10; i++)
+ if (z[i].t != z2[i])
+ __builtin_abort ();
+ if (w[0][0].t != ~0x249249L || w[0][1].t != ~0x249249L)
+ __builtin_abort ();
+ return 0;
+}
--- /dev/null
+char z[10] = { 0 };
+
+__attribute__((noinline, noclone)) void
+foo (int (*x)[3][2], int *y, long w[1][2], int p1, long p2, long p3, int p4,
+ int p5, long p6, short p7)
+{
+ unsigned long long a[p7 + 4];
+ short b[p7];
+ int i;
+ for (i = 0; i < p7 + 4; i++)
+ {
+ if (i < p7)
+ b[i] = -6;
+ a[i] = 0;
+ }
+ #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2], z[:p3]) \
+ reduction(*:y[:p4]) reduction(|:a[:p5]) \
+ reduction(&:w[0:p6 - 1][:p6]) reduction(max:b)
+ for (i = 0; i < 128; i++)
+ {
+ x[i / 64][i % 3][(i / 4) & 1] += i;
+ if ((i & 15) == 1)
+ y[0] *= 3;
+ if ((i & 31) == 2)
+ y[1] *= 7;
+ if ((i & 63) == 3)
+ y[2] *= 17;
+ z[i / 32] += (i & 3);
+ if (i < 4)
+ z[i] += i;
+ a[i / 32] |= 1ULL << (i & 30);
+ w[0][i & 1] &= ~(1L << (i / 17 * 3));
+ if ((i % 79) > b[0])
+ b[0] = i % 79;
+ if ((i % 13) > b[1])
+ b[1] = i % 13;
+ if ((i % 23) > b[2])
+ b[2] = i % 23;
+ if ((i % 85) > b[3])
+ b[3] = i % 85;
+ if ((i % 192) > b[4])
+ b[4] = i % 192;
+ }
+ for (i = 0; i < 9; i++)
+ if (a[i] != (i < 4 ? 0x55555555ULL : 0))
+ __builtin_abort ();
+ if (b[0] != 78 || b[1] != 12 || b[2] != 22 || b[3] != 84 || b[4] != 127)
+ __builtin_abort ();
+}
+
+int
+main ()
+{
+ int a[4][3][2] = {};
+ static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }},
+ {{ 312, 381 }, { 295, 356 }, { 337, 335 }},
+ {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }},
+ {{ 0, 0 }, { 0, 0 }, { 0, 0 }}};
+ int y[5] = { 0, 1, 1, 1, 0 };
+ int y2[5] = { 0, 6561, 2401, 289, 0 };
+ char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 };
+ long w[1][2] = { ~0L, ~0L };
+ foo (&a[1], y + 1, w, 1, 3L, 4L, 3, 4, 2L, 5);
+ if (__builtin_memcmp (a, a2, sizeof (a))
+ || __builtin_memcmp (y, y2, sizeof (y))
+ || __builtin_memcmp (z, z2, sizeof (z))
+ || w[0][0] != ~0x249249L
+ || w[0][1] != ~0x249249L)
+ __builtin_abort ();
+ return 0;
+}
fn1 (b, c, x);
#pragma omp target data map(to: b)
{
- #pragma omp target map(tofrom: c)
+ #pragma omp target map(tofrom: c, s)
#pragma omp teams num_teams(y) thread_limit(z) reduction(+:s) firstprivate(x)
#pragma omp distribute dist_schedule(static, 4) collapse(1)
for (j=0; j < x; j += y)
double b[1024], c[1024], s = 0;
int i;
fn1 (b, c, x);
- #pragma omp target map(to: b, c)
+ #pragma omp target map(to: b, c) map(tofrom:s)
#pragma omp parallel for reduction(+:s)
for (i = 0; i < x; i++)
tgt (), s += b[i] * c[i];
int i;
fn1 (b, c, x);
fn1 (d + x, p + x, x);
- #pragma omp target map(to: b, c[0:x], d[x:x]) map(to:p[x:64 + (x & 31)])
+ #pragma omp target map(to: b, c[0:x], d[x:x]) map(to:p[x:64 + (x & 31)]) \
+ map(tofrom: s)
#pragma omp parallel for reduction(+:s)
for (i = 0; i < x; i++)
s += b[i] * c[i] + d[x + i] + p[x + i];
--- /dev/null
+/* { dg-require-effective-target offload_device_nonshared_as } */
+
+#include <stdlib.h>
+#include <assert.h>
+
+#define N 32
+
+void test_array_section (int *p)
+{
+ #pragma omp target data map(alloc: p[0:N])
+ {
+ int ok = 1;
+ for (int i = 10; i < 10 + 4; i++)
+ p[i] = 997 * i;
+
+ #pragma omp target map(always to:p[10:4]) map(tofrom: ok)
+ for (int i = 10; i < 10 + 4; i++)
+ if (p[i] != 997 * i)
+ ok = 0;
+
+ assert (ok);
+
+ #pragma omp target map(always from:p[7:9])
+ for (int i = 0; i < N; i++)
+ p[i] = i;
+ }
+}
+
+int main ()
+{
+ int aa = 0, bb = 0, cc = 0, dd = 0;
+
+ #pragma omp target data map(tofrom: aa) map(to: bb) map(from: cc, dd)
+ {
+ int ok;
+ aa = bb = cc = 1;
+
+ /* Set dd on target to 0 for the further check. */
+ #pragma omp target map(always to: dd)
+ ;
+
+ dd = 1;
+ #pragma omp target map(tofrom: aa) map(always to: bb) \
+ map(always from: cc) map(to: dd) map(from: ok)
+ {
+ /* bb is always to, aa and dd are not. */
+ ok = (aa == 0) && (bb == 1) && (dd == 0);
+ aa = bb = cc = dd = 2;
+ }
+
+ assert (ok);
+ assert (aa == 1);
+ assert (bb == 1);
+ assert (cc == 2); /* cc is always from. */
+ assert (dd == 1);
+
+ dd = 3;
+ #pragma omp target map(from: cc) map(always to: dd) map(from: ok)
+ {
+ ok = (dd == 3); /* dd is always to. */
+ cc = dd = 4;
+ }
+
+ assert (ok);
+ assert (cc == 2);
+ assert (dd == 3);
+ }
+
+ assert (aa == 2);
+ assert (bb == 1);
+ assert (cc == 4);
+ assert (dd == 4);
+
+ int *array = calloc (N, sizeof (int));
+ test_array_section (array);
+
+ for (int i = 0; i < 7; i++)
+ assert (array[i] == 0);
+ for (int i = 7; i < 7 + 9; i++)
+ assert (array[i] == i);
+ for (int i = 7 + 9; i < N; i++)
+ assert (array[i] == 0);
+
+ free (array);
+ return 0;
+}
--- /dev/null
+#include <omp.h>
+#include <stdlib.h>
+
+int
+main ()
+{
+ int d = omp_get_default_device ();
+ int id = omp_get_initial_device ();
+ int err;
+ int q[128], i;
+ void *p;
+
+ if (d < 0 || d >= omp_get_num_devices ())
+ d = id;
+
+ for (i = 0; i < 128; i++)
+ q[i] = i;
+
+ p = omp_target_alloc (130 * sizeof (int), d);
+ if (p == NULL)
+ return 0;
+
+ if (omp_target_memcpy_rect (NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL,
+ d, id) < 3
+ || omp_target_memcpy_rect (NULL, NULL, 0, 0, NULL, NULL, NULL, NULL,
+ NULL, id, d) < 3
+ || omp_target_memcpy_rect (NULL, NULL, 0, 0, NULL, NULL, NULL, NULL,
+ NULL, id, id) < 3)
+ abort ();
+
+ if (omp_target_associate_ptr (q, p, 128 * sizeof (int), sizeof (int), d) == 0)
+ {
+ size_t volume[3] = { 128, 0, 0 };
+ size_t dst_offsets[3] = { 0, 0, 0 };
+ size_t src_offsets[3] = { 1, 0, 0 };
+ size_t dst_dimensions[3] = { 128, 0, 0 };
+ size_t src_dimensions[3] = { 128, 0, 0 };
+
+ if (omp_target_associate_ptr (q, p, 128 * sizeof (int), sizeof (int), d) != 0)
+ abort ();
+
+ if (omp_target_is_present (q, d) != 1
+ || omp_target_is_present (&q[32], d) != 1
+ || omp_target_is_present (&q[128], d) != 1)
+ abort ();
+
+ if (omp_target_memcpy (p, q, 128 * sizeof (int), sizeof (int), 0,
+ d, id) != 0)
+ abort ();
+
+ #pragma omp target if (d >= 0) device (d >= 0 ? d : 0) map(alloc:q[0:32]) map(from:err)
+ {
+ int j;
+ err = 0;
+ for (j = 0; j < 128; j++)
+ if (q[j] != j)
+ err = 1;
+ else
+ q[j] += 4;
+ }
+
+ if (err)
+ abort ();
+
+ if (omp_target_memcpy_rect (q, p, sizeof (int), 1, volume,
+ dst_offsets, src_offsets, dst_dimensions,
+ src_dimensions, id, d) != 0)
+ abort ();
+
+ for (i = 0; i < 128; i++)
+ if (q[i] != i + 4)
+ abort ();
+
+ volume[2] = 2;
+ volume[1] = 3;
+ volume[0] = 6;
+ dst_offsets[2] = 1;
+ dst_offsets[1] = 0;
+ dst_offsets[0] = 0;
+ src_offsets[2] = 1;
+ src_offsets[1] = 0;
+ src_offsets[0] = 3;
+ dst_dimensions[2] = 2;
+ dst_dimensions[1] = 3;
+ dst_dimensions[0] = 6;
+ src_dimensions[2] = 3;
+ src_dimensions[1] = 4;
+ src_dimensions[0] = 6;
+ if (omp_target_memcpy_rect (p, q, sizeof (int), 3, volume,
+ dst_offsets, src_offsets, dst_dimensions,
+ src_dimensions, d, id) != 0)
+ abort ();
+
+ #pragma omp target if (d >= 0) device (d >= 0 ? d : 0) map(alloc:q[0:32]) map(from:err)
+ {
+ int j, k, l;
+ err = 0;
+ for (j = 0; j < 6; j++)
+ for (k = 0; k < 3; k++)
+ for (l = 0; l < 2; l++)
+ if (q[j * 6 + k * 2 + l] != 3 * 12 + 4 + 1 + l + k * 3 + j * 12)
+ err = 1;
+ }
+
+ if (err)
+ abort ();
+
+ if (omp_target_memcpy (p, p, 10 * sizeof (int), 51 * sizeof (int),
+ 111 * sizeof (int), d, d) != 0)
+ abort ();
+
+ #pragma omp target if (d >= 0) device (d >= 0 ? d : 0) map(alloc:q[0:32]) map(from:err)
+ {
+ int j;
+ err = 0;
+ for (j = 0; j < 10; j++)
+ if (q[50 + j] != q[110 + j])
+ err = 1;
+ }
+
+ if (err)
+ abort ();
+
+ if (omp_target_disassociate_ptr (q, d) != 0)
+ abort ();
+ }
+
+ omp_target_free (p, d);
+ return 0;
+}
--- /dev/null
+#ifdef __cplusplus
+extern "C"
+#else
+extern
+#endif
+void abort (void);
+struct S { int s, t; };
+
+void
+foo ()
+{
+ int x = 5, y = 6, err = 0;
+ struct S u = { 7, 8 }, v = { 9, 10 };
+ double s = 11.5, t = 12.5;
+ #pragma omp target private (x, u, s) firstprivate (y, v, t) map(from:err)
+ {
+ x = y;
+ u = v;
+ s = t;
+ err = (x != 6 || y != 6
+ || u.s != 9 || u.t != 10 || v.s != 9 || v.t != 10
+ || s != 12.5 || t != 12.5);
+ x += 1;
+ y += 2;
+ u.s += 3;
+ v.t += 4;
+ s += 2.5;
+ t += 3.0;
+ if (x != 7 || y != 8
+ || u.s != 12 || u.t != 10 || v.s != 9 || v.t != 14
+ || s != 15.0 || t != 15.5)
+ err = 1;
+ }
+ if (err || x != 5 || y != 6
+ || u.s != 7 || u.t != 8 || v.s != 9 || v.t != 10
+ || s != 11.5 || t != 12.5)
+ abort ();
+}
+
+int
+main ()
+{
+ foo ();
+ return 0;
+}
--- /dev/null
+#include <omp.h>
+#include <stdlib.h>
+
+int
+main ()
+{
+ int d = omp_get_default_device ();
+ int id = omp_get_initial_device ();
+ int err;
+ void *p;
+
+ if (d < 0 || d >= omp_get_num_devices ())
+ d = id;
+
+ p = omp_target_alloc (128 * sizeof (int), d);
+ if (p == NULL)
+ return 0;
+
+ #pragma omp target is_device_ptr (p) if (d >= 0) device (d >= 0 ? d : 0)
+ {
+ int i, *q = (int *) p;
+ for (i = 0; i < 128; i++)
+ q[i] = i + 7;
+ }
+ #pragma omp target is_device_ptr (p) if (d >= 0) device (d >= 0 ? d : 0) map(from:err)
+ {
+ int i;
+ err = 0;
+ for (i = 0; i < 128; i++)
+ if (((int *) p)[i] != i + 7)
+ err = 1;
+ }
+ if (err)
+ abort ();
+
+ omp_target_free (p, d);
+ return 0;
+}
--- /dev/null
+extern void abort (void);
+
+void
+foo (int *x)
+{
+ int a[10], b[15], err, i;
+ for (i = 0; i < 10; i++)
+ a[i] = 7 * i;
+ for (i = 0; i < 15; i++)
+ b[i] = 8 * i;
+ #pragma omp target map(to:x[5:10], a[0:10], b[5:10]) map(from:err)
+ {
+ err = 0;
+ for (i = 0; i < 10; i++)
+ if (x[5 + i] != 20 + 4 * i
+ || a[i] != 7 * i
+ || b[5 + i] != 40 + 8 * i)
+ err = 1;
+ }
+ if (err)
+ abort ();
+}
+
+void
+bar (int n, int v)
+{
+ int a[n], b[n], c[n], d[n], e[n], err, i;
+ int (*x)[n] = &c;
+ for (i = 0; i < n; i++)
+ {
+ (*x)[i] = 4 * i;
+ a[i] = 7 * i;
+ b[i] = 8 * i;
+ }
+ #pragma omp target map(to:x[0][5:10], a[0:10], b[5:10]) map(from:err)
+ {
+ err = 0;
+ for (i = 0; i < 10; i++)
+ if ((*x)[5 + i] != 20 + 4 * i
+ || a[i] != 7 * i
+ || b[5 + i] != 40 + 8 * i)
+ err = 1;
+ }
+ if (err)
+ abort ();
+ for (i = 0; i < n; i++)
+ {
+ (*x)[i] = 9 * i;
+ a[i] = 12 * i;
+ b[i] = 13 * i;
+ }
+ #pragma omp target map(to:x[0][v:v+5], a[v-5:v+5], b[v:v+5]) map(from:err)
+ {
+ err = 0;
+ for (i = 0; i < 10; i++)
+ if ((*x)[5 + i] != 45 + 9 * i
+ || a[i] != 12 * i
+ || b[5 + i] != 65 + 13 * i)
+ err = 1;
+ }
+ if (err)
+ abort ();
+}
+
+int
+main ()
+{
+ int x[15], i;
+ for (i = 0; i < 15; i++)
+ x[i] = 4 * i;
+ foo (x);
+ bar (15, 5);
+ return 0;
+}
--- /dev/null
+extern void abort (void);
+
+void
+foo (int n)
+{
+ int a[n], i, err;
+ for (i = 0; i < n; i++)
+ a[i] = 7 * i;
+ #pragma omp target firstprivate (a) map(from:err) private (i)
+ {
+ err = 0;
+ for (i = 0; i < n; i++)
+ if (a[i] != 7 * i)
+ err = 1;
+ }
+ if (err)
+ abort ();
+}
+
+void
+bar (int n)
+{
+ int a[n], i, err;
+ #pragma omp target private (a) map(from:err)
+ {
+ #pragma omp parallel for
+ for (i = 0; i < n; i++)
+ a[i] = 7 * i;
+ err = 0;
+ #pragma omp parallel for reduction(|:err)
+ for (i = 0; i < n; i++)
+ if (a[i] != 7 * i)
+ err |= 1;
+ }
+ if (err)
+ abort ();
+}
+
+int
+main ()
+{
+ foo (7);
+ bar (7);
+ return 0;
+}
--- /dev/null
+extern void abort (void);
+
+void
+foo (int n)
+{
+ int a[n], i, err;
+ for (i = 0; i < n; i++)
+ a[i] = 5 * i;
+ #pragma omp target map(to:a) map(from:err) private(i)
+ {
+ err = 0;
+ for (i = 0; i < n; i++)
+ if (a[i] != 5 * i)
+ err = 1;
+ }
+ if (err)
+ abort ();
+ for (i = 0; i < n; i++)
+ a[i] += i;
+ #pragma omp target map(from:err) private(i)
+ {
+ err = 0;
+ for (i = 0; i < n; i++)
+ if (a[i] != 6 * i)
+ err = 1;
+ }
+ if (err)
+ abort ();
+ for (i = 0; i < n; i++)
+ a[i] += i;
+ #pragma omp target firstprivate (a) map(from:err) private(i)
+ {
+ err = 0;
+ for (i = 0; i < n; i++)
+ if (a[i] != 7 * i)
+ err = 1;
+ }
+ if (err)
+ abort ();
+ int on = n;
+ #pragma omp target firstprivate (n) map(tofrom: n)
+ {
+ n++;
+ }
+ if (on != n)
+ abort ();
+ #pragma omp target map(tofrom: n) private (n)
+ {
+ n = 25;
+ }
+ if (on != n)
+ abort ();
+ for (i = 0; i < n; i++)
+ a[i] += i;
+ #pragma omp target map(to:a) firstprivate (a) map(from:err) private(i)
+ {
+ err = 0;
+ for (i = 0; i < n; i++)
+ if (a[i] != 8 * i)
+ err = 1;
+ }
+ if (err)
+ abort ();
+ for (i = 0; i < n; i++)
+ a[i] += i;
+ #pragma omp target firstprivate (a) map(to:a) map(from:err) private(i)
+ {
+ err = 0;
+ for (i = 0; i < n; i++)
+ if (a[i] != 9 * i)
+ err = 1;
+ }
+ if (err)
+ abort ();
+ for (i = 0; i < n; i++)
+ a[i] += i;
+ #pragma omp target map(tofrom:a) map(from:err) private(a, i)
+ {
+ err = 0;
+ for (i = 0; i < n; i++)
+ a[i] = 7;
+ #pragma omp parallel for reduction(|:err)
+ for (i = 0; i < n; i++)
+ if (a[i] != 7)
+ err |= 1;
+ }
+ if (err)
+ abort ();
+ for (i = 0; i < n; i++)
+ if (a[i] != 10 * i)
+ abort ();
+}
+
+int
+main ()
+{
+ foo (9);
+ return 0;
+}
--- /dev/null
+extern void abort (void);
+
+void
+foo (int n)
+{
+ int a[4] = { 0, 1, 2, 3 }, b[n];
+ int *p = a + 1, i, err;
+ for (i = 0; i < n; i++)
+ b[i] = 9 + i;
+ #pragma omp target data map(to:a)
+ #pragma omp target data use_device_ptr(p) map(from:err)
+ #pragma omp target is_device_ptr(p) private(i) map(from:err)
+ {
+ err = 0;
+ for (i = 0; i < 4; i++)
+ if (p[i - 1] != i)
+ err = 1;
+ }
+ if (err)
+ abort ();
+ for (i = 0; i < 4; i++)
+ a[i] = 23 + i;
+ #pragma omp target data map(to:a)
+ #pragma omp target data use_device_ptr(a) map(from:err)
+ #pragma omp target is_device_ptr(a) private(i) map(from:err)
+ {
+ err = 0;
+ for (i = 0; i < 4; i++)
+ if (a[i] != 23 + i)
+ err = 1;
+ }
+ if (err)
+ abort ();
+ #pragma omp target data map(to:b)
+ #pragma omp target data use_device_ptr(b) map(from:err)
+ #pragma omp target is_device_ptr(b) private(i) map(from:err)
+ {
+ err = 0;
+ for (i = 0; i < 4; i++)
+ if (b[i] != 9 + i)
+ err = 1;
+ }
+ if (err)
+ abort ();
+}
+
+int
+main ()
+{
+ foo (9);
+ return 0;
+}
--- /dev/null
+extern void abort (void);
+
+void
+foo (int *p, int *q, int *r, int n, int m)
+{
+ int i, err, *s = r;
+ #pragma omp target data map(to:p[0:8])
+ {
+ /* For zero length array sections, p points to the start of
+ already mapped range, q to the end of it, and r does not point
+ to an mapped range. */
+ #pragma omp target map(alloc:p[:0]) map(to:q[:0]) map(from:r[:0]) private(i) map(from:err) firstprivate (s)
+ {
+ err = 0;
+ for (i = 0; i < 8; i++)
+ if (p[i] != i + 1 || q[i - 8] != i + 1)
+ err = 1;
+ if (p + 8 != q || (r != (int *) 0 && r != s))
+ err = 1;
+ }
+ if (err)
+ abort ();
+ /* Implicit mapping of pointers behaves the same way. */
+ #pragma omp target private(i) map(from:err) firstprivate (s)
+ {
+ err = 0;
+ for (i = 0; i < 8; i++)
+ if (p[i] != i + 1 || q[i - 8] != i + 1)
+ err = 1;
+ if (p + 8 != q || (r != (int *) 0 && r != s))
+ err = 1;
+ }
+ if (err)
+ abort ();
+ /* And zero-length array sections, though not known at compile
+ time, behave the same. */
+ #pragma omp target map(p[:n]) map(tofrom:q[:n]) map(alloc:r[:n]) private(i) map(from:err) firstprivate (s)
+ {
+ err = 0;
+ for (i = 0; i < 8; i++)
+ if (p[i] != i + 1 || q[i - 8] != i + 1)
+ err = 1;
+ if (p + 8 != q || (r != (int *) 0 && r != s))
+ err = 1;
+ }
+ if (err)
+ abort ();
+ /* Non-zero length array sections, though not known at compile,
+ behave differently. */
+ #pragma omp target map(p[:m]) map(tofrom:q[:m]) map(to:r[:m]) private(i) map(from:err)
+ {
+ err = 0;
+ for (i = 0; i < 8; i++)
+ if (p[i] != i + 1)
+ err = 1;
+ if (q[0] != 9 || r[0] != 10)
+ err = 1;
+ }
+ if (err)
+ abort ();
+ #pragma omp target data map(to:q[0:1])
+ {
+ /* For zero length array sections, p points to the start of
+ already mapped range, q points to the start of another one,
+ and r to the end of the second one. */
+ #pragma omp target map(to:p[:0]) map(from:q[:0]) map(tofrom:r[:0]) private(i) map(from:err)
+ {
+ err = 0;
+ for (i = 0; i < 8; i++)
+ if (p[i] != i + 1)
+ err = 1;
+ if (q[0] != 9 || r != q + 1)
+ err = 1;
+ }
+ if (err)
+ abort ();
+ /* Implicit mapping of pointers behaves the same way. */
+ #pragma omp target private(i) map(from:err)
+ {
+ err = 0;
+ for (i = 0; i < 8; i++)
+ if (p[i] != i + 1)
+ err = 1;
+ if (q[0] != 9 || r != q + 1)
+ err = 1;
+ }
+ if (err)
+ abort ();
+ /* And zero-length array sections, though not known at compile
+ time, behave the same. */
+ #pragma omp target map(p[:n]) map(alloc:q[:n]) map(from:r[:n]) private(i) map(from:err)
+ {
+ err = 0;
+ for (i = 0; i < 8; i++)
+ if (p[i] != i + 1)
+ err = 1;
+ if (q[0] != 9 || r != q + 1)
+ err = 1;
+ }
+ if (err)
+ abort ();
+ /* Non-zero length array sections, though not known at compile,
+ behave differently. */
+ #pragma omp target map(p[:m]) map(alloc:q[:m]) map(tofrom:r[:m]) private(i) map(from:err)
+ {
+ err = 0;
+ for (i = 0; i < 8; i++)
+ if (p[i] != i + 1)
+ err = 1;
+ if (q[0] != 9 || r[0] != 10)
+ err = 1;
+ }
+ if (err)
+ abort ();
+ }
+ }
+}
+
+int
+main ()
+{
+ int a[32], i;
+ for (i = 0; i < 32; i++)
+ a[i] = i;
+ foo (a + 1, a + 9, a + 10, 0, 1);
+ return 0;
+}
int i;
fn1 (b, c, x);
fn1 (e, d + x, x);
- #pragma omp target map(to: b, c[:x], d[x:x], e)
+ #pragma omp target map(to: b, c[:x], d[x:x], e) map(tofrom: s)
#pragma omp parallel for reduction(+:s)
for (i = 0; i < x; i++)
s += b[i] * c[i] + d[x + i] + sizeof (b) - sizeof (c);
int i;
fn1 (b, c, x);
fn1 (e, d, x);
- #pragma omp target
+ #pragma omp target map(tofrom: s)
#pragma omp parallel for reduction(+:s)
for (i = 0; i < x; i++)
s += b[i] * c[i] + d[i];
#pragma omp target data map(from: b, c[:x], d[x:x], e)
{
#pragma omp target update to(b, c[:x], d[x:x], e)
- #pragma omp target map(c[:x], d[x:x])
+ #pragma omp target map(c[:x], d[x:x], s)
#pragma omp parallel for reduction(+:s)
for (i = 0; i < x; i++)
{
--- /dev/null
+/* { dg-require-effective-target offload_device_nonshared_as } */
+
+#include <stdlib.h>
+#include <assert.h>
+
+#define N 40
+
+int sum;
+int var1 = 1;
+int var2 = 2;
+
+#pragma omp declare target
+int D[N];
+#pragma omp end declare target
+
+void enter_data (int *X)
+{
+ #pragma omp target enter data map(to: var1, var2, X[:N]) map(alloc: sum)
+}
+
+void exit_data_0 (int *D)
+{
+ #pragma omp target exit data map(delete: D[:N])
+}
+
+void exit_data_1 ()
+{
+ #pragma omp target exit data map(from: var1)
+}
+
+void exit_data_2 (int *X)
+{
+ #pragma omp target exit data map(from: var2) map(release: X[:N], sum)
+}
+
+void exit_data_3 (int *p)
+{
+ #pragma omp target exit data map(from: p[:0])
+}
+
+void test_nested ()
+{
+ int X = 0, Y = 0, Z = 0;
+
+ #pragma omp target data map(from: X, Y, Z)
+ {
+ #pragma omp target data map(from: X, Y, Z)
+ {
+ #pragma omp target map(from: X, Y, Z)
+ X = Y = Z = 1337;
+ assert (X == 0);
+ assert (Y == 0);
+ assert (Z == 0);
+
+ #pragma omp target exit data map(from: X) map(release: Y)
+ assert (X == 0);
+ assert (Y == 0);
+
+ #pragma omp target exit data map(release: Y) map(delete: Z)
+ assert (Y == 0);
+ assert (Z == 0);
+ }
+ assert (X == 1337);
+ assert (Y == 0);
+ assert (Z == 0);
+
+ #pragma omp target map(from: X)
+ X = 2448;
+ assert (X == 2448);
+ assert (Y == 0);
+ assert (Z == 0);
+
+ X = 4896;
+ }
+ assert (X == 4896);
+ assert (Y == 0);
+ assert (Z == 0);
+}
+
+int main ()
+{
+ int *X = malloc (N * sizeof (int));
+ int *Y = malloc (N * sizeof (int));
+ X[10] = 10;
+ Y[20] = 20;
+ enter_data (X);
+
+ exit_data_0 (D); /* This should have no effect on D. */
+
+ #pragma omp target map(alloc: var1, var2, X[:N]) map(to: Y[:N]) map(always from: sum)
+ {
+ var1 += X[10];
+ var2 += Y[20];
+ sum = var1 + var2;
+ D[sum]++;
+ }
+
+ assert (var1 == 1);
+ assert (var2 == 2);
+ assert (sum == 33);
+
+ exit_data_1 ();
+ assert (var1 == 11);
+ assert (var2 == 2);
+
+ /* Increase refcount of already mapped X[0:N]. */
+ #pragma omp target enter data map(alloc: X[16:1])
+
+ exit_data_2 (X);
+ assert (var2 == 22);
+
+ exit_data_3 (X + 5); /* Unmap X[0:N]. */
+
+ free (X);
+ free (Y);
+
+ test_nested ();
+
+ return 0;
+}
--- /dev/null
+extern void abort (void);
+union U { int x; long long y; };
+struct T { int a; union U b; int c; };
+struct S { int s; int u; struct T v; int x[10]; union U w; int y[10]; int z[10]; };
+volatile int z;
+
+int
+main ()
+{
+ struct S s;
+ s.s = 0;
+ s.u = 1;
+ s.v.a = 2;
+ s.v.b.y = 3LL;
+ s.v.c = 19;
+ s.w.x = 4;
+ s.x[0] = 7;
+ s.x[1] = 8;
+ s.y[3] = 9;
+ s.y[4] = 10;
+ s.y[5] = 11;
+ int err = 0;
+ #pragma omp target map (to:s.v.b, s.u, s.x[0:z + 2]) \
+ map (tofrom:s.y[3:3]) \
+ map (from: s.w, s.z[z + 1:z + 3], err)
+ {
+ err = 0;
+ if (s.u != 1 || s.v.b.y != 3LL || s.x[0] != 7 || s.x[1] != 8
+ || s.y[3] != 9 || s.y[4] != 10 || s.y[5] != 11)
+ err = 1;
+ s.w.x = 6;
+ s.y[3] = 12;
+ s.y[4] = 13;
+ s.y[5] = 14;
+ s.z[1] = 15;
+ s.z[2] = 16;
+ s.z[3] = 17;
+ }
+ if (err || s.w.x != 6 || s.y[3] != 12 || s.y[4] != 13 || s.y[5] != 14
+ || s.z[1] != 15 || s.z[2] != 16 || s.z[3] != 17)
+ abort ();
+ s.u++;
+ s.v.a++;
+ s.v.b.y++;
+ s.w.x++;
+ s.x[1] = 18;
+ s.z[0] = 19;
+ #pragma omp target data map (tofrom: s)
+ #pragma omp target map (always to: s.w, s.x[1], err) map (alloc:s.u, s.v.b, s.z[z:z + 1])
+ {
+ err = 0;
+ if (s.u != 2 || s.v.b.y != 4LL || s.w.x != 7 || s.x[1] != 18 || s.z[0] != 19)
+ err = 1;
+ s.w.x = 8;
+ s.x[1] = 20;
+ s.z[0] = 21;
+ }
+ if (err || s.w.x != 8 || s.x[1] != 20 || s.z[0] != 21)
+ abort ();
+ s.u++;
+ s.v.a++;
+ s.v.b.y++;
+ s.w.x++;
+ s.x[0] = 22;
+ s.x[1] = 23;
+ #pragma omp target data map (from: s.w, s.x[0:2]) map (to: s.v.b, s.u)
+ #pragma omp target map (always to: s.w, s.x[0:2], err) map (alloc:s.u, s.v.b)
+ {
+ err = 0;
+ if (s.u != 3 || s.v.b.y != 5LL || s.w.x != 9 || s.x[0] != 22 || s.x[1] != 23)
+ err = 1;
+ s.w.x = 11;
+ s.x[0] = 24;
+ s.x[1] = 25;
+ }
+ if (err || s.w.x != 11 || s.x[0] != 24 || s.x[1] != 25)
+ abort ();
+ return 0;
+}
--- /dev/null
+extern void abort (void);
+struct T { int a; int *b; int c; };
+struct S { int *s; char *u; struct T v; short *w; };
+volatile int z;
+
+int
+main ()
+{
+ struct S s;
+ int a[32], i;
+ char b[32];
+ short c[32];
+ for (i = 0; i < 32; i++)
+ {
+ a[i] = i;
+ b[i] = 32 + i;
+ c[i] = 64 + i;
+ }
+ s.s = a;
+ s.u = b + 2;
+ s.v.b = a + 16;
+ s.w = c + 3;
+ int err = 0;
+ #pragma omp target map (to:s.v.b[0:z + 7], s.u[z + 1:z + 4]) \
+ map (tofrom:s.s[3:3]) \
+ map (from: s.w[z:4], err) private (i)
+ {
+ err = 0;
+ for (i = 0; i < 7; i++)
+ if (s.v.b[i] != 16 + i)
+ err = 1;
+ for (i = 1; i < 5; i++)
+ if (s.u[i] != 34 + i)
+ err = 1;
+ for (i = 3; i < 6; i++)
+ if (s.s[i] != i)
+ err = 1;
+ else
+ s.s[i] = 128 + i;
+ for (i = 0; i < 4; i++)
+ s.w[i] = 96 + i;
+ }
+ if (err)
+ abort ();
+ for (i = 0; i < 32; i++)
+ if (a[i] != ((i >= 3 && i < 6) ? 128 + i : i)
+ || b[i] != 32 + i
+ || c[i] != ((i >= 3 && i < 7) ? 93 + i : 64 + i))
+ abort ();
+ return 0;
+}
--- /dev/null
+extern void abort (void);
+struct S { int s; int *u; int v[5]; };
+volatile int z;
+
+int
+main ()
+{
+ int u[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, err = 0;
+ struct S s = { 9, u + 3, { 10, 11, 12, 13, 14 } };
+ int *v = u + 4;
+ #pragma omp target enter data map (to: s.s, s.u[0:5]) map (alloc: s.v[1:3])
+ s.s++;
+ u[3]++;
+ s.v[1]++;
+ #pragma omp target update to (s.s) to (s.u[0:2], s.v[1:3])
+ #pragma omp target map (alloc: s.s, s.v[1:3]) map (from: err)
+ {
+ err = 0;
+ if (s.s != 10 || s.v[1] != 12 || s.v[2] != 12 || s.v[3] != 13)
+ err = 1;
+ if (v[-1] != 4 || v[0] != 4 || v[1] != 5 || v[2] != 6 || v[3] != 7)
+ err = 1;
+ s.s++;
+ s.v[2] += 2;
+ v[-1] = 5;
+ v[3] = 9;
+ }
+ if (err)
+ abort ();
+ #pragma omp target map (alloc: s.u[0:5])
+ {
+ err = 0;
+ if (s.u[0] != 5 || s.u[1] != 4 || s.u[2] != 5 || s.u[3] != 6 || s.u[4] != 9)
+ err = 1;
+ s.u[1] = 12;
+ }
+ #pragma omp target update from (s.s, s.u[0:5]) from (s.v[1:3])
+ if (err || s.s != 11 || u[0] != 0 || u[1] != 1 || u[2] != 2 || u[3] != 5
+ || u[4] != 12 || u[5] != 5 || u[6] != 6 || u[7] != 9 || u[8] != 8
+ || u[9] != 9 || s.v[0] != 10 || s.v[1] != 12 || s.v[2] != 14
+ || s.v[3] != 13 || s.v[4] != 14)
+ abort ();
+ #pragma omp target exit data map (release: s.s)
+ #pragma omp target exit data map (release: s.u[0:5])
+ #pragma omp target exit data map (delete: s.v[1:3])
+ #pragma omp target exit data map (release: s.s)
+ return 0;
+}
--- /dev/null
+#include <omp.h>
+#include <stdlib.h>
+
+int
+main ()
+{
+ int d = omp_get_default_device ();
+ int id = omp_get_initial_device ();
+
+ if (d < 0 || d >= omp_get_num_devices ())
+ d = id;
+
+ int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ int *b = a;
+ int shared_mem = 0;
+ #pragma omp target map (alloc: shared_mem)
+ shared_mem = 1;
+ if (omp_target_is_present (b, d) != shared_mem)
+ abort ();
+ #pragma omp target enter data map (to: a)
+ if (omp_target_is_present (b, d) == 0)
+ abort ();
+ #pragma omp target enter data map (alloc: b[:0])
+ if (omp_target_is_present (b, d) == 0)
+ abort ();
+ #pragma omp target exit data map (release: b[:0])
+ if (omp_target_is_present (b, d) == 0)
+ abort ();
+ #pragma omp target exit data map (release: b[:0])
+ if (omp_target_is_present (b, d) != shared_mem)
+ abort ();
+ #pragma omp target enter data map (to: a)
+ if (omp_target_is_present (b, d) == 0)
+ abort ();
+ #pragma omp target enter data map (always, to: b[:0])
+ if (omp_target_is_present (b, d) == 0)
+ abort ();
+ #pragma omp target exit data map (delete: b[:0])
+ if (omp_target_is_present (b, d) != shared_mem)
+ abort ();
+ #pragma omp target exit data map (from: b[:0])
+ return 0;
+}
--- /dev/null
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+main ()
+{
+ int x = 0, y = 0, z = 0, s = 11, t = 12, u = 13, w = 7, err;
+ #pragma omp parallel
+ #pragma omp single
+ {
+ #pragma omp task depend(in: x)
+ {
+ usleep (5000);
+ x = 1;
+ }
+ #pragma omp task depend(in: x)
+ {
+ usleep (6000);
+ y = 2;
+ }
+ #pragma omp task depend(out: z)
+ {
+ usleep (7000);
+ z = 3;
+ }
+ #pragma omp target map(tofrom: x) map(from: err) firstprivate (y) depend(inout: x, z)
+ err = (x != 1 || y != 2 || z != 3);
+ if (err)
+ abort ();
+ #pragma omp task depend(in: x)
+ {
+ usleep (5000);
+ x = 4;
+ }
+ #pragma omp task depend(in: x)
+ {
+ usleep (4000);
+ y = 5;
+ }
+ #pragma omp task depend(in: z)
+ {
+ usleep (3000);
+ z = 6;
+ }
+ #pragma omp target enter data nowait map (to: w)
+ #pragma omp target enter data depend (inout: x, z) map (to: x, y, z)
+ #pragma omp target map (alloc: x, y, z) map(from: err)
+ {
+ err = (x != 4 || y != 5 || z != 6);
+ x = 7;
+ y = 8;
+ z = 9;
+ }
+ if (err)
+ abort ();
+ #pragma omp taskwait
+ #pragma omp target map (alloc: w) map(from: err)
+ {
+ err = w != 7;
+ w = 17;
+ }
+ if (err)
+ abort ();
+ #pragma omp task depend(in: x)
+ {
+ usleep (2000);
+ s = 14;
+ }
+ #pragma omp task depend(in: x)
+ {
+ usleep (3000);
+ t = 15;
+ }
+ #pragma omp task depend(in: z)
+ {
+ usleep (4000);
+ u = 16;
+ }
+ #pragma omp target exit data depend (inout: x, z) map (from: x, y, z, w)
+ if (x != 7 || y != 8 || z != 9 || s != 14 || t != 15 || u != 16 || w != 17)
+ abort ();
+ }
+ return 0;
+}
--- /dev/null
+extern void abort (void);
+#pragma omp declare target
+int a[4] = { 2, 3, 4, 5 }, *b;
+#pragma omp end declare target
+
+int
+main ()
+{
+ int err;
+ int c[3] = { 6, 7, 8 };
+ b = c;
+ #pragma omp target map(to: a[0:2], b[0:2]) map(from: err)
+ err = a[0] != 2 || a[1] != 3 || a[2] != 4 || a[3] != 5 || b[0] != 6 || b[1] != 7;
+ if (err)
+ abort ();
+ a[1] = 9;
+ a[2] = 10;
+ #pragma omp target map(always,to:a[1:2]) map(from: err)
+ err = a[0] != 2 || a[1] != 9 || a[2] != 10 || a[3] != 5;
+ if (err)
+ abort ();
+ #pragma omp parallel firstprivate(a, b, c, err) num_threads (2)
+ #pragma omp single
+ {
+ b = c + 1;
+ a[0] = 11;
+ a[2] = 13;
+ c[1] = 14;
+ int d = 0;
+ #pragma omp target map(to: a[0:3], b[d:2]) map (from: err)
+ err = a[0] != 11 || a[1] != 9 || a[2] != 13 || b[0] != 14 || b[1] != 8;
+ if (err)
+ abort ();
+ }
+ return 0;
+}
--- /dev/null
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+main ()
+{
+ int x = 0, y = 0, z = 0, err;
+ int shared_mem = 0;
+ #pragma omp target map(to: shared_mem)
+ shared_mem = 1;
+ #pragma omp parallel
+ #pragma omp single
+ {
+ #pragma omp task depend(in: x)
+ {
+ usleep (5000);
+ x = 1;
+ }
+ #pragma omp task depend(in: x)
+ {
+ usleep (6000);
+ y = 2;
+ }
+ #pragma omp task depend(out: z)
+ {
+ usleep (7000);
+ z = 3;
+ }
+ #pragma omp target enter data map(to: x, y, z) depend(inout: x, z) nowait
+ #pragma omp task depend(inout: x, z)
+ {
+ x++; y++; z++;
+ }
+ #pragma omp target update to(x, y) depend(inout: x) nowait
+ #pragma omp target enter data map(always, to: z) depend(inout: z) nowait
+ #pragma omp target map (alloc: x, y, z) map (from: err) depend(inout: x, z)
+ {
+ err = x != 2 || y != 3 || z != 4;
+ x = 5; y = 6; z = 7;
+ }
+ #pragma omp task depend(in: x)
+ {
+ usleep (5000);
+ if (!shared_mem)
+ x = 1;
+ }
+ #pragma omp task depend(in: x)
+ {
+ usleep (6000);
+ if (!shared_mem)
+ y = 2;
+ }
+ #pragma omp task depend(out: z)
+ {
+ usleep (3000);
+ if (!shared_mem)
+ z = 3;
+ }
+ #pragma omp target exit data map(release: z) depend(inout: z) nowait
+ #pragma omp target exit data map(from: x, y) depend(inout: x) nowait
+ #pragma omp target exit data map(from: z) depend(inout: z) nowait
+ #pragma omp taskwait
+ if (err || x != 5 || y != 6 || z != 7)
+ abort ();
+ }
+ return 0;
+}
abort ();
#pragma omp target data device (d) map (to: h)
{
- #pragma omp target device (d)
+ #pragma omp target device (d) map (h)
if (omp_get_level () != 0 || (f && !omp_is_initial_device ()) || h++ != 5)
abort ();
#pragma omp target update device (d) from (h)
}
#pragma omp target data if (v > 1) map (to: h)
{
- #pragma omp target if (v > 1)
+ #pragma omp target if (v > 1) map(h)
if (omp_get_level () != 0 || !omp_is_initial_device () || h++ != 6)
abort ();
#pragma omp target update if (v > 1) from (h)
}
#pragma omp target data device (d) if (v > 1) map (to: h)
{
- #pragma omp target device (d) if (v > 1)
+ #pragma omp target device (d) if (v > 1) map(h)
if (omp_get_level () != 0 || !omp_is_initial_device () || h++ != 7)
abort ();
#pragma omp target update device (d) if (v > 1) from (h)
}
#pragma omp target data if (v <= 1) map (to: h)
{
- #pragma omp target if (v <= 1)
+ #pragma omp target if (v <= 1) map (tofrom: h)
if (omp_get_level () != 0 || h++ != 8)
abort ();
#pragma omp target update if (v <= 1) from (h)
}
#pragma omp target data device (d) if (v <= 1) map (to: h)
{
- #pragma omp target device (d) if (v <= 1)
+ #pragma omp target device (d) if (v <= 1) map (h)
if (omp_get_level () != 0 || (f && !omp_is_initial_device ()) || h++ != 9)
abort ();
#pragma omp target update device (d) if (v <= 1) from (h)
}
#pragma omp target data if (0) map (to: h)
{
- #pragma omp target if (0)
+ #pragma omp target if (0) map (h)
if (omp_get_level () != 0 || !omp_is_initial_device () || h++ != 10)
abort ();
#pragma omp target update if (0) from (h)
}
#pragma omp target data device (d) if (0) map (to: h)
{
- #pragma omp target device (d) if (0)
+ #pragma omp target device (d) if (0) map (h)
if (omp_get_level () != 0 || !omp_is_initial_device () || h++ != 11)
abort ();
#pragma omp target update device (d) if (0) from (h)
}
#pragma omp target data if (1) map (to: h)
{
- #pragma omp target if (1)
+ #pragma omp target if (1) map (tofrom: h)
if (omp_get_level () != 0 || h++ != 12)
abort ();
#pragma omp target update if (1) from (h)
}
#pragma omp target data device (d) if (1) map (to: h)
{
- #pragma omp target device (d) if (1)
+ #pragma omp target device (d) if (1) map (tofrom: h)
if (omp_get_level () != 0 || (f && !omp_is_initial_device ()) || h++ != 13)
abort ();
#pragma omp target update device (d) if (1) from (h)
--- /dev/null
+/* { dg-do run } */
+/* { dg-options "-O2 -fopenmp -std=c99" } */
+
+int q, r, e;
+
+__attribute__((noinline, noclone)) void
+foo (long a, long b)
+{
+ #pragma omp taskloop lastprivate (q) nogroup
+ for (long d = a; d < b; d += 2)
+ {
+ q = d;
+ if (d < 2 || d > 6 || (d & 1))
+ #pragma omp atomic
+ e |= 1;
+ }
+}
+
+__attribute__((noinline, noclone)) int
+bar (int a, int b)
+{
+ int q = 7;
+ #pragma omp taskloop lastprivate (q)
+ for (int d = a; d < b; d++)
+ {
+ if (d < 12 || d > 17)
+ #pragma omp atomic
+ e |= 1;
+ q = d;
+ }
+ return q;
+}
+
+int
+main ()
+{
+ #pragma omp parallel
+ #pragma omp single
+ {
+ foo (2, 7);
+ r = bar (12, 18);
+ }
+ if (q != 6 || r != 17 || e)
+ __builtin_abort ();
+ return 0;
+}
--- /dev/null
+/* { dg-do run } */
+/* { dg-options "-O2 -std=c99" } */
+/* { dg-additional-options "-msse2" { target sse2_runtime } } */
+/* { dg-additional-options "-mavx" { target avx_runtime } } */
+
+int u[1024], v[1024], w[1024], m;
+
+__attribute__((noinline, noclone)) void
+f1 (long a, long b)
+{
+ #pragma omp taskloop simd default(none) shared(u, v, w) nogroup
+ for (long d = a; d < b; d++)
+ u[d] = v[d] + w[d];
+}
+
+__attribute__((noinline, noclone)) int
+f2 (long a, long b, long c)
+{
+ int d, e;
+ #pragma omp taskloop simd default(none) shared(u, v, w) linear(d:1) linear(c:5) lastprivate(e)
+ for (d = a; d < b; d++)
+ {
+ u[d] = v[d] + w[d];
+ c = c + 5;
+ e = c + 9;
+ }
+ return d + c + e;
+}
+
+__attribute__((noinline, noclone)) int
+f3 (long a, long b)
+{
+ int d;
+ #pragma omp taskloop simd default(none) shared(u, v, w)
+ for (d = a; d < b; d++)
+ {
+ int *p = &d;
+ u[d] = v[d] + w[d];
+ }
+ return d;
+}
+
+__attribute__((noinline, noclone)) int
+f4 (long a, long b, long c, long d)
+{
+ int e, f, g;
+ #pragma omp taskloop simd default(none) shared(u, v, w) collapse(2) lastprivate(g)
+ for (e = a; e < b; e++)
+ for (f = c; f < d; f++)
+ {
+ int *p = &e;
+ int *q = &f;
+ int r = 32 * e + f;
+ u[r] = v[r] + w[r];
+ g = r;
+ }
+ return e + f + g;
+}
+
+__attribute__((noinline, noclone)) int
+f5 (long a, long b, long c, long d)
+{
+ int e, f;
+ #pragma omp taskloop simd default(none) shared(u, v, w) collapse(2)
+ for (e = a; e < b; e++)
+ for (f = c; f < d; f++)
+ {
+ int r = 32 * e + f;
+ u[r] = v[r] + w[r];
+ }
+ return e + f;
+}
+
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 1024; i++)
+ {
+ v[i] = i;
+ w[i] = i + 1;
+ }
+ #pragma omp parallel
+ #pragma omp single
+ f1 (0, 1024);
+ for (i = 0; i < 1024; i++)
+ if (u[i] != 2 * i + 1)
+ __builtin_abort ();
+ else
+ {
+ v[i] = 1024 - i;
+ w[i] = 512 - i;
+ }
+ #pragma omp parallel
+ #pragma omp single
+ m = f2 (2, 1022, 17);
+ for (i = 0; i < 1024; i++)
+ if ((i < 2 || i >= 1022) ? u[i] != 2 * i + 1 : u[i] != 1536 - 2 * i)
+ __builtin_abort ();
+ else
+ {
+ v[i] = i;
+ w[i] = i + 1;
+ }
+ if (m != 1022 + 2 * (1020 * 5 + 17) + 9)
+ __builtin_abort ();
+ #pragma omp parallel
+ #pragma omp single
+ m = f3 (0, 1024);
+ for (i = 0; i < 1024; i++)
+ if (u[i] != 2 * i + 1)
+ __builtin_abort ();
+ else
+ {
+ v[i] = 1024 - i;
+ w[i] = 512 - i;
+ }
+ if (m != 1024)
+ __builtin_abort ();
+ #pragma omp parallel
+ #pragma omp single
+ m = f4 (0, 32, 0, 32);
+ for (i = 0; i < 1024; i++)
+ if (u[i] != 1536 - 2 * i)
+ __builtin_abort ();
+ else
+ {
+ v[i] = i;
+ w[i] = i + 1;
+ }
+ if (m != 32 + 32 + 1023)
+ __builtin_abort ();
+ #pragma omp parallel
+ #pragma omp single
+ m = f5 (0, 32, 0, 32);
+ for (i = 0; i < 1024; i++)
+ if (u[i] != 2 * i + 1)
+ __builtin_abort ();
+ else
+ {
+ v[i] = 1024 - i;
+ w[i] = 512 - i;
+ }
+ if (m != 32 + 32)
+ __builtin_abort ();
+ return 0;
+}
--- /dev/null
+/* { dg-do run } */
+/* { dg-options "-O2 -fopenmp -std=c99" } */
+
+int g;
+int a[1024];
+
+__attribute__((noinline, noclone)) int
+f1 (int x)
+{
+ #pragma omp taskloop firstprivate (x) lastprivate (x)
+ for (int i = 0; i < 64; i++)
+ {
+ if (x != 74)
+ __builtin_abort ();
+ if (i == 63)
+ x = i + 4;
+ }
+ return x;
+}
+
+__attribute__((noinline, noclone)) void
+f2 (void)
+{
+ #pragma omp taskloop firstprivate (g) lastprivate (g) nogroup
+ for (int i = 0; i < 64; i++)
+ {
+ if (g != 77)
+ __builtin_abort ();
+ if (i == 63)
+ g = i + 9;
+ }
+}
+
+__attribute__((noinline, noclone)) long long
+f3 (long long a, long long b, long long c)
+{
+ long long i;
+ int l;
+ #pragma omp taskloop default (none) lastprivate (i, l)
+ for (i = a; i < b; i += c)
+ l = i;
+ return l * 7 + i;
+}
+
+__attribute__((noinline, noclone)) long long
+f4 (long long a, long long b, long long c, long long d,
+ long long e, long long f, int k)
+{
+ long long i, j;
+ int l;
+ #pragma omp taskloop default (none) collapse(2) \
+ firstprivate (k) lastprivate (i, j, k, l)
+ for (i = a; i < b; i += e)
+ for (j = c; j < d; j += f)
+ {
+ if (k != 73)
+ __builtin_abort ();
+ if (i == 31 && j == 46)
+ k = i;
+ l = j;
+ }
+ return i + 5 * j + 11 * k + 17 * l;
+}
+
+int
+main ()
+{
+ #pragma omp parallel
+ #pragma omp single
+ {
+ if (f1 (74) != 63 + 4)
+ __builtin_abort ();
+ g = 77;
+ f2 ();
+ #pragma omp taskwait
+ if (g != 63 + 9)
+ __builtin_abort ();
+ if (f3 (7, 12, 2) != 11 * 7 + 13)
+ __builtin_abort ();
+ if (f4 (0, 32, 16, 48, 1, 2, 73) != 32 + 5 * 48 + 11 * 31 + 17 * 46)
+ __builtin_abort ();
+ }
+ return 0;
+}
--- /dev/null
+/* { dg-do run } */
+/* { dg-options "-O2 -fopenmp" } */
+
+int u[64], v;
+
+__attribute__((noinline, noclone)) int
+test (int a, int b, int c, int d, void (*fn) (int, int, int, int),
+ int *num_tasks, int *min_iters, int *max_iters)
+{
+ int i, t = 0;
+ __builtin_memset (u, 0, sizeof u);
+ v = 0;
+ fn (a, b, c, d);
+ *min_iters = 0;
+ *max_iters = 0;
+ *num_tasks = v;
+ if (v)
+ {
+ *min_iters = u[0];
+ *max_iters = u[0];
+ t = u[0];
+ for (i = 1; i < v; i++)
+ {
+ if (*min_iters > u[i])
+ *min_iters = u[i];
+ if (*max_iters < u[i])
+ *max_iters = u[i];
+ t += u[i];
+ }
+ }
+ return t;
+}
+
+void
+grainsize (int a, int b, int c, int d)
+{
+ int i, j = 0, k = 0;
+ #pragma omp taskloop firstprivate (j, k) grainsize(d)
+ for (i = a; i < b; i += c)
+ {
+ if (j == 0)
+ {
+ #pragma omp atomic capture
+ k = v++;
+ if (k >= 64)
+ __builtin_abort ();
+ }
+ u[k] = ++j;
+ }
+}
+
+void
+num_tasks (int a, int b, int c, int d)
+{
+ int i, j = 0, k = 0;
+ #pragma omp taskloop firstprivate (j, k) num_tasks(d)
+ for (i = a; i < b; i += c)
+ {
+ if (j == 0)
+ {
+ #pragma omp atomic capture
+ k = v++;
+ if (k >= 64)
+ __builtin_abort ();
+ }
+ u[k] = ++j;
+ }
+}
+
+int
+main ()
+{
+ #pragma omp parallel
+ #pragma omp single
+ {
+ int min_iters, max_iters, ntasks;
+ /* If grainsize is present, # of task loop iters is >= grainsize && < 2 * grainsize,
+ unless # of loop iterations is smaller than grainsize. */
+ if (test (0, 79, 1, 17, grainsize, &ntasks, &min_iters, &max_iters) != 79
+ || min_iters < 17 || max_iters >= 17 * 2)
+ __builtin_abort ();
+ if (test (-49, 2541, 7, 28, grainsize, &ntasks, &min_iters, &max_iters) != 370
+ || min_iters < 28 || max_iters >= 28 * 2)
+ __builtin_abort ();
+ if (test (7, 21, 2, 15, grainsize, &ntasks, &min_iters, &max_iters) != 7
+ || ntasks != 1 || min_iters != 7 || max_iters != 7)
+ __builtin_abort ();
+ /* If num_tasks is present, # of task loop iters is min (# of loop iters, num_tasks). */
+ if (test (-51, 2500, 48, 9, num_tasks, &ntasks, &min_iters, &max_iters) != 54
+ || ntasks != 9)
+ __builtin_abort ();
+ if (test (0, 25, 2, 17, num_tasks, &ntasks, &min_iters, &max_iters) != 13
+ || ntasks != 13)
+ __builtin_abort ();
+ }
+ return 0;
+}
--- /dev/null
+! { dg-do run }
+! { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O2" } }
+! { dg-set-target-env-var OMP_PROC_BIND "spread,close" }
+! { dg-set-target-env-var OMP_PLACES "{6,7}:4:-2,!{2,3}" }
+! { dg-set-target-env-var OMP_NUM_THREADS "2" }
+
+ use omp_lib
+ integer :: num, i, nump
+ num = omp_get_num_places ()
+ print *, 'omp_get_num_places () == ', num
+ do i = 0, num - 1
+ nump = omp_get_place_num_procs (place_num = i)
+ if (nump .eq. 0) then
+ print *, 'place ', i, ' {}'
+ else
+ call print_place (i, nump)
+ end if
+ end do
+ call print_place_var
+ call omp_set_nested (nested = .true.)
+ !$omp parallel
+ if (omp_get_thread_num () == omp_get_num_threads () - 1) then
+ !$omp parallel
+ if (omp_get_thread_num () == omp_get_num_threads () - 1) &
+ call print_place_var
+ !$omp end parallel
+ end if
+ !$omp end parallel
+contains
+ subroutine print_place (i, nump)
+ integer, intent (in) :: i, nump
+ integer :: ids(nump)
+ call omp_get_place_proc_ids (place_num = i, ids = ids)
+ print *, 'place ', i, ' {', ids, '}'
+ end subroutine
+ subroutine print_place_var
+ integer :: place, num_places
+ place = omp_get_place_num ()
+ num_places = omp_get_partition_num_places ()
+ print *, 'place ', place
+ if (num_places .gt. 0) call print_partition (num_places)
+ end subroutine
+ subroutine print_partition (num_places)
+ integer, intent (in) :: num_places
+ integer :: place_nums(num_places)
+ call omp_get_partition_place_nums (place_nums = place_nums)
+ print *, 'partition ', place_nums(1), '-', place_nums(num_places)
+ end subroutine
+end
--- /dev/null
+! { dg-do run }
+! { dg-additional-options "-fdefault-integer-8" }
+! { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O2" } }
+! { dg-set-target-env-var OMP_PROC_BIND "spread,close" }
+! { dg-set-target-env-var OMP_PLACES "{6,7}:4:-2,!{2,3}" }
+! { dg-set-target-env-var OMP_NUM_THREADS "2" }
+
+include 'affinity1.f90'
+2015-10-13 Ilya Verbin <ilya.verbin@intel.com>
+
+ * plugin/libgomp-plugin-intelmic.cpp (GOMP_OFFLOAD_dev2dev): New
+ function.
+ * plugin/offload_target_main.cpp (__offload_target_tgt2tgt): New
+ static function, register it in liboffloadmic.
+
2015-10-08 Ilya Verbin <ilya.verbin@intel.com>
* runtime/offload_engine.cpp (Engine::init_process): Use strdup instead
return host_ptr;
}
+extern "C" void *
+GOMP_OFFLOAD_dev2dev (int device, void *dst_ptr, const void *src_ptr,
+ size_t size)
+{
+ TRACE ("(dst_ptr = %p, src_ptr = %p, size = %d)", dst_ptr, src_ptr, size);
+ if (!size)
+ return dst_ptr;
+
+ VarDesc vd1[3] = { vd_host2tgt, vd_host2tgt, vd_host2tgt };
+ vd1[0].ptr = &dst_ptr;
+ vd1[0].size = sizeof (void *);
+ vd1[1].ptr = &src_ptr;
+ vd1[1].size = sizeof (void *);
+ vd1[2].ptr = &size;
+ vd1[2].size = sizeof (size);
+ VarDesc2 vd1g[3] = { { "dst_ptr", 0 }, { "src_ptr", 0 }, { "size", 0 } };
+
+ offload (__FILE__, __LINE__, device, "__offload_target_tgt2tgt", 3, vd1,
+ vd1g);
+
+ return dst_ptr;
+}
+
extern "C" void
GOMP_OFFLOAD_run (int device, void *tgt_fn, void *tgt_vars)
{
__offload_target_leave (ofldt);
}
+/* Copy SIZE bytes from SRC_PTR to DST_PTR. */
+static void
+__offload_target_tgt2tgt (OFFLOAD ofldt)
+{
+ void *src_ptr = NULL;
+ void *dst_ptr = NULL;
+ size_t size = 0;
+
+ VarDesc vd1[3] = { vd_host2tgt, vd_host2tgt, vd_host2tgt };
+ vd1[0].ptr = &dst_ptr;
+ vd1[0].size = sizeof (void *);
+ vd1[1].ptr = &src_ptr;
+ vd1[1].size = sizeof (void *);
+ vd1[2].ptr = &size;
+ vd1[2].size = sizeof (size);
+ VarDesc2 vd1g[3] = { { "dst_ptr", 0 }, { "src_ptr", 0 }, { "size", 0 } };
+
+ __offload_target_enter (ofldt, 3, vd1, vd1g);
+ TRACE ("(dst_ptr = %p, src_ptr = %p, size = %d)", dst_ptr, src_ptr, size);
+ memcpy (dst_ptr, src_ptr, size);
+ __offload_target_leave (ofldt);
+}
+
/* Call offload function by the address fn_ptr and pass vars_ptr to it. */
static void
__offload_target_run (OFFLOAD ofldt)
REGISTER (host2tgt_p2);
REGISTER (tgt2host_p1);
REGISTER (tgt2host_p2);
+REGISTER (tgt2tgt);
REGISTER (run);
#undef REGISTER