diff --git a/gcc/ChangeLog.cilkplus b/gcc/ChangeLog.cilkplus new file mode 100644 index 0000000000000..352d724927271 --- /dev/null +++ b/gcc/ChangeLog.cilkplus @@ -0,0 +1,45 @@ +2013-06-20 Aldy Hernandez + Balaji V. Iyer + + * Makefile.in (C_COMMON_OBJS): Depend on c-family/c-cilkplus.o. + (c-cilkplus.o): New dependency. + * omp-low.c (extract_omp_for_data): Add case for NE_EXPR. + (build_outer_var_ref): Check for GF_OMP_FOR_KIND_SIMD bitwise. + (check_omp_nesting_restrictions): Same. + (lower_rec_input_clauses): Same. + (expand_omp_for): Same. + (lower_omp_for): Same. + (diagnose_sb_0): Adjust for Cilk Plus for loops. + (gate_expand_omp): Check for Cilk Plus. + (execute_lower_omp): Same. + (gate_diagnose_omp_blocks): Same. + * tree.def (CILK_SIMD): New entry. + * tree-pretty-print.c (dump_generic_node): Add case for CILK_SIMD. + * gimple-pretty-print.c (dump_gimple_omp_for): Add case for + GF_OMP_FOR_KIND_CILKSIMD. + * gimplify.c (gimplify_omp_for): Add case for CILK_SIMD. + (gimplify_expr): Same. + (is_gimple_stmt): Same. + +c-family/ + * c-cilkplus.c: New. + * c-pragma.c (init_pragma): Register "simd" pragma. + * c-pragma.h (enum pragma_kind): Add PRAGMA_CILK_SIMD enum. + (enum pragma_cilk_clause): New. + * c.opt (fcilkplus): New flag. + * c-common.h (c_finish_cilk_simd_loop): Protoize. + (c_finish_cilk_clauses): Same. + +c/ + * c-parser.c (c_parser_pragma): Add case for PRAGMA_CILK_SIMD. + (c_parser_cilk_verify_simd): New. + (c_parser_cilk_clause_vectorlength): New. + (c_parser_cilk_clause_linear): New. + (c_parser_cilk_clause_name): New. + (c_parser_cilk_all_clauses): New. + (c_parser_cilk_for_statement): New. + (c_parser_cilk_simd_construct): New. + * c-typeck.c (c_finish_bc_stmt): Add case for _Cilk_for loops. + +testsuite/ + * gcc.dg/cilk-plus: New directory and associated infrastructure. diff --git a/gcc/ChangeLog.gomp b/gcc/ChangeLog.gomp new file mode 100644 index 0000000000000..afd5677310624 --- /dev/null +++ b/gcc/ChangeLog.gomp @@ -0,0 +1,449 @@ +2013-06-28 Jakub Jelinek + Aldy Hernandez + + * internal-fn.def (GOMP_SIMD_LANE, GOMP_SIMD_VF, + GOMP_SIMD_LAST_LANE): New internal functions. + * omp-low.c (omp_max_vf, lower_rec_simd_input_clauses): New + functions. + (lower_rec_input_clauses): Add fd argument. Enforce max_vf = 1 + if any data sharing clauses mention VLAs or for array reductions. + Handle OMP_CLAUSE__LOOPTEMP_ clause. For + OMP_CLAUSE_{{FIRST,LAST,}PRIVATE,LINEAR,REDUCTION} on SIMD + constructs use "omp simd array" temporaries. For OMP_CLAUSE_LINEAR + adjust initial value in combined constructs. Don't emit any + barriers for #pragma omp distribute. If max_vf is lower than + current safelen, prepend an OMP_CLAUSE_SAFELEN clause. + (lower_lastprivate_clauses): Handle "omp simd array" temporaries. + (lower_reduction_clauses): Exit early for #pragma omp simd. + (expand_omp_simd): Set loop->simduid from OMP_CLAUSE__SIMDUID_ + and cfun->has_simduid_loops if set. + If OMP_CLAUSE_SAFELEN (1) is present, don't set loop->safelen + nor loop->force_vect. + (lower_omp_sections, lower_omp_single, lower_omp_taskreg): Adjust + lower_rec_input_clauses callers. + (lower_omp_for_lastprivate): Unshare vinit. + (lower_omp_for): Add OMP_CLAUSE__LOOPTEMP_ clauses before calling + lower_rec_input_clauses. Adjust lower_rec_input_clauses caller. + Always call lower_omp_for_lastprivate at the same place, even for + #pragma omp simd. + * tree.h (enum clause_code): Add OMP_CLAUSE__SIMDUID_. + (OMP_CLAUSE__SIMDUID__DECL): Define. + * tree-vectorizer.c: Include hash-table.h and tree-ssa-propagate.h. + (simduid_to_vf, decl_to_simduid): New classes. + (simduid_to_vf::hash, simduid_to_vf::equal, decl_to_simduid::hash, + decl_to_simduid::equal): New methods. + (note_simd_array_uses_struct): New struct. + (adjust_simduid_builtins, note_simd_array_uses_cb, + note_simd_array_uses): New functions. + (vectorize_loops): Adjust "omp simd array" temporary array sizes + and fold GOMP_SIMD_{LANE,VF,LAST_LANE} builtins. + * tree-vectorizer.h (struct _stmt_vec_info): Add simd_lane_access_p + field. + (STMT_VINFO_SIMD_LANE_ACCESS_P): Define. + * tree-data-ref.c (get_references_in_stmt): Allow GOMP_SIMD_LANE + builtins in their own loops. + * tree-inline.c (copy_cfg_body): Propagate has_force_vect_loops + and has_simduid_loops. + * function.h (struct function): Add has_simduid_loops field. + * tree-ssa-ccp.c (likely_value): For GOMP_SIMD_{LANE,LAST_LANE,VF} + builtins ignore the undefined magic argument. + * tree-pretty-print.c (dump_omp_clause): Handle OMP_CLAUSE__SIMDUID_ + clause. + * cfgloop.h (struct loop): Add simduid field. + * Makefile.in (tree-vectorizer.o): Depend on $(HASH_TABLE_H) + and tree-ssa-propagate.h. + * tree-vect-data-refs.c (vect_analyze_data_refs): Check for SIMD + lane access. + * gimplify.c (omp_add_variable): Handle combination of aligned + clause and some data sharing clause for the same decl. + (gimplify_omp_for): For collapse (2) and above simd loops + predetermine loop iteration vars as lastprivate instead of + linear. + * tree.c (omp_clause_num_ops, omp_clause_code_name): Add + entries for OMP_CLAUSE__SIMDUID_. + (walk_tree_1): Handle OMP_CLAUSE__SIMDUID_. + * tree-vect-loop.c (vectorizable_live_operation): Handle live + GOMP_SIMD_LANE result. + * tree-vect-stmts.c (vectorizable_call): Vectorize GOMP_SIMD_LANE + builtin. + (vectorizable_store, vectorizable_load): Handle + STMT_VINFO_SIMD_LANE_ACCESS_P. + * internal-fn.c (expand_GOMP_SIMD_LANE, expand_GOMP_SIMD_VF, + expand_GOMP_SIMD_LAST_LANE): New functions. + +2013-06-21 Jakub Jelinek + + * gimple.h (enum gf_mask): Adjust GF_OMP_FOR_COMBINED + value representation, add GF_OMP_FOR_COMBINED_INTO. + (gimple_omp_for_combined_into_p, + gimple_omp_for_set_combined_into_p): New inlines. + * gimplify.c (enum omp_region_type): Remove outdated + ORT_SIMD comment. + (struct gimplify_omp_ctx): Add combined_loop field. + (gimplify_omp_for): Call gimple_omp_for_set_combined_into_p + for inner for/simd constructs combined with an outer + loop construct (for or distribute). + * tree.c (omp_clause_num_ops): Add OMP_CLAUSE__LOOPTEMP_ + entry. + (omp_clause_code_name): Likewise. + (walk_tree_1): Handle OMP_CLAUSE__LOOPTEMP_. + * tree-pretty-print.c (dump_omp_clause): Handle OMP_CLAUSE__LOOPTEMP_. + * tree.h (enum omp_clause_code): Add OMP_CLAUSE__LOOPTEMP_. + (OMP_CLAUSE_DECL): Allow also on OMP_CLAUSE__LOOPTEMP_. + * omp-low.c (extract_omp_for_data): Rename non_ws to simd. Don't set + fd->chunk_size for non-chunk OMP_CLAUSE_SCHEDULE_STATIC, unless + fd->have_ordered. For OMP_CLAUSE_SCHEDULE_STATIC non-ordered loops + compute fd->iter_type the same as for simd. + (get_ws_args_for): Add par_stmt argument, if + gimple_omp_for_combined_into_p, use first two _looptemp_ clauses + temporaries instead of fd->loop.n{1,2}. + (determine_parallel_type): Adjust caller. + (scan_sharing_clauses): Handle OMP_CLAUSE__LOOPTEMP_. + (find_combined_for): New function. + (scan_omp_parallel): If gimple_omp_parallel_combined_p and + it is combined with gimple_omp_for_combined_into_p OMP_FOR, + add OMP_CLAUSE__LOOPTEMP_ clauses to the parallel. + (check_omp_nesting_restrictions): Don't insist that the only construct + nested in OMP_DISTRIBUTE must be OMP_PARALLEL. + (lower_rec_input_clauses, lower_send_clauses): Handle + OMP_CLAUSE__LOOPTEMP_. + (expand_omp_for_init_counts, expand_omp_for_init_vars, + extract_omp_for_update_vars): New functions. + (expand_omp_for_generic): Add inner_stmt argument. Use + expand_omp_for_{init,update}* helper functions. Handle combined loop + constructs. + (expand_omp_for_static_nochunk, expand_omp_for_static_chunk): + Likewise. Handle fd->collapse > 1 and broken_loop cases. + (expand_omp_simd): Use expand_omp_for_init* helper functions. Handle + combined loop constructs. + (expand_omp_for): Add inner_stmt argument. Pass it through to + expand_omp_for_{generic,static_{,no}chunk}. Use + expand_omp_for_static* even for fd->collapse > 1 and/or broken_loop + cases, just not when fd->have_ordered. + (expand_omp): Adjust expand_omp_for caller. + (lower_omp_for): If gimple_omp_parallel_combined_p, add + OMP_CLAUSE__LOOPTEMP_ clauses to the GIMPLE_FOR stmt. + +2013-06-14 Jakub Jelinek + + * gimple-pretty-print.c (dump_gimple_omp_for): Don't handle + GF_OMP_FOR_KIND_FOR_SIMD. + * gimple.h (GF_OMP_FOR_KIND_FOR_SIMD): Remove. + (GF_OMP_FOR_COMBINED): New. + (gimple_omp_for_combined_p, gimple_omp_for_set_combined_p): New + inline functions. + * gimplify.c (is_gimple_stmt): Don't handle OMP_FOR_SIMD. + (find_combined_omp_for): New function. + (gimplify_omp_for): Handle combined OMP_DISTRIBUTE and OMP_FOR + loops. + * Makefile.in (c-family/c-omp.o): Depend on $(C_PRAGMA_H). + * omp-low.c (build_outer_var_ref): Fix up simd handling. + (check_omp_nesting_restrictions): Don't handle + GF_OMP_FOR_KIND_FOR_SIMD. + * tree.def (OMP_FOR_SIMD): Remove. + * tree-pretty-print.c (dump_generic_node): Don't handle OMP_FOR_SIMD. + Handle NULL OMP_FOR_INIT. + +2013-06-12 Jakub Jelinek + + * gimplify.c (gimplify_scan_omp_clauses): Handle + OMP_CLAUSE_THREAD_LIMIT. + * tree-pretty-print.c (dump_omp_clause): Likewise. + * tree.c (omp_clause_num_ops, omp_clause_code_name): Add entries for + OMP_CLAUSE_THREAD_LIMIT. + * tree.h (enum omp_clause_code): Add OMP_CLAUSE_THREAD_LIMIT. + (OMP_CLAUSE_THREAD_LIMIT_EXPR): Define. + +2013-06-04 Jakub Jelinek + + * gimplify.c (gimplify_scan_omp_clauses): Handle array + sections on OMP_CLAUSE_{MAP,TO,FROM} clauses, handle + OMP_CLAUSE_DEPEND clause. + (gimplify_adjust_omp_clauses): Handle array sections on + OMP_CLAUSE_MAP, handle OMP_CLAUSE_DEPEND clause. + * tree.c (omp_clause_num_ops): OMP_CLAUSE_{MAP,TO,FROM} + now have 2 arguments, move OMP_CLAUSE_UNIFORM before these + 3. + (omp_clause_code_name): Adjust for OMP_CLAUSE_UNIFORM movement. + (walk_tree_1): Adjust to handle 2 arguments of + OMP_CLAUSE_{MAP,TO,FROM}. + * tree-pretty-print.c (dump_omp_clause): For OMP_CLAUSE_{MAP,TO,FROM} + print OMP_CLAUSE_SIZE, and for OMP_CLAUSE_MAP handle + OMP_CLAUSE_MAP_POINTER. + * tree.h (enum omp_clause_code): Move OMP_CLAUSE_UNIFORM before + OMP_CLAUSE_{MAP,TO,FROM}. + (OMP_CLAUSE_SIZE): Define. + (enum omp_clause_map_kind): Add OMP_CLAUSE_MAP_POINTER. + * omp-low.c (scan_sharing_clauses): Handle OMP_CLAUSE_DEPEND. + +2013-05-29 Jakub Jelinek + + * omp-builtins.def (BUILT_IN_OMP_GET_TEAM_NUM, + BUILT_IN_OMP_GET_NUM_TEAMS): New built-ins. + * omp-low.c (extract_omp_for_data, expand_omp_for_static_nochunk, + expand_omp_for_static_chunk): Handle #pragma omp distribute. + (expand_omp_for): Add assertion for non-finished distribute collapse + > 1 support. + (check_omp_nesting_restrictions): Allow orphaned distribute construct. + + * omp-low.c (check_omp_nesting_restrictions): Add some + accelerator related nesting restrictions. + (scan_omp_1_stmt): Call check_omp_nesting_restrictions + even for GOMP_taskgroup_{start,end}. + * gimplify.c (omp_notice_threadprivate_variable): Fix a typo. + (gimplify_body): For functions with "omp declare target" attribute + add ORT_TARGET region around the body. + +2013-05-27 Jakub Jelinek + + * tree.def (OMP_TEAMS, OMP_TARGET_DATA, OMP_TARGET, + OMP_TARGET_UPDATE): New tree codes. + * tree-cfg.c (make_edges): Handle GIMPLE_OMP_TARGET + and GIMPLE_OMP_TEAMS. + * omp-low.c (scan_sharing_clauses): Handle OMP_CLAUSE_DIST_SCHEDULE. + * gimple-low.c (lower_stmt): Handle GIMPLE_OMP_TARGET + and GIMPLE_OMP_TEAMS. + * tree.h (OMP_TEAMS_BODY, OMP_TEAMS_CLAUSES, OMP_TARGET_DATA_BODY, + OMP_TARGET_DATA_CLAUSES, OMP_TARGET_BODY, OMP_TARGET_CLAUSES, + OMP_TARGET_UPDATE_CLAUSES): Define. + * tree-nested.c (convert_nonlocal_reference_stmt, + convert_local_reference_stmt, convert_gimple_call): Handle + GIMPLE_OMP_TARGET and GIMPLE_OMP_TEAMS. + * tree-inline.c (estimate_num_insns): Likewise. + (remap_gimple_stmt): Likewise. Adjust gimple_build_omp_for + caller. + * gimple.def: Adjust comments describing OMP_CLAUSEs. + (GIMPLE_OMP_TARGET, GIMPLE_OMP_TEAMS): New GIMPLE stmts. + * tree-parloops.c (create_parallel_loop): Adjust gimple_build_omp_for + caller. + * tree-pretty-print.c (dump_generic_node): Handle OMP_TEAMS, + OMP_TARGET, OMP_TARGET_DATA and OMP_TARGET_UPDATE. + * gimple.h (GF_OMP_TARGET_KIND_MASK, GF_OMP_TARGET_KIND_REGION, + GF_OMP_TARGET_KIND_DATA, GF_OMP_TARGET_KIND_UPDATE): New. + (gimple_build_omp_for): Add kind argument to prototype. + (gimple_build_omp_target, gimple_build_omp_teams): New prototypes. + (gimple_has_substatements): Handle GIMPLE_OMP_TARGET and + GIMPLE_OMP_TEAMS. + (gimple_omp_subcode): Change GIMPLE_OMP_SINGLE to GIMPLE_OMP_TEAMS. + (gimple_omp_target_clauses, gimple_omp_target_clauses_ptr, + gimple_omp_target_set_clauses, gimple_omp_target_kind, + gimple_omp_target_set_kind, gimple_omp_teams_clauses, + gimple_omp_teams_clauses_ptr, gimple_omp_teams_set_clauses): New + inline functions. + (gimple_return_set_retval): Handle GIMPLE_OMP_TARGET and + GIMPLE_OMP_TEAMS. + * gimple.c (gimple_build_omp_for): Add kind argument, call + gimple_omp_for_set_kind. + (gimple_build_omp_target, gimple_build_omp_teams): New functions. + (walk_gimple_op, walk_gimple_stmt, gimple_copy): Handle + GIMPLE_OMP_TARGET and GIMPLE_OMP_TEAMS. + * gimple-pretty-print.c (dump_gimple_omp_target, + dump_gimple_omp_teams): New functions. + (pp_gimple_stmt_1): Handle GIMPLE_OMP_TARGET and GIMPLE_OMP_TEAMS. + * gimplify.c (enum gimplify_omp_var_data): Add GOVD_MAP. + (enum omp_region_type): Add ORT_TEAMS, ORT_TARGET and ORT_TARGET_DATA. + (omp_add_variable): Add temporary assertions. + (omp_notice_threadprivate_variable): Complain if threadprivate vars + appear in target region. + (omp_notice_variable): ORT_TARGET, ORT_TARGET_DATA and ORT_TEAMS + handling. + (omp_check_private): Ignore ORT_TARGET and ORT_TARGET_DATA regions. + (gimplify_scan_omp_clauses): Handle OMP_CLAUSE_MAP, OMP_CLAUSE_TO, + OMP_CLAUSE_FROM, OMP_CLAUSE_NUM_TEAMS, OMP_CLAUSE_DIST_SCHEDULE + and OMP_CLAUSE_DEVICE. + (gimplify_adjust_omp_clauses): Likewise. + (gimplify_adjust_omp_clauses_1): Handle GOVD_MAP. Fix up + check for privatization by also testing for GOVD_LINEAR. + (gimplify_omp_for): Adjust gimple_build_omp_for caller. + Clear *expr_p. + (gimplify_omp_workshare): Handle also OMP_TARGET, OMP_TARGET_DATA + and OMP_TEAMS. Clear *expr_p. + (gimplify_omp_target_update): New function. + (gimplify_expr): Handle OMP_TARGET, OMP_TARGET_DATA, OMP_TARGET_UPDATE + and OMP_TEAMS. + +2013-05-20 Jakub Jelinek + + * omp-low.c (expand_omp_simd): For collapse > 1 loops, + if some loop condition might be not true initially, add runtime + test and skip the whole loop. + +2013-05-14 Jakub Jelinek + + * cfgloop.h (struct loop): Add safelen and force_vect fields. + * function.h (struct function): Add has_force_vect_loops field. + * omp-low.c (expand_omp_simd): If !broken_loop, create loop for + the simd region and set safelen and force_vect fields in it. + * tree-vectorizer.c (vectorize_loops): If loop has force_vect set, + vectorize it even if flag_vectorize isn't set. Clear loop->force_vect + after vectorization. + * tree-ssa-loop.c (gate_tree_vectorize): Return true even + cfun->has_force_vect_loops. + * tree-ssa-loop-ivcanon.c (tree_unroll_loops_completely_1): Don't + unroll loops with loop->force_vect. + * tree-vect-data-refs.c (vect_analyze_data_ref_dependence): For + unknown or bad data dependency, if loop->safelen is non-zero, just + decrease *max_vf to loop->safelen if needed and return false. + * tree-if-conv.c (main_tree_if_conversion): If-convert also loops with + loop->force_vect. + (gate_tree_if_conversion): Return true even if + cfun->has_force_vect_loops. + +2013-05-09 Jakub Jelinek + + * tree.c (omp_declare_simd_clauses_equal): New function. + (attribute_value_equal): Call it for -fopenmp if + TREE_VALUE of the attributes are both OMP_CLAUSEs. + * tree.h (omp_declare_simd_clauses_equal): Declare. + +2013-04-30 Jakub Jelinek + + * gimple-pretty-print.c (dump_gimple_omp_atomic_load, + dump_gimple_omp_atomic_store): Handle gimple_omp_atomic_seq_cst_p. + * gimple.h (enum gf_mask): Add GF_OMP_ATOMIC_SEQ_CST. + (gimple_omp_atomic_set_seq_cst, gimple_omp_atomic_seq_cst_p): New + inline functions. + * omp-low.c (expand_omp_atomic_load, expand_omp_atomic_store, + expand_omp_atomic_fetch_op): If gimple_omp_atomic_seq_cst_p, + pass MEMMODEL_SEQ_CST instead of MEMMODEL_RELAXED to the builtin. + * gimplify.c (gimplify_omp_atomic): Handle OMP_ATOMIC_SEQ_CST. + * tree-pretty-print.c (dump_generic_node): Handle OMP_ATOMIC_SEQ_CST. + * tree.def (OMP_ATOMIC): Add comment that OMP_ATOMIC* must stay + consecutive. + * tree.h (OMP_ATOMIC_SEQ_CST): Define. + + * omp-low.c (check_omp_nesting_restrictions): Diagnose + OpenMP constructs nested inside simd region. Don't treat + #pragma omp simd as work-sharing region. Disallow work-sharing + constructs inside of critical region. Complain if ordered + region is nested inside of parallel region without loop + region in between. + (scan_omp_1_stmt): Call check_omp_nesting_restrictions even + for GOMP_{cancel{,lation_point},taskyield,taskwait} calls. + +2013-04-23 Jakub Jelinek + + * Makefile.in (omp-low.o): Depend on $(TARGET_H). + * gimplify.c (gimplify_adjust_omp_clauses): For linear clauses + if outer_context is non-NULL, but not ORT_COMBINED_PARALLEL, + call omp_notice_variable. Remove aligned clauses that can't + be handled yet. + * omp-low.c: Include target.h. + (scan_sharing_clauses): For aligned clauses with global arrays + register local replacement. + (omp_clause_aligned_alignment): New function. + (lower_rec_input_clauses): For aligned clauses for global + arrays or automatic pointers emit __builtin_assume_aligned + before the loop if possible. + (expand_omp_regimplify_p, expand_omp_build_assign): New functions. + (expand_omp_simd): Use them. Handle pointer iterators and broken + loops. + (lower_omp_for): Call lower_omp on gimple_omp_body_ptr after + calling lower_rec_input_clauses, not before it. + +2013-04-19 Jakub Jelinek + + * tree.h (OMP_CLAUSE_LINEAR_NO_COPYIN, + OMP_CLAUSE_LINEAR_NO_COPYOUT): Define. + * omp-low.c (extract_omp_for_data): Handle #pragma omp simd. + (build_outer_var_ref): For #pragma omp simd allow linear etc. + clauses to bind even to private vars. + (scan_sharing_clauses): Handle OMP_CLAUSE_LINEAR, OMP_CLAUSE_ALIGNED + and OMP_CLAUSE_SAFELEN. + (lower_rec_input_clauses): Handle OMP_CLAUSE_LINEAR. Don't emit + a GOMP_barrier call for firstprivate/lastprivate in #pragma omp simd. + (lower_lastprivate_clauses): Handle also OMP_CLAUSE_LINEAR. + (expand_omp_simd): New function. + (expand_omp_for): Handle #pragma omp simd. + * gimplify.c (enum gimplify_omp_var_data): Add GOVD_LINEAR and + GOVD_ALIGNED, add GOVD_LINEAR into GOVD_DATA_SHARE_CLASS. + (enum omp_region_type): Add ORT_SIMD. + (gimple_add_tmp_var, gimplify_var_or_parm_decl, omp_check_private, + omp_firstprivatize_variable, omp_notice_variable): Handle ORT_SIMD + like ORT_WORKSHARE. + (omp_is_private): Likewise. Add SIMD argument, tweak diagnostics + and add extra errors in simd constructs. + (gimplify_scan_omp_clauses, gimplify_adjust_omp_clauses): Handle + OMP_CLAUSE_LINEAR, OMP_CLAUSE_ALIGNED and OMP_CLAUSE_SAFELEN. + (gimplify_adjust_omp_clauses_1): Handle GOVD_LASTPRIVATE and + GOVD_ALIGNED. + (gimplify_omp_for): Handle #pragma omp simd. + +2013-04-10 Jakub Jelinek + + * builtin-types.def (DEF_FUNCTION_TYPE_8): Document. + (BT_FN_VOID_OMPFN_PTR_UINT, BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG, + BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG): Remove. + (BT_FN_VOID_OMPFN_PTR_UINT_UINT_UINT, + BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_UINT, + BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT): New. + * gimplify.c (gimplify_scan_omp_clauses, gimplify_adjust_omp_clauses): + Handle OMP_CLAUSE_PROC_BIND. + * omp-builtins.def (BUILT_IN_GOMP_TASKGROUP_START, + BUILT_IN_GOMP_TASKGROUP_END, BUILT_IN_GOMP_PARALLEL_LOOP_STATIC, + BUILT_IN_GOMP_PARALLEL_LOOP_DYNAMIC, + BUILT_IN_GOMP_PARALLEL_LOOP_GUIDED, + BUILT_IN_GOMP_PARALLEL_LOOP_RUNTIME, BUILT_IN_GOMP_PARALLEL, + BUILT_IN_GOMP_PARALLEL_SECTIONS): New built-ins. + (BUILT_IN_GOMP_PARALLEL_LOOP_STATIC_START, + BUILT_IN_GOMP_PARALLEL_LOOP_DYNAMIC_START, + BUILT_IN_GOMP_PARALLEL_LOOP_GUIDED_START, + BUILT_IN_GOMP_PARALLEL_LOOP_RUNTIME_START, + BUILT_IN_GOMP_PARALLEL_START, BUILT_IN_GOMP_PARALLEL_END, + BUILT_IN_GOMP_PARALLEL_SECTIONS_START): Remove. + * omp-low.c (scan_sharing_clauses): Handle OMP_CLAUSE_PROC_BIND. + (expand_parallel_call): Expand #pragma omp parallel* as + calls to the new GOMP_parallel_* APIs without _start at the end, + instead of GOMP_parallel_*_start followed by fn.omp_fn.N call, + followed by GOMP_parallel_end. Handle OMP_CLAUSE_PROC_BIND. + * tree-ssa-alias.c (ref_maybe_used_by_call_p_1, + call_may_clobber_ref_p_1): Handle BUILT_IN_GOMP_TASKGROUP_END + instead of BUILT_IN_GOMP_PARALLEL_END. + +2013-03-27 Jakub Jelinek + + * gimple-pretty-print.c (dump_gimple_omp_for): Handle different + GIMPLE_OMP_FOR kinds. + * tree.def (OMP_SIMD, OMP_FOR_SIMD, OMP_DISTRIBUTE): New tree codes. + * gimple.h (enum gf_mask): Add GF_OMP_FOR_KIND_MASK, + GF_OMP_FOR_KIND_FOR, GF_OMP_FOR_KIND_SIMD, GF_OMP_FOR_KIND_FOR_SIMD + and GF_OMP_FOR_KIND_DISTRIBUTE. + (gimple_omp_for_kind, gimple_omp_for_set_kind): New inline functions. + * gimplify.c (is_gimple_stmt, gimplify_omp_for, gimplify_expr): Handle + OMP_SIMD, OMP_FOR_SIMD and OMP_DISTRIBUTE. + * tree.c (omp_clause_num_ops, omp_clause_code_name, walk_tree_1): + Handle new OpenMP 4.0 clauses. + * tree-pretty-print.c (dump_omp_clause): Likewise. + (dump_generic_node): Handle OMP_SIMD, OMP_FOR_SIMD and OMP_DISTRIBUTE. + * tree.h (enum omp_clause_code): Add OMP_CLAUSE_LINEAR, + OMP_CLAUSE_ALIGNED, OMP_CLAUSE_DEPEND, OMP_CLAUSE_FROM, OMP_CLAUSE_TO, + OMP_CLAUSE_UNIFORM, OMP_CLAUSE_MAP, OMP_CLAUSE_DEVICE, + OMP_CLAUSE_DIST_SCHEDULE, OMP_CLAUSE_INBRANCH, OMP_CLAUSE_NOTINBRANCH, + OMP_CLAUSE_NUM_TEAMS, OMP_CLAUSE_PROC_BIND, OMP_CLAUSE_SAFELEN, + OMP_CLAUSE_SIMDLEN, OMP_CLAUSE_FOR, OMP_CLAUSE_PARALLEL, + OMP_CLAUSE_SECTIONS and OMP_CLAUSE_TASKGROUP. + (OMP_LOOP_CHECK): Define. + (OMP_FOR_BODY, OMP_FOR_CLAUSES, OMP_FOR_INIT, OMP_FOR_COND, + OMP_FOR_INCR, OMP_FOR_PRE_BODY): Use OMP_LOOP_CHECK instead of + OMP_FOR_CHECK. + (OMP_CLAUSE_DECL): Extend check range up to OMP_CLAUSE_MAP. + (OMP_CLAUSE_LINEAR_STEP, OMP_CLAUSE_ALIGNED_ALIGNMENT, + OMP_CLAUSE_NUM_TEAMS_EXPR, OMP_CLAUSE_DEVICE_ID, + OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR, OMP_CLAUSE_SAFELEN_EXPR, + OMP_CLAUSE_SIMDLEN_EXPR): Define. + (enum omp_clause_depend_kind, enum omp_clause_map_kind, + enum omp_clause_proc_bind_kind): New enums. + (OMP_CLAUSE_DEPEND_KIND, OMP_CLAUSE_MAP_KIND, + OMP_CLAUSE_PROC_BIND_KIND): Define. + (struct tree_omp_clause): Add subcode.depend_kind, subcode.map_kind + and subcode.proc_bind_kind. + (find_omp_clause): New prototype. + * omp-builtins.def (BUILT_IN_GOMP_CANCEL, + BUILT_IN_GOMP_CANCELLATION_POINT): New built-ins. + * tree-flow.h (find_omp_clause): Remove prototype. + +Copyright (C) 2013 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index ffd85e76f0310..1ab1da48aa5bb 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1150,7 +1150,7 @@ C_COMMON_OBJS = c-family/c-common.o c-family/c-cppbuiltin.o c-family/c-dump.o \ c-family/c-omp.o c-family/c-opts.o c-family/c-pch.o \ c-family/c-ppoutput.o c-family/c-pragma.o c-family/c-pretty-print.o \ c-family/c-semantics.o c-family/c-ada-spec.o tree-mudflap.o \ - c-family/array-notation-common.o + c-family/array-notation-common.o c-family/c-cilkplus.o # Language-independent object files. # We put the insn-*.o files first so that a parallel make will build @@ -1977,7 +1977,10 @@ c-family/c-lex.o : c-family/c-lex.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(CPPLIB_H) $(TARGET_H) $(TIMEVAR_H) c-family/c-omp.o : c-family/c-omp.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TREE_H) $(C_COMMON_H) $(GIMPLE_H) langhooks.h + $(TREE_H) $(C_COMMON_H) $(C_PRAGMA_H) $(GIMPLE_H) langhooks.h + +c-family/c-cilkplus.o : c-family/c-cilkplus.c $(CONFIG_H) $(SYSTEM_H) \ + coretypes.h $(TREE_H) $(C_COMMON_H) langhooks.h CFLAGS-c-family/c-opts.o += @TARGET_SYSTEM_ROOT_DEFINE@ c-family/c-opts.o : c-family/c-opts.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ @@ -2557,7 +2560,7 @@ omp-low.o : omp-low.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(RTL_H) $(GIMPLE_H) $(TREE_INLINE_H) langhooks.h $(DIAGNOSTIC_CORE_H) \ $(TREE_FLOW_H) $(FLAGS_H) $(EXPR_H) $(DIAGNOSTIC_CORE_H) \ $(TREE_PASS_H) $(GGC_H) $(EXCEPT_H) $(SPLAY_TREE_H) $(OPTABS_H) \ - $(CFGLOOP_H) tree-iterator.h gt-omp-low.h + $(CFGLOOP_H) tree-iterator.h $(TARGET_H) gt-omp-low.h tree-browser.o : tree-browser.c tree-browser.def $(CONFIG_H) $(SYSTEM_H) \ coretypes.h $(HASH_TABLE_H) $(TREE_H) $(TREE_PRETTY_PRINT_H) omega.o : omega.c $(OMEGA_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h $(DUMPFILE_H) \ @@ -2637,7 +2640,7 @@ tree-vect-data-refs.o: tree-vect-data-refs.c $(CONFIG_H) $(SYSTEM_H) \ tree-vectorizer.o: tree-vectorizer.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(DUMPFILE_H) $(TM_H) $(GGC_H) $(TREE_H) $(TREE_FLOW_H) \ $(CFGLOOP_H) $(TREE_PASS_H) $(TREE_VECTORIZER_H) \ - $(TREE_PRETTY_PRINT_H) + $(TREE_PRETTY_PRINT_H) $(HASH_TABLE_H) tree-ssa-propagate.h tree-loop-distribution.o: tree-loop-distribution.c $(CONFIG_H) $(SYSTEM_H) \ coretypes.h $(TREE_FLOW_H) $(CFGLOOP_H) $(TREE_DATA_REF_H) $(TREE_PASS_H) tree-parloops.o: tree-parloops.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ diff --git a/gcc/ada/ChangeLog.gomp b/gcc/ada/ChangeLog.gomp new file mode 100644 index 0000000000000..0bb46186d2b10 --- /dev/null +++ b/gcc/ada/ChangeLog.gomp @@ -0,0 +1,9 @@ +2013-04-10 Jakub Jelinek + + * gcc-interface/utils.c (DEF_FUNCTION_TYPE_8): Define. + +Copyright (C) 2013 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c index 409c0dee94faf..d8cffce3cc979 100644 --- a/gcc/ada/gcc-interface/utils.c +++ b/gcc/ada/gcc-interface/utils.c @@ -5765,6 +5765,7 @@ enum c_builtin_type #define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME, #define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) NAME, #define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) NAME, +#define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8) 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, @@ -5783,6 +5784,7 @@ enum c_builtin_type #undef DEF_FUNCTION_TYPE_5 #undef DEF_FUNCTION_TYPE_6 #undef DEF_FUNCTION_TYPE_7 +#undef DEF_FUNCTION_TYPE_8 #undef DEF_FUNCTION_TYPE_VAR_0 #undef DEF_FUNCTION_TYPE_VAR_1 #undef DEF_FUNCTION_TYPE_VAR_2 @@ -5878,6 +5880,10 @@ install_builtin_function_types (void) #define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7) \ def_fn_type (ENUM, RETURN, 0, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7); +#define DEF_FUNCTION_TYPE_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8) \ + def_fn_type (ENUM, RETURN, 0, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ + ARG7, ARG8); #define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \ def_fn_type (ENUM, RETURN, 1, 0); #define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \ diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def index 2634eccababd5..7c67394b52e38 100644 --- a/gcc/builtin-types.def +++ b/gcc/builtin-types.def @@ -34,6 +34,8 @@ along with GCC; see the file COPYING3. If not see DEF_FUNCTION_TYPE_5 (ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) DEF_FUNCTION_TYPE_6 (ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) DEF_FUNCTION_TYPE_7 (ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) + DEF_FUNCTION_TYPE_8 (ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, + ARG8) These macros describe function types. ENUM is as above. The RETURN type is one of the enumerals already defined. ARG1, ARG2, @@ -411,8 +413,6 @@ DEF_FUNCTION_TYPE_3 (BT_FN_I4_VPTR_I4_I4, BT_I4, BT_VOLATILE_PTR, BT_I4, BT_I4) DEF_FUNCTION_TYPE_3 (BT_FN_I8_VPTR_I8_I8, BT_I8, BT_VOLATILE_PTR, BT_I8, BT_I8) DEF_FUNCTION_TYPE_3 (BT_FN_I16_VPTR_I16_I16, BT_I16, BT_VOLATILE_PTR, BT_I16, BT_I16) -DEF_FUNCTION_TYPE_3 (BT_FN_VOID_OMPFN_PTR_UINT, BT_VOID, BT_PTR_FN_VOID_PTR, - BT_PTR, BT_UINT) DEF_FUNCTION_TYPE_3 (BT_FN_PTR_CONST_PTR_INT_SIZE, BT_PTR, BT_CONST_PTR, BT_INT, BT_SIZE) DEF_FUNCTION_TYPE_3 (BT_FN_I1_VPTR_I1_INT, BT_I1, BT_VOLATILE_PTR, BT_I1, BT_INT) @@ -467,6 +467,9 @@ DEF_FUNCTION_TYPE_5 (BT_FN_BOOL_VPTR_PTR_I8_INT_INT, BT_BOOL, BT_VOLATILE_PTR, BT_PTR, BT_I8, BT_INT, BT_INT) DEF_FUNCTION_TYPE_5 (BT_FN_BOOL_VPTR_PTR_I16_INT_INT, BT_BOOL, BT_VOLATILE_PTR, BT_PTR, BT_I16, BT_INT, BT_INT) +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_6 (BT_FN_INT_STRING_SIZE_INT_SIZE_CONST_STRING_VALIST_ARG, BT_INT, BT_STRING, BT_SIZE, BT_INT, BT_SIZE, @@ -474,9 +477,6 @@ DEF_FUNCTION_TYPE_6 (BT_FN_INT_STRING_SIZE_INT_SIZE_CONST_STRING_VALIST_ARG, DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_LONG_LONG_LONG_LONG_LONGPTR_LONGPTR, BT_BOOL, BT_LONG, BT_LONG, BT_LONG, BT_LONG, BT_PTR_LONG, BT_PTR_LONG) -DEF_FUNCTION_TYPE_6 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG, - BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, - BT_LONG, BT_LONG, BT_LONG) DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULLPTR_ULLPTR, BT_BOOL, BT_BOOL, BT_ULONGLONG, BT_ULONGLONG, BT_ULONGLONG, BT_PTR_ULONGLONG, BT_PTR_ULONGLONG) @@ -498,10 +498,9 @@ DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_VPTR_PTR_I16_BOOL_INT_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_7 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG, +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_LONG, BT_LONG, BT_LONG, BT_LONG) + BT_LONG, BT_LONG, BT_LONG, BT_UINT) DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT, BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_PTR_FN_VOID_PTR_PTR, BT_LONG, BT_LONG, @@ -511,6 +510,10 @@ DEF_FUNCTION_TYPE_7 (BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULL_ULLPTR_ULLPTR, BT_ULONGLONG, BT_ULONGLONG, BT_PTR_ULONGLONG, BT_PTR_ULONGLONG) +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_VAR_0 (BT_FN_VOID_VAR, BT_VOID) DEF_FUNCTION_TYPE_VAR_0 (BT_FN_INT_VAR, BT_INT) DEF_FUNCTION_TYPE_VAR_0 (BT_FN_PTR_VAR, BT_PTR) diff --git a/gcc/c-family/ChangeLog.gomp b/gcc/c-family/ChangeLog.gomp new file mode 100644 index 0000000000000..ce6c8dda44ae7 --- /dev/null +++ b/gcc/c-family/ChangeLog.gomp @@ -0,0 +1,102 @@ +2013-06-21 Jakub Jelinek + + * c-omp.c (c_omp_split_clauses): Fix up OMP_CLAUSE_COLLAPSE + handling. + +2013-06-14 Jakub Jelinek + + * c-common.h: Move omp_clause_mask code earlier in the file. + (c_omp_split_clauses): New prototype. + (c_split_parallel_clauses): Removed. + * c-pragma.h (enum pragma_kind): Add + PRAGMA_OMP_DISTRIBUTE_PARALLEL_FOR, + PRAGMA_OMP_DISTRIBUTE_PARALLEL_FOR_SIMD, + PRAGMA_OMP_DISTRIBUTE_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_TEAMS_DISTRIBUTE, + PRAGMA_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR, + and PRAGMA_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD. + * c-omp.c: Include c-pragma.h. + (c_omp_split_clauses): New function. + (c_split_parallel_clauses): Remove. + +2013-06-12 Jakub Jelinek + + * c-pragma.h (enum pragma_omp_clause): Add + PRAGMA_OMP_CLAUSE_THREAD_LIMIT. + +2013-05-29 Jakub Jelinek + + * c-common.c (c_common_attribute_table): Add "omp declare target" + attribute. + (handle_omp_declare_target_attribute): New function. + +2013-05-09 Jakub Jelinek + + * c-common.c (c_common_attribute_table): Add "omp declare simd" + attribute. + (handle_omp_declare_simd_attribute): New function. + * c-common.h (c_omp_declare_simd_clauses_to_numbers, + c_omp_declare_simd_clauses_to_decls): Declare. + * c-omp.c (c_omp_declare_simd_clause_cmp, + c_omp_declare_simd_clauses_to_numbers, + c_omp_declare_simd_clauses_to_decls): New functions. + +2013-04-30 Jakub Jelinek + + * c-omp.c (c_finish_omp_atomic): Add seq_cst argument, store it + into OMP_ATOMIC_SEQ_CST bit. + * c-common.h (c_finish_omp_atomic): Adjust prototype. + + * c-pragma.c (omp_pragmas): Add PRAGMA_OMP_DISTRIBUTE. + +2013-04-10 Jakub Jelinek + + * c-common.c (DEF_FUNCTION_TYPE_8): Define. + * c-omp.c (c_split_parallel_clauses): Handle OMP_CLAUSE_PROC_BIND. + +2013-03-27 Jakub Jelinek + + * c-omp.c (c_finish_omp_for): Add code argument, pass it down to + make_code. + (c_split_parallel_clauses): Handle OMP_CLAUSE_SAFELEN, + OMP_CLAUSE_ALIGNED and OMP_CLAUSE_LINEAR. + * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_CANCEL, + PRAGMA_OMP_CANCELLATION_POINT, PRAGMA_OMP_DECLARE_REDUCTION, + PRAGMA_OMP_DECLARE_SIMD, PRAGMA_OMP_DECLARE_TARGET, + PRAGMA_OMP_DISTRIBUTE, PRAGMA_OMP_END_DECLARE_TARGET, + PRAGMA_OMP_FOR_SIMD, PRAGMA_OMP_PARALLEL_FOR_SIMD, PRAGMA_OMP_SIMD, + PRAGMA_OMP_TARGET, PRAGMA_OMP_TARGET_DATA, PRAGMA_OMP_TARGET_UPDATE, + PRAGMA_OMP_TASKGROUP and PRAGMA_OMP_TEAMS. + (enum pragma_omp_clause): Add PRAGMA_OMP_CLAUSE_ALIGNED, + PRAGMA_OMP_CLAUSE_DEPEND, PRAGMA_OMP_CLAUSE_DEVICE, + PRAGMA_OMP_CLAUSE_DIST_SCHEDULE, PRAGMA_OMP_CLAUSE_FOR, + PRAGMA_OMP_CLAUSE_FROM, PRAGMA_OMP_CLAUSE_INBRANCH, + PRAGMA_OMP_CLAUSE_LINEAR, PRAGMA_OMP_CLAUSE_MAP, + PRAGMA_OMP_CLAUSE_NOTINBRANCH, PRAGMA_OMP_CLAUSE_NUM_TEAMS, + PRAGMA_OMP_CLAUSE_PARALLEL, PRAGMA_OMP_CLAUSE_PROC_BIND, + PRAGMA_OMP_CLAUSE_SAFELEN, PRAGMA_OMP_CLAUSE_SECTIONS, + PRAGMA_OMP_CLAUSE_SIMDLEN, PRAGMA_OMP_CLAUSE_TASKGROUP, + PRAGMA_OMP_CLAUSE_TO and PRAGMA_OMP_CLAUSE_UNIFORM. + * c-pragma.c (omp_pragmas): Add new OpenMP 4.0 constructs. + * c-common.h (c_finish_omp_for): Add enum tree_code as second + argument. + (OMP_CLAUSE_MASK_1): Define. + (omp_clause_mask): For HWI >= 64 new typedef for + unsigned HOST_WIDE_INT, otherwise a class with needed ctors and + operators. + +2013-03-20 Jakub Jelinek + + * c-omp.c (c_finish_omp_atomic): Add swapped argument, if true, + build the operation first with rhs, lhs arguments and use NOP_EXPR + build_modify_expr. + * c-common.h (c_finish_omp_atomic): Adjust prototype. + +Copyright (C) 2013 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/gcc/c-family/c-cilkplus.c b/gcc/c-family/c-cilkplus.c new file mode 100644 index 0000000000000..861bcbc4d704d --- /dev/null +++ b/gcc/c-family/c-cilkplus.c @@ -0,0 +1,407 @@ +/* This file contains routines to construct and validate Cilk Plus + constructs within the C and C++ front ends. + + Copyright (C) 2011-2013 Free Software Foundation, Inc. + Contributed by Balaji V. Iyer , + Aldy Hernandez . + +This file is part of GCC. + +GCC 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. + +GCC 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. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "c-common.h" + +/* Helper function for c_check_cilk_loop. + + Validate the increment in a _Cilk_for construct or a <#pragma simd> + for loop. + + LOC is the location of the `for' keyword. DECL is the induction + variable. INCR is the original increment expression. + + Returns the canonicalized increment expression for an OMP_FOR_INCR. + If there is a validation error, returns error_mark_node. */ + +static tree +c_check_cilk_loop_incr (location_t loc, tree decl, tree incr) +{ + if (EXPR_HAS_LOCATION (incr)) + loc = EXPR_LOCATION (incr); + + if (!incr) + { + error_at (loc, "missing increment"); + return error_mark_node; + } + + switch (TREE_CODE (incr)) + { + case POSTINCREMENT_EXPR: + case PREINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + case PREDECREMENT_EXPR: + if (TREE_OPERAND (incr, 0) != decl) + break; + + // Bah... canonicalize into whatever OMP_FOR_INCR needs. + if (POINTER_TYPE_P (TREE_TYPE (decl)) + && TREE_OPERAND (incr, 1)) + { + tree t = fold_convert_loc (loc, + sizetype, TREE_OPERAND (incr, 1)); + + if (TREE_CODE (incr) == POSTDECREMENT_EXPR + || TREE_CODE (incr) == PREDECREMENT_EXPR) + t = fold_build1_loc (loc, NEGATE_EXPR, sizetype, t); + t = fold_build_pointer_plus (decl, t); + incr = build2 (MODIFY_EXPR, void_type_node, decl, t); + } + return incr; + + case MODIFY_EXPR: + { + tree rhs; + + if (TREE_OPERAND (incr, 0) != decl) + break; + + rhs = TREE_OPERAND (incr, 1); + if (TREE_CODE (rhs) == PLUS_EXPR + && (TREE_OPERAND (rhs, 0) == decl + || TREE_OPERAND (rhs, 1) == decl) + && INTEGRAL_TYPE_P (TREE_TYPE (rhs))) + return incr; + else if (TREE_CODE (rhs) == MINUS_EXPR + && TREE_OPERAND (rhs, 0) == decl + && INTEGRAL_TYPE_P (TREE_TYPE (rhs))) + return incr; + // Otherwise fail because only PLUS_EXPR and MINUS_EXPR are + // allowed. + break; + } + + default: + break; + } + + error_at (loc, "invalid increment expression"); + return error_mark_node; +} + +/* Callback for walk_tree to validate the body of a pragma simd loop + or _cilk_for loop. + + This function is passed in as a function pointer to walk_tree. *TP is + the current tree pointer, *WALK_SUBTREES is set to 0 by this function if + recursing into TP's subtrees is unnecessary. *DATA is a bool variable that + is set to false if an error has occured. */ + +tree +c_validate_cilk_plus_loop (tree *tp, int *walk_subtrees, void *data) +{ + if (!tp || !*tp) + return NULL_TREE; + + bool *valid = (bool *) data; + + switch (TREE_CODE (*tp)) + { + case CALL_EXPR: + { + tree fndecl = CALL_EXPR_FN (*tp); + + if (TREE_CODE (fndecl) == ADDR_EXPR) + fndecl = TREE_OPERAND (fndecl, 0); + if (TREE_CODE (fndecl) == FUNCTION_DECL) + { + if (setjmp_call_p (fndecl)) + { + error_at (EXPR_LOCATION (*tp), + "calls to setjmp are not allowed within loops " + "annotated with #pragma simd"); + *valid = false; + *walk_subtrees = 0; + } + } + break; + } + + case OMP_PARALLEL: + case OMP_TASK: + case OMP_FOR: + case OMP_SIMD: + case OMP_DISTRIBUTE: + case OMP_SECTIONS: + case OMP_SINGLE: + case OMP_SECTION: + case OMP_MASTER: + case OMP_ORDERED: + case OMP_CRITICAL: + case OMP_ATOMIC: + case OMP_ATOMIC_READ: + case OMP_ATOMIC_CAPTURE_OLD: + case OMP_ATOMIC_CAPTURE_NEW: + error_at (EXPR_LOCATION (*tp), "OpenMP statements are not allowed " + "within loops annotated with #pragma simd"); + *valid = false; + *walk_subtrees = 0; + break; + + default: + break; + } + return NULL_TREE; +} + +/* Validate the body of a _Cilk_for construct or a <#pragma simd> for + loop. + + Returns true if there were no errors, false otherwise. */ + +static bool +c_check_cilk_loop_body (tree body) +{ + bool valid = true; + walk_tree (&body, c_validate_cilk_plus_loop, (void *) &valid, NULL); + return valid; +} + +/* Validate a _Cilk_for construct (or a #pragma simd for loop, which + has the same syntactic restrictions). Returns TRUE if there were + no errors, FALSE otherwise. LOC is the location of the for. DECL + is the controlling variable. COND is the condition. INCRP is a + pointer the increment expression (in case, the increment needs to + be canonicalized). BODY is the body of the LOOP. */ + +static bool +c_check_cilk_loop (location_t loc, tree decl, tree cond, tree *incrp, + tree body) +{ + tree incr = *incrp; + + if (decl == error_mark_node + || cond == error_mark_node + || incr == error_mark_node + || body == error_mark_node) + return false; + + /* Validate the initialization. */ + gcc_assert (decl != NULL); + if (TREE_THIS_VOLATILE (decl)) + { + error_at (loc, "induction variable cannot be volatile"); + return false; + } + if (DECL_EXTERNAL (decl)) + { + error_at (loc, "induction variable cannot be extern"); + return false; + } + if (TREE_STATIC (decl)) + { + error_at (loc, "induction variable cannot be static"); + return false; + } + if (DECL_REGISTER (decl)) + { + error_at (loc, "induction variable cannot be declared register"); + return false; + } + if (!INTEGRAL_TYPE_P (TREE_TYPE (decl)) + && !POINTER_TYPE_P (TREE_TYPE (decl))) + { + error_at (loc, "initialization variable must be of integral " + "or pointer type"); + return false; + } + + /* Validate the condition. */ + if (!cond) + { + error_at (loc, "missing condition"); + return false; + } + bool cond_ok = false; + if (TREE_CODE (cond) == NE_EXPR + || TREE_CODE (cond) == LT_EXPR + || TREE_CODE (cond) == LE_EXPR + || TREE_CODE (cond) == GT_EXPR + || TREE_CODE (cond) == GE_EXPR) + { + /* Comparison must either be: + DECL EXPR + EXPR DECL + */ + if (decl == TREE_OPERAND (cond, 0)) + cond_ok = true; + else if (decl == TREE_OPERAND (cond, 1)) + { + /* Canonicalize the comparison so the DECL is on the LHS. */ + TREE_SET_CODE (cond, + swap_tree_comparison (TREE_CODE (cond))); + TREE_OPERAND (cond, 1) = TREE_OPERAND (cond, 0); + TREE_OPERAND (cond, 0) = decl; + cond_ok = true; + } + } + if (!cond_ok) + { + error_at (loc, "invalid controlling predicate"); + return false; + } + + /* Validate and canonicalize the increment. */ + incr = c_check_cilk_loop_incr (loc, decl, incr); + if (incr == error_mark_node) + return false; + *incrp = incr; + + if (!c_check_cilk_loop_body (body)) + return false; + + return true; +} + +/* Adjust any clauses to match the requirements for OpenMP. */ + +static tree +adjust_clauses_for_omp (tree clauses) +{ + return clauses; +} + +/* Validate and emit code for the FOR loop following a # + construct. + + LOC is the location of the location of the FOR. + DECL is the iteration variable. + INIT is the initialization expression. + COND is the controlling predicate. + INCR is the increment expression. + BODY is the body of the loop. + CLAUSES are the clauses associated with the pragma simd loop. + + Returns the generated statement. */ + +tree +c_finish_cilk_simd_loop (location_t loc, + tree decl, + tree init, tree cond, tree incr, + tree body, + tree clauses) +{ + location_t rhs_loc; + + if (!c_check_cilk_loop (loc, decl, cond, &incr, body)) + return NULL; + + /* In the case of "for (int i = 0...)", init will be a decl. It should + have a DECL_INITIAL that we can turn into an assignment. */ + if (init == decl) + { + rhs_loc = DECL_SOURCE_LOCATION (decl); + + init = DECL_INITIAL (decl); + if (init == NULL) + { + error_at (rhs_loc, "%qE is not initialized", decl); + init = integer_zero_node; + return NULL; + } + + init = build_modify_expr (loc, decl, NULL_TREE, NOP_EXPR, rhs_loc, + init, NULL_TREE); + } + + // The C++ parser just gives us the rhs. + if (TREE_CODE (init) != MODIFY_EXPR) + init = build2 (MODIFY_EXPR, void_type_node, decl, init); + + gcc_assert (TREE_OPERAND (init, 0) == decl); + + tree initv = make_tree_vec (1); + tree condv = make_tree_vec (1); + tree incrv = make_tree_vec (1); + TREE_VEC_ELT (initv, 0) = init; + TREE_VEC_ELT (condv, 0) = cond; + TREE_VEC_ELT (incrv, 0) = incr; + + tree t = make_node (CILK_SIMD); + TREE_TYPE (t) = void_type_node; + OMP_FOR_INIT (t) = initv; + OMP_FOR_COND (t) = condv; + OMP_FOR_INCR (t) = incrv; + OMP_FOR_BODY (t) = body; + OMP_FOR_PRE_BODY (t) = NULL; + OMP_FOR_CLAUSES (t) = adjust_clauses_for_omp (clauses); + + SET_EXPR_LOCATION (t, loc); + return add_stmt (t); +} + +/* Validate and emit code for <#pragma simd> clauses. */ + +tree +c_finish_cilk_clauses (tree clauses) +{ + for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) + { + tree prev = clauses; + + /* If a variable appears in a linear clause it cannot appear in + any other OMP clause. */ + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR) + for (tree c2 = clauses; c2; c2 = OMP_CLAUSE_CHAIN (c2)) + { + if (c == c2) + continue; + enum omp_clause_code code = OMP_CLAUSE_CODE (c2); + + switch (code) + { + case OMP_CLAUSE_LINEAR: + case OMP_CLAUSE_PRIVATE: + case OMP_CLAUSE_FIRSTPRIVATE: + case OMP_CLAUSE_LASTPRIVATE: + case OMP_CLAUSE_REDUCTION: + break; + + case OMP_CLAUSE_SAFELEN: + goto next; + + default: + gcc_unreachable (); + } + + if (OMP_CLAUSE_DECL (c) == OMP_CLAUSE_DECL (c2)) + { + error_at (OMP_CLAUSE_LOCATION (c2), + "variable appears in more than one clause"); + inform (OMP_CLAUSE_LOCATION (c), + "multiple clause defined here"); + // Remove problematic clauses. + OMP_CLAUSE_CHAIN (prev) = OMP_CLAUSE_CHAIN (c2); + } + next: + prev = c2; + } + } + + return clauses; +} diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 8f7f5e52b0a9b..9ba25ec06c31a 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -368,6 +368,10 @@ static tree handle_optimize_attribute (tree *, tree, tree, int, bool *); static tree ignore_attribute (tree *, tree, tree, int, bool *); static tree handle_no_split_stack_attribute (tree *, tree, tree, int, bool *); static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *); +static tree handle_omp_declare_simd_attribute (tree *, tree, tree, int, + bool *); +static tree handle_omp_declare_target_attribute (tree *, tree, tree, int, + bool *); static void check_function_nonnull (tree, int, tree *); static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT); @@ -738,6 +742,10 @@ const struct attribute_spec c_common_attribute_table[] = The name contains space to prevent its usage in source code. */ { "fn spec", 1, 1, false, true, true, handle_fnspec_attribute, false }, + { "omp declare simd", 0, -1, true, false, false, + handle_omp_declare_simd_attribute, false }, + { "omp declare target", 0, 0, true, false, false, + handle_omp_declare_target_attribute, false }, { NULL, 0, 0, false, false, false, NULL, false } }; @@ -5020,6 +5028,7 @@ enum c_builtin_type #define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME, #define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) NAME, #define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) NAME, +#define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8) 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, @@ -5038,6 +5047,7 @@ enum c_builtin_type #undef DEF_FUNCTION_TYPE_5 #undef DEF_FUNCTION_TYPE_6 #undef DEF_FUNCTION_TYPE_7 +#undef DEF_FUNCTION_TYPE_8 #undef DEF_FUNCTION_TYPE_VAR_0 #undef DEF_FUNCTION_TYPE_VAR_1 #undef DEF_FUNCTION_TYPE_VAR_2 @@ -5120,6 +5130,10 @@ c_define_builtins (tree va_list_ref_type_node, tree va_list_arg_type_node) #define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7) \ def_fn_type (ENUM, RETURN, 0, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7); +#define DEF_FUNCTION_TYPE_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8) \ + def_fn_type (ENUM, RETURN, 0, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ + ARG7, ARG8); #define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \ def_fn_type (ENUM, RETURN, 1, 0); #define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \ @@ -7950,6 +7964,24 @@ handle_fnspec_attribute (tree *node ATTRIBUTE_UNUSED, tree ARG_UNUSED (name), return NULL_TREE; } +/* Handle an "omp declare simd" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_omp_declare_simd_attribute (tree *, tree, tree, int, bool *) +{ + return NULL_TREE; +} + +/* Handle an "omp declare target" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_omp_declare_target_attribute (tree *, tree, tree, int, bool *) +{ + return NULL_TREE; +} + /* Handle a "returns_twice" attribute; arguments as in struct attribute_spec.handler. */ diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 6dfcffd792183..986487786a7b8 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -521,6 +521,11 @@ struct GTY(()) c_language_function { #define building_stmt_list_p() (stmt_list_stack && !stmt_list_stack->is_empty()) +/* In c-cilkplus.c */ +extern tree c_finish_cilk_simd_loop (location_t, tree, tree, tree, tree, + tree, tree); +extern tree c_finish_cilk_clauses (tree); + /* Language-specific hooks. */ /* If non-NULL, this function is called after a precompile header file @@ -1033,17 +1038,158 @@ extern void pp_dir_change (cpp_reader *, const char *); extern bool check_missing_format_attribute (tree, tree); /* In c-omp.c */ +#if HOST_BITS_PER_WIDE_INT >= 64 +typedef unsigned HOST_WIDE_INT omp_clause_mask; +# define OMP_CLAUSE_MASK_1 ((omp_clause_mask) 1) +#else +struct omp_clause_mask +{ + inline omp_clause_mask (); + inline omp_clause_mask (unsigned HOST_WIDE_INT l); + inline omp_clause_mask (unsigned HOST_WIDE_INT l, + unsigned HOST_WIDE_INT h); + inline omp_clause_mask &operator &= (omp_clause_mask); + inline omp_clause_mask &operator |= (omp_clause_mask); + inline omp_clause_mask operator ~ () const; + inline omp_clause_mask operator & (omp_clause_mask) const; + inline omp_clause_mask operator | (omp_clause_mask) const; + inline omp_clause_mask operator >> (int); + inline omp_clause_mask operator << (int); + inline bool operator == (omp_clause_mask) const; + unsigned HOST_WIDE_INT low, high; +}; + +inline +omp_clause_mask::omp_clause_mask () +{ +} + +inline +omp_clause_mask::omp_clause_mask (unsigned HOST_WIDE_INT l) +: low (l), high (0) +{ +} + +inline +omp_clause_mask::omp_clause_mask (unsigned HOST_WIDE_INT l, + unsigned HOST_WIDE_INT h) +: low (l), high (h) +{ +} + +inline omp_clause_mask & +omp_clause_mask::operator &= (omp_clause_mask b) +{ + low &= b.low; + high &= b.high; + return *this; +} + +inline omp_clause_mask & +omp_clause_mask::operator |= (omp_clause_mask b) +{ + low |= b.low; + high |= b.high; + return *this; +} + +inline omp_clause_mask +omp_clause_mask::operator ~ () const +{ + omp_clause_mask ret (~low, ~high); + return ret; +} + +inline omp_clause_mask +omp_clause_mask::operator | (omp_clause_mask b) const +{ + omp_clause_mask ret (low | b.low, high | b.high); + return ret; +} + +inline omp_clause_mask +omp_clause_mask::operator & (omp_clause_mask b) const +{ + omp_clause_mask ret (low & b.low, high & b.high); + return ret; +} + +inline omp_clause_mask +omp_clause_mask::operator << (int amount) +{ + omp_clause_mask ret; + if (amount >= HOST_BITS_PER_WIDE_INT) + { + ret.low = 0; + ret.high = low << (amount - HOST_BITS_PER_WIDE_INT); + } + else if (amount == 0) + ret = *this; + else + { + ret.low = low << amount; + ret.high = (low >> (HOST_BITS_PER_WIDE_INT - amount)) + | (high << amount); + } + return ret; +} + +inline omp_clause_mask +omp_clause_mask::operator >> (int amount) +{ + omp_clause_mask ret; + if (amount >= HOST_BITS_PER_WIDE_INT) + { + ret.low = high >> (amount - HOST_BITS_PER_WIDE_INT); + ret.high = 0; + } + else if (amount == 0) + ret = *this; + else + { + ret.low = (high << (HOST_BITS_PER_WIDE_INT - amount)) + | (low >> amount); + ret.high = high >> amount; + } + return ret; +} + +inline bool +omp_clause_mask::operator == (omp_clause_mask b) const +{ + return low == b.low && high == b.high; +} + +# define OMP_CLAUSE_MASK_1 omp_clause_mask (1) +#endif + +enum c_omp_clause_split +{ + C_OMP_CLAUSE_SPLIT_TARGET = 0, + C_OMP_CLAUSE_SPLIT_TEAMS, + C_OMP_CLAUSE_SPLIT_DISTRIBUTE, + C_OMP_CLAUSE_SPLIT_PARALLEL, + 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 +}; + extern tree c_finish_omp_master (location_t, tree); extern tree c_finish_omp_critical (location_t, tree, tree); extern tree c_finish_omp_ordered (location_t, 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); + tree, tree, tree, tree, tree, bool, bool); extern void c_finish_omp_flush (location_t); extern void c_finish_omp_taskwait (location_t); extern void c_finish_omp_taskyield (location_t); -extern tree c_finish_omp_for (location_t, tree, tree, tree, tree, tree, tree); -extern void c_split_parallel_clauses (location_t, tree, tree *, tree *); +extern tree c_finish_omp_for (location_t, enum tree_code, tree, tree, tree, + tree, tree, tree); +extern void c_omp_split_clauses (location_t, enum tree_code, omp_clause_mask, + tree, tree *); +extern tree c_omp_declare_simd_clauses_to_numbers (tree, tree); +extern void c_omp_declare_simd_clauses_to_decls (tree, tree); extern enum omp_clause_default_kind c_omp_predetermined_sharing (tree); /* Not in c-omp.c; provided by the front end. */ @@ -1136,6 +1282,12 @@ enum stv_conv { extern enum stv_conv scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1, bool); +/* In c-cilkplus.c */ +extern tree c_finish_cilk_simd_loop (location_t, tree, tree, tree, tree, + tree, tree); +extern tree c_finish_cilk_clauses (tree); +extern tree c_validate_cilk_plus_loop (tree *, int *, void *); + /* These #defines allow users to access different operands of the array notation tree. */ diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c index f05b60a403501..75e607c3e55c9 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -26,6 +26,7 @@ along with GCC; see the file COPYING3. If not see #include "coretypes.h" #include "tree.h" #include "c-common.h" +#include "c-pragma.h" #include "gimple.h" /* For create_tmp_var_raw. */ #include "langhooks.h" @@ -122,7 +123,7 @@ c_finish_omp_taskyield (location_t loc) tree c_finish_omp_atomic (location_t loc, enum tree_code code, enum tree_code opcode, tree lhs, tree rhs, - tree v, tree lhs1, tree rhs1) + tree v, tree lhs1, tree rhs1, bool swapped, bool seq_cst) { tree x, type, addr; @@ -168,6 +169,7 @@ c_finish_omp_atomic (location_t loc, enum tree_code code, { x = build1 (OMP_ATOMIC_READ, type, addr); SET_EXPR_LOCATION (x, loc); + OMP_ATOMIC_SEQ_CST (x) = seq_cst; return build_modify_expr (loc, v, NULL_TREE, NOP_EXPR, loc, x, NULL_TREE); return x; @@ -176,8 +178,12 @@ c_finish_omp_atomic (location_t loc, enum tree_code code, /* There are lots of warnings, errors, and conversions that need to happen in the course of interpreting a statement. Use the normal mechanisms to do this, and then take it apart again. */ - x = build_modify_expr (input_location, lhs, NULL_TREE, opcode, - input_location, rhs, NULL_TREE); + if (swapped) + { + rhs = build2_loc (loc, opcode, TREE_TYPE (lhs), rhs, lhs); + opcode = NOP_EXPR; + } + x = build_modify_expr (loc, lhs, NULL_TREE, opcode, loc, rhs, NULL_TREE); if (x == error_mark_node) return error_mark_node; gcc_assert (TREE_CODE (x) == MODIFY_EXPR); @@ -188,6 +194,7 @@ c_finish_omp_atomic (location_t loc, enum tree_code code, type = void_type_node; x = build2 (code, type, addr, rhs); SET_EXPR_LOCATION (x, loc); + OMP_ATOMIC_SEQ_CST (x) = seq_cst; /* Generally it is hard to prove lhs1 and lhs are the same memory location, just diagnose different variables. */ @@ -339,8 +346,8 @@ check_omp_for_incr_expr (location_t loc, tree exp, tree decl) the loop. */ tree -c_finish_omp_for (location_t locus, tree declv, tree initv, tree condv, - tree incrv, tree body, tree pre_body) +c_finish_omp_for (location_t locus, enum tree_code code, tree declv, + tree initv, tree condv, tree incrv, tree body, tree pre_body) { location_t elocus; bool fail = false; @@ -565,7 +572,7 @@ c_finish_omp_for (location_t locus, tree declv, tree initv, tree condv, return NULL; else { - tree t = make_node (OMP_FOR); + tree t = make_node (code); TREE_TYPE (t) = void_type_node; OMP_FOR_INIT (t) = initv; @@ -579,21 +586,55 @@ c_finish_omp_for (location_t locus, tree declv, tree initv, tree condv, } } - -/* Divide CLAUSES into two lists: those that apply to a parallel - construct, and those that apply to a work-sharing construct. Place - the results in *PAR_CLAUSES and *WS_CLAUSES respectively. In - addition, add a nowait clause to the work-sharing list. LOC is the - location of the OMP_PARALLEL*. */ +/* Right now we have 14 different combined 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 + #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 target teams + #pragma omp target teams distribute + #pragma omp target teams distribute parallel for + #pragma omp target teams distribute parallel for simd */ void -c_split_parallel_clauses (location_t loc, tree clauses, - tree *par_clauses, tree *ws_clauses) +c_omp_split_clauses (location_t loc, enum tree_code code, + omp_clause_mask mask, tree clauses, tree *cclauses) { - tree next; + tree next, c; + enum c_omp_clause_split s; + int i; - *par_clauses = NULL; - *ws_clauses = build_omp_clause (loc, OMP_CLAUSE_NOWAIT); + for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++) + cclauses[i] = NULL; + /* Add implicit nowait clause on + #pragma omp parallel {for,for simd,sections}. */ + if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)) + switch (code) + { + case OMP_FOR: + case OMP_SIMD: + cclauses[C_OMP_CLAUSE_SPLIT_FOR] + = build_omp_clause (loc, OMP_CLAUSE_NOWAIT); + break; + case OMP_SECTIONS: + cclauses[C_OMP_CLAUSE_SPLIT_SECTIONS] + = build_omp_clause (loc, OMP_CLAUSE_NOWAIT); + break; + default: + break; + } for (; clauses ; clauses = next) { @@ -601,32 +642,322 @@ c_split_parallel_clauses (location_t loc, tree clauses, switch (OMP_CLAUSE_CODE (clauses)) { - case OMP_CLAUSE_PRIVATE: - case OMP_CLAUSE_SHARED: - case OMP_CLAUSE_FIRSTPRIVATE: - case OMP_CLAUSE_LASTPRIVATE: - case OMP_CLAUSE_REDUCTION: + /* First the clauses that are unique to some constructs. */ + case OMP_CLAUSE_DEVICE: + case OMP_CLAUSE_MAP: + s = C_OMP_CLAUSE_SPLIT_TARGET; + break; + case OMP_CLAUSE_NUM_TEAMS: + case OMP_CLAUSE_THREAD_LIMIT: + s = C_OMP_CLAUSE_SPLIT_TEAMS; + break; + case OMP_CLAUSE_DIST_SCHEDULE: + s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE; + break; case OMP_CLAUSE_COPYIN: - case OMP_CLAUSE_IF: case OMP_CLAUSE_NUM_THREADS: - case OMP_CLAUSE_DEFAULT: - OMP_CLAUSE_CHAIN (clauses) = *par_clauses; - *par_clauses = clauses; + case OMP_CLAUSE_PROC_BIND: + s = C_OMP_CLAUSE_SPLIT_PARALLEL; break; - - case OMP_CLAUSE_SCHEDULE: case OMP_CLAUSE_ORDERED: + case OMP_CLAUSE_SCHEDULE: + case OMP_CLAUSE_NOWAIT: + s = C_OMP_CLAUSE_SPLIT_FOR; + break; + case OMP_CLAUSE_SAFELEN: + case OMP_CLAUSE_LINEAR: + case OMP_CLAUSE_ALIGNED: + s = C_OMP_CLAUSE_SPLIT_SIMD; + break; + /* Duplicate this to all of distribute, for and simd. */ case OMP_CLAUSE_COLLAPSE: - OMP_CLAUSE_CHAIN (clauses) = *ws_clauses; - *ws_clauses = clauses; + 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)) + { + if (mask & (OMP_CLAUSE_MASK_1 + << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) + { + 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_FOR]; + cclauses[C_OMP_CLAUSE_SPLIT_FOR] = c; + s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE; + } + else + s = C_OMP_CLAUSE_SPLIT_FOR; + } + else + s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE; + break; + /* Private clause is supported on all constructs but target, + 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. */ + case OMP_CLAUSE_PRIVATE: + switch (code) + { + case OMP_SIMD: s = C_OMP_CLAUSE_SPLIT_SIMD; break; + case OMP_FOR: case OMP_SECTIONS: + case OMP_PARALLEL: s = C_OMP_CLAUSE_SPLIT_PARALLEL; break; + case OMP_DISTRIBUTE: s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE; break; + case OMP_TEAMS: s = C_OMP_CLAUSE_SPLIT_TEAMS; break; + default: gcc_unreachable (); + } + break; + /* Firstprivate clause is supported on all constructs but + target and simd. Put it on the outermost of those and + duplicate on parallel. */ + case OMP_CLAUSE_FIRSTPRIVATE: + if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)) + { + if (mask & ((OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS) + | (OMP_CLAUSE_MASK_1 + << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE))) + { + 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_PARALLEL]; + cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] = c; + if (mask & (OMP_CLAUSE_MASK_1 + << PRAGMA_OMP_CLAUSE_NUM_TEAMS)) + s = C_OMP_CLAUSE_SPLIT_TEAMS; + else + s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE; + } + else + /* This must be + #pragma omp parallel{, for{, simd}, sections}. */ + s = C_OMP_CLAUSE_SPLIT_PARALLEL; + } + else if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS)) + { + /* This must be #pragma omp {,target }teams distribute. */ + gcc_assert (code == OMP_DISTRIBUTE); + s = C_OMP_CLAUSE_SPLIT_TEAMS; + } + else if (mask & (OMP_CLAUSE_MASK_1 + << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) + { + /* This must be #pragma omp distribute simd. */ + gcc_assert (code == OMP_SIMD); + s = C_OMP_CLAUSE_SPLIT_TEAMS; + } + else + { + /* This must be #pragma omp for simd. */ + gcc_assert (code == OMP_SIMD); + s = C_OMP_CLAUSE_SPLIT_FOR; + } + break; + /* Lastprivate is allowed on for, sections and simd. In + parallel {for{, simd},sections} we actually want to put it on + parallel rather than for or sections. */ + case OMP_CLAUSE_LASTPRIVATE: + if (code == OMP_FOR || code == OMP_SECTIONS) + { + if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)) + s = C_OMP_CLAUSE_SPLIT_PARALLEL; + else + s = C_OMP_CLAUSE_SPLIT_FOR; + break; + } + gcc_assert (code == OMP_SIMD); + if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE)) + { + c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses), + OMP_CLAUSE_LASTPRIVATE); + OMP_CLAUSE_DECL (c) = OMP_CLAUSE_DECL (clauses); + if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)) + s = C_OMP_CLAUSE_SPLIT_PARALLEL; + else + s = C_OMP_CLAUSE_SPLIT_FOR; + OMP_CLAUSE_CHAIN (c) = cclauses[s]; + cclauses[s] = c; + } + s = C_OMP_CLAUSE_SPLIT_SIMD; + break; + /* Shared and default clauses are allowed on private and teams. */ + case OMP_CLAUSE_SHARED: + case OMP_CLAUSE_DEFAULT: + if (code == OMP_TEAMS) + { + s = C_OMP_CLAUSE_SPLIT_TEAMS; + break; + } + if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS)) + { + c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses), + OMP_CLAUSE_CODE (clauses)); + if (OMP_CLAUSE_CODE (clauses) == OMP_CLAUSE_SHARED) + OMP_CLAUSE_DECL (c) = OMP_CLAUSE_DECL (clauses); + else + OMP_CLAUSE_DEFAULT_KIND (c) + = 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; + /* Reduction is allowed on simd, for, parallel, sections and teams. + 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_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)) + { + if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS)) + { + 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_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; + cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] = c; + s = C_OMP_CLAUSE_SPLIT_TEAMS; + } + else if (mask & (OMP_CLAUSE_MASK_1 + << PRAGMA_OMP_CLAUSE_NUM_THREADS)) + s = C_OMP_CLAUSE_SPLIT_PARALLEL; + else + s = C_OMP_CLAUSE_SPLIT_FOR; + } + else if (code == OMP_SECTIONS) + s = C_OMP_CLAUSE_SPLIT_PARALLEL; + 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)) + s = C_OMP_CLAUSE_SPLIT_PARALLEL; + else + s = C_OMP_CLAUSE_SPLIT_TARGET; break; - default: gcc_unreachable (); } + OMP_CLAUSE_CHAIN (clauses) = cclauses[s]; + cclauses[s] = clauses; } } + +/* qsort callback to compare #pragma omp declare simd clauses. */ + +static int +c_omp_declare_simd_clause_cmp (const void *p, const void *q) +{ + tree a = *(const tree *) p; + tree b = *(const tree *) q; + if (OMP_CLAUSE_CODE (a) != OMP_CLAUSE_CODE (b)) + { + if (OMP_CLAUSE_CODE (a) > OMP_CLAUSE_CODE (b)) + return -1; + return 1; + } + if (OMP_CLAUSE_CODE (a) != OMP_CLAUSE_SIMDLEN + && OMP_CLAUSE_CODE (a) != OMP_CLAUSE_INBRANCH + && OMP_CLAUSE_CODE (a) != OMP_CLAUSE_NOTINBRANCH) + { + int c = tree_low_cst (OMP_CLAUSE_DECL (a), 0); + int d = tree_low_cst (OMP_CLAUSE_DECL (b), 0); + if (c < d) + return 1; + if (c > d) + return -1; + } + return 0; +} + +/* Change PARM_DECLs in OMP_CLAUSE_DECL of #pragma omp declare simd + CLAUSES on FNDECL into argument indexes and sort them. */ + +tree +c_omp_declare_simd_clauses_to_numbers (tree fndecl, tree clauses) +{ + tree c; + vec clvec = vNULL; + + for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) + { + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_SIMDLEN + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_INBRANCH + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_NOTINBRANCH) + { + tree decl = OMP_CLAUSE_DECL (c); + tree arg; + int idx; + for (arg = DECL_ARGUMENTS (fndecl), idx = 0; arg; + arg = TREE_CHAIN (arg), idx++) + if (arg == decl) + break; + if (arg == NULL_TREE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD is not an argument of %qD", decl, fndecl); + continue; + } + OMP_CLAUSE_DECL (c) = build_int_cst (integer_type_node, idx); + } + clvec.safe_push (c); + } + if (!clvec.is_empty ()) + { + unsigned int len = clvec.length (), i; + clvec.qsort (c_omp_declare_simd_clause_cmp); + clauses = clvec[0]; + for (i = 0; i < len; i++) + OMP_CLAUSE_CHAIN (clvec[i]) = (i < len - 1) ? clvec[i + 1] : NULL_TREE; + } + clvec.release (); + return clauses; +} + +/* Change argument indexes in CLAUSES of FNDECL back to PARM_DECLs. */ + +void +c_omp_declare_simd_clauses_to_decls (tree fndecl, tree clauses) +{ + tree c; + + for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_SIMDLEN + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_INBRANCH + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_NOTINBRANCH) + { + int idx = tree_low_cst (OMP_CLAUSE_DECL (c), 0), i; + tree arg; + for (arg = DECL_ARGUMENTS (fndecl), i = 0; arg; + arg = TREE_CHAIN (arg), i++) + if (i == idx) + break; + gcc_assert (arg); + OMP_CLAUSE_DECL (c) = arg; + } +} + /* True if OpenMP sharing attribute of DECL is predetermined. */ enum omp_clause_default_kind diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c index 309859fc8ec4c..cdc92d53b9a5a 100644 --- a/gcc/c-family/c-pragma.c +++ b/gcc/c-family/c-pragma.c @@ -1167,7 +1167,12 @@ struct omp_pragma_def { const char *name; unsigned int id; }; static const struct omp_pragma_def omp_pragmas[] = { { "atomic", PRAGMA_OMP_ATOMIC }, { "barrier", PRAGMA_OMP_BARRIER }, + { "cancel", PRAGMA_OMP_CANCEL }, + { "cancellation", PRAGMA_OMP_CANCELLATION_POINT }, { "critical", PRAGMA_OMP_CRITICAL }, + { "declare", PRAGMA_OMP_DECLARE_REDUCTION }, + { "distribute", PRAGMA_OMP_DISTRIBUTE }, + { "end", PRAGMA_OMP_END_DECLARE_TARGET }, { "flush", PRAGMA_OMP_FLUSH }, { "for", PRAGMA_OMP_FOR }, { "master", PRAGMA_OMP_MASTER }, @@ -1175,10 +1180,14 @@ static const struct omp_pragma_def omp_pragmas[] = { { "parallel", PRAGMA_OMP_PARALLEL }, { "section", PRAGMA_OMP_SECTION }, { "sections", PRAGMA_OMP_SECTIONS }, + { "simd", PRAGMA_OMP_SIMD }, { "single", PRAGMA_OMP_SINGLE }, + { "target", PRAGMA_OMP_TARGET }, { "task", PRAGMA_OMP_TASK }, + { "taskgroup", PRAGMA_OMP_TASKGROUP }, { "taskwait", PRAGMA_OMP_TASKWAIT }, { "taskyield", PRAGMA_OMP_TASKYIELD }, + { "teams", PRAGMA_OMP_TEAMS }, { "threadprivate", PRAGMA_OMP_THREADPRIVATE } }; @@ -1349,6 +1358,12 @@ init_pragma (void) omp_pragmas[i].id, true, true); } + if (flag_enable_cilkplus && !flag_preprocess_only) + { + cpp_register_deferred_pragma (parse_in, NULL, "simd", + PRAGMA_CILK_SIMD, true, false); + } + if (!flag_preprocess_only) cpp_register_deferred_pragma (parse_in, "GCC", "pch_preprocess", PRAGMA_GCC_PCH_PREPROCESS, false, false); diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h index 41215db00a08b..5814debb1873b 100644 --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -29,21 +29,49 @@ typedef enum pragma_kind { PRAGMA_OMP_ATOMIC, PRAGMA_OMP_BARRIER, + PRAGMA_OMP_CANCEL, + PRAGMA_OMP_CANCELLATION_POINT, PRAGMA_OMP_CRITICAL, + PRAGMA_OMP_DECLARE_REDUCTION, + PRAGMA_OMP_DECLARE_SIMD, + PRAGMA_OMP_DECLARE_TARGET, + PRAGMA_OMP_DISTRIBUTE, + PRAGMA_OMP_DISTRIBUTE_PARALLEL_FOR, + PRAGMA_OMP_DISTRIBUTE_PARALLEL_FOR_SIMD, + PRAGMA_OMP_DISTRIBUTE_SIMD, + PRAGMA_OMP_END_DECLARE_TARGET, PRAGMA_OMP_FLUSH, PRAGMA_OMP_FOR, + PRAGMA_OMP_FOR_SIMD, PRAGMA_OMP_MASTER, PRAGMA_OMP_ORDERED, PRAGMA_OMP_PARALLEL, PRAGMA_OMP_PARALLEL_FOR, + PRAGMA_OMP_PARALLEL_FOR_SIMD, PRAGMA_OMP_PARALLEL_SECTIONS, PRAGMA_OMP_SECTION, PRAGMA_OMP_SECTIONS, + PRAGMA_OMP_SIMD, PRAGMA_OMP_SINGLE, + PRAGMA_OMP_TARGET, + PRAGMA_OMP_TARGET_DATA, + 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_UPDATE, PRAGMA_OMP_TASK, + PRAGMA_OMP_TASKGROUP, PRAGMA_OMP_TASKWAIT, PRAGMA_OMP_TASKYIELD, PRAGMA_OMP_THREADPRIVATE, + PRAGMA_OMP_TEAMS, + PRAGMA_OMP_TEAMS_DISTRIBUTE, + PRAGMA_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR, + PRAGMA_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD, + + /* Top level clause to handle all Cilk Plus pragma simd clauses. */ + PRAGMA_CILK_SIMD, PRAGMA_GCC_PCH_PREPROCESS, @@ -51,30 +79,61 @@ typedef enum pragma_kind { } pragma_kind; -/* All clauses defined by OpenMP 2.5 and 3.0. +/* All clauses defined by OpenMP 2.5, 3.0, 3.1 and 4.0. Used internally by both C and C++ parsers. */ typedef enum pragma_omp_clause { PRAGMA_OMP_CLAUSE_NONE = 0, + PRAGMA_OMP_CLAUSE_ALIGNED, PRAGMA_OMP_CLAUSE_COLLAPSE, PRAGMA_OMP_CLAUSE_COPYIN, PRAGMA_OMP_CLAUSE_COPYPRIVATE, PRAGMA_OMP_CLAUSE_DEFAULT, + PRAGMA_OMP_CLAUSE_DEPEND, + PRAGMA_OMP_CLAUSE_DEVICE, + PRAGMA_OMP_CLAUSE_DIST_SCHEDULE, + PRAGMA_OMP_CLAUSE_FINAL, PRAGMA_OMP_CLAUSE_FIRSTPRIVATE, + PRAGMA_OMP_CLAUSE_FOR, + PRAGMA_OMP_CLAUSE_FROM, PRAGMA_OMP_CLAUSE_IF, + PRAGMA_OMP_CLAUSE_INBRANCH, PRAGMA_OMP_CLAUSE_LASTPRIVATE, + PRAGMA_OMP_CLAUSE_LINEAR, + PRAGMA_OMP_CLAUSE_MAP, + PRAGMA_OMP_CLAUSE_MERGEABLE, + PRAGMA_OMP_CLAUSE_NOTINBRANCH, PRAGMA_OMP_CLAUSE_NOWAIT, + PRAGMA_OMP_CLAUSE_NUM_TEAMS, PRAGMA_OMP_CLAUSE_NUM_THREADS, PRAGMA_OMP_CLAUSE_ORDERED, + PRAGMA_OMP_CLAUSE_PARALLEL, PRAGMA_OMP_CLAUSE_PRIVATE, + PRAGMA_OMP_CLAUSE_PROC_BIND, PRAGMA_OMP_CLAUSE_REDUCTION, + PRAGMA_OMP_CLAUSE_SAFELEN, PRAGMA_OMP_CLAUSE_SCHEDULE, + PRAGMA_OMP_CLAUSE_SECTIONS, PRAGMA_OMP_CLAUSE_SHARED, - PRAGMA_OMP_CLAUSE_UNTIED, - PRAGMA_OMP_CLAUSE_FINAL, - PRAGMA_OMP_CLAUSE_MERGEABLE + PRAGMA_OMP_CLAUSE_SIMDLEN, + PRAGMA_OMP_CLAUSE_TASKGROUP, + PRAGMA_OMP_CLAUSE_THREAD_LIMIT, + PRAGMA_OMP_CLAUSE_TO, + PRAGMA_OMP_CLAUSE_UNIFORM, + PRAGMA_OMP_CLAUSE_UNTIED } pragma_omp_clause; +/* All Cilk Plus #pragma omp clauses. */ +typedef enum pragma_cilk_clause { + PRAGMA_CILK_CLAUSE_NONE = 0, + PRAGMA_CILK_CLAUSE_VECTORLENGTH, + PRAGMA_CILK_CLAUSE_LINEAR, + PRAGMA_CILK_CLAUSE_PRIVATE, + PRAGMA_CILK_CLAUSE_FIRSTPRIVATE, + PRAGMA_CILK_CLAUSE_LASTPRIVATE, + PRAGMA_CILK_CLAUSE_REDUCTION +} pragma_cilk_clause; + extern struct cpp_reader* parse_in; /* It's safe to always leave visibility pragma enabled as if diff --git a/gcc/c/ChangeLog.gomp b/gcc/c/ChangeLog.gomp new file mode 100644 index 0000000000000..463d392ffc105 --- /dev/null +++ b/gcc/c/ChangeLog.gomp @@ -0,0 +1,126 @@ +2013-06-14 Jakub Jelinek + + * c-parser.c (c_parser_omp_for): Comment out OMP_FOR_SIMD uses. + (c_parser_omp_parallel): Call c_omp_split_clauses instead of + c_split_parallel_clauses, adjust the code for different API + of the new function. + +2013-05-13 Jakub Jelinek + + * c-tree.h (c_finish_omp_declare_simd): New prototype. + * c-typeck.c (c_finish_omp_clauses): Handle OMP_CLAUSE_LINEAR_STEP + adjustments for pointer-types here. Diagnose inbranch notinbranch + being used together. + (c_finish_omp_declare_simd): New function. + * c-parser.c (enum pragma_context): Add pragma_struct and + pragma_param. + (c_parser_declaration_or_fndef): Add omp_declare_simd_clauses + argument. Call c_finish_omp_declare_simd if needed. + (c_parser_external_declaration, c_parser_compound_statement_nostart, + c_parser_label, c_parser_for_statement, c_parser_objc_methodprotolist, + c_parser_omp_for_loop): Adjust c_parser_declaration_or_fndef callers. + (c_parser_struct_or_union_specifier): Use pragma_struct instead of + pragma_external. + (c_parser_parameter_declaration): Use pragma_param instead of + pragma_external. + (c_parser_pragma): Handle PRAGMA_OMP_DECLARE_REDUCTION. + Replace == pragma_external with != pragma_stmt && != pragma_compound + test. + (c_parser_omp_variable_list): Add declare_simd argument. Don't lookup + vars if it is true, just store identifiers. + (c_parser_omp_var_list_parens, c_parser_omp_clause_depend, + c_parser_omp_clause_map): Adjust callers. + (c_parser_omp_clause_reduction, c_parser_omp_clause_aligned): Add + declare_simd argument, pass it through to c_parser_omp_variable_list. + (c_parser_omp_clause_linear): Likewise. Don't handle + OMP_CLAUSE_LINEAR_STEP adjustements for pointer-types here. + (c_parser_omp_clause_uniform): Call c_parser_omp_variable_list + instead of c_parser_omp_var_list_parens to pass true as declare_simd. + (c_parser_omp_all_clauses): Add declare_simd argument, pass it through + clause parsing routines as needed. Don't call c_finish_omp_clauses if + set. + (c_parser_omp_simd, c_parser_omp_for, c_parser_omp_sections, + c_parser_omp_parallel, c_parser_omp_single, c_parser_omp_task, + c_parser_omp_cancel, c_parser_omp_cancellation_point): Adjust callers. + (OMP_DECLARE_SIMD_CLAUSE_MASK): Define. + (c_parser_omp_declare_simd, c_parser_omp_declare): New functions. + +2013-04-30 Jakub Jelinek + + * c-parser.c (c_parser_omp_atomic): Parse seq_cst clause, pass + true if it is present to c_finish_omp_atomic. + +2013-04-24 Jakub Jelinek + + * c-parser.c (c_parser_compound_statement, + c_parser_statement): Adjust comments for OpenMP 3.0+ + additions. + (c_parser_pragma): Handle PRAGMA_OMP_CANCEL and + PRAGMA_OMP_CANCELLATION_POINT. + (c_parser_omp_clause_name): Handle new OpenMP 4.0 clauses. + (c_parser_omp_clause_collapse): Fully fold collapse + expression. + (c_parser_omp_clause_branch, c_parser_omp_clause_cancelkind, + c_parser_omp_clause_num_teams, c_parser_omp_clause_aligned, + c_parser_omp_clause_linear, c_parser_omp_clause_safelen, + c_parser_omp_clause_simdlen, c_parser_omp_clause_depend, + c_parser_omp_clause_map, c_parser_omp_clause_device, + c_parser_omp_clause_dist_schedule, c_parser_omp_clause_proc_bind, + c_parser_omp_clause_to, c_parser_omp_clause_from, + c_parser_omp_clause_uniform): New functions. + (c_parser_omp_all_clauses): Handle new OpenMP 4.0 clauses. + (c_parser_omp_for_loop): Add CODE argument, pass it through + to c_finish_omp_for. + (OMP_SIMD_CLAUSE_MASK): Define. + (c_parser_omp_simd): New function. + (c_parser_omp_for): Parse #pragma omp for simd. + (OMP_PARALLEL_CLAUSE_MASK): Add OMP_CLAUSE_PROC_BIND. + (c_parser_omp_parallel): Parse #pragma omp parallel for simd. + (OMP_TASK_CLAUSE_MASK): Add OMP_CLAUSE_DEPEND. + (c_parser_omp_taskgroup): New function. + (OMP_CANCEL_CLAUSE_MASK, OMP_CANCELLATION_POINT_CLAUSE_MASK): Define. + (c_parser_omp_cancel, c_parser_omp_cancellation_point): New functions. + (c_parser_omp_construct): Handle PRAGMA_OMP_SIMD and + PRAGMA_OMP_TASKGROUP. + (c_parser_transaction_cancel): Formatting fix. + * c-tree.h (c_begin_omp_taskgroup, c_finish_omp_taskgroup, + c_finish_omp_cancel, c_finish_omp_cancellation_point): New prototypes. + * c-typeck.c (c_begin_omp_taskgroup, c_finish_omp_taskgroup, + c_finish_omp_cancel, c_finish_omp_cancellation_point): New functions. + (c_finish_omp_clauses): Handle new OpenMP 4.0 clauses. + +2013-03-27 Jakub Jelinek + + * c-parser.c (c_parser_omp_all_clauses): Change mask argument type + from unsigned to omp_clause_mask. + (c_parser_omp_for_loop): Adjust c_finish_omp_for caller. + (OMP_FOR_CLAUSE_MASK, OMP_SECTIONS_CLAUSE_MASK, + OMP_PARALLEL_CLAUSE_MASK, OMP_SINGLE_CLAUSE_MASK, + OMP_TASK_CLAUSE_MASK): Use OMP_CLAUSE_MASK_1 instead of 1. + (c_parser_omp_parallel): Use omp_clause_mask type instead of unsigned + for mask, use OMP_CLAUSE_MASK_1 instead of 1 for masks. + +2013-03-20 Jakub Jelinek + + * c-parser.c (c_parser_expr_no_commas): Add omp_atomic_lhs argument + with default value, pass it down to c_parser_conditional_expression. + (c_parser_conditional_expression): Add omp_atomic_lhs argument, pass + it down to c_parser_binary_expression. Don't pass PREC_NONE to + it. Adjust recursive call. + (c_parser_binary_expression): Remove prec argument, add omp_atomic_lhs + argument. Always start from PREC_NONE, if omp_atomic_lhs is non-NULL + and one of the arguments of toplevel binop matches it, use build2 + instead of parser_build_binary_op. + (c_parser_omp_atomic): Handle OpenMP 4.0 atomics. + (c_parser_omp_for_loop): Adjust c_parser_binary_expression caller. + * c-tree.h (c_tree_equal): New prototype. + * c-typeck.c (c_tree_equal): New function. + + * c-parser.c (c_parser_omp_atomic): Adjust comment. + Add another argument to c_finish_omp_atomic. + +Copyright (C) 2013 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index d6a500e72b37e..e064b32aeec8c 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1112,7 +1112,7 @@ enum c_parser_prec { static void c_parser_external_declaration (c_parser *); static void c_parser_asm_definition (c_parser *); static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool, - bool, bool, tree *); + bool, bool, tree *, vec); static void c_parser_static_assert_declaration_no_semi (c_parser *); static void c_parser_static_assert_declaration (c_parser *); static void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool, @@ -1155,11 +1155,12 @@ static tree c_parser_asm_statement (c_parser *); static tree c_parser_asm_operands (c_parser *); static tree c_parser_asm_goto_operands (c_parser *); static tree c_parser_asm_clobbers (c_parser *); -static struct c_expr c_parser_expr_no_commas (c_parser *, struct c_expr *); +static struct c_expr c_parser_expr_no_commas (c_parser *, struct c_expr *, + tree = NULL_TREE); static struct c_expr c_parser_conditional_expression (c_parser *, - struct c_expr *); + struct c_expr *, tree); static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *, - enum c_parser_prec); + tree); static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *); static struct c_expr c_parser_unary_expression (c_parser *); static struct c_expr c_parser_sizeof_expression (c_parser *); @@ -1185,9 +1186,13 @@ static void c_parser_omp_barrier (c_parser *); static void c_parser_omp_flush (c_parser *); static void c_parser_omp_taskwait (c_parser *); static void c_parser_omp_taskyield (c_parser *); +static void c_parser_omp_cancel (c_parser *); +static void c_parser_omp_cancellation_point (c_parser *); -enum pragma_context { pragma_external, pragma_stmt, pragma_compound }; +enum pragma_context { pragma_external, pragma_struct, pragma_param, + pragma_stmt, pragma_compound }; static bool c_parser_pragma (c_parser *, enum pragma_context); +static void c_parser_omp_declare (c_parser *, enum pragma_context); /* These Objective-C parser functions are only ever called when compiling Objective-C. */ @@ -1216,6 +1221,10 @@ static void c_parser_objc_at_dynamic_declaration (c_parser *); static bool c_parser_objc_diagnose_bad_element_prefix (c_parser *, struct c_declspecs *); +/* Cilk Plus supporting routines. */ +static void c_parser_cilk_for_statement (c_parser *, enum rid, tree); +static void c_parser_cilk_simd_construct (c_parser *); +static bool c_parser_cilk_verify_simd (c_parser *, enum pragma_context); static tree c_parser_array_notation (location_t, c_parser *, tree, tree); /* Parse a translation unit (C90 6.7, C99 6.9). @@ -1360,7 +1369,8 @@ c_parser_external_declaration (c_parser *parser) an @interface or @protocol with prefix attributes). We can only tell which after parsing the declaration specifiers, if any, and the first declarator. */ - c_parser_declaration_or_fndef (parser, true, true, true, false, true, NULL); + c_parser_declaration_or_fndef (parser, true, true, true, false, true, + NULL, vNULL); break; } } @@ -1440,7 +1450,8 @@ static void c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool static_assert_ok, bool empty_ok, bool nested, bool start_attr_ok, - tree *objc_foreach_object_declaration) + tree *objc_foreach_object_declaration, + vec omp_declare_simd_clauses) { struct c_declspecs *specs; tree prefix_attrs; @@ -1610,6 +1621,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, C_DTR_NORMAL, &dummy); if (declarator == NULL) { + if (omp_declare_simd_clauses.exists ()) + c_finish_omp_declare_simd (NULL_TREE, NULL_TREE, + omp_declare_simd_clauses); c_parser_skip_to_end_of_block_or_statement (parser); return; } @@ -1646,6 +1660,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, chainon (postfix_attrs, all_prefix_attrs)); if (!d) d = error_mark_node; + if (omp_declare_simd_clauses.exists ()) + c_finish_omp_declare_simd (d, NULL_TREE, + omp_declare_simd_clauses); start_init (d, asm_name, global_bindings_p ()); init_loc = c_parser_peek_token (parser)->location; init = c_parser_initializer (parser); @@ -1662,6 +1679,24 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, tree d = start_decl (declarator, specs, false, chainon (postfix_attrs, all_prefix_attrs)); + if (omp_declare_simd_clauses.exists ()) + { + tree parms = NULL_TREE; + if (d && TREE_CODE (d) == FUNCTION_DECL) + { + struct c_declarator *ce = declarator; + while (ce != NULL) + if (ce->kind == cdk_function) + { + parms = ce->u.arg_info->parms; + break; + } + else + ce = ce->declarator; + } + c_finish_omp_declare_simd (d, parms, + omp_declare_simd_clauses); + } if (d) finish_decl (d, UNKNOWN_LOCATION, NULL_TREE, NULL_TREE, asm_name); @@ -1751,8 +1786,11 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, while (c_parser_next_token_is_not (parser, CPP_EOF) && c_parser_next_token_is_not (parser, CPP_OPEN_BRACE)) c_parser_declaration_or_fndef (parser, false, false, false, - true, false, NULL); + true, false, NULL, vNULL); store_parm_decls (); + if (omp_declare_simd_clauses.exists ()) + c_finish_omp_declare_simd (current_function_decl, NULL_TREE, + omp_declare_simd_clauses); DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus = c_parser_peek_token (parser)->location; fnbody = c_parser_compound_statement (parser); @@ -2481,7 +2519,7 @@ c_parser_struct_or_union_specifier (c_parser *parser) /* Accept #pragmas at struct scope. */ if (c_parser_next_token_is (parser, CPP_PRAGMA)) { - c_parser_pragma (parser, pragma_external); + c_parser_pragma (parser, pragma_struct); continue; } /* Parse some comma-separated declarations, but not the @@ -3329,7 +3367,7 @@ c_parser_parameter_declaration (c_parser *parser, tree attrs) /* Accept #pragmas between parameter declarations. */ while (c_parser_next_token_is (parser, CPP_PRAGMA)) - c_parser_pragma (parser, pragma_external); + c_parser_pragma (parser, pragma_param); if (!c_parser_next_token_starts_declspecs (parser)) { @@ -4074,7 +4112,11 @@ c_parser_initval (c_parser *parser, struct c_expr *after, openmp-directive: barrier-directive - flush-directive */ + flush-directive + taskwait-directive + taskyield-directive + cancel-directive + cancellation-point-directive */ static tree c_parser_compound_statement (c_parser *parser) @@ -4179,7 +4221,8 @@ c_parser_compound_statement_nostart (c_parser *parser) { last_label = false; mark_valid_location_for_stdc_pragma (false); - c_parser_declaration_or_fndef (parser, true, true, true, true, true, NULL); + c_parser_declaration_or_fndef (parser, true, true, true, true, + true, NULL, vNULL); if (last_stmt) pedwarn_c90 (loc, (pedantic && !flag_isoc99) @@ -4207,7 +4250,7 @@ c_parser_compound_statement_nostart (c_parser *parser) last_label = false; mark_valid_location_for_stdc_pragma (false); c_parser_declaration_or_fndef (parser, true, true, true, true, - true, NULL); + true, NULL, vNULL); /* Following the old parser, __extension__ does not disable this diagnostic. */ restore_extension_diagnostics (ext); @@ -4345,7 +4388,8 @@ c_parser_label (c_parser *parser) c_parser_declaration_or_fndef (parser, /*fndef_ok*/ false, /*static_assert_ok*/ true, /*empty_ok*/ true, /*nested*/ true, - /*start_attr_ok*/ true, NULL); + /*start_attr_ok*/ true, NULL, + vNULL); } } } @@ -4408,9 +4452,12 @@ c_parser_label (c_parser *parser) openmp-construct: parallel-construct for-construct + simd-construct + for-simd-construct sections-construct single-construct parallel-for-construct + parallel-for-simd-construct parallel-sections-construct master-construct critical-construct @@ -4423,6 +4470,12 @@ c_parser_label (c_parser *parser) for-construct: for-directive iteration-statement + simd-construct: + simd-directive iteration-statements + + for-simd-construct: + for-simd-directive iteration-statements + sections-construct: sections-directive section-scope @@ -4432,6 +4485,9 @@ c_parser_label (c_parser *parser) parallel-for-construct: parallel-for-directive iteration-statement + parallel-for-simd-construct: + parallel-for-simd-directive iteration-statement + parallel-sections-construct: parallel-sections-directive section-scope @@ -4979,7 +5035,7 @@ c_parser_for_statement (c_parser *parser) else if (c_parser_next_tokens_start_declaration (parser)) { c_parser_declaration_or_fndef (parser, true, true, true, true, true, - &object_expression); + &object_expression, vNULL); parser->objc_could_be_foreach_context = false; if (c_parser_next_token_is_keyword (parser, RID_IN)) @@ -5008,7 +5064,7 @@ c_parser_for_statement (c_parser *parser) ext = disable_extension_diagnostics (); c_parser_consume_token (parser); c_parser_declaration_or_fndef (parser, true, true, true, true, - true, &object_expression); + true, &object_expression, vNULL); parser->objc_could_be_foreach_context = false; restore_extension_diagnostics (ext); @@ -5396,13 +5452,14 @@ c_parser_asm_goto_operands (c_parser *parser) error. */ static struct c_expr -c_parser_expr_no_commas (c_parser *parser, struct c_expr *after) +c_parser_expr_no_commas (c_parser *parser, struct c_expr *after, + tree omp_atomic_lhs) { struct c_expr lhs, rhs, ret; enum tree_code code; location_t op_location, exp_location; gcc_assert (!after || c_dialect_objc ()); - lhs = c_parser_conditional_expression (parser, after); + lhs = c_parser_conditional_expression (parser, after, omp_atomic_lhs); op_location = c_parser_peek_token (parser)->location; switch (c_parser_peek_token (parser)->type) { @@ -5476,14 +5533,15 @@ c_parser_expr_no_commas (c_parser *parser, struct c_expr *after) */ static struct c_expr -c_parser_conditional_expression (c_parser *parser, struct c_expr *after) +c_parser_conditional_expression (c_parser *parser, struct c_expr *after, + tree omp_atomic_lhs) { struct c_expr cond, exp1, exp2, ret; location_t cond_loc, colon_loc, middle_loc; gcc_assert (!after || c_dialect_objc ()); - cond = c_parser_binary_expression (parser, after, PREC_NONE); + cond = c_parser_binary_expression (parser, after, omp_atomic_lhs); if (c_parser_next_token_is_not (parser, CPP_QUERY)) return cond; @@ -5535,7 +5593,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after) } { location_t exp2_loc = c_parser_peek_token (parser)->location; - exp2 = c_parser_conditional_expression (parser, NULL); + exp2 = c_parser_conditional_expression (parser, NULL, NULL_TREE); exp2 = default_function_array_read_conversion (exp2_loc, exp2); } c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node; @@ -5622,7 +5680,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after) static struct c_expr c_parser_binary_expression (c_parser *parser, struct c_expr *after, - enum c_parser_prec prec) + tree omp_atomic_lhs) { /* A binary expression is parsed using operator-precedence parsing, with the operands being cast expressions. All the binary @@ -5680,16 +5738,30 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after, stack[sp].expr \ = default_function_array_read_conversion (stack[sp].loc, \ stack[sp].expr); \ - stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc, \ - stack[sp].op, \ - stack[sp - 1].expr, \ - stack[sp].expr); \ + if (__builtin_expect (omp_atomic_lhs != NULL_TREE, 0) && sp == 1 \ + && c_parser_peek_token (parser)->type == CPP_SEMICOLON \ + && ((1 << stack[sp].prec) \ + & (1 << (PREC_BITOR | PREC_BITXOR | PREC_BITAND | PREC_SHIFT \ + | PREC_ADD | PREC_MULT))) \ + && stack[sp].op != TRUNC_MOD_EXPR \ + && stack[0].expr.value != error_mark_node \ + && stack[1].expr.value != error_mark_node \ + && (c_tree_equal (stack[0].expr.value, omp_atomic_lhs) \ + || c_tree_equal (stack[1].expr.value, omp_atomic_lhs))) \ + stack[0].expr.value \ + = build2 (stack[1].op, TREE_TYPE (stack[0].expr.value), \ + stack[0].expr.value, stack[1].expr.value); \ + else \ + stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc, \ + stack[sp].op, \ + stack[sp - 1].expr, \ + stack[sp].expr); \ sp--; \ } while (0) gcc_assert (!after || c_dialect_objc ()); stack[0].loc = c_parser_peek_token (parser)->location; stack[0].expr = c_parser_cast_expression (parser, after); - stack[0].prec = prec; + stack[0].prec = PREC_NONE; sp = 0; while (true) { @@ -5778,11 +5850,7 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after, } binary_loc = c_parser_peek_token (parser)->location; while (oprec <= stack[sp].prec) - { - if (sp == 0) - goto out; - POP; - } + POP; c_parser_consume_token (parser); switch (ocode) { @@ -7732,7 +7800,7 @@ c_parser_objc_methodprotolist (c_parser *parser) } else c_parser_declaration_or_fndef (parser, false, false, true, - false, true, NULL); + false, true, NULL, vNULL); break; } } @@ -8713,6 +8781,28 @@ c_parser_pragma (c_parser *parser, enum pragma_context context) c_parser_omp_taskyield (parser); return false; + case PRAGMA_OMP_CANCEL: + if (context != pragma_compound) + { + if (context == pragma_stmt) + c_parser_error (parser, "%<#pragma omp cancel%> may only be " + "used in compound statements"); + goto bad_stmt; + } + c_parser_omp_cancel (parser); + return false; + + case PRAGMA_OMP_CANCELLATION_POINT: + if (context != pragma_compound) + { + if (context == pragma_stmt) + c_parser_error (parser, "%<#pragma omp cancellation point%> may " + "only be used in compound statements"); + goto bad_stmt; + } + c_parser_omp_cancellation_point (parser); + return false; + case PRAGMA_OMP_THREADPRIVATE: c_parser_omp_threadprivate (parser); return false; @@ -8724,15 +8814,26 @@ c_parser_pragma (c_parser *parser, enum pragma_context context) c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); return false; + case PRAGMA_OMP_DECLARE_REDUCTION: + c_parser_omp_declare (parser, context); + return false; + case PRAGMA_GCC_PCH_PREPROCESS: c_parser_error (parser, "%<#pragma GCC pch_preprocess%> must be first"); c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); return false; + case PRAGMA_CILK_SIMD: + if (!c_parser_cilk_verify_simd (parser, context)) + return false; + c_parser_consume_pragma (parser); + c_parser_cilk_simd_construct (parser); + return false; + default: if (id < PRAGMA_FIRST_EXTERNAL) { - if (context == pragma_external) + if (context != pragma_stmt && context != pragma_compound) { bad_stmt: c_parser_error (parser, "expected declaration specifiers"); @@ -8797,7 +8898,7 @@ c_parser_pragma_pch_preprocess (c_parser *parser) c_common_pch_pragma (parse_in, TREE_STRING_POINTER (name)); } -/* OpenMP 2.5 parsing routines. */ +/* OpenMP 2.5 / 3.0 / 3.1 / 4.0 parsing routines. */ /* Returns name of the next clause. If the clause is not recognized PRAGMA_OMP_CLAUSE_NONE is returned and @@ -8813,12 +8914,18 @@ c_parser_omp_clause_name (c_parser *parser) result = PRAGMA_OMP_CLAUSE_IF; else if (c_parser_next_token_is_keyword (parser, RID_DEFAULT)) result = PRAGMA_OMP_CLAUSE_DEFAULT; + else if (c_parser_next_token_is_keyword (parser, RID_FOR)) + result = PRAGMA_OMP_CLAUSE_FOR; else if (c_parser_next_token_is (parser, CPP_NAME)) { const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); switch (p[0]) { + case 'a': + if (!strcmp ("aligned", p)) + result = PRAGMA_OMP_CLAUSE_ALIGNED; + break; case 'c': if (!strcmp ("collapse", p)) result = PRAGMA_OMP_CLAUSE_COLLAPSE; @@ -8827,23 +8934,45 @@ c_parser_omp_clause_name (c_parser *parser) else if (!strcmp ("copyprivate", p)) result = PRAGMA_OMP_CLAUSE_COPYPRIVATE; break; + case 'd': + if (!strcmp ("depend", p)) + result = PRAGMA_OMP_CLAUSE_DEPEND; + else if (!strcmp ("device", p)) + result = PRAGMA_OMP_CLAUSE_DEVICE; + else if (!strcmp ("dist_schedule", p)) + result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE; + break; case 'f': if (!strcmp ("final", p)) result = PRAGMA_OMP_CLAUSE_FINAL; else if (!strcmp ("firstprivate", p)) result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE; + else if (!strcmp ("from", p)) + result = PRAGMA_OMP_CLAUSE_FROM; + break; + case 'i': + if (!strcmp ("inbranch", p)) + result = PRAGMA_OMP_CLAUSE_INBRANCH; break; case 'l': if (!strcmp ("lastprivate", p)) result = PRAGMA_OMP_CLAUSE_LASTPRIVATE; + else if (!strcmp ("linear", p)) + result = PRAGMA_OMP_CLAUSE_LINEAR; break; case 'm': - if (!strcmp ("mergeable", p)) + if (!strcmp ("map", p)) + result = PRAGMA_OMP_CLAUSE_MAP; + else if (!strcmp ("mergeable", p)) result = PRAGMA_OMP_CLAUSE_MERGEABLE; break; case 'n': - if (!strcmp ("nowait", p)) + if (!strcmp ("notinbranch", p)) + result = PRAGMA_OMP_CLAUSE_NOTINBRANCH; + else if (!strcmp ("nowait", p)) result = PRAGMA_OMP_CLAUSE_NOWAIT; + else if (!strcmp ("num_teams", p)) + result = PRAGMA_OMP_CLAUSE_NUM_TEAMS; else if (!strcmp ("num_threads", p)) result = PRAGMA_OMP_CLAUSE_NUM_THREADS; break; @@ -8852,21 +8981,39 @@ c_parser_omp_clause_name (c_parser *parser) result = PRAGMA_OMP_CLAUSE_ORDERED; break; case 'p': - if (!strcmp ("private", p)) + if (!strcmp ("parallel", p)) + result = PRAGMA_OMP_CLAUSE_PARALLEL; + else if (!strcmp ("private", p)) result = PRAGMA_OMP_CLAUSE_PRIVATE; + else if (!strcmp ("proc_bind", p)) + result = PRAGMA_OMP_CLAUSE_PROC_BIND; break; case 'r': if (!strcmp ("reduction", p)) result = PRAGMA_OMP_CLAUSE_REDUCTION; break; case 's': - if (!strcmp ("schedule", p)) + if (!strcmp ("safelen", p)) + result = PRAGMA_OMP_CLAUSE_SAFELEN; + else if (!strcmp ("schedule", p)) result = PRAGMA_OMP_CLAUSE_SCHEDULE; + else if (!strcmp ("sections", p)) + result = PRAGMA_OMP_CLAUSE_SECTIONS; else if (!strcmp ("shared", p)) result = PRAGMA_OMP_CLAUSE_SHARED; + else if (!strcmp ("simdlen", p)) + result = PRAGMA_OMP_CLAUSE_SIMDLEN; + break; + case 't': + if (!strcmp ("taskgroup", p)) + result = PRAGMA_OMP_CLAUSE_TASKGROUP; + else if (!strcmp ("to", p)) + result = PRAGMA_OMP_CLAUSE_TO; break; case 'u': - if (!strcmp ("untied", p)) + if (!strcmp ("uniform", p)) + result = PRAGMA_OMP_CLAUSE_UNIFORM; + else if (!strcmp ("untied", p)) result = PRAGMA_OMP_CLAUSE_UNTIED; break; } @@ -8911,7 +9058,7 @@ static tree c_parser_omp_variable_list (c_parser *parser, location_t clause_loc, enum omp_clause_code kind, - tree list) + tree list, bool declare_simd) { if (c_parser_next_token_is_not (parser, CPP_NAME) || c_parser_peek_token (parser)->id_kind != C_ID_ID) @@ -8920,7 +9067,12 @@ c_parser_omp_variable_list (c_parser *parser, 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 t; + + if (declare_simd) + t = c_parser_peek_token (parser)->value; + else + t = lookup_name (c_parser_peek_token (parser)->value); if (t == NULL_TREE) undeclared_variable (c_parser_peek_token (parser)->location, @@ -8960,7 +9112,7 @@ c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind, if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { - list = c_parser_omp_variable_list (parser, loc, kind, list); + list = c_parser_omp_variable_list (parser, loc, kind, list, false); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); } return list; @@ -8986,6 +9138,8 @@ c_parser_omp_clause_collapse (c_parser *parser, tree list) } if (num == error_mark_node) return list; + mark_exp_read (num); + num = c_fully_fold (num, false, NULL); if (!INTEGRAL_TYPE_P (TREE_TYPE (num)) || !host_integerp (num, 0) || (n = tree_low_cst (num, 0)) <= 0 @@ -9251,14 +9405,14 @@ c_parser_omp_clause_private (c_parser *parser, tree list) reduction-operator: One of: + * - & ^ | && || - + OpenMP 3.1: reduction-operator: One of: + * - & ^ | && || max min */ static tree -c_parser_omp_clause_reduction (c_parser *parser, tree list) +c_parser_omp_clause_reduction (c_parser *parser, tree list, bool declare_simd) { location_t clause_loc = c_parser_peek_token (parser)->location; if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) @@ -9320,7 +9474,8 @@ c_parser_omp_clause_reduction (c_parser *parser, tree list) tree nl, c; nl = c_parser_omp_variable_list (parser, clause_loc, - OMP_CLAUSE_REDUCTION, list); + OMP_CLAUSE_REDUCTION, list, + declare_simd); for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) OMP_CLAUSE_REDUCTION_CODE (c) = code; @@ -9452,195 +9607,813 @@ c_parser_omp_clause_untied (c_parser *parser ATTRIBUTE_UNUSED, tree list) return c; } -/* Parse all OpenMP clauses. The set clauses allowed by the directive - is a bitmask in MASK. Return the list of clauses found; the result - of clause default goes in *pdefault. */ +/* OpenMP 4.0: + inbranch + notinbranch */ static tree -c_parser_omp_all_clauses (c_parser *parser, unsigned int mask, - const char *where) +c_parser_omp_clause_branch (c_parser *parser ATTRIBUTE_UNUSED, + enum omp_clause_code code, tree list) { - tree clauses = NULL; - bool first = true; + check_no_duplicate_clause (list, code, omp_clause_code_name[code]); - while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) - { - location_t here; - pragma_omp_clause c_kind; - const char *c_name; - tree prev = clauses; + tree c = build_omp_clause (c_parser_peek_token (parser)->location, code); + OMP_CLAUSE_CHAIN (c) = list; - if (!first && c_parser_next_token_is (parser, CPP_COMMA)) - c_parser_consume_token (parser); + return c; +} - first = false; - here = c_parser_peek_token (parser)->location; - c_kind = c_parser_omp_clause_name (parser); +/* OpenMP 4.0: + parallel + for + sections + taskgroup */ - switch (c_kind) +static tree +c_parser_omp_clause_cancelkind (c_parser *parser ATTRIBUTE_UNUSED, + enum omp_clause_code code, tree list) +{ + tree c; + location_t loc = c_parser_peek_token (parser)->location; + + for (c = list; c; c = OMP_CLAUSE_CHAIN (c)) + switch (OMP_CLAUSE_CODE (c)) + { + case OMP_CLAUSE_PARALLEL: + case OMP_CLAUSE_FOR: + case OMP_CLAUSE_SECTIONS: + case OMP_CLAUSE_TASKGROUP: + error_at (loc, "only one of %, %, % " + "and % clauses can be specified"); + break; + default: + break; + } + + c = build_omp_clause (loc, code); + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 4.0: + num_teams ( expression ) */ + +static tree +c_parser_omp_clause_num_teams (c_parser *parser, tree list) +{ + location_t num_teams_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))) { - case PRAGMA_OMP_CLAUSE_COLLAPSE: - clauses = c_parser_omp_clause_collapse (parser, clauses); - c_name = "collapse"; - break; - case PRAGMA_OMP_CLAUSE_COPYIN: - clauses = c_parser_omp_clause_copyin (parser, clauses); - c_name = "copyin"; - break; - case PRAGMA_OMP_CLAUSE_COPYPRIVATE: - clauses = c_parser_omp_clause_copyprivate (parser, clauses); - c_name = "copyprivate"; - break; - case PRAGMA_OMP_CLAUSE_DEFAULT: - clauses = c_parser_omp_clause_default (parser, clauses); - c_name = "default"; - break; - case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE: - clauses = c_parser_omp_clause_firstprivate (parser, clauses); - c_name = "firstprivate"; - break; - case PRAGMA_OMP_CLAUSE_FINAL: - clauses = c_parser_omp_clause_final (parser, clauses); - c_name = "final"; - break; - case PRAGMA_OMP_CLAUSE_IF: - clauses = c_parser_omp_clause_if (parser, clauses); - c_name = "if"; - break; - case PRAGMA_OMP_CLAUSE_LASTPRIVATE: - clauses = c_parser_omp_clause_lastprivate (parser, clauses); - c_name = "lastprivate"; - break; - case PRAGMA_OMP_CLAUSE_MERGEABLE: - clauses = c_parser_omp_clause_mergeable (parser, clauses); - c_name = "mergeable"; - break; - case PRAGMA_OMP_CLAUSE_NOWAIT: - clauses = c_parser_omp_clause_nowait (parser, clauses); - c_name = "nowait"; - break; - case PRAGMA_OMP_CLAUSE_NUM_THREADS: - clauses = c_parser_omp_clause_num_threads (parser, clauses); - c_name = "num_threads"; - break; - case PRAGMA_OMP_CLAUSE_ORDERED: - clauses = c_parser_omp_clause_ordered (parser, clauses); - c_name = "ordered"; - break; - case PRAGMA_OMP_CLAUSE_PRIVATE: - clauses = c_parser_omp_clause_private (parser, clauses); - c_name = "private"; - break; - case PRAGMA_OMP_CLAUSE_REDUCTION: - clauses = c_parser_omp_clause_reduction (parser, clauses); - c_name = "reduction"; - break; - case PRAGMA_OMP_CLAUSE_SCHEDULE: - clauses = c_parser_omp_clause_schedule (parser, clauses); - c_name = "schedule"; - break; - case PRAGMA_OMP_CLAUSE_SHARED: - clauses = c_parser_omp_clause_shared (parser, clauses); - c_name = "shared"; - break; - case PRAGMA_OMP_CLAUSE_UNTIED: - clauses = c_parser_omp_clause_untied (parser, clauses); - c_name = "untied"; - break; - default: - c_parser_error (parser, "expected %<#pragma omp%> clause"); - goto saw_error; + c_parser_error (parser, "expected integer expression"); + return list; } - if (((mask >> c_kind) & 1) == 0 && !parser->error) + /* 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) { - /* Remove the invalid clause(s) from the list to avoid - confusing the rest of the compiler. */ - clauses = prev; - error_at (here, "%qs is not valid for %qs", c_name, where); + warning_at (expr_loc, 0, "% value must be positive"); + t = integer_one_node; } - } - saw_error: - c_parser_skip_to_pragma_eol (parser); + check_no_duplicate_clause (list, OMP_CLAUSE_NUM_TEAMS, "num_teams"); - return c_finish_omp_clauses (clauses); -} + c = build_omp_clause (num_teams_loc, OMP_CLAUSE_NUM_TEAMS); + OMP_CLAUSE_NUM_TEAMS_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } -/* OpenMP 2.5: - structured-block: - statement + return list; +} - In practice, we're also interested in adding the statement to an - outer node. So it is convenient if we work around the fact that - c_parser_statement calls add_stmt. */ +/* OpenMP 4.0: + aligned ( variable-list ) + aligned ( variable-list : constant-expression ) */ static tree -c_parser_omp_structured_block (c_parser *parser) +c_parser_omp_clause_aligned (c_parser *parser, tree list, bool declare_simd) { - tree stmt = push_stmt_list (); - c_parser_statement (parser); - return pop_stmt_list (stmt); -} - -/* OpenMP 2.5: - # pragma omp atomic new-line - expression-stmt - - expression-stmt: - x binop= expr | x++ | ++x | x-- | --x - binop: - +, *, -, /, &, ^, |, <<, >> + location_t clause_loc = c_parser_peek_token (parser)->location; + tree nl, c; - where x is an lvalue expression with scalar type. + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; - OpenMP 3.1: - # pragma omp atomic new-line - update-stmt + nl = c_parser_omp_variable_list (parser, clause_loc, + OMP_CLAUSE_ALIGNED, list, declare_simd); - # pragma omp atomic read new-line - read-stmt + if (c_parser_next_token_is (parser, CPP_COLON)) + { + c_parser_consume_token (parser); + tree alignment = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (alignment); + alignment = c_fully_fold (alignment, false, NULL); + if (!INTEGRAL_TYPE_P (TREE_TYPE (alignment)) + && TREE_CODE (alignment) != INTEGER_CST + && tree_int_cst_sgn (alignment) != 1) + { + error_at (clause_loc, "% clause alignment expression must " + "be positive constant integer expression"); + alignment = NULL_TREE; + } - # pragma omp atomic write new-line - write-stmt + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_ALIGNED_ALIGNMENT (c) = alignment; + } - # pragma omp atomic update new-line - update-stmt + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return nl; +} - # pragma omp atomic capture new-line - capture-stmt +/* OpenMP 4.0: + linear ( variable-list ) + linear ( variable-list : expression ) */ - # pragma omp atomic capture new-line - capture-block +static tree +c_parser_omp_clause_linear (c_parser *parser, tree list, bool declare_simd) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + tree nl, c, step; - read-stmt: - v = x - write-stmt: - x = expr - update-stmt: - expression-stmt | x = x binop expr - capture-stmt: - v = x binop= expr | v = x++ | v = ++x | v = x-- | v = --x - capture-block: - { v = x; update-stmt; } | { update-stmt; v = x; } + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; - where x and v are lvalue expressions with scalar type. + nl = c_parser_omp_variable_list (parser, clause_loc, + OMP_CLAUSE_LINEAR, list, declare_simd); - LOC is the location of the #pragma token. */ + if (c_parser_next_token_is (parser, CPP_COLON)) + { + c_parser_consume_token (parser); + step = c_parser_expression (parser).value; + mark_exp_read (step); + step = c_fully_fold (step, false, NULL); + if (!INTEGRAL_TYPE_P (TREE_TYPE (step))) + { + error_at (clause_loc, "% clause step expression must " + "be integral"); + step = integer_one_node; + } -static void -c_parser_omp_atomic (location_t loc, c_parser *parser) -{ - tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE; - tree lhs1 = NULL_TREE, rhs1 = NULL_TREE; - tree stmt, orig_lhs; - enum tree_code code = OMP_ATOMIC, opcode = NOP_EXPR; - struct c_expr rhs_expr; - bool structured_block = false; + } + else + step = integer_one_node; - if (c_parser_next_token_is (parser, CPP_NAME)) + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) { - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + OMP_CLAUSE_LINEAR_STEP (c) = step; + } + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return nl; +} + +/* OpenMP 4.0: + safelen ( constant-expression ) */ + +static tree +c_parser_omp_clause_safelen (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + tree c, t; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + + t = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (t); + t = c_fully_fold (t, false, NULL); + if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) + && TREE_CODE (t) != INTEGER_CST + && tree_int_cst_sgn (t) != 1) + { + error_at (clause_loc, "% clause expression must " + "be positive constant integer expression"); + t = NULL_TREE; + } + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + if (t == NULL_TREE || t == error_mark_node) + return list; + + check_no_duplicate_clause (list, OMP_CLAUSE_SAFELEN, "safelen"); + + c = build_omp_clause (clause_loc, OMP_CLAUSE_SAFELEN); + OMP_CLAUSE_SAFELEN_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 4.0: + simdlen ( constant-expression ) */ + +static tree +c_parser_omp_clause_simdlen (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + tree c, t; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + + t = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (t); + t = c_fully_fold (t, false, NULL); + if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) + && TREE_CODE (t) != INTEGER_CST + && tree_int_cst_sgn (t) != 1) + { + error_at (clause_loc, "% clause expression must " + "be positive constant integer expression"); + t = NULL_TREE; + } + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + if (t == NULL_TREE || t == error_mark_node) + return list; + + check_no_duplicate_clause (list, OMP_CLAUSE_SIMDLEN, "simdlen"); + + c = build_omp_clause (clause_loc, OMP_CLAUSE_SIMDLEN); + OMP_CLAUSE_SIMDLEN_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 4.0: + depend ( depend-kind: variable-list ) + + depend-kind: + in | out | inout */ + +static tree +c_parser_omp_clause_depend (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_INOUT; + tree nl, c; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp ("in", p) == 0) + kind = OMP_CLAUSE_DEPEND_IN; + else if (strcmp ("inout", p) == 0) + kind = OMP_CLAUSE_DEPEND_INOUT; + else if (strcmp ("out", p) == 0) + kind = OMP_CLAUSE_DEPEND_OUT; + else + goto invalid_kind; + } + else + goto invalid_kind; + + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + goto resync_fail; + + nl = c_parser_omp_variable_list (parser, clause_loc, + OMP_CLAUSE_DEPEND, list, false); + + 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; + + invalid_kind: + c_parser_error (parser, "invalid depend kind"); + resync_fail: + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return list; +} + +/* OpenMP 4.0: + map ( map-kind: variable-list ) + map ( variable-list ) + + map-kind: + alloc | to | from | tofrom */ + +static tree +c_parser_omp_clause_map (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + enum omp_clause_map_kind kind = OMP_CLAUSE_MAP_TOFROM; + tree nl, c; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_COLON) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp ("alloc", p) == 0) + kind = OMP_CLAUSE_MAP_ALLOC; + else if (strcmp ("to", p) == 0) + kind = OMP_CLAUSE_MAP_TO; + else if (strcmp ("from", p) == 0) + kind = OMP_CLAUSE_MAP_FROM; + else if (strcmp ("tofrom", p) == 0) + kind = OMP_CLAUSE_MAP_TOFROM; + else + { + c_parser_error (parser, "invalid map kind"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return list; + } + c_parser_consume_token (parser); + c_parser_consume_token (parser); + } + + nl = c_parser_omp_variable_list (parser, clause_loc, + OMP_CLAUSE_MAP, list, false); + + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_MAP_KIND (c) = kind; + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return nl; +} + +/* OpenMP 4.0: + device ( expression ) */ + +static tree +c_parser_omp_clause_device (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + tree c, t = c_parser_expr_no_commas (parser, NULL).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_DEVICE, "device"); + + c = build_omp_clause (clause_loc, OMP_CLAUSE_DEVICE); + OMP_CLAUSE_DEVICE_ID (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + +/* OpenMP 4.0: + dist_schedule ( static ) + dist_schedule ( static , expression ) */ + +static tree +c_parser_omp_clause_dist_schedule (c_parser *parser, tree list) +{ + tree c, t = NULL_TREE; + location_t loc = c_parser_peek_token (parser)->location; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + + if (!c_parser_next_token_is_keyword (parser, RID_STATIC)) + { + c_parser_error (parser, "invalid dist_schedule kind"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return list; + } + + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_COMMA)) + { + c_parser_consume_token (parser); + + t = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (t); + t = c_fully_fold (t, false, NULL); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + } + else + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<,%> or %<)%>"); + + check_no_duplicate_clause (list, OMP_CLAUSE_SCHEDULE, "schedule"); + if (t == error_mark_node) + return list; + + c = build_omp_clause (loc, OMP_CLAUSE_DIST_SCHEDULE); + OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 4.0: + proc_bind ( proc-bind-kind ) + + proc-bind-kind: + master | close | spread */ + +static tree +c_parser_omp_clause_proc_bind (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + enum omp_clause_proc_bind_kind kind; + tree c; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp ("master", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_MASTER; + else if (strcmp ("close", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_CLOSE; + else if (strcmp ("spread", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_SPREAD; + else + goto invalid_kind; + } + else + goto invalid_kind; + + c_parser_consume_token (parser); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + c = build_omp_clause (clause_loc, OMP_CLAUSE_PROC_BIND); + OMP_CLAUSE_PROC_BIND_KIND (c) = kind; + OMP_CLAUSE_CHAIN (c) = list; + return c; + + invalid_kind: + c_parser_error (parser, "invalid proc_bind kind"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return list; +} + +/* OpenMP 4.0: + to ( variable-list ) */ + +static tree +c_parser_omp_clause_to (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO, list); +} + +/* OpenMP 4.0: + from ( variable-list ) */ + +static tree +c_parser_omp_clause_from (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FROM, list); +} + +/* OpenMP 4.0: + uniform ( variable-list ) */ + +static tree +c_parser_omp_clause_uniform (c_parser *parser, tree list) +{ + /* The clauses location. */ + location_t loc = c_parser_peek_token (parser)->location; + + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + list = c_parser_omp_variable_list (parser, loc, OMP_CLAUSE_UNIFORM, + list, true); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + } + return list; +} + +/* Parse all OpenMP clauses. The set clauses allowed by the directive + is a bitmask in MASK. Return the list of clauses found; the result + of clause default goes in *pdefault. */ + +static tree +c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, + const char *where, bool declare_simd) +{ + tree clauses = NULL; + bool first = true; + + while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + { + location_t here; + pragma_omp_clause c_kind; + const char *c_name; + tree prev = clauses; + + if (!first && c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + + first = false; + here = c_parser_peek_token (parser)->location; + c_kind = c_parser_omp_clause_name (parser); + + switch (c_kind) + { + case PRAGMA_OMP_CLAUSE_COLLAPSE: + clauses = c_parser_omp_clause_collapse (parser, clauses); + c_name = "collapse"; + break; + case PRAGMA_OMP_CLAUSE_COPYIN: + clauses = c_parser_omp_clause_copyin (parser, clauses); + c_name = "copyin"; + break; + case PRAGMA_OMP_CLAUSE_COPYPRIVATE: + clauses = c_parser_omp_clause_copyprivate (parser, clauses); + c_name = "copyprivate"; + break; + case PRAGMA_OMP_CLAUSE_DEFAULT: + clauses = c_parser_omp_clause_default (parser, clauses); + c_name = "default"; + break; + case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE: + clauses = c_parser_omp_clause_firstprivate (parser, clauses); + c_name = "firstprivate"; + break; + case PRAGMA_OMP_CLAUSE_FINAL: + clauses = c_parser_omp_clause_final (parser, clauses); + c_name = "final"; + break; + case PRAGMA_OMP_CLAUSE_IF: + clauses = c_parser_omp_clause_if (parser, clauses); + c_name = "if"; + break; + case PRAGMA_OMP_CLAUSE_LASTPRIVATE: + clauses = c_parser_omp_clause_lastprivate (parser, clauses); + c_name = "lastprivate"; + break; + case PRAGMA_OMP_CLAUSE_MERGEABLE: + clauses = c_parser_omp_clause_mergeable (parser, clauses); + c_name = "mergeable"; + break; + case PRAGMA_OMP_CLAUSE_NOWAIT: + clauses = c_parser_omp_clause_nowait (parser, clauses); + c_name = "nowait"; + break; + case PRAGMA_OMP_CLAUSE_NUM_THREADS: + clauses = c_parser_omp_clause_num_threads (parser, clauses); + c_name = "num_threads"; + break; + case PRAGMA_OMP_CLAUSE_ORDERED: + clauses = c_parser_omp_clause_ordered (parser, clauses); + c_name = "ordered"; + break; + case PRAGMA_OMP_CLAUSE_PRIVATE: + clauses = c_parser_omp_clause_private (parser, clauses); + c_name = "private"; + break; + case PRAGMA_OMP_CLAUSE_REDUCTION: + clauses = c_parser_omp_clause_reduction (parser, clauses, + declare_simd); + c_name = "reduction"; + break; + case PRAGMA_OMP_CLAUSE_SCHEDULE: + clauses = c_parser_omp_clause_schedule (parser, clauses); + c_name = "schedule"; + break; + case PRAGMA_OMP_CLAUSE_SHARED: + clauses = c_parser_omp_clause_shared (parser, clauses); + c_name = "shared"; + break; + case PRAGMA_OMP_CLAUSE_UNTIED: + clauses = c_parser_omp_clause_untied (parser, clauses); + c_name = "untied"; + break; + case PRAGMA_OMP_CLAUSE_INBRANCH: + clauses = c_parser_omp_clause_branch (parser, OMP_CLAUSE_INBRANCH, + clauses); + c_name = "inbranch"; + break; + case PRAGMA_OMP_CLAUSE_NOTINBRANCH: + clauses = c_parser_omp_clause_branch (parser, OMP_CLAUSE_NOTINBRANCH, + clauses); + c_name = "notinbranch"; + break; + case PRAGMA_OMP_CLAUSE_PARALLEL: + clauses + = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_PARALLEL, + clauses); + c_name = "parallel"; + break; + case PRAGMA_OMP_CLAUSE_FOR: + clauses + = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_FOR, + clauses); + c_name = "for"; + break; + case PRAGMA_OMP_CLAUSE_SECTIONS: + clauses + = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_SECTIONS, + clauses); + c_name = "sections"; + break; + case PRAGMA_OMP_CLAUSE_TASKGROUP: + clauses + = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_TASKGROUP, + clauses); + c_name = "taskgroup"; + break; + case PRAGMA_OMP_CLAUSE_TO: + clauses = c_parser_omp_clause_to (parser, clauses); + c_name = "to"; + break; + case PRAGMA_OMP_CLAUSE_FROM: + clauses = c_parser_omp_clause_from (parser, clauses); + c_name = "from"; + break; + case PRAGMA_OMP_CLAUSE_UNIFORM: + clauses = c_parser_omp_clause_uniform (parser, clauses); + c_name = "uniform"; + break; + case PRAGMA_OMP_CLAUSE_NUM_TEAMS: + clauses = c_parser_omp_clause_num_teams (parser, clauses); + c_name = "num_teams"; + break; + case PRAGMA_OMP_CLAUSE_ALIGNED: + clauses = c_parser_omp_clause_aligned (parser, clauses, + declare_simd); + c_name = "aligned"; + break; + case PRAGMA_OMP_CLAUSE_LINEAR: + clauses = c_parser_omp_clause_linear (parser, clauses, declare_simd); + c_name = "linear"; + break; + case PRAGMA_OMP_CLAUSE_DEPEND: + clauses = c_parser_omp_clause_depend (parser, clauses); + c_name = "depend"; + break; + case PRAGMA_OMP_CLAUSE_MAP: + clauses = c_parser_omp_clause_map (parser, clauses); + c_name = "map"; + break; + case PRAGMA_OMP_CLAUSE_DEVICE: + clauses = c_parser_omp_clause_device (parser, clauses); + c_name = "device"; + break; + case PRAGMA_OMP_CLAUSE_DIST_SCHEDULE: + clauses = c_parser_omp_clause_dist_schedule (parser, clauses); + c_name = "dist_schedule"; + break; + case PRAGMA_OMP_CLAUSE_PROC_BIND: + clauses = c_parser_omp_clause_proc_bind (parser, clauses); + c_name = "proc_bind"; + break; + case PRAGMA_OMP_CLAUSE_SAFELEN: + clauses = c_parser_omp_clause_safelen (parser, clauses); + c_name = "safelen"; + break; + case PRAGMA_OMP_CLAUSE_SIMDLEN: + clauses = c_parser_omp_clause_simdlen (parser, clauses); + c_name = "simdlen"; + break; + default: + c_parser_error (parser, "expected %<#pragma omp%> clause"); + goto saw_error; + } + + if (((mask >> c_kind) & 1) == 0 && !parser->error) + { + /* Remove the invalid clause(s) from the list to avoid + confusing the rest of the compiler. */ + clauses = prev; + error_at (here, "%qs is not valid for %qs", c_name, where); + } + } + + saw_error: + c_parser_skip_to_pragma_eol (parser); + + if (declare_simd) + return clauses; + + return c_finish_omp_clauses (clauses); +} + +/* OpenMP 2.5: + structured-block: + statement + + In practice, we're also interested in adding the statement to an + outer node. So it is convenient if we work around the fact that + c_parser_statement calls add_stmt. */ + +static tree +c_parser_omp_structured_block (c_parser *parser) +{ + tree stmt = push_stmt_list (); + c_parser_statement (parser); + return pop_stmt_list (stmt); +} + +/* OpenMP 2.5: + # pragma omp atomic new-line + expression-stmt + + expression-stmt: + x binop= expr | x++ | ++x | x-- | --x + binop: + +, *, -, /, &, ^, |, <<, >> + + where x is an lvalue expression with scalar type. + + OpenMP 3.1: + # pragma omp atomic new-line + update-stmt + + # pragma omp atomic read new-line + read-stmt + + # pragma omp atomic write new-line + write-stmt + + # pragma omp atomic update new-line + update-stmt + + # pragma omp atomic capture new-line + capture-stmt + + # pragma omp atomic capture new-line + capture-block + + read-stmt: + v = x + write-stmt: + x = expr + update-stmt: + expression-stmt | x = x binop expr + capture-stmt: + v = expression-stmt + capture-block: + { v = x; update-stmt; } | { update-stmt; v = x; } + + OpenMP 4.0: + update-stmt: + expression-stmt | x = x binop expr | x = expr binop x + capture-stmt: + v = update-stmt + capture-block: + { v = x; update-stmt; } | { update-stmt; v = x; } | { v = x; x = expr; } + + where x and v are lvalue expressions with scalar type. + + LOC is the location of the #pragma token. */ + +static void +c_parser_omp_atomic (location_t loc, c_parser *parser) +{ + tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE; + tree lhs1 = NULL_TREE, rhs1 = NULL_TREE; + tree stmt, orig_lhs, unfolded_lhs = NULL_TREE, unfolded_lhs1 = NULL_TREE; + enum tree_code code = OMP_ATOMIC, opcode = NOP_EXPR; + struct c_expr expr; + location_t eloc; + bool structured_block = false; + bool swapped = false; + bool seq_cst = false; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (!strcmp (p, "seq_cst")) + { + seq_cst = true; + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_COMMA) + && c_parser_peek_2nd_token (parser)->type == CPP_NAME) + c_parser_consume_token (parser); + } + } + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); if (!strcmp (p, "read")) code = OMP_ATOMIC_READ; @@ -9655,6 +10428,23 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) if (p) c_parser_consume_token (parser); } + if (!seq_cst) + { + if (c_parser_next_token_is (parser, CPP_COMMA) + && c_parser_peek_2nd_token (parser)->type == CPP_NAME) + c_parser_consume_token (parser); + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p + = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (!strcmp (p, "seq_cst")) + { + seq_cst = true; + c_parser_consume_token (parser); + } + } + } c_parser_skip_to_pragma_eol (parser); switch (code) @@ -9708,7 +10498,11 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) /* For structured_block case we don't know yet whether old or new x should be captured. */ restart: - lhs = c_parser_unary_expression (parser).value; + eloc = c_parser_peek_token (parser)->location; + expr = c_parser_unary_expression (parser); + lhs = expr.value; + expr = default_function_array_conversion (eloc, expr); + unfolded_lhs = expr.value; lhs = c_fully_fold (lhs, false, NULL); orig_lhs = lhs; switch (TREE_CODE (lhs)) @@ -9735,6 +10529,7 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) /* FALLTHROUGH */ case PREINCREMENT_EXPR: lhs = TREE_OPERAND (lhs, 0); + unfolded_lhs = NULL_TREE; opcode = PLUS_EXPR; rhs = integer_one_node; break; @@ -9745,6 +10540,7 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) /* FALLTHROUGH */ case PREDECREMENT_EXPR: lhs = TREE_OPERAND (lhs, 0); + unfolded_lhs = NULL_TREE; opcode = MINUS_EXPR; rhs = integer_one_node; break; @@ -9770,6 +10566,7 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) /* This is pre or post increment. */ rhs = TREE_OPERAND (lhs, 1); lhs = TREE_OPERAND (lhs, 0); + unfolded_lhs = NULL_TREE; opcode = NOP_EXPR; if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block @@ -9784,6 +10581,7 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) /* This is pre or post decrement. */ rhs = TREE_OPERAND (lhs, 1); lhs = TREE_OPERAND (lhs, 0); + unfolded_lhs = NULL_TREE; opcode = NOP_EXPR; if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block @@ -9824,87 +10622,67 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) opcode = BIT_XOR_EXPR; break; case CPP_EQ: - if (structured_block || code == OMP_ATOMIC) + c_parser_consume_token (parser); + eloc = c_parser_peek_token (parser)->location; + expr = c_parser_expr_no_commas (parser, NULL, unfolded_lhs); + rhs1 = expr.value; + switch (TREE_CODE (rhs1)) { - location_t aloc = c_parser_peek_token (parser)->location; - location_t rhs_loc; - enum c_parser_prec oprec = PREC_NONE; - - c_parser_consume_token (parser); - rhs1 = c_parser_unary_expression (parser).value; - rhs1 = c_fully_fold (rhs1, false, NULL); - if (rhs1 == error_mark_node) - goto saw_error; - switch (c_parser_peek_token (parser)->type) + case MULT_EXPR: + case TRUNC_DIV_EXPR: + case PLUS_EXPR: + case MINUS_EXPR: + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case BIT_AND_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + if (c_tree_equal (TREE_OPERAND (rhs1, 0), unfolded_lhs)) { - case CPP_SEMICOLON: - if (code == OMP_ATOMIC_CAPTURE_NEW) - { - code = OMP_ATOMIC_CAPTURE_OLD; - v = lhs; - lhs = NULL_TREE; - lhs1 = rhs1; - rhs1 = NULL_TREE; - c_parser_consume_token (parser); - goto restart; - } - c_parser_error (parser, - "invalid form of %<#pragma omp atomic%>"); - goto saw_error; - case CPP_MULT: - opcode = MULT_EXPR; - oprec = PREC_MULT; - break; - case CPP_DIV: - opcode = TRUNC_DIV_EXPR; - oprec = PREC_MULT; - break; - case CPP_PLUS: - opcode = PLUS_EXPR; - oprec = PREC_ADD; - break; - case CPP_MINUS: - opcode = MINUS_EXPR; - oprec = PREC_ADD; - break; - case CPP_LSHIFT: - opcode = LSHIFT_EXPR; - oprec = PREC_SHIFT; - break; - case CPP_RSHIFT: - opcode = RSHIFT_EXPR; - oprec = PREC_SHIFT; - break; - case CPP_AND: - opcode = BIT_AND_EXPR; - oprec = PREC_BITAND; - break; - case CPP_OR: - opcode = BIT_IOR_EXPR; - oprec = PREC_BITOR; - break; - case CPP_XOR: - opcode = BIT_XOR_EXPR; - oprec = PREC_BITXOR; - break; - default: - c_parser_error (parser, - "invalid operator for %<#pragma omp atomic%>"); - goto saw_error; + opcode = TREE_CODE (rhs1); + rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL); + rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 0), false, NULL); + goto stmt_done; + } + if (c_tree_equal (TREE_OPERAND (rhs1, 1), unfolded_lhs)) + { + opcode = TREE_CODE (rhs1); + rhs = c_fully_fold (TREE_OPERAND (rhs1, 0), false, NULL); + rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL); + swapped = !commutative_tree_code (opcode); + goto stmt_done; + } + break; + case ERROR_MARK: + goto saw_error; + default: + break; + } + if (c_parser_peek_token (parser)->type == CPP_SEMICOLON) + { + if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW) + { + code = OMP_ATOMIC_CAPTURE_OLD; + v = lhs; + lhs = NULL_TREE; + expr = default_function_array_read_conversion (eloc, expr); + unfolded_lhs1 = expr.value; + lhs1 = c_fully_fold (unfolded_lhs1, false, NULL); + rhs1 = NULL_TREE; + c_parser_consume_token (parser); + goto restart; + } + if (structured_block) + { + opcode = NOP_EXPR; + expr = default_function_array_read_conversion (eloc, expr); + rhs = c_fully_fold (expr.value, false, NULL); + rhs1 = NULL_TREE; + goto stmt_done; } - loc = aloc; - c_parser_consume_token (parser); - rhs_loc = c_parser_peek_token (parser)->location; - if (commutative_tree_code (opcode)) - oprec = (enum c_parser_prec) (oprec - 1); - rhs_expr = c_parser_binary_expression (parser, NULL, oprec); - rhs_expr = default_function_array_read_conversion (rhs_loc, - rhs_expr); - rhs = rhs_expr.value; - rhs = c_fully_fold (rhs, false, NULL); - goto stmt_done; } - /* FALLTHROUGH */ + c_parser_error (parser, "invalid form of %<#pragma omp atomic%>"); + goto saw_error; default: c_parser_error (parser, "invalid operator for %<#pragma omp atomic%>"); @@ -9915,12 +10693,10 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) c_finish_omp_atomic. */ loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); - { - location_t rhs_loc = c_parser_peek_token (parser)->location; - rhs_expr = c_parser_expression (parser); - rhs_expr = default_function_array_read_conversion (rhs_loc, rhs_expr); - } - rhs = rhs_expr.value; + eloc = c_parser_peek_token (parser)->location; + expr = c_parser_expression (parser); + expr = default_function_array_read_conversion (eloc, expr); + rhs = expr.value; rhs = c_fully_fold (rhs, false, NULL); break; } @@ -9935,7 +10711,11 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) goto saw_error; if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) goto saw_error; - lhs1 = c_parser_unary_expression (parser).value; + eloc = c_parser_peek_token (parser)->location; + expr = c_parser_unary_expression (parser); + lhs1 = expr.value; + expr = default_function_array_read_conversion (eloc, expr); + unfolded_lhs1 = expr.value; lhs1 = c_fully_fold (lhs1, false, NULL); if (lhs1 == error_mark_node) goto saw_error; @@ -9946,7 +10726,16 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>"); } done: - stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1); + if (unfolded_lhs && unfolded_lhs1 + && !c_tree_equal (unfolded_lhs, unfolded_lhs1)) + { + error ("%<#pragma omp atomic capture%> uses two different " + "expressions for memory"); + stmt = error_mark_node; + } + else + stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1, + swapped, seq_cst); if (stmt != error_mark_node) add_stmt (stmt); @@ -10026,8 +10815,8 @@ c_parser_omp_flush (c_parser *parser) LOC is the location of the OMP in "#pragma omp". */ static tree -c_parser_omp_for_loop (location_t loc, - c_parser *parser, tree clauses, tree *par_clauses) +c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, + tree clauses, tree *par_clauses) { tree decl, cond, incr, save_break, save_cont, body, init, stmt, cl; tree declv, condv, incrv, initv, ret = NULL; @@ -10067,7 +10856,8 @@ c_parser_omp_for_loop (location_t loc, { if (i > 0) vec_safe_push (for_block, c_begin_compound_stmt (true)); - c_parser_declaration_or_fndef (parser, true, true, true, true, true, NULL); + c_parser_declaration_or_fndef (parser, true, true, true, true, true, + NULL, vNULL); decl = check_for_loop_decls (for_loc, flag_isoc99); if (decl == NULL) goto error_init; @@ -10114,8 +10904,8 @@ c_parser_omp_for_loop (location_t loc, if (c_parser_next_token_is_not (parser, CPP_SEMICOLON)) { location_t cond_loc = c_parser_peek_token (parser)->location; - struct c_expr cond_expr = c_parser_binary_expression (parser, NULL, - PREC_NONE); + struct c_expr cond_expr + = c_parser_binary_expression (parser, NULL, NULL_TREE); cond = cond_expr.value; cond = c_objc_common_truthvalue_conversion (cond_loc, cond); @@ -10254,7 +11044,8 @@ c_parser_omp_for_loop (location_t loc, an error from the initialization parsing. */ if (!fail) { - stmt = c_finish_omp_for (loc, declv, initv, condv, incrv, body, NULL); + stmt = c_finish_omp_for (loc, code, declv, initv, condv, + incrv, body, NULL); if (stmt) { if (par_clauses != NULL) @@ -10309,33 +11100,84 @@ c_parser_omp_for_loop (location_t loc, return ret; } +/* OpenMP 4.0: + #pragma omp simd simd-clause[optseq] new-line + for-loop + + LOC is the location of the #pragma token. +*/ + +#define OMP_SIMD_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SAFELEN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE)) + +static tree +c_parser_omp_simd (location_t loc, c_parser *parser) +{ + tree block, clauses, ret; + + clauses = c_parser_omp_all_clauses (parser, OMP_SIMD_CLAUSE_MASK, + "#pragma omp simd", false); + + block = c_begin_compound_stmt (true); + ret = c_parser_omp_for_loop (loc, parser, OMP_SIMD, clauses, NULL); + block = c_end_compound_stmt (loc, block, true); + add_stmt (block); + + return ret; +} + /* OpenMP 2.5: #pragma omp for for-clause[optseq] new-line for-loop + OpenMP 4.0: + #pragma omp for simd for-simd-clause[optseq] new-line + for-loop + LOC is the location of the #pragma token. */ -#define OMP_FOR_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ - | (1u << PRAGMA_OMP_CLAUSE_ORDERED) \ - | (1u << PRAGMA_OMP_CLAUSE_SCHEDULE) \ - | (1u << PRAGMA_OMP_CLAUSE_COLLAPSE) \ - | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) +#define OMP_FOR_CLAUSE_MASK \ + ( (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_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) static tree c_parser_omp_for (location_t loc, c_parser *parser) { tree block, clauses, ret; + enum tree_code code = OMP_FOR; + omp_clause_mask mask = OMP_FOR_CLAUSE_MASK; + const char *p_name = "#pragma omp for"; + + 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) + { + c_parser_consume_token (parser); + /* code = OMP_FOR_SIMD; */ + mask |= OMP_SIMD_CLAUSE_MASK; + p_name = "#pragma omp for simd"; + } + } - clauses = c_parser_omp_all_clauses (parser, OMP_FOR_CLAUSE_MASK, - "#pragma omp for"); + clauses = c_parser_omp_all_clauses (parser, mask, p_name, false); block = c_begin_compound_stmt (true); - ret = c_parser_omp_for_loop (loc, parser, clauses, NULL); + ret = c_parser_omp_for_loop (loc, parser, code, clauses, NULL); block = c_end_compound_stmt (loc, block, true); add_stmt (block); @@ -10465,12 +11307,12 @@ c_parser_omp_sections_scope (location_t sections_loc, c_parser *parser) LOC is the location of the #pragma token. */ -#define OMP_SECTIONS_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ - | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) +#define OMP_SECTIONS_CLAUSE_MASK \ + ( (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_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) static tree c_parser_omp_sections (location_t loc, c_parser *parser) @@ -10478,7 +11320,7 @@ c_parser_omp_sections (location_t loc, c_parser *parser) tree block, clauses, ret; clauses = c_parser_omp_all_clauses (parser, OMP_SECTIONS_CLAUSE_MASK, - "#pragma omp sections"); + "#pragma omp sections", false); block = c_begin_compound_stmt (true); ret = c_parser_omp_sections_scope (loc, parser); @@ -10498,15 +11340,16 @@ c_parser_omp_sections (location_t loc, c_parser *parser) LOC is the location of the #pragma token. */ -#define OMP_PARALLEL_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_IF) \ - | (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \ - | (1u << PRAGMA_OMP_CLAUSE_SHARED) \ - | (1u << PRAGMA_OMP_CLAUSE_COPYIN) \ - | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ - | (1u << PRAGMA_OMP_CLAUSE_NUM_THREADS)) +#define OMP_PARALLEL_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PROC_BIND)) static tree c_parser_omp_parallel (location_t loc, c_parser *parser) @@ -10514,7 +11357,8 @@ c_parser_omp_parallel (location_t loc, c_parser *parser) enum pragma_kind p_kind = PRAGMA_OMP_PARALLEL; const char *p_name = "#pragma omp parallel"; tree stmt, clauses, par_clause, ws_clause, block; - unsigned int mask = OMP_PARALLEL_CLAUSE_MASK; + omp_clause_mask mask = OMP_PARALLEL_CLAUSE_MASK; + tree cclauses[C_OMP_CLAUSE_SPLIT_COUNT]; if (c_parser_next_token_is_keyword (parser, RID_FOR)) { @@ -10522,7 +11366,19 @@ c_parser_omp_parallel (location_t loc, c_parser *parser) p_kind = PRAGMA_OMP_PARALLEL_FOR; p_name = "#pragma omp parallel for"; mask |= OMP_FOR_CLAUSE_MASK; - mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT); + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); + 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) + { + c_parser_consume_token (parser); + p_kind = PRAGMA_OMP_PARALLEL_FOR_SIMD; + p_name = "#pragma omp parallel for simd"; + mask |= OMP_SIMD_CLAUSE_MASK; + } + } } else if (c_parser_next_token_is (parser, CPP_NAME)) { @@ -10533,11 +11389,11 @@ c_parser_omp_parallel (location_t loc, c_parser *parser) p_kind = PRAGMA_OMP_PARALLEL_SECTIONS; p_name = "#pragma omp parallel sections"; mask |= OMP_SECTIONS_CLAUSE_MASK; - mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT); + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); } } - clauses = c_parser_omp_all_clauses (parser, mask, p_name); + clauses = c_parser_omp_all_clauses (parser, mask, p_name, false); switch (p_kind) { @@ -10549,15 +11405,30 @@ c_parser_omp_parallel (location_t loc, c_parser *parser) case PRAGMA_OMP_PARALLEL_FOR: block = c_begin_omp_parallel (); - c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause); - c_parser_omp_for_loop (loc, parser, ws_clause, &par_clause); + c_omp_split_clauses (loc, OMP_FOR, mask, clauses, cclauses); + par_clause = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; + ws_clause = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; + c_parser_omp_for_loop (loc, parser, OMP_FOR, ws_clause, &par_clause); + stmt = c_finish_omp_parallel (loc, par_clause, block); + OMP_PARALLEL_COMBINED (stmt) = 1; + break; + + case PRAGMA_OMP_PARALLEL_FOR_SIMD: + block = c_begin_omp_parallel (); + c_omp_split_clauses (loc, OMP_FOR, mask, clauses, cclauses); + par_clause = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; + ws_clause = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; + c_parser_omp_for_loop (loc, parser, OMP_FOR /*_SIMD*/, ws_clause, + &par_clause); stmt = c_finish_omp_parallel (loc, par_clause, block); OMP_PARALLEL_COMBINED (stmt) = 1; break; case PRAGMA_OMP_PARALLEL_SECTIONS: block = c_begin_omp_parallel (); - c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause); + c_omp_split_clauses (loc, OMP_SECTIONS, mask, clauses, cclauses); + par_clause = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; + ws_clause = cclauses[C_OMP_CLAUSE_SPLIT_SECTIONS]; stmt = c_parser_omp_sections_scope (loc, parser); if (stmt) OMP_SECTIONS_CLAUSES (stmt) = ws_clause; @@ -10579,11 +11450,11 @@ c_parser_omp_parallel (location_t loc, c_parser *parser) LOC is the location of the #pragma. */ -#define OMP_SINGLE_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) +#define OMP_SINGLE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) static tree c_parser_omp_single (location_t loc, c_parser *parser) @@ -10594,7 +11465,7 @@ c_parser_omp_single (location_t loc, c_parser *parser) OMP_SINGLE_CLAUSES (stmt) = c_parser_omp_all_clauses (parser, OMP_SINGLE_CLAUSE_MASK, - "#pragma omp single"); + "#pragma omp single", false); OMP_SINGLE_BODY (stmt) = c_parser_omp_structured_block (parser); return add_stmt (stmt); @@ -10606,15 +11477,16 @@ c_parser_omp_single (location_t loc, c_parser *parser) LOC is the location of the #pragma. */ -#define OMP_TASK_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_IF) \ - | (1u << PRAGMA_OMP_CLAUSE_UNTIED) \ - | (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \ - | (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_SHARED) \ - | (1u << PRAGMA_OMP_CLAUSE_FINAL) \ - | (1u << PRAGMA_OMP_CLAUSE_MERGEABLE)) +#define OMP_TASK_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNTIED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (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)) static tree c_parser_omp_task (location_t loc, c_parser *parser) @@ -10622,39 +11494,253 @@ c_parser_omp_task (location_t loc, c_parser *parser) tree clauses, block; clauses = c_parser_omp_all_clauses (parser, OMP_TASK_CLAUSE_MASK, - "#pragma omp task"); + "#pragma omp task", false); block = c_begin_omp_task (); c_parser_statement (parser); return c_finish_omp_task (loc, clauses, block); } -/* OpenMP 3.0: - # pragma omp taskwait new-line -*/ +/* OpenMP 3.0: + # pragma omp taskwait new-line +*/ + +static void +c_parser_omp_taskwait (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_pragma (parser); + c_parser_skip_to_pragma_eol (parser); + + c_finish_omp_taskwait (loc); +} + +/* OpenMP 3.1: + # pragma omp taskyield new-line +*/ + +static void +c_parser_omp_taskyield (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_pragma (parser); + c_parser_skip_to_pragma_eol (parser); + + c_finish_omp_taskyield (loc); +} + +/* OpenMP 4.0: + # pragma omp taskgroup new-line +*/ + +static void +c_parser_omp_taskgroup (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_skip_to_pragma_eol (parser); + + tree block = c_begin_omp_taskgroup (); + c_parser_statement (parser); + c_finish_omp_taskgroup (loc, block); +} + +/* OpenMP 4.0: + # pragma omp cancel cancel-clause[optseq] new-line + + LOC is the location of the #pragma. +*/ + +#define OMP_CANCEL_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARALLEL) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FOR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)) + +static void +c_parser_omp_cancel (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + + c_parser_consume_pragma (parser); + tree clauses = c_parser_omp_all_clauses (parser, OMP_CANCEL_CLAUSE_MASK, + "#pragma omp cancel", false); + + c_finish_omp_cancel (loc, clauses); +} + +/* OpenMP 4.0: + # pragma omp cancellation point cancelpt-clause[optseq] new-line + + LOC is the location of the #pragma. +*/ + +#define OMP_CANCELLATION_POINT_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARALLEL) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FOR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP)) + +static void +c_parser_omp_cancellation_point (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + tree clauses; + bool point_seen = false; + + c_parser_consume_pragma (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "point") == 0) + { + c_parser_consume_token (parser); + point_seen = true; + } + } + if (!point_seen) + { + c_parser_error (parser, "expected %"); + c_parser_skip_to_pragma_eol (parser); + return; + } + + clauses + = c_parser_omp_all_clauses (parser, OMP_CANCELLATION_POINT_CLAUSE_MASK, + "#pragma omp cancellation point", false); + + c_finish_omp_cancellation_point (loc, clauses); +} + +/* OpenMP 4.0: + # pragma omp declare simd declare-simd-clauses[optseq] new-line */ + +#define OMP_DECLARE_SIMD_CLAUSE_MASK \ + ( (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_UNIFORM) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_INBRANCH) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOTINBRANCH)) static void -c_parser_omp_taskwait (c_parser *parser) +c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context) { - location_t loc = c_parser_peek_token (parser)->location; - c_parser_consume_pragma (parser); - c_parser_skip_to_pragma_eol (parser); + vec clauses = vNULL; + tree cl = c_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK, + "#pragma omp declare simd", true); + clauses.safe_push (cl); - c_finish_omp_taskwait (loc); + while (c_parser_next_token_is (parser, CPP_PRAGMA)) + { + if (c_parser_peek_token (parser)->pragma_kind + != PRAGMA_OMP_DECLARE_REDUCTION + || c_parser_peek_2nd_token (parser)->type != CPP_NAME + || strcmp (IDENTIFIER_POINTER + (c_parser_peek_2nd_token (parser)->value), + "simd") != 0) + { + c_parser_error (parser, + "%<#pragma omp declare simd%> must be followed by " + "function declaration or definition or another " + "%<#pragma omp declare simd%>"); + clauses.release (); + return; + } + c_parser_consume_pragma (parser); + c_parser_consume_token (parser); + cl = c_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK, + "#pragma omp declare simd", true); + clauses.safe_push (cl); + } + + switch (context) + { + case pragma_external: + if (c_parser_next_token_is (parser, CPP_KEYWORD) + && c_parser_peek_token (parser)->keyword == RID_EXTENSION) + { + int ext = disable_extension_diagnostics (); + do + c_parser_consume_token (parser); + while (c_parser_next_token_is (parser, CPP_KEYWORD) + && c_parser_peek_token (parser)->keyword == RID_EXTENSION); + c_parser_declaration_or_fndef (parser, true, true, true, false, true, + NULL, clauses); + restore_extension_diagnostics (ext); + } + else + c_parser_declaration_or_fndef (parser, true, true, true, false, true, + NULL, clauses); + break; + case pragma_struct: + case pragma_param: + c_parser_error (parser, "%<#pragma omp declare simd%> must be followed by " + "function declaration or definition"); + break; + case pragma_compound: + case pragma_stmt: + if (c_parser_next_token_is (parser, CPP_KEYWORD) + && c_parser_peek_token (parser)->keyword == RID_EXTENSION) + { + int ext = disable_extension_diagnostics (); + do + c_parser_consume_token (parser); + while (c_parser_next_token_is (parser, CPP_KEYWORD) + && c_parser_peek_token (parser)->keyword == RID_EXTENSION); + if (c_parser_next_tokens_start_declaration (parser)) + { + c_parser_declaration_or_fndef (parser, true, true, true, true, + true, NULL, clauses); + restore_extension_diagnostics (ext); + break; + } + restore_extension_diagnostics (ext); + } + else if (c_parser_next_tokens_start_declaration (parser)) + { + c_parser_declaration_or_fndef (parser, true, true, true, true, true, + NULL, clauses); + break; + } + c_parser_error (parser, "%<#pragma omp declare simd%> must be followed by " + "function declaration or definition"); + break; + default: + gcc_unreachable (); + } + clauses.release (); } -/* OpenMP 3.1: - # pragma omp taskyield new-line -*/ +/* OpenMP 4.0 + #pragma omp declare simd declare-simd-clauses[optseq] new-line + #pragma omp declare reduction (reduction-id : typename-list : expression) \ + identity-clause[opt] new-line */ static void -c_parser_omp_taskyield (c_parser *parser) +c_parser_omp_declare (c_parser *parser, enum pragma_context context) { - location_t loc = c_parser_peek_token (parser)->location; c_parser_consume_pragma (parser); - c_parser_skip_to_pragma_eol (parser); + 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) + { + c_parser_consume_token (parser); + c_parser_omp_declare_simd (parser, context); + return; + } +/* if (strcmp (p, "reduction") == 0) + { + c_parser_consume_token (parser); + c_parser_omp_declare_reduction (parser); + return; + } */ + } - c_finish_omp_taskyield (loc); + c_parser_error (parser, "expected % or %"); + c_parser_skip_to_pragma_eol (parser); } /* Main entry point to parsing most OpenMP pragmas. */ @@ -10693,12 +11779,18 @@ c_parser_omp_construct (c_parser *parser) case PRAGMA_OMP_SECTIONS: stmt = c_parser_omp_sections (loc, parser); break; + case PRAGMA_OMP_SIMD: + stmt = c_parser_omp_simd (loc, parser); + break; case PRAGMA_OMP_SINGLE: stmt = c_parser_omp_single (loc, parser); break; case PRAGMA_OMP_TASK: stmt = c_parser_omp_task (loc, parser); break; + case PRAGMA_OMP_TASKGROUP: + c_parser_omp_taskgroup (parser); + return; default: gcc_unreachable (); } @@ -10761,7 +11853,391 @@ c_parser_omp_threadprivate (c_parser *parser) c_parser_skip_to_pragma_eol (parser); } + +/* Cilk Plus <#pragma simd> parsing routines. */ + +/* Helper function for c_parser_pragma. Perform some sanity checking + for <#pragma simd> constructs. Returns FALSE if there was a + problem. */ + +static bool +c_parser_cilk_verify_simd (c_parser *parser, + enum pragma_context context) +{ + if (!flag_enable_cilkplus) + { + warning (0, "pragma simd ignored because -fcilkplus is not enabled"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + } + if (!flag_tree_vectorize) + { + warning (0, "pragma simd is useless without -ftree-vectorize"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + } + if (context == pragma_external) + { + c_parser_error (parser,"pragma simd must be inside a function"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + } + return true; +} + +/* Cilk Plus: + vectorlength ( constant-expression ) */ + +static tree +c_parser_cilk_clause_vectorlength (c_parser *parser, tree clauses) +{ + /* The vectorlength clause behaves exactly like OpenMP's safelen + clause. Represent it in OpenMP terms. */ + check_no_duplicate_clause (clauses, OMP_CLAUSE_SAFELEN, "vectorlength"); + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return clauses; + + location_t loc = c_parser_peek_token (parser)->location; + tree expr = c_parser_expr_no_commas (parser, NULL).value; + expr = c_fully_fold (expr, false, NULL); + + if (!TREE_TYPE (expr) + || !TREE_CONSTANT (expr) + || !INTEGRAL_TYPE_P (TREE_TYPE (expr))) + error_at (loc, "vectorlength must be an integer constant"); + else if (exact_log2 (TREE_INT_CST_LOW (expr)) == -1) + error_at (loc, "vectorlength must be a power of 2"); + else + { + tree u = build_omp_clause (loc, OMP_CLAUSE_SAFELEN); + OMP_CLAUSE_SAFELEN_EXPR (u) = expr; + OMP_CLAUSE_CHAIN (u) = clauses; + clauses = u; + } + + c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + return clauses; +} + +/* Cilk Plus: + linear ( simd-linear-variable-list ) + + simd-linear-variable-list: + simd-linear-variable + simd-linear-variable-list , simd-linear-variable + + simd-linear-variable: + id-expression + id-expression : simd-linear-step + + simd-linear-step: + conditional-expression */ + +static tree +c_parser_cilk_clause_linear (c_parser *parser, tree clauses) +{ + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return clauses; + + location_t loc = c_parser_peek_token (parser)->location; + + 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"); + + while (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_token (parser)->id_kind == C_ID_ID) + { + tree var = lookup_name (c_parser_peek_token (parser)->value); + + if (var == NULL) + { + undeclared_variable (c_parser_peek_token (parser)->location, + c_parser_peek_token (parser)->value); + c_parser_consume_token (parser); + } + else if (var == error_mark_node) + c_parser_consume_token (parser); + else + { + tree step = integer_one_node; + + /* Parse the linear step if present. */ + if (c_parser_peek_2nd_token (parser)->type == CPP_COLON) + { + c_parser_consume_token (parser); + c_parser_consume_token (parser); + + tree expr = c_parser_expr_no_commas (parser, NULL).value; + expr = c_fully_fold (expr, false, NULL); + + if (!TREE_TYPE (expr) + || !TREE_CONSTANT (expr) + || !INTEGRAL_TYPE_P (TREE_TYPE (expr))) + c_parser_error (parser, + "step size must be an integer constant"); + else + step = expr; + } + else + c_parser_consume_token (parser); + + /* Use OMP_CLAUSE_LINEAR, which has the same semantics. */ + tree u = build_omp_clause (loc, OMP_CLAUSE_LINEAR); + OMP_CLAUSE_DECL (u) = var; + OMP_CLAUSE_LINEAR_STEP (u) = step; + OMP_CLAUSE_CHAIN (u) = clauses; + clauses = u; + } + + if (c_parser_next_token_is_not (parser, CPP_COMMA)) + break; + + c_parser_consume_token (parser); + } + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + return clauses; +} + +/* Returns the name of the next clause. If the clause is not + recognized SIMD_OMP_CLAUSE_NONE is returned and the next token is + not consumed. Otherwise, the appropriate pragma_simd_clause is + returned and the token is consumed. */ + +static pragma_cilk_clause +c_parser_cilk_clause_name (c_parser *parser) +{ + pragma_cilk_clause result; + c_token *token = c_parser_peek_token (parser); + + if (!token->value || token->type != CPP_NAME) + return PRAGMA_CILK_CLAUSE_NONE; + + const char *p = IDENTIFIER_POINTER (token->value); + + if (!strcmp (p, "vectorlength")) + result = PRAGMA_CILK_CLAUSE_VECTORLENGTH; + else if (!strcmp (p, "linear")) + result = PRAGMA_CILK_CLAUSE_LINEAR; + else if (!strcmp (p, "private")) + result = PRAGMA_CILK_CLAUSE_PRIVATE; + else if (!strcmp (p, "firstprivate")) + result = PRAGMA_CILK_CLAUSE_FIRSTPRIVATE; + else if (!strcmp (p, "lastprivate")) + result = PRAGMA_CILK_CLAUSE_LASTPRIVATE; + else if (!strcmp (p, "reduction")) + result = PRAGMA_CILK_CLAUSE_REDUCTION; + else + return PRAGMA_CILK_CLAUSE_NONE; + + c_parser_consume_token (parser); + return result; +} + +/* Parse all # clauses. Return the list of clauses + found. */ + +static tree +c_parser_cilk_all_clauses (c_parser *parser) +{ + tree clauses = NULL; + + while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + { + pragma_cilk_clause c_kind; + + c_kind = c_parser_cilk_clause_name (parser); + + switch (c_kind) + { + case PRAGMA_CILK_CLAUSE_VECTORLENGTH: + clauses = c_parser_cilk_clause_vectorlength (parser, clauses); + break; + case PRAGMA_CILK_CLAUSE_LINEAR: + clauses = c_parser_cilk_clause_linear (parser, clauses); + break; + case PRAGMA_CILK_CLAUSE_PRIVATE: + /* Use the OpenMP counterpart. */ + clauses = c_parser_omp_clause_private (parser, clauses); + break; + case PRAGMA_CILK_CLAUSE_FIRSTPRIVATE: + /* Use the OpenMP counterpart. */ + clauses = c_parser_omp_clause_firstprivate (parser, clauses); + break; + case PRAGMA_CILK_CLAUSE_LASTPRIVATE: + /* Use the OpenMP counterpart. */ + clauses = c_parser_omp_clause_lastprivate (parser, clauses); + break; + case PRAGMA_CILK_CLAUSE_REDUCTION: + /* Use the OpenMP counterpart. */ + clauses = c_parser_omp_clause_reduction (parser, clauses, false); + break; + default: + c_parser_error (parser, "expected %<#pragma simd%> clause"); + goto saw_error; + } + } + + saw_error: + c_parser_skip_to_pragma_eol (parser); + return c_finish_cilk_clauses (clauses); +} + +/* Parse the restriction form of the for statement allowed by + Cilk Plus. This function parses both the _CILK_FOR construct as + well as the for loop following a <#pragma simd> construct, both of + which have the same syntactic restrictions. + + FOR_KEYWORD can be either RID_CILK_FOR or RID_FOR, for parsing + _Cilk_for or the <#pragma simd> for loop construct respectively. + + (NOTE: For now, only RID_FOR is handled). + + For a <#pragma simd>, CLAUSES are the clauses that should have been + previously parsed. If there are none, or if we are parsing a + _Cilk_for instead, this will be NULL. */ + +static void +c_parser_cilk_for_statement (c_parser *parser, enum rid for_keyword, + tree clauses) +{ + tree init, decl, cond, stmt; + tree block, incr, save_break, save_cont, body; + location_t loc; + bool fail = false; + + gcc_assert (/*for_keyword == RID_CILK_FOR || */for_keyword == RID_FOR); + + if (!c_parser_next_token_is_keyword (parser, for_keyword)) + { + if (for_keyword == RID_FOR) + c_parser_error (parser, "for statement expected"); + else + c_parser_error (parser, "_Cilk_for statement expected"); + return; + } + + loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + + block = c_begin_compound_stmt (true); + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + add_stmt (c_end_compound_stmt (loc, block, true)); + return; + } + + /* Parse the initialization declaration. */ + if (c_parser_next_tokens_start_declaration (parser)) + { + c_parser_declaration_or_fndef (parser, true, false, false, + false, false, NULL, vNULL); + decl = check_for_loop_decls (loc, flag_isoc99); + if (decl == NULL) + goto error_init; + if (DECL_INITIAL (decl) == error_mark_node) + decl = error_mark_node; + init = decl; + } + else if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_EQ) + { + struct c_expr decl_exp; + struct c_expr init_exp; + location_t init_loc; + + decl_exp = c_parser_postfix_expression (parser); + decl = decl_exp.value; + + c_parser_require (parser, CPP_EQ, "expected %<=%>"); + + init_loc = c_parser_peek_token (parser)->location; + init_exp = c_parser_expr_no_commas (parser, NULL); + init_exp = default_function_array_read_conversion (init_loc, + init_exp); + init = build_modify_expr (init_loc, decl, decl_exp.original_type, + NOP_EXPR, init_loc, init_exp.value, + init_exp.original_type); + init = c_process_expr_stmt (init_loc, init); + + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + } + else + { + error_init: + c_parser_error (parser, + "expected iteration declaration or initialization"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return; + } + + /* Parse the loop condition. */ + cond = NULL_TREE; + if (c_parser_next_token_is_not (parser, CPP_SEMICOLON)) + { + location_t cond_loc = c_parser_peek_token (parser)->location; + struct c_expr cond_expr = c_parser_binary_expression (parser, NULL, + NULL); + + cond = cond_expr.value; + cond = c_objc_common_truthvalue_conversion (cond_loc, cond); + cond = c_fully_fold (cond, false, NULL); + } + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + + /* Parse the increment expression. */ + incr = NULL_TREE; + if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)) + { + location_t incr_loc = c_parser_peek_token (parser)->location; + incr = c_process_expr_stmt (incr_loc, + c_parser_expression (parser).value); + } + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + if (decl == NULL || decl == error_mark_node || init == error_mark_node) + fail = true; + + save_break = c_break_label; + /* Magic number to inform c_finish_bc_stmt() that we are within a + Cilk for construct. */ + c_break_label = build_int_cst (size_type_node, 2); + + save_cont = c_cont_label; + c_cont_label = NULL_TREE; + body = c_parser_c99_block_statement (parser); + c_break_label = save_break; + c_cont_label = save_cont; + + if (!fail) + { + if (for_keyword == RID_FOR) + c_finish_cilk_simd_loop (loc, decl, init, cond, incr, body, clauses); + } + + stmt = c_end_compound_stmt (loc, block, true); + add_stmt (stmt); + c_break_label = save_break; + c_cont_label = save_cont; +} + +/* Main entry point for parsing Cilk Plus <#pragma simd> for + loops. */ + +static void +c_parser_cilk_simd_construct (c_parser *parser) +{ + tree clauses = c_parser_cilk_all_clauses (parser); + c_parser_cilk_for_statement (parser, RID_FOR, clauses); +} + /* Parse a transaction attribute (GCC Extension). transaction-attribute: @@ -10925,7 +12401,7 @@ c_parser_transaction_expression (c_parser *parser, enum rid keyword) */ static tree -c_parser_transaction_cancel(c_parser *parser) +c_parser_transaction_cancel (c_parser *parser) { location_t loc = c_parser_peek_token (parser)->location; tree attrs; diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index d1a871daa683c..93516dabd6628 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -637,9 +637,15 @@ extern tree c_begin_omp_parallel (void); extern tree c_finish_omp_parallel (location_t, tree, tree); extern tree c_begin_omp_task (void); extern tree c_finish_omp_task (location_t, tree, tree); +extern tree c_begin_omp_taskgroup (void); +extern void c_finish_omp_taskgroup (location_t, 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 void c_finish_omp_declare_simd (tree, tree, vec); 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); /* Set to 0 at beginning of a function definition, set to 1 if a return statement that specifies a return value is seen. */ diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 3a92311142982..cebe7cb858ee3 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -9153,6 +9153,13 @@ c_finish_bc_stmt (location_t loc, tree *label_p, bool is_break) error_at (loc, "break statement used with OpenMP for loop"); return NULL_TREE; + case 2: + if (is_break) + error ("break statement within <#pragma simd> loop body"); + else + error ("continue statement within <#pragma simd> loop loop"); + return NULL_TREE; + default: gcc_unreachable (); } @@ -10643,6 +10650,93 @@ c_finish_omp_task (location_t loc, tree clauses, tree block) return add_stmt (stmt); } +/* Like c_begin_compound_stmt, except force the retention of the BLOCK. */ + +tree +c_begin_omp_taskgroup (void) +{ + tree block; + + keep_next_level (); + block = c_begin_compound_stmt (true); + + return block; +} + +/* Generate code for #pragma omp taskgroup. */ + +void +c_finish_omp_taskgroup (location_t loc, tree block) +{ + tree fn = builtin_decl_explicit (BUILT_IN_GOMP_TASKGROUP_START); + tree stmt = build_call_expr_loc (loc, fn, 0); + block = c_end_compound_stmt (loc, block, true); + add_stmt (stmt); + add_stmt (block); + fn = builtin_decl_explicit (BUILT_IN_GOMP_TASKGROUP_END); + stmt = build_call_expr_loc (loc, fn, 0); + add_stmt (stmt); +} + +/* Generate GOMP_cancel call for #pragma omp cancel. */ + +void +c_finish_omp_cancel (location_t loc, tree clauses) +{ + tree fn = builtin_decl_explicit (BUILT_IN_GOMP_CANCEL); + int mask = 0; + if (find_omp_clause (clauses, OMP_CLAUSE_PARALLEL)) + mask = 1; + else if (find_omp_clause (clauses, OMP_CLAUSE_FOR)) + mask = 2; + else if (find_omp_clause (clauses, OMP_CLAUSE_SECTIONS)) + mask = 4; + else if (find_omp_clause (clauses, OMP_CLAUSE_TASKGROUP)) + mask = 8; + else + { + error_at (loc, "%<#pragma omp cancel must specify one of " + "%, %, % or % " + "clauses"); + return; + } + tree stmt = build_call_expr_loc (loc, fn, 1, + build_int_cst (integer_type_node, mask)); + tree ifc = find_omp_clause (clauses, OMP_CLAUSE_IF); + if (ifc != NULL_TREE) + stmt = build3 (COND_EXPR, void_type_node, OMP_CLAUSE_IF_EXPR (ifc), + stmt, NULL_TREE); + add_stmt (stmt); +} + +/* Generate GOMP_cancellation_point call for + #pragma omp cancellation point. */ + +void +c_finish_omp_cancellation_point (location_t loc, tree clauses) +{ + tree fn = builtin_decl_explicit (BUILT_IN_GOMP_CANCELLATION_POINT); + int mask = 0; + if (find_omp_clause (clauses, OMP_CLAUSE_PARALLEL)) + mask = 1; + else if (find_omp_clause (clauses, OMP_CLAUSE_FOR)) + mask = 2; + else if (find_omp_clause (clauses, OMP_CLAUSE_SECTIONS)) + mask = 4; + else if (find_omp_clause (clauses, OMP_CLAUSE_TASKGROUP)) + mask = 8; + else + { + error_at (loc, "%<#pragma omp cancellation point must specify one of " + "%, %, % or % " + "clauses"); + return; + } + tree stmt = build_call_expr_loc (loc, fn, 1, + build_int_cst (integer_type_node, mask)); + add_stmt (stmt); +} + /* For all elements of CLAUSES, validate them vs OpenMP constraints. Remove any elements from the list that are invalid. */ @@ -10650,13 +10744,16 @@ tree c_finish_omp_clauses (tree clauses) { bitmap_head generic_head, firstprivate_head, lastprivate_head; + bitmap_head aligned_head; tree c, t, *pc = &clauses; const char *name; + bool branch_seen = false; bitmap_obstack_initialize (NULL); bitmap_initialize (&generic_head, &bitmap_default_obstack); bitmap_initialize (&firstprivate_head, &bitmap_default_obstack); bitmap_initialize (&lastprivate_head, &bitmap_default_obstack); + bitmap_initialize (&aligned_head, &bitmap_default_obstack); for (pc = &clauses, c = clauses; c ; c = *pc) { @@ -10744,6 +10841,30 @@ c_finish_omp_clauses (tree clauses) } goto check_dup_generic; + case OMP_CLAUSE_LINEAR: + name = "linear"; + t = OMP_CLAUSE_DECL (c); + if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) + && TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "linear clause applied to non-integral non-pointer"); + remove = true; + break; + } + if (TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c))) == POINTER_TYPE) + { + tree s = OMP_CLAUSE_LINEAR_STEP (c); + s = pointer_int_sum (OMP_CLAUSE_LOCATION (c), PLUS_EXPR, + OMP_CLAUSE_DECL (c), s); + s = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR, + sizetype, s, OMP_CLAUSE_DECL (c)); + if (s == error_mark_node) + s = size_one_node; + OMP_CLAUSE_LINEAR_STEP (c) = s; + } + goto check_dup_generic; + check_dup_generic: t = OMP_CLAUSE_DECL (c); if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) @@ -10808,6 +10929,71 @@ c_finish_omp_clauses (tree clauses) bitmap_set_bit (&lastprivate_head, DECL_UID (t)); break; + case OMP_CLAUSE_ALIGNED: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in % clause", t); + remove = true; + } + else if (bitmap_bit_p (&aligned_head, DECL_UID (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE appears more than once in % clauses", + t); + remove = true; + } + else + bitmap_set_bit (&aligned_head, DECL_UID (t)); + break; + + case OMP_CLAUSE_DEPEND: + t = OMP_CLAUSE_DECL (c); + /* FIXME: depend clause argument may be also array section. */ + if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in % clause", t); + remove = true; + } + break; + + case OMP_CLAUSE_MAP: + case OMP_CLAUSE_TO: + case OMP_CLAUSE_FROM: + t = OMP_CLAUSE_DECL (c); + /* FIXME: map clause argument may be also array section. */ + if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (TREE_CODE (t) == VAR_DECL && 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; + } + break; + + case OMP_CLAUSE_UNIFORM: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) != PARM_DECL) + { + if (DECL_P (t)) + error_at (OMP_CLAUSE_LOCATION (c), + "%qD is not an argument in % clause", t); + else + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not an argument in % clause", t); + remove = true; + } + break; + case OMP_CLAUSE_IF: case OMP_CLAUSE_NUM_THREADS: case OMP_CLAUSE_SCHEDULE: @@ -10818,6 +11004,29 @@ c_finish_omp_clauses (tree clauses) case OMP_CLAUSE_COLLAPSE: case OMP_CLAUSE_FINAL: case OMP_CLAUSE_MERGEABLE: + case OMP_CLAUSE_SAFELEN: + case OMP_CLAUSE_SIMDLEN: + case OMP_CLAUSE_DEVICE: + case OMP_CLAUSE_DIST_SCHEDULE: + case OMP_CLAUSE_PARALLEL: + case OMP_CLAUSE_FOR: + case OMP_CLAUSE_SECTIONS: + case OMP_CLAUSE_TASKGROUP: + case OMP_CLAUSE_PROC_BIND: + pc = &OMP_CLAUSE_CHAIN (c); + continue; + + case OMP_CLAUSE_INBRANCH: + case OMP_CLAUSE_NOTINBRANCH: + if (branch_seen) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% clause is incompatible with " + "%"); + remove = true; + break; + } + branch_seen = true; pc = &OMP_CLAUSE_CHAIN (c); continue; @@ -10879,6 +11088,93 @@ c_finish_omp_clauses (tree clauses) return clauses; } +/* Finalize #pragma omp declare simd clauses after FNDECL has been parsed, + and put that into "omp declare simd" attribute. */ + +void +c_finish_omp_declare_simd (tree fndecl, tree parms, vec clauses) +{ + tree cl; + int i; + + if (clauses[0] == error_mark_node) + return; + if (fndecl == NULL_TREE || TREE_CODE (fndecl) != FUNCTION_DECL) + { + error ("%<#pragma omp declare simd%> not immediately followed by " + "a function declaration or definition"); + clauses[0] = error_mark_node; + return; + } + if (clauses[0] == integer_zero_node) + { + error_at (DECL_SOURCE_LOCATION (fndecl), + "%<#pragma omp declare simd%> not immediately followed by " + "a single function declaration or definition"); + clauses[0] = error_mark_node; + return; + } + + if (parms == NULL_TREE) + parms = DECL_ARGUMENTS (fndecl); + + FOR_EACH_VEC_ELT (clauses, i, cl) + { + tree c, *pc, decl, name; + for (pc = &cl, c = cl; c; c = *pc) + { + bool remove = false; + switch (OMP_CLAUSE_CODE (c)) + { + case OMP_CLAUSE_UNIFORM: + case OMP_CLAUSE_LINEAR: + case OMP_CLAUSE_ALIGNED: + case OMP_CLAUSE_REDUCTION: + name = OMP_CLAUSE_DECL (c); + if (name == error_mark_node) + remove = true; + else + { + for (decl = parms; decl; decl = TREE_CHAIN (decl)) + if (DECL_NAME (decl) == name) + break; + if (decl == NULL_TREE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a function parameter", name); + remove = true; + } + else + OMP_CLAUSE_DECL (c) = decl; + } + break; + default: + break; + } + if (remove) + *pc = OMP_CLAUSE_CHAIN (c); + else + pc = &OMP_CLAUSE_CHAIN (c); + } + cl = c_finish_omp_clauses (cl); + tree saved_arguments = DECL_ARGUMENTS (fndecl); + DECL_ARGUMENTS (fndecl) = parms; + cl = c_omp_declare_simd_clauses_to_numbers (fndecl, cl); + DECL_ARGUMENTS (fndecl) = saved_arguments; + for (c = lookup_attribute ("omp declare simd", DECL_ATTRIBUTES (fndecl)); + c; c = lookup_attribute ("omp declare simd", TREE_CHAIN (c))) + if (omp_declare_simd_clauses_equal (TREE_VALUE (c), cl)) + break; + if (c) + continue; + c = build_tree_list (get_identifier ("omp declare simd"), cl); + TREE_CHAIN (c) = DECL_ATTRIBUTES (fndecl); + DECL_ATTRIBUTES (fndecl) = c; + } + + clauses[0] = integer_zero_node; +} + /* Create a transaction node. */ tree @@ -10967,3 +11263,205 @@ c_build_va_arg (location_t loc, tree expr, tree type) "C++ requires promoted type, not enum type, in %"); return build_va_arg (loc, expr, type); } + +/* Return truthvalue of whether T1 is the same tree structure as T2. + Return 1 if they are the same. Return 0 if they are different. */ + +bool +c_tree_equal (tree t1, tree t2) +{ + enum tree_code code1, code2; + + if (t1 == t2) + return true; + if (!t1 || !t2) + return false; + + for (code1 = TREE_CODE (t1); + CONVERT_EXPR_CODE_P (code1) + || code1 == NON_LVALUE_EXPR; + code1 = TREE_CODE (t1)) + t1 = TREE_OPERAND (t1, 0); + for (code2 = TREE_CODE (t2); + CONVERT_EXPR_CODE_P (code2) + || code2 == NON_LVALUE_EXPR; + code2 = TREE_CODE (t2)) + t2 = TREE_OPERAND (t2, 0); + + /* They might have become equal now. */ + if (t1 == t2) + return true; + + if (code1 != code2) + return false; + + switch (code1) + { + case INTEGER_CST: + return TREE_INT_CST_LOW (t1) == TREE_INT_CST_LOW (t2) + && TREE_INT_CST_HIGH (t1) == TREE_INT_CST_HIGH (t2); + + case REAL_CST: + return REAL_VALUES_EQUAL (TREE_REAL_CST (t1), TREE_REAL_CST (t2)); + + case STRING_CST: + return TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2) + && !memcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2), + TREE_STRING_LENGTH (t1)); + + case FIXED_CST: + return FIXED_VALUES_IDENTICAL (TREE_FIXED_CST (t1), + TREE_FIXED_CST (t2)); + + case COMPLEX_CST: + return c_tree_equal (TREE_REALPART (t1), TREE_REALPART (t2)) + && c_tree_equal (TREE_IMAGPART (t1), TREE_IMAGPART (t2)); + + case VECTOR_CST: + return operand_equal_p (t1, t2, OEP_ONLY_CONST); + + case CONSTRUCTOR: + /* We need to do this when determining whether or not two + non-type pointer to member function template arguments + are the same. */ + if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2)) + || CONSTRUCTOR_NELTS (t1) != CONSTRUCTOR_NELTS (t2)) + return false; + { + tree field, value; + unsigned int i; + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t1), i, field, value) + { + constructor_elt *elt2 = CONSTRUCTOR_ELT (t2, i); + if (!c_tree_equal (field, elt2->index) + || !c_tree_equal (value, elt2->value)) + return false; + } + } + return true; + + case TREE_LIST: + if (!c_tree_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2))) + return false; + if (!c_tree_equal (TREE_VALUE (t1), TREE_VALUE (t2))) + return false; + return c_tree_equal (TREE_CHAIN (t1), TREE_CHAIN (t2)); + + case SAVE_EXPR: + return c_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)); + + case CALL_EXPR: + { + tree arg1, arg2; + call_expr_arg_iterator iter1, iter2; + if (!c_tree_equal (CALL_EXPR_FN (t1), CALL_EXPR_FN (t2))) + return false; + for (arg1 = first_call_expr_arg (t1, &iter1), + arg2 = first_call_expr_arg (t2, &iter2); + arg1 && arg2; + arg1 = next_call_expr_arg (&iter1), + arg2 = next_call_expr_arg (&iter2)) + if (!c_tree_equal (arg1, arg2)) + return false; + if (arg1 || arg2) + return false; + return true; + } + + case TARGET_EXPR: + { + tree o1 = TREE_OPERAND (t1, 0); + tree o2 = TREE_OPERAND (t2, 0); + + /* Special case: if either target is an unallocated VAR_DECL, + it means that it's going to be unified with whatever the + TARGET_EXPR is really supposed to initialize, so treat it + as being equivalent to anything. */ + if (TREE_CODE (o1) == VAR_DECL && DECL_NAME (o1) == NULL_TREE + && !DECL_RTL_SET_P (o1)) + /*Nop*/; + else if (TREE_CODE (o2) == VAR_DECL && DECL_NAME (o2) == NULL_TREE + && !DECL_RTL_SET_P (o2)) + /*Nop*/; + else if (!c_tree_equal (o1, o2)) + return false; + + return c_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1)); + } + + case COMPONENT_REF: + if (TREE_OPERAND (t1, 1) != TREE_OPERAND (t2, 1)) + return false; + return c_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)); + + case PARM_DECL: + case VAR_DECL: + case CONST_DECL: + case FIELD_DECL: + case FUNCTION_DECL: + case IDENTIFIER_NODE: + case SSA_NAME: + return false; + + case TREE_VEC: + { + unsigned ix; + if (TREE_VEC_LENGTH (t1) != TREE_VEC_LENGTH (t2)) + return false; + for (ix = TREE_VEC_LENGTH (t1); ix--;) + if (!c_tree_equal (TREE_VEC_ELT (t1, ix), + TREE_VEC_ELT (t2, ix))) + return false; + return true; + } + + default: + break; + } + + switch (TREE_CODE_CLASS (code1)) + { + case tcc_unary: + case tcc_binary: + case tcc_comparison: + case tcc_expression: + case tcc_vl_exp: + case tcc_reference: + case tcc_statement: + { + int i, n = TREE_OPERAND_LENGTH (t1); + + switch (code1) + { + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + n = 1; + break; + case ARRAY_REF: + n = 2; + break; + default: + break; + } + + if (TREE_CODE_CLASS (code1) == tcc_vl_exp + && n != TREE_OPERAND_LENGTH (t2)) + return false; + + for (i = 0; i < n; ++i) + if (!c_tree_equal (TREE_OPERAND (t1, i), TREE_OPERAND (t2, i))) + return false; + + return true; + } + + case tcc_type: + return comptypes (t1, t2); + default: + gcc_unreachable (); + } + /* We can get here with --disable-checking. */ + return false; +} diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h index 0f24799663057..cd2f527bb4710 100644 --- a/gcc/cfgloop.h +++ b/gcc/cfgloop.h @@ -168,6 +168,20 @@ struct GTY ((chain_next ("%h.next"))) loop { describes what is the state of the estimation. */ enum loop_estimation estimate_state; + /* If > 0, an integer, where the user asserted that for any + I in [ 0, nb_iterations ) and for any J in + [ I, min ( I + safelen, nb_iterations ) ), the Ith and Jth iterations + of the loop can be safely evaluated concurrently. */ + int safelen; + + /* True if we should try harder to vectorize this loop. */ + bool force_vect; + + /* For SIMD loops, this is a unique identifier of the loop, referenced + by IFN_GOMP_SIMD_VF, IFN_GOMP_SIMD_LANE and IFN_GOMP_SIMD_LAST_LANE + builtins. */ + tree simduid; + /* Upper bound on number of iterations of a loop. */ struct nb_iter_bound *bounds; diff --git a/gcc/cp/ChangeLog.cilkplus b/gcc/cp/ChangeLog.cilkplus new file mode 100644 index 0000000000000..f0ee3ee6ed877 --- /dev/null +++ b/gcc/cp/ChangeLog.cilkplus @@ -0,0 +1,28 @@ +2013-06-26 Aldy Hernandez + + * cp-gimplify.c (cp_gimplify_expr): Add case for CILK_SIMD. + (cp_genericize_r): Same. + * pt.c (tsubst_expr): Same. + * semantics.c (finish_omp_for): Same. + +2013-05-21 Balaji V. Iyer + Aldy Hernandez + + * cp-tree.h (p_simd_valid_stmts_in_body_p): New prototype. + (finish_cilk_for_cond): Likewise. + * parser.h (IN_CILK_P_SIMD_FOR): New #define. + * Make-lang.in (CXX_AND_OBJCXX_OBJS): Added new obj-file cp-cilkplus.o + * cp-cilkplus.c: New file. + * semantics.c (finish_cilk_for_cond): New. + * parser.c (cp_parser_pragma): Added a PRAGMA_CILK_SIMD case. + (cp_parser_cilk_simd_vectorlength): New function. + (cp_parser_cilk_simd_linear): Likewise. + (cp_parser_cilk_simd_clause_name): Likewise. + (cp_parser_cilk_simd_all_clauses): Likewise. + (cp_parser_cilk_simd_construct): Likewise. + (cp_parser_simd_for_init_statement): Likewise. + (cp_parser_cilk_for_expression_iterator): Likewise. + (cp_parser_cilk_for_condition): Likewise. + (cp_parser_cilk_for): Likewise. + (cp_parser_jump_statement): Added a IN_CILK_P_SIMD_FOR case. + diff --git a/gcc/cp/ChangeLog.gomp b/gcc/cp/ChangeLog.gomp new file mode 100644 index 0000000000000..2eadb071243e2 --- /dev/null +++ b/gcc/cp/ChangeLog.gomp @@ -0,0 +1,275 @@ +2013-06-21 Jakub Jelinek + + * decl2.c (cplus_decl_attributes): Only add attribute + to TREE_STATIC vars. + * parser.c (cp_parser_omp_distribute): Don't reject + #pragma omp teams distribute simd and + #pragma omp target teams distribute simd. Consume + simd or parallel token. + +2013-06-14 Jakub Jelinek + + * parser.c (cp_parser_omp_all_clauses): Add defaulted finish_p + argument. Don't call finish_omp_clauses if it is false. + (cp_parser_omp_for_loop): Change last argument to cclauses, + and adjust uses to grab parallel clauses from the array of all + the split clauses. + (cp_omp_split_clauses): New function. + (cp_parser_omp_simd): Add p_name, mask and cclauses arguments. + Allow the function to be called also when parsing combined constructs. + (cp_parser_omp_sections): Likewise. + (cp_parser_omp_for): Add p_name, mask and cclauses arguments. + Allow the function to be called also when parsing combined constructs, + and call cp_parser_omp_simd when parsing for simd. + (cp_parser_omp_parallel): Likewise. + (cp_parser_omp_distribute): Likewise. + (cp_parser_omp_teams): Likewise. + (cp_parser_omp_target): If next token is teams, call + cp_parser_omp_teams and parse it as combined construct. + (cp_parser_omp_declare_simd): Pass false as last argument to + cp_parser_omp_all_clauses. + (cp_parser_omp_construct): Adjust callers of cp_parser_omp_simd, + cp_parser_omp_sections, cp_parser_omp_for, cp_parser_omp_parallel, + cp_parser_omp_distribute and cp_parser_omp_teams. + * pt.c (tsubst_expr): Don't handle OMP_FOR_SIMD. Handle NULL + OMP_FOR_INIT. + * semantics.c (finish_omp_for): Don't handle OMP_FOR_SIMD. + * cp-tree.h (OMP_FOR_GIMPLIFYING_P): Adjust comment. + * cp-gimplify.c (cp_gimplify_expr, cp_genericize_r): Don't handle + OMP_FOR_SIMD. + + * decl2.c (cp_omp_mappable_type): No longer static. Handle array + types and recurse for FIELD_DECL types. + * semantics.c (handle_omp_array_sections_1): Call + convert_from_reference before testing for pointer_based_p. + (finish_omp_clauses): Complain if OMP_CLAUSE_{MAP,TO,FROM} + decls or array sections don't have cp_omp_mappable_type. + * cp-tree.h (cp_omp_mappable_type): New prototype. + +2013-06-12 Jakub Jelinek + + * semantics.c (finish_omp_clause): Don't mark references addressable. + For OMP_CLAUSE_{TO,FROM} detect same decl appearing more than once + in motion clauses. + * parser.c (cp_parser_omp_var_list_no_open): Handle [ expression ] + notation in array section specification. + (cp_parser_omp_all_clauses): Don't require to/from clauses to be + first. + (cp_parser_omp_target_update): Adjust diagnostics. + + * semantics.c (finish_omp_clauses): Handle OMP_CLAUSE_THREAD_LIMIT. + * parser.c (cp_parser_omp_clause_name): Handle thread_limit clause. + (cp_parser_omp_clause_thread_limit): New function. + (cp_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_THREAD_LIMIT. + (OMP_TEAMS_CLAUSE_MASK): Replace PRAGMA_OMP_CLAUSE_NUM_THREADS + with PRAGMA_OMP_CLAUSE_THREAD_LIMIT. + * pt.c (tsubst_omp_clauses): Handle OMP_CLAUSE_THREAD_LIMIT. + +2013-06-04 Jakub Jelinek + + * semantics.c (handle_omp_array_sections_1, handle_omp_array_sections): + New functions. + (finish_omp_clauses): Handle array sections on + OMP_CLAUSE_{MAP,TO,FROM,DEPEND}. If not array sections, mark the decl + addressable. + * parser.c (cp_parser_omp_var_list_no_open): Parse array sections + on OMP_CLAUSE_{MAP,TO,FROM,DEPEND} clauses. + +2013-05-29 Jakub Jelinek + + * parser.c (cp_parser_omp_declare_target, + cp_parser_omp_end_declare_target): New functions. + (cp_parser_omp_declare): For target keyword call + cp_parser_omp_declare_target. + (cp_parser_pragma): Handle PRAGMA_OMP_END_DECLARE_TARGET. + * cp-tree.h (current_omp_declare_target_attribute): Declare. + * decl2.c (current_omp_declare_target_attribute): New variable. + (cp_omp_mappable_type): New function. + (cplus_decl_attributes): Handle addition of "omp declare target" + attribute for decls in #pragma omp declare target region. Complain + for invalid uses. + +2013-05-27 Jakub Jelinek + + * parser.c (cp_parser_omp_clause_cancelkind): Remove diagnostics. + (cp_parser_omp_all_clauses): Require that OMP_CLAUSE_{TO,FROM} + and OMP_CLAUSE_{PARALLEL,FOR,SECTIONS,TASKGROUP} must be first in + the list of clauses. + (OMP_TEAMS_CLAUSE_MASK, OMP_TARGET_CLAUSE_MASK, + OMP_TARGET_DATA_CLAUSE_MASK, OMP_TARGET_UPDATE_CLAUSE_MASK, + OMP_DISTRIBUTE_CLAUSE_MASK): Define. + (cp_parser_omp_teams, cp_parser_omp_target, cp_parser_omp_target_data, + cp_parser_omp_target_update, cp_parser_omp_distribute): New functions. + (cp_parser_omp_construct): Handle PRAGMA_OMP_DISTRIBUTE and + PRAGMA_OMP_TEAMS. + (cp_parser_pragma): Handle PRAGMA_OMP_DISTRIBUTE, PRAGMA_OMP_TEAMS + and PRAGMA_OMP_TARGET. + * pt.c (tsubst_expr): Handle OMP_TEAMS, OMP_TARGET, OMP_TARGET_DATA + and OMP_TARGET_UPDATE. + +2013-05-09 Jakub Jelinek + + * cp-tree.h (cp_decl_specifier_seq): Add omp_declare_simd_clauses + field. + (finish_omp_declare_simd): Declare. + * decl2.c (is_late_template_attribute): Return true for + "omp declare simd" attribute. + (cp_check_const_attributes): Don't check TREE_VALUE of arg if + arg isn't a TREE_LIST. + * decl.c (grokfndecl): Add omp_declare_simd_clauses argument, call + finish_omp_declare_simd if non-NULL. + (grokdeclarator): Pass it declspecs->omp_declare_simd_clauses + to grokfndecl. + * pt.c (apply_late_template_attributes): Handle "omp declare simd" + attribute specially. + (tsubst_omp_clauses): Add declare_simd argument, don't call + finish_omp_clauses if it is set. Handle OpenMP 4.0 clauses. + (tsubst_expr): Adjust tsubst_omp_clauses callers. + * semantics.c (finish_omp_clauses): Diagnose inbranch notinbranch. + (finish_omp_declare_simd): New function. + * parser.h (struct cp_parser): Add omp_declare_simd_clauses field. + * parser.c (cp_ensure_no_omp_declare_simd, + cp_finish_omp_declare_simd): New functions. + (enum pragma_context): Add pragma_member and pragma_objc_icode. + (cp_parser_linkage_specification, cp_parser_namespace_definition, + cp_parser_class_specifier_1): Call cp_ensure_no_omp_declare_simd. + (cp_parser_init_declarator, cp_parser_member_declaration, + cp_parser_function_definition_from_specifiers_and_declarator, + cp_parser_save_member_function_body): Copy + parser->omp_declare_simd_clauses to + decl_specifiers->omp_declare_simd_clauses, call + cp_finish_omp_declare_simd. + (cp_parser_member_specification_opt): Pass pragma_member instead + of pragma_external to cp_parser_pragma. + (cp_parser_objc_interstitial_code): Pass pragma_objc_icode instead + of pragma_external to cp_parser_pragma. + (cp_parser_omp_var_list_no_open): If parser->omp_declare_simd_clauses, + just cp_parser_identifier the argument names. + (cp_parser_omp_all_clauses): Don't call finish_omp_clauses for + parser->omp_declare_simd_clauses. + (OMP_DECLARE_SIMD_CLAUSE_MASK): Define. + (cp_parser_omp_declare_simd, cp_parser_omp_declare): New functions. + (cp_parser_pragma): Call cp_ensure_no_omp_declare_simd. Handle + PRAGMA_OMP_DECLARE_REDUCTION. Replace == pragma_external with + != pragma_stmt and != pragma_compound. + +2013-04-30 Jakub Jelinek + + * pt.c (tsubst_expr): Pass OMP_ATOMIC_SEQ_CST to finish_omp_atomic. + * semantics.c (finish_omp_atomic): Add seq_cst argument, pass + it through to c_finish_omp_atomic or store into OMP_ATOMIC_SEQ_CST. + * cp-tree.h (finish_omp_atomic): Adjust prototype. + * parser.c (cp_parser_omp_atomic): Parse seq_cst clause, pass + true if it is present to finish_omp_atomic. + +2013-04-24 Jakub Jelinek + + * parser.c (cp_parser_omp_clause_name): Add missing break after + case 'i'. + (cp_parser_omp_cancellation_point): Diagnose error if + #pragma omp cancellation isn't followed by point. + * semantics.c (finish_omp_clauses): Complain also about zero + in alignment of aligned directive or safelen/simdlen expressions. + (finish_omp_cancel): Fix up diagnostics wording. + +2013-04-23 Jakub Jelinek + + * semantics.c (finish_omp_clauses): On OMP_CLAUSE_LINEAR clauses + verify OMP_CLAUSE_DECL has integral or pointer type, and handle + linear steps for pointer type decls. FIx up handling of + OMP_CLAUSE_UNIFORM. + +2013-04-19 Jakub Jelinek + + * cp-tree.h (CP_OMP_CLAUSE_INFO): Also allow it on OMP_CLAUSE_LINEAR. + * parser.c (cp_parser_omp_var_list_no_open): If colon is non-NULL, + temporarily disable colon_corrects_to_scope_p during the parsing + of the variable list. + (cp_parser_omp_clause_safelen, cp_parser_omp_clause_simdlen): New + functions. + (cp_parser_omp_all_clauses): Handle OMP_CLAUSE_SAFELEN and + OMP_CLAUSE_SIMDLEN. + * semantics.c (finish_omp_clauses): Allow NULL_TREE in + OMP_CLAUSE_ALIGNED_ALIGNMENT. + +2013-04-10 Jakub Jelinek + + * cp-tree.h (finish_omp_taskgroup): New prototype. + * parser.c (cp_parser_omp_clause_proc_bind): Require ) instead of + colon at the end of the clause. + (cp_parser_omp_taskgroup): New function. + (cp_parser_omp_construct, cp_parser_pragma): Handle + PRAGMA_OMP_TASKGROUP. + * semantics.c (finish_omp_taskgroup): New function. + +2013-04-05 Jakub Jelinek + + * semantics.c (finish_omp_for): Disallow class iterators for + OMP_SIMD and OMP_FOR_SIMD loops. + +2013-03-27 Jakub Jelinek + + * cp-tree.h (OMP_FOR_GIMPLIFYING_P): Use OMP_LOOP_CHECK instead of + OMP_FOR_CHECK. + (finish_omp_for): Add enum tree_code second argument. + (finish_omp_cancel, finish_omp_cancellation_point): New prototypes. + * cp-gimplify.c (cp_gimplify_expr, cp_genericize_r): Handle + OMP_SIMD, OMP_FOR_SIMD and OMP_DISTRIBUTE. + * semantics.c (finish_omp_clauses): Handle new OpenMP 4.0 clauses. + (finish_omp_for): Add code argument, pass it down to make_node + or c_finish_omp_for. + (finish_omp_cancel, finish_omp_cancellation_point): New functions. + * parser.c (cp_parser_omp_clause_name): Add parsing of new + OpenMP 4.0 clauses. + (cp_parser_omp_var_list_no_open): Add COLON argument, if non-NULL, + accept termination by colon instead of closing paren. + (cp_parser_omp_var_list, cp_parser_omp_clause_reduction): Adjust + callers. + (cp_parser_omp_clause_branch, cp_parser_omp_clause_cancelkind, + cp_parser_omp_clause_num_teams, cp_parser_omp_clause_aligned, + cp_parser_omp_clause_linear, cp_parser_omp_clause_depend, + cp_parser_omp_clause_map, cp_parser_omp_clause_device, + cp_parser_omp_clause_dist_schedule, cp_parser_omp_clause_proc_bind): + New functions. + (cp_parser_omp_all_clauses): Change mask argument's type to + omp_clause_mask from unsigned. Fix c_name for + PRAGMA_OMP_CLAUSE_UNTIED. Handle new OpenMP 4.0 clauses. + (cp_parser_omp_for_loop): Add code argument. Pass it down to + finish_omp_for. + (OMP_SIMD_CLAUSE_MASK): Define. + (cp_parser_omp_simd): New function. + (OMP_FOR_CLAUSE_MASK, OMP_SECTIONS_CLAUSE_MASK, + OMP_PARALLEL_CLAUSE_MASK, OMP_SINGLE_CLAUSE_MASK, + OMP_TASK_CLAUSE_MASK): Use OMP_CLAUSE_MASK_1 instead of 1. + (cp_parser_omp_for): Handle parsing of #pragma omp for simd. + (cp_parser_omp_parallel): Handle parsing of + #pragma omp parallel for simd. Use omp_clause_mask type + instead of unsigned for mask, use OMP_CLAUSE_MASK_1 instead + of 1 for masks. + (OMP_CANCEL_CLAUSE_MASK, OMP_CANCELLATION_POINT_CLAUSE_MASK): Define. + (cp_parser_omp_cancel, cp_parser_omp_cancellation_point): New + functions. + (cp_parser_omp_construct): Handle PRAGMA_OMP_SIMD, PRAGMA_OMP_CANCEL + and PRAGMA_OMP_CANCELLATION_POINT. + (cp_parser_pragma): Handle PRAGMA_OMP_SIMD. + * pt.c (tsubst_expr): Handle OMP_SIMD, OMP_FOR_SIMD and + OMP_DISTRIBUTE. Pass down TREE_CODE to finish_omp_for. + +2013-03-20 Jakub Jelinek + + * parser.c (cp_parser_omp_atomic): Never restart unless + structured_block is true. + + * parser.c (cp_parser_binary_expression): Handle no_toplevel_fold_p + even for binary operations other than comparison. + (cp_parser_omp_atomic): Handle parsing OpenMP 4.0 atomics. + * pt.c (tsubst_expr) : Handle atomic exchange. + * semantics.c (finish_omp_atomic): Use cp_tree_equal to diagnose + expression mismatches and to find out if c_finish_omp_atomic + should be called with swapped set to true or false. + +Copyright (C) 2013 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index 6e80bcf8c101c..fa36369578d19 100644 --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -80,6 +80,7 @@ CXX_AND_OBJCXX_OBJS = cp/call.o cp/decl.o cp/expr.o cp/pt.o cp/typeck2.o \ cp/typeck.o cp/cvt.o cp/except.o cp/friend.o cp/init.o cp/method.o \ cp/search.o cp/semantics.o cp/tree.o cp/repo.o cp/dump.o cp/optimize.o \ cp/mangle.o cp/cp-objcp-common.o cp/name-lookup.o cp/cxx-pretty-print.o \ + cp/cp-cilkplus.o \ cp/cp-gimplify.o cp/cp-array-notation.o $(CXX_C_OBJS) # Language-specific object files for C++. @@ -348,3 +349,5 @@ cp/name-lookup.o: cp/name-lookup.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ cp/cxx-pretty-print.o: cp/cxx-pretty-print.c $(CXX_PRETTY_PRINT_H) \ $(CONFIG_H) $(SYSTEM_H) $(TM_H) coretypes.h $(CXX_TREE_H) tree-pretty-print.h +cp/cp-cilkplus.o: cp/cp-cilkplus.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(CXX_TREE_H) $(DIAGNOSTIC_CORE_H) diff --git a/gcc/cp/cp-cilkplus.c b/gcc/cp/cp-cilkplus.c new file mode 100644 index 0000000000000..aa803438e5d61 --- /dev/null +++ b/gcc/cp/cp-cilkplus.c @@ -0,0 +1,78 @@ +/* This file is part of the Intel(R) Cilk(TM) Plus support + This file contains routines to handle Cilk Plus specific + routines for the C++ Compiler. + Copyright (C) 2013 Free Software Foundation, Inc. + Contributed by Balaji V. Iyer , + Aldy Hernandez . + + This file is part of GCC. + + GCC 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. + + GCC 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. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + . */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "cp-tree.h" +#include "diagnostic-core.h" + + +/* Callback for cp_walk_tree to validate the body of a pragma simd loop + or _cilk_for loop. + + This function is passed in as a function pointer to walk_tree. *TP is + the current tree pointer, *WALK_SUBTREES is set to 0 by this function if + recursing into TP's subtrees is unnecessary. *DATA is a bool variable that + is set to false if an error has occured. */ + +static tree +cpp_validate_cilk_plus_loop_aux (tree *tp, int *walk_subtrees, void *data) +{ + bool *valid = (bool *) data; + location_t loc = EXPR_HAS_LOCATION (*tp) ? EXPR_LOCATION (*tp) : + UNKNOWN_LOCATION; + + if (!tp || !*tp) + return NULL_TREE; + + if (TREE_CODE (*tp) == THROW_EXPR) + { + error_at (loc, "throw expressions are not allowed inside loops " + "marked with pragma simd"); + *walk_subtrees = 0; + *valid = false; + } + else if (TREE_CODE (*tp) == TRY_BLOCK) + { + error_at (loc, "try statements are not allowed inside loops marked " + "with #pragma simd"); + *valid = false; + *walk_subtrees = 0; + } + return NULL_TREE; +} + + +/* Walks through all the subtrees of BODY using walk_tree to make sure + invalid statements/expressions are not found inside BODY. Returns + false if any invalid statements are found. */ + +bool +cpp_validate_cilk_plus_loop (tree body) +{ + bool valid = true; + cp_walk_tree (&body, cpp_validate_cilk_plus_loop_aux, + (void *) &valid, NULL); + return valid; +} diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index 38ef87868a8f6..52ce57baa000b 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -669,6 +669,9 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) gcc_unreachable (); case OMP_FOR: + case OMP_SIMD: + case CILK_SIMD: + case OMP_DISTRIBUTE: ret = cp_gimplify_omp_for (expr_p, pre_p); break; @@ -1116,7 +1119,10 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) genericize_continue_stmt (stmt_p); else if (TREE_CODE (stmt) == BREAK_STMT) genericize_break_stmt (stmt_p); - else if (TREE_CODE (stmt) == OMP_FOR) + else if (TREE_CODE (stmt) == OMP_FOR + || TREE_CODE (stmt) == OMP_SIMD + || TREE_CODE (stmt) == CILK_SIMD + || TREE_CODE (stmt) == OMP_DISTRIBUTE) genericize_omp_for_stmt (stmt_p, walk_subtrees, data); else if (TREE_CODE (stmt) == SIZEOF_EXPR) { diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 4b2cd512f1c6c..a10b2a6db8dcb 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -60,7 +60,7 @@ c-common.h, not after. STMT_EXPR_NO_SCOPE (in STMT_EXPR) BIND_EXPR_TRY_BLOCK (in BIND_EXPR) TYPENAME_IS_ENUM_P (in TYPENAME_TYPE) - OMP_FOR_GIMPLIFYING_P (in OMP_FOR) + OMP_FOR_GIMPLIFYING_P (in OMP_FOR, OMP_SIMD and OMP_DISTRIBUTE) BASELINK_QUALIFIED_P (in BASELINK) TARGET_EXPR_IMPLICIT_P (in TARGET_EXPR) TEMPLATE_PARM_PARAMETER_PACK (in TEMPLATE_PARM_INDEX) @@ -4017,14 +4017,14 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) /* Used while gimplifying continue statements bound to OMP_FOR nodes. */ #define OMP_FOR_GIMPLIFYING_P(NODE) \ - (TREE_LANG_FLAG_0 (OMP_FOR_CHECK (NODE))) + (TREE_LANG_FLAG_0 (OMP_LOOP_CHECK (NODE))) /* A language-specific token attached to the OpenMP data clauses to hold code (or code fragments) related to ctors, dtors, and op=. See semantics.c for details. */ #define CP_OMP_CLAUSE_INFO(NODE) \ TREE_TYPE (OMP_CLAUSE_RANGE_CHECK (NODE, OMP_CLAUSE_PRIVATE, \ - OMP_CLAUSE_COPYPRIVATE)) + OMP_CLAUSE_LINEAR)) /* Nonzero if this transaction expression's body contains statements. */ #define TRANSACTION_EXPR_IS_STMT(NODE) \ @@ -4433,6 +4433,10 @@ extern GTY(()) vec *local_classes; extern int at_eof; +/* If non-zero, implicit "omp declare target" attribute is added into the + attribute lists. */ +extern GTY(()) int current_omp_declare_target_attribute; + /* A list of namespace-scope objects which have constructors or destructors which reside in the global scope. The decl is stored in the TREE_VALUE slot and the initializer is stored in the @@ -4795,6 +4799,10 @@ typedef struct cp_decl_specifier_seq { /* If non-NULL, a built-in type that the user attempted to redefine to some other type. */ tree redefined_builtin_type; + /* When parsing #pragma omp declare simd, this is a vector of + the clauses, each tree is either NULL_TREE, or OMP_CLAUSE + with optional chain of other clauses. */ + vec *omp_declare_simd_clauses; /* The storage class specified -- or sc_none if no storage class was explicitly specified. */ cp_storage_class storage_class; @@ -5297,6 +5305,7 @@ extern void note_vague_linkage_fn (tree); extern tree build_artificial_parm (tree, tree); extern bool possibly_inlined_p (tree); extern int parm_index (tree); +extern bool cp_omp_mappable_type (tree); /* in error.c */ extern void init_error (void); @@ -5769,6 +5778,7 @@ extern void simplify_aggr_init_expr (tree *); extern void finalize_nrv (tree *, tree, tree); extern void note_decl_for_pch (tree); extern tree finish_omp_clauses (tree); +extern void finish_omp_declare_simd (tree, vec *); extern void finish_omp_threadprivate (tree); extern tree begin_omp_structured_block (void); extern tree finish_omp_structured_block (tree); @@ -5776,17 +5786,23 @@ extern tree begin_omp_parallel (void); extern tree finish_omp_parallel (tree, tree); extern tree begin_omp_task (void); extern tree finish_omp_task (tree, tree); -extern tree finish_omp_for (location_t, tree, tree, - tree, tree, tree, tree, tree); +extern tree finish_omp_for (location_t, enum tree_code, + tree, tree, tree, tree, tree, + tree, tree); extern void finish_omp_atomic (enum tree_code, enum tree_code, - tree, tree, tree, tree, tree); + tree, tree, tree, tree, tree, + bool); extern void finish_omp_barrier (void); extern void finish_omp_flush (void); extern void finish_omp_taskwait (void); +extern void finish_omp_taskyield (void); +extern void finish_omp_taskgroup (tree); +extern void finish_omp_cancel (tree); +extern void finish_omp_cancellation_point (tree); +extern tree finish_cilk_for_cond (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 void finish_omp_taskyield (void); extern bool cxx_omp_create_clause_info (tree, tree, bool, bool, bool); extern tree baselink_for_fns (tree); extern void finish_static_assert (tree, tree, location_t, @@ -6141,6 +6157,9 @@ extern bool cxx_omp_privatize_by_reference (const_tree); extern void suggest_alternatives_for (location_t, tree); extern tree strip_using_decl (tree); +/* In cp-cilkplus.c. */ +extern bool cpp_validate_cilk_plus_loop (tree); + /* In cp/cp-array-notations.c */ extern tree expand_array_notation_exprs (tree); bool cilkplus_an_triplet_types_ok_p (location_t, tree, tree, tree, diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 047fd77fd74ab..ec1cde4aa657c 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -7337,7 +7337,8 @@ grokfndecl (tree ctype, int template_count, tree in_namespace, tree* attrlist, - location_t location) + location_t location, + vec *omp_declare_simd_clauses) { tree decl; int staticp = ctype && TREE_CODE (type) == FUNCTION_TYPE; @@ -7626,6 +7627,9 @@ grokfndecl (tree ctype, if (TYPE_NOTHROW_P (type) || nothrow_libfn_p (decl)) TREE_NOTHROW (decl) = 1; + if (omp_declare_simd_clauses) + finish_omp_declare_simd (decl, omp_declare_simd_clauses); + /* Caller will do the rest of this. */ if (check < 0) return decl; @@ -10490,7 +10494,8 @@ grokdeclarator (const cp_declarator *declarator, inlinep | (2 * constexpr_p), sfk, funcdef_flag, template_count, in_namespace, - attrlist, declarator->id_loc); + attrlist, declarator->id_loc, + declspecs->omp_declare_simd_clauses); decl = set_virt_specifiers (decl, virt_specifiers); if (decl == NULL_TREE) return error_mark_node; @@ -10703,7 +10708,8 @@ grokdeclarator (const cp_declarator *declarator, publicp, inlinep | (2 * constexpr_p), sfk, funcdef_flag, template_count, in_namespace, attrlist, - declarator->id_loc); + declarator->id_loc, + declspecs->omp_declare_simd_clauses); if (decl == NULL_TREE) return error_mark_node; diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 1573cede8992a..37b20ae86237a 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -102,6 +102,9 @@ static GTY(()) vec *no_linkage_decls; int at_eof; +/* If non-zero, implicit "omp declare target" attribute is added into the + attribute lists. */ +int current_omp_declare_target_attribute; /* Return a member function type (a METHOD_TYPE), given FNTYPE (a @@ -1139,6 +1142,11 @@ is_late_template_attribute (tree attr, tree decl) if (is_attribute_p ("unused", name)) return false; + /* #pragma omp declare simd attribute needs to be always finalized. */ + if (flag_openmp + && is_attribute_p ("omp declare simd", name)) + return true; + /* If any of the arguments are dependent expressions, we can't evaluate the attribute until instantiation time. */ for (arg = args; arg; arg = TREE_CHAIN (arg)) @@ -1326,6 +1334,9 @@ cp_check_const_attributes (tree attributes) for (attr = attributes; attr; attr = TREE_CHAIN (attr)) { tree arg; + if (TREE_VALUE (attr) == NULL_TREE + || TREE_CODE (TREE_VALUE (attr)) != TREE_LIST) + continue; for (arg = TREE_VALUE (attr); arg; arg = TREE_CHAIN (arg)) { tree expr = TREE_VALUE (arg); @@ -1335,6 +1346,34 @@ cp_check_const_attributes (tree attributes) } } +/* Return true if TYPE is an OpenMP mappable type. */ +bool +cp_omp_mappable_type (tree type) +{ + /* Mappable type has to be complete. */ + if (type == error_mark_node || !COMPLETE_TYPE_P (type)) + return false; + /* Arrays have mappable type if the elements have mappable type. */ + while (TREE_CODE (type) == ARRAY_TYPE) + type = TREE_TYPE (type); + /* A mappable type cannot contain virtual members. */ + if (CLASS_TYPE_P (type) && CLASSTYPE_VTABLES (type)) + return false; + /* All data members must be non-static. */ + if (CLASS_TYPE_P (type)) + { + tree field; + for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) + if (TREE_CODE (field) == VAR_DECL) + return false; + /* All fields must have mappable types. */ + else if (TREE_CODE (field) == FIELD_DECL + && !cp_omp_mappable_type (TREE_TYPE (field))) + return false; + } + return true; +} + /* Like decl_attributes, but handle C++ complexity. */ void @@ -1344,6 +1383,30 @@ cplus_decl_attributes (tree *decl, tree attributes, int flags) || *decl == error_mark_node) return; + /* Add implicit "omp declare target" attribute if requested. */ + if (current_omp_declare_target_attribute + && ((TREE_CODE (*decl) == VAR_DECL && TREE_STATIC (*decl)) + || TREE_CODE (*decl) == FUNCTION_DECL)) + { + if (TREE_CODE (*decl) == VAR_DECL + && RECORD_OR_UNION_CODE_P (TREE_CODE (CP_DECL_CONTEXT (*decl)))) + error ("%q+D static data member inside of declare target directive", + *decl); + else if (TREE_CODE (*decl) == VAR_DECL + && (TREE_CODE (CP_DECL_CONTEXT (*decl)) == FUNCTION_DECL + || (current_function_decl && !DECL_EXTERNAL (*decl)))) + error ("%q+D in block scope inside of declare target directive", + *decl); + else if (!processing_template_decl + && TREE_CODE (*decl) == VAR_DECL + && !cp_omp_mappable_type (TREE_TYPE (*decl))) + error ("%q+D in declare target directive does not have mappable type", + *decl); + else + attributes = tree_cons (get_identifier ("omp declare target"), + NULL_TREE, attributes); + } + if (processing_template_decl) { if (check_for_bare_parameter_packs (attributes)) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index c6ecf69e50e98..cf4cb4206f24c 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -231,6 +231,11 @@ static void cp_parser_initial_pragma static tree cp_literal_operator_id (const char *); +static void cp_parser_cilk_simd_construct + (cp_parser *, cp_token *); +static tree cp_parser_cilk_for + (cp_parser *, enum rid, tree); + /* Manifest constants. */ #define CP_LEXER_BUFFER_SIZE ((256 * 1024) / sizeof (cp_token)) #define CP_SAVED_TOKEN_STACK 5 @@ -1221,6 +1226,43 @@ cp_token_cache_new (cp_token *first, cp_token *last) return cache; } +/* Diagnose if #pragma omp declare simd isn't followed immediately + by function declaration or definition. */ + +static inline void +cp_ensure_no_omp_declare_simd (cp_parser *parser) +{ + if (parser->omp_declare_simd_clauses + && (*parser->omp_declare_simd_clauses)[0] != error_mark_node) + { + error ("%<#pragma omp declare simd%> not immediately followed by " + "function declaration or definition"); + parser->omp_declare_simd_clauses = NULL; + } +} + +/* Finalize #pragma omp declare simd clauses after FNDECL has been parsed, + and put that into "omp declare simd" attribute. */ + +static inline void +cp_finish_omp_declare_simd (cp_parser *parser, + cp_decl_specifier_seq *declspecs, tree fndecl) +{ + if (__builtin_expect (parser->omp_declare_simd_clauses != NULL, 0)) + { + if (fndecl == error_mark_node) + { + parser->omp_declare_simd_clauses = NULL; + return; + } + if (TREE_CODE (fndecl) != FUNCTION_DECL) + { + cp_ensure_no_omp_declare_simd (parser); + return; + } + } + declspecs->omp_declare_simd_clauses = NULL; +} /* Decl-specifiers. */ @@ -2205,7 +2247,13 @@ static bool cp_parser_function_transaction static tree cp_parser_transaction_cancel (cp_parser *); -enum pragma_context { pragma_external, pragma_stmt, pragma_compound }; +enum pragma_context { + pragma_external, + pragma_member, + pragma_objc_icode, + pragma_stmt, + pragma_compound +}; static bool cp_parser_pragma (cp_parser *, enum pragma_context); @@ -7885,9 +7933,11 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p, */ if (no_toplevel_fold_p && lookahead_prec <= current.prec - && sp == stack - && TREE_CODE_CLASS (current.tree_type) == tcc_comparison) - current.lhs = build2 (current.tree_type, boolean_type_node, + && sp == stack) + current.lhs = build2 (current.tree_type, + TREE_CODE_CLASS (current.tree_type) + == tcc_comparison + ? boolean_type_node : TREE_TYPE (current.lhs), current.lhs, rhs); else current.lhs = build_x_binary_op (current.loc, current.tree_type, @@ -10504,6 +10554,10 @@ cp_parser_jump_statement (cp_parser* parser) case IN_OMP_FOR: error_at (token->location, "break statement used with OpenMP for loop"); break; + case IN_CILK_P_SIMD_FOR: + error_at (token->location, + "break statement within <#pragma simd> loop body"); + break; } cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); break; @@ -10521,6 +10575,10 @@ cp_parser_jump_statement (cp_parser* parser) case IN_OMP_BLOCK: error_at (token->location, "invalid exit from OpenMP structured block"); break; + case IN_CILK_P_SIMD_FOR: + error_at (token->location, + "continue statement within <#pragma simd> loop loop"); + break; default: gcc_unreachable (); } @@ -11584,6 +11642,8 @@ cp_parser_linkage_specification (cp_parser* parser) production. */ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) { + cp_ensure_no_omp_declare_simd (parser); + /* Consume the `{' token. */ cp_lexer_consume_token (parser->lexer); /* Parse the declarations. */ @@ -15527,6 +15587,7 @@ cp_parser_namespace_definition (cp_parser* parser) bool has_visibility; bool is_inline; + cp_ensure_no_omp_declare_simd (parser); if (cp_lexer_next_token_is_keyword (parser->lexer, RID_INLINE)) { maybe_warn_cpp0x (CPP0X_INLINE_NAMESPACES); @@ -16456,10 +16517,12 @@ cp_parser_init_declarator (cp_parser* parser, { if (parser->in_unbraced_linkage_specification_p) decl_specifiers->storage_class = sc_extern; + decl_specifiers->omp_declare_simd_clauses + = parser->omp_declare_simd_clauses; decl = start_decl (declarator, decl_specifiers, range_for_decl_p? SD_INITIALIZED : is_initialized, - attributes, prefix_attributes, - &pushed_scope); + attributes, prefix_attributes, &pushed_scope); + cp_finish_omp_declare_simd (parser, decl_specifiers, decl); /* Adjust location of decl if declarator->id_loc is more appropriate: set, and decl wasn't merged with another decl, in which case its location would be different from input_location, and more accurate. */ @@ -16563,12 +16626,14 @@ cp_parser_init_declarator (cp_parser* parser, pop_scope (pushed_scope); pushed_scope = NULL_TREE; } + decl_specifiers->omp_declare_simd_clauses + = parser->omp_declare_simd_clauses; decl = grokfield (declarator, decl_specifiers, initializer, !is_non_constant_init, - /*asmspec=*/NULL_TREE, - prefix_attributes); + /*asmspec=*/NULL_TREE, prefix_attributes); if (decl && TREE_CODE (decl) == FUNCTION_DECL) cp_parser_save_default_args (parser, decl); + cp_finish_omp_declare_simd (parser, decl_specifiers, decl); } /* Finish processing the declaration. But, skip member @@ -18869,6 +18934,8 @@ cp_parser_class_specifier_1 (cp_parser* parser) return error_mark_node; } + cp_ensure_no_omp_declare_simd (parser); + /* Issue an error message if type-definitions are forbidden here. */ cp_parser_check_type_definition (parser); /* Remember that we are defining one more class. */ @@ -19644,7 +19711,7 @@ cp_parser_member_specification_opt (cp_parser* parser) /* Accept #pragmas at class scope. */ if (token->type == CPP_PRAGMA) { - cp_parser_pragma (parser, pragma_external); + cp_parser_pragma (parser, pragma_member); break; } @@ -20096,13 +20163,16 @@ cp_parser_member_declaration (cp_parser* parser) else if (declarator->kind == cdk_function) declarator->id_loc = token->location; - /* Create the declaration. */ - decl = grokfield (declarator, &decl_specifiers, - initializer, /*init_const_expr_p=*/true, - asm_specification, - attributes); + /* Create the declaration. */ + decl_specifiers.omp_declare_simd_clauses + = parser->omp_declare_simd_clauses; + decl = grokfield (declarator, &decl_specifiers, + initializer, /*init_const_expr_p=*/true, + asm_specification, attributes); } + cp_finish_omp_declare_simd (parser, &decl_specifiers, decl); + /* Reset PREFIX_ATTRIBUTES. */ while (attributes && TREE_CHAIN (attributes) != first_attribute) attributes = TREE_CHAIN (attributes); @@ -22236,6 +22306,8 @@ cp_parser_function_definition_from_specifiers_and_declarator bool success_p; /* Begin the function-definition. */ + decl_specifiers->omp_declare_simd_clauses + = parser->omp_declare_simd_clauses; success_p = start_function (decl_specifiers, declarator, attributes); /* The things we're about to see are not directly qualified by any @@ -22248,9 +22320,17 @@ cp_parser_function_definition_from_specifiers_and_declarator might be a friend. */ perform_deferred_access_checks (tf_warning_or_error); + if (success_p) + { + cp_finish_omp_declare_simd (parser, decl_specifiers, + current_function_decl); + parser->omp_declare_simd_clauses = NULL; + } + if (!success_p) { /* Skip the entire function. */ + decl_specifiers->omp_declare_simd_clauses = NULL; cp_parser_skip_to_end_of_block_or_statement (parser); fn = error_mark_node; } @@ -22781,7 +22861,10 @@ cp_parser_save_member_function_body (cp_parser* parser, tree fn; /* Create the FUNCTION_DECL. */ + decl_specifiers->omp_declare_simd_clauses + = parser->omp_declare_simd_clauses; fn = grokmethod (decl_specifiers, declarator, attributes); + cp_finish_omp_declare_simd (parser, decl_specifiers, fn); /* If something went badly wrong, bail out now. */ if (fn == error_mark_node) { @@ -25177,7 +25260,7 @@ cp_parser_objc_interstitial_code (cp_parser* parser) cp_parser_linkage_specification (parser); /* Handle #pragma, if any. */ else if (token->type == CPP_PRAGMA) - cp_parser_pragma (parser, pragma_external); + cp_parser_pragma (parser, pragma_objc_icode); /* Allow stray semicolons. */ else if (token->type == CPP_SEMICOLON) cp_lexer_consume_token (parser->lexer); @@ -26342,7 +26425,7 @@ cp_parser_objc_at_dynamic_declaration (cp_parser *parser) } -/* OpenMP 2.5 parsing routines. */ +/* OpenMP 2.5 / 3.0 / 3.1 / 4.0 parsing routines. */ /* Returns name of the next clause. If the clause is not recognized PRAGMA_OMP_CLAUSE_NONE is returned and @@ -26360,6 +26443,8 @@ cp_parser_omp_clause_name (cp_parser *parser) result = PRAGMA_OMP_CLAUSE_DEFAULT; else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_PRIVATE)) result = PRAGMA_OMP_CLAUSE_PRIVATE; + else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR)) + result = PRAGMA_OMP_CLAUSE_FOR; else if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { tree id = cp_lexer_peek_token (parser->lexer)->u.value; @@ -26367,6 +26452,10 @@ cp_parser_omp_clause_name (cp_parser *parser) switch (p[0]) { + case 'a': + if (!strcmp ("aligned", p)) + result = PRAGMA_OMP_CLAUSE_ALIGNED; + break; case 'c': if (!strcmp ("collapse", p)) result = PRAGMA_OMP_CLAUSE_COLLAPSE; @@ -26375,23 +26464,45 @@ cp_parser_omp_clause_name (cp_parser *parser) else if (!strcmp ("copyprivate", p)) result = PRAGMA_OMP_CLAUSE_COPYPRIVATE; break; + case 'd': + if (!strcmp ("depend", p)) + result = PRAGMA_OMP_CLAUSE_DEPEND; + else if (!strcmp ("device", p)) + result = PRAGMA_OMP_CLAUSE_DEVICE; + else if (!strcmp ("dist_schedule", p)) + result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE; + break; case 'f': if (!strcmp ("final", p)) result = PRAGMA_OMP_CLAUSE_FINAL; else if (!strcmp ("firstprivate", p)) result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE; + else if (!strcmp ("from", p)) + result = PRAGMA_OMP_CLAUSE_FROM; + break; + case 'i': + if (!strcmp ("inbranch", p)) + result = PRAGMA_OMP_CLAUSE_INBRANCH; break; case 'l': if (!strcmp ("lastprivate", p)) result = PRAGMA_OMP_CLAUSE_LASTPRIVATE; + else if (!strcmp ("linear", p)) + result = PRAGMA_OMP_CLAUSE_LINEAR; break; case 'm': - if (!strcmp ("mergeable", p)) + if (!strcmp ("map", p)) + result = PRAGMA_OMP_CLAUSE_MAP; + else if (!strcmp ("mergeable", p)) result = PRAGMA_OMP_CLAUSE_MERGEABLE; break; case 'n': - if (!strcmp ("nowait", p)) + if (!strcmp ("notinbranch", p)) + result = PRAGMA_OMP_CLAUSE_NOTINBRANCH; + else if (!strcmp ("nowait", p)) result = PRAGMA_OMP_CLAUSE_NOWAIT; + else if (!strcmp ("num_teams", p)) + result = PRAGMA_OMP_CLAUSE_NUM_TEAMS; else if (!strcmp ("num_threads", p)) result = PRAGMA_OMP_CLAUSE_NUM_THREADS; break; @@ -26399,18 +26510,40 @@ cp_parser_omp_clause_name (cp_parser *parser) if (!strcmp ("ordered", p)) result = PRAGMA_OMP_CLAUSE_ORDERED; break; + case 'p': + if (!strcmp ("parallel", p)) + result = PRAGMA_OMP_CLAUSE_PARALLEL; + else if (!strcmp ("proc_bind", p)) + result = PRAGMA_OMP_CLAUSE_PROC_BIND; + break; case 'r': if (!strcmp ("reduction", p)) result = PRAGMA_OMP_CLAUSE_REDUCTION; break; case 's': - if (!strcmp ("schedule", p)) + if (!strcmp ("safelen", p)) + result = PRAGMA_OMP_CLAUSE_SAFELEN; + else if (!strcmp ("schedule", p)) result = PRAGMA_OMP_CLAUSE_SCHEDULE; + else if (!strcmp ("sections", p)) + result = PRAGMA_OMP_CLAUSE_SECTIONS; else if (!strcmp ("shared", p)) result = PRAGMA_OMP_CLAUSE_SHARED; + else if (!strcmp ("simdlen", p)) + result = PRAGMA_OMP_CLAUSE_SIMDLEN; + break; + case 't': + if (!strcmp ("taskgroup", p)) + result = PRAGMA_OMP_CLAUSE_TASKGROUP; + else if (!strcmp ("thread_limit", p)) + result = PRAGMA_OMP_CLAUSE_THREAD_LIMIT; + else if (!strcmp ("to", p)) + result = PRAGMA_OMP_CLAUSE_TO; break; case 'u': - if (!strcmp ("untied", p)) + if (!strcmp ("uniform", p)) + result = PRAGMA_OMP_CLAUSE_UNIFORM; + else if (!strcmp ("untied", p)) result = PRAGMA_OMP_CLAUSE_UNTIED; break; } @@ -26443,39 +26576,96 @@ check_no_duplicate_clause (tree clauses, enum omp_clause_code code, identifier variable-list , identifier - In addition, we match a closing parenthesis. An opening parenthesis - will have been consumed by the caller. + In addition, we match a closing parenthesis (or, if COLON is non-NULL, + colon). An opening parenthesis will have been consumed by the caller. If KIND is nonzero, create the appropriate node and install the decl in OMP_CLAUSE_DECL and add the node to the head of the list. If KIND is zero, create a TREE_LIST with the decl in TREE_PURPOSE; - return the list created. */ + return the list created. + + COLON can be NULL if only closing parenthesis should end the list, + or pointer to bool which will receive false if the list is terminated + by closing parenthesis or true if the list is terminated by colon. */ static tree cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, - tree list) + tree list, bool *colon) { cp_token *token; + bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p; + if (colon) + { + parser->colon_corrects_to_scope_p = false; + *colon = false; + } while (1) { 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 (parser->omp_declare_simd_clauses) + decl = name = cp_parser_identifier (parser); + 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); else if (kind != 0) { + switch (kind) + { + case OMP_CLAUSE_MAP: + case OMP_CLAUSE_FROM: + case OMP_CLAUSE_TO: + case OMP_CLAUSE_DEPEND: + while (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE)) + { + tree low_bound = NULL_TREE, length = NULL_TREE; + + parser->colon_corrects_to_scope_p = false; + cp_lexer_consume_token (parser->lexer); + if (!cp_lexer_next_token_is (parser->lexer, CPP_COLON)) + low_bound = cp_parser_expression (parser, /*cast_p=*/false, + NULL); + if (!colon) + parser->colon_corrects_to_scope_p + = saved_colon_corrects_to_scope_p; + if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SQUARE)) + length = integer_one_node; + else + { + /* Look for `:'. */ + if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) + goto skip_comma; + if (!cp_lexer_next_token_is (parser->lexer, + CPP_CLOSE_SQUARE)) + length = cp_parser_expression (parser, + /*cast_p=*/false, + NULL); + } + /* Look for the closing `]'. */ + if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, + RT_CLOSE_SQUARE)) + goto skip_comma; + decl = tree_cons (low_bound, length, decl); + } + break; + default: + break; + } + tree u = build_omp_clause (token->location, kind); OMP_CLAUSE_DECL (u) = decl; OMP_CLAUSE_CHAIN (u) = list; @@ -26490,6 +26680,16 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, cp_lexer_consume_token (parser->lexer); } + if (colon) + parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; + + if (colon != NULL && cp_lexer_next_token_is (parser->lexer, CPP_COLON)) + { + *colon = true; + cp_parser_require (parser, CPP_COLON, RT_COLON); + return list; + } + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) { int ending; @@ -26497,6 +26697,8 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, /* Try to resync to an unnested comma. Copied from cp_parser_parenthesized_expression_list. */ skip_comma: + if (colon) + parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; ending = cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/true, @@ -26515,7 +26717,7 @@ static tree cp_parser_omp_var_list (cp_parser *parser, enum omp_clause_code kind, tree list) { if (cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) - return cp_parser_omp_var_list_no_open (parser, kind, list); + return cp_parser_omp_var_list_no_open (parser, kind, list, NULL); return list; } @@ -26831,7 +27033,8 @@ cp_parser_omp_clause_reduction (cp_parser *parser, tree list) if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) goto resync_fail; - nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_REDUCTION, list); + nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_REDUCTION, list, + NULL); for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) OMP_CLAUSE_REDUCTION_CODE (c) = code; @@ -26946,188 +27149,756 @@ cp_parser_omp_clause_untied (cp_parser * /*parser*/, return c; } -/* Parse all OpenMP clauses. The set clauses allowed by the directive - is a bitmask in MASK. Return the list of clauses found; the result - of clause default goes in *pdefault. */ +/* OpenMP 4.0: + inbranch + notinbranch */ static tree -cp_parser_omp_all_clauses (cp_parser *parser, unsigned int mask, - const char *where, cp_token *pragma_tok) +cp_parser_omp_clause_branch (cp_parser * /*parser*/, enum omp_clause_code code, + tree list, location_t location) { - tree clauses = NULL; - bool first = true; - cp_token *token = NULL; + 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; +} - while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) - { - pragma_omp_clause c_kind; - const char *c_name; - tree prev = clauses; +/* OpenMP 4.0: + parallel + for + sections + taskgroup */ - if (!first && cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) - cp_lexer_consume_token (parser->lexer); +static tree +cp_parser_omp_clause_cancelkind (cp_parser * /*parser*/, + enum omp_clause_code code, + tree list, location_t location) +{ + tree c = build_omp_clause (location, code); + OMP_CLAUSE_CHAIN (c) = list; + return c; +} - token = cp_lexer_peek_token (parser->lexer); - c_kind = cp_parser_omp_clause_name (parser); - first = false; +/* OpenMP 4.0: + num_teams ( expression ) */ - switch (c_kind) - { - case PRAGMA_OMP_CLAUSE_COLLAPSE: - clauses = cp_parser_omp_clause_collapse (parser, clauses, - token->location); - c_name = "collapse"; - break; - case PRAGMA_OMP_CLAUSE_COPYIN: - clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_COPYIN, clauses); - c_name = "copyin"; - break; - case PRAGMA_OMP_CLAUSE_COPYPRIVATE: - clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_COPYPRIVATE, - clauses); - c_name = "copyprivate"; - break; - case PRAGMA_OMP_CLAUSE_DEFAULT: - clauses = cp_parser_omp_clause_default (parser, clauses, - token->location); - c_name = "default"; - break; - case PRAGMA_OMP_CLAUSE_FINAL: - clauses = cp_parser_omp_clause_final (parser, clauses, token->location); - c_name = "final"; - break; - case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE: - clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FIRSTPRIVATE, - clauses); - c_name = "firstprivate"; - break; - case PRAGMA_OMP_CLAUSE_IF: - clauses = cp_parser_omp_clause_if (parser, clauses, token->location); - c_name = "if"; - break; - case PRAGMA_OMP_CLAUSE_LASTPRIVATE: - clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_LASTPRIVATE, - clauses); - c_name = "lastprivate"; - break; - case PRAGMA_OMP_CLAUSE_MERGEABLE: - clauses = cp_parser_omp_clause_mergeable (parser, clauses, - token->location); - c_name = "mergeable"; - break; - case PRAGMA_OMP_CLAUSE_NOWAIT: - clauses = cp_parser_omp_clause_nowait (parser, clauses, token->location); - c_name = "nowait"; - break; - case PRAGMA_OMP_CLAUSE_NUM_THREADS: - clauses = cp_parser_omp_clause_num_threads (parser, clauses, - token->location); - c_name = "num_threads"; - break; - case PRAGMA_OMP_CLAUSE_ORDERED: - clauses = cp_parser_omp_clause_ordered (parser, clauses, - token->location); - c_name = "ordered"; - break; - case PRAGMA_OMP_CLAUSE_PRIVATE: - clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_PRIVATE, - clauses); - c_name = "private"; - break; - case PRAGMA_OMP_CLAUSE_REDUCTION: - clauses = cp_parser_omp_clause_reduction (parser, clauses); - c_name = "reduction"; - break; - case PRAGMA_OMP_CLAUSE_SCHEDULE: - clauses = cp_parser_omp_clause_schedule (parser, clauses, - token->location); - c_name = "schedule"; - break; - case PRAGMA_OMP_CLAUSE_SHARED: - clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_SHARED, - clauses); - c_name = "shared"; - break; - case PRAGMA_OMP_CLAUSE_UNTIED: - clauses = cp_parser_omp_clause_untied (parser, clauses, - token->location); - c_name = "nowait"; - break; - default: - cp_parser_error (parser, "expected %<#pragma omp%> clause"); - goto saw_error; - } +static tree +cp_parser_omp_clause_num_teams (cp_parser *parser, tree list, + location_t location) +{ + tree t, c; - if (((mask >> c_kind) & 1) == 0) - { - /* Remove the invalid clause(s) from the list to avoid - confusing the rest of the compiler. */ - clauses = prev; - error_at (token->location, "%qs is not valid for %qs", c_name, where); - } - } - saw_error: - cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return finish_omp_clauses (clauses); -} + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; -/* OpenMP 2.5: - structured-block: - statement + t = cp_parser_expression (parser, false, NULL); - In practice, we're also interested in adding the statement to an - outer node. So it is convenient if we work around the fact that - cp_parser_statement calls add_stmt. */ + 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); -static unsigned -cp_parser_begin_omp_structured_block (cp_parser *parser) -{ - unsigned save = parser->in_statement; + check_no_duplicate_clause (list, OMP_CLAUSE_NUM_TEAMS, + "num_teams", location); - /* Only move the values to IN_OMP_BLOCK if they weren't false. - This preserves the "not within loop or switch" style error messages - for nonsense cases like - void foo() { - #pragma omp single - break; - } - */ - if (parser->in_statement) - parser->in_statement = IN_OMP_BLOCK; + c = build_omp_clause (location, OMP_CLAUSE_NUM_TEAMS); + OMP_CLAUSE_NUM_TEAMS_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; - return save; + return c; } -static void -cp_parser_end_omp_structured_block (cp_parser *parser, unsigned save) -{ - parser->in_statement = save; -} +/* OpenMP 4.0: + thread_limit ( expression ) */ static tree -cp_parser_omp_structured_block (cp_parser *parser) +cp_parser_omp_clause_thread_limit (cp_parser *parser, tree list, + location_t location) { - tree stmt = begin_omp_structured_block (); - unsigned int save = cp_parser_begin_omp_structured_block (parser); + tree t, c; - cp_parser_statement (parser, NULL_TREE, false, NULL); + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; - cp_parser_end_omp_structured_block (parser, save); - return finish_omp_structured_block (stmt); -} + t = cp_parser_expression (parser, false, NULL); -/* OpenMP 2.5: - # pragma omp atomic new-line - expression-stmt + 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); - expression-stmt: - x binop= expr | x++ | ++x | x-- | --x - binop: - +, *, -, /, &, ^, |, <<, >> + check_no_duplicate_clause (list, OMP_CLAUSE_THREAD_LIMIT, + "thread_limit", location); - where x is an lvalue expression with scalar type. + c = build_omp_clause (location, OMP_CLAUSE_THREAD_LIMIT); + OMP_CLAUSE_THREAD_LIMIT_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; - OpenMP 3.1: + return c; +} + +/* OpenMP 4.0: + aligned ( variable-list ) + aligned ( variable-list : constant-expression ) */ + +static tree +cp_parser_omp_clause_aligned (cp_parser *parser, tree list) +{ + tree nlist, c, alignment = NULL_TREE; + bool colon; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_ALIGNED, list, + &colon); + + if (colon) + { + alignment = cp_parser_constant_expression (parser, false, NULL); + + 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 (alignment == error_mark_node) + alignment = NULL_TREE; + } + + for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_ALIGNED_ALIGNMENT (c) = alignment; + + return nlist; +} + +/* OpenMP 4.0: + linear ( variable-list ) + linear ( variable-list : expression ) */ + +static tree +cp_parser_omp_clause_linear (cp_parser *parser, tree list) +{ + tree nlist, c, step = integer_one_node; + bool colon; + + 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 (colon) + { + step = cp_parser_expression (parser, false, NULL); + + 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 (step == error_mark_node) + return list; + } + + for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_LINEAR_STEP (c) = step; + + return nlist; +} + +/* OpenMP 4.0: + safelen ( constant-expression ) */ + +static tree +cp_parser_omp_clause_safelen (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_constant_expression (parser, false, NULL); + + 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_SAFELEN, "safelen", location); + + c = build_omp_clause (location, OMP_CLAUSE_SAFELEN); + OMP_CLAUSE_SAFELEN_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 4.0: + simdlen ( constant-expression ) */ + +static tree +cp_parser_omp_clause_simdlen (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_constant_expression (parser, false, NULL); + + 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_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.0: + depend ( depend-kind : variable-list ) + + depend-kind: + in | out | inout */ + +static tree +cp_parser_omp_clause_depend (cp_parser *parser, tree list) +{ + tree nlist, c; + enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_INOUT; + + 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 ("in", p) == 0) + kind = OMP_CLAUSE_DEPEND_IN; + else if (strcmp ("inout", p) == 0) + kind = OMP_CLAUSE_DEPEND_INOUT; + else if (strcmp ("out", p) == 0) + kind = OMP_CLAUSE_DEPEND_OUT; + else + goto invalid_kind; + } + else + goto invalid_kind; + + cp_lexer_consume_token (parser->lexer); + 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; + + return nlist; + + invalid_kind: + cp_parser_error (parser, "invalid depend kind"); + resync_fail: + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; +} + +/* OpenMP 4.0: + map ( map-kind : variable-list ) + map ( variable-list ) + + map-kind: + alloc | to | from | tofrom */ + +static tree +cp_parser_omp_clause_map (cp_parser *parser, tree list) +{ + tree nlist, c; + enum omp_clause_map_kind kind = OMP_CLAUSE_MAP_TOFROM; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME) + && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_COLON) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + + if (strcmp ("alloc", p) == 0) + kind = OMP_CLAUSE_MAP_ALLOC; + else if (strcmp ("to", p) == 0) + kind = OMP_CLAUSE_MAP_TO; + else if (strcmp ("from", p) == 0) + kind = OMP_CLAUSE_MAP_FROM; + else if (strcmp ("tofrom", p) == 0) + kind = OMP_CLAUSE_MAP_TOFROM; + else + { + cp_parser_error (parser, "invalid map kind"); + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; + } + 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); + + for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_MAP_KIND (c) = kind; + + return nlist; +} + +/* OpenMP 4.0: + device ( expression ) */ + +static tree +cp_parser_omp_clause_device (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, false, NULL); + + 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_DEVICE, + "device", location); + + c = build_omp_clause (location, OMP_CLAUSE_DEVICE); + OMP_CLAUSE_DEVICE_ID (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 4.0: + dist_schedule ( static ) + dist_schedule ( static , expression ) */ + +static tree +cp_parser_omp_clause_dist_schedule (cp_parser *parser, tree list, + location_t location) +{ + tree c, t; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + c = build_omp_clause (location, OMP_CLAUSE_DIST_SCHEDULE); + + if (!cp_lexer_next_token_is_keyword (parser->lexer, RID_STATIC)) + goto invalid_kind; + cp_lexer_consume_token (parser->lexer); + + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + { + cp_lexer_consume_token (parser->lexer); + + t = cp_parser_assignment_expression (parser, false, NULL); + + if (t == error_mark_node) + goto resync_fail; + OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (c) = t; + + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + goto resync_fail; + } + else if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_COMMA_CLOSE_PAREN)) + goto resync_fail; + + check_no_duplicate_clause (list, OMP_CLAUSE_DIST_SCHEDULE, "dist_schedule", + location); + OMP_CLAUSE_CHAIN (c) = list; + return c; + + invalid_kind: + cp_parser_error (parser, "invalid dist_schedule kind"); + resync_fail: + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; +} + +/* OpenMP 4.0: + proc_bind ( proc-bind-kind ) + + proc-bind-kind: + master | close | spread */ + +static tree +cp_parser_omp_clause_proc_bind (cp_parser *parser, tree list, + location_t location) +{ + tree c; + enum omp_clause_proc_bind_kind kind; + + 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 ("master", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_MASTER; + else if (strcmp ("close", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_CLOSE; + else if (strcmp ("spread", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_SPREAD; + else + goto invalid_kind; + } + else + goto invalid_kind; + + cp_lexer_consume_token (parser->lexer); + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_COMMA_CLOSE_PAREN)) + goto resync_fail; + + c = build_omp_clause (location, OMP_CLAUSE_PROC_BIND); + check_no_duplicate_clause (list, OMP_CLAUSE_PROC_BIND, "proc_bind", + location); + OMP_CLAUSE_PROC_BIND_KIND (c) = kind; + OMP_CLAUSE_CHAIN (c) = list; + return c; + + invalid_kind: + cp_parser_error (parser, "invalid depend kind"); + resync_fail: + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; +} + +/* Parse all OpenMP clauses. The set clauses allowed by the directive + is a bitmask in MASK. Return the list of clauses found; the result + of clause default goes in *pdefault. */ + +static tree +cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, + const char *where, cp_token *pragma_tok, + bool finish_p = true) +{ + tree clauses = NULL; + bool first = true; + cp_token *token = NULL; + + while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) + { + pragma_omp_clause c_kind; + const char *c_name; + tree prev = clauses; + + if (!first && cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + cp_lexer_consume_token (parser->lexer); + + token = cp_lexer_peek_token (parser->lexer); + c_kind = cp_parser_omp_clause_name (parser); + + switch (c_kind) + { + case PRAGMA_OMP_CLAUSE_COLLAPSE: + clauses = cp_parser_omp_clause_collapse (parser, clauses, + token->location); + c_name = "collapse"; + break; + case PRAGMA_OMP_CLAUSE_COPYIN: + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_COPYIN, clauses); + c_name = "copyin"; + break; + case PRAGMA_OMP_CLAUSE_COPYPRIVATE: + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_COPYPRIVATE, + clauses); + c_name = "copyprivate"; + break; + case PRAGMA_OMP_CLAUSE_DEFAULT: + clauses = cp_parser_omp_clause_default (parser, clauses, + token->location); + c_name = "default"; + break; + case PRAGMA_OMP_CLAUSE_FINAL: + clauses = cp_parser_omp_clause_final (parser, clauses, token->location); + c_name = "final"; + break; + case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE: + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FIRSTPRIVATE, + clauses); + c_name = "firstprivate"; + break; + case PRAGMA_OMP_CLAUSE_IF: + clauses = cp_parser_omp_clause_if (parser, clauses, token->location); + c_name = "if"; + break; + case PRAGMA_OMP_CLAUSE_LASTPRIVATE: + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_LASTPRIVATE, + clauses); + c_name = "lastprivate"; + break; + case PRAGMA_OMP_CLAUSE_MERGEABLE: + clauses = cp_parser_omp_clause_mergeable (parser, clauses, + token->location); + c_name = "mergeable"; + break; + case PRAGMA_OMP_CLAUSE_NOWAIT: + clauses = cp_parser_omp_clause_nowait (parser, clauses, token->location); + c_name = "nowait"; + break; + case PRAGMA_OMP_CLAUSE_NUM_THREADS: + clauses = cp_parser_omp_clause_num_threads (parser, clauses, + token->location); + c_name = "num_threads"; + break; + case PRAGMA_OMP_CLAUSE_ORDERED: + clauses = cp_parser_omp_clause_ordered (parser, clauses, + token->location); + c_name = "ordered"; + break; + case PRAGMA_OMP_CLAUSE_PRIVATE: + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_PRIVATE, + clauses); + c_name = "private"; + break; + case PRAGMA_OMP_CLAUSE_REDUCTION: + clauses = cp_parser_omp_clause_reduction (parser, clauses); + c_name = "reduction"; + break; + case PRAGMA_OMP_CLAUSE_SCHEDULE: + clauses = cp_parser_omp_clause_schedule (parser, clauses, + token->location); + c_name = "schedule"; + break; + case PRAGMA_OMP_CLAUSE_SHARED: + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_SHARED, + clauses); + c_name = "shared"; + break; + case PRAGMA_OMP_CLAUSE_UNTIED: + clauses = cp_parser_omp_clause_untied (parser, clauses, + token->location); + c_name = "untied"; + break; + case PRAGMA_OMP_CLAUSE_INBRANCH: + clauses = cp_parser_omp_clause_branch (parser, OMP_CLAUSE_INBRANCH, + clauses, token->location); + c_name = "inbranch"; + break; + case PRAGMA_OMP_CLAUSE_NOTINBRANCH: + clauses = cp_parser_omp_clause_branch (parser, + OMP_CLAUSE_NOTINBRANCH, + clauses, token->location); + c_name = "notinbranch"; + break; + case PRAGMA_OMP_CLAUSE_PARALLEL: + clauses = cp_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_PARALLEL, + clauses, token->location); + c_name = "parallel"; + if (!first) + { + clause_not_first: + error_at (token->location, "%qs must be the first clause of %qs", + c_name, where); + clauses = prev; + } + break; + case PRAGMA_OMP_CLAUSE_FOR: + clauses = cp_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_FOR, + clauses, token->location); + c_name = "for"; + if (!first) + goto clause_not_first; + break; + case PRAGMA_OMP_CLAUSE_SECTIONS: + clauses = cp_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_SECTIONS, + clauses, token->location); + c_name = "sections"; + if (!first) + goto clause_not_first; + break; + case PRAGMA_OMP_CLAUSE_TASKGROUP: + clauses = cp_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_TASKGROUP, + clauses, token->location); + c_name = "taskgroup"; + if (!first) + goto clause_not_first; + break; + case PRAGMA_OMP_CLAUSE_TO: + 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); + c_name = "from"; + break; + case PRAGMA_OMP_CLAUSE_UNIFORM: + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_UNIFORM, + clauses); + c_name = "uniform"; + break; + case PRAGMA_OMP_CLAUSE_NUM_TEAMS: + clauses = cp_parser_omp_clause_num_teams (parser, clauses, + token->location); + c_name = "num_teams"; + break; + case PRAGMA_OMP_CLAUSE_THREAD_LIMIT: + clauses = cp_parser_omp_clause_thread_limit (parser, clauses, + token->location); + c_name = "thread_limit"; + break; + case PRAGMA_OMP_CLAUSE_ALIGNED: + clauses = cp_parser_omp_clause_aligned (parser, clauses); + c_name = "aligned"; + break; + case PRAGMA_OMP_CLAUSE_LINEAR: + clauses = cp_parser_omp_clause_linear (parser, clauses); + c_name = "linear"; + break; + case PRAGMA_OMP_CLAUSE_DEPEND: + clauses = cp_parser_omp_clause_depend (parser, clauses); + c_name = "depend"; + break; + case PRAGMA_OMP_CLAUSE_MAP: + clauses = cp_parser_omp_clause_map (parser, clauses); + c_name = "map"; + break; + case PRAGMA_OMP_CLAUSE_DEVICE: + clauses = cp_parser_omp_clause_device (parser, clauses, + token->location); + c_name = "device"; + break; + case PRAGMA_OMP_CLAUSE_DIST_SCHEDULE: + clauses = cp_parser_omp_clause_dist_schedule (parser, clauses, + token->location); + c_name = "dist_schedule"; + break; + case PRAGMA_OMP_CLAUSE_PROC_BIND: + clauses = cp_parser_omp_clause_proc_bind (parser, clauses, + token->location); + c_name = "proc_bind"; + break; + case PRAGMA_OMP_CLAUSE_SAFELEN: + clauses = cp_parser_omp_clause_safelen (parser, clauses, + token->location); + c_name = "safelen"; + break; + case PRAGMA_OMP_CLAUSE_SIMDLEN: + clauses = cp_parser_omp_clause_simdlen (parser, clauses, + token->location); + c_name = "simdlen"; + break; + default: + cp_parser_error (parser, "expected %<#pragma omp%> clause"); + goto saw_error; + } + + first = false; + + if (((mask >> c_kind) & 1) == 0) + { + /* Remove the invalid clause(s) from the list to avoid + confusing the rest of the compiler. */ + clauses = prev; + error_at (token->location, "%qs is not valid for %qs", c_name, where); + } + } + saw_error: + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + if (finish_p) + return finish_omp_clauses (clauses); + return clauses; +} + +/* OpenMP 2.5: + structured-block: + statement + + In practice, we're also interested in adding the statement to an + outer node. So it is convenient if we work around the fact that + cp_parser_statement calls add_stmt. */ + +static unsigned +cp_parser_begin_omp_structured_block (cp_parser *parser) +{ + unsigned save = parser->in_statement; + + /* Only move the values to IN_OMP_BLOCK if they weren't false. + This preserves the "not within loop or switch" style error messages + for nonsense cases like + void foo() { + #pragma omp single + break; + } + */ + if (parser->in_statement) + parser->in_statement = IN_OMP_BLOCK; + + return save; +} + +static void +cp_parser_end_omp_structured_block (cp_parser *parser, unsigned save) +{ + parser->in_statement = save; +} + +static tree +cp_parser_omp_structured_block (cp_parser *parser) +{ + tree stmt = begin_omp_structured_block (); + unsigned int save = cp_parser_begin_omp_structured_block (parser); + + cp_parser_statement (parser, NULL_TREE, false, NULL); + + cp_parser_end_omp_structured_block (parser, save); + return finish_omp_structured_block (stmt); +} + +/* OpenMP 2.5: + # pragma omp atomic new-line + expression-stmt + + expression-stmt: + x binop= expr | x++ | ++x | x-- | --x + binop: + +, *, -, /, &, ^, |, <<, >> + + where x is an lvalue expression with scalar type. + + OpenMP 3.1: # pragma omp atomic new-line update-stmt @@ -27153,10 +27924,18 @@ cp_parser_omp_structured_block (cp_parser *parser) update-stmt: expression-stmt | x = x binop expr capture-stmt: - v = x binop= expr | v = x++ | v = ++x | v = x-- | v = --x + v = expression-stmt capture-block: { v = x; update-stmt; } | { update-stmt; v = x; } + OpenMP 4.0: + update-stmt: + expression-stmt | x = x binop expr | x = expr binop x + capture-stmt: + v = update-stmt + capture-block: + { v = x; update-stmt; } | { update-stmt; v = x; } | { v = x; x = expr; } + where x and v are lvalue expressions with scalar type. */ static void @@ -27166,7 +27945,22 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok) tree rhs1 = NULL_TREE, orig_lhs; enum tree_code code = OMP_ATOMIC, opcode = NOP_EXPR; bool structured_block = false; + bool seq_cst = 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, "seq_cst")) + { + seq_cst = true; + cp_lexer_consume_token (parser->lexer); + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_NAME) + 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; @@ -27185,6 +27979,24 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok) if (p) cp_lexer_consume_token (parser->lexer); } + if (!seq_cst) + { + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_NAME) + cp_lexer_consume_token (parser->lexer); + + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + + if (!strcmp (p, "seq_cst")) + { + seq_cst = true; + cp_lexer_consume_token (parser->lexer); + } + } + } cp_parser_require_pragma_eol (parser, pragma_tok); switch (code) @@ -27323,75 +28135,139 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok) opcode = BIT_XOR_EXPR; break; case CPP_EQ: - if (structured_block || code == OMP_ATOMIC) + enum cp_parser_prec oprec; + cp_token *token; + cp_lexer_consume_token (parser->lexer); + cp_parser_parse_tentatively (parser); + rhs1 = cp_parser_simple_cast_expression (parser); + if (rhs1 == error_mark_node) { - enum cp_parser_prec oprec; - cp_token *token; - cp_lexer_consume_token (parser->lexer); - rhs1 = cp_parser_unary_expression (parser, /*address_p=*/false, - /*cast_p=*/false, NULL); - if (rhs1 == error_mark_node) - goto saw_error; - token = cp_lexer_peek_token (parser->lexer); - switch (token->type) + cp_parser_abort_tentative_parse (parser); + cp_parser_simple_cast_expression (parser); + goto saw_error; + } + token = cp_lexer_peek_token (parser->lexer); + if (token->type != CPP_SEMICOLON && !cp_tree_equal (lhs, rhs1)) + { + cp_parser_abort_tentative_parse (parser); + cp_parser_parse_tentatively (parser); + rhs = cp_parser_binary_expression (parser, false, true, + PREC_NOT_OPERATOR, NULL); + if (rhs == error_mark_node) + { + cp_parser_abort_tentative_parse (parser); + cp_parser_binary_expression (parser, false, true, + PREC_NOT_OPERATOR, NULL); + goto saw_error; + } + switch (TREE_CODE (rhs)) { - case CPP_SEMICOLON: - if (code == OMP_ATOMIC_CAPTURE_NEW) + case MULT_EXPR: + case TRUNC_DIV_EXPR: + case PLUS_EXPR: + case MINUS_EXPR: + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case BIT_AND_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + if (cp_tree_equal (lhs, TREE_OPERAND (rhs, 1))) { - code = OMP_ATOMIC_CAPTURE_OLD; - v = lhs; - lhs = NULL_TREE; - lhs1 = rhs1; - rhs1 = NULL_TREE; - cp_lexer_consume_token (parser->lexer); - goto restart; + if (cp_parser_parse_definitely (parser)) + { + opcode = TREE_CODE (rhs); + rhs1 = TREE_OPERAND (rhs, 0); + rhs = TREE_OPERAND (rhs, 1); + goto stmt_done; + } + else + goto saw_error; } - cp_parser_error (parser, - "invalid form of %<#pragma omp atomic%>"); - goto saw_error; - case CPP_MULT: - opcode = MULT_EXPR; - break; - case CPP_DIV: - opcode = TRUNC_DIV_EXPR; - break; - case CPP_PLUS: - opcode = PLUS_EXPR; - break; - case CPP_MINUS: - opcode = MINUS_EXPR; - break; - case CPP_LSHIFT: - opcode = LSHIFT_EXPR; - break; - case CPP_RSHIFT: - opcode = RSHIFT_EXPR; - break; - case CPP_AND: - opcode = BIT_AND_EXPR; - break; - case CPP_OR: - opcode = BIT_IOR_EXPR; - break; - case CPP_XOR: - opcode = BIT_XOR_EXPR; break; default: - cp_parser_error (parser, - "invalid operator for %<#pragma omp atomic%>"); - goto saw_error; + break; + } + cp_parser_abort_tentative_parse (parser); + if (structured_block && code == OMP_ATOMIC_CAPTURE_OLD) + { + rhs = cp_parser_expression (parser, /*cast_p=*/false, NULL); + if (rhs == error_mark_node) + goto saw_error; + opcode = NOP_EXPR; + rhs1 = NULL_TREE; + goto stmt_done; + } + cp_parser_error (parser, + "invalid form of %<#pragma omp atomic%>"); + goto saw_error; + } + if (!cp_parser_parse_definitely (parser)) + goto saw_error; + switch (token->type) + { + case CPP_SEMICOLON: + if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW) + { + code = OMP_ATOMIC_CAPTURE_OLD; + v = lhs; + lhs = NULL_TREE; + lhs1 = rhs1; + rhs1 = NULL_TREE; + cp_lexer_consume_token (parser->lexer); + goto restart; } - oprec = TOKEN_PRECEDENCE (token); - gcc_assert (oprec != PREC_NOT_OPERATOR); - if (commutative_tree_code (opcode)) - oprec = (enum cp_parser_prec) (oprec - 1); - cp_lexer_consume_token (parser->lexer); - rhs = cp_parser_binary_expression (parser, false, false, - oprec, NULL); - if (rhs == error_mark_node) - goto saw_error; - goto stmt_done; + else if (structured_block) + { + opcode = NOP_EXPR; + rhs = rhs1; + rhs1 = NULL_TREE; + goto stmt_done; + } + cp_parser_error (parser, + "invalid form of %<#pragma omp atomic%>"); + goto saw_error; + case CPP_MULT: + opcode = MULT_EXPR; + break; + case CPP_DIV: + opcode = TRUNC_DIV_EXPR; + break; + case CPP_PLUS: + opcode = PLUS_EXPR; + break; + case CPP_MINUS: + opcode = MINUS_EXPR; + break; + case CPP_LSHIFT: + opcode = LSHIFT_EXPR; + break; + case CPP_RSHIFT: + opcode = RSHIFT_EXPR; + break; + case CPP_AND: + opcode = BIT_AND_EXPR; + break; + case CPP_OR: + opcode = BIT_IOR_EXPR; + break; + case CPP_XOR: + opcode = BIT_XOR_EXPR; + break; + default: + cp_parser_error (parser, + "invalid operator for %<#pragma omp atomic%>"); + goto saw_error; } + oprec = TOKEN_PRECEDENCE (token); + gcc_assert (oprec != PREC_NOT_OPERATOR); + if (commutative_tree_code (opcode)) + oprec = (enum cp_parser_prec) (oprec - 1); + cp_lexer_consume_token (parser->lexer); + rhs = cp_parser_binary_expression (parser, false, false, + oprec, NULL); + if (rhs == error_mark_node) + goto saw_error; + goto stmt_done; /* FALLTHROUGH */ default: cp_parser_error (parser, @@ -27427,7 +28303,7 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok) cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); } done: - finish_omp_atomic (code, opcode, lhs, rhs, v, lhs1, rhs1); + finish_omp_atomic (code, opcode, lhs, rhs, v, lhs1, rhs1, seq_cst); if (!structured_block) cp_parser_consume_semicolon_at_end_of_statement (parser); return; @@ -27636,7 +28512,8 @@ cp_parser_omp_for_incr (cp_parser *parser, tree decl) /* Parse the restricted form of the for statement allowed by OpenMP. */ static tree -cp_parser_omp_for_loop (cp_parser *parser, tree clauses, tree *par_clauses) +cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, + tree *cclauses) { tree init, cond, incr, body, decl, pre_body = NULL_TREE, ret; tree real_decl, initv, condv, incrv, declv; @@ -27846,10 +28723,12 @@ cp_parser_omp_for_loop (cp_parser *parser, tree clauses, tree *par_clauses) if (decl) real_decl = decl; - if (par_clauses != NULL && real_decl != NULL_TREE) + if (cclauses != NULL + && cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] != NULL + && real_decl != NULL_TREE) { tree *c; - for (c = par_clauses; *c ; ) + for (c = &cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; *c ; ) if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_FIRSTPRIVATE && OMP_CLAUSE_DECL (*c) == real_decl) { @@ -27995,7 +28874,7 @@ cp_parser_omp_for_loop (cp_parser *parser, tree clauses, tree *par_clauses) if (declv == NULL_TREE) ret = NULL_TREE; else - ret = finish_omp_for (loc_first, declv, initv, condv, incrv, body, + ret = finish_omp_for (loc_first, code, declv, initv, condv, incrv, body, pre_body, clauses); while (nbraces) @@ -28028,33 +28907,137 @@ cp_parser_omp_for_loop (cp_parser *parser, tree clauses, tree *par_clauses) return ret; } +/* Helper function for OpenMP parsing, split clauses and call + finish_omp_clauses on each of the set of clauses afterwards. */ + +static void +cp_omp_split_clauses (location_t loc, enum tree_code code, + omp_clause_mask mask, tree clauses, tree *cclauses) +{ + int i; + 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]); +} + +/* OpenMP 4.0: + #pragma omp simd simd-clause[optseq] new-line + for-loop */ + +#define OMP_SIMD_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SAFELEN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE)) + +static tree +cp_parser_omp_simd (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, " 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); + if (cclauses) + { + cp_omp_split_clauses (loc, OMP_SIMD, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_SIMD]; + } + + sb = begin_omp_structured_block (); + save = cp_parser_begin_omp_structured_block (parser); + + ret = cp_parser_omp_for_loop (parser, OMP_SIMD, clauses, cclauses); + + cp_parser_end_omp_structured_block (parser, save); + add_stmt (finish_omp_structured_block (sb)); + + return ret; +} + /* OpenMP 2.5: #pragma omp for for-clause[optseq] new-line + for-loop + + OpenMP 4.0: + #pragma omp for simd for-simd-clause[optseq] new-line for-loop */ -#define OMP_FOR_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ - | (1u << PRAGMA_OMP_CLAUSE_ORDERED) \ - | (1u << PRAGMA_OMP_CLAUSE_SCHEDULE) \ - | (1u << PRAGMA_OMP_CLAUSE_NOWAIT) \ - | (1u << PRAGMA_OMP_CLAUSE_COLLAPSE)) +#define OMP_FOR_CLAUSE_MASK \ + ( (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_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE)) static tree -cp_parser_omp_for (cp_parser *parser, cp_token *pragma_tok) +cp_parser_omp_for (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, " for"); + mask |= OMP_FOR_CLAUSE_MASK; + if (cclauses) + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); + + 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); + 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_FOR); + TREE_TYPE (ret) = void_type_node; + OMP_FOR_BODY (ret) = body; + OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; + SET_EXPR_LOCATION (ret, loc); + add_stmt (ret); + return ret; + } + } - clauses = cp_parser_omp_all_clauses (parser, OMP_FOR_CLAUSE_MASK, - "#pragma omp for", pragma_tok); + clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok, + cclauses == NULL); + if (cclauses) + { + cp_omp_split_clauses (loc, OMP_FOR, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; + } sb = begin_omp_structured_block (); save = cp_parser_begin_omp_structured_block (parser); - ret = cp_parser_omp_for_loop (parser, clauses, NULL); + ret = cp_parser_omp_for_loop (parser, OMP_FOR, clauses, cclauses); cp_parser_end_omp_structured_block (parser, save); add_stmt (finish_omp_structured_block (sb)); @@ -28141,226 +29124,726 @@ cp_parser_omp_sections_scope (cp_parser *parser) if (tok->type == CPP_EOF) break; - if (tok->pragma_kind == PRAGMA_OMP_SECTION) + if (tok->pragma_kind == PRAGMA_OMP_SECTION) + { + cp_lexer_consume_token (parser->lexer); + cp_parser_require_pragma_eol (parser, tok); + error_suppress = false; + } + else if (!error_suppress) + { + cp_parser_error (parser, "expected %<#pragma omp section%> or %<}%>"); + error_suppress = true; + } + + substmt = cp_parser_omp_structured_block (parser); + substmt = build1 (OMP_SECTION, void_type_node, substmt); + add_stmt (substmt); + } + cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); + + substmt = pop_stmt_list (stmt); + + stmt = make_node (OMP_SECTIONS); + TREE_TYPE (stmt) = void_type_node; + OMP_SECTIONS_BODY (stmt) = substmt; + + add_stmt (stmt); + return stmt; +} + +/* OpenMP 2.5: + # pragma omp sections sections-clause[optseq] newline + sections-scope */ + +#define OMP_SECTIONS_CLAUSE_MASK \ + ( (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_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) + +static tree +cp_parser_omp_sections (cp_parser *parser, cp_token *pragma_tok, + char *p_name, omp_clause_mask mask, tree *cclauses) +{ + tree clauses, ret; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + + strcat (p_name, " sections"); + mask |= OMP_SECTIONS_CLAUSE_MASK; + if (cclauses) + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); + + clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok, + cclauses == NULL); + if (cclauses) + { + cp_omp_split_clauses (loc, OMP_SECTIONS, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_SECTIONS]; + } + + ret = cp_parser_omp_sections_scope (parser); + if (ret) + OMP_SECTIONS_CLAUSES (ret) = clauses; + + return ret; +} + +/* OpenMP 2.5: + # pragma parallel parallel-clause new-line + # pragma parallel for parallel-for-clause new-line + # pragma parallel sections parallel-sections-clause new-line + + OpenMP 4.0: + # pragma parallel for simd parallel-for-simd-clause new-line */ + +#define OMP_PARALLEL_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PROC_BIND)) + +static tree +cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok, + char *p_name, omp_clause_mask mask, tree *cclauses) +{ + tree stmt, clauses, block; + unsigned int save; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + + strcat (p_name, " parallel"); + mask |= OMP_PARALLEL_CLAUSE_MASK; + + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR)) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + + cp_lexer_consume_token (parser->lexer); + block = begin_omp_parallel (); + save = cp_parser_begin_omp_structured_block (parser); + cp_parser_omp_for (parser, pragma_tok, p_name, mask, cclauses); + cp_parser_end_omp_structured_block (parser, save); + stmt = finish_omp_parallel (cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], + block); + OMP_PARALLEL_COMBINED (stmt) = 1; + return stmt; + } + else if (cclauses) + { + error_at (loc, "expected % after %qs", p_name); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return NULL_TREE; + } + else 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, "sections") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + cclauses = cclauses_buf; + + cp_lexer_consume_token (parser->lexer); + block = begin_omp_parallel (); + save = cp_parser_begin_omp_structured_block (parser); + cp_parser_omp_sections (parser, pragma_tok, p_name, mask, cclauses); + cp_parser_end_omp_structured_block (parser, save); + stmt = finish_omp_parallel (cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], + block); + OMP_PARALLEL_COMBINED (stmt) = 1; + return stmt; + } + } + + clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok); + + block = begin_omp_parallel (); + save = cp_parser_begin_omp_structured_block (parser); + cp_parser_statement (parser, NULL_TREE, false, NULL); + cp_parser_end_omp_structured_block (parser, save); + stmt = finish_omp_parallel (clauses, block); + return stmt; +} + +/* OpenMP 2.5: + # pragma omp single single-clause[optseq] new-line + structured-block */ + +#define OMP_SINGLE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) + +static tree +cp_parser_omp_single (cp_parser *parser, cp_token *pragma_tok) +{ + tree stmt = make_node (OMP_SINGLE); + TREE_TYPE (stmt) = void_type_node; + + OMP_SINGLE_CLAUSES (stmt) + = cp_parser_omp_all_clauses (parser, OMP_SINGLE_CLAUSE_MASK, + "#pragma omp single", pragma_tok); + OMP_SINGLE_BODY (stmt) = cp_parser_omp_structured_block (parser); + + return add_stmt (stmt); +} + +/* OpenMP 3.0: + # pragma omp task task-clause[optseq] new-line + structured-block */ + +#define OMP_TASK_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNTIED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (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)) + +static tree +cp_parser_omp_task (cp_parser *parser, cp_token *pragma_tok) +{ + tree clauses, block; + unsigned int save; + + clauses = cp_parser_omp_all_clauses (parser, OMP_TASK_CLAUSE_MASK, + "#pragma omp task", pragma_tok); + block = begin_omp_task (); + save = cp_parser_begin_omp_structured_block (parser); + cp_parser_statement (parser, NULL_TREE, false, NULL); + cp_parser_end_omp_structured_block (parser, save); + return finish_omp_task (clauses, block); +} + +/* OpenMP 3.0: + # pragma omp taskwait new-line */ + +static void +cp_parser_omp_taskwait (cp_parser *parser, cp_token *pragma_tok) +{ + cp_parser_require_pragma_eol (parser, pragma_tok); + finish_omp_taskwait (); +} + +/* OpenMP 3.1: + # pragma omp taskyield new-line */ + +static void +cp_parser_omp_taskyield (cp_parser *parser, cp_token *pragma_tok) +{ + cp_parser_require_pragma_eol (parser, pragma_tok); + finish_omp_taskyield (); +} + +/* OpenMP 4.0: + # pragma omp taskgroup new-line + structured-block */ + +static void +cp_parser_omp_taskgroup (cp_parser *parser, cp_token *pragma_tok) +{ + tree sb; + unsigned int save; + location_t saved_loc; + + cp_parser_require_pragma_eol (parser, pragma_tok); + sb = begin_omp_structured_block (); + save = cp_parser_begin_omp_structured_block (parser); + cp_parser_statement (parser, NULL_TREE, false, NULL); + cp_parser_end_omp_structured_block (parser, save); + saved_loc = input_location; + input_location = pragma_tok->location; + finish_omp_taskgroup (finish_omp_structured_block (sb)); + input_location = saved_loc; +} + + + +/* OpenMP 2.5: + # pragma omp threadprivate (variable-list) */ + +static void +cp_parser_omp_threadprivate (cp_parser *parser, cp_token *pragma_tok) +{ + tree vars; + + vars = cp_parser_omp_var_list (parser, OMP_CLAUSE_ERROR, NULL); + cp_parser_require_pragma_eol (parser, pragma_tok); + + finish_omp_threadprivate (vars); +} + +/* OpenMP 4.0: + # pragma omp cancel cancel-clause[optseq] new-line */ + +#define OMP_CANCEL_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARALLEL) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FOR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)) + +static void +cp_parser_omp_cancel (cp_parser *parser, cp_token *pragma_tok) +{ + tree clauses = cp_parser_omp_all_clauses (parser, OMP_CANCEL_CLAUSE_MASK, + "#pragma omp cancel", pragma_tok); + finish_omp_cancel (clauses); +} + +/* OpenMP 4.0: + # pragma omp cancellation point cancelpt-clause[optseq] new-line */ + +#define OMP_CANCELLATION_POINT_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARALLEL) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FOR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP)) + +static void +cp_parser_omp_cancellation_point (cp_parser *parser, cp_token *pragma_tok) +{ + tree clauses; + bool point_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, "point") == 0) { cp_lexer_consume_token (parser->lexer); - cp_parser_require_pragma_eol (parser, tok); - error_suppress = false; - } - else if (!error_suppress) - { - cp_parser_error (parser, "expected %<#pragma omp section%> or %<}%>"); - error_suppress = true; + point_seen = true; } - - substmt = cp_parser_omp_structured_block (parser); - substmt = build1 (OMP_SECTION, void_type_node, substmt); - add_stmt (substmt); } - cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); - - substmt = pop_stmt_list (stmt); - - stmt = make_node (OMP_SECTIONS); - TREE_TYPE (stmt) = void_type_node; - OMP_SECTIONS_BODY (stmt) = substmt; + if (!point_seen) + { + cp_parser_error (parser, "expected %"); + cp_parser_require_pragma_eol (parser, pragma_tok); + return; + } - add_stmt (stmt); - return stmt; + clauses = cp_parser_omp_all_clauses (parser, + OMP_CANCELLATION_POINT_CLAUSE_MASK, + "#pragma omp cancellation point", + pragma_tok); + finish_omp_cancellation_point (clauses); } -/* OpenMP 2.5: - # pragma omp sections sections-clause[optseq] newline - sections-scope */ +/* OpenMP 4.0: + #pragma omp distribute distribute-clause[optseq] new-line + for-loop */ -#define OMP_SECTIONS_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ - | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) +#define OMP_DISTRIBUTE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)\ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE)) static tree -cp_parser_omp_sections (cp_parser *parser, cp_token *pragma_tok) +cp_parser_omp_distribute (cp_parser *parser, cp_token *pragma_tok, + char *p_name, omp_clause_mask mask, tree *cclauses) { - tree clauses, ret; + tree clauses, sb, ret; + unsigned int save; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; - clauses = cp_parser_omp_all_clauses (parser, OMP_SECTIONS_CLAUSE_MASK, - "#pragma omp sections", pragma_tok); + strcat (p_name, " distribute"); + mask |= OMP_DISTRIBUTE_CLAUSE_MASK; - ret = cp_parser_omp_sections_scope (parser); - if (ret) - OMP_SECTIONS_CLAUSES (ret) = clauses; + 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); + bool simd = false; + bool parallel = false; + + if (strcmp (p, "simd") == 0) + simd = true; + else + parallel = strcmp (p, "parallel") == 0; + if (parallel || simd) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + cp_lexer_consume_token (parser->lexer); + sb = begin_omp_structured_block (); + save = cp_parser_begin_omp_structured_block (parser); + if (simd) + ret = cp_parser_omp_simd (parser, pragma_tok, p_name, mask, + cclauses); + else + ret = cp_parser_omp_parallel (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_DISTRIBUTE); + TREE_TYPE (ret) = void_type_node; + OMP_FOR_BODY (ret) = body; + OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE]; + SET_EXPR_LOCATION (ret, loc); + add_stmt (ret); + return ret; + } + } + + clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok, + cclauses == NULL); + if (cclauses) + { + cp_omp_split_clauses (loc, OMP_DISTRIBUTE, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE]; + } + + sb = begin_omp_structured_block (); + save = cp_parser_begin_omp_structured_block (parser); + + ret = cp_parser_omp_for_loop (parser, OMP_DISTRIBUTE, clauses, NULL); + + cp_parser_end_omp_structured_block (parser, save); + add_stmt (finish_omp_structured_block (sb)); return ret; } -/* OpenMP 2.5: - # pragma parallel parallel-clause new-line - # pragma parallel for parallel-for-clause new-line - # pragma parallel sections parallel-sections-clause new-line */ - -#define OMP_PARALLEL_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_IF) \ - | (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \ - | (1u << PRAGMA_OMP_CLAUSE_SHARED) \ - | (1u << PRAGMA_OMP_CLAUSE_COPYIN) \ - | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ - | (1u << PRAGMA_OMP_CLAUSE_NUM_THREADS)) +/* OpenMP 4.0: + # pragma omp teams teams-clause[optseq] new-line + structured-block */ + +#define OMP_TEAMS_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT)) static tree -cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok) +cp_parser_omp_teams (cp_parser *parser, cp_token *pragma_tok, + char *p_name, omp_clause_mask mask, tree *cclauses) { - enum pragma_kind p_kind = PRAGMA_OMP_PARALLEL; - const char *p_name = "#pragma omp parallel"; - tree stmt, clauses, par_clause, ws_clause, block; - unsigned int mask = OMP_PARALLEL_CLAUSE_MASK; + tree clauses, sb, ret; unsigned int save; location_t loc = cp_lexer_peek_token (parser->lexer)->location; - if (cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR)) - { - cp_lexer_consume_token (parser->lexer); - p_kind = PRAGMA_OMP_PARALLEL_FOR; - p_name = "#pragma omp parallel for"; - mask |= OMP_FOR_CLAUSE_MASK; - mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT); - } - else if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + 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, "sections") == 0) + 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); - p_kind = PRAGMA_OMP_PARALLEL_SECTIONS; - p_name = "#pragma omp parallel sections"; - mask |= OMP_SECTIONS_CLAUSE_MASK; - mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT); + 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; + return add_stmt (ret); } } - clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok); - block = begin_omp_parallel (); - save = cp_parser_begin_omp_structured_block (parser); - - switch (p_kind) + clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok, + cclauses == NULL); + if (cclauses) { - case PRAGMA_OMP_PARALLEL: - cp_parser_statement (parser, NULL_TREE, false, NULL); - par_clause = clauses; - break; - - case PRAGMA_OMP_PARALLEL_FOR: - c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause); - cp_parser_omp_for_loop (parser, ws_clause, &par_clause); - break; - - case PRAGMA_OMP_PARALLEL_SECTIONS: - c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause); - stmt = cp_parser_omp_sections_scope (parser); - if (stmt) - OMP_SECTIONS_CLAUSES (stmt) = ws_clause; - break; - - default: - gcc_unreachable (); + cp_omp_split_clauses (loc, OMP_TEAMS, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; } - cp_parser_end_omp_structured_block (parser, save); - stmt = finish_omp_parallel (par_clause, block); - if (p_kind != PRAGMA_OMP_PARALLEL) - OMP_PARALLEL_COMBINED (stmt) = 1; - return stmt; + 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 2.5: - # pragma omp single single-clause[optseq] new-line +/* OpenMP 4.0: + # pragma omp target data target-data-clause[optseq] new-line structured-block */ -#define OMP_SINGLE_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) +#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)) static tree -cp_parser_omp_single (cp_parser *parser, cp_token *pragma_tok) +cp_parser_omp_target_data (cp_parser *parser, cp_token *pragma_tok) { - tree stmt = make_node (OMP_SINGLE); + tree stmt = make_node (OMP_TARGET_DATA); TREE_TYPE (stmt) = void_type_node; - OMP_SINGLE_CLAUSES (stmt) - = cp_parser_omp_all_clauses (parser, OMP_SINGLE_CLAUSE_MASK, - "#pragma omp single", pragma_tok); - OMP_SINGLE_BODY (stmt) = cp_parser_omp_structured_block (parser); + OMP_TARGET_DATA_CLAUSES (stmt) + = cp_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK, + "#pragma omp target data", pragma_tok); + OMP_TARGET_DATA_BODY (stmt) = cp_parser_omp_structured_block (parser); + SET_EXPR_LOCATION (stmt, pragma_tok->location); return add_stmt (stmt); } -/* OpenMP 3.0: - # pragma omp task task-clause[optseq] new-line +/* OpenMP 4.0: + # pragma omp target update target-update-clause[optseq] new-line */ + +#define OMP_TARGET_UPDATE_CLAUSE_MASK \ + ( (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)) + +static bool +cp_parser_omp_target_update (cp_parser *parser, cp_token *pragma_tok, + enum pragma_context context) +{ + if (context == pragma_stmt) + { + error_at (pragma_tok->location, + "%<#pragma omp target update%> 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_TARGET_UPDATE_CLAUSE_MASK, + "#pragma omp target update", pragma_tok); + if (find_omp_clause (clauses, OMP_CLAUSE_TO) == NULL_TREE + && find_omp_clause (clauses, OMP_CLAUSE_FROM) == NULL_TREE) + { + error_at (pragma_tok->location, + "%<#pragma omp target update must contain at least one " + "% or % clauses"); + return false; + } + + tree stmt = make_node (OMP_TARGET_UPDATE); + TREE_TYPE (stmt) = void_type_node; + OMP_TARGET_UPDATE_CLAUSES (stmt) = clauses; + SET_EXPR_LOCATION (stmt, pragma_tok->location); + add_stmt (stmt); + return false; +} + +/* OpenMP 4.0: + # pragma omp target target-clause[optseq] new-line structured-block */ -#define OMP_TASK_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_IF) \ - | (1u << PRAGMA_OMP_CLAUSE_UNTIED) \ - | (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \ - | (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_SHARED) \ - | (1u << PRAGMA_OMP_CLAUSE_FINAL) \ - | (1u << PRAGMA_OMP_CLAUSE_MERGEABLE)) +#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)) -static tree -cp_parser_omp_task (cp_parser *parser, cp_token *pragma_tok) +static bool +cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok, + enum pragma_context context) { - tree clauses, block; - unsigned int save; + 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; + } - clauses = cp_parser_omp_all_clauses (parser, OMP_TASK_CLAUSE_MASK, - "#pragma omp task", pragma_tok); - block = begin_omp_task (); - save = cp_parser_begin_omp_structured_block (parser); - cp_parser_statement (parser, NULL_TREE, false, NULL); - cp_parser_end_omp_structured_block (parser, save); - return finish_omp_task (clauses, block); + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + + if (strcmp (p, "data") == 0) + { + cp_lexer_consume_token (parser->lexer); + cp_parser_omp_target_data (parser, pragma_tok); + return true; + } + else if (strcmp (p, "update") == 0) + { + cp_lexer_consume_token (parser->lexer); + return cp_parser_omp_target_update (parser, pragma_tok, context); + } + else if (strcmp (p, "teams") == 0) + { + tree cclauses[C_OMP_CLAUSE_SPLIT_COUNT]; + char p_name[sizeof ("#pragma omp target teams distribute " + "parallel for simd")]; + + cp_lexer_consume_token (parser->lexer); + strcpy (p_name, "#pragma omp target"); + tree sb = begin_omp_structured_block (); + 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); + cp_parser_end_omp_structured_block (parser, save); + tree body = finish_omp_structured_block (sb); + if (ret == NULL) + return ret; + tree stmt = make_node (OMP_TARGET); + TREE_TYPE (stmt) = void_type_node; + OMP_TARGET_CLAUSES (stmt) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET]; + OMP_TARGET_BODY (stmt) = body; + add_stmt (stmt); + return true; + } + } + + tree 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); + OMP_TARGET_BODY (stmt) = cp_parser_omp_structured_block (parser); + + SET_EXPR_LOCATION (stmt, pragma_tok->location); + add_stmt (stmt); + return true; } -/* OpenMP 3.0: - # pragma omp taskwait new-line */ +/* OpenMP 4.0: + # pragma omp declare simd declare-simd-clauses[optseq] new-line */ + +#define OMP_DECLARE_SIMD_CLAUSE_MASK \ + ( (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_UNIFORM) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_INBRANCH) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOTINBRANCH)) static void -cp_parser_omp_taskwait (cp_parser *parser, cp_token *pragma_tok) -{ - cp_parser_require_pragma_eol (parser, pragma_tok); - finish_omp_taskwait (); +cp_parser_omp_declare_simd (cp_parser *parser, cp_token *pragma_tok, + enum pragma_context context) +{ + bool first_p = parser->omp_declare_simd_clauses == NULL; + vec_safe_push (parser->omp_declare_simd_clauses, NULL_TREE); + tree clauses + = cp_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK, + "#pragma omp declare simd", pragma_tok, + false); + parser->omp_declare_simd_clauses->last () = clauses; + if (first_p) + { + while (cp_lexer_next_token_is (parser->lexer, CPP_PRAGMA)) + cp_parser_pragma (parser, context); + switch (context) + { + case pragma_external: + cp_parser_declaration (parser); + break; + case pragma_member: + cp_parser_member_declaration (parser); + break; + case pragma_objc_icode: + cp_parser_block_declaration (parser, /*statement_p=*/false); + break; + default: + cp_parser_declaration_statement (parser); + break; + } + if (parser->omp_declare_simd_clauses + && (*parser->omp_declare_simd_clauses)[0] != error_mark_node + && (*parser->omp_declare_simd_clauses)[0] != integer_zero_node) + error_at (pragma_tok->location, + "%<#pragma omp declare simd%> not immediately followed by " + "function declaration or definition"); + parser->omp_declare_simd_clauses = NULL; + } } -/* OpenMP 3.1: - # pragma omp taskyield new-line */ +/* OpenMP 4.0: + # pragma omp declare target new-line + declarations and definitions + # pragma omp end declare target new-line */ static void -cp_parser_omp_taskyield (cp_parser *parser, cp_token *pragma_tok) +cp_parser_omp_declare_target (cp_parser *parser, cp_token *pragma_tok) { - cp_parser_require_pragma_eol (parser, pragma_tok); - finish_omp_taskyield (); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + current_omp_declare_target_attribute++; } -/* OpenMP 2.5: - # pragma omp threadprivate (variable-list) */ +static void +cp_parser_omp_end_declare_target (cp_parser *parser, cp_token *pragma_tok) +{ + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + if (!current_omp_declare_target_attribute) + error_at (pragma_tok->location, + "%<#pragma omp end declare target%> without corresponding " + "%<#pragma omp declare target%>"); + else + current_omp_declare_target_attribute--; +} + +/* OpenMP 4.0 + #pragma omp declare simd declare-simd-clauses[optseq] new-line + #pragma omp declare reduction (reduction-id : typename-list : expression) \ + identity-clause[opt] new-line */ static void -cp_parser_omp_threadprivate (cp_parser *parser, cp_token *pragma_tok) +cp_parser_omp_declare (cp_parser *parser, cp_token *pragma_tok, + enum pragma_context context) { - tree vars; + 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); - vars = cp_parser_omp_var_list (parser, OMP_CLAUSE_ERROR, NULL); + if (strcmp (p, "simd") == 0) + { + cp_lexer_consume_token (parser->lexer); + cp_parser_omp_declare_simd (parser, pragma_tok, + context); + return; + } + cp_ensure_no_omp_declare_simd (parser); +/* if (strcmp (p, "reduction") == 0) + { + cp_lexer_consume_token (parser->lexer); + cp_parser_omp_declare_reduction (parser, pragma_tok, + context); + return; + } */ + if (strcmp (p, "target") == 0) + { + cp_lexer_consume_token (parser->lexer); + cp_parser_omp_declare_target (parser, pragma_tok); + return; + } + } + cp_parser_error (parser, "expected % or %"); cp_parser_require_pragma_eol (parser, pragma_tok); - - finish_omp_threadprivate (vars); } /* Main entry point to OpenMP statement pragmas. */ @@ -28369,6 +29852,8 @@ static void cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok) { tree stmt; + char p_name[sizeof "#pragma omp teams distribute parallel for simd"]; + omp_clause_mask mask (0); switch (pragma_tok->pragma_kind) { @@ -28378,8 +29863,13 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok) case PRAGMA_OMP_CRITICAL: stmt = cp_parser_omp_critical (parser, pragma_tok); break; + case PRAGMA_OMP_DISTRIBUTE: + strcpy (p_name, "#pragma omp"); + stmt = cp_parser_omp_distribute (parser, pragma_tok, p_name, mask, NULL); + break; case PRAGMA_OMP_FOR: - stmt = cp_parser_omp_for (parser, pragma_tok); + strcpy (p_name, "#pragma omp"); + stmt = cp_parser_omp_for (parser, pragma_tok, p_name, mask, NULL); break; case PRAGMA_OMP_MASTER: stmt = cp_parser_omp_master (parser, pragma_tok); @@ -28388,10 +29878,16 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok) stmt = cp_parser_omp_ordered (parser, pragma_tok); break; case PRAGMA_OMP_PARALLEL: - stmt = cp_parser_omp_parallel (parser, pragma_tok); + strcpy (p_name, "#pragma omp"); + stmt = cp_parser_omp_parallel (parser, pragma_tok, p_name, mask, NULL); break; case PRAGMA_OMP_SECTIONS: - stmt = cp_parser_omp_sections (parser, pragma_tok); + strcpy (p_name, "#pragma omp"); + stmt = cp_parser_omp_sections (parser, pragma_tok, p_name, mask, NULL); + break; + case PRAGMA_OMP_SIMD: + strcpy (p_name, "#pragma omp"); + stmt = cp_parser_omp_simd (parser, pragma_tok, p_name, mask, NULL); break; case PRAGMA_OMP_SINGLE: stmt = cp_parser_omp_single (parser, pragma_tok); @@ -28399,6 +29895,13 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok) case PRAGMA_OMP_TASK: stmt = cp_parser_omp_task (parser, pragma_tok); break; + case PRAGMA_OMP_TASKGROUP: + cp_parser_omp_taskgroup (parser, pragma_tok); + return; + case PRAGMA_OMP_TEAMS: + strcpy (p_name, "#pragma omp"); + stmt = cp_parser_omp_teams (parser, pragma_tok, p_name, mask, NULL); + break; default: gcc_unreachable (); } @@ -28756,6 +30259,8 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context) parser->lexer->in_pragma = true; id = pragma_tok->pragma_kind; + if (id != PRAGMA_OMP_DECLARE_REDUCTION) + cp_ensure_no_omp_declare_simd (parser); switch (id) { case PRAGMA_GCC_PCH_PREPROCESS: @@ -28797,11 +30302,43 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context) switch (context) { case pragma_compound: - cp_parser_omp_taskwait (parser, pragma_tok); + cp_parser_omp_taskwait (parser, pragma_tok); + return false; + case pragma_stmt: + error_at (pragma_tok->location, + "%<#pragma omp taskwait%> may only be " + "used in compound statements"); + break; + default: + goto bad_stmt; + } + break; + + case PRAGMA_OMP_TASKYIELD: + switch (context) + { + case pragma_compound: + cp_parser_omp_taskyield (parser, pragma_tok); + return false; + case pragma_stmt: + error_at (pragma_tok->location, + "%<#pragma omp taskyield%> may only be " + "used in compound statements"); + break; + default: + goto bad_stmt; + } + break; + + case PRAGMA_OMP_CANCEL: + switch (context) + { + case pragma_compound: + cp_parser_omp_cancel (parser, pragma_tok); return false; case pragma_stmt: error_at (pragma_tok->location, - "%<#pragma omp taskwait%> may only be " + "%<#pragma omp cancel%> may only be " "used in compound statements"); break; default: @@ -28809,15 +30346,15 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context) } break; - case PRAGMA_OMP_TASKYIELD: + case PRAGMA_OMP_CANCELLATION_POINT: switch (context) { case pragma_compound: - cp_parser_omp_taskyield (parser, pragma_tok); + cp_parser_omp_cancellation_point (parser, pragma_tok); return false; case pragma_stmt: error_at (pragma_tok->location, - "%<#pragma omp taskyield%> may only be " + "%<#pragma omp cancellation point%> may only be " "used in compound statements"); break; default: @@ -28829,26 +30366,51 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context) cp_parser_omp_threadprivate (parser, pragma_tok); return false; + case PRAGMA_OMP_DECLARE_REDUCTION: + cp_parser_omp_declare (parser, pragma_tok, context); + return false; + case PRAGMA_OMP_ATOMIC: case PRAGMA_OMP_CRITICAL: + 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: - if (context == pragma_external) + case PRAGMA_OMP_TASKGROUP: + case PRAGMA_OMP_TEAMS: + if (context != pragma_stmt && context != pragma_compound) goto bad_stmt; cp_parser_omp_construct (parser, pragma_tok); return true; + case PRAGMA_OMP_TARGET: + return cp_parser_omp_target (parser, pragma_tok, context); + + case PRAGMA_OMP_END_DECLARE_TARGET: + cp_parser_omp_end_declare_target (parser, pragma_tok); + return false; + case PRAGMA_OMP_SECTION: error_at (pragma_tok->location, "%<#pragma omp section%> may only be used in " "%<#pragma omp sections%> construct"); break; + case PRAGMA_CILK_SIMD: + if (context == pragma_external) + { + error_at (pragma_tok->location, + "%<#pragma simd%> must be inside a function"); + break; + } + cp_parser_cilk_simd_construct (parser, pragma_tok); + return true; + default: gcc_assert (id >= PRAGMA_FIRST_EXTERNAL); c_invoke_pragma_handler (id); @@ -28914,4 +30476,522 @@ c_parse_file (void) the_parser = NULL; } + +/* Parses the Cilk Plus #pragma simd vectorlength clause: + Syntax: + vectorlength ( constant-expression ) */ + +static tree +cp_parser_cilk_simd_vectorlength (cp_parser *parser, tree clauses) +{ + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + tree expr; + /* The vectorlength clause behaves exactly like OpenMP's safelen + clause. Thus, vectorlength is represented as OMP 4.0 + safelen. */ + check_no_duplicate_clause (clauses, OMP_CLAUSE_SAFELEN, "vectorlength", loc); + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return error_mark_node; + + expr = cp_parser_constant_expression (parser, false, NULL); + expr = maybe_constant_value (expr); + + if (TREE_CONSTANT (expr) + && exact_log2 (TREE_INT_CST_LOW (expr)) == -1) + error_at (loc, "vectorlength must be a power of 2"); + else if (expr != error_mark_node) + { + tree c = build_omp_clause (loc, OMP_CLAUSE_SAFELEN); + OMP_CLAUSE_SAFELEN_EXPR (c) = expr; + OMP_CLAUSE_CHAIN (c) = clauses; + clauses = c; + } + + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + return error_mark_node; + return clauses; +} + +/* Handles the Cilk Plus #pragma simd linear clause. + Syntax: + linear ( simd-linear-variable-list ) + + simd-linear-variable-list: + simd-linear-variable + simd-linear-variable-list , simd-linear-variable + + simd-linear-variable: + id-expression + id-expression : simd-linear-step + + simd-linear-step: + conditional-expression */ + +static tree +cp_parser_cilk_simd_linear (cp_parser *parser, tree clauses) +{ + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return clauses; + if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME)) + { + cp_parser_error (parser, "expected identifier"); + cp_parser_skip_to_closing_parenthesis (parser, false, false, true); + return error_mark_node; + } + + while (1) + { + cp_token *token = cp_lexer_peek_token (parser->lexer); + if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME)) + { + cp_parser_error (parser, "expected variable-name"); + clauses = error_mark_node; + break; + } + + tree var_name = cp_parser_id_expression (parser, false, true, NULL, + false, false); + tree decl = cp_parser_lookup_name_simple (parser, var_name, + token->location); + if (decl == error_mark_node) + { + cp_parser_name_lookup_error (parser, var_name, decl, NLE_NULL, + token->location); + clauses = error_mark_node; + } + else + { + tree e = NULL_TREE; + tree step_size = integer_one_node; + + /* If present, parse the linear step. Otherwise, assume the default + value of 1. */ + if (cp_lexer_peek_token (parser->lexer)->type == CPP_COLON) + { + cp_lexer_consume_token (parser->lexer); + + e = cp_parser_constant_expression (parser, false, NULL); + e = maybe_constant_value (e); + + if (e == error_mark_node) + { + /* If an error has occurred, then the whole pragma is + considered ill-formed. Thus, no reason to keep + parsing. */ + clauses = error_mark_node; + break; + } + else if (!TREE_TYPE (e) || !TREE_CONSTANT (e) + || !INTEGRAL_TYPE_P (TREE_TYPE (e))) + cp_parser_error (parser, + "step size must be an integer constant"); + else + step_size = e; + } + + /* Use the OMP_CLAUSE_LINEAR, which has the same semantics. */ + tree l = build_omp_clause (loc, OMP_CLAUSE_LINEAR); + OMP_CLAUSE_DECL (l) = decl; + OMP_CLAUSE_LINEAR_STEP (l) = step_size; + OMP_CLAUSE_CHAIN (l) = clauses; + clauses = l; + } + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + cp_lexer_consume_token (parser->lexer); + else if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)) + break; + else + { + error_at (cp_lexer_peek_token (parser->lexer)->location, + "expected %<,%> or %<)%> after %qE", decl); + clauses = error_mark_node; + break; + } + } + cp_parser_skip_to_closing_parenthesis (parser, false, false, true); + return clauses; +} + +/* Returns the name of the next clause. If the clause is not + recognized, then PRAGMA_CILK_CLAUSE_NONE is returned and the next + token is not consumed. Otherwise, the appropriate enum from the + pragma_simd_clause is returned and the token is consumed. */ + +static pragma_cilk_clause +cp_parser_cilk_simd_clause_name (cp_parser *parser) +{ + pragma_cilk_clause clause_type; + cp_token *token = cp_lexer_peek_token (parser->lexer); + + if (token->keyword == RID_PRIVATE) + clause_type = PRAGMA_CILK_CLAUSE_PRIVATE; + else if (!token->u.value || token->type != CPP_NAME) + return PRAGMA_CILK_CLAUSE_NONE; + else if (!strcmp (IDENTIFIER_POINTER (token->u.value), "vectorlength")) + clause_type = PRAGMA_CILK_CLAUSE_VECTORLENGTH; + else if (!strcmp (IDENTIFIER_POINTER (token->u.value), "linear")) + clause_type = PRAGMA_CILK_CLAUSE_LINEAR; + else if (!strcmp (IDENTIFIER_POINTER (token->u.value), "firstprivate")) + clause_type = PRAGMA_CILK_CLAUSE_FIRSTPRIVATE; + else if (!strcmp (IDENTIFIER_POINTER (token->u.value), "lastprivate")) + clause_type = PRAGMA_CILK_CLAUSE_LASTPRIVATE; + else if (!strcmp (IDENTIFIER_POINTER (token->u.value), "reduction")) + clause_type = PRAGMA_CILK_CLAUSE_REDUCTION; + else + return PRAGMA_CILK_CLAUSE_NONE; + + cp_lexer_consume_token (parser->lexer); + return clause_type; +} + +/* Parses all the #pragma simd clauses. Returns a list of clauses found. */ + +static tree +cp_parser_cilk_simd_all_clauses (cp_parser *parser, cp_token *pragma_token) +{ + tree clauses = NULL_TREE; + + while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL) + && clauses != error_mark_node) + { + pragma_cilk_clause c_kind; + c_kind = cp_parser_cilk_simd_clause_name (parser); + if (c_kind == PRAGMA_CILK_CLAUSE_VECTORLENGTH) + clauses = cp_parser_cilk_simd_vectorlength (parser, clauses); + else if (c_kind == PRAGMA_CILK_CLAUSE_LINEAR) + clauses = cp_parser_cilk_simd_linear (parser, clauses); + else if (c_kind == PRAGMA_CILK_CLAUSE_PRIVATE) + /* Use the OpenMP 4.0 equivalent function. */ + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_PRIVATE, clauses); + else if (c_kind == PRAGMA_CILK_CLAUSE_FIRSTPRIVATE) + /* Use the OpenMP 4.0 equivalent function. */ + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FIRSTPRIVATE, + clauses); + else if (c_kind == PRAGMA_CILK_CLAUSE_LASTPRIVATE) + /* Use the OMP 4.0 equivalent function. */ + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_LASTPRIVATE, + clauses); + else if (c_kind == PRAGMA_CILK_CLAUSE_REDUCTION) + /* Use the OMP 4.0 equivalent function. */ + clauses = cp_parser_omp_clause_reduction (parser, clauses); + else + { + clauses = error_mark_node; + cp_parser_error (parser, "expected %<#pragma simd%> clause"); + break; + } + } + + cp_parser_skip_to_pragma_eol (parser, pragma_token); + + if (clauses == error_mark_node) + return error_mark_node; + else + return c_finish_cilk_clauses (clauses); +} + +/* Main entry-point for parsing Cilk Plus <#pragma simd> for loops. */ + +static void +cp_parser_cilk_simd_construct (cp_parser *parser, cp_token *pragma_token) +{ + tree clauses = cp_parser_cilk_simd_all_clauses (parser, pragma_token); + + if (clauses == error_mark_node) + return; + + if (cp_lexer_next_token_is_not_keyword (parser->lexer, RID_FOR)) + { + error_at (cp_lexer_peek_token (parser->lexer)->location, + "for statement expected"); + return; + } + + tree sb = begin_omp_structured_block (); + int save = cp_parser_begin_omp_structured_block (parser); + cp_parser_cilk_for (parser, RID_FOR, clauses); + cp_parser_end_omp_structured_block (parser, save); + add_stmt (finish_omp_structured_block (sb)); + return; +} + +/* Parses the initializer of a for/_Cilk_for statement. The initial + value is stored in *INIT, and the inital value's declaration is + stored as DECL_EXPR in *PRE_BODY. */ + +static tree +cp_parser_simd_for_init_statement (cp_parser *parser, tree *init, + tree *pre_body) +{ + cp_token *token = cp_lexer_peek_token (parser->lexer); + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + tree decl = NULL_TREE; + cp_decl_specifier_seq type_specifiers; + tree this_pre_body = push_stmt_list (); + if (token->type == CPP_SEMICOLON) + { + error_at (loc, "expected iteration declaration"); + return error_mark_node; + } + + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_STATIC) + || cp_lexer_next_token_is_keyword (parser->lexer, RID_REGISTER) + || cp_lexer_next_token_is_keyword (parser->lexer, RID_EXTERN) + || cp_lexer_next_token_is_keyword (parser->lexer, RID_MUTABLE) + || cp_lexer_next_token_is_keyword (parser->lexer, RID_THREAD)) + { + error_at (loc, "storage class is not allowed"); + cp_lexer_consume_token (parser->lexer); + } + + cp_parser_parse_tentatively (parser); + cp_parser_type_specifier_seq (parser, true, false, &type_specifiers); + if (cp_parser_parse_definitely (parser)) + { + cp_declarator *cp_decl; + tree asm_spec, attr; + cp_decl = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED, + NULL, NULL, false); + attr = cp_parser_attributes_opt (parser); + asm_spec = cp_parser_asm_specification_opt (parser); + if (cp_decl == cp_error_declarator) + cp_parser_skip_to_end_of_statement (parser); + else + { + tree pushed_scope, auto_node; + decl = start_decl (cp_decl, &type_specifiers, SD_INITIALIZED, attr, + NULL_TREE, &pushed_scope); + auto_node = type_uses_auto (TREE_TYPE (decl)); + if (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ)) + { + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) + error_at (loc, "parenthesized initialization is " + "not allowed in for-loop"); + else + { + if (!cp_parser_require (parser, CPP_EQ, RT_EQ)) + decl = error_mark_node; + } + + *init = error_mark_node; + cp_parser_skip_to_end_of_statement (parser); + } + else if (CLASS_TYPE_P (TREE_TYPE (decl)) || auto_node + || type_dependent_expression_p (decl)) + { + bool is_direct_init, is_non_constant_init; + *init = cp_parser_initializer (parser, &is_direct_init, + &is_non_constant_init); + if (auto_node) + { + TREE_TYPE (decl) + = do_auto_deduction (TREE_TYPE (decl), *init, auto_node); + if (!CLASS_TYPE_P (TREE_TYPE (decl)) + && !type_dependent_expression_p (decl)) + goto non_class; + } + cp_finish_decl (decl, *init, !is_non_constant_init, asm_spec, + LOOKUP_ONLYCONVERTING); + if (CLASS_TYPE_P (TREE_TYPE (decl))) + *init = NULL_TREE; + else + *init = pop_stmt_list (this_pre_body); + this_pre_body = NULL_TREE; + } + else + { + /* Consume the '='. */ + cp_lexer_consume_token (parser->lexer); + *init = cp_parser_assignment_expression (parser, false, NULL); + non_class: + if (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE) + *init = error_mark_node; + else + cp_finish_decl (decl, NULL_TREE, false, asm_spec, + LOOKUP_ONLYCONVERTING); + if (decl != error_mark_node) + DECL_INITIAL (decl) = (*init || *init != error_mark_node) ? + *init : NULL_TREE; + } + if (pushed_scope) + pop_scope (pushed_scope); + } + } + else + { + cp_id_kind idk; + cp_parser_parse_tentatively (parser); + decl = cp_parser_primary_expression (parser, false, false, + false, &idk); + if (!cp_parser_error_occurred (parser) && decl && DECL_P (decl) + && CLASS_TYPE_P (TREE_TYPE (decl))) + { + tree rhs, new_expr; + // ?? FIXME: I don't see any definition for *init in this + // code path. ?? + gcc_unreachable (); + cp_parser_parse_definitely (parser); + cp_parser_require (parser, CPP_EQ, RT_EQ); + rhs = cp_parser_assignment_expression (parser, false, NULL); + new_expr = build_x_modify_expr (EXPR_LOCATION (rhs), decl, + NOP_EXPR, rhs, + tf_warning_or_error); + finish_expr_stmt (new_expr); + } + else + { + if (decl != error_mark_node) + decl = NULL; + cp_parser_abort_tentative_parse (parser); + *init = cp_parser_expression (parser, false, NULL); + } + } + + if (this_pre_body) + this_pre_body = pop_stmt_list (this_pre_body); + + *pre_body = this_pre_body; + return decl; +} + +/* Top-level function to parse _Cilk_for and the for statement + following <#pragma simd>. */ + +static tree +cp_parser_cilk_for (cp_parser *parser, enum rid for_keyword, tree clauses) +{ + bool valid = true; + tree cond = NULL_TREE; + tree incr_expr = NULL_TREE; + tree init = NULL_TREE, pre_body = NULL_TREE, decl; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + + gcc_assert (for_keyword == RID_FOR); + + if (!cp_lexer_next_token_is_keyword (parser->lexer, for_keyword)) + { + if (for_keyword == RID_FOR) + cp_parser_error (parser, "for statement expected"); + else + cp_parser_error (parser, "_Cilk_for statement expected"); + return error_mark_node; + } + cp_lexer_consume_token (parser->lexer); + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + { + cp_parser_skip_to_end_of_statement (parser); + return error_mark_node; + } + + /* Parse initialization. */ + if (for_keyword == RID_FOR) + decl = cp_parser_simd_for_init_statement (parser, &init, &pre_body); + + if (decl == error_mark_node) + valid = false; + else if (!decl || (TREE_CODE (decl) != VAR_DECL + && TREE_CODE (decl) != DECL_EXPR)) + { + error_at (loc, "%s-loop initializer does not declare a variable", + for_keyword == RID_FOR ? "for" : "_Cilk_for"); + valid = false; + decl = error_mark_node; + } + else if (!processing_template_decl + && !DECL_NONTRIVIALLY_INITIALIZED_P (decl) + && !DECL_INITIAL (decl) + && !TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) + { + error_at (loc, "control variable for the %s-loop needs to " + "be initialized", + for_keyword == RID_FOR ? "for" : "_Cilk_for"); + valid = false; + } + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + { + error_at (loc, "%s-loop initializer cannot have multiple variable " + "declarations", for_keyword == RID_FOR ? "for" : "_Cilk_for"); + cp_parser_skip_to_end_of_statement (parser); + valid = false; + } + + if (!valid) + { + /* Skip to the semicolon ending the init. */ + cp_parser_skip_to_end_of_statement (parser); + } + + /* Parse condition. */ + if (!cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON)) + return error_mark_node; + if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) + { + error_at (loc, "missing condition"); + cond = error_mark_node; + } + else + { + cond = cp_parser_condition (parser); + cond = finish_cilk_for_cond (cond); + } + + if (cond == error_mark_node) + valid = false; + cp_parser_consume_semicolon_at_end_of_statement (parser); + + /* Parse increment. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)) + { + error_at (loc, "missing increment"); + incr_expr = error_mark_node; + } + else + incr_expr = cp_parser_expression (parser, false, NULL); + + if (incr_expr == error_mark_node) + { + cp_parser_skip_to_closing_parenthesis (parser, true, false, false); + valid = false; + } + + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + { + cp_parser_skip_to_end_of_statement (parser); + valid = false; + } + + if (!valid) + { + gcc_assert (sorrycount || errorcount); + return error_mark_node; + } + + if (for_keyword == RID_FOR) + { + parser->in_statement = IN_CILK_P_SIMD_FOR; + tree body = push_stmt_list (); + cp_parser_statement (parser, NULL_TREE, false, NULL); + body = pop_stmt_list (body); + + /* Check if the body satisfies all the requirement of a #pragma + simd for body. If it is invalid, then do not make the OpenMP + nodes, just return an error mark node. */ + if (!cpp_validate_cilk_plus_loop (body)) + return error_mark_node; + + return c_finish_cilk_simd_loop (loc, decl, init, cond, incr_expr, + body, clauses); + } + else + { + /* Handle _Cilk_for here when implemented. */ + gcc_unreachable (); + return NULL_TREE; + } +} + #include "gt-cp-parser.h" diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index 3d8bb742d221c..48ec8ddafa11c 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -292,6 +292,7 @@ typedef struct GTY(()) cp_parser { #define IN_OMP_BLOCK 4 #define IN_OMP_FOR 8 #define IN_IF_STMT 16 +#define IN_CILK_P_SIMD_FOR 32 unsigned char in_statement; /* TRUE if we are presently parsing the body of a switch statement. @@ -341,6 +342,15 @@ typedef struct GTY(()) cp_parser { /* The number of template parameter lists that apply directly to the current declaration. */ unsigned num_template_parameter_lists; + + /* When parsing #pragma omp declare simd, this is a vector of + the clauses, each tree is either NULL_TREE, or OMP_CLAUSE + with optional chain of other clauses. If error regarding + omp declare simd has been reported already, either + omp_declare_simd_clauses is set to NULL, or first element set + to error_mark_node. If a FUNCTION_DECL has been seen already, + first element is set to integer_zero_node. */ + vec *omp_declare_simd_clauses; } cp_parser; /* In parser.c */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 4ab64c9d826a5..3f68bef1ebb72 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -8441,6 +8441,8 @@ can_complete_type_without_circularity (tree type) return 1; } +static tree tsubst_omp_clauses (tree, 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; ARGS, COMPLAIN, IN_DECL are as tsubst. */ @@ -8482,14 +8484,27 @@ apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags, { *p = TREE_CHAIN (t); TREE_CHAIN (t) = NULL_TREE; + if (flag_openmp + && is_attribute_p ("omp declare simd", + get_attribute_name (t)) + && TREE_VALUE (t)) + { + tree clauses = TREE_VALUE (t); + clauses = tsubst_omp_clauses (clauses, true, args, + complain, in_decl); + c_omp_declare_simd_clauses_to_decls (*decl_p, clauses); + clauses = finish_omp_clauses (clauses); + TREE_VALUE (t) + = c_omp_declare_simd_clauses_to_numbers (*decl_p, clauses); + } /* If the first attribute argument is an identifier, don't pass it through tsubst. Attributes like mode, format, cleanup and several target specific attributes expect it unmodified. */ - if (TREE_VALUE (t) - && TREE_CODE (TREE_VALUE (t)) == TREE_LIST - && TREE_VALUE (TREE_VALUE (t)) - && (identifier_p (TREE_VALUE (TREE_VALUE (t))))) + else if (TREE_VALUE (t) + && TREE_CODE (TREE_VALUE (t)) == TREE_LIST + && TREE_VALUE (TREE_VALUE (t)) + && identifier_p (TREE_VALUE (TREE_VALUE (t)))) { tree chain = tsubst_expr (TREE_CHAIN (TREE_VALUE (t)), args, complain, @@ -12621,8 +12636,8 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) /* Like tsubst_copy, but specifically for OpenMP clauses. */ static tree -tsubst_omp_clauses (tree clauses, tree args, tsubst_flags_t complain, - tree in_decl) +tsubst_omp_clauses (tree clauses, bool declare_simd, + tree args, tsubst_flags_t complain, tree in_decl) { tree new_clauses = NULL, nc, oc; @@ -12655,22 +12670,53 @@ tsubst_omp_clauses (tree clauses, tree args, tsubst_flags_t complain, case OMP_CLAUSE_SCHEDULE: case OMP_CLAUSE_COLLAPSE: case OMP_CLAUSE_FINAL: + case OMP_CLAUSE_DEPEND: + case OMP_CLAUSE_FROM: + case OMP_CLAUSE_TO: + case OMP_CLAUSE_UNIFORM: + case OMP_CLAUSE_MAP: + case OMP_CLAUSE_DEVICE: + case OMP_CLAUSE_DIST_SCHEDULE: + case OMP_CLAUSE_NUM_TEAMS: + case OMP_CLAUSE_THREAD_LIMIT: + case OMP_CLAUSE_SAFELEN: + case OMP_CLAUSE_SIMDLEN: OMP_CLAUSE_OPERAND (nc, 0) = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 0), args, complain, in_decl, /*integral_constant_expression_p=*/false); break; + case OMP_CLAUSE_LINEAR: + case OMP_CLAUSE_ALIGNED: + OMP_CLAUSE_OPERAND (nc, 0) + = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 0), args, complain, + in_decl, /*integral_constant_expression_p=*/false); + OMP_CLAUSE_OPERAND (nc, 1) + = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 1), args, complain, + in_decl, /*integral_constant_expression_p=*/false); + break; + case OMP_CLAUSE_NOWAIT: case OMP_CLAUSE_ORDERED: case OMP_CLAUSE_DEFAULT: case OMP_CLAUSE_UNTIED: case OMP_CLAUSE_MERGEABLE: + case OMP_CLAUSE_INBRANCH: + case OMP_CLAUSE_NOTINBRANCH: + case OMP_CLAUSE_PROC_BIND: + case OMP_CLAUSE_FOR: + case OMP_CLAUSE_PARALLEL: + case OMP_CLAUSE_SECTIONS: + case OMP_CLAUSE_TASKGROUP: break; default: gcc_unreachable (); } } - return finish_omp_clauses (nreverse (new_clauses)); + new_clauses = nreverse (new_clauses); + if (!declare_simd) + new_clauses = finish_omp_clauses (new_clauses); + return new_clauses; } /* Like tsubst_copy_and_build, but unshare TREE_LIST nodes. */ @@ -13240,7 +13286,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, break; case OMP_PARALLEL: - tmp = tsubst_omp_clauses (OMP_PARALLEL_CLAUSES (t), + tmp = tsubst_omp_clauses (OMP_PARALLEL_CLAUSES (t), false, args, complain, in_decl); stmt = begin_omp_parallel (); RECUR (OMP_PARALLEL_BODY (t)); @@ -13249,7 +13295,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, break; case OMP_TASK: - tmp = tsubst_omp_clauses (OMP_TASK_CLAUSES (t), + tmp = tsubst_omp_clauses (OMP_TASK_CLAUSES (t), false, args, complain, in_decl); stmt = begin_omp_task (); RECUR (OMP_TASK_BODY (t)); @@ -13257,17 +13303,24 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, break; case OMP_FOR: + case OMP_SIMD: + case CILK_SIMD: + case OMP_DISTRIBUTE: { tree clauses, body, pre_body; - tree declv, initv, condv, incrv; + tree declv = NULL_TREE, initv = NULL_TREE, condv = NULL_TREE; + tree incrv = NULL_TREE; int i; - clauses = tsubst_omp_clauses (OMP_FOR_CLAUSES (t), + clauses = tsubst_omp_clauses (OMP_FOR_CLAUSES (t), false, args, complain, in_decl); - 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) + { + 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))); + } stmt = begin_omp_structured_block (); @@ -13275,17 +13328,29 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, RECUR (OMP_FOR_PRE_BODY (t)); pre_body = pop_stmt_list (pre_body); - for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (t)); i++) - tsubst_omp_for_iterator (t, i, declv, initv, condv, incrv, - &clauses, args, complain, in_decl, - integral_constant_expression_p); + 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, + integral_constant_expression_p); body = push_stmt_list (); RECUR (OMP_FOR_BODY (t)); body = pop_stmt_list (body); - t = finish_omp_for (EXPR_LOCATION (t), declv, initv, condv, incrv, - body, pre_body, clauses); + 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); + else + { + t = make_node (TREE_CODE (t)); + TREE_TYPE (t) = void_type_node; + OMP_FOR_BODY (t) = body; + OMP_FOR_PRE_BODY (t) = pre_body; + OMP_FOR_CLAUSES (t) = clauses; + SET_EXPR_LOCATION (t, EXPR_LOCATION (t)); + add_stmt (t); + } add_stmt (finish_omp_structured_block (stmt)); } @@ -13293,7 +13358,11 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, case OMP_SECTIONS: case OMP_SINGLE: - tmp = tsubst_omp_clauses (OMP_CLAUSES (t), args, complain, in_decl); + case OMP_TEAMS: + case OMP_TARGET_DATA: + case OMP_TARGET: + tmp = tsubst_omp_clauses (OMP_CLAUSES (t), false, + args, complain, in_decl); stmt = push_stmt_list (); RECUR (OMP_BODY (t)); stmt = pop_stmt_list (stmt); @@ -13304,6 +13373,14 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, add_stmt (t); break; + case OMP_TARGET_UPDATE: + tmp = tsubst_omp_clauses (OMP_TARGET_UPDATE_CLAUSES (t), false, + args, complain, in_decl); + t = copy_node (t); + OMP_CLAUSES (t) = tmp; + add_stmt (t); + break; + case OMP_SECTION: case OMP_CRITICAL: case OMP_MASTER: @@ -13332,7 +13409,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, lhs = RECUR (TREE_OPERAND (op1, 0)); rhs = RECUR (TREE_OPERAND (op1, 1)); finish_omp_atomic (OMP_ATOMIC, TREE_CODE (op1), lhs, rhs, - NULL_TREE, NULL_TREE, rhs1); + NULL_TREE, NULL_TREE, rhs1, + OMP_ATOMIC_SEQ_CST (t)); } else { @@ -13360,6 +13438,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, lhs = RECUR (TREE_OPERAND (op11, 0)); rhs = RECUR (TREE_OPERAND (op11, 1)); opcode = TREE_CODE (op11); + if (opcode == MODIFY_EXPR) + opcode = NOP_EXPR; } else { @@ -13367,7 +13447,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, lhs = RECUR (TREE_OPERAND (op1, 0)); rhs = RECUR (TREE_OPERAND (op1, 1)); } - finish_omp_atomic (code, opcode, lhs, rhs, v, lhs1, rhs1); + finish_omp_atomic (code, opcode, lhs, rhs, v, lhs1, rhs1, + OMP_ATOMIC_SEQ_CST (t)); } break; diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 4c76b80d0cd5a..b64947d5f3baf 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -4092,6 +4092,458 @@ cxx_omp_create_clause_info (tree c, tree type, bool need_default_ctor, return errorcount != save_errorcount; } +/* 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 + a TREE_LIST for array-section-subscript (TREE_PURPOSE is low-bound + expression if specified, TREE_VALUE length expression if specified, + TREE_CHAIN is what it has been specified after, or some decl. + TYPES vector is populated with array section types, MAYBE_ZERO_LEN + set to true if any of the array-section-subscript could have length + of zero (explicit or implicit), FIRST_NON_ONE is the index of the + first array-section-subscript which is known not to have length + of one. Given say: + 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_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 + case though, as some lengths could be zero. */ + +static tree +handle_omp_array_sections_1 (tree c, tree t, vec &types, + bool &maybe_zero_len, unsigned int &first_non_one, + bool &pointer_based_p) +{ + tree ret, low_bound, length, type; + if (TREE_CODE (t) != TREE_LIST) + { + if (error_operand_p (t)) + return error_mark_node; + if (type_dependent_expression_p (t)) + return NULL_TREE; + if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + if (processing_template_decl) + return NULL_TREE; + if (DECL_P (t)) + error_at (OMP_CLAUSE_LOCATION (c), + "%qD is not a variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + else + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + else if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + && TREE_CODE (t) == VAR_DECL && 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)]); + return error_mark_node; + } + t = convert_from_reference (t); + if (!processing_template_decl + && POINTER_TYPE_P (TREE_TYPE (t)) + && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP) + pointer_based_p = true; + return t; + } + + ret = handle_omp_array_sections_1 (c, TREE_CHAIN (t), types, + maybe_zero_len, first_non_one, + pointer_based_p); + if (ret == error_mark_node || ret == NULL_TREE) + return ret; + + type = TREE_TYPE (ret); + low_bound = TREE_PURPOSE (t); + length = TREE_VALUE (t); + if ((low_bound && type_dependent_expression_p (low_bound)) + || (length && type_dependent_expression_p (length))) + return NULL_TREE; + + if (low_bound == error_mark_node || length == error_mark_node) + return error_mark_node; + + if (low_bound && !INTEGRAL_TYPE_P (TREE_TYPE (low_bound))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "low bound %qE of array section does not have integral type", + low_bound); + return error_mark_node; + } + if (length && !INTEGRAL_TYPE_P (TREE_TYPE (length))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "length %qE of array section does not have integral type", + length); + return error_mark_node; + } + if (low_bound + && TREE_CODE (low_bound) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (low_bound)) + > TYPE_PRECISION (sizetype)) + low_bound = fold_convert (sizetype, low_bound); + if (length + && TREE_CODE (length) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (length)) + > TYPE_PRECISION (sizetype)) + length = fold_convert (sizetype, length); + if (low_bound == NULL_TREE) + low_bound = integer_zero_node; + + if (length != NULL_TREE) + { + if (!integer_nonzerop (length)) + maybe_zero_len = true; + if (first_non_one == types.length () + && (TREE_CODE (length) != INTEGER_CST || integer_onep (length))) + first_non_one++; + } + if (TREE_CODE (type) == ARRAY_TYPE) + { + if (length == NULL_TREE + && (TYPE_DOMAIN (type) == NULL_TREE + || TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "for unknown bound array type length expression is " + "not optional"); + return error_mark_node; + } + if (TREE_CODE (low_bound) == INTEGER_CST + && tree_int_cst_sgn (low_bound) == -1) + { + error_at (OMP_CLAUSE_LOCATION (c), + "negative low bound in array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + 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 (TYPE_DOMAIN (type) + && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) + && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) + == INTEGER_CST) + { + tree size = size_binop (PLUS_EXPR, + TYPE_MAX_VALUE (TYPE_DOMAIN (type)), + size_one_node); + if (TREE_CODE (low_bound) == INTEGER_CST) + { + if (tree_int_cst_lt (size, low_bound)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "low bound %qE above array section size " + "in %qs clause", low_bound, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + if (tree_int_cst_equal (size, low_bound)) + maybe_zero_len = true; + else if (length == NULL_TREE + && first_non_one == types.length () + && tree_int_cst_equal + (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), + low_bound)) + first_non_one++; + } + else if (length == NULL_TREE) + { + maybe_zero_len = true; + if (first_non_one == types.length ()) + first_non_one++; + } + if (length && TREE_CODE (length) == INTEGER_CST) + { + if (tree_int_cst_lt (size, length)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "length %qE above array section size " + "in %qs clause", length, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + if (TREE_CODE (low_bound) == INTEGER_CST) + { + tree lbpluslen + = size_binop (PLUS_EXPR, + fold_convert (sizetype, low_bound), + fold_convert (sizetype, length)); + if (TREE_CODE (lbpluslen) == INTEGER_CST + && tree_int_cst_lt (size, lbpluslen)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "high bound %qE above array section size " + "in %qs clause", lbpluslen, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + } + } + } + else if (length == NULL_TREE) + { + maybe_zero_len = true; + if (first_non_one == types.length ()) + first_non_one++; + } + + /* For [lb:] we will need to evaluate lb more than once. */ + if (length == NULL_TREE && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND) + { + tree lb = cp_save_expr (low_bound); + if (lb != low_bound) + { + TREE_PURPOSE (t) = lb; + low_bound = lb; + } + } + } + else if (TREE_CODE (type) == POINTER_TYPE) + { + if (length == NULL_TREE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "for pointer type length expression is not optional"); + 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 + && TREE_CODE (TREE_CHAIN (t)) == TREE_LIST) + { + error_at (OMP_CLAUSE_LOCATION (c), + "array section is not contiguous in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + } + else + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE does not have pointer or array type", ret); + return error_mark_node; + } + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND) + types.safe_push (TREE_TYPE (ret)); + /* For pointer based array sections we will need to evaluate lb more + than once. */ + if (pointer_based_p) + { + tree lb = cp_save_expr (low_bound); + if (lb != low_bound) + { + TREE_PURPOSE (t) = lb; + low_bound = lb; + } + } + ret = grok_array_decl (OMP_CLAUSE_LOCATION (c), ret, low_bound, false); + return ret; +} + +/* Handle array sections for clause C. */ + +static bool +handle_omp_array_sections (tree c) +{ + bool maybe_zero_len = false; + bool pointer_based_p = false; + unsigned int first_non_one = 0; + vec types = vNULL; + tree first = handle_omp_array_sections_1 (c, OMP_CLAUSE_DECL (c), types, + maybe_zero_len, first_non_one, + pointer_based_p); + if (first == error_mark_node) + { + types.release (); + return true; + } + if (first == NULL_TREE) + { + types.release (); + return false; + } + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND) + { + tree t = OMP_CLAUSE_DECL (c); + tree tem = NULL_TREE; + types.release (); + if (processing_template_decl) + return false; + /* Need to evaluate side effects in the length expressions + if any. */ + while (TREE_CODE (t) == TREE_LIST) + { + if (TREE_VALUE (t) && TREE_SIDE_EFFECTS (TREE_VALUE (t))) + { + if (tem == NULL_TREE) + tem = TREE_VALUE (t); + else + tem = build2 (COMPOUND_EXPR, TREE_TYPE (tem), + TREE_VALUE (t), tem); + } + t = TREE_CHAIN (t); + } + if (tem) + first = build2 (COMPOUND_EXPR, TREE_TYPE (first), tem, first); + OMP_CLAUSE_DECL (c) = first; + } + else + { + unsigned int num = types.length (), i; + tree t, side_effects = NULL_TREE, size = NULL_TREE; + tree condition = NULL_TREE; + + if (int_size_in_bytes (TREE_TYPE (first)) <= 0) + maybe_zero_len = true; + if (processing_template_decl && maybe_zero_len) + { + types.release (); + return false; + } + + for (i = num, t = OMP_CLAUSE_DECL (c); i > 0; + t = TREE_CHAIN (t)) + { + tree low_bound = TREE_PURPOSE (t); + tree length = TREE_VALUE (t); + + i--; + if (low_bound + && TREE_CODE (low_bound) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (low_bound)) + > TYPE_PRECISION (sizetype)) + low_bound = fold_convert (sizetype, low_bound); + if (length + && TREE_CODE (length) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (length)) + > TYPE_PRECISION (sizetype)) + length = fold_convert (sizetype, length); + if (low_bound == NULL_TREE) + low_bound = integer_zero_node; + if (!maybe_zero_len && i > first_non_one) + { + if (integer_nonzerop (low_bound)) + goto do_warn_noncontiguous; + if (length != NULL_TREE + && TREE_CODE (length) == INTEGER_CST + && TYPE_DOMAIN (types[i]) + && TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])) + && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (types[i]))) + == INTEGER_CST) + { + tree size; + size = size_binop (PLUS_EXPR, + TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])), + size_one_node); + if (!tree_int_cst_equal (length, size)) + { + do_warn_noncontiguous: + error_at (OMP_CLAUSE_LOCATION (c), + "array section is not contiguous in %qs " + "clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + types.release (); + return true; + } + } + if (!processing_template_decl + && length != NULL_TREE + && TREE_SIDE_EFFECTS (length)) + { + if (side_effects == NULL_TREE) + side_effects = length; + else + side_effects = build2 (COMPOUND_EXPR, + TREE_TYPE (side_effects), + length, side_effects); + } + } + else if (processing_template_decl) + continue; + else + { + tree l; + + if (i > first_non_one && length && integer_nonzerop (length)) + continue; + if (length) + l = fold_convert (sizetype, length); + else + { + l = size_binop (PLUS_EXPR, + TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])), + size_one_node); + l = size_binop (MINUS_EXPR, l, + fold_convert (sizetype, low_bound)); + } + if (i > first_non_one) + { + l = fold_build2 (NE_EXPR, boolean_type_node, l, + size_zero_node); + if (condition == NULL_TREE) + condition = l; + else + condition = fold_build2 (BIT_AND_EXPR, boolean_type_node, + l, condition); + } + else if (size == NULL_TREE) + { + size = size_in_bytes (TREE_TYPE (types[i])); + size = size_binop (MULT_EXPR, size, l); + if (condition) + size = fold_build3 (COND_EXPR, sizetype, condition, + size, size_zero_node); + } + else + size = size_binop (MULT_EXPR, size, l); + } + } + types.release (); + if (!processing_template_decl) + { + if (side_effects) + size = build2 (COMPOUND_EXPR, sizetype, side_effects, size); + OMP_CLAUSE_DECL (c) = first; + OMP_CLAUSE_SIZE (c) = size; + if (pointer_based_p) + { + tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), + OMP_CLAUSE_MAP); + OMP_CLAUSE_MAP_KIND (c2) = OMP_CLAUSE_MAP_POINTER; + if (!cxx_mark_addressable (t)) + return false; + OMP_CLAUSE_DECL (c2) = t; + t = build_fold_addr_expr (first); + t = fold_convert_loc (OMP_CLAUSE_LOCATION (c), + build_pointer_type (char_type_node), t); + t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR, + ptrdiff_type_node, t, + fold_convert_loc (OMP_CLAUSE_LOCATION (c), + TREE_TYPE (t), + OMP_CLAUSE_DECL (c2))); + OMP_CLAUSE_SIZE (c2) = t; + OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c); + OMP_CLAUSE_CHAIN (c) = c2; + } + } + } + return false; +} + /* For all elements of CLAUSES, validate them vs OpenMP constraints. Remove any elements from the list that are invalid. */ @@ -4099,13 +4551,16 @@ tree finish_omp_clauses (tree clauses) { bitmap_head generic_head, firstprivate_head, lastprivate_head; + bitmap_head aligned_head; tree c, t, *pc = &clauses; const char *name; + bool branch_seen = false; bitmap_obstack_initialize (NULL); bitmap_initialize (&generic_head, &bitmap_default_obstack); bitmap_initialize (&firstprivate_head, &bitmap_default_obstack); bitmap_initialize (&lastprivate_head, &bitmap_default_obstack); + bitmap_initialize (&aligned_head, &bitmap_default_obstack); for (pc = &clauses, c = clauses; c ; c = *pc) { @@ -4128,6 +4583,49 @@ finish_omp_clauses (tree clauses) case OMP_CLAUSE_COPYIN: name = "copyin"; goto check_dup_generic; + case OMP_CLAUSE_LINEAR: + name = "linear"; + t = OMP_CLAUSE_DECL (c); + if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t)) + && TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE) + { + error ("linear clause applied to non-integral non-pointer"); + remove = true; + break; + } + t = OMP_CLAUSE_LINEAR_STEP (c); + if (t == NULL_TREE) + t = integer_one_node; + if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("linear step expression must be integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + { + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + if (TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c))) + == POINTER_TYPE) + { + t = pointer_int_sum (OMP_CLAUSE_LOCATION (c), PLUS_EXPR, + OMP_CLAUSE_DECL (c), t); + t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), + MINUS_EXPR, sizetype, t, + OMP_CLAUSE_DECL (c)); + if (t == error_mark_node) + remove = true; + } + } + 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) @@ -4255,12 +4753,293 @@ finish_omp_clauses (tree clauses) } break; + case OMP_CLAUSE_SIMDLEN: + case OMP_CLAUSE_SAFELEN: + t = OMP_CLAUSE_OPERAND (c, 0); + if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("%qs length expression must be integral", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else + { + t = mark_rvalue_use (t); + t = maybe_constant_value (t); + if (!processing_template_decl) + { + if (TREE_CODE (t) != INTEGER_CST + || tree_int_cst_sgn (t) != 1) + { + error ("%qs length expression must be positive constant" + " integer expression", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + } + OMP_CLAUSE_OPERAND (c, 0) = t; + } + break; + + case OMP_CLAUSE_NUM_TEAMS: + t = OMP_CLAUSE_NUM_TEAMS_EXPR (c); + if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("% expression must be integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + OMP_CLAUSE_NUM_TEAMS_EXPR (c) = t; + } + break; + + case OMP_CLAUSE_THREAD_LIMIT: + t = OMP_CLAUSE_THREAD_LIMIT_EXPR (c); + if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("% expression must be integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + OMP_CLAUSE_THREAD_LIMIT_EXPR (c) = t; + } + break; + + case OMP_CLAUSE_DEVICE: + t = OMP_CLAUSE_DEVICE_ID (c); + if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("% id must be integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + OMP_CLAUSE_DEVICE_ID (c) = t; + } + break; + + case OMP_CLAUSE_DIST_SCHEDULE: + t = OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (c); + if (t == NULL) + ; + else if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("% chunk size expression must be " + "integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (c) = t; + } + break; + + case OMP_CLAUSE_ALIGNED: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + if (processing_template_decl) + break; + if (DECL_P (t)) + error ("%qD is not a variable in % clause", t); + else + error ("%qE is not a variable in % clause", t); + remove = true; + } + else if (bitmap_bit_p (&aligned_head, DECL_UID (t))) + { + error ("%qD appears more than once in % clauses", t); + remove = true; + } + else + bitmap_set_bit (&aligned_head, DECL_UID (t)); + t = OMP_CLAUSE_ALIGNED_ALIGNMENT (c); + if (t == error_mark_node) + remove = true; + else if (t == NULL_TREE) + break; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("% clause alignment expression must " + "be integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + t = maybe_constant_value (t); + if (!processing_template_decl) + { + if (TREE_CODE (t) != INTEGER_CST + || tree_int_cst_sgn (t) != 1) + { + error ("% clause alignment expression must be " + "positive constant integer expression"); + remove = true; + } + } + OMP_CLAUSE_ALIGNED_ALIGNMENT (c) = t; + } + break; + + case OMP_CLAUSE_DEPEND: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) == TREE_LIST) + { + if (handle_omp_array_sections (c)) + remove = true; + break; + } + if (t == error_mark_node) + remove = true; + else if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + if (processing_template_decl) + break; + if (DECL_P (t)) + error ("%qD is not a variable in % clause", t); + else + error ("%qE is not a variable in % clause", t); + remove = true; + } + else if (!processing_template_decl + && !cxx_mark_addressable (t)) + remove = true; + break; + + case OMP_CLAUSE_MAP: + case OMP_CLAUSE_TO: + case OMP_CLAUSE_FROM: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) == TREE_LIST) + { + if (handle_omp_array_sections (c)) + remove = true; + else + { + t = OMP_CLAUSE_DECL (c); + if (!cp_omp_mappable_type (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "array section does not have mappable type " + "in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + } + break; + } + if (t == error_mark_node) + remove = true; + else if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + if (processing_template_decl) + break; + if (DECL_P (t)) + error ("%qD is not a variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + else + error ("%qE is not a variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (TREE_CODE (t) == VAR_DECL && DECL_THREAD_LOCAL_P (t)) + { + error ("%qD is threadprivate variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (!processing_template_decl + && TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE + && !cxx_mark_addressable (t)) + remove = true; + else if (!cp_omp_mappable_type ((TREE_CODE (TREE_TYPE (t)) + == REFERENCE_TYPE) + ? TREE_TYPE (TREE_TYPE (t)) + : 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; + } + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP) + break; + else if (bitmap_bit_p (&generic_head, DECL_UID (t))) + { + error ("%qD appears more than once in motion clauses", t); + remove = true; + } + else + bitmap_set_bit (&generic_head, DECL_UID (t)); + break; + + case OMP_CLAUSE_UNIFORM: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) != PARM_DECL) + { + if (processing_template_decl) + break; + if (DECL_P (t)) + error ("%qD is not an argument in % clause", t); + else + error ("%qE is not an argument in % clause", t); + remove = true; + } + break; + case OMP_CLAUSE_NOWAIT: case OMP_CLAUSE_ORDERED: case OMP_CLAUSE_DEFAULT: case OMP_CLAUSE_UNTIED: case OMP_CLAUSE_COLLAPSE: case OMP_CLAUSE_MERGEABLE: + case OMP_CLAUSE_PARALLEL: + case OMP_CLAUSE_FOR: + case OMP_CLAUSE_SECTIONS: + case OMP_CLAUSE_TASKGROUP: + case OMP_CLAUSE_PROC_BIND: + break; + + case OMP_CLAUSE_INBRANCH: + case OMP_CLAUSE_NOTINBRANCH: + if (branch_seen) + { + error ("% clause is incompatible with " + "%"); + remove = true; + } + branch_seen = true; break; default: @@ -4447,6 +5226,90 @@ finish_omp_clauses (tree clauses) return clauses; } +/* Finalize #pragma omp declare simd clauses after FNDECL has been parsed, + and put that into "omp declare simd" attribute. */ + +void +finish_omp_declare_simd (tree fndecl, vec *clauses) +{ + tree cl; + int i; + + if (TREE_CODE (fndecl) != FUNCTION_DECL) + return; + if ((*clauses)[0] == integer_zero_node) + { + error_at (DECL_SOURCE_LOCATION (fndecl), + "%<#pragma omp declare simd%> not immediately followed by " + "a single function declaration or definition"); + (*clauses)[0] = error_mark_node; + return; + } + if ((*clauses)[0] == error_mark_node) + return; + + FOR_EACH_VEC_SAFE_ELT (clauses, i, cl) + { + tree c, *pc, decl, name; + for (pc = &cl, c = cl; c; c = *pc) + { + bool remove = false; + switch (OMP_CLAUSE_CODE (c)) + { + case OMP_CLAUSE_UNIFORM: + case OMP_CLAUSE_LINEAR: + case OMP_CLAUSE_ALIGNED: + case OMP_CLAUSE_REDUCTION: + name = OMP_CLAUSE_DECL (c); + if (name == error_mark_node) + remove = true; + else + { + for (decl = DECL_ARGUMENTS (fndecl); decl; + decl = TREE_CHAIN (decl)) + if (DECL_NAME (decl) == name) + break; + if (decl == NULL_TREE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a function parameter", name); + remove = true; + } + else + OMP_CLAUSE_DECL (c) = decl; + } + break; + default: + break; + } + if (remove) + *pc = OMP_CLAUSE_CHAIN (c); + else + pc = &OMP_CLAUSE_CHAIN (c); + } + cl = finish_omp_clauses (cl); + cl = c_omp_declare_simd_clauses_to_numbers (fndecl, cl); + if (!processing_template_decl) + { + for (c = lookup_attribute ("omp declare simd", + DECL_ATTRIBUTES (fndecl)); + c; c = lookup_attribute ("omp declare simd", + TREE_CHAIN (c))) + if (omp_declare_simd_clauses_equal (TREE_VALUE (c), cl)) + break; + if (c) + continue; + } + c = build_tree_list (get_identifier ("omp declare simd"), cl); + TREE_CHAIN (c) = DECL_ATTRIBUTES (fndecl); + if (processing_template_decl) + ATTR_IS_DEPENDENT (c) = 1; + DECL_ATTRIBUTES (fndecl) = c; + } + + (*clauses)[0] = integer_zero_node; +} + /* For all variables in the tree_list VARS, mark them as thread local. */ void @@ -4815,8 +5678,8 @@ handle_omp_for_class_iterator (int i, location_t locus, tree declv, tree initv, sk_omp scope. */ tree -finish_omp_for (location_t locus, 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 initv, + tree condv, tree incrv, tree body, tree pre_body, tree clauses) { tree omp_for = NULL, orig_incr = NULL; tree decl, init, cond, incr; @@ -4885,7 +5748,7 @@ finish_omp_for (location_t locus, tree declv, tree initv, tree condv, { tree stmt; - stmt = make_node (OMP_FOR); + stmt = make_node (code); for (i = 0; i < TREE_VEC_LENGTH (declv); i++) { @@ -4943,6 +5806,12 @@ finish_omp_for (location_t locus, tree declv, tree initv, tree condv, if (CLASS_TYPE_P (TREE_TYPE (decl))) { + if (code == OMP_SIMD || code == CILK_SIMD) + { + error_at (elocus, "%<#pragma omp simd%> used with class " + "iteration variable %qE", decl); + return NULL; + } if (handle_omp_for_class_iterator (i, locus, declv, initv, condv, incrv, &body, &pre_body, clauses)) return NULL; @@ -4997,7 +5866,7 @@ finish_omp_for (location_t locus, tree declv, tree initv, tree condv, if (IS_EMPTY_STMT (pre_body)) pre_body = NULL; - omp_for = c_finish_omp_for (locus, declv, initv, condv, incrv, + omp_for = c_finish_omp_for (locus, code, declv, initv, condv, incrv, body, pre_body); if (omp_for == NULL) @@ -5042,7 +5911,7 @@ finish_omp_for (location_t locus, tree declv, tree initv, tree condv, void finish_omp_atomic (enum tree_code code, enum tree_code opcode, tree lhs, - tree rhs, tree v, tree lhs1, tree rhs1) + tree rhs, tree v, tree lhs1, tree rhs1, bool seq_cst) { tree orig_lhs; tree orig_rhs; @@ -5084,8 +5953,36 @@ finish_omp_atomic (enum tree_code code, enum tree_code opcode, tree lhs, } if (!dependent_p) { + bool swapped = false; + if (rhs1 && cp_tree_equal (lhs, rhs)) + { + tree tem = rhs; + rhs = rhs1; + rhs1 = tem; + swapped = !commutative_tree_code (opcode); + } + if (rhs1 && !cp_tree_equal (lhs, rhs1)) + { + if (code == OMP_ATOMIC) + error ("%<#pragma omp atomic update%> uses two different " + "expressions for memory"); + else + error ("%<#pragma omp atomic capture%> uses two different " + "expressions for memory"); + return; + } + if (lhs1 && !cp_tree_equal (lhs, lhs1)) + { + if (code == OMP_ATOMIC) + error ("%<#pragma omp atomic update%> uses two different " + "expressions for memory"); + else + error ("%<#pragma omp atomic capture%> uses two different " + "expressions for memory"); + return; + } stmt = c_finish_omp_atomic (input_location, code, opcode, lhs, rhs, - v, lhs1, rhs1); + v, lhs1, rhs1, swapped, seq_cst); if (stmt == error_mark_node) return; } @@ -5095,6 +5992,7 @@ finish_omp_atomic (enum tree_code code, enum tree_code opcode, tree lhs, { stmt = build_min_nt_loc (EXPR_LOCATION (orig_lhs), OMP_ATOMIC_READ, orig_lhs); + OMP_ATOMIC_SEQ_CST (stmt) = seq_cst; stmt = build2 (MODIFY_EXPR, void_type_node, orig_v, stmt); } else @@ -5110,10 +6008,12 @@ finish_omp_atomic (enum tree_code code, enum tree_code opcode, tree lhs, { stmt = build_min_nt_loc (EXPR_LOCATION (orig_lhs1), code, orig_lhs1, stmt); + OMP_ATOMIC_SEQ_CST (stmt) = seq_cst; stmt = build2 (MODIFY_EXPR, void_type_node, orig_v, stmt); } } stmt = build2 (OMP_ATOMIC, void_type_node, integer_zero_node, stmt); + OMP_ATOMIC_SEQ_CST (stmt) = seq_cst; } add_stmt (stmt); } @@ -5157,6 +6057,83 @@ finish_omp_taskyield (void) release_tree_vector (vec); finish_expr_stmt (stmt); } + +void +finish_omp_taskgroup (tree block_stmt) +{ + tree fn = builtin_decl_explicit (BUILT_IN_GOMP_TASKGROUP_START); + vec *vec = make_tree_vector (); + tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error); + finish_expr_stmt (stmt); + finish_expr_stmt (block_stmt); + fn = builtin_decl_explicit (BUILT_IN_GOMP_TASKGROUP_END); + stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error); + finish_expr_stmt (stmt); + release_tree_vector (vec); +} + +void +finish_omp_cancel (tree clauses) +{ + tree fn = builtin_decl_explicit (BUILT_IN_GOMP_CANCEL); + int mask = 0; + if (find_omp_clause (clauses, OMP_CLAUSE_PARALLEL)) + mask = 1; + else if (find_omp_clause (clauses, OMP_CLAUSE_FOR)) + mask = 2; + else if (find_omp_clause (clauses, OMP_CLAUSE_SECTIONS)) + mask = 4; + else if (find_omp_clause (clauses, OMP_CLAUSE_TASKGROUP)) + mask = 8; + else + { + error ("%<#pragma omp cancel must specify one of " + "%, %, % or % clauses"); + return; + } + vec *vec + = make_tree_vector_single (build_int_cst (integer_type_node, mask)); + tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error); + release_tree_vector (vec); + tree ifc = find_omp_clause (clauses, OMP_CLAUSE_IF); + if (ifc != NULL_TREE) + stmt = build3 (COND_EXPR, void_type_node, OMP_CLAUSE_IF_EXPR (ifc), + stmt, NULL_TREE); + finish_expr_stmt (stmt); +} + +void +finish_omp_cancellation_point (tree clauses) +{ + tree fn = builtin_decl_explicit (BUILT_IN_GOMP_CANCELLATION_POINT); + int mask = 0; + if (find_omp_clause (clauses, OMP_CLAUSE_PARALLEL)) + mask = 1; + else if (find_omp_clause (clauses, OMP_CLAUSE_FOR)) + mask = 2; + else if (find_omp_clause (clauses, OMP_CLAUSE_SECTIONS)) + mask = 4; + else if (find_omp_clause (clauses, OMP_CLAUSE_TASKGROUP)) + mask = 8; + else + { + error ("%<#pragma omp cancellation point must specify one of " + "%, %, % or % clauses"); + return; + } + vec *vec + = make_tree_vector_single (build_int_cst (integer_type_node, mask)); + tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error); + release_tree_vector (vec); + finish_expr_stmt (stmt); +} + +/* Perform any canonicalization of the conditional in a Cilk for loop. */ +tree +finish_cilk_for_cond (tree cond) +{ + return cp_truthvalue_conversion (cond); +} /* Begin a __transaction_atomic or __transaction_relaxed statement. If PCOMPOUND is non-null, this is for a function-transaction-block, and we diff --git a/gcc/fortran/ChangeLog.gomp b/gcc/fortran/ChangeLog.gomp new file mode 100644 index 0000000000000..78870f73c5593 --- /dev/null +++ b/gcc/fortran/ChangeLog.gomp @@ -0,0 +1,19 @@ +2013-04-10 Jakub Jelinek + + * f95-lang.c (DEF_FUNCTION_TYPE_8): Define. + * types.def (DEF_FUNCTION_TYPE_8): Document. + (BT_FN_VOID_OMPFN_PTR_UINT, BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG, + BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG): Remove. + (BT_FN_VOID_OMPFN_PTR_UINT_UINT_UINT, + BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_UINT, + BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT): New. + +2013-03-27 Jakub Jelinek + + * f95-lang.c (ATTR_NULL): Define. + +Copyright (C) 2013 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/gcc/fortran/f95-lang.c b/gcc/fortran/f95-lang.c index 30cbfe594769f..b89e73f7982f1 100644 --- a/gcc/fortran/f95-lang.c +++ b/gcc/fortran/f95-lang.c @@ -531,7 +531,8 @@ gfc_builtin_function (tree decl) return decl; } -/* So far we need just these 4 attribute types. */ +/* So far we need just these 6 attribute types. */ +#define ATTR_NULL 0 #define ATTR_NOTHROW_LEAF_LIST (ECF_NOTHROW | ECF_LEAF) #define ATTR_NOTHROW_LEAF_MALLOC_LIST (ECF_NOTHROW | ECF_LEAF | ECF_MALLOC) #define ATTR_CONST_NOTHROW_LEAF_LIST (ECF_NOTHROW | ECF_LEAF | ECF_CONST) @@ -618,6 +619,7 @@ gfc_init_builtin_functions (void) #define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME, #define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) NAME, #define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) NAME, +#define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8) NAME, #define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME, #define DEF_POINTER_TYPE(NAME, TYPE) NAME, #include "types.def" @@ -630,6 +632,7 @@ gfc_init_builtin_functions (void) #undef DEF_FUNCTION_TYPE_5 #undef DEF_FUNCTION_TYPE_6 #undef DEF_FUNCTION_TYPE_7 +#undef DEF_FUNCTION_TYPE_8 #undef DEF_FUNCTION_TYPE_VAR_0 #undef DEF_POINTER_TYPE BT_LAST @@ -992,6 +995,19 @@ gfc_init_builtin_functions (void) builtin_types[(int) ARG6], \ builtin_types[(int) ARG7], \ NULL_TREE); +#define DEF_FUNCTION_TYPE_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8) \ + 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], \ + NULL_TREE); #define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \ builtin_types[(int) ENUM] \ = build_varargs_function_type_list (builtin_types[(int) RETURN], \ diff --git a/gcc/fortran/types.def b/gcc/fortran/types.def index e4cd1d18eb955..e1f3da1522af0 100644 --- a/gcc/fortran/types.def +++ b/gcc/fortran/types.def @@ -34,6 +34,8 @@ along with GCC; see the file COPYING3. If not see DEF_FUNCTION_TYPE_5 (ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) DEF_FUNCTION_TYPE_6 (ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) DEF_FUNCTION_TYPE_7 (ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) + DEF_FUNCTION_TYPE_8 (ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, + ARG8) These macros describe function types. ENUM is as above. The RETURN type is one of the enumerals already defined. ARG1, ARG2, @@ -137,8 +139,6 @@ DEF_FUNCTION_TYPE_3 (BT_FN_I4_VPTR_I4_I4, BT_I4, BT_VOLATILE_PTR, BT_I4, BT_I4) DEF_FUNCTION_TYPE_3 (BT_FN_I8_VPTR_I8_I8, BT_I8, BT_VOLATILE_PTR, BT_I8, BT_I8) DEF_FUNCTION_TYPE_3 (BT_FN_I16_VPTR_I16_I16, BT_I16, BT_VOLATILE_PTR, BT_I16, BT_I16) -DEF_FUNCTION_TYPE_3 (BT_FN_VOID_OMPFN_PTR_UINT, BT_VOID, BT_PTR_FN_VOID_PTR, - BT_PTR, BT_UINT) DEF_FUNCTION_TYPE_3 (BT_FN_I1_VPTR_I1_INT, BT_I1, BT_VOLATILE_PTR, BT_I1, BT_INT) DEF_FUNCTION_TYPE_3 (BT_FN_I2_VPTR_I2_INT, BT_I2, BT_VOLATILE_PTR, BT_I2, BT_INT) DEF_FUNCTION_TYPE_3 (BT_FN_I4_VPTR_I4_INT, BT_I4, BT_VOLATILE_PTR, BT_I4, BT_INT) @@ -159,6 +159,9 @@ DEF_FUNCTION_TYPE_4 (BT_FN_VOID_SIZE_VPTR_PTR_INT, BT_VOID, BT_SIZE, 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_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_LONG_LONG_LONG_LONGPTR_LONGPTR, BT_BOOL, BT_LONG, BT_LONG, BT_LONG, BT_PTR_LONG, BT_PTR_LONG) @@ -168,9 +171,6 @@ DEF_FUNCTION_TYPE_5 (BT_FN_VOID_SIZE_VPTR_PTR_PTR_INT, BT_VOID, BT_SIZE, DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_LONG_LONG_LONG_LONG_LONGPTR_LONGPTR, BT_BOOL, BT_LONG, BT_LONG, BT_LONG, BT_LONG, BT_PTR_LONG, BT_PTR_LONG) -DEF_FUNCTION_TYPE_6 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG, - BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, - BT_LONG, BT_LONG, BT_LONG) DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULLPTR_ULLPTR, BT_BOOL, BT_BOOL, BT_ULONGLONG, BT_ULONGLONG, BT_ULONGLONG, BT_PTR_ULONGLONG, BT_PTR_ULONGLONG) @@ -192,9 +192,9 @@ DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_VPTR_PTR_I16_BOOL_INT_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_7 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG, +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_LONG, BT_LONG, BT_LONG, BT_LONG) + BT_LONG, BT_LONG, BT_LONG, BT_UINT) DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT, BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_PTR_FN_VOID_PTR_PTR, BT_LONG, BT_LONG, @@ -204,4 +204,8 @@ DEF_FUNCTION_TYPE_7 (BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULL_ULLPTR_ULLPTR, BT_ULONGLONG, BT_ULONGLONG, BT_PTR_ULONGLONG, BT_PTR_ULONGLONG) +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_VAR_0 (BT_FN_VOID_VAR, BT_VOID) diff --git a/gcc/function.h b/gcc/function.h index c651f5037f8b1..d1f4ffc1fd4cc 100644 --- a/gcc/function.h +++ b/gcc/function.h @@ -650,6 +650,14 @@ struct GTY(()) function { adjusts one of its arguments and forwards to another function. */ unsigned int is_thunk : 1; + + /* Nonzero if the current function contains any loops with + loop->force_vect set. */ + unsigned int has_force_vect_loops : 1; + + /* Nonzero if the current function contains any loops with + nonzero value in loop->simduid. */ + unsigned int has_simduid_loops : 1; }; /* Add the decl D to the local_decls list of FUN. */ diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c index 64cc031785d37..5d0e90b322ffe 100644 --- a/gcc/gimple-low.c +++ b/gcc/gimple-low.c @@ -448,6 +448,8 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data) case GIMPLE_OMP_PARALLEL: case GIMPLE_OMP_TASK: + case GIMPLE_OMP_TARGET: + case GIMPLE_OMP_TEAMS: data->cannot_fallthru = false; lower_omp_directive (gsi, data); data->cannot_fallthru = false; diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c index ddb086c571501..8c92b5bb18d29 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -1101,8 +1101,26 @@ dump_gimple_omp_for (pretty_printer *buffer, gimple gs, int spc, int flags) if (flags & TDF_RAW) { - dump_gimple_fmt (buffer, spc, flags, "%G <%+BODY <%S>%nCLAUSES <", gs, - gimple_omp_body (gs)); + const char *kind; + switch (gimple_omp_for_kind (gs)) + { + case GF_OMP_FOR_KIND_FOR: + kind = ""; + break; + case GF_OMP_FOR_KIND_SIMD: + kind = " simd"; + break; + case GF_OMP_FOR_KIND_CILKSIMD: + kind = " cilksimd"; + break; + case GF_OMP_FOR_KIND_DISTRIBUTE: + kind = " distribute"; + break; + default: + gcc_unreachable (); + } + dump_gimple_fmt (buffer, spc, flags, "%G%s <%+BODY <%S>%nCLAUSES <", gs, + kind, gimple_omp_body (gs)); dump_omp_clauses (buffer, gimple_omp_for_clauses (gs), spc, flags); dump_gimple_fmt (buffer, spc, flags, " >,"); for (i = 0; i < gimple_omp_for_collapse (gs); i++) @@ -1118,7 +1136,23 @@ dump_gimple_omp_for (pretty_printer *buffer, gimple gs, int spc, int flags) } else { - pp_string (buffer, "#pragma omp for"); + switch (gimple_omp_for_kind (gs)) + { + case GF_OMP_FOR_KIND_FOR: + pp_string (buffer, "#pragma omp for"); + break; + case GF_OMP_FOR_KIND_SIMD: + pp_string (buffer, "#pragma omp simd"); + break; + case GF_OMP_FOR_KIND_CILKSIMD: + pp_string (buffer, "#pragma simd"); + break; + case GF_OMP_FOR_KIND_DISTRIBUTE: + pp_string (buffer, "#pragma omp distribute"); + break; + default: + gcc_unreachable (); + } dump_omp_clauses (buffer, gimple_omp_for_clauses (gs), spc, flags); for (i = 0; i < gimple_omp_for_collapse (gs); i++) { @@ -1230,6 +1264,78 @@ dump_gimple_omp_single (pretty_printer *buffer, gimple gs, int spc, int flags) } } +/* Dump a GIMPLE_OMP_TARGET tuple on the pretty_printer BUFFER. */ + +static void +dump_gimple_omp_target (pretty_printer *buffer, gimple gs, int spc, int flags) +{ + const char *kind; + switch (gimple_omp_target_kind (gs)) + { + case GF_OMP_TARGET_KIND_REGION: + kind = ""; + break; + case GF_OMP_TARGET_KIND_DATA: + kind = " data"; + break; + case GF_OMP_TARGET_KIND_UPDATE: + kind = " update"; + break; + default: + gcc_unreachable (); + } + if (flags & TDF_RAW) + { + dump_gimple_fmt (buffer, spc, flags, "%G%s <%+BODY <%S>%nCLAUSES <", gs, + kind, gimple_omp_body (gs)); + dump_omp_clauses (buffer, gimple_omp_target_clauses (gs), spc, flags); + dump_gimple_fmt (buffer, spc, flags, " >"); + } + else + { + pp_string (buffer, "#pragma omp target"); + pp_string (buffer, kind); + dump_omp_clauses (buffer, gimple_omp_target_clauses (gs), spc, flags); + if (!gimple_seq_empty_p (gimple_omp_body (gs))) + { + newline_and_indent (buffer, spc + 2); + pp_character (buffer, '{'); + pp_newline (buffer); + dump_gimple_seq (buffer, gimple_omp_body (gs), spc + 4, flags); + newline_and_indent (buffer, spc + 2); + pp_character (buffer, '}'); + } + } +} + +/* Dump a GIMPLE_OMP_TEAMS tuple on the pretty_printer BUFFER. */ + +static void +dump_gimple_omp_teams (pretty_printer *buffer, gimple gs, int spc, int flags) +{ + if (flags & TDF_RAW) + { + dump_gimple_fmt (buffer, spc, flags, "%G <%+BODY <%S>%nCLAUSES <", gs, + gimple_omp_body (gs)); + dump_omp_clauses (buffer, gimple_omp_teams_clauses (gs), spc, flags); + dump_gimple_fmt (buffer, spc, flags, " >"); + } + else + { + pp_string (buffer, "#pragma omp teams"); + dump_omp_clauses (buffer, gimple_omp_teams_clauses (gs), spc, flags); + if (!gimple_seq_empty_p (gimple_omp_body (gs))) + { + newline_and_indent (buffer, spc + 2); + pp_character (buffer, '{'); + pp_newline (buffer); + dump_gimple_seq (buffer, gimple_omp_body (gs), spc + 4, flags); + newline_and_indent (buffer, spc + 2); + pp_character (buffer, '}'); + } + } +} + /* Dump a GIMPLE_OMP_SECTIONS tuple on the pretty_printer BUFFER. */ static void @@ -1785,6 +1891,8 @@ dump_gimple_omp_atomic_load (pretty_printer *buffer, gimple gs, int spc, else { pp_string (buffer, "#pragma omp atomic_load"); + if (gimple_omp_atomic_seq_cst_p (gs)) + pp_string (buffer, " seq_cst"); if (gimple_omp_atomic_need_value_p (gs)) pp_string (buffer, " [needed]"); newline_and_indent (buffer, spc + 2); @@ -1815,6 +1923,8 @@ dump_gimple_omp_atomic_store (pretty_printer *buffer, gimple gs, int spc, else { pp_string (buffer, "#pragma omp atomic_store "); + if (gimple_omp_atomic_seq_cst_p (gs)) + pp_string (buffer, "seq_cst "); if (gimple_omp_atomic_need_value_p (gs)) pp_string (buffer, "[needed] "); pp_character (buffer, '('); @@ -2000,6 +2110,14 @@ pp_gimple_stmt_1 (pretty_printer *buffer, gimple gs, int spc, int flags) dump_gimple_omp_single (buffer, gs, spc, flags); break; + case GIMPLE_OMP_TARGET: + dump_gimple_omp_target (buffer, gs, spc, flags); + break; + + case GIMPLE_OMP_TEAMS: + dump_gimple_omp_teams (buffer, gs, spc, flags); + break; + case GIMPLE_OMP_RETURN: dump_gimple_omp_return (buffer, gs, spc, flags); break; diff --git a/gcc/gimple.c b/gcc/gimple.c index f5074199381bf..7d137fdfc5aca 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -908,13 +908,14 @@ gimple_build_omp_critical (gimple_seq body, tree name) PRE_BODY is the sequence of statements that are loop invariant. */ gimple -gimple_build_omp_for (gimple_seq body, tree clauses, size_t collapse, +gimple_build_omp_for (gimple_seq body, int kind, tree clauses, size_t collapse, gimple_seq pre_body) { gimple p = gimple_alloc (GIMPLE_OMP_FOR, 0); if (body) gimple_omp_set_body (p, body); gimple_omp_for_set_clauses (p, clauses); + gimple_omp_for_set_kind (p, kind); p->gimple_omp_for.collapse = collapse; p->gimple_omp_for.iter = ggc_alloc_cleared_vec_gimple_omp_for_iter (collapse); @@ -1094,6 +1095,41 @@ gimple_build_omp_single (gimple_seq body, tree clauses) } +/* Build a GIMPLE_OMP_TARGET statement. + + BODY is the sequence of statements that will be executed. + CLAUSES are any of the OMP target construct's clauses. */ + +gimple +gimple_build_omp_target (gimple_seq body, int kind, tree clauses) +{ + gimple p = gimple_alloc (GIMPLE_OMP_TARGET, 0); + if (body) + gimple_omp_set_body (p, body); + gimple_omp_target_set_clauses (p, clauses); + gimple_omp_target_set_kind (p, kind); + + return p; +} + + +/* Build a GIMPLE_OMP_TEAMS statement. + + BODY is the sequence of statements that will be executed. + CLAUSES are any of the OMP teams construct's clauses. */ + +gimple +gimple_build_omp_teams (gimple_seq body, tree clauses) +{ + gimple p = gimple_alloc (GIMPLE_OMP_TEAMS, 0); + if (body) + gimple_omp_set_body (p, body); + gimple_omp_teams_set_clauses (p, clauses); + + return p; +} + + /* Build a GIMPLE_OMP_ATOMIC_LOAD statement. */ gimple @@ -1610,6 +1646,20 @@ walk_gimple_op (gimple stmt, walk_tree_fn callback_op, return ret; break; + case GIMPLE_OMP_TARGET: + ret = walk_tree (gimple_omp_target_clauses_ptr (stmt), callback_op, wi, + pset); + if (ret) + return ret; + break; + + case GIMPLE_OMP_TEAMS: + ret = walk_tree (gimple_omp_teams_clauses_ptr (stmt), callback_op, wi, + pset); + if (ret) + return ret; + break; + case GIMPLE_OMP_ATOMIC_LOAD: ret = walk_tree (gimple_omp_atomic_load_lhs_ptr (stmt), callback_op, wi, pset); @@ -1786,6 +1836,8 @@ walk_gimple_stmt (gimple_stmt_iterator *gsi, walk_stmt_fn callback_stmt, case GIMPLE_OMP_TASK: case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SINGLE: + case GIMPLE_OMP_TARGET: + case GIMPLE_OMP_TEAMS: ret = walk_gimple_seq_mod (gimple_omp_body_ptr (stmt), callback_stmt, callback_op, wi); if (ret) @@ -2308,6 +2360,8 @@ gimple_copy (gimple stmt) /* FALLTHRU */ case GIMPLE_OMP_SINGLE: + case GIMPLE_OMP_TARGET: + case GIMPLE_OMP_TEAMS: case GIMPLE_OMP_SECTION: case GIMPLE_OMP_MASTER: case GIMPLE_OMP_ORDERED: diff --git a/gcc/gimple.def b/gcc/gimple.def index acad572e35307..8d75ada3ec3d0 100644 --- a/gcc/gimple.def +++ b/gcc/gimple.def @@ -287,7 +287,7 @@ DEFGSCODE(GIMPLE_OMP_ORDERED, "gimple_omp_ordered", GSS_OMP) BODY is a the sequence of statements to be executed by all threads. - CLAUSES is a TREE_LIST node with all the clauses. + CLAUSES is an OMP_CLAUSE chain with all the clauses. CHILD_FN is set when outlining the body of the parallel region. All the statements in BODY are moved into this newly created @@ -306,7 +306,7 @@ DEFGSCODE(GIMPLE_OMP_PARALLEL, "gimple_omp_parallel", GSS_OMP_PARALLEL) BODY is a the sequence of statements to be executed by all threads. - CLAUSES is a TREE_LIST node with all the clauses. + CLAUSES is an OMP_CLAUSE chain with all the clauses. CHILD_FN is set when outlining the body of the explicit task region. All the statements in BODY are moved into this newly created @@ -334,7 +334,7 @@ DEFGSCODE(GIMPLE_OMP_SECTION, "gimple_omp_section", GSS_OMP) /* OMP_SECTIONS represents #pragma omp sections. BODY is the sequence of statements in the sections body. - CLAUSES is a TREE_LIST node holding the list of associated clauses. + CLAUSES is an OMP_CLAUSE chain holding the list of associated clauses. CONTROL is a VAR_DECL used for deciding which of the sections to execute. */ DEFGSCODE(GIMPLE_OMP_SECTIONS, "gimple_omp_sections", GSS_OMP_SECTIONS) @@ -346,9 +346,21 @@ DEFGSCODE(GIMPLE_OMP_SECTIONS_SWITCH, "gimple_omp_sections_switch", GSS_BASE) /* GIMPLE_OMP_SINGLE represents #pragma omp single BODY is the sequence of statements inside the single section. - CLAUSES is a TREE_LIST node holding the associated clauses. */ + CLAUSES is an OMP_CLAUSE chain holding the associated clauses. */ DEFGSCODE(GIMPLE_OMP_SINGLE, "gimple_omp_single", GSS_OMP_SINGLE) +/* GIMPLE_OMP_TARGET represents + #pragma omp target {,data,update} + BODY is the sequence of statements inside the target construct + (NULL for target update). + CLAUSES is an OMP_CLAUSE chain holding the associated clauses. */ +DEFGSCODE(GIMPLE_OMP_TARGET, "gimple_omp_target", GSS_OMP_SINGLE) + +/* GIMPLE_OMP_TEAMS represents #pragma omp teams + BODY is the sequence of statements inside the single section. + CLAUSES is an OMP_CLAUSE chain holding the associated clauses. */ +DEFGSCODE(GIMPLE_OMP_TEAMS, "gimple_omp_teams", GSS_OMP_SINGLE) + /* GIMPLE_PREDICT specifies a hint for branch prediction. PREDICT is one of the predictors from predict.def. diff --git a/gcc/gimple.h b/gcc/gimple.h index 8ae07c9ba5d9d..fce7d88d5b914 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -110,6 +110,17 @@ enum gf_mask { GF_CALL_ALLOCA_FOR_VAR = 1 << 5, GF_CALL_INTERNAL = 1 << 6, GF_OMP_PARALLEL_COMBINED = 1 << 0, + GF_OMP_FOR_KIND_MASK = 3 << 0, + GF_OMP_FOR_KIND_FOR = 0 << 0, + GF_OMP_FOR_KIND_DISTRIBUTE = 1 << 0, + GF_OMP_FOR_KIND_SIMD = 2 << 0, + GF_OMP_FOR_KIND_CILKSIMD = 3 << 0, + GF_OMP_FOR_COMBINED = 1 << 2, + GF_OMP_FOR_COMBINED_INTO = 1 << 3, + GF_OMP_TARGET_KIND_MASK = 3 << 0, + GF_OMP_TARGET_KIND_REGION = 0 << 0, + GF_OMP_TARGET_KIND_DATA = 1 << 0, + GF_OMP_TARGET_KIND_UPDATE = 2 << 0, /* True on an GIMPLE_OMP_RETURN statement if the return does not require a thread synchronization via some sort of barrier. The exact barrier @@ -119,6 +130,7 @@ enum gf_mask { GF_OMP_SECTION_LAST = 1 << 0, GF_OMP_ATOMIC_NEED_VALUE = 1 << 0, + GF_OMP_ATOMIC_SEQ_CST = 1 << 1, GF_PREDICT_TAKEN = 1 << 15 }; @@ -612,7 +624,7 @@ struct GTY(()) gimple_statement_omp_continue { tree control_use; }; -/* GIMPLE_OMP_SINGLE */ +/* GIMPLE_OMP_SINGLE, GIMPLE_OMP_TARGET, GIMPLE_OMP_TEAMS */ struct GTY(()) gimple_statement_omp_single { /* [ WORD 1-7 ] */ @@ -799,7 +811,7 @@ gimple gimple_build_switch_nlabels (unsigned, tree, tree); gimple gimple_build_switch (tree, tree, vec ); gimple gimple_build_omp_parallel (gimple_seq, tree, tree, tree); gimple gimple_build_omp_task (gimple_seq, tree, tree, tree, tree, tree, tree); -gimple gimple_build_omp_for (gimple_seq, tree, size_t, gimple_seq); +gimple gimple_build_omp_for (gimple_seq, int, tree, size_t, gimple_seq); gimple gimple_build_omp_critical (gimple_seq, tree); gimple gimple_build_omp_section (gimple_seq); gimple gimple_build_omp_continue (tree, tree); @@ -809,6 +821,8 @@ gimple gimple_build_omp_ordered (gimple_seq); gimple gimple_build_omp_sections (gimple_seq, tree); gimple gimple_build_omp_sections_switch (void); gimple gimple_build_omp_single (gimple_seq, tree); +gimple gimple_build_omp_target (gimple_seq, int, tree); +gimple gimple_build_omp_teams (gimple_seq, tree); gimple gimple_build_cdt (tree, tree); gimple gimple_build_omp_atomic_load (tree, tree); gimple gimple_build_omp_atomic_store (tree); @@ -1261,6 +1275,8 @@ gimple_has_substatements (gimple g) case GIMPLE_OMP_TASK: case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SINGLE: + case GIMPLE_OMP_TARGET: + case GIMPLE_OMP_TEAMS: case GIMPLE_OMP_CRITICAL: case GIMPLE_WITH_CLEANUP_EXPR: case GIMPLE_TRANSACTION: @@ -1688,7 +1704,7 @@ static inline unsigned gimple_omp_subcode (const_gimple s) { gcc_gimple_checking_assert (gimple_code (s) >= GIMPLE_OMP_ATOMIC_LOAD - && gimple_code (s) <= GIMPLE_OMP_SINGLE); + && gimple_code (s) <= GIMPLE_OMP_TEAMS); return s->gsbase.subcode; } @@ -1793,6 +1809,29 @@ gimple_omp_atomic_set_need_value (gimple g) } +/* Return true if OMP atomic load/store statement G has the + GF_OMP_ATOMIC_SEQ_CST flag set. */ + +static inline bool +gimple_omp_atomic_seq_cst_p (const_gimple g) +{ + if (gimple_code (g) != GIMPLE_OMP_ATOMIC_LOAD) + GIMPLE_CHECK (g, GIMPLE_OMP_ATOMIC_STORE); + return (gimple_omp_subcode (g) & GF_OMP_ATOMIC_SEQ_CST) != 0; +} + + +/* Set the GF_OMP_ATOMIC_SEQ_CST flag on G. */ + +static inline void +gimple_omp_atomic_set_seq_cst (gimple g) +{ + if (gimple_code (g) != GIMPLE_OMP_ATOMIC_LOAD) + GIMPLE_CHECK (g, GIMPLE_OMP_ATOMIC_STORE); + g->gsbase.subcode |= GF_OMP_ATOMIC_SEQ_CST; +} + + /* Return the number of operands for statement GS. */ static inline unsigned @@ -3948,6 +3987,77 @@ gimple_omp_critical_set_name (gimple gs, tree name) } +/* Return the kind of OMP for statemement. */ + +static inline int +gimple_omp_for_kind (const_gimple g) +{ + GIMPLE_CHECK (g, GIMPLE_OMP_FOR); + return (gimple_omp_subcode (g) & GF_OMP_FOR_KIND_MASK); +} + + +/* Set the OMP for kind. */ + +static inline void +gimple_omp_for_set_kind (gimple g, int kind) +{ + GIMPLE_CHECK (g, GIMPLE_OMP_FOR); + g->gsbase.subcode = (g->gsbase.subcode & ~GF_OMP_FOR_KIND_MASK) + | (kind & GF_OMP_FOR_KIND_MASK); +} + + +/* Return true if OMP for statement G has the + GF_OMP_FOR_COMBINED flag set. */ + +static inline bool +gimple_omp_for_combined_p (const_gimple g) +{ + GIMPLE_CHECK (g, GIMPLE_OMP_FOR); + return (gimple_omp_subcode (g) & GF_OMP_FOR_COMBINED) != 0; +} + + +/* Set the GF_OMP_FOR_COMBINED field in G depending on the boolean + value of COMBINED_P. */ + +static inline void +gimple_omp_for_set_combined_p (gimple g, bool combined_p) +{ + GIMPLE_CHECK (g, GIMPLE_OMP_FOR); + if (combined_p) + g->gsbase.subcode |= GF_OMP_FOR_COMBINED; + else + g->gsbase.subcode &= ~GF_OMP_FOR_COMBINED; +} + + +/* Return true if OMP for statement G has the + GF_OMP_FOR_COMBINED_INTO flag set. */ + +static inline bool +gimple_omp_for_combined_into_p (const_gimple g) +{ + GIMPLE_CHECK (g, GIMPLE_OMP_FOR); + return (gimple_omp_subcode (g) & GF_OMP_FOR_COMBINED_INTO) != 0; +} + + +/* Set the GF_OMP_FOR_COMBINED_INTO field in G depending on the boolean + value of COMBINED_P. */ + +static inline void +gimple_omp_for_set_combined_into_p (gimple g, bool combined_p) +{ + GIMPLE_CHECK (g, GIMPLE_OMP_FOR); + if (combined_p) + g->gsbase.subcode |= GF_OMP_FOR_COMBINED_INTO; + else + g->gsbase.subcode &= ~GF_OMP_FOR_COMBINED_INTO; +} + + /* Return the clauses associated with OMP_FOR GS. */ static inline tree @@ -4557,6 +4667,87 @@ gimple_omp_single_set_clauses (gimple gs, tree clauses) } +/* Return the clauses associated with OMP_TARGET GS. */ + +static inline tree +gimple_omp_target_clauses (const_gimple gs) +{ + GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET); + return gs->gimple_omp_single.clauses; +} + + +/* Return a pointer to the clauses associated with OMP_TARGET GS. */ + +static inline tree * +gimple_omp_target_clauses_ptr (gimple gs) +{ + GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET); + return &gs->gimple_omp_single.clauses; +} + + +/* Set CLAUSES to be the clauses associated with OMP_TARGET GS. */ + +static inline void +gimple_omp_target_set_clauses (gimple gs, tree clauses) +{ + GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET); + gs->gimple_omp_single.clauses = clauses; +} + + +/* Return the kind of OMP target statemement. */ + +static inline int +gimple_omp_target_kind (const_gimple g) +{ + GIMPLE_CHECK (g, GIMPLE_OMP_TARGET); + return (gimple_omp_subcode (g) & GF_OMP_TARGET_KIND_MASK); +} + + +/* Set the OMP target kind. */ + +static inline void +gimple_omp_target_set_kind (gimple g, int kind) +{ + GIMPLE_CHECK (g, GIMPLE_OMP_TARGET); + g->gsbase.subcode = (g->gsbase.subcode & ~GF_OMP_TARGET_KIND_MASK) + | (kind & GF_OMP_TARGET_KIND_MASK); +} + + +/* Return the clauses associated with OMP_TEAMS GS. */ + +static inline tree +gimple_omp_teams_clauses (const_gimple gs) +{ + GIMPLE_CHECK (gs, GIMPLE_OMP_TEAMS); + return gs->gimple_omp_single.clauses; +} + + +/* Return a pointer to the clauses associated with OMP_TEAMS GS. */ + +static inline tree * +gimple_omp_teams_clauses_ptr (gimple gs) +{ + GIMPLE_CHECK (gs, GIMPLE_OMP_TEAMS); + return &gs->gimple_omp_single.clauses; +} + + +/* Set CLAUSES to be the clauses associated with OMP_TEAMS GS. */ + +static inline void +gimple_omp_teams_set_clauses (gimple gs, tree clauses) +{ + GIMPLE_CHECK (gs, GIMPLE_OMP_TEAMS); + gs->gimple_omp_single.clauses = clauses; +} + + /* Return the clauses associated with OMP_SECTIONS GS. */ static inline tree @@ -4899,6 +5090,8 @@ gimple_return_set_retval (gimple gs, tree retval) case GIMPLE_OMP_SECTIONS: \ case GIMPLE_OMP_SECTIONS_SWITCH: \ case GIMPLE_OMP_SINGLE: \ + case GIMPLE_OMP_TARGET: \ + case GIMPLE_OMP_TEAMS: \ case GIMPLE_OMP_SECTION: \ case GIMPLE_OMP_MASTER: \ case GIMPLE_OMP_ORDERED: \ diff --git a/gcc/gimplify.c b/gcc/gimplify.c index e2ae8932dfae4..44889e8102f5a 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -57,20 +57,28 @@ enum gimplify_omp_var_data GOVD_LASTPRIVATE = 32, GOVD_REDUCTION = 64, GOVD_LOCAL = 128, - GOVD_DEBUG_PRIVATE = 256, - GOVD_PRIVATE_OUTER_REF = 512, + GOVD_MAP = 256, + GOVD_DEBUG_PRIVATE = 512, + GOVD_PRIVATE_OUTER_REF = 1024, + GOVD_LINEAR = 2048, + GOVD_ALIGNED = 4096, GOVD_DATA_SHARE_CLASS = (GOVD_SHARED | GOVD_PRIVATE | GOVD_FIRSTPRIVATE - | GOVD_LASTPRIVATE | GOVD_REDUCTION | GOVD_LOCAL) + | GOVD_LASTPRIVATE | GOVD_REDUCTION | GOVD_LINEAR + | GOVD_LOCAL) }; enum omp_region_type { ORT_WORKSHARE = 0, + ORT_SIMD = 1, ORT_PARALLEL = 2, ORT_COMBINED_PARALLEL = 3, ORT_TASK = 4, - ORT_UNTIED_TASK = 5 + ORT_UNTIED_TASK = 5, + ORT_TEAMS = 8, + ORT_TARGET_DATA = 16, + ORT_TARGET = 32 }; struct gimplify_omp_ctx @@ -81,6 +89,7 @@ struct gimplify_omp_ctx location_t location; enum omp_clause_default_kind default_kind; enum omp_region_type region_type; + bool combined_loop; }; static struct gimplify_ctx *gimplify_ctxp; @@ -711,7 +720,9 @@ gimple_add_tmp_var (tree tmp) if (gimplify_omp_ctxp) { struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp; - while (ctx && ctx->region_type == ORT_WORKSHARE) + while (ctx + && (ctx->region_type == ORT_WORKSHARE + || ctx->region_type == ORT_SIMD)) ctx = ctx->outer_context; if (ctx) omp_add_variable (ctx, tmp, GOVD_LOCAL | GOVD_SEEN); @@ -2062,7 +2073,9 @@ gimplify_var_or_parm_decl (tree *expr_p) && decl_function_context (decl) != current_function_decl) { struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp; - while (ctx && ctx->region_type == ORT_WORKSHARE) + while (ctx + && (ctx->region_type == ORT_WORKSHARE + || ctx->region_type == ORT_SIMD)) ctx = ctx->outer_context; if (!ctx && !pointer_set_insert (nonlocal_vlas, decl)) { @@ -4703,6 +4716,9 @@ is_gimple_stmt (tree t) case STATEMENT_LIST: case OMP_PARALLEL: case OMP_FOR: + case OMP_SIMD: + case CILK_SIMD: + case OMP_DISTRIBUTE: case OMP_SECTIONS: case OMP_SECTION: case OMP_SINGLE: @@ -5715,7 +5731,8 @@ omp_firstprivatize_variable (struct gimplify_omp_ctx *ctx, tree decl) else return; } - else if (ctx->region_type != ORT_WORKSHARE) + else if (ctx->region_type != ORT_WORKSHARE + && ctx->region_type != ORT_SIMD) omp_add_variable (ctx, decl, GOVD_FIRSTPRIVATE); ctx = ctx->outer_context; @@ -5798,7 +5815,7 @@ omp_add_variable (struct gimplify_omp_ctx *ctx, tree decl, unsigned int flags) flags |= GOVD_SEEN; n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl); - if (n != NULL) + if (n != NULL && n->value != GOVD_ALIGNED) { /* We shouldn't be re-adding the decl with the same data sharing class. */ @@ -5807,7 +5824,8 @@ omp_add_variable (struct gimplify_omp_ctx *ctx, tree decl, unsigned int flags) FIRSTPRIVATE and LASTPRIVATE. */ nflags = n->value | flags; gcc_assert ((nflags & GOVD_DATA_SHARE_CLASS) - == (GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE)); + == (GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE) + || (flags & GOVD_DATA_SHARE_CLASS) == 0); n->value = nflags; return; } @@ -5817,6 +5835,9 @@ omp_add_variable (struct gimplify_omp_ctx *ctx, tree decl, unsigned int flags) the parameters of the type. */ if (DECL_SIZE (decl) && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST) { + /* To be handled later. */ + gcc_assert ((flags & GOVD_MAP) == 0); + /* Add the pointer replacement variable as PRIVATE if the variable replacement is private, else FIRSTPRIVATE since we'll need the address of the original variable either for SHARED, or for the @@ -5858,6 +5879,9 @@ omp_add_variable (struct gimplify_omp_ctx *ctx, tree decl, unsigned int flags) } else if (lang_hooks.decls.omp_privatize_by_reference (decl)) { + /* To be handled later. */ + gcc_assert ((flags & GOVD_MAP) == 0); + gcc_assert ((flags & GOVD_LOCAL) == 0); omp_firstprivatize_type_sizes (ctx, TREE_TYPE (decl)); @@ -5871,7 +5895,10 @@ omp_add_variable (struct gimplify_omp_ctx *ctx, tree decl, unsigned int flags) } } - splay_tree_insert (ctx->variables, (splay_tree_key)decl, flags); + if (n != NULL) + n->value |= flags; + else + splay_tree_insert (ctx->variables, (splay_tree_key)decl, flags); } /* Notice a threadprivate variable DECL used in OpenMP context CTX. @@ -5884,6 +5911,22 @@ omp_notice_threadprivate_variable (struct gimplify_omp_ctx *ctx, tree decl, tree decl2) { splay_tree_node n; + struct gimplify_omp_ctx *octx; + + for (octx = ctx; octx; octx = octx->outer_context) + if (octx->region_type == ORT_TARGET) + { + n = splay_tree_lookup (octx->variables, (splay_tree_key)decl); + if (n == NULL) + { + error ("threadprivate variable %qE used in target region", + DECL_NAME (decl)); + error_at (octx->location, "enclosing target region"); + splay_tree_insert (octx->variables, (splay_tree_key)decl, 0); + } + if (decl2) + splay_tree_insert (octx->variables, (splay_tree_key)decl2, 0); + } if (ctx->region_type != ORT_UNTIED_TASK) return false; @@ -5932,12 +5975,24 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code) } n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl); + if (ctx->region_type == ORT_TARGET) + { + if (n == NULL) + omp_add_variable (ctx, decl, GOVD_MAP | flags); + else + n->value |= flags; + ret = lang_hooks.decls.omp_disregard_value_expr (decl, true); + goto do_outer; + } + if (n == NULL) { enum omp_clause_default_kind default_kind, kind; struct gimplify_omp_ctx *octx; - if (ctx->region_type == ORT_WORKSHARE) + if (ctx->region_type == ORT_WORKSHARE + || ctx->region_type == ORT_SIMD + || ctx->region_type == ORT_TARGET_DATA) goto do_outer; /* ??? Some compiler-generated variables (like SAVE_EXPRs) could be @@ -5951,12 +6006,24 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code) switch (default_kind) { case OMP_CLAUSE_DEFAULT_NONE: - error ("%qE not specified in enclosing parallel", - DECL_NAME (lang_hooks.decls.omp_report_decl (decl))); if ((ctx->region_type & ORT_TASK) != 0) - error_at (ctx->location, "enclosing task"); + { + error ("%qE not specified in enclosing task", + DECL_NAME (lang_hooks.decls.omp_report_decl (decl))); + error_at (ctx->location, "enclosing task"); + } + else if (ctx->region_type == ORT_TEAMS) + { + error ("%qE not specified in enclosing teams construct", + DECL_NAME (lang_hooks.decls.omp_report_decl (decl))); + error_at (ctx->location, "enclosing teams construct"); + } else - error_at (ctx->location, "enclosing parallel"); + { + error ("%qE not specified in enclosing parallel", + DECL_NAME (lang_hooks.decls.omp_report_decl (decl))); + error_at (ctx->location, "enclosing parallel"); + } /* FALLTHRU */ case OMP_CLAUSE_DEFAULT_SHARED: flags |= GOVD_SHARED; @@ -5976,13 +6043,15 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code) { splay_tree_node n2; + if ((octx->region_type & (ORT_TARGET_DATA | ORT_TARGET)) != 0) + continue; n2 = splay_tree_lookup (octx->variables, (splay_tree_key) decl); if (n2 && (n2->value & GOVD_DATA_SHARE_CLASS) != GOVD_SHARED) { flags |= GOVD_FIRSTPRIVATE; break; } - if ((octx->region_type & ORT_PARALLEL) != 0) + if ((octx->region_type & (ORT_PARALLEL | ORT_TEAMS)) != 0) break; } if (flags & GOVD_FIRSTPRIVATE) @@ -6050,7 +6119,7 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code) to the contrary in the innermost scope, generate an error. */ static bool -omp_is_private (struct gimplify_omp_ctx *ctx, tree decl) +omp_is_private (struct gimplify_omp_ctx *ctx, tree decl, bool simd) { splay_tree_node n; @@ -6061,8 +6130,12 @@ omp_is_private (struct gimplify_omp_ctx *ctx, tree decl) { if (ctx == gimplify_omp_ctxp) { - error ("iteration variable %qE should be private", - DECL_NAME (decl)); + if (simd) + error ("iteration variable %qE is predetermined linear", + DECL_NAME (decl)); + else + error ("iteration variable %qE should be private", + DECL_NAME (decl)); n->value = GOVD_PRIVATE; return true; } @@ -6080,16 +6153,26 @@ omp_is_private (struct gimplify_omp_ctx *ctx, tree decl) else if ((n->value & GOVD_REDUCTION) != 0) error ("iteration variable %qE should not be reduction", DECL_NAME (decl)); + else if (simd && (n->value & GOVD_LASTPRIVATE) != 0) + error ("iteration variable %qE should not be lastprivate", + DECL_NAME (decl)); + else if (simd && (n->value & GOVD_PRIVATE) != 0) + error ("iteration variable %qE should not be private", + DECL_NAME (decl)); + else if (simd && (n->value & GOVD_LINEAR) != 0) + error ("iteration variable %qE is predetermined linear", + DECL_NAME (decl)); } return (ctx == gimplify_omp_ctxp || (ctx->region_type == ORT_COMBINED_PARALLEL && gimplify_omp_ctxp->outer_context == ctx)); } - if (ctx->region_type != ORT_WORKSHARE) + if (ctx->region_type != ORT_WORKSHARE + && ctx->region_type != ORT_SIMD) return false; else if (ctx->outer_context) - return omp_is_private (ctx->outer_context, decl); + return omp_is_private (ctx->outer_context, decl, simd); return false; } @@ -6110,11 +6193,15 @@ omp_check_private (struct gimplify_omp_ctx *ctx, tree decl) /* References might be private, but might be shared too. */ || lang_hooks.decls.omp_privatize_by_reference (decl)); + 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; } - while (ctx->region_type == ORT_WORKSHARE); + while (ctx->region_type == ORT_WORKSHARE + || ctx->region_type == ORT_SIMD); return false; } @@ -6167,6 +6254,88 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, flags = GOVD_REDUCTION | GOVD_SEEN | GOVD_EXPLICIT; check_non_private = "reduction"; goto do_add; + case OMP_CLAUSE_LINEAR: + if (gimplify_expr (&OMP_CLAUSE_LINEAR_STEP (c), pre_p, NULL, + is_gimple_val, fb_rvalue) == GS_ERROR) + { + remove = true; + break; + } + flags = GOVD_LINEAR | GOVD_EXPLICIT; + goto do_add; + + case OMP_CLAUSE_MAP: + if (OMP_CLAUSE_SIZE (c) + && gimplify_expr (&OMP_CLAUSE_SIZE (c), pre_p, + NULL, is_gimple_val, fb_rvalue) == GS_ERROR) + { + remove = true; + break; + } + decl = OMP_CLAUSE_DECL (c); + if (!DECL_P (decl)) + { + if (gimplify_expr (&OMP_CLAUSE_DECL (c), pre_p, + NULL, is_gimple_lvalue, fb_lvalue) + == GS_ERROR) + { + remove = true; + break; + } + break; + } + flags = GOVD_MAP | GOVD_EXPLICIT; + notice_outer = false; + goto do_add; + + case OMP_CLAUSE_DEPEND: + if (TREE_CODE (OMP_CLAUSE_DECL (c)) == COMPOUND_EXPR) + { + gimplify_expr (&TREE_OPERAND (OMP_CLAUSE_DECL (c), 0), pre_p, + NULL, is_gimple_val, fb_rvalue); + OMP_CLAUSE_DECL (c) = TREE_OPERAND (OMP_CLAUSE_DECL (c), 1); + } + if (error_operand_p (OMP_CLAUSE_DECL (c))) + { + remove = true; + break; + } + OMP_CLAUSE_DECL (c) = build_fold_addr_expr (OMP_CLAUSE_DECL (c)); + if (gimplify_expr (&OMP_CLAUSE_DECL (c), pre_p, NULL, + is_gimple_val, fb_rvalue) == GS_ERROR) + { + remove = true; + break; + } + break; + + case OMP_CLAUSE_TO: + case OMP_CLAUSE_FROM: + if (OMP_CLAUSE_SIZE (c) + && gimplify_expr (&OMP_CLAUSE_SIZE (c), pre_p, + NULL, is_gimple_val, fb_rvalue) == GS_ERROR) + { + remove = true; + break; + } + decl = OMP_CLAUSE_DECL (c); + if (error_operand_p (decl)) + { + remove = true; + break; + } + if (!DECL_P (decl)) + { + if (gimplify_expr (&OMP_CLAUSE_DECL (c), pre_p, + NULL, is_gimple_lvalue, fb_lvalue) + == GS_ERROR) + { + remove = true; + break; + } + break; + } + goto do_notice; do_add: decl = OMP_CLAUSE_DECL (c); @@ -6255,9 +6424,13 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, case OMP_CLAUSE_SCHEDULE: case OMP_CLAUSE_NUM_THREADS: + case OMP_CLAUSE_NUM_TEAMS: + case OMP_CLAUSE_THREAD_LIMIT: + case OMP_CLAUSE_DIST_SCHEDULE: + case OMP_CLAUSE_DEVICE: if (gimplify_expr (&OMP_CLAUSE_OPERAND (c, 0), pre_p, NULL, is_gimple_val, fb_rvalue) == GS_ERROR) - remove = true; + remove = true; break; case OMP_CLAUSE_NOWAIT: @@ -6265,6 +6438,20 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, case OMP_CLAUSE_UNTIED: case OMP_CLAUSE_COLLAPSE: case OMP_CLAUSE_MERGEABLE: + case OMP_CLAUSE_PROC_BIND: + case OMP_CLAUSE_SAFELEN: + break; + + case OMP_CLAUSE_ALIGNED: + decl = OMP_CLAUSE_DECL (c); + if (error_operand_p (decl)) + { + remove = true; + break; + } + if (!is_global_var (decl) + && TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE) + omp_add_variable (ctx, decl, GOVD_ALIGNED); break; case OMP_CLAUSE_DEFAULT: @@ -6306,12 +6493,40 @@ gimplify_adjust_omp_clauses_1 (splay_tree_node n, void *data) gcc_assert ((flags & GOVD_DATA_SHARE_CLASS) == GOVD_PRIVATE); private_debug = true; } + else if (flags & GOVD_MAP) + private_debug = false; else private_debug = lang_hooks.decls.omp_private_debug_clause (decl, !!(flags & GOVD_SHARED)); if (private_debug) code = OMP_CLAUSE_PRIVATE; + else if (flags & GOVD_MAP) + { + /* If decl is already in the enclosing device data environment, + the spec says that it should just be used and no init/assignment + should be done. If there was any privatization in between though, + it means that original decl might be in the enclosing device data + environment, but the privatized might not. */ + struct gimplify_omp_ctx *ctx; + for (ctx = gimplify_omp_ctxp->outer_context; + ctx; ctx = ctx->outer_context) + { + n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); + if (n == NULL) + continue; + if (ctx->region_type == ORT_TARGET_DATA) + { + if ((n->value & GOVD_MAP) != 0) + return 0; + } + else if ((n->value & (GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE + | GOVD_PRIVATE | GOVD_REDUCTION + | GOVD_LINEAR)) != 0) + break; + } + code = OMP_CLAUSE_MAP; + } else if (flags & GOVD_SHARED) { if (is_global_var (decl)) @@ -6322,7 +6537,8 @@ gimplify_adjust_omp_clauses_1 (splay_tree_node n, void *data) splay_tree_node on = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); if (on && (on->value & (GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE - | GOVD_PRIVATE | GOVD_REDUCTION)) != 0) + | GOVD_PRIVATE | GOVD_REDUCTION + | GOVD_LINEAR)) != 0) break; ctx = ctx->outer_context; } @@ -6335,6 +6551,10 @@ gimplify_adjust_omp_clauses_1 (splay_tree_node n, void *data) code = OMP_CLAUSE_PRIVATE; else if (flags & GOVD_FIRSTPRIVATE) code = OMP_CLAUSE_FIRSTPRIVATE; + else if (flags & GOVD_LASTPRIVATE) + code = OMP_CLAUSE_LASTPRIVATE; + else if (flags & GOVD_ALIGNED) + return 0; else gcc_unreachable (); @@ -6345,6 +6565,8 @@ gimplify_adjust_omp_clauses_1 (splay_tree_node n, void *data) OMP_CLAUSE_PRIVATE_DEBUG (clause) = 1; else if (code == OMP_CLAUSE_PRIVATE && (flags & GOVD_PRIVATE_OUTER_REF)) OMP_CLAUSE_PRIVATE_OUTER_REF (clause) = 1; + else if (code == OMP_CLAUSE_MAP) + OMP_CLAUSE_MAP_KIND (clause) = OMP_CLAUSE_MAP_TOFROM; *list_p = clause; lang_hooks.decls.omp_finish_clause (clause); @@ -6367,6 +6589,7 @@ gimplify_adjust_omp_clauses (tree *list_p) case OMP_CLAUSE_PRIVATE: case OMP_CLAUSE_SHARED: case OMP_CLAUSE_FIRSTPRIVATE: + case OMP_CLAUSE_LINEAR: decl = OMP_CLAUSE_DECL (c); n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); remove = !(n->value & GOVD_SEEN); @@ -6382,6 +6605,31 @@ gimplify_adjust_omp_clauses (tree *list_p) OMP_CLAUSE_SET_CODE (c, OMP_CLAUSE_PRIVATE); OMP_CLAUSE_PRIVATE_DEBUG (c) = 1; } + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR + && ctx->outer_context + && !(OMP_CLAUSE_LINEAR_NO_COPYIN (c) + && OMP_CLAUSE_LINEAR_NO_COPYOUT (c)) + && !is_global_var (decl)) + { + if (ctx->outer_context->region_type == ORT_COMBINED_PARALLEL) + { + n = splay_tree_lookup (ctx->outer_context->variables, + (splay_tree_key) decl); + if (n == NULL + || (n->value & GOVD_DATA_SHARE_CLASS) == 0) + { + int flags = OMP_CLAUSE_LINEAR_NO_COPYIN (c) + ? GOVD_LASTPRIVATE : GOVD_SHARED; + if (n == NULL) + omp_add_variable (ctx->outer_context, decl, + flags | GOVD_SEEN); + else + n->value |= flags | GOVD_SEEN; + } + } + else + omp_notice_variable (ctx->outer_context, decl, true); + } } break; @@ -6394,11 +6642,90 @@ gimplify_adjust_omp_clauses (tree *list_p) = (n->value & GOVD_FIRSTPRIVATE) != 0; break; + case OMP_CLAUSE_ALIGNED: + decl = OMP_CLAUSE_DECL (c); + if (!is_global_var (decl)) + { + n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); + remove = n == NULL || !(n->value & GOVD_SEEN); + if (!remove && TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE) + { + struct gimplify_omp_ctx *octx; + if (n != NULL + && (n->value & (GOVD_DATA_SHARE_CLASS + & ~GOVD_FIRSTPRIVATE))) + remove = true; + else + for (octx = ctx->outer_context; octx; + octx = octx->outer_context) + { + n = splay_tree_lookup (octx->variables, + (splay_tree_key) decl); + if (n == NULL) + continue; + if (n->value & GOVD_LOCAL) + break; + /* We have to avoid assigning a shared variable + to itself when trying to add + __builtin_assume_aligned. */ + if (n->value & GOVD_SHARED) + { + remove = true; + break; + } + } + } + } + else if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) + { + n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); + if (n != NULL && (n->value & GOVD_DATA_SHARE_CLASS) != 0) + remove = true; + } + break; + + case OMP_CLAUSE_MAP: + decl = OMP_CLAUSE_DECL (c); + if (!DECL_P (decl)) + break; + n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); + if (ctx->region_type == ORT_TARGET && !(n->value & GOVD_SEEN)) + remove = true; + else + { + /* If decl is already in the enclosing device data environment, + the spec says that it should just be used and no init/assignment + should be done. If there was any privatization in between though, + it means that original decl might be in the enclosing device data + environment, but the privatized might not. */ + 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 == NULL) + continue; + if (octx->region_type == ORT_TARGET_DATA) + { + if ((n->value & GOVD_MAP) != 0) + remove = true; + } + else if ((n->value & (GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE + | GOVD_PRIVATE | GOVD_REDUCTION + | GOVD_LINEAR)) != 0) + break; + } + } + break; + case OMP_CLAUSE_REDUCTION: case OMP_CLAUSE_COPYIN: case OMP_CLAUSE_COPYPRIVATE: case OMP_CLAUSE_IF: case OMP_CLAUSE_NUM_THREADS: + case OMP_CLAUSE_NUM_TEAMS: + case OMP_CLAUSE_DIST_SCHEDULE: + case OMP_CLAUSE_DEVICE: case OMP_CLAUSE_SCHEDULE: case OMP_CLAUSE_NOWAIT: case OMP_CLAUSE_ORDERED: @@ -6407,6 +6734,11 @@ gimplify_adjust_omp_clauses (tree *list_p) case OMP_CLAUSE_COLLAPSE: case OMP_CLAUSE_FINAL: case OMP_CLAUSE_MERGEABLE: + case OMP_CLAUSE_PROC_BIND: + case OMP_CLAUSE_SAFELEN: + case OMP_CLAUSE_TO: + case OMP_CLAUSE_FROM: + case OMP_CLAUSE_DEPEND: break; default: @@ -6499,28 +6831,90 @@ gimplify_omp_task (tree *expr_p, gimple_seq *pre_p) *expr_p = NULL_TREE; } +/* Helper function of gimplify_omp_for, find OMP_FOR resp. OMP_SIMD + with non-NULL OMP_FOR_INIT. */ + +static tree +find_combined_omp_for (tree *tp, int *walk_subtrees, void *) +{ + *walk_subtrees = 0; + switch (TREE_CODE (*tp)) + { + case OMP_FOR: + *walk_subtrees = 1; + /* FALLTHRU */ + case OMP_SIMD: + if (OMP_FOR_INIT (*tp) != NULL_TREE) + return *tp; + break; + case BIND_EXPR: + case STATEMENT_LIST: + case OMP_PARALLEL: + *walk_subtrees = 1; + break; + default: + break; + } + return NULL_TREE; +} + /* Gimplify the gross structure of an OMP_FOR statement. */ static enum gimplify_status gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) { - tree for_stmt, decl, var, t; + tree for_stmt, orig_for_stmt, decl, var, t; enum gimplify_status ret = GS_ALL_DONE; enum gimplify_status tret; gimple gfor; gimple_seq for_body, for_pre_body; int i; + bool simd; + bitmap has_decl_expr = NULL; - for_stmt = *expr_p; + orig_for_stmt = for_stmt = *expr_p; + simd = TREE_CODE (for_stmt) == OMP_SIMD + || TREE_CODE (for_stmt) == CILK_SIMD; gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p, - ORT_WORKSHARE); + simd ? ORT_SIMD : ORT_WORKSHARE); /* Handle OMP_FOR_INIT. */ for_pre_body = NULL; + if (simd && OMP_FOR_PRE_BODY (for_stmt)) + { + has_decl_expr = BITMAP_ALLOC (NULL); + if (TREE_CODE (OMP_FOR_PRE_BODY (for_stmt)) == DECL_EXPR + && TREE_CODE (DECL_EXPR_DECL (OMP_FOR_PRE_BODY (for_stmt))) + == VAR_DECL) + { + t = OMP_FOR_PRE_BODY (for_stmt); + bitmap_set_bit (has_decl_expr, DECL_UID (DECL_EXPR_DECL (t))); + } + else if (TREE_CODE (OMP_FOR_PRE_BODY (for_stmt)) == STATEMENT_LIST) + { + tree_stmt_iterator si; + for (si = tsi_start (OMP_FOR_PRE_BODY (for_stmt)); !tsi_end_p (si); + tsi_next (&si)) + { + t = tsi_stmt (si); + if (TREE_CODE (t) == DECL_EXPR + && TREE_CODE (DECL_EXPR_DECL (t)) == VAR_DECL) + bitmap_set_bit (has_decl_expr, DECL_UID (DECL_EXPR_DECL (t))); + } + } + } gimplify_and_add (OMP_FOR_PRE_BODY (for_stmt), &for_pre_body); OMP_FOR_PRE_BODY (for_stmt) = NULL_TREE; + if (OMP_FOR_INIT (for_stmt) == NULL_TREE) + { + for_stmt = walk_tree (&OMP_FOR_BODY (for_stmt), find_combined_omp_for, + NULL, NULL); + gcc_assert (for_stmt != NULL_TREE); + 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))); @@ -6536,7 +6930,46 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) || POINTER_TYPE_P (TREE_TYPE (decl))); /* Make sure the iteration variable is private. */ - if (omp_is_private (gimplify_omp_ctxp, decl)) + tree c = NULL_TREE; + if (orig_for_stmt != for_stmt) + /* Do this only on innermost construct for combined ones. */; + else if (simd) + { + splay_tree_node n = splay_tree_lookup (gimplify_omp_ctxp->variables, + (splay_tree_key)decl); + omp_is_private (gimplify_omp_ctxp, decl, simd); + if (n != NULL && (n->value & GOVD_DATA_SHARE_CLASS) != 0) + omp_notice_variable (gimplify_omp_ctxp, decl, true); + else if (TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) == 1) + { + c = build_omp_clause (input_location, OMP_CLAUSE_LINEAR); + OMP_CLAUSE_LINEAR_NO_COPYIN (c) = 1; + if (has_decl_expr + && bitmap_bit_p (has_decl_expr, DECL_UID (decl))) + OMP_CLAUSE_LINEAR_NO_COPYOUT (c) = 1; + OMP_CLAUSE_DECL (c) = decl; + OMP_CLAUSE_CHAIN (c) = OMP_FOR_CLAUSES (for_stmt); + OMP_FOR_CLAUSES (for_stmt) = c; + omp_add_variable (gimplify_omp_ctxp, decl, + GOVD_LINEAR | GOVD_EXPLICIT | GOVD_SEEN); + } + else + { + bool lastprivate + = (!has_decl_expr + || !bitmap_bit_p (has_decl_expr, DECL_UID (decl))); + c = build_omp_clause (input_location, + lastprivate ? OMP_CLAUSE_LASTPRIVATE + : OMP_CLAUSE_PRIVATE); + OMP_CLAUSE_DECL (c) = decl; + OMP_CLAUSE_CHAIN (c) = OMP_FOR_CLAUSES (for_stmt); + omp_add_variable (gimplify_omp_ctxp, decl, + (lastprivate ? GOVD_LASTPRIVATE : GOVD_PRIVATE) + | GOVD_SEEN); + c = NULL_TREE; + } + } + else if (omp_is_private (gimplify_omp_ctxp, decl, simd)) omp_notice_variable (gimplify_omp_ctxp, decl, true); else omp_add_variable (gimplify_omp_ctxp, decl, GOVD_PRIVATE | GOVD_SEEN); @@ -6544,7 +6977,9 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) /* If DECL is not a gimple register, create a temporary variable to act as an iteration counter. This is valid, since DECL cannot be modified in the body of the loop. */ - if (!is_gimple_reg (decl)) + if (orig_for_stmt != for_stmt) + var = decl; + else if (!is_gimple_reg (decl)) { var = create_tmp_var (TREE_TYPE (decl), get_name (decl)); TREE_OPERAND (t, 0) = var; @@ -6577,7 +7012,11 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) { case PREINCREMENT_EXPR: case POSTINCREMENT_EXPR: + if (orig_for_stmt != for_stmt) + break; t = build_int_cst (TREE_TYPE (decl), 1); + if (c) + OMP_CLAUSE_LINEAR_STEP (c) = t; t = build2 (PLUS_EXPR, TREE_TYPE (decl), var, t); t = build2 (MODIFY_EXPR, TREE_TYPE (var), var, t); TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i) = t; @@ -6585,7 +7024,11 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) case PREDECREMENT_EXPR: case POSTDECREMENT_EXPR: + if (orig_for_stmt != for_stmt) + break; t = build_int_cst (TREE_TYPE (decl), -1); + if (c) + OMP_CLAUSE_LINEAR_STEP (c) = t; t = build2 (PLUS_EXPR, TREE_TYPE (decl), var, t); t = build2 (MODIFY_EXPR, TREE_TYPE (var), var, t); TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i) = t; @@ -6619,15 +7062,29 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) tret = gimplify_expr (&TREE_OPERAND (t, 1), &for_pre_body, NULL, is_gimple_val, fb_rvalue); ret = MIN (ret, tret); + if (c) + { + OMP_CLAUSE_LINEAR_STEP (c) = TREE_OPERAND (t, 1); + if (TREE_CODE (t) == MINUS_EXPR) + { + t = TREE_OPERAND (t, 1); + OMP_CLAUSE_LINEAR_STEP (c) + = fold_build1 (NEGATE_EXPR, TREE_TYPE (t), t); + tret = gimplify_expr (&OMP_CLAUSE_LINEAR_STEP (c), + &for_pre_body, NULL, + is_gimple_val, fb_rvalue); + ret = MIN (ret, tret); + } + } break; default: gcc_unreachable (); } - if (var != decl || TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) > 1) + if ((var != decl || TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) > 1) + && orig_for_stmt == for_stmt) { - tree c; for (c = OMP_FOR_CLAUSES (for_stmt); c ; c = OMP_CLAUSE_CHAIN (c)) if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE && OMP_CLAUSE_DECL (c) == decl @@ -6649,13 +7106,52 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) } } - gimplify_and_add (OMP_FOR_BODY (for_stmt), &for_body); + BITMAP_FREE (has_decl_expr); - gimplify_adjust_omp_clauses (&OMP_FOR_CLAUSES (for_stmt)); + gimplify_and_add (OMP_FOR_BODY (orig_for_stmt), &for_body); - gfor = gimple_build_omp_for (for_body, OMP_FOR_CLAUSES (for_stmt), + 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); + var = create_tmp_var (TREE_TYPE (decl), get_name (decl)); + 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 (t, 1) = copy_node (TREE_OPERAND (t, 1)); + TREE_OPERAND (TREE_OPERAND (t, 1), 0) = var; + } + + gimplify_adjust_omp_clauses (&OMP_FOR_CLAUSES (orig_for_stmt)); + + int kind; + switch (TREE_CODE (orig_for_stmt)) + { + case OMP_FOR: kind = GF_OMP_FOR_KIND_FOR; break; + case OMP_SIMD: kind = GF_OMP_FOR_KIND_SIMD; break; + case CILK_SIMD: kind = GF_OMP_FOR_KIND_CILKSIMD; break; + case OMP_DISTRIBUTE: kind = GF_OMP_FOR_KIND_DISTRIBUTE; break; + default: + gcc_unreachable (); + } + gfor = gimple_build_omp_for (for_body, kind, OMP_FOR_CLAUSES (orig_for_stmt), TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)), for_pre_body); + if (orig_for_stmt != for_stmt) + gimple_omp_for_set_combined_p (gfor, true); + if (gimplify_omp_ctxp + && (gimplify_omp_ctxp->combined_loop + || (gimplify_omp_ctxp->region_type == ORT_COMBINED_PARALLEL + && gimplify_omp_ctxp->outer_context + && gimplify_omp_ctxp->outer_context->combined_loop))) + { + gimple_omp_for_set_combined_into_p (gfor, true); + if (gimplify_omp_ctxp->combined_loop) + gcc_assert (TREE_CODE (orig_for_stmt) == OMP_SIMD); + else + gcc_assert (TREE_CODE (orig_for_stmt) == OMP_FOR); + } for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++) { @@ -6670,11 +7166,15 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) } gimplify_seq_add_stmt (pre_p, gfor); - return ret == GS_ALL_DONE ? GS_ALL_DONE : GS_ERROR; + if (ret != GS_ALL_DONE) + return GS_ERROR; + *expr_p = NULL_TREE; + return GS_ALL_DONE; } -/* Gimplify the gross structure of other OpenMP worksharing constructs. - In particular, OMP_SECTIONS and OMP_SINGLE. */ +/* Gimplify the gross structure of other OpenMP constructs. + In particular, OMP_SECTIONS, OMP_SINGLE, OMP_TARGET, OMP_TARGET_DATA + and OMP_TEAMS. */ static void gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p) @@ -6682,19 +7182,72 @@ gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p) tree expr = *expr_p; gimple stmt; gimple_seq body = NULL; + enum omp_region_type ort = ORT_WORKSHARE; - gimplify_scan_omp_clauses (&OMP_CLAUSES (expr), pre_p, ORT_WORKSHARE); + switch (TREE_CODE (expr)) + { + case OMP_SECTIONS: + case OMP_SINGLE: + break; + case OMP_TARGET: + ort = ORT_TARGET; + break; + case OMP_TARGET_DATA: + ort = ORT_TARGET_DATA; + break; + case OMP_TEAMS: + ort = ORT_TEAMS; + break; + default: + gcc_unreachable (); + } + gimplify_scan_omp_clauses (&OMP_CLAUSES (expr), pre_p, ort); gimplify_and_add (OMP_BODY (expr), &body); gimplify_adjust_omp_clauses (&OMP_CLAUSES (expr)); - if (TREE_CODE (expr) == OMP_SECTIONS) - stmt = gimple_build_omp_sections (body, OMP_CLAUSES (expr)); - else if (TREE_CODE (expr) == OMP_SINGLE) - stmt = gimple_build_omp_single (body, OMP_CLAUSES (expr)); - else - gcc_unreachable (); + switch (TREE_CODE (expr)) + { + case OMP_SECTIONS: + stmt = gimple_build_omp_sections (body, OMP_CLAUSES (expr)); + break; + case OMP_SINGLE: + stmt = gimple_build_omp_single (body, OMP_CLAUSES (expr)); + break; + case OMP_TARGET: + stmt = gimple_build_omp_target (body, GF_OMP_TARGET_KIND_REGION, + OMP_CLAUSES (expr)); + break; + case OMP_TARGET_DATA: + stmt = gimple_build_omp_target (body, GF_OMP_TARGET_KIND_DATA, + OMP_CLAUSES (expr)); + break; + case OMP_TEAMS: + stmt = gimple_build_omp_teams (body, OMP_CLAUSES (expr)); + break; + default: + gcc_unreachable (); + } gimplify_seq_add_stmt (pre_p, stmt); + *expr_p = NULL_TREE; +} + +/* Gimplify the gross structure of OpenMP target update construct. */ + +static void +gimplify_omp_target_update (tree *expr_p, gimple_seq *pre_p) +{ + tree expr = *expr_p; + gimple stmt; + + gimplify_scan_omp_clauses (&OMP_TARGET_UPDATE_CLAUSES (expr), pre_p, + ORT_WORKSHARE); + gimplify_adjust_omp_clauses (&OMP_TARGET_UPDATE_CLAUSES (expr)); + stmt = gimple_build_omp_target (NULL, GF_OMP_TARGET_KIND_UPDATE, + OMP_TARGET_UPDATE_CLAUSES (expr)); + + gimplify_seq_add_stmt (pre_p, stmt); + *expr_p = NULL_TREE; } /* A subroutine of gimplify_omp_atomic. The front end is supposed to have @@ -6833,6 +7386,11 @@ gimplify_omp_atomic (tree *expr_p, gimple_seq *pre_p) rhs = tmp_load; storestmt = gimple_build_omp_atomic_store (rhs); gimplify_seq_add_stmt (pre_p, storestmt); + if (OMP_ATOMIC_SEQ_CST (*expr_p)) + { + gimple_omp_atomic_set_seq_cst (loadstmt); + gimple_omp_atomic_set_seq_cst (storestmt); + } switch (TREE_CODE (*expr_p)) { case OMP_ATOMIC_READ: @@ -6849,7 +7407,7 @@ gimplify_omp_atomic (tree *expr_p, gimple_seq *pre_p) break; } - return GS_ALL_DONE; + return GS_ALL_DONE; } /* Gimplify a TRANSACTION_EXPR. This involves gimplification of the @@ -7588,15 +8146,26 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, break; case OMP_FOR: + case OMP_SIMD: + case CILK_SIMD: + case OMP_DISTRIBUTE: ret = gimplify_omp_for (expr_p, pre_p); break; case OMP_SECTIONS: case OMP_SINGLE: + case OMP_TARGET: + case OMP_TARGET_DATA: + case OMP_TEAMS: gimplify_omp_workshare (expr_p, pre_p); ret = GS_ALL_DONE; break; + case OMP_TARGET_UPDATE: + gimplify_omp_target_update (expr_p, pre_p); + ret = GS_ALL_DONE; + break; + case OMP_SECTION: case OMP_MASTER: case OMP_ORDERED: @@ -8170,6 +8739,13 @@ gimplify_body (tree fndecl, bool do_parms) gcc_assert (gimplify_ctxp == NULL); push_gimplify_context (&gctx); + if (flag_openmp) + { + gcc_assert (gimplify_omp_ctxp == NULL); + if (lookup_attribute ("omp declare target", DECL_ATTRIBUTES (fndecl))) + gimplify_omp_ctxp = new_omp_context (ORT_TARGET); + } + /* Unshare most shared trees in the body and in that of any nested functions. It would seem we don't have to do this for nested functions because they are supposed to be output and then the outer function gimplified @@ -8232,6 +8808,12 @@ gimplify_body (tree fndecl, bool do_parms) nonlocal_vlas = NULL; } + if (flag_openmp && gimplify_omp_ctxp) + { + delete_omp_context (gimplify_omp_ctxp); + gimplify_omp_ctxp = NULL; + } + pop_gimplify_context (outer_bind); gcc_assert (gimplify_ctxp == NULL); diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c index b841abd328ebb..983efeb751b33 100644 --- a/gcc/internal-fn.c +++ b/gcc/internal-fn.c @@ -109,6 +109,30 @@ expand_STORE_LANES (gimple stmt) expand_insn (get_multi_vector_move (type, vec_store_lanes_optab), 2, ops); } +/* This should get expanded in adjust_simduid_builtins. */ + +static void +expand_GOMP_SIMD_LANE (gimple stmt ATTRIBUTE_UNUSED) +{ + gcc_unreachable (); +} + +/* This should get expanded in adjust_simduid_builtins. */ + +static void +expand_GOMP_SIMD_VF (gimple stmt ATTRIBUTE_UNUSED) +{ + gcc_unreachable (); +} + +/* This should get expanded in adjust_simduid_builtins. */ + +static void +expand_GOMP_SIMD_LAST_LANE (gimple stmt ATTRIBUTE_UNUSED) +{ + gcc_unreachable (); +} + /* Routines to expand each internal function, indexed by function number. Each routine has the prototype: diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def index 8900d90dc22f9..5427664b8e3c5 100644 --- a/gcc/internal-fn.def +++ b/gcc/internal-fn.def @@ -40,3 +40,6 @@ along with GCC; see the file COPYING3. If not see DEF_INTERNAL_FN (LOAD_LANES, ECF_CONST | ECF_LEAF) DEF_INTERNAL_FN (STORE_LANES, ECF_CONST | ECF_LEAF) +DEF_INTERNAL_FN (GOMP_SIMD_LANE, ECF_NOVOPS | ECF_LEAF | ECF_NOTHROW) +DEF_INTERNAL_FN (GOMP_SIMD_VF, ECF_CONST | ECF_LEAF | ECF_NOTHROW) +DEF_INTERNAL_FN (GOMP_SIMD_LAST_LANE, ECF_CONST | ECF_LEAF | ECF_NOTHROW) diff --git a/gcc/lto/ChangeLog.gomp b/gcc/lto/ChangeLog.gomp new file mode 100644 index 0000000000000..96cf420959b20 --- /dev/null +++ b/gcc/lto/ChangeLog.gomp @@ -0,0 +1,9 @@ +2013-04-10 Jakub Jelinek + + * lto-lang.c (DEF_FUNCTION_TYPE_8): Define. + +Copyright (C) 2013 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/gcc/lto/lto-lang.c b/gcc/lto/lto-lang.c index 87a756d57639b..79cc5609994d7 100644 --- a/gcc/lto/lto-lang.c +++ b/gcc/lto/lto-lang.c @@ -140,6 +140,7 @@ enum lto_builtin_type #define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME, #define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) NAME, #define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) NAME, +#define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8) 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, @@ -158,6 +159,7 @@ enum lto_builtin_type #undef DEF_FUNCTION_TYPE_5 #undef DEF_FUNCTION_TYPE_6 #undef DEF_FUNCTION_TYPE_7 +#undef DEF_FUNCTION_TYPE_8 #undef DEF_FUNCTION_TYPE_VAR_0 #undef DEF_FUNCTION_TYPE_VAR_1 #undef DEF_FUNCTION_TYPE_VAR_2 @@ -631,6 +633,10 @@ lto_define_builtins (tree va_list_ref_type_node ATTRIBUTE_UNUSED, #define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7) \ def_fn_type (ENUM, RETURN, 0, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7); +#define DEF_FUNCTION_TYPE_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8) \ + def_fn_type (ENUM, RETURN, 0, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ + ARG7, ARG8); #define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \ def_fn_type (ENUM, RETURN, 1, 0); #define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \ diff --git a/gcc/omp-builtins.def b/gcc/omp-builtins.def index 83c26c44fc970..44c48f496fe4f 100644 --- a/gcc/omp-builtins.def +++ b/gcc/omp-builtins.def @@ -28,6 +28,10 @@ DEF_GOMP_BUILTIN (BUILT_IN_OMP_GET_THREAD_NUM, "omp_get_thread_num", BT_FN_INT, ATTR_CONST_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_OMP_GET_NUM_THREADS, "omp_get_num_threads", BT_FN_INT, ATTR_CONST_NOTHROW_LEAF_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_OMP_GET_TEAM_NUM, "omp_get_team_num", + BT_FN_INT, ATTR_CONST_NOTHROW_LEAF_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_OMP_GET_NUM_TEAMS, "omp_get_num_teams", + BT_FN_INT, ATTR_CONST_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_ATOMIC_START, "GOMP_atomic_start", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) @@ -39,6 +43,14 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKWAIT, "GOMP_taskwait", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKYIELD, "GOMP_taskyield", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKGROUP_START, "GOMP_taskgroup_start", + BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKGROUP_END, "GOMP_taskgroup_end", + BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_CANCEL, "GOMP_cancel", + BT_FN_VOID_INT, ATTR_NULL) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_CANCELLATION_POINT, "GOMP_cancellation_point", + BT_FN_VOID_INT, ATTR_NULL) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_CRITICAL_START, "GOMP_critical_start", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_CRITICAL_END, "GOMP_critical_end", @@ -156,24 +168,24 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ULL_ORDERED_GUIDED_NEXT, DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ULL_ORDERED_RUNTIME_NEXT, "GOMP_loop_ull_ordered_runtime_next", BT_FN_BOOL_ULONGLONGPTR_ULONGLONGPTR, ATTR_NOTHROW_LEAF_LIST) -/* NOTE: Do not change the order of BUILT_IN_GOMP_PARALLEL_LOOP_*_START. +/* NOTE: Do not change the order of BUILT_IN_GOMP_PARALLEL_LOOP_*. They are used in index arithmetic with enum omp_clause_schedule_kind in omp-low.c. */ -DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_LOOP_STATIC_START, - "GOMP_parallel_loop_static_start", - BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG, +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_LOOP_STATIC, + "GOMP_parallel_loop_static", + BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT, ATTR_NOTHROW_LIST) -DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_LOOP_DYNAMIC_START, - "GOMP_parallel_loop_dynamic_start", - BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG, +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_LOOP_DYNAMIC, + "GOMP_parallel_loop_dynamic", + BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT, ATTR_NOTHROW_LIST) -DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_LOOP_GUIDED_START, - "GOMP_parallel_loop_guided_start", - BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG, +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_LOOP_GUIDED, + "GOMP_parallel_loop_guided", + BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT, ATTR_NOTHROW_LIST) -DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_LOOP_RUNTIME_START, - "GOMP_parallel_loop_runtime_start", - BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG, +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_LOOP_RUNTIME, + "GOMP_parallel_loop_runtime", + BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_UINT, ATTR_NOTHROW_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_END, "GOMP_loop_end", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) @@ -183,10 +195,8 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_ORDERED_START, "GOMP_ordered_start", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_ORDERED_END, "GOMP_ordered_end", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) -DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_START, "GOMP_parallel_start", - BT_FN_VOID_OMPFN_PTR_UINT, ATTR_NOTHROW_LIST) -DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_END, "GOMP_parallel_end", - BT_FN_VOID, ATTR_NOTHROW_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, ATTR_NOTHROW_LIST) @@ -194,9 +204,9 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SECTIONS_START, "GOMP_sections_start", BT_FN_UINT_UINT, ATTR_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SECTIONS_NEXT, "GOMP_sections_next", BT_FN_UINT, ATTR_NOTHROW_LEAF_LIST) -DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_SECTIONS_START, - "GOMP_parallel_sections_start", - BT_FN_VOID_OMPFN_PTR_UINT_UINT, ATTR_NOTHROW_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_SECTIONS, + "GOMP_parallel_sections", + BT_FN_VOID_OMPFN_PTR_UINT_UINT_UINT, ATTR_NOTHROW_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SECTIONS_END, "GOMP_sections_end", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SECTIONS_END_NOWAIT, diff --git a/gcc/omp-low.c b/gcc/omp-low.c index afddf3774074a..f5d1735964a55 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see #include "splay-tree.h" #include "optabs.h" #include "cfgloop.h" +#include "target.h" /* Lowering of OpenMP parallel and workshare constructs proceeds in two @@ -222,6 +223,9 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd, int i; struct omp_for_data_loop dummy_loop; location_t loc = gimple_location (for_stmt); + bool simd = gimple_omp_for_kind (for_stmt) & GF_OMP_FOR_KIND_SIMD; + bool distribute = gimple_omp_for_kind (for_stmt) + == GF_OMP_FOR_KIND_DISTRIBUTE; fd->for_stmt = for_stmt; fd->pre = NULL; @@ -231,7 +235,8 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd, else fd->loops = &fd->loop; - fd->have_nowait = fd->have_ordered = false; + fd->have_nowait = distribute; + fd->have_ordered = false; fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC; fd->chunk_size = NULL_TREE; collapse_iter = NULL; @@ -247,9 +252,14 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd, fd->have_ordered = true; break; case OMP_CLAUSE_SCHEDULE: + gcc_assert (!distribute); fd->sched_kind = OMP_CLAUSE_SCHEDULE_KIND (t); fd->chunk_size = OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (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: if (fd->collapse > 1) { @@ -277,8 +287,7 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd, /* We only need to compute a default chunk size for ordered static loops and dynamic loops. */ if (fd->sched_kind != OMP_CLAUSE_SCHEDULE_STATIC - || fd->have_ordered - || fd->collapse > 1) + || fd->have_ordered) fd->chunk_size = (fd->sched_kind == OMP_CLAUSE_SCHEDULE_STATIC) ? integer_zero_node : integer_one_node; } @@ -292,7 +301,6 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd, else loop = &dummy_loop; - loop->v = gimple_omp_for_index (for_stmt, i); gcc_assert (SSA_VAR_P (loop->v)); gcc_assert (TREE_CODE (TREE_TYPE (loop->v)) == INTEGER_TYPE @@ -307,6 +315,10 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd, case LT_EXPR: case GT_EXPR: break; + case NE_EXPR: + gcc_assert (gimple_omp_for_kind (for_stmt) + == GF_OMP_FOR_KIND_CILKSIMD); + break; case LE_EXPR: if (POINTER_TYPE_P (TREE_TYPE (loop->n2))) loop->n2 = fold_build_pointer_plus_hwi_loc (loc, loop->n2, 1); @@ -349,7 +361,20 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd, gcc_unreachable (); } - if (iter_type != long_long_unsigned_type_node) + if (simd + || (fd->sched_kind == OMP_CLAUSE_SCHEDULE_STATIC + && !fd->have_ordered)) + { + if (fd->collapse == 1) + iter_type = TREE_TYPE (loop->v); + else if (i == 0 + || TYPE_PRECISION (iter_type) + < TYPE_PRECISION (TREE_TYPE (loop->v))) + iter_type + = build_nonstandard_integer_type + (TYPE_PRECISION (TREE_TYPE (loop->v)), 1); + } + else if (iter_type != long_long_unsigned_type_node) { if (POINTER_TYPE_P (TREE_TYPE (loop->v))) iter_type = long_long_unsigned_type_node; @@ -445,7 +470,10 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd, } } - if (count) + if (count + && !simd + && (fd->sched_kind != OMP_CLAUSE_SCHEDULE_STATIC + || fd->have_ordered)) { if (!tree_int_cst_lt (count, TYPE_MAX_VALUE (long_integer_type_node))) iter_type = long_long_unsigned_type_node; @@ -556,7 +584,7 @@ workshare_safe_to_combine_p (basic_block ws_entry_bb) expanded. */ static vec * -get_ws_args_for (gimple ws_stmt) +get_ws_args_for (gimple par_stmt, gimple ws_stmt) { tree t; location_t loc = gimple_location (ws_stmt); @@ -565,15 +593,31 @@ get_ws_args_for (gimple ws_stmt) if (gimple_code (ws_stmt) == GIMPLE_OMP_FOR) { struct omp_for_data fd; + tree n1, n2; extract_omp_for_data (ws_stmt, &fd, NULL); + n1 = fd.loop.n1; + n2 = fd.loop.n2; + + if (gimple_omp_for_combined_into_p (ws_stmt)) + { + tree innerc + = find_omp_clause (gimple_omp_parallel_clauses (par_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); + } vec_alloc (ws_args, 3 + (fd.chunk_size != 0)); - t = fold_convert_loc (loc, long_integer_type_node, fd.loop.n1); + t = fold_convert_loc (loc, long_integer_type_node, n1); ws_args->quick_push (t); - t = fold_convert_loc (loc, long_integer_type_node, fd.loop.n2); + t = fold_convert_loc (loc, long_integer_type_node, n2); ws_args->quick_push (t); t = fold_convert_loc (loc, long_integer_type_node, fd.loop.step); @@ -636,6 +680,7 @@ determine_parallel_type (struct omp_region *region) || (last_and_only_stmt (ws_entry_bb) && last_and_only_stmt (par_exit_bb)))) { + gimple par_stmt = last_stmt (par_entry_bb); gimple ws_stmt = last_stmt (ws_entry_bb); if (region->inner->type == GIMPLE_OMP_FOR) @@ -663,7 +708,7 @@ determine_parallel_type (struct omp_region *region) region->is_combined_parallel = true; region->inner->is_combined_parallel = true; - region->ws_args = get_ws_args_for (ws_stmt); + region->ws_args = get_ws_args_for (par_stmt, ws_stmt); } } @@ -918,6 +963,19 @@ build_outer_var_ref (tree var, omp_context *ctx) bool by_ref = use_pointer_for_field (var, NULL); x = build_receiver_ref (var, by_ref, ctx); } + else if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR + && gimple_omp_for_kind (ctx->stmt) & GF_OMP_FOR_KIND_SIMD) + { + /* #pragma omp simd isn't a worksharing construct, and can reference even + private vars in its linear etc. clauses. */ + x = NULL_TREE; + if (ctx->outer && is_taskreg_ctx (ctx)) + x = lookup_decl (var, ctx->outer); + else if (ctx->outer) + x = maybe_lookup_decl (var, ctx->outer); + if (x == NULL_TREE) + x = var; + } else if (ctx->outer) x = lookup_decl (var, ctx->outer); else if (is_reference (var)) @@ -1423,6 +1481,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_FIRSTPRIVATE: case OMP_CLAUSE_REDUCTION: + case OMP_CLAUSE_LINEAR: decl = OMP_CLAUSE_DECL (c); do_private: if (is_variable_sized (decl)) @@ -1450,6 +1509,13 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) install_var_local (decl, ctx); break; + case OMP_CLAUSE__LOOPTEMP_: + gcc_assert (is_parallel_ctx (ctx)); + decl = OMP_CLAUSE_DECL (c); + install_var_field (decl, false, 3, ctx); + install_var_local (decl, ctx); + break; + case OMP_CLAUSE_COPYPRIVATE: case OMP_CLAUSE_COPYIN: decl = OMP_CLAUSE_DECL (c); @@ -1465,6 +1531,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_IF: case OMP_CLAUSE_NUM_THREADS: case OMP_CLAUSE_SCHEDULE: + case OMP_CLAUSE_DIST_SCHEDULE: + case OMP_CLAUSE_DEPEND: if (ctx->outer) scan_omp_op (&OMP_CLAUSE_OPERAND (c, 0), ctx->outer); break; @@ -1474,6 +1542,15 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_COLLAPSE: case OMP_CLAUSE_UNTIED: case OMP_CLAUSE_MERGEABLE: + case OMP_CLAUSE_PROC_BIND: + case OMP_CLAUSE_SAFELEN: + break; + + case OMP_CLAUSE_ALIGNED: + decl = OMP_CLAUSE_DECL (c); + if (is_global_var (decl) + && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) + install_var_local (decl, ctx); break; default: @@ -1497,6 +1574,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_PRIVATE: case OMP_CLAUSE_FIRSTPRIVATE: case OMP_CLAUSE_REDUCTION: + case OMP_CLAUSE_LINEAR: decl = OMP_CLAUSE_DECL (c); if (is_variable_sized (decl)) install_var_local (decl, ctx); @@ -1520,12 +1598,18 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_IF: case OMP_CLAUSE_NUM_THREADS: case OMP_CLAUSE_SCHEDULE: + case OMP_CLAUSE_DIST_SCHEDULE: case OMP_CLAUSE_NOWAIT: case OMP_CLAUSE_ORDERED: case OMP_CLAUSE_COLLAPSE: case OMP_CLAUSE_UNTIED: case OMP_CLAUSE_FINAL: case OMP_CLAUSE_MERGEABLE: + case OMP_CLAUSE_PROC_BIND: + case OMP_CLAUSE_SAFELEN: + case OMP_CLAUSE_ALIGNED: + case OMP_CLAUSE_DEPEND: + case OMP_CLAUSE__LOOPTEMP_: break; default: @@ -1632,6 +1716,35 @@ create_omp_child_function (omp_context *ctx, bool task_copy) } +/* Callback for walk_gimple_seq. Check if combined parallel + contains gimple_omp_for_combined_into_p OMP_FOR. */ + +static tree +find_combined_for (gimple_stmt_iterator *gsi_p, + bool *handled_ops_p, + struct walk_stmt_info *wi) +{ + gimple stmt = gsi_stmt (*gsi_p); + + *handled_ops_p = true; + switch (gimple_code (stmt)) + { + WALK_SUBSTMTS; + + case GIMPLE_OMP_FOR: + if (gimple_omp_for_combined_into_p (stmt) + && gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_FOR) + { + wi->info = stmt; + return integer_zero_node; + } + break; + default: + break; + } + return NULL; +} + /* Scan an OpenMP parallel directive. */ static void @@ -1652,6 +1765,40 @@ scan_omp_parallel (gimple_stmt_iterator *gsi, omp_context *outer_ctx) return; } + if (gimple_omp_parallel_combined_p (stmt)) + { + gimple for_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); + for_stmt = (gimple) wi.info; + if (for_stmt) + { + 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, NULL); + tree c = build_omp_clause (UNKNOWN_LOCATION, + OMP_CLAUSE__LOOPTEMP_); + OMP_CLAUSE_DECL (c) = temp; + OMP_CLAUSE_CHAIN (c) = gimple_omp_parallel_clauses (stmt); + gimple_omp_parallel_set_clauses (stmt, c); + } + } + } + ctx = new_omp_context (stmt, outer_ctx); if (taskreg_nesting_level > 1) ctx->is_nested = true; @@ -1831,9 +1978,46 @@ scan_omp_single (gimple stmt, omp_context *outer_ctx) static bool check_omp_nesting_restrictions (gimple stmt, omp_context *ctx) { + if (ctx != NULL) + { + if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR + && gimple_omp_for_kind (ctx->stmt) & GF_OMP_FOR_KIND_SIMD) + { + error_at (gimple_location (stmt), + "OpenMP constructs may not be nested inside simd region"); + return false; + } + else if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS) + { + if ((gimple_code (stmt) != GIMPLE_OMP_FOR + || (gimple_omp_for_kind (ctx->stmt) + != GF_OMP_FOR_KIND_DISTRIBUTE)) + && gimple_code (stmt) != GIMPLE_OMP_PARALLEL) + { + error_at (gimple_location (stmt), + "only distribute or parallel constructs are allowed to " + "be closely nested inside teams construct"); + return false; + } + } + } switch (gimple_code (stmt)) { case GIMPLE_OMP_FOR: + if (gimple_omp_for_kind (stmt) & GF_OMP_FOR_KIND_SIMD) + return true; + if (gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_DISTRIBUTE) + { + if (ctx != NULL && gimple_code (ctx->stmt) != GIMPLE_OMP_TEAMS) + { + error_at (gimple_location (stmt), + "distribute construct must be closely nested inside " + "teams construct"); + return false; + } + return true; + } + /* FALLTHRU */ case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SINGLE: case GIMPLE_CALL: @@ -1846,8 +2030,12 @@ check_omp_nesting_restrictions (gimple stmt, omp_context *ctx) case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_MASTER: case GIMPLE_OMP_TASK: + case GIMPLE_OMP_CRITICAL: if (is_gimple_call (stmt)) { + if (DECL_FUNCTION_CODE (gimple_call_fndecl (stmt)) + != BUILT_IN_GOMP_BARRIER) + return true; error_at (gimple_location (stmt), "barrier region may not be closely nested inside " "of work-sharing, critical, ordered, master or " @@ -1904,7 +2092,10 @@ check_omp_nesting_restrictions (gimple stmt, omp_context *ctx) } return true; case GIMPLE_OMP_PARALLEL: - return true; + error_at (gimple_location (stmt), + "ordered region must be closely nested inside " + "a loop region with an ordered clause"); + return false; default: break; } @@ -1921,6 +2112,17 @@ check_omp_nesting_restrictions (gimple stmt, omp_context *ctx) return false; } break; + case GIMPLE_OMP_TEAMS: + if (ctx == NULL + || gimple_code (ctx->stmt) != GIMPLE_OMP_TARGET + || gimple_omp_target_kind (ctx->stmt) != GF_OMP_TARGET_KIND_REGION) + { + error_at (gimple_location (stmt), + "teams construct not closely nested inside of target " + "region"); + return false; + } + break; default: break; } @@ -2001,9 +2203,22 @@ scan_omp_1_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, else if (is_gimple_call (stmt)) { tree fndecl = gimple_call_fndecl (stmt); - if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL - && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_GOMP_BARRIER) - remove = !check_omp_nesting_restrictions (stmt, ctx); + if (fndecl + && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL) + switch (DECL_FUNCTION_CODE (fndecl)) + { + case BUILT_IN_GOMP_BARRIER: + case BUILT_IN_GOMP_CANCEL: + case BUILT_IN_GOMP_CANCELLATION_POINT: + case BUILT_IN_GOMP_TASKYIELD: + case BUILT_IN_GOMP_TASKWAIT: + case BUILT_IN_GOMP_TASKGROUP_START: + case BUILT_IN_GOMP_TASKGROUP_END: + remove = !check_omp_nesting_restrictions (stmt, ctx); + break; + default: + break; + } } if (remove) { @@ -2254,6 +2469,116 @@ omp_reduction_init (tree clause, tree type) } } +/* Return alignment to be assumed for var in CLAUSE, which should be + OMP_CLAUSE_ALIGNED. */ + +static tree +omp_clause_aligned_alignment (tree clause) +{ + if (OMP_CLAUSE_ALIGNED_ALIGNMENT (clause)) + return OMP_CLAUSE_ALIGNED_ALIGNMENT (clause); + + /* Otherwise return implementation defined alignment. */ + unsigned int al = 1; + enum machine_mode mode, vmode; + int vs = targetm.vectorize.autovectorize_vector_sizes (); + if (vs) + vs = 1 << floor_log2 (vs); + static enum mode_class classes[] + = { MODE_INT, MODE_VECTOR_INT, MODE_FLOAT, MODE_VECTOR_FLOAT }; + for (int i = 0; i < 4; i += 2) + for (mode = GET_CLASS_NARROWEST_MODE (classes[i]); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + { + vmode = targetm.vectorize.preferred_simd_mode (mode); + if (GET_MODE_CLASS (vmode) != classes[i + 1]) + continue; + while (vs + && GET_MODE_SIZE (vmode) < vs + && GET_MODE_2XWIDER_MODE (vmode) != VOIDmode) + vmode = GET_MODE_2XWIDER_MODE (vmode); + + tree type = lang_hooks.types.type_for_mode (mode, 1); + if (type == NULL_TREE || TYPE_MODE (type) != mode) + continue; + type = build_vector_type (type, GET_MODE_SIZE (vmode) + / GET_MODE_SIZE (mode)); + if (TYPE_MODE (type) != vmode) + continue; + if (TYPE_ALIGN_UNIT (type) > al) + al = TYPE_ALIGN_UNIT (type); + } + return build_int_cst (integer_type_node, al); +} + +/* Return maximum possible vectorization factor for the target. */ + +static int +omp_max_vf (void) +{ + if (!optimize + || optimize_debug + || (!flag_tree_vectorize + && global_options_set.x_flag_tree_vectorize)) + return 1; + + int vs = targetm.vectorize.autovectorize_vector_sizes (); + if (vs) + { + vs = 1 << floor_log2 (vs); + return vs; + } + enum machine_mode vqimode = targetm.vectorize.preferred_simd_mode (QImode); + if (GET_MODE_CLASS (vqimode) == MODE_VECTOR_INT) + return GET_MODE_NUNITS (vqimode); + return 1; +} + +/* Helper function of lower_rec_input_clauses, used for #pragma omp simd + privatization. */ + +static bool +lower_rec_simd_input_clauses (tree new_var, omp_context *ctx, int &max_vf, + tree &idx, tree &lane, tree &ivar, tree &lvar) +{ + if (max_vf == 0) + { + max_vf = omp_max_vf (); + if (max_vf > 1) + { + tree c = find_omp_clause (gimple_omp_for_clauses (ctx->stmt), + OMP_CLAUSE_SAFELEN); + if (c + && compare_tree_int (OMP_CLAUSE_SAFELEN_EXPR (c), max_vf) == -1) + max_vf = tree_low_cst (OMP_CLAUSE_SAFELEN_EXPR (c), 0); + } + if (max_vf > 1) + { + idx = create_tmp_var (unsigned_type_node, NULL); + lane = create_tmp_var (unsigned_type_node, NULL); + } + } + if (max_vf == 1) + return false; + + tree atype = build_array_type_nelts (TREE_TYPE (new_var), max_vf); + tree avar = create_tmp_var_raw (atype, NULL); + if (TREE_ADDRESSABLE (new_var)) + TREE_ADDRESSABLE (avar) = 1; + DECL_ATTRIBUTES (avar) + = tree_cons (get_identifier ("omp simd array"), NULL, + DECL_ATTRIBUTES (avar)); + gimple_add_tmp_var (avar); + ivar = build4 (ARRAY_REF, TREE_TYPE (new_var), avar, idx, + NULL_TREE, NULL_TREE); + lvar = build4 (ARRAY_REF, TREE_TYPE (new_var), avar, lane, + NULL_TREE, NULL_TREE); + SET_DECL_VALUE_EXPR (new_var, lvar); + DECL_HAS_VALUE_EXPR_P (new_var) = 1; + return true; +} + /* Generate code to implement the input clauses, FIRSTPRIVATE and COPYIN, from the receiver (aka child) side and initializers for REFERENCE_TYPE private variables. Initialization statements go in ILIST, while calls @@ -2261,15 +2586,43 @@ omp_reduction_init (tree clause, tree type) static void lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, - omp_context *ctx) + omp_context *ctx, struct omp_for_data *fd) { tree c, dtor, copyin_seq, x, ptr; bool copyin_by_ref = false; bool lastprivate_firstprivate = false; int pass; + bool is_simd = (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR + && gimple_omp_for_kind (ctx->stmt) & GF_OMP_FOR_KIND_SIMD); + int max_vf = 0; + tree lane = NULL_TREE, idx = NULL_TREE; + tree ivar = NULL_TREE, lvar = NULL_TREE; + gimple_seq llist[2] = { NULL, NULL }; copyin_seq = NULL; + /* Enforce simdlen 1 in simd loops with data sharing clauses referencing + variable sized vars. That is unnecessarily hard to support and very + unlikely to result in vectorized code anyway. */ + if (is_simd) + for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c)) + switch (OMP_CLAUSE_CODE (c)) + { + case OMP_CLAUSE_REDUCTION: + if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)) + max_vf = 1; + /* FALLTHRU */ + case OMP_CLAUSE_PRIVATE: + case OMP_CLAUSE_FIRSTPRIVATE: + case OMP_CLAUSE_LASTPRIVATE: + case OMP_CLAUSE_LINEAR: + if (is_variable_sized (OMP_CLAUSE_DECL (c))) + max_vf = 1; + break; + default: + continue; + } + /* Do all the fixed sized types in the first pass, and the variable sized types in the second pass. This makes sure that the scalar arguments to the variable sized types are processed before we use them in the @@ -2298,6 +2651,12 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, case OMP_CLAUSE_FIRSTPRIVATE: case OMP_CLAUSE_COPYIN: case OMP_CLAUSE_REDUCTION: + case OMP_CLAUSE_LINEAR: + break; + case OMP_CLAUSE__LOOPTEMP_: + /* Handle _looptemp_ clauses only on parallel. */ + if (fd) + continue; break; case OMP_CLAUSE_LASTPRIVATE: if (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c)) @@ -2307,6 +2666,42 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, continue; } break; + case OMP_CLAUSE_ALIGNED: + if (pass == 0) + continue; + var = OMP_CLAUSE_DECL (c); + if (TREE_CODE (TREE_TYPE (var)) == POINTER_TYPE + && !is_global_var (var)) + { + new_var = maybe_lookup_decl (var, ctx); + if (new_var == NULL_TREE) + new_var = maybe_lookup_decl_in_outer_ctx (var, ctx); + x = builtin_decl_explicit (BUILT_IN_ASSUME_ALIGNED); + x = build_call_expr_loc (clause_loc, x, 2, new_var, + omp_clause_aligned_alignment (c)); + x = fold_convert_loc (clause_loc, TREE_TYPE (new_var), x); + x = build2 (MODIFY_EXPR, TREE_TYPE (new_var), new_var, x); + gimplify_and_add (x, ilist); + } + else if (TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE + && is_global_var (var)) + { + tree ptype = build_pointer_type (TREE_TYPE (var)), t, t2; + new_var = lookup_decl (var, ctx); + t = maybe_lookup_decl_in_outer_ctx (var, ctx); + t = build_fold_addr_expr_loc (clause_loc, t); + t2 = builtin_decl_explicit (BUILT_IN_ASSUME_ALIGNED); + t = build_call_expr_loc (clause_loc, t2, 2, t, + omp_clause_aligned_alignment (c)); + t = fold_convert_loc (clause_loc, ptype, t); + x = create_tmp_var (ptype, NULL); + t = build2 (MODIFY_EXPR, ptype, x, t); + gimplify_and_add (t, ilist); + t = build_simple_mem_ref_loc (clause_loc, x); + SET_DECL_VALUE_EXPR (new_var, t); + DECL_HAS_VALUE_EXPR_P (new_var) = 1; + } + continue; default: continue; } @@ -2443,7 +2838,36 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, } else x = NULL; + do_private: x = lang_hooks.decls.omp_clause_default_ctor (c, new_var, x); + if (is_simd) + { + tree y = lang_hooks.decls.omp_clause_dtor (c, new_var); + if ((TREE_ADDRESSABLE (new_var) || x || y + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE) + && lower_rec_simd_input_clauses (new_var, ctx, max_vf, + idx, lane, ivar, lvar)) + { + if (x) + x = lang_hooks.decls.omp_clause_default_ctor + (c, unshare_expr (ivar), x); + if (x) + gimplify_and_add (x, &llist[0]); + if (y) + { + y = lang_hooks.decls.omp_clause_dtor (c, ivar); + if (y) + { + gimple_seq tseq = NULL; + + dtor = y; + gimplify_stmt (&dtor, &tseq); + gimple_seq_add_seq (&llist[1], tseq); + } + } + break; + } + } if (x) gimplify_and_add (x, ilist); /* FALLTHRU */ @@ -2460,6 +2884,15 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, } break; + case OMP_CLAUSE_LINEAR: + if (!OMP_CLAUSE_LINEAR_NO_COPYIN (c)) + goto do_firstprivate; + if (OMP_CLAUSE_LINEAR_NO_COPYOUT (c)) + x = NULL; + else + x = build_outer_var_ref (var, ctx); + goto do_private; + case OMP_CLAUSE_FIRSTPRIVATE: if (is_task_ctx (ctx)) { @@ -2475,10 +2908,100 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, goto do_dtor; } } + do_firstprivate: x = build_outer_var_ref (var, ctx); + if (is_simd) + { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR + && gimple_omp_for_combined_into_p (ctx->stmt)) + { + tree stept = POINTER_TYPE_P (TREE_TYPE (x)) + ? sizetype : TREE_TYPE (x); + tree t = fold_convert (stept, + OMP_CLAUSE_LINEAR_STEP (c)); + tree c = find_omp_clause (clauses, + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (c); + tree l = OMP_CLAUSE_DECL (c); + if (fd->collapse == 1) + { + tree n1 = fd->loop.n1; + tree step = fd->loop.step; + tree itype = TREE_TYPE (l); + if (POINTER_TYPE_P (itype)) + itype = signed_type_for (itype); + l = fold_build2 (MINUS_EXPR, itype, l, n1); + if (TYPE_UNSIGNED (itype) + && fd->loop.cond_code == GT_EXPR) + l = fold_build2 (TRUNC_DIV_EXPR, itype, + fold_build1 (NEGATE_EXPR, + itype, l), + fold_build1 (NEGATE_EXPR, + itype, step)); + else + l = fold_build2 (TRUNC_DIV_EXPR, itype, l, step); + } + t = fold_build2 (MULT_EXPR, stept, + fold_convert (stept, l), t); + if (POINTER_TYPE_P (TREE_TYPE (x))) + x = fold_build2 (POINTER_PLUS_EXPR, + TREE_TYPE (x), x, t); + else + x = fold_build2 (PLUS_EXPR, TREE_TYPE (x), x, t); + } + + if ((OMP_CLAUSE_CODE (c) != OMP_CLAUSE_LINEAR + || TREE_ADDRESSABLE (new_var)) + && lower_rec_simd_input_clauses (new_var, ctx, max_vf, + idx, lane, ivar, lvar)) + { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR) + { + tree iv = create_tmp_var (TREE_TYPE (new_var), NULL); + x = lang_hooks.decls.omp_clause_copy_ctor (c, iv, x); + gimplify_and_add (x, ilist); + gimple_stmt_iterator gsi + = gsi_start_1 (gimple_omp_body_ptr (ctx->stmt)); + gimple g + = gimple_build_assign (unshare_expr (lvar), iv); + gsi_insert_before_without_update (&gsi, g, + GSI_SAME_STMT); + tree stept = POINTER_TYPE_P (TREE_TYPE (x)) + ? sizetype : TREE_TYPE (x); + tree t = fold_convert (stept, + OMP_CLAUSE_LINEAR_STEP (c)); + enum tree_code code = PLUS_EXPR; + if (POINTER_TYPE_P (TREE_TYPE (new_var))) + code = POINTER_PLUS_EXPR; + g = gimple_build_assign_with_ops (code, iv, iv, t); + gsi_insert_before_without_update (&gsi, g, + GSI_SAME_STMT); + break; + } + x = lang_hooks.decls.omp_clause_copy_ctor + (c, unshare_expr (ivar), x); + gimplify_and_add (x, &llist[0]); + x = lang_hooks.decls.omp_clause_dtor (c, ivar); + if (x) + { + gimple_seq tseq = NULL; + + dtor = x; + gimplify_stmt (&dtor, &tseq); + gimple_seq_add_seq (&llist[1], tseq); + } + break; + } + } x = lang_hooks.decls.omp_clause_copy_ctor (c, new_var, x); gimplify_and_add (x, ilist); goto do_dtor; + + case OMP_CLAUSE__LOOPTEMP_: + gcc_assert (is_parallel_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); break; case OMP_CLAUSE_COPYIN: @@ -2495,6 +3018,8 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, tree placeholder = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c); x = build_outer_var_ref (var, ctx); + /* FIXME: Not handled yet. */ + gcc_assert (!is_simd); if (is_reference (var)) x = build_fold_addr_expr_loc (clause_loc, x); SET_DECL_VALUE_EXPR (placeholder, x); @@ -2509,7 +3034,31 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, { x = omp_reduction_init (c, TREE_TYPE (new_var)); gcc_assert (TREE_CODE (TREE_TYPE (new_var)) != ARRAY_TYPE); - gimplify_assign (new_var, x, ilist); + if (is_simd + && lower_rec_simd_input_clauses (new_var, ctx, max_vf, + idx, lane, ivar, lvar)) + { + enum tree_code code = OMP_CLAUSE_REDUCTION_CODE (c); + tree ref = build_outer_var_ref (var, ctx); + + gimplify_assign (unshare_expr (ivar), x, &llist[0]); + + /* reduction(-:var) sums up the partial results, so it + acts identically to reduction(+:var). */ + if (code == MINUS_EXPR) + code = PLUS_EXPR; + + x = build2 (code, TREE_TYPE (ref), ref, ivar); + ref = build_outer_var_ref (var, ctx); + gimplify_assign (ref, x, &llist[1]); + } + else + { + gimplify_assign (new_var, x, ilist); + if (is_simd) + gimplify_assign (build_outer_var_ref (var, ctx), + new_var, dlist); + } } break; @@ -2519,6 +3068,49 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, } } + if (lane) + { + tree uid = create_tmp_var (ptr_type_node, "simduid"); + gimple g + = gimple_build_call_internal (IFN_GOMP_SIMD_LANE, 1, uid); + gimple_call_set_lhs (g, lane); + gimple_stmt_iterator gsi = gsi_start_1 (gimple_omp_body_ptr (ctx->stmt)); + gsi_insert_before_without_update (&gsi, g, GSI_SAME_STMT); + c = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE__SIMDUID_); + OMP_CLAUSE__SIMDUID__DECL (c) = uid; + OMP_CLAUSE_CHAIN (c) = gimple_omp_for_clauses (ctx->stmt); + gimple_omp_for_set_clauses (ctx->stmt, c); + g = gimple_build_assign_with_ops (INTEGER_CST, lane, + build_int_cst (unsigned_type_node, 0), + NULL_TREE); + gimple_seq_add_stmt (ilist, g); + for (int i = 0; i < 2; i++) + if (llist[i]) + { + tree vf = create_tmp_var (unsigned_type_node, NULL); + g = gimple_build_call_internal (IFN_GOMP_SIMD_VF, 1, uid); + gimple_call_set_lhs (g, vf); + gimple_seq *seq = i == 0 ? ilist : dlist; + gimple_seq_add_stmt (seq, g); + tree t = build_int_cst (unsigned_type_node, 0); + g = gimple_build_assign_with_ops (INTEGER_CST, idx, t, NULL_TREE); + gimple_seq_add_stmt (seq, g); + tree body = create_artificial_label (UNKNOWN_LOCATION); + tree header = create_artificial_label (UNKNOWN_LOCATION); + tree end = create_artificial_label (UNKNOWN_LOCATION); + gimple_seq_add_stmt (seq, gimple_build_goto (header)); + gimple_seq_add_stmt (seq, gimple_build_label (body)); + gimple_seq_add_seq (seq, llist[i]); + t = build_int_cst (unsigned_type_node, 1); + g = gimple_build_assign_with_ops (PLUS_EXPR, idx, idx, t); + gimple_seq_add_stmt (seq, g); + gimple_seq_add_stmt (seq, gimple_build_label (header)); + g = gimple_build_cond (LT_EXPR, idx, vf, body, end); + gimple_seq_add_stmt (seq, g); + gimple_seq_add_stmt (seq, gimple_build_label (end)); + } + } + /* The copyin sequence is not to be executed by the main thread, since that would result in self-copies. Perhaps not visible to scalars, but it certainly is to C++ operator=. */ @@ -2538,7 +3130,31 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, lastprivate clauses we need to ensure the lastprivate copying happens after firstprivate copying in all threads. */ if (copyin_by_ref || lastprivate_firstprivate) - gimplify_and_add (build_omp_barrier (), ilist); + { + /* Don't add any barrier for #pragma omp simd or + #pragma omp distribute. */ + if (gimple_code (ctx->stmt) != GIMPLE_OMP_FOR + || gimple_omp_for_kind (ctx->stmt) & GF_OMP_FOR_KIND_FOR) + gimplify_and_add (build_omp_barrier (), ilist); + } + + /* If max_vf is non-NULL, then we can use only vectorization factor + up to the max_vf we chose. So stick it into safelen clause. */ + if (max_vf) + { + tree c = find_omp_clause (gimple_omp_for_clauses (ctx->stmt), + OMP_CLAUSE_SAFELEN); + if (c == NULL_TREE + || compare_tree_int (OMP_CLAUSE_SAFELEN_EXPR (c), + max_vf) == 1) + { + c = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE_SAFELEN); + OMP_CLAUSE_SAFELEN_EXPR (c) = build_int_cst (integer_type_node, + max_vf); + OMP_CLAUSE_CHAIN (c) = gimple_omp_for_clauses (ctx->stmt); + gimple_omp_for_set_clauses (ctx->stmt, c); + } + } } @@ -2548,13 +3164,18 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, static void lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *stmt_list, - omp_context *ctx) + omp_context *ctx) { - tree x, c, label = NULL; + tree x, c, label = NULL, orig_clauses = clauses; bool par_clauses = false; + tree simduid = NULL, lastlane = NULL; - /* Early exit if there are no lastprivate clauses. */ - clauses = find_omp_clause (clauses, OMP_CLAUSE_LASTPRIVATE); + /* Early exit if there are no lastprivate or linear clauses. */ + for (; clauses ; clauses = OMP_CLAUSE_CHAIN (clauses)) + if (OMP_CLAUSE_CODE (clauses) == OMP_CLAUSE_LASTPRIVATE + || (OMP_CLAUSE_CODE (clauses) == OMP_CLAUSE_LINEAR + && !OMP_CLAUSE_LINEAR_NO_COPYOUT (clauses))) + break; if (clauses == NULL) { /* If this was a workshare clause, see if it had been combined @@ -2591,23 +3212,59 @@ lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *stmt_list, gimple_seq_add_stmt (stmt_list, gimple_build_label (label_true)); } + if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR + && gimple_omp_for_kind (ctx->stmt) & GF_OMP_FOR_KIND_SIMD) + { + simduid = find_omp_clause (orig_clauses, OMP_CLAUSE__SIMDUID_); + if (simduid) + simduid = OMP_CLAUSE__SIMDUID__DECL (simduid); + } + for (c = clauses; c ;) { tree var, new_var; location_t clause_loc = OMP_CLAUSE_LOCATION (c); - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE + || (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR + && !OMP_CLAUSE_LINEAR_NO_COPYOUT (c))) { var = OMP_CLAUSE_DECL (c); new_var = lookup_decl (var, ctx); - if (OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c)) + if (simduid && DECL_HAS_VALUE_EXPR_P (new_var)) + { + tree val = DECL_VALUE_EXPR (new_var); + if (TREE_CODE (val) == ARRAY_REF + && VAR_P (TREE_OPERAND (val, 0)) + && lookup_attribute ("omp simd array", + DECL_ATTRIBUTES (TREE_OPERAND (val, + 0)))) + { + if (lastlane == NULL) + { + lastlane = create_tmp_var (unsigned_type_node, NULL); + gimple g + = gimple_build_call_internal (IFN_GOMP_SIMD_LAST_LANE, + 2, simduid, + TREE_OPERAND (val, 1)); + gimple_call_set_lhs (g, lastlane); + gimple_seq_add_stmt (stmt_list, g); + } + new_var = build4 (ARRAY_REF, TREE_TYPE (val), + TREE_OPERAND (val, 0), lastlane, + NULL_TREE, NULL_TREE); + } + } + + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE + && OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c)) { lower_omp (&OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c), ctx); gimple_seq_add_seq (stmt_list, OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c)); + OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c) = NULL; } - OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c) = NULL; x = build_outer_var_ref (var, ctx); if (is_reference (var)) @@ -2649,6 +3306,11 @@ lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp, omp_context *ctx) tree x, c; int count = 0; + /* SIMD reductions are handled in lower_rec_input_clauses. */ + if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR + && gimple_omp_for_kind (ctx->stmt) & GF_OMP_FOR_KIND_SIMD) + return; + /* First see if there is exactly one reduction clause. Use OMP_ATOMIC update in that case, otherwise use a lock. */ for (c = clauses; c && count < 2; c = OMP_CLAUSE_CHAIN (c)) @@ -2806,6 +3468,7 @@ lower_send_clauses (tree clauses, gimple_seq *ilist, gimple_seq *olist, case OMP_CLAUSE_COPYIN: case OMP_CLAUSE_LASTPRIVATE: case OMP_CLAUSE_REDUCTION: + case OMP_CLAUSE__LOOPTEMP_: break; default: continue; @@ -2826,6 +3489,7 @@ lower_send_clauses (tree clauses, gimple_seq *ilist, gimple_seq *olist, case OMP_CLAUSE_PRIVATE: case OMP_CLAUSE_FIRSTPRIVATE: case OMP_CLAUSE_COPYIN: + case OMP_CLAUSE__LOOPTEMP_: do_in = true; break; @@ -2948,7 +3612,7 @@ static void expand_parallel_call (struct omp_region *region, basic_block bb, gimple entry_stmt, vec *ws_args) { - tree t, t1, t2, val, cond, c, clauses; + tree t, t1, t2, val, cond, c, clauses, flags; gimple_stmt_iterator gsi; gimple stmt; enum built_in_function start_ix; @@ -2958,23 +3622,23 @@ expand_parallel_call (struct omp_region *region, basic_block bb, clauses = gimple_omp_parallel_clauses (entry_stmt); - /* Determine what flavor of GOMP_parallel_start we will be + /* Determine what flavor of GOMP_parallel we will be emitting. */ - start_ix = BUILT_IN_GOMP_PARALLEL_START; + start_ix = BUILT_IN_GOMP_PARALLEL; if (is_combined_parallel (region)) { switch (region->inner->type) { case GIMPLE_OMP_FOR: gcc_assert (region->inner->sched_kind != OMP_CLAUSE_SCHEDULE_AUTO); - start_ix2 = ((int)BUILT_IN_GOMP_PARALLEL_LOOP_STATIC_START + start_ix2 = ((int)BUILT_IN_GOMP_PARALLEL_LOOP_STATIC + (region->inner->sched_kind == OMP_CLAUSE_SCHEDULE_RUNTIME ? 3 : region->inner->sched_kind)); start_ix = (enum built_in_function)start_ix2; break; case GIMPLE_OMP_SECTIONS: - start_ix = BUILT_IN_GOMP_PARALLEL_SECTIONS_START; + start_ix = BUILT_IN_GOMP_PARALLEL_SECTIONS; break; default: gcc_unreachable (); @@ -2985,6 +3649,7 @@ expand_parallel_call (struct omp_region *region, basic_block bb, and there is no conditional. */ cond = NULL_TREE; val = build_int_cst (unsigned_type_node, 0); + flags = build_int_cst (unsigned_type_node, 0); c = find_omp_clause (clauses, OMP_CLAUSE_IF); if (c) @@ -2999,6 +3664,10 @@ expand_parallel_call (struct omp_region *region, basic_block bb, else clause_loc = gimple_location (entry_stmt); + c = find_omp_clause (clauses, OMP_CLAUSE_PROC_BIND); + if (c) + flags = build_int_cst (unsigned_type_node, OMP_CLAUSE_PROC_BIND_KIND (c)); + /* Ensure 'val' is of the correct type. */ val = fold_convert_loc (clause_loc, unsigned_type_node, val); @@ -3090,34 +3759,19 @@ expand_parallel_call (struct omp_region *region, basic_block bb, t1 = build_fold_addr_expr (t); t2 = build_fold_addr_expr (gimple_omp_parallel_child_fn (entry_stmt)); - vec_alloc (args, 3 + vec_safe_length (ws_args)); + vec_alloc (args, 4 + vec_safe_length (ws_args)); args->quick_push (t2); args->quick_push (t1); args->quick_push (val); if (ws_args) args->splice (*ws_args); + args->quick_push (flags); t = build_call_expr_loc_vec (UNKNOWN_LOCATION, builtin_decl_explicit (start_ix), args); force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, false, GSI_CONTINUE_LINKING); - - t = gimple_omp_parallel_data_arg (entry_stmt); - if (t == NULL) - t = null_pointer_node; - else - t = build_fold_addr_expr (t); - t = build_call_expr_loc (gimple_location (entry_stmt), - gimple_omp_parallel_child_fn (entry_stmt), 1, t); - force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, - false, GSI_CONTINUE_LINKING); - - t = build_call_expr_loc (gimple_location (entry_stmt), - builtin_decl_explicit (BUILT_IN_GOMP_PARALLEL_END), - 0); - force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, - false, GSI_CONTINUE_LINKING); } @@ -3411,6 +4065,24 @@ expand_omp_regimplify_p (tree *tp, int *walk_subtrees, void *) return NULL_TREE; } +/* Prepend TO = FROM assignment before *GSI_P. */ + +static void +expand_omp_build_assign (gimple_stmt_iterator *gsi_p, tree to, tree from) +{ + 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); + gimple stmt = gimple_build_assign (to, from); + 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)) + { + gimple_stmt_iterator gsi = gsi_for_stmt (stmt); + gimple_regimplify_operands (stmt, &gsi); + } +} + /* Expand the OpenMP parallel or task directive starting at REGION. */ static void @@ -3654,77 +4326,415 @@ expand_omp_taskreg (struct omp_region *region) } -/* 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. - - 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; +/* Helper function for expand_omp_{for_*,simd}. If this is the outermost + of the combined collapse > 1 loop constructs, generate code like: + if (__builtin_expect (N32 cond3 N31, 0)) goto ZERO_ITER_BB; 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 (__builtin_expect (N22 cond2 N21, 0)) goto ZERO_ITER_BB; 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 (__builtin_expect (N12 cond1 N11, 0)) goto ZERO_ITER_BB; if (cond1 is <) adj = STEP1 - 1; else adj = STEP1 + 1; count1 = (adj + N12 - N11) / STEP1; count = count1 * count2 * count3; - goto Z1; - Z0: + Furthermore, if ZERO_ITER_BB is NULL, create a BB which does: count = 0; - Z1: - more = GOMP_loop_foo_start (0, count, 1, CHUNK, &istart0, &iend0); - if (more) goto L0; else goto L3; - L0: - V = istart0; - T = V; - V3 = N31 + (T % count3) * STEP3; - T = T / count3; - V2 = N21 + (T % count2) * STEP2; - T = T / count2; - V1 = N11 + T * STEP1; - iend = iend0; - L1: - BODY; - V += 1; - if (V < iend) goto L10; else goto L2; - L10: + and set ZERO_ITER_BB to that bb. If this isn't the outermost + of the combined loop constructs, just initialize COUNTS array + from the _looptemp_ clauses. */ + +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 &l2_dom_bb) +{ + tree t, type = TREE_TYPE (fd->loop.v); + gimple stmt; + edge e, ne; + int i; + + /* collapsed loops need work for expansion in SSA form. */ + gcc_assert (!gimple_in_ssa_p (cfun)); + + if (gimple_omp_for_combined_into_p (fd->for_stmt) + && TREE_CODE (fd->loop.n2) != INTEGER_CST) + { + /* First two _looptemp_ clauses are for istart/iend, counts[0] + isn't supposed to be handled, as the inner loop doesn't + use it. */ + tree innerc = find_omp_clause (gimple_omp_for_clauses (fd->for_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); + if (i) + counts[i] = OMP_CLAUSE_DECL (innerc); + else + counts[0] = NULL_TREE; + } + return; + } + + for (i = 0; i < fd->collapse; i++) + { + tree itype = TREE_TYPE (fd->loops[i].v); + + if (SSA_VAR_P (fd->loop.n2) + && ((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))) + == NULL_TREE || !integer_onep (t))) + { + tree n1, n2; + n1 = fold_convert (itype, unshare_expr (fd->loops[i].n1)); + n1 = force_gimple_operand_gsi (gsi, n1, true, NULL_TREE, + true, GSI_SAME_STMT); + n2 = fold_convert (itype, unshare_expr (fd->loops[i].n2)); + n2 = force_gimple_operand_gsi (gsi, n2, true, NULL_TREE, + true, GSI_SAME_STMT); + stmt = gimple_build_cond (fd->loops[i].cond_code, n1, n2, + NULL_TREE, NULL_TREE); + gsi_insert_before (gsi, stmt, GSI_SAME_STMT); + if (walk_tree (gimple_cond_lhs_ptr (stmt), + expand_omp_regimplify_p, NULL, NULL) + || walk_tree (gimple_cond_rhs_ptr (stmt), + expand_omp_regimplify_p, NULL, NULL)) + { + *gsi = gsi_for_stmt (stmt); + gimple_regimplify_operands (stmt, gsi); + } + e = split_block (entry_bb, stmt); + if (zero_iter_bb == NULL) + { + first_zero_iter = i; + zero_iter_bb = create_empty_bb (entry_bb); + if (current_loops) + add_bb_to_loop (zero_iter_bb, entry_bb->loop_father); + *gsi = gsi_after_labels (zero_iter_bb); + stmt = gimple_build_assign (fd->loop.n2, + build_zero_cst (type)); + gsi_insert_before (gsi, stmt, GSI_SAME_STMT); + set_immediate_dominator (CDI_DOMINATORS, zero_iter_bb, + entry_bb); + } + ne = make_edge (entry_bb, zero_iter_bb, EDGE_FALSE_VALUE); + ne->probability = REG_BR_PROB_BASE / 2000 - 1; + e->flags = EDGE_TRUE_VALUE; + e->probability = REG_BR_PROB_BASE - ne->probability; + if (l2_dom_bb == NULL) + l2_dom_bb = entry_bb; + entry_bb = e->dest; + *gsi = gsi_last_bb (entry_bb); + } + + if (POINTER_TYPE_P (itype)) + itype = signed_type_for (itype); + t = build_int_cst (itype, (fd->loops[i].cond_code == LT_EXPR + ? -1 : 1)); + t = fold_build2 (PLUS_EXPR, itype, + fold_convert (itype, fd->loops[i].step), t); + t = fold_build2 (PLUS_EXPR, itype, t, + fold_convert (itype, fd->loops[i].n2)); + t = fold_build2 (MINUS_EXPR, itype, t, + fold_convert (itype, fd->loops[i].n1)); + if (TYPE_UNSIGNED (itype) && fd->loops[i].cond_code == GT_EXPR) + t = fold_build2 (TRUNC_DIV_EXPR, itype, + fold_build1 (NEGATE_EXPR, itype, t), + fold_build1 (NEGATE_EXPR, itype, + fold_convert (itype, + fd->loops[i].step))); + else + t = fold_build2 (TRUNC_DIV_EXPR, itype, t, + fold_convert (itype, fd->loops[i].step)); + t = fold_convert (type, t); + if (TREE_CODE (t) == INTEGER_CST) + counts[i] = t; + else + { + counts[i] = create_tmp_reg (type, ".count"); + expand_omp_build_assign (gsi, counts[i], t); + } + if (SSA_VAR_P (fd->loop.n2)) + { + if (i == 0) + t = counts[0]; + else + t = fold_build2 (MULT_EXPR, type, fd->loop.n2, counts[i]); + expand_omp_build_assign (gsi, fd->loop.n2, t); + } + } +} + + +/* Helper function for expand_omp_{for_*,simd}. Generate code like: + T = V; + V3 = N31 + (T % count3) * STEP3; + T = T / count3; + V2 = N21 + (T % count2) * STEP2; + T = T / count2; + V1 = N11 + T * STEP1; + if this loop doesn't have an inner loop construct combined with it. + If it does have an inner loop construct combined with it and the + iteration count isn't known constant, store values from counts array + into its _looptemp_ temporaries instead. */ + +static void +expand_omp_for_init_vars (struct omp_for_data *fd, gimple_stmt_iterator *gsi, + tree *counts, gimple inner_stmt, tree startvar) +{ + int i; + if (gimple_omp_for_combined_p (fd->for_stmt)) + { + /* If fd->loop.n2 is constant, then no propagation of the counts + is needed, they are constant. */ + if (TREE_CODE (fd->loop.n2) == INTEGER_CST) + return; + + tree clauses = gimple_code (inner_stmt) == GIMPLE_OMP_PARALLEL + ? gimple_omp_parallel_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 + use it. */ + tree innerc = find_omp_clause (clauses, 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); + if (i) + { + tree tem = OMP_CLAUSE_DECL (innerc); + tree t = fold_convert (TREE_TYPE (tem), counts[i]); + t = force_gimple_operand_gsi (gsi, t, false, NULL_TREE, + false, GSI_CONTINUE_LINKING); + gimple stmt = gimple_build_assign (tem, t); + gsi_insert_after (gsi, stmt, GSI_CONTINUE_LINKING); + } + } + return; + } + + tree type = TREE_TYPE (fd->loop.v); + tree tem = create_tmp_reg (type, ".tem"); + gimple stmt = gimple_build_assign (tem, startvar); + gsi_insert_after (gsi, stmt, GSI_CONTINUE_LINKING); + + for (i = fd->collapse - 1; i >= 0; i--) + { + tree vtype = TREE_TYPE (fd->loops[i].v), itype, t; + itype = vtype; + if (POINTER_TYPE_P (vtype)) + itype = signed_type_for (vtype); + if (i != 0) + t = fold_build2 (TRUNC_MOD_EXPR, type, tem, counts[i]); + else + t = tem; + t = fold_convert (itype, t); + t = fold_build2 (MULT_EXPR, itype, t, + fold_convert (itype, fd->loops[i].step)); + if (POINTER_TYPE_P (vtype)) + t = fold_build_pointer_plus (fd->loops[i].n1, t); + else + t = fold_build2 (PLUS_EXPR, itype, fd->loops[i].n1, t); + t = force_gimple_operand_gsi (gsi, t, + DECL_P (fd->loops[i].v) + && TREE_ADDRESSABLE (fd->loops[i].v), + NULL_TREE, false, + GSI_CONTINUE_LINKING); + stmt = gimple_build_assign (fd->loops[i].v, t); + gsi_insert_after (gsi, stmt, GSI_CONTINUE_LINKING); + if (i != 0) + { + t = fold_build2 (TRUNC_DIV_EXPR, type, tem, counts[i]); + t = force_gimple_operand_gsi (gsi, t, false, NULL_TREE, + false, GSI_CONTINUE_LINKING); + stmt = gimple_build_assign (tem, t); + gsi_insert_after (gsi, stmt, GSI_CONTINUE_LINKING); + } + } +} + + +/* Helper function for expand_omp_for_*. Generate code like: + L10: + V3 += STEP3; + if (V3 cond3 N32) goto BODY_BB; else goto L11; + L11: + V3 = N31; + V2 += STEP2; + if (V2 cond2 N22) goto BODY_BB; else goto L12; + L12: + V2 = N21; + V1 += STEP1; + goto BODY_BB; */ + +static basic_block +extract_omp_for_update_vars (struct omp_for_data *fd, basic_block cont_bb, + basic_block body_bb) +{ + basic_block last_bb, bb, collapse_bb = NULL; + int i; + gimple_stmt_iterator gsi; + edge e; + tree t; + gimple stmt; + + last_bb = cont_bb; + for (i = fd->collapse - 1; i >= 0; i--) + { + tree vtype = TREE_TYPE (fd->loops[i].v); + + bb = create_empty_bb (last_bb); + if (current_loops) + add_bb_to_loop (bb, last_bb->loop_father); + gsi = gsi_start_bb (bb); + + if (i < fd->collapse - 1) + { + e = make_edge (last_bb, bb, EDGE_FALSE_VALUE); + e->probability = REG_BR_PROB_BASE / 8; + + t = fd->loops[i + 1].n1; + t = force_gimple_operand_gsi (&gsi, t, + DECL_P (fd->loops[i + 1].v) + && TREE_ADDRESSABLE (fd->loops[i + + 1].v), + NULL_TREE, false, + GSI_CONTINUE_LINKING); + stmt = gimple_build_assign (fd->loops[i + 1].v, t); + gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); + } + else + collapse_bb = bb; + + set_immediate_dominator (CDI_DOMINATORS, bb, last_bb); + + if (POINTER_TYPE_P (vtype)) + t = fold_build_pointer_plus (fd->loops[i].v, fd->loops[i].step); + else + t = fold_build2 (PLUS_EXPR, vtype, fd->loops[i].v, fd->loops[i].step); + t = force_gimple_operand_gsi (&gsi, t, + DECL_P (fd->loops[i].v) + && TREE_ADDRESSABLE (fd->loops[i].v), + NULL_TREE, false, GSI_CONTINUE_LINKING); + stmt = gimple_build_assign (fd->loops[i].v, t); + gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); + + if (i > 0) + { + t = fd->loops[i].n2; + t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, + false, GSI_CONTINUE_LINKING); + tree v = fd->loops[i].v; + if (DECL_P (v) && TREE_ADDRESSABLE (v)) + v = force_gimple_operand_gsi (&gsi, v, true, NULL_TREE, + false, GSI_CONTINUE_LINKING); + t = fold_build2 (fd->loops[i].cond_code, boolean_type_node, v, t); + stmt = gimple_build_cond_empty (t); + gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); + e = make_edge (bb, body_bb, EDGE_TRUE_VALUE); + e->probability = REG_BR_PROB_BASE * 7 / 8; + } + else + make_edge (bb, body_bb, EDGE_FALLTHRU); + last_bb = bb; + } + + return collapse_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 <) + adj = STEP1 - 1; + else + adj = STEP1 + 1; + count1 = (adj + N12 - N11) / STEP1; + count = count1 * count2 * count3; + goto Z1; + Z0: + count = 0; + Z1: + more = GOMP_loop_foo_start (0, count, 1, CHUNK, &istart0, &iend0); + if (more) goto L0; else goto L3; + L0: + V = istart0; + T = V; + V3 = N31 + (T % count3) * STEP3; + T = T / count3; + V2 = N21 + (T % count2) * STEP2; + T = T / count2; + V1 = N11 + T * STEP1; + iend = iend0; + L1: + BODY; + V += 1; + if (V < iend) goto L10; else goto L2; + L10: V3 += STEP3; if (V3 cond3 N32) goto L1; else goto L11; L11: @@ -3745,7 +4755,8 @@ static void expand_omp_for_generic (struct omp_region *region, struct omp_for_data *fd, enum built_in_function start_fn, - enum built_in_function next_fn) + enum built_in_function next_fn, + gimple inner_stmt) { tree type, istart0, iend0, iend; tree t, vmain, vback, bias = NULL_TREE; @@ -3816,105 +4827,14 @@ expand_omp_for_generic (struct omp_region *region, gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR); if (fd->collapse > 1) { - basic_block zero_iter_bb = NULL; int first_zero_iter = -1; + basic_block zero_iter_bb = NULL, l2_dom_bb = NULL; - /* collapsed loops need work for expansion in SSA form. */ - gcc_assert (!gimple_in_ssa_p (cfun)); - counts = (tree *) alloca (fd->collapse * sizeof (tree)); - for (i = 0; i < fd->collapse; i++) - { - tree itype = TREE_TYPE (fd->loops[i].v); + counts = XALLOCAVEC (tree, fd->collapse); + expand_omp_for_init_counts (fd, &gsi, entry_bb, counts, + zero_iter_bb, first_zero_iter, + l2_dom_bb); - if (SSA_VAR_P (fd->loop.n2) - && ((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))) - == NULL_TREE || !integer_onep (t))) - { - tree n1, n2; - n1 = fold_convert (itype, unshare_expr (fd->loops[i].n1)); - n1 = force_gimple_operand_gsi (&gsi, n1, true, NULL_TREE, - true, GSI_SAME_STMT); - n2 = fold_convert (itype, unshare_expr (fd->loops[i].n2)); - n2 = force_gimple_operand_gsi (&gsi, n2, true, NULL_TREE, - true, GSI_SAME_STMT); - stmt = gimple_build_cond (fd->loops[i].cond_code, n1, n2, - NULL_TREE, NULL_TREE); - gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); - if (walk_tree (gimple_cond_lhs_ptr (stmt), - expand_omp_regimplify_p, NULL, NULL) - || walk_tree (gimple_cond_rhs_ptr (stmt), - expand_omp_regimplify_p, NULL, NULL)) - { - gsi = gsi_for_stmt (stmt); - gimple_regimplify_operands (stmt, &gsi); - } - e = split_block (entry_bb, stmt); - if (zero_iter_bb == NULL) - { - first_zero_iter = i; - zero_iter_bb = create_empty_bb (entry_bb); - if (current_loops) - add_bb_to_loop (zero_iter_bb, entry_bb->loop_father); - gsi = gsi_after_labels (zero_iter_bb); - stmt = gimple_build_assign (fd->loop.n2, - build_zero_cst (type)); - gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); - set_immediate_dominator (CDI_DOMINATORS, zero_iter_bb, - entry_bb); - } - ne = make_edge (entry_bb, zero_iter_bb, EDGE_FALSE_VALUE); - ne->probability = REG_BR_PROB_BASE / 2000 - 1; - e->flags = EDGE_TRUE_VALUE; - e->probability = REG_BR_PROB_BASE - ne->probability; - entry_bb = e->dest; - gsi = gsi_last_bb (entry_bb); - } - if (POINTER_TYPE_P (itype)) - itype = signed_type_for (itype); - t = build_int_cst (itype, (fd->loops[i].cond_code == LT_EXPR - ? -1 : 1)); - t = fold_build2 (PLUS_EXPR, itype, - fold_convert (itype, fd->loops[i].step), t); - t = fold_build2 (PLUS_EXPR, itype, t, - fold_convert (itype, fd->loops[i].n2)); - t = fold_build2 (MINUS_EXPR, itype, t, - fold_convert (itype, fd->loops[i].n1)); - if (TYPE_UNSIGNED (itype) && fd->loops[i].cond_code == GT_EXPR) - t = fold_build2 (TRUNC_DIV_EXPR, itype, - fold_build1 (NEGATE_EXPR, itype, t), - fold_build1 (NEGATE_EXPR, itype, - fold_convert (itype, - fd->loops[i].step))); - else - t = fold_build2 (TRUNC_DIV_EXPR, itype, t, - fold_convert (itype, fd->loops[i].step)); - t = fold_convert (type, t); - if (TREE_CODE (t) == INTEGER_CST) - counts[i] = t; - else - { - counts[i] = create_tmp_reg (type, ".count"); - t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE, - true, GSI_SAME_STMT); - stmt = gimple_build_assign (counts[i], t); - gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); - } - if (SSA_VAR_P (fd->loop.n2)) - { - if (i == 0) - t = counts[0]; - else - { - t = fold_build2 (MULT_EXPR, type, fd->loop.n2, counts[i]); - t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE, - true, GSI_SAME_STMT); - } - stmt = gimple_build_assign (fd->loop.n2, t); - gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); - } - } if (zero_iter_bb) { /* Some counts[i] vars might be uninitialized if @@ -3949,18 +4869,32 @@ expand_omp_for_generic (struct omp_region *region, t4 = build_fold_addr_expr (iend0); t3 = build_fold_addr_expr (istart0); t2 = fold_convert (fd->iter_type, fd->loop.step); - if (POINTER_TYPE_P (type) - && TYPE_PRECISION (type) != TYPE_PRECISION (fd->iter_type)) + 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, fd->loop.n2)); - t0 = fold_convert (fd->iter_type, fold_convert (itype, fd->loop.n1)); + 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, fd->loop.n2); - t0 = fold_convert (fd->iter_type, fd->loop.n1); + t1 = fold_convert (fd->iter_type, t1); + t0 = fold_convert (fd->iter_type, t0); } if (bias) { @@ -4015,64 +4949,53 @@ expand_omp_for_generic (struct omp_region *region, gsi_remove (&gsi, true); /* Iteration setup for sequential loop goes in L0_BB. */ + tree startvar = fd->loop.v; + tree endvar = NULL_TREE; + + if (gimple_omp_for_combined_p (fd->for_stmt)) + { + gcc_assert (gimple_code (inner_stmt) == GIMPLE_OMP_FOR + && gimple_omp_for_kind (inner_stmt) + & GF_OMP_FOR_KIND_SIMD); + tree innerc = find_omp_clause (gimple_omp_for_clauses (inner_stmt), + 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); + } + gsi = gsi_start_bb (l0_bb); t = istart0; if (bias) t = fold_build2 (MINUS_EXPR, fd->iter_type, t, bias); - if (POINTER_TYPE_P (type)) - t = fold_convert (signed_type_for (type), t); - t = fold_convert (type, t); + 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 (fd->loop.v) - && TREE_ADDRESSABLE (fd->loop.v), + DECL_P (startvar) + && TREE_ADDRESSABLE (startvar), NULL_TREE, false, GSI_CONTINUE_LINKING); - stmt = gimple_build_assign (fd->loop.v, t); + stmt = gimple_build_assign (startvar, t); gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); t = iend0; if (bias) t = fold_build2 (MINUS_EXPR, fd->iter_type, t, bias); - if (POINTER_TYPE_P (type)) - t = fold_convert (signed_type_for (type), t); - t = fold_convert (type, t); + 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 (fd->collapse > 1) + if (endvar) { - tree tem = create_tmp_reg (type, ".tem"); - stmt = gimple_build_assign (tem, fd->loop.v); + stmt = gimple_build_assign (endvar, iend); gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); - for (i = fd->collapse - 1; i >= 0; i--) - { - tree vtype = TREE_TYPE (fd->loops[i].v), itype; - itype = vtype; - if (POINTER_TYPE_P (vtype)) - itype = signed_type_for (vtype); - t = fold_build2 (TRUNC_MOD_EXPR, type, tem, counts[i]); - t = fold_convert (itype, t); - t = fold_build2 (MULT_EXPR, itype, t, - fold_convert (itype, fd->loops[i].step)); - if (POINTER_TYPE_P (vtype)) - t = fold_build_pointer_plus (fd->loops[i].n1, t); - else - t = fold_build2 (PLUS_EXPR, itype, fd->loops[i].n1, t); - t = force_gimple_operand_gsi (&gsi, t, - DECL_P (fd->loops[i].v) - && TREE_ADDRESSABLE (fd->loops[i].v), - NULL_TREE, false, - GSI_CONTINUE_LINKING); - stmt = gimple_build_assign (fd->loops[i].v, t); - gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); - if (i != 0) - { - t = fold_build2 (TRUNC_DIV_EXPR, type, tem, counts[i]); - t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE, - false, GSI_CONTINUE_LINKING); - stmt = gimple_build_assign (tem, t); - gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); - } - } } + if (fd->collapse > 1) + expand_omp_for_init_vars (fd, &gsi, counts, inner_stmt, startvar); if (!broken_loop) { @@ -4084,93 +5007,31 @@ expand_omp_for_generic (struct omp_region *region, vmain = gimple_omp_continue_control_use (stmt); vback = gimple_omp_continue_control_def (stmt); - if (POINTER_TYPE_P (type)) - t = fold_build_pointer_plus (vmain, fd->loop.step); - else - t = fold_build2 (PLUS_EXPR, type, vmain, fd->loop.step); - t = force_gimple_operand_gsi (&gsi, t, - DECL_P (vback) && TREE_ADDRESSABLE (vback), - NULL_TREE, true, GSI_SAME_STMT); - stmt = gimple_build_assign (vback, t); - gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); - - t = build2 (fd->loop.cond_code, boolean_type_node, - DECL_P (vback) && TREE_ADDRESSABLE (vback) ? t : vback, - iend); - stmt = gimple_build_cond_empty (t); - gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); + if (!gimple_omp_for_combined_p (fd->for_stmt)) + { + if (POINTER_TYPE_P (type)) + t = fold_build_pointer_plus (vmain, fd->loop.step); + else + t = fold_build2 (PLUS_EXPR, type, vmain, fd->loop.step); + t = force_gimple_operand_gsi (&gsi, t, + DECL_P (vback) + && TREE_ADDRESSABLE (vback), + NULL_TREE, true, GSI_SAME_STMT); + stmt = gimple_build_assign (vback, t); + gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); + + t = build2 (fd->loop.cond_code, boolean_type_node, + DECL_P (vback) && TREE_ADDRESSABLE (vback) ? t : vback, + iend); + stmt = gimple_build_cond_empty (t); + gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); + } /* Remove GIMPLE_OMP_CONTINUE. */ gsi_remove (&gsi, true); - if (fd->collapse > 1) - { - basic_block last_bb, bb; - - last_bb = cont_bb; - for (i = fd->collapse - 1; i >= 0; i--) - { - tree vtype = TREE_TYPE (fd->loops[i].v); - - bb = create_empty_bb (last_bb); - if (current_loops) - add_bb_to_loop (bb, last_bb->loop_father); - gsi = gsi_start_bb (bb); - - if (i < fd->collapse - 1) - { - e = make_edge (last_bb, bb, EDGE_FALSE_VALUE); - e->probability = REG_BR_PROB_BASE / 8; - - t = fd->loops[i + 1].n1; - t = force_gimple_operand_gsi (&gsi, t, - DECL_P (fd->loops[i + 1].v) - && TREE_ADDRESSABLE - (fd->loops[i + 1].v), - NULL_TREE, false, - GSI_CONTINUE_LINKING); - stmt = gimple_build_assign (fd->loops[i + 1].v, t); - gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); - } - else - collapse_bb = bb; - - set_immediate_dominator (CDI_DOMINATORS, bb, last_bb); - - if (POINTER_TYPE_P (vtype)) - t = fold_build_pointer_plus (fd->loops[i].v, fd->loops[i].step); - else - t = fold_build2 (PLUS_EXPR, vtype, fd->loops[i].v, - fd->loops[i].step); - t = force_gimple_operand_gsi (&gsi, t, - DECL_P (fd->loops[i].v) - && TREE_ADDRESSABLE (fd->loops[i].v), - NULL_TREE, false, - GSI_CONTINUE_LINKING); - stmt = gimple_build_assign (fd->loops[i].v, t); - gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); - - if (i > 0) - { - t = fd->loops[i].n2; - t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, - false, GSI_CONTINUE_LINKING); - tree v = fd->loops[i].v; - if (DECL_P (v) && TREE_ADDRESSABLE (v)) - v = force_gimple_operand_gsi (&gsi, v, true, NULL_TREE, - false, GSI_CONTINUE_LINKING); - t = fold_build2 (fd->loops[i].cond_code, boolean_type_node, - v, t); - stmt = gimple_build_cond_empty (t); - gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); - e = make_edge (bb, l1_bb, EDGE_TRUE_VALUE); - e->probability = REG_BR_PROB_BASE * 7 / 8; - } - else - make_edge (bb, l1_bb, EDGE_FALLTHRU); - last_bb = bb; - } - } + if (fd->collapse > 1 && !gimple_omp_for_combined_p (fd->for_stmt)) + collapse_bb = extract_omp_for_update_vars (fd, cont_bb, l1_bb); /* Emit code to get the next parallel iteration in L2_BB. */ gsi = gsi_start_bb (l2_bb); @@ -4220,19 +5081,29 @@ expand_omp_for_generic (struct omp_region *region, make_edge (cont_bb, l2_bb, EDGE_FALSE_VALUE); if (current_loops) add_bb_to_loop (l2_bb, cont_bb->loop_father); - if (fd->collapse > 1) + e = find_edge (cont_bb, l1_bb); + if (gimple_omp_for_combined_p (fd->for_stmt)) + { + remove_edge (e); + e = NULL; + } + else if (fd->collapse > 1) { - e = find_edge (cont_bb, l1_bb); remove_edge (e); e = make_edge (cont_bb, collapse_bb, EDGE_TRUE_VALUE); } else + e->flags = EDGE_TRUE_VALUE; + if (e) { - e = find_edge (cont_bb, l1_bb); - e->flags = EDGE_TRUE_VALUE; + e->probability = REG_BR_PROB_BASE * 7 / 8; + find_edge (cont_bb, l2_bb)->probability = REG_BR_PROB_BASE / 8; + } + else + { + e = find_edge (cont_bb, l2_bb); + e->flags = EDGE_FALLTHRU; } - e->probability = REG_BR_PROB_BASE * 7 / 8; - find_edge (cont_bb, l2_bb)->probability = REG_BR_PROB_BASE / 8; make_edge (l2_bb, l0_bb, EDGE_TRUE_VALUE); set_immediate_dominator (CDI_DOMINATORS, l2_bb, @@ -4249,10 +5120,13 @@ expand_omp_for_generic (struct omp_region *region, outer_loop->latch = l2_bb; add_loop (outer_loop, l0_bb->loop_father); - struct loop *loop = alloc_loop (); - loop->header = l1_bb; - /* The loop may have multiple latches. */ - add_loop (loop, outer_loop); + if (!gimple_omp_for_combined_p (fd->for_stmt)) + { + struct loop *loop = alloc_loop (); + loop->header = l1_bb; + /* The loop may have multiple latches. */ + add_loop (loop, outer_loop); + } } } @@ -4296,16 +5170,22 @@ expand_omp_for_generic (struct omp_region *region, static void expand_omp_for_static_nochunk (struct omp_region *region, - struct omp_for_data *fd) + struct omp_for_data *fd, + gimple inner_stmt) { tree n, q, s0, e0, e, t, tt, nthreads, threadid; tree type, itype, vmain, vback; basic_block entry_bb, second_bb, third_bb, exit_bb, seq_start_bb; - basic_block body_bb, cont_bb; + basic_block body_bb, cont_bb, collapse_bb = NULL; basic_block fin_bb; gimple_stmt_iterator gsi; gimple stmt; edge ep; + enum built_in_function get_num_threads = BUILT_IN_OMP_GET_NUM_THREADS; + enum built_in_function get_thread_num = BUILT_IN_OMP_GET_THREAD_NUM; + 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)) @@ -4314,25 +5194,49 @@ expand_omp_for_static_nochunk (struct omp_region *region, 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); + fin_bb = BRANCH_EDGE (entry_bb)->dest; + gcc_assert (broken_loop + || (fin_bb == FALLTHRU_EDGE (cont_bb)->dest)); seq_start_bb = split_edge (FALLTHRU_EDGE (entry_bb)); body_bb = single_succ (seq_start_bb); - gcc_assert (BRANCH_EDGE (cont_bb)->dest == body_bb); - gcc_assert (EDGE_COUNT (cont_bb->succs) == 2); - fin_bb = FALLTHRU_EDGE (cont_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); - t = fold_binary (fd->loop.cond_code, boolean_type_node, - fold_convert (type, fd->loop.n1), - fold_convert (type, fd->loop.n2)); - if (TYPE_UNSIGNED (type) + if (gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_DISTRIBUTE) + { + get_num_threads = BUILT_IN_OMP_GET_NUM_TEAMS; + get_thread_num = BUILT_IN_OMP_GET_TEAM_NUM; + } + + if (fd->collapse > 1) + { + int first_zero_iter = -1; + basic_block l2_dom_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); + t = NULL_TREE; + } + else if (gimple_omp_for_combined_into_p (fd->for_stmt)) + t = integer_one_node; + else + t = fold_binary (fd->loop.cond_code, boolean_type_node, + fold_convert (type, fd->loop.n1), + fold_convert (type, fd->loop.n2)); + if (fd->collapse == 1 + && TYPE_UNSIGNED (type) && (t == NULL_TREE || !integer_onep (t))) { - tree n1, n2; n1 = fold_convert (type, unshare_expr (fd->loop.n1)); n1 = force_gimple_operand_gsi (&gsi, n1, true, NULL_TREE, true, GSI_SAME_STMT); @@ -4370,36 +5274,47 @@ expand_omp_for_static_nochunk (struct omp_region *region, gsi = gsi_last_bb (entry_bb); } - t = build_call_expr (builtin_decl_explicit (BUILT_IN_OMP_GET_NUM_THREADS), 0); + t = build_call_expr (builtin_decl_explicit (get_num_threads), 0); t = fold_convert (itype, t); nthreads = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, true, GSI_SAME_STMT); - t = build_call_expr (builtin_decl_explicit (BUILT_IN_OMP_GET_THREAD_NUM), 0); + t = build_call_expr (builtin_decl_explicit (get_thread_num), 0); t = fold_convert (itype, t); threadid = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, true, GSI_SAME_STMT); - fd->loop.n1 - = force_gimple_operand_gsi (&gsi, fold_convert (type, fd->loop.n1), - true, NULL_TREE, true, GSI_SAME_STMT); - fd->loop.n2 - = force_gimple_operand_gsi (&gsi, fold_convert (itype, fd->loop.n2), - true, NULL_TREE, true, GSI_SAME_STMT); - fd->loop.step - = force_gimple_operand_gsi (&gsi, fold_convert (itype, fd->loop.step), - true, NULL_TREE, true, GSI_SAME_STMT); + n1 = fd->loop.n1; + n2 = fd->loop.n2; + step = fd->loop.step; + 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); + n1 = OMP_CLAUSE_DECL (innerc); + innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc), + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + n2 = OMP_CLAUSE_DECL (innerc); + } + 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); t = build_int_cst (itype, (fd->loop.cond_code == LT_EXPR ? -1 : 1)); - t = fold_build2 (PLUS_EXPR, itype, fd->loop.step, t); - t = fold_build2 (PLUS_EXPR, itype, t, fd->loop.n2); - t = fold_build2 (MINUS_EXPR, itype, t, fold_convert (itype, fd->loop.n1)); + t = fold_build2 (PLUS_EXPR, itype, step, t); + t = fold_build2 (PLUS_EXPR, itype, t, n2); + t = fold_build2 (MINUS_EXPR, itype, t, fold_convert (itype, n1)); if (TYPE_UNSIGNED (itype) && fd->loop.cond_code == GT_EXPR) t = fold_build2 (TRUNC_DIV_EXPR, itype, fold_build1 (NEGATE_EXPR, itype, t), - fold_build1 (NEGATE_EXPR, itype, fd->loop.step)); + fold_build1 (NEGATE_EXPR, itype, step)); else - t = fold_build2 (TRUNC_DIV_EXPR, itype, t, fd->loop.step); + t = fold_build2 (TRUNC_DIV_EXPR, itype, t, step); t = fold_convert (itype, t); n = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, true, GSI_SAME_STMT); @@ -4447,56 +5362,93 @@ expand_omp_for_static_nochunk (struct omp_region *region, /* Setup code for sequential iteration goes in SEQ_START_BB. */ gsi = gsi_start_bb (seq_start_bb); + tree startvar = fd->loop.v; + tree endvar = NULL_TREE; + + if (gimple_omp_for_combined_p (fd->for_stmt)) + { + tree clauses = gimple_code (inner_stmt) == GIMPLE_OMP_PARALLEL + ? gimple_omp_parallel_clauses (inner_stmt) + : 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 (itype, s0); - t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step); + t = fold_build2 (MULT_EXPR, itype, t, step); if (POINTER_TYPE_P (type)) - t = fold_build_pointer_plus (fd->loop.n1, t); + t = fold_build_pointer_plus (n1, t); else - t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1); + t = fold_build2 (PLUS_EXPR, type, t, n1); + t = fold_convert (TREE_TYPE (startvar), t); t = force_gimple_operand_gsi (&gsi, t, - DECL_P (fd->loop.v) - && TREE_ADDRESSABLE (fd->loop.v), + DECL_P (startvar) + && TREE_ADDRESSABLE (startvar), NULL_TREE, false, GSI_CONTINUE_LINKING); - stmt = gimple_build_assign (fd->loop.v, t); + stmt = gimple_build_assign (startvar, t); gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); t = fold_convert (itype, e0); - t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step); + t = fold_build2 (MULT_EXPR, itype, t, step); if (POINTER_TYPE_P (type)) - t = fold_build_pointer_plus (fd->loop.n1, t); + t = fold_build_pointer_plus (n1, t); else - t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1); + t = fold_build2 (PLUS_EXPR, type, t, n1); + t = fold_convert (TREE_TYPE (startvar), t); e = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, false, GSI_CONTINUE_LINKING); + if (endvar) + { + stmt = gimple_build_assign (endvar, e); + gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); + } + if (fd->collapse > 1) + expand_omp_for_init_vars (fd, &gsi, counts, inner_stmt, startvar); - /* The code controlling the sequential loop replaces the - GIMPLE_OMP_CONTINUE. */ - gsi = gsi_last_bb (cont_bb); - stmt = gsi_stmt (gsi); - gcc_assert (gimple_code (stmt) == GIMPLE_OMP_CONTINUE); - vmain = gimple_omp_continue_control_use (stmt); - vback = gimple_omp_continue_control_def (stmt); + if (!broken_loop) + { + /* The code controlling the sequential loop replaces the + GIMPLE_OMP_CONTINUE. */ + gsi = gsi_last_bb (cont_bb); + stmt = gsi_stmt (gsi); + gcc_assert (gimple_code (stmt) == GIMPLE_OMP_CONTINUE); + vmain = gimple_omp_continue_control_use (stmt); + vback = gimple_omp_continue_control_def (stmt); - if (POINTER_TYPE_P (type)) - t = fold_build_pointer_plus (vmain, fd->loop.step); - else - t = fold_build2 (PLUS_EXPR, type, vmain, fd->loop.step); - t = force_gimple_operand_gsi (&gsi, t, - DECL_P (vback) && TREE_ADDRESSABLE (vback), - NULL_TREE, true, GSI_SAME_STMT); - stmt = gimple_build_assign (vback, t); - gsi_insert_before (&gsi, stmt, GSI_SAME_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); + stmt = gimple_build_assign (vback, t); + gsi_insert_before (&gsi, 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); + } - 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); - /* 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); + } /* Replace the GIMPLE_OMP_RETURN with a barrier, or nothing. */ gsi = gsi_last_bb (exit_bb); - if (!gimple_omp_return_nowait_p (gsi_stmt (gsi))) + if (!gimple_omp_return_nowait_p (gsi_stmt (gsi)) + && gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_FOR) force_gimple_operand_gsi (&gsi, build_omp_barrier (), false, NULL_TREE, false, GSI_SAME_STMT); gsi_remove (&gsi, true); @@ -4510,21 +5462,42 @@ expand_omp_for_static_nochunk (struct omp_region *region, find_edge (third_bb, seq_start_bb)->flags = EDGE_FALSE_VALUE; find_edge (third_bb, fin_bb)->flags = EDGE_TRUE_VALUE; - find_edge (cont_bb, body_bb)->flags = EDGE_TRUE_VALUE; - find_edge (cont_bb, fin_bb)->flags = EDGE_FALSE_VALUE; + if (!broken_loop) + { + ep = find_edge (cont_bb, body_bb); + if (gimple_omp_for_combined_p (fd->for_stmt)) + { + remove_edge (ep); + ep = NULL; + } + else if (fd->collapse > 1) + { + remove_edge (ep); + ep = make_edge (cont_bb, collapse_bb, EDGE_TRUE_VALUE); + } + else + ep->flags = EDGE_TRUE_VALUE; + find_edge (cont_bb, fin_bb)->flags + = ep ? EDGE_FALSE_VALUE : EDGE_FALLTHRU; + } set_immediate_dominator (CDI_DOMINATORS, second_bb, entry_bb); set_immediate_dominator (CDI_DOMINATORS, third_bb, entry_bb); set_immediate_dominator (CDI_DOMINATORS, seq_start_bb, third_bb); + set_immediate_dominator (CDI_DOMINATORS, body_bb, recompute_dominator (CDI_DOMINATORS, body_bb)); set_immediate_dominator (CDI_DOMINATORS, fin_bb, recompute_dominator (CDI_DOMINATORS, fin_bb)); - struct loop *loop = alloc_loop (); - loop->header = body_bb; - loop->latch = cont_bb; - add_loop (loop, body_bb->loop_father); + 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); + } } @@ -4567,16 +5540,22 @@ expand_omp_for_static_nochunk (struct omp_region *region, */ static void -expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd) +expand_omp_for_static_chunk (struct omp_region *region, + struct omp_for_data *fd, gimple inner_stmt) { tree n, s0, e0, e, t; tree trip_var, trip_init, trip_main, trip_back, nthreads, threadid; tree type, itype, v_main, v_back, v_extra; basic_block entry_bb, exit_bb, body_bb, seq_start_bb, iter_part_bb; - basic_block trip_update_bb, cont_bb, fin_bb; + basic_block trip_update_bb = NULL, cont_bb, collapse_bb = NULL, fin_bb; gimple_stmt_iterator si; gimple stmt; edge se; + enum built_in_function get_num_threads = BUILT_IN_OMP_GET_NUM_THREADS; + enum built_in_function get_thread_num = BUILT_IN_OMP_GET_THREAD_NUM; + 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)) @@ -4588,27 +5567,50 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd) iter_part_bb = se->dest; cont_bb = region->cont; gcc_assert (EDGE_COUNT (iter_part_bb->succs) == 2); - gcc_assert (BRANCH_EDGE (iter_part_bb)->dest - == FALLTHRU_EDGE (cont_bb)->dest); + fin_bb = BRANCH_EDGE (iter_part_bb)->dest; + gcc_assert (broken_loop + || fin_bb == FALLTHRU_EDGE (cont_bb)->dest); seq_start_bb = split_edge (FALLTHRU_EDGE (iter_part_bb)); body_bb = single_succ (seq_start_bb); - gcc_assert (BRANCH_EDGE (cont_bb)->dest == body_bb); - gcc_assert (EDGE_COUNT (cont_bb->succs) == 2); - fin_bb = FALLTHRU_EDGE (cont_bb)->dest; - trip_update_bb = split_edge (FALLTHRU_EDGE (cont_bb)); + if (!broken_loop) + { + gcc_assert (BRANCH_EDGE (cont_bb)->dest == body_bb); + gcc_assert (EDGE_COUNT (cont_bb->succs) == 2); + trip_update_bb = split_edge (FALLTHRU_EDGE (cont_bb)); + } exit_bb = region->exit; /* Trip and adjustment setup goes in ENTRY_BB. */ si = gsi_last_bb (entry_bb); gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_FOR); - t = fold_binary (fd->loop.cond_code, boolean_type_node, - fold_convert (type, fd->loop.n1), - fold_convert (type, fd->loop.n2)); - if (TYPE_UNSIGNED (type) + if (gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_DISTRIBUTE) + { + get_num_threads = BUILT_IN_OMP_GET_NUM_TEAMS; + get_thread_num = BUILT_IN_OMP_GET_TEAM_NUM; + } + + if (fd->collapse > 1) + { + int first_zero_iter = -1; + basic_block l2_dom_bb = NULL; + + counts = XALLOCAVEC (tree, fd->collapse); + expand_omp_for_init_counts (fd, &si, entry_bb, counts, + fin_bb, first_zero_iter, + l2_dom_bb); + t = NULL_TREE; + } + else if (gimple_omp_for_combined_into_p (fd->for_stmt)) + t = integer_one_node; + else + t = fold_binary (fd->loop.cond_code, boolean_type_node, + fold_convert (type, fd->loop.n1), + fold_convert (type, fd->loop.n2)); + if (fd->collapse == 1 + && TYPE_UNSIGNED (type) && (t == NULL_TREE || !integer_onep (t))) { - tree n1, n2; n1 = fold_convert (type, unshare_expr (fd->loop.n1)); n1 = force_gimple_operand_gsi (&si, n1, true, NULL_TREE, true, GSI_SAME_STMT); @@ -4646,39 +5648,50 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd) si = gsi_last_bb (entry_bb); } - t = build_call_expr (builtin_decl_explicit (BUILT_IN_OMP_GET_NUM_THREADS), 0); + t = build_call_expr (builtin_decl_explicit (get_num_threads), 0); t = fold_convert (itype, t); nthreads = force_gimple_operand_gsi (&si, t, true, NULL_TREE, true, GSI_SAME_STMT); - t = build_call_expr (builtin_decl_explicit (BUILT_IN_OMP_GET_THREAD_NUM), 0); + t = build_call_expr (builtin_decl_explicit (get_thread_num), 0); t = fold_convert (itype, t); threadid = force_gimple_operand_gsi (&si, t, true, NULL_TREE, true, GSI_SAME_STMT); - fd->loop.n1 - = force_gimple_operand_gsi (&si, fold_convert (type, fd->loop.n1), - true, NULL_TREE, true, GSI_SAME_STMT); - fd->loop.n2 - = force_gimple_operand_gsi (&si, fold_convert (itype, fd->loop.n2), - true, NULL_TREE, true, GSI_SAME_STMT); - fd->loop.step - = force_gimple_operand_gsi (&si, fold_convert (itype, fd->loop.step), - true, NULL_TREE, true, GSI_SAME_STMT); + n1 = fd->loop.n1; + n2 = fd->loop.n2; + step = fd->loop.step; + 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); + n1 = OMP_CLAUSE_DECL (innerc); + innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc), + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + n2 = OMP_CLAUSE_DECL (innerc); + } + n1 = force_gimple_operand_gsi (&si, fold_convert (type, n1), + true, NULL_TREE, true, GSI_SAME_STMT); + n2 = force_gimple_operand_gsi (&si, fold_convert (itype, n2), + true, NULL_TREE, true, GSI_SAME_STMT); + step = force_gimple_operand_gsi (&si, fold_convert (itype, step), + true, NULL_TREE, true, GSI_SAME_STMT); fd->chunk_size = force_gimple_operand_gsi (&si, fold_convert (itype, fd->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, fd->loop.step, t); - t = fold_build2 (PLUS_EXPR, itype, t, fd->loop.n2); - t = fold_build2 (MINUS_EXPR, itype, t, fold_convert (itype, fd->loop.n1)); + t = fold_build2 (PLUS_EXPR, itype, step, t); + t = fold_build2 (PLUS_EXPR, itype, t, n2); + t = fold_build2 (MINUS_EXPR, itype, t, fold_convert (itype, n1)); if (TYPE_UNSIGNED (itype) && fd->loop.cond_code == GT_EXPR) t = fold_build2 (TRUNC_DIV_EXPR, itype, fold_build1 (NEGATE_EXPR, itype, t), - fold_build1 (NEGATE_EXPR, itype, fd->loop.step)); + fold_build1 (NEGATE_EXPR, itype, step)); else - t = fold_build2 (TRUNC_DIV_EXPR, itype, t, fd->loop.step); + t = fold_build2 (TRUNC_DIV_EXPR, itype, t, step); t = fold_convert (itype, t); n = force_gimple_operand_gsi (&si, t, true, NULL_TREE, true, GSI_SAME_STMT); @@ -4701,11 +5714,11 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd) gsi_insert_before (&si, stmt, GSI_SAME_STMT); t = fold_build2 (MULT_EXPR, itype, threadid, fd->chunk_size); - t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step); + t = fold_build2 (MULT_EXPR, itype, t, step); if (POINTER_TYPE_P (type)) - t = fold_build_pointer_plus (fd->loop.n1, t); + t = fold_build_pointer_plus (n1, t); else - t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1); + t = fold_build2 (PLUS_EXPR, type, t, n1); v_extra = force_gimple_operand_gsi (&si, t, true, NULL_TREE, true, GSI_SAME_STMT); @@ -4732,65 +5745,101 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd) /* Setup code for sequential iteration goes in SEQ_START_BB. */ si = gsi_start_bb (seq_start_bb); + tree startvar = fd->loop.v; + tree endvar = NULL_TREE; + + if (gimple_omp_for_combined_p (fd->for_stmt)) + { + tree clauses = gimple_code (inner_stmt) == GIMPLE_OMP_PARALLEL + ? gimple_omp_parallel_clauses (inner_stmt) + : 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 (itype, s0); - t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step); + t = fold_build2 (MULT_EXPR, itype, t, step); if (POINTER_TYPE_P (type)) - t = fold_build_pointer_plus (fd->loop.n1, t); + t = fold_build_pointer_plus (n1, t); else - t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1); + t = fold_build2 (PLUS_EXPR, type, t, n1); + t = fold_convert (TREE_TYPE (startvar), t); t = force_gimple_operand_gsi (&si, t, - DECL_P (fd->loop.v) - && TREE_ADDRESSABLE (fd->loop.v), + DECL_P (startvar) + && TREE_ADDRESSABLE (startvar), NULL_TREE, false, GSI_CONTINUE_LINKING); - stmt = gimple_build_assign (fd->loop.v, t); + stmt = gimple_build_assign (startvar, t); gsi_insert_after (&si, stmt, GSI_CONTINUE_LINKING); t = fold_convert (itype, e0); - t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step); + t = fold_build2 (MULT_EXPR, itype, t, step); if (POINTER_TYPE_P (type)) - t = fold_build_pointer_plus (fd->loop.n1, t); + t = fold_build_pointer_plus (n1, t); else - t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1); + t = fold_build2 (PLUS_EXPR, type, t, n1); + t = fold_convert (TREE_TYPE (startvar), t); e = force_gimple_operand_gsi (&si, t, true, NULL_TREE, false, GSI_CONTINUE_LINKING); + if (endvar) + { + stmt = gimple_build_assign (endvar, e); + gsi_insert_after (&si, stmt, GSI_CONTINUE_LINKING); + } + if (fd->collapse > 1) + expand_omp_for_init_vars (fd, &si, counts, inner_stmt, startvar); - /* The code controlling the sequential loop goes in CONT_BB, - replacing the GIMPLE_OMP_CONTINUE. */ - si = gsi_last_bb (cont_bb); - stmt = gsi_stmt (si); - gcc_assert (gimple_code (stmt) == GIMPLE_OMP_CONTINUE); - v_main = gimple_omp_continue_control_use (stmt); - v_back = gimple_omp_continue_control_def (stmt); + if (!broken_loop) + { + /* The code controlling the sequential loop goes in CONT_BB, + replacing the GIMPLE_OMP_CONTINUE. */ + si = gsi_last_bb (cont_bb); + stmt = gsi_stmt (si); + gcc_assert (gimple_code (stmt) == GIMPLE_OMP_CONTINUE); + v_main = gimple_omp_continue_control_use (stmt); + v_back = gimple_omp_continue_control_def (stmt); - if (POINTER_TYPE_P (type)) - t = fold_build_pointer_plus (v_main, fd->loop.step); - else - t = fold_build2 (PLUS_EXPR, type, v_main, fd->loop.step); - if (DECL_P (v_back) && TREE_ADDRESSABLE (v_back)) - t = force_gimple_operand_gsi (&si, t, true, NULL_TREE, - true, GSI_SAME_STMT); - stmt = gimple_build_assign (v_back, t); - gsi_insert_before (&si, stmt, GSI_SAME_STMT); + if (!gimple_omp_for_combined_p (fd->for_stmt)) + { + if (POINTER_TYPE_P (type)) + t = fold_build_pointer_plus (v_main, step); + else + t = fold_build2 (PLUS_EXPR, type, v_main, step); + if (DECL_P (v_back) && TREE_ADDRESSABLE (v_back)) + t = force_gimple_operand_gsi (&si, t, true, NULL_TREE, + true, GSI_SAME_STMT); + stmt = gimple_build_assign (v_back, t); + gsi_insert_before (&si, stmt, GSI_SAME_STMT); - t = build2 (fd->loop.cond_code, boolean_type_node, - DECL_P (v_back) && TREE_ADDRESSABLE (v_back) - ? t : v_back, e); - gsi_insert_before (&si, gimple_build_cond_empty (t), GSI_SAME_STMT); + t = build2 (fd->loop.cond_code, boolean_type_node, + DECL_P (v_back) && TREE_ADDRESSABLE (v_back) + ? t : v_back, e); + gsi_insert_before (&si, gimple_build_cond_empty (t), GSI_SAME_STMT); + } - /* Remove GIMPLE_OMP_CONTINUE. */ - gsi_remove (&si, true); + /* Remove GIMPLE_OMP_CONTINUE. */ + gsi_remove (&si, true); - /* Trip update code goes into TRIP_UPDATE_BB. */ - si = gsi_start_bb (trip_update_bb); + if (fd->collapse > 1 && !gimple_omp_for_combined_p (fd->for_stmt)) + collapse_bb = extract_omp_for_update_vars (fd, cont_bb, body_bb); - t = build_int_cst (itype, 1); - t = build2 (PLUS_EXPR, itype, trip_main, t); - stmt = gimple_build_assign (trip_back, t); - gsi_insert_after (&si, stmt, GSI_CONTINUE_LINKING); + /* Trip update code goes into TRIP_UPDATE_BB. */ + si = gsi_start_bb (trip_update_bb); + + t = build_int_cst (itype, 1); + t = build2 (PLUS_EXPR, itype, trip_main, t); + stmt = gimple_build_assign (trip_back, t); + gsi_insert_after (&si, stmt, GSI_CONTINUE_LINKING); + } /* Replace the GIMPLE_OMP_RETURN with a barrier, or nothing. */ si = gsi_last_bb (exit_bb); - if (!gimple_omp_return_nowait_p (gsi_stmt (si))) + if (!gimple_omp_return_nowait_p (gsi_stmt (si)) + && gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_FOR) force_gimple_operand_gsi (&si, build_omp_barrier (), false, NULL_TREE, false, GSI_SAME_STMT); gsi_remove (&si, true); @@ -4799,10 +5848,26 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd) find_edge (iter_part_bb, seq_start_bb)->flags = EDGE_TRUE_VALUE; find_edge (iter_part_bb, fin_bb)->flags = EDGE_FALSE_VALUE; - find_edge (cont_bb, body_bb)->flags = EDGE_TRUE_VALUE; - find_edge (cont_bb, trip_update_bb)->flags = EDGE_FALSE_VALUE; + if (!broken_loop) + { + se = find_edge (cont_bb, body_bb); + if (gimple_omp_for_combined_p (fd->for_stmt)) + { + remove_edge (se); + se = NULL; + } + else if (fd->collapse > 1) + { + remove_edge (se); + se = make_edge (cont_bb, collapse_bb, EDGE_TRUE_VALUE); + } + else + se->flags = EDGE_TRUE_VALUE; + find_edge (cont_bb, trip_update_bb)->flags + = se ? EDGE_FALSE_VALUE : EDGE_FALLTHRU; - redirect_edge_and_branch (single_succ_edge (trip_update_bb), iter_part_bb); + redirect_edge_and_branch (single_succ_edge (trip_update_bb), iter_part_bb); + } if (gimple_in_ssa_p (cfun)) { @@ -4813,6 +5878,8 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd) edge_var_map *vm; size_t i; + gcc_assert (fd->collapse == 1 && !broken_loop); + /* When we redirect the edge from trip_update_bb to iter_part_bb, we remove arguments of the phi nodes in fin_bb. We need to create appropriate phi nodes in iter_part_bb instead. */ @@ -4862,7 +5929,8 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd) UNKNOWN_LOCATION); } - set_immediate_dominator (CDI_DOMINATORS, trip_update_bb, cont_bb); + if (!broken_loop) + set_immediate_dominator (CDI_DOMINATORS, trip_update_bb, cont_bb); set_immediate_dominator (CDI_DOMINATORS, iter_part_bb, recompute_dominator (CDI_DOMINATORS, iter_part_bb)); set_immediate_dominator (CDI_DOMINATORS, fin_bb, @@ -4872,22 +5940,335 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd) set_immediate_dominator (CDI_DOMINATORS, body_bb, recompute_dominator (CDI_DOMINATORS, body_bb)); - struct loop *trip_loop = alloc_loop (); - trip_loop->header = iter_part_bb; - trip_loop->latch = trip_update_bb; - add_loop (trip_loop, iter_part_bb->loop_father); + if (!broken_loop) + { + struct loop *trip_loop = alloc_loop (); + trip_loop->header = iter_part_bb; + trip_loop->latch = trip_update_bb; + add_loop (trip_loop, iter_part_bb->loop_father); - struct loop *loop = alloc_loop (); - loop->header = body_bb; - loop->latch = cont_bb; - add_loop (loop, trip_loop); + if (!gimple_omp_for_combined_p (fd->for_stmt)) + { + struct loop *loop = alloc_loop (); + loop->header = body_bb; + loop->latch = cont_bb; + add_loop (loop, trip_loop); + } + } +} + + +/* A subroutine of expand_omp_for. Generate code for a simd non-worksharing + loop. Given parameters: + + for (V = N1; V cond N2; V += STEP) BODY; + + where COND is "<" or ">", we generate pseudocode + + V = N1; + goto L1; + L0: + BODY; + V += STEP; + L1: + if (V cond N2) goto L0; else goto L2; + L2: + + 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 (cond3 is <) + adj = STEP3 - 1; + else + adj = STEP3 + 1; + count3 = (adj + N32 - N31) / STEP3; + if (cond2 is <) + adj = STEP2 - 1; + else + adj = STEP2 + 1; + count2 = (adj + N22 - N21) / STEP2; + if (cond1 is <) + adj = STEP1 - 1; + else + adj = STEP1 + 1; + count1 = (adj + N12 - N11) / STEP1; + count = count1 * count2 * count3; + V = 0; + V1 = N11; + V2 = N21; + V3 = N31; + goto L1; + L0: + BODY; + V += 1; + V3 += STEP3; + V2 += (V3 cond3 N32) ? 0 : STEP2; + V3 = (V3 cond3 N32) ? V3 : N31; + V1 += (V2 cond2 N22) ? 0 : STEP1; + V2 = (V2 cond2 N22) ? V2 : N21; + L1: + if (V < count) goto L0; else goto L2; + L2: + + */ + +static void +expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) +{ + tree type, t; + basic_block entry_bb, cont_bb, exit_bb, l0_bb, l1_bb, l2_bb, l2_dom_bb; + gimple_stmt_iterator gsi; + gimple stmt; + bool broken_loop = region->cont == NULL; + edge e, ne; + tree *counts = NULL; + int i; + tree safelen = find_omp_clause (gimple_omp_for_clauses (fd->for_stmt), + OMP_CLAUSE_SAFELEN); + tree simduid = find_omp_clause (gimple_omp_for_clauses (fd->for_stmt), + OMP_CLAUSE__SIMDUID_); + tree n1, n2; + + type = TREE_TYPE (fd->loop.v); + entry_bb = region->entry; + cont_bb = region->cont; + gcc_assert (EDGE_COUNT (entry_bb->succs) == 2); + gcc_assert (broken_loop + || BRANCH_EDGE (entry_bb)->dest == FALLTHRU_EDGE (cont_bb)->dest); + l0_bb = FALLTHRU_EDGE (entry_bb)->dest; + if (!broken_loop) + { + gcc_assert (BRANCH_EDGE (cont_bb)->dest == l0_bb); + gcc_assert (EDGE_COUNT (cont_bb->succs) == 2); + l1_bb = split_block (cont_bb, last_stmt (cont_bb))->dest; + l2_bb = BRANCH_EDGE (entry_bb)->dest; + } + else + { + BRANCH_EDGE (entry_bb)->flags &= ~EDGE_ABNORMAL; + l1_bb = split_edge (BRANCH_EDGE (entry_bb)); + l2_bb = single_succ (l1_bb); + } + exit_bb = region->exit; + l2_dom_bb = NULL; + + gsi = gsi_last_bb (entry_bb); + + gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR); + /* Not needed in SSA form right now. */ + gcc_assert (!gimple_in_ssa_p (cfun)); + if (fd->collapse > 1) + { + int first_zero_iter = -1; + basic_block zero_iter_bb = l2_bb; + + counts = XALLOCAVEC (tree, fd->collapse); + expand_omp_for_init_counts (fd, &gsi, entry_bb, counts, + zero_iter_bb, first_zero_iter, + l2_dom_bb); + } + if (l2_dom_bb == NULL) + l2_dom_bb = l1_bb; + + n1 = fd->loop.n1; + n2 = fd->loop.n2; + 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); + n1 = OMP_CLAUSE_DECL (innerc); + innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc), + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + n2 = OMP_CLAUSE_DECL (innerc); + expand_omp_build_assign (&gsi, fd->loop.v, + fold_convert (type, n1)); + if (fd->collapse > 1) + { + gsi_prev (&gsi); + expand_omp_for_init_vars (fd, &gsi, counts, NULL, n1); + gsi_next (&gsi); + } + } + else + { + expand_omp_build_assign (&gsi, fd->loop.v, + fold_convert (type, fd->loop.n1)); + if (fd->collapse > 1) + for (i = 0; i < fd->collapse; i++) + { + tree itype = TREE_TYPE (fd->loops[i].v); + if (POINTER_TYPE_P (itype)) + itype = signed_type_for (itype); + t = fold_convert (TREE_TYPE (fd->loops[i].v), fd->loops[i].n1); + expand_omp_build_assign (&gsi, fd->loops[i].v, t); + } + } + + /* Remove the GIMPLE_OMP_FOR statement. */ + gsi_remove (&gsi, true); + + if (!broken_loop) + { + /* Code to control the increment goes in the CONT_BB. */ + gsi = gsi_last_bb (cont_bb); + stmt = gsi_stmt (gsi); + gcc_assert (gimple_code (stmt) == GIMPLE_OMP_CONTINUE); + + if (POINTER_TYPE_P (type)) + t = fold_build_pointer_plus (fd->loop.v, fd->loop.step); + else + t = fold_build2 (PLUS_EXPR, type, fd->loop.v, fd->loop.step); + expand_omp_build_assign (&gsi, fd->loop.v, t); + + if (fd->collapse > 1) + { + i = fd->collapse - 1; + if (POINTER_TYPE_P (TREE_TYPE (fd->loops[i].v))) + { + t = fold_convert (sizetype, fd->loops[i].step); + t = fold_build_pointer_plus (fd->loops[i].v, t); + } + else + { + t = fold_convert (TREE_TYPE (fd->loops[i].v), + fd->loops[i].step); + t = fold_build2 (PLUS_EXPR, TREE_TYPE (fd->loops[i].v), + fd->loops[i].v, t); + } + expand_omp_build_assign (&gsi, fd->loops[i].v, t); + + for (i = fd->collapse - 1; i > 0; i--) + { + tree itype = TREE_TYPE (fd->loops[i].v); + tree itype2 = TREE_TYPE (fd->loops[i - 1].v); + if (POINTER_TYPE_P (itype2)) + itype2 = signed_type_for (itype2); + t = build3 (COND_EXPR, itype2, + build2 (fd->loops[i].cond_code, boolean_type_node, + fd->loops[i].v, + fold_convert (itype, fd->loops[i].n2)), + build_int_cst (itype2, 0), + fold_convert (itype2, fd->loops[i - 1].step)); + if (POINTER_TYPE_P (TREE_TYPE (fd->loops[i - 1].v))) + t = fold_build_pointer_plus (fd->loops[i - 1].v, t); + else + t = fold_build2 (PLUS_EXPR, itype2, fd->loops[i - 1].v, t); + expand_omp_build_assign (&gsi, fd->loops[i - 1].v, t); + + t = build3 (COND_EXPR, itype, + build2 (fd->loops[i].cond_code, boolean_type_node, + fd->loops[i].v, + fold_convert (itype, fd->loops[i].n2)), + fd->loops[i].v, + fold_convert (itype, fd->loops[i].n1)); + expand_omp_build_assign (&gsi, fd->loops[i].v, t); + } + } + + /* Remove GIMPLE_OMP_CONTINUE. */ + gsi_remove (&gsi, true); + } + + /* Emit the condition in L1_BB. */ + gsi = gsi_start_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); + stmt = gimple_build_cond_empty (t); + gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); + if (walk_tree (gimple_cond_lhs_ptr (stmt), expand_omp_regimplify_p, + NULL, NULL) + || walk_tree (gimple_cond_rhs_ptr (stmt), expand_omp_regimplify_p, + NULL, NULL)) + { + gsi = gsi_for_stmt (stmt); + gimple_regimplify_operands (stmt, &gsi); + } + + /* Remove GIMPLE_OMP_RETURN. */ + gsi = gsi_last_bb (exit_bb); + gsi_remove (&gsi, true); + + /* Connect the new blocks. */ + remove_edge (FALLTHRU_EDGE (entry_bb)); + + if (!broken_loop) + { + remove_edge (BRANCH_EDGE (entry_bb)); + make_edge (entry_bb, l1_bb, EDGE_FALLTHRU); + + e = BRANCH_EDGE (l1_bb); + ne = FALLTHRU_EDGE (l1_bb); + e->flags = EDGE_TRUE_VALUE; + } + else + { + single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU; + + ne = single_succ_edge (l1_bb); + e = make_edge (l1_bb, l0_bb, EDGE_TRUE_VALUE); + + } + ne->flags = EDGE_FALSE_VALUE; + e->probability = REG_BR_PROB_BASE * 7 / 8; + ne->probability = REG_BR_PROB_BASE / 8; + + set_immediate_dominator (CDI_DOMINATORS, l1_bb, entry_bb); + set_immediate_dominator (CDI_DOMINATORS, l2_bb, l2_dom_bb); + set_immediate_dominator (CDI_DOMINATORS, l0_bb, l1_bb); + + if (!broken_loop) + { + struct loop *loop = alloc_loop (); + loop->header = l1_bb; + loop->latch = e->dest; + add_loop (loop, l1_bb->loop_father); + if (safelen == NULL_TREE) + loop->safelen = INT_MAX; + else + { + safelen = OMP_CLAUSE_SAFELEN_EXPR (safelen); + if (!host_integerp (safelen, 1) + || (unsigned HOST_WIDE_INT) tree_low_cst (safelen, 1) + > INT_MAX) + loop->safelen = INT_MAX; + else + loop->safelen = tree_low_cst (safelen, 1); + if (loop->safelen == 1) + loop->safelen = 0; + } + if (simduid) + { + loop->simduid = OMP_CLAUSE__SIMDUID__DECL (simduid); + cfun->has_simduid_loops = true; + } + /* If not -fno-tree-vectorize, hint that we want to vectorize + the loop. */ + if ((flag_tree_vectorize + || !global_options_set.x_flag_tree_vectorize) + && loop->safelen > 1) + { + loop->force_vect = true; + cfun->has_force_vect_loops = true; + } + } } /* Expand the OpenMP loop defined by REGION. */ static void -expand_omp_for (struct omp_region *region) +expand_omp_for (struct omp_region *region, gimple inner_stmt) { struct omp_for_data fd; struct omp_for_data_loop *loops; @@ -4914,20 +6295,22 @@ expand_omp_for (struct omp_region *region) original loops from being detected. Fix that up. */ loops_state_set (LOOPS_NEED_FIXUP); - if (fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC - && !fd.have_ordered - && fd.collapse == 1 - && region->cont != NULL) + if (gimple_omp_for_kind (fd.for_stmt) & GF_OMP_FOR_KIND_SIMD) + expand_omp_simd (region, &fd); + else if (fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC + && !fd.have_ordered) { if (fd.chunk_size == NULL) - expand_omp_for_static_nochunk (region, &fd); + expand_omp_for_static_nochunk (region, &fd, inner_stmt); else - expand_omp_for_static_chunk (region, &fd); + expand_omp_for_static_chunk (region, &fd, inner_stmt); } else { int fn_index, start_ix, next_ix; + gcc_assert (gimple_omp_for_kind (fd.for_stmt) + == GF_OMP_FOR_KIND_FOR); if (fd.chunk_size == NULL && fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC) fd.chunk_size = integer_zero_node; @@ -4945,7 +6328,7 @@ expand_omp_for (struct omp_region *region) - (int)BUILT_IN_GOMP_LOOP_STATIC_NEXT); } expand_omp_for_generic (region, &fd, (enum built_in_function) start_ix, - (enum built_in_function) next_ix); + (enum built_in_function) next_ix, inner_stmt); } if (gimple_in_ssa_p (cfun)) @@ -5266,7 +6649,10 @@ expand_omp_atomic_load (basic_block load_bb, tree addr, itype = TREE_TYPE (TREE_TYPE (decl)); call = build_call_expr_loc (loc, decl, 2, addr, - build_int_cst (NULL, MEMMODEL_RELAXED)); + build_int_cst (NULL, + gimple_omp_atomic_seq_cst_p (stmt) + ? MEMMODEL_SEQ_CST + : MEMMODEL_RELAXED)); if (!useless_type_conversion_p (type, itype)) call = fold_build1_loc (loc, VIEW_CONVERT_EXPR, type, call); call = build2_loc (loc, MODIFY_EXPR, void_type_node, loaded_val, call); @@ -5338,7 +6724,10 @@ expand_omp_atomic_store (basic_block load_bb, tree addr, if (!useless_type_conversion_p (itype, type)) stored_val = fold_build1_loc (loc, VIEW_CONVERT_EXPR, itype, stored_val); call = build_call_expr_loc (loc, decl, 3, addr, stored_val, - build_int_cst (NULL, MEMMODEL_RELAXED)); + build_int_cst (NULL, + gimple_omp_atomic_seq_cst_p (stmt) + ? MEMMODEL_SEQ_CST + : MEMMODEL_RELAXED)); if (exchange) { if (!useless_type_conversion_p (type, itype)) @@ -5379,6 +6768,7 @@ expand_omp_atomic_fetch_op (basic_block load_bb, enum tree_code code; bool need_old, need_new; enum machine_mode imode; + bool seq_cst; /* We expect to find the following sequences: @@ -5404,6 +6794,7 @@ expand_omp_atomic_fetch_op (basic_block load_bb, return false; need_new = gimple_omp_atomic_need_value_p (gsi_stmt (gsi)); need_old = gimple_omp_atomic_need_value_p (last_stmt (load_bb)); + seq_cst = gimple_omp_atomic_seq_cst_p (last_stmt (load_bb)); gcc_checking_assert (!need_old || !need_new); if (!operand_equal_p (gimple_assign_lhs (stmt), stored_val, 0)) @@ -5470,7 +6861,9 @@ expand_omp_atomic_fetch_op (basic_block load_bb, use the RELAXED memory model. */ call = build_call_expr_loc (loc, decl, 3, addr, fold_convert_loc (loc, itype, rhs), - build_int_cst (NULL, MEMMODEL_RELAXED)); + build_int_cst (NULL, + seq_cst ? MEMMODEL_SEQ_CST + : MEMMODEL_RELAXED)); if (need_old || need_new) { @@ -5812,12 +7205,17 @@ expand_omp (struct omp_region *region) while (region) { location_t saved_location; + gimple inner_stmt = NULL; /* First, determine whether this is a combined parallel+workshare region. */ if (region->type == GIMPLE_OMP_PARALLEL) determine_parallel_type (region); + if (region->type == GIMPLE_OMP_FOR + && gimple_omp_for_combined_p (last_stmt (region->entry))) + inner_stmt = last_stmt (region->inner->entry); + if (region->inner) expand_omp (region->inner); @@ -5833,7 +7231,7 @@ expand_omp (struct omp_region *region) break; case GIMPLE_OMP_FOR: - expand_omp_for (region); + expand_omp_for (region, inner_stmt); break; case GIMPLE_OMP_SECTIONS: @@ -6015,7 +7413,7 @@ execute_expand_omp (void) static bool gate_expand_omp (void) { - return (flag_openmp != 0 && !seen_error ()); + return ((flag_openmp || flag_enable_cilkplus) && !seen_error ()); } struct gimple_opt_pass pass_expand_omp = @@ -6059,7 +7457,7 @@ lower_omp_sections (gimple_stmt_iterator *gsi_p, omp_context *ctx) dlist = NULL; ilist = NULL; lower_rec_input_clauses (gimple_omp_sections_clauses (stmt), - &ilist, &dlist, ctx); + &ilist, &dlist, ctx, NULL); new_body = gimple_omp_body (stmt); gimple_omp_set_body (stmt, NULL); @@ -6267,7 +7665,7 @@ lower_omp_single (gimple_stmt_iterator *gsi_p, omp_context *ctx) bind_body = NULL; dlist = NULL; lower_rec_input_clauses (gimple_omp_single_clauses (single_stmt), - &bind_body, &dlist, ctx); + &bind_body, &dlist, ctx, NULL); lower_omp (gimple_omp_body_ptr (single_stmt), ctx); gimple_seq_add_stmt (&bind_body, single_stmt); @@ -6516,6 +7914,8 @@ lower_omp_for_lastprivate (struct omp_for_data *fd, gimple_seq *body_p, && host_integerp (fd->loop.n2, 0) && ! integer_zerop (fd->loop.n2)) vinit = build_int_cst (TREE_TYPE (fd->loop.v), 0); + else + vinit = unshare_expr (vinit); /* Initialize the iterator variable, so that threads that don't execute any iterations don't execute the lastprivate clauses by accident. */ @@ -6530,7 +7930,7 @@ static void lower_omp_for (gimple_stmt_iterator *gsi_p, omp_context *ctx) { tree *rhs_p, block; - struct omp_for_data fd; + struct omp_for_data fd, *fdp = NULL; gimple stmt = gsi_stmt (*gsi_p), new_stmt; gimple_seq omp_for_body, body, dlist; size_t i; @@ -6539,7 +7939,6 @@ lower_omp_for (gimple_stmt_iterator *gsi_p, omp_context *ctx) push_gimplify_context (&gctx); lower_omp (gimple_omp_for_pre_body_ptr (stmt), ctx); - lower_omp (gimple_omp_body_ptr (stmt), ctx); block = make_node (BLOCK); new_stmt = gimple_build_bind (NULL, NULL, block); @@ -6558,12 +7957,54 @@ lower_omp_for (gimple_stmt_iterator *gsi_p, omp_context *ctx) gimple_bind_append_vars (new_stmt, vars); } + if (gimple_omp_for_combined_into_p (stmt)) + { + extract_omp_for_data (stmt, &fd, NULL); + fdp = &fd; + + /* 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; + tree type = fd.iter_type; + 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; + tree outerc = NULL, *pc = gimple_omp_for_clauses_ptr (stmt); + tree clauses = *pc; + if (parallel_for) + outerc + = find_omp_clause (gimple_omp_parallel_clauses (ctx->outer->stmt), + OMP_CLAUSE__LOOPTEMP_); + for (i = 0; i < count; i++) + { + tree temp; + if (parallel_for) + { + gcc_assert (outerc); + temp = lookup_decl (OMP_CLAUSE_DECL (outerc), ctx->outer); + outerc = find_omp_clause (OMP_CLAUSE_CHAIN (outerc), + OMP_CLAUSE__LOOPTEMP_); + } + else + temp = create_tmp_var (type, NULL); + *pc = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE__LOOPTEMP_); + OMP_CLAUSE_DECL (*pc) = temp; + pc = &OMP_CLAUSE_CHAIN (*pc); + } + *pc = clauses; + } + /* The pre-body and input clauses go before the lowered GIMPLE_OMP_FOR. */ dlist = NULL; body = NULL; - lower_rec_input_clauses (gimple_omp_for_clauses (stmt), &body, &dlist, ctx); + lower_rec_input_clauses (gimple_omp_for_clauses (stmt), &body, &dlist, ctx, + fdp); gimple_seq_add_seq (&body, gimple_omp_for_pre_body (stmt)); + lower_omp (gimple_omp_body_ptr (stmt), ctx); + /* Lower the header expressions. At this point, we can assume that the header is of the form: @@ -6599,13 +8040,13 @@ lower_omp_for (gimple_stmt_iterator *gsi_p, omp_context *ctx) /* After the loop, add exit clauses. */ lower_reduction_clauses (gimple_omp_for_clauses (stmt), &body, ctx); + gimple_seq_add_seq (&body, dlist); body = maybe_catch_exception (body); /* Region exit marker goes at the end of the loop body. */ gimple_seq_add_stmt (&body, gimple_build_omp_return (fd.have_nowait)); - pop_gimplify_context (new_stmt); gimple_bind_append_vars (new_stmt, ctx->block_vars); @@ -6964,7 +8405,7 @@ lower_omp_taskreg (gimple_stmt_iterator *gsi_p, omp_context *ctx) par_olist = NULL; par_ilist = NULL; - lower_rec_input_clauses (clauses, &par_ilist, &par_olist, ctx); + lower_rec_input_clauses (clauses, &par_ilist, &par_olist, ctx, NULL); lower_omp (&par_body, ctx); if (gimple_code (stmt) == GIMPLE_OMP_PARALLEL) lower_reduction_clauses (clauses, &par_olist, ctx); @@ -7163,7 +8604,7 @@ execute_lower_omp (void) /* This pass always runs, to provide PROP_gimple_lomp. But there is nothing to do unless -fopenmp is given. */ - if (flag_openmp == 0) + if (!flag_openmp && !flag_enable_cilkplus) return 0; all_contexts = splay_tree_new (splay_tree_compare_pointers, 0, @@ -7266,12 +8707,33 @@ diagnose_sb_0 (gimple_stmt_iterator *gsi_p, error ("invalid entry to OpenMP structured block"); #endif + bool cilkplus_block = false; + if (flag_enable_cilkplus) + { + if ((branch_ctx + && gimple_code (branch_ctx) == GIMPLE_OMP_FOR + && gimple_omp_for_kind (branch_ctx) == GF_OMP_FOR_KIND_CILKSIMD) + || (gimple_code (label_ctx) == GIMPLE_OMP_FOR + && gimple_omp_for_kind (label_ctx) == GF_OMP_FOR_KIND_CILKSIMD)) + cilkplus_block = true; + } + /* If it's obvious we have an invalid entry, be specific about the error. */ if (branch_ctx == NULL) - error ("invalid entry to OpenMP structured block"); + { + if (cilkplus_block) + error ("invalid entry to Cilk Plus structured block"); + else + error ("invalid entry to OpenMP structured block"); + } else - /* Otherwise, be vague and lazy, but efficient. */ - error ("invalid branch to/from an OpenMP structured block"); + { + /* Otherwise, be vague and lazy, but efficient. */ + if (cilkplus_block) + error ("invalid branch to/from a Cilk Plus structured block"); + else + error ("invalid branch to/from an OpenMP structured block"); + } gsi_replace (gsi_p, gimple_build_nop (), false); return true; @@ -7454,7 +8916,7 @@ diagnose_omp_structured_block_errors (void) static bool gate_diagnose_omp_blocks (void) { - return flag_openmp != 0; + return flag_openmp || flag_enable_cilkplus; } struct gimple_opt_pass pass_diagnose_omp_blocks = diff --git a/gcc/testsuite/ChangeLog.gomp b/gcc/testsuite/ChangeLog.gomp new file mode 100644 index 0000000000000..8c20fa7cb51af --- /dev/null +++ b/gcc/testsuite/ChangeLog.gomp @@ -0,0 +1,59 @@ +2013-06-04 Jakub Jelinek + + * g++.dg/gomp/depend-1.C: New test. + * g++.dg/gomp/depend-2.C: New test. + * c-c++-common/gomp/depend-1.c: New test. + * c-c++-common/gomp/depend-2.c: New test. + * c-c++-common/gomp/map-1.c: New test. + +2013-05-13 Jakub Jelinek + + * gcc.dg/gomp/declare-simd-1.c: New test. + * gcc.dg/gomp/declare-simd-2.c: New test. + +2013-05-09 Jakub Jelinek + + * g++.dg/gomp/declare-simd-1.C: New test. + * g++.dg/gomp/declare-simd-2.C: New test. + +2013-04-30 Jakub Jelinek + + * gfortran.dg/gomp/appendix-a/a.35.5.f90: Add dg-error. + +2013-04-24 Jakub Jelinek + + * c-c++-common/gomp/simd1.c: Enable also for C. + * c-c++-common/gomp/simd2.c: Likewise. + * c-c++-common/gomp/simd3.c: Likewise. + * c-c++-common/gomp/simd4.c: Likewise. Adjust expected + diagnostics for C. + * c-c++-common/gomp/simd5.c: Enable also for C. + +2013-04-23 Jakub Jelinek + + * c-c++-common/gomp/simd3.c: New test. + * c-c++-common/gomp/simd4.c: New test. + * c-c++-common/gomp/simd5.c: New test. + +2013-04-19 Jakub Jelinek + + * c-c++-common/gomp/simd1.c: New test. + * c-c++-common/gomp/simd2.c: New test. + +2013-04-10 Jakub Jelinek + + * gcc.dg/gomp/combined-1.c: Look for GOMP_parallel_loop_runtime + instead of GOMP_parallel_loop_runtime_start. + +2013-03-20 Jakub Jelinek + + * c-c++-common/gomp/atomic-15.c: Adjust for C diagnostics. + + * c-c++-common/gomp/atomic-15.c: Remove error test that is now + valid in OpenMP 4.0. + +Copyright (C) 2013 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/body.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/body.c new file mode 100644 index 0000000000000..e8e2066de4343 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/body.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-fcilkplus -fopenmp" } */ + +int *a, *b, c; +void *jmpbuf[10]; + +void foo() +{ + int j; + +#pragma simd + for (int i=0; i < 1000; ++i) + { + if (c == 6) + __builtin_setjmp (jmpbuf); /* { dg-error "calls to setjmp are not allowed" } */ + a[i] = b[i]; + } + +#pragma simd + for (int i=0; i < 1000; ++i) + { + if (c==5) + break; /* { dg-error "break statement within" } */ + } + +#pragma simd + for (int i=0; i < 1000; ++i) + { +#pragma omp for /* { dg-error "OpenMP statements are not allowed" } */ + for (j=0; j < 1000; ++j) + a[i] = b[i]; + } +} diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses1.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses1.c new file mode 100644 index 0000000000000..6d84791c60585 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses1.c @@ -0,0 +1,76 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -Werror -Wunknown-pragmas -fcilkplus" } */ + +volatile int *a, *b; + +void foo() +{ + int i, j, k; + +#pragma simd assert /* { dg-error "expected '#pragma simd' clause" } */ + for (i=0; i < 100; ++i) + a[i] = b[i]; + +#pragma simd vectorlength /* { dg-error "expected '\\('" } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd vectorlength /* { dg-error "expected '\\('" } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd vectorlength(sizeof (a) == sizeof (float) ? 4 : 8) + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd vectorlength(4,8) /* { dg-error "expected '\\)'" } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd vectorlength(i) /* { dg-error "\(vectorlength must be an integer\|in a constant\)" } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd linear(35) /* { dg-error "expected identifier" } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd linear(blah) /* { dg-error "'blah' \(undeclared\|has not been\)" } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd linear(j, 36, k) /* { dg-error "expected" } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd linear(i, j) + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd linear(i) + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd linear(i : 4) + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd linear(i : 2, j : 4, k) + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd linear(j : sizeof (a) == sizeof (float) ? 4 : 8) + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + + // And now everyone in unison! +#pragma simd linear(j : 4) vectorlength(4) + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd linear(blah2, 36) + /* { dg-error "'blah2' \(undeclared\|has not been\)" "undeclared" { target *-*-* } 71 } */ + /* { dg-error "expected" "expected" { target *-*-* } 71 } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; +} diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses2.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses2.c new file mode 100644 index 0000000000000..71589c2b1786f --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses2.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fdump-tree-original -fcilkplus" } */ + +volatile int *a, *b; + +void foo() +{ + int j, k; + +#pragma simd linear(j : 4, k) vectorlength(4) + for (int i=0; i < 1000; ++i) + a[i] = b[j]; +} + +/* { dg-final { scan-tree-dump-times "linear\\(j:4\\)" 1 "original" } } */ +/* { dg-final { scan-tree-dump-times "linear\\(k:1\\)" 1 "original" } } */ +/* { dg-final { scan-tree-dump-times "safelen\\(4\\)" 1 "original" } } */ +/* { dg-final { cleanup-tree-dump "original" } } */ diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses3.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses3.c new file mode 100644 index 0000000000000..579b718a01c69 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses3.c @@ -0,0 +1,39 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fcilkplus" } */ + +#define N 1000 + +int A[N], B[N], C[N]; +int main (void) +{ +#pragma simd private (B) linear(B:1) /* { dg-error "more than one clause" } */ + for (int ii = 0; ii < N; ii++) + { + A[ii] = B[ii] + C[ii]; + } + +#pragma simd private (B, C) linear(B:1) /* { dg-error "more than one clause" } */ + for (int ii = 0; ii < N; ii++) + { + A[ii] = B[ii] + C[ii]; + } + +#pragma simd private (B) linear(C:2, B:1) /* { dg-error "more than one clause" } */ + for (int ii = 0; ii < N; ii++) + { + A[ii] = B[ii] + C[ii]; + } + +#pragma simd reduction (+:B) linear(B:1) /* { dg-error "more than one clause" } */ + for (int ii = 0; ii < N; ii++) + { + A[ii] = B[ii] + C[ii]; + } + +#pragma simd reduction (+:B) linear(B) /* { dg-error "more than one clause" } */ + for (int ii = 0; ii < N; ii++) + { + A[ii] = B[ii] + C[ii]; + } + return 0; +} diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/for1.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/for1.c new file mode 100644 index 0000000000000..04773d127556d --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/for1.c @@ -0,0 +1,139 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fcilkplus" } */ + +int *a, *b, *c; +int something; + +void foo() +{ + int i, j; + + // Declaration and initialization is allowed. +#pragma simd + for (int i=0; i < 1000; i++) + a[i] = b[j]; + + // Empty initialization is not allowed. +#pragma simd + for (; i < 5; ++i) // { dg-error "expected iteration decl" } + a[i] = i; + + // Empty condition is not allowed. +#pragma simd + for (int i=0; ; ++i) /* { dg-error "missing condition" } */ + a[i] = i; + + // Empty increment is not allowed. +#pragma simd + for (int i=0; i < 1234; ) /* { dg-error "missing increment" } */ + a[i] = i*2; + +#pragma simd + i = 5; /* { dg-error "for statement expected" } */ + + // Initialization variables must be either integral or pointer types. + struct S { + int i; + }; +#pragma simd + for (struct S ss = { 0 }; ss.i <= 1000; ++ss.i) /* { dg-error "initialization variable must be of integral or pointer type" } */ + a[ss.i] = b[ss.i]; + + #pragma simd + for (float f=0.0; f < 15.0; ++f) /* { dg-error "must be of integral" } */ + a[(int)f] = (int) f; + + // Pointers are OK. + #pragma simd + for (int *i=c; i < &c[100]; ++i) + *a = '5'; + + // Condition of '==' is not allowed. +#pragma simd + for (int i=j; i == 5; ++i) /* { dg-error "invalid controlling predicate" } */ + a[i] = b[i]; + + // The LHS or RHS of the condition must be the initialization variable. +#pragma simd + for (int i=0; i+j < 1234; ++i) /* { dg-error "invalid controlling predicate" } */ + a[i] = b[i]; + + // Likewise. +#pragma simd + for (int i=0; 1234 < i + j; ++i) /* { dg-error "invalid controlling predicate" } */ + a[i] = b[i]; + + // Likewise, this is ok. +#pragma simd + for (int i=0; 1234 + j < i; ++i) + a[i] = b[i]; + + // According to the CilkPlus forum, casts are not allowed, even if + // they are no-ops. +#pragma simd + for (int i=0; (char)i < 1234; ++i) /* { dg-error "invalid controlling predicate" } */ + a[i] = b[i]; + +#pragma simd + for (int i=255; i != something; --i) + a[i] = b[i]; + + // This condition gets folded into "i != 0" by + // c_parser_cilk_for_statement(). This is allowed as per the "!=" + // allowance above. +#pragma simd + for (int i=100; i; --i) + a[i] = b[i]; + +#pragma simd + for (int i=100; i != 5; i += something) + a[i] = b[i]; + + // Increment must be on the induction variable. +#pragma simd + for (int i=0; i < 100; j++) /* { dg-error "invalid increment expression" } */ + a[i] = b[i]; + + // Likewise. +#pragma simd + for (int i=0; i < 100; j = i + 1) /* { dg-error "invalid increment expression" } */ + a[i] = b[i]; + + // Likewise. +#pragma simd + for (int i=0; i < 100; i = j + 1) /* { dg-error "invalid increment expression" } */ + a[i] = b[i]; + +#pragma simd + for (int i=0; i < 100; i = i + 5) + a[i] = b[i]; + + // Only PLUS and MINUS increments are allowed. +#pragma simd + for (int i=0; i < 100; i *= 5) /* { dg-error "invalid increment expression" } */ + a[i] = b[i]; + +#pragma simd + for (int i=0; i < 100; i -= j) + a[i] = b[i]; + +#pragma simd + for (int i=0; i < 100; i = i + j) + a[i] = b[i]; + +#pragma simd + for (int i=0; i < 100; i = j + i) + a[i] = b[i]; + +#pragma simd + for (int i=0; i < 100; ++i, ++j) /* { dg-error "invalid increment expression" } */ + a[i] = b[i]; + +#pragma simd + for (int *point=0; point < b; ++point) + *point = 555; + +#pragma simd + for (int *point=0; point > b; --point) + *point = 555; +} diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/for3.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/for3.c new file mode 100644 index 0000000000000..86606275ac471 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/for3.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fcilkplus" } */ + +#pragma simd /* { dg-error "must be inside a function" } */ + +void foo() +{ +} diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/for4.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/for4.c new file mode 100644 index 0000000000000..2da8235f3194c --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/for4.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fcilkplus" } */ + +int *a, *c; + +void foo() +{ + int i, j; + + // Pointers are OK. + #pragma simd + for (int *i=c; i < c; ++i) + *a = '5'; +} diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/for5.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/for5.c new file mode 100644 index 0000000000000..7075a44718eb3 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/for5.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fcilkplus" } */ + +int *a, *b; + +void foo() +{ +#pragma simd + for (int i=100; i; --i) + a[i] = b[i]; +} diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/p_simd_test1.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/p_simd_test1.c new file mode 100644 index 0000000000000..43a359a9442b5 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/p_simd_test1.c @@ -0,0 +1,36 @@ +/* { dg-do run } */ +/* { dg-options "-O3 -fcilkplus" } */ + +#include + +#define ARRAY_SIZE (256) +int a[ARRAY_SIZE]; + +__attribute__((noinline)) +int addit (int *arr, int N) +{ + int s=0; +#pragma simd reduction (+:s) + for (int i = 0; i < N; i++) + s += arr[i]; + return s; +} + +int main () { + int i, s = 0, r = 0; + for (i = 0; i < ARRAY_SIZE; i++) + { + a[i] = i; + } + + s = addit (a, ARRAY_SIZE); + + for (i = 0; i < ARRAY_SIZE; i++) + r += i; + + if (s == r) + return 0; + else + return 1; + return 0; +} diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/p_simd_test2.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/p_simd_test2.c new file mode 100644 index 0000000000000..fe51a2916a1d3 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/p_simd_test2.c @@ -0,0 +1,41 @@ +/* { dg-do run } */ +/* { dg-options "-O3 -fcilkplus" } */ + +#define N 256 +#if HAVE_IO +#include +#endif +#include + +int +reduction_simd (int *a) +{ + int s = 0; + +#pragma simd reduction (+:s) + for (int i = 0; i < N; i++) + { + s += a[i]; + } + + return s; +} + +int +main () +{ + int *a = (int *) malloc (N * sizeof (int)); + int i, s = (N - 1) * N / 2; + + for (i = 0; i < N; i++) + { + a[i] = i; + } +#if HAVE_IO + printf ("%d, %d\n", s, reduction_simd (a)); +#endif + if (s == reduction_simd (a)) + return 0; + else + return 1; +} diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/reduction_ex.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/reduction_ex.c new file mode 100644 index 0000000000000..920b6db133144 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/reduction_ex.c @@ -0,0 +1,36 @@ +/* { dg-do run } */ +/* { dg-options "-O3 -fcilkplus" } */ + +int argc = 1; + +/* This is a simple vectorization, it checks if check_off_reduction_var works + and it also checks if it can vectorize this loop in func correctly. */ +#define N 1000 + +int func (int *p, int *q) { + int x = 0; +#pragma simd reduction (+:x) + for (int ii = 0; ii < N; ii++) { + x += (q[ii] + p[ii]); + } + return x; + +} + +int main () +{ + int ii = 0, x; + int Array[N], Array2[N]; + + for (ii = 0; ii < N; ii++) + { + Array[ii] = 5 + argc; + Array2[ii] = argc; + } + x = func (Array, Array2); + + if (x != N * 7) + return 1; + return 0; +} + diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/run-1.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/run-1.c new file mode 100644 index 0000000000000..c8fe1c762bc32 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/run-1.c @@ -0,0 +1,28 @@ +/* { dg-do run } */ +/* { dg-options "-fcilkplus -O3" } */ + +#include + +#define N 4 + +float f1[] = { 2.0, 3.0, 4.0, 5.0 }; +float f2[] = { 1.0, 6.0, -1.0, -2.0 }; +float res[] = { 3.0, 9.0, 3.0, 3.0 }; + +__attribute__((noinline)) +void verify (float *sum) +{ + for (int i=0; i < N; ++i) + if (sum[i] != res[i]) + abort (); +} + +int main() +{ + float sum[N]; +#pragma simd + for (int i=0; i < N; ++i) + sum[i] = f1[i] + f2[i]; + verify (sum); + return 0; +} diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/safelen.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/safelen.c new file mode 100644 index 0000000000000..2c59de9b02d92 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/safelen.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fdump-tree-gimple -fcilkplus" } */ + +int *a, *b; + +void foo() +{ +#pragma simd vectorlength(8) + for (int i=0; i < 1000; ++i) + a[i] = b[i]; +} + +/* { dg-final { scan-tree-dump-times "safelen\\(8\\)" 1 "gimple" } } */ +/* { dg-final { cleanup-tree-dump "gimple" } } */ diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/vectorlength.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/vectorlength.c new file mode 100644 index 0000000000000..9aa4a68290d56 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/vectorlength.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fcilkplus" } */ + +volatile int *a, *b, N; +typedef int tint; +struct someclass { + int a; + char b; + int *p; +}; + +void foo() +{ +#pragma simd vectorlength(4) vectorlength(8) /* { dg-error "too many 'vectorlength' clauses" } */ + for (int i=0; i < N; ++i) + a[i] = b[i]; + +#pragma simd vectorlength(3) /* { dg-error "must be a power of 2" } */ + for (int i=0; i < N; ++i) + a[i] = b[i]; +} diff --git a/gcc/testsuite/c-c++-common/gomp/atomic-15.c b/gcc/testsuite/c-c++-common/gomp/atomic-15.c index 13a9e0ce48a15..5e669fa3543d8 100644 --- a/gcc/testsuite/c-c++-common/gomp/atomic-15.c +++ b/gcc/testsuite/c-c++-common/gomp/atomic-15.c @@ -8,39 +8,37 @@ main () { int v; #pragma omp atomic - x = x * 7 + 6; /* { dg-error "expected" } */ + x = x * 7 + 6; /* { dg-error "expected|invalid form of" } */ #pragma omp atomic - x = x * 7 ^ 6; /* { dg-error "expected" } */ + x = x * 7 ^ 6; /* { dg-error "expected|invalid form of" } */ #pragma omp atomic update - x = x - 8 + 6; /* { dg-error "expected" } */ + x = x - 8 + 6; /* { dg-error "expected|invalid form of" } */ #pragma omp atomic - x = x ^ 7 | 2; /* { dg-error "expected" } */ + x = x ^ 7 | 2; /* { dg-error "expected|invalid form of" } */ #pragma omp atomic - x = x / 7 * 2; /* { dg-error "expected" } */ + x = x / 7 * 2; /* { dg-error "expected|invalid form of" } */ #pragma omp atomic - x = x / 7 / 2; /* { dg-error "expected" } */ + x = x / 7 / 2; /* { dg-error "expected|invalid form of" } */ #pragma omp atomic capture - v = x = x | 6; /* { dg-error "invalid operator" } */ + { v = x; x = x * 7 + 6; } /* { dg-error "expected" "" { target c++ } } */ #pragma omp atomic capture - { v = x; x = x * 7 + 6; } /* { dg-error "expected" } */ + { v = x; x = x * 7 ^ 6; } /* { dg-error "expected" "" { target c++ } } */ #pragma omp atomic capture - { v = x; x = x * 7 ^ 6; } /* { dg-error "expected" } */ + { v = x; x = x - 8 + 6; } /* { dg-error "expected" "" { target c++ } } */ #pragma omp atomic capture - { v = x; x = x - 8 + 6; } /* { dg-error "expected" } */ + { v = x; x = x ^ 7 | 2; } /* { dg-error "expected" "" { target c++ } } */ #pragma omp atomic capture - { v = x; x = x ^ 7 | 2; } /* { dg-error "expected" } */ + { v = x; x = x / 7 * 2; } /* { dg-error "expected" "" { target c++ } } */ #pragma omp atomic capture - { v = x; x = x / 7 * 2; } /* { dg-error "expected" } */ + { v = x; x = x / 7 / 2; } /* { dg-error "expected" "" { target c++ } } */ #pragma omp atomic capture - { v = x; x = x / 7 / 2; } /* { dg-error "expected" } */ + { x = x * 7 + 6; v = x; } /* { dg-error "expected|uses two different expressions for memory" } */ #pragma omp atomic capture - { x = x * 7 + 6; v = x; } /* { dg-error "expected" } */ + { x = x * 7 ^ 6; v = x; } /* { dg-error "expected|uses two different expressions for memory" } */ #pragma omp atomic capture - { x = x * 7 ^ 6; v = x; } /* { dg-error "expected" } */ + { x = x - 8 + 6; v = x; } /* { dg-error "expected|uses two different expressions for memory" } */ #pragma omp atomic capture - { x = x - 8 + 6; v = x; } /* { dg-error "expected" } */ - #pragma omp atomic capture - { x = x ^ 7 | 2; v = x; } /* { dg-error "expected" } */ + { x = x ^ 7 | 2; v = x; } /* { dg-error "expected|uses two different expressions for memory" } */ (void) v; return 0; } diff --git a/gcc/testsuite/c-c++-common/gomp/depend-1.c b/gcc/testsuite/c-c++-common/gomp/depend-1.c new file mode 100644 index 0000000000000..03d4de98fec0f --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/depend-1.c @@ -0,0 +1,79 @@ +/* { dg-do compile { target c++ } } */ +/* { dg-options "-fopenmp" } */ + +extern int a[][10], a2[][10]; +int b[10], c[10][2], d[10], e[10], f[10]; +int b2[10], c2[10][2], d2[10], e2[10], f2[10]; +int k[10], l[10], m[10], n[10], o; +int *p; +void bar (void); +int t[10]; +#pragma omp threadprivate (t) + +void +foo (int g[3][10], int h[4][8], int i[2][10], int j[][9], + int g2[3][10], int h2[4][8], int i2[2][10], int j2[][9]) +{ + #pragma omp task depend(in: bar[2:5]) /* { dg-error "is not a variable" } */ + ; + #pragma omp task depend(out: t[2:5]) + ; + #pragma omp task depend(inout: k[0.5:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */ + ; + #pragma omp task depend(in: l[:7.5f]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */ + ; + #pragma omp task depend(out: m[p:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */ + ; + #pragma omp task depend(inout: n[:p]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */ + ; + #pragma omp task depend(in: o[2:5]) /* { dg-error "does not have pointer or array type" } */ + ; + #pragma omp task depend(out: a[:][2:4]) /* { dg-error "array type length expression is not optional" } */ + ; + #pragma omp task depend(inout: b[-1:]) /* { dg-error "negative low bound in array section" } */ + ; + #pragma omp task depend(inout: c[:-3][1:1]) /* { dg-error "negative length in array section" } */ + ; + #pragma omp task depend(in: d[11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */ + ; + #pragma omp task depend(out: e[:11]) /* { dg-error "length \[^\n\r]* above array section size" } */ + ; + #pragma omp task depend(out: f[1:10]) /* { dg-error "high bound \[^\n\r]* above array section size" } */ + ; + #pragma omp task depend(in: g[:][2:4]) /* { dg-error "for pointer type length expression is not optional" } */ + ; + #pragma omp task depend(in: h[2:2][-1:]) /* { dg-error "negative low bound in array section" } */ + ; + #pragma omp task depend(inout: h[:1][:-3]) /* { dg-error "negative length in array section" } */ + ; + #pragma omp task depend(out: i[:1][11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */ + ; + #pragma omp task depend(in: j[3:4][:10]) /* { dg-error "length \[^\n\r]* above array section size" } */ + ; + #pragma omp task depend(out: j[30:10][5:5]) /* { dg-error "high bound \[^\n\r]* above array section size" } */ + ; + #pragma omp task depend(out: a2[:3][2:4]) + ; + #pragma omp task depend(inout: b2[0:]) + ; + #pragma omp task depend(inout: c2[:3][1:1]) + ; + #pragma omp task depend(in: d2[9:]) + ; + #pragma omp task depend(out: e2[:10]) + ; + #pragma omp task depend(out: f2[1:9]) + ; + #pragma omp task depend(in: g2[:2][2:4]) + ; + #pragma omp task depend(in: h2[2:2][0:]) + ; + #pragma omp task depend(inout: h2[:1][:3]) + ; + #pragma omp task depend(out: i2[:1][9:]) + ; + #pragma omp task depend(in: j2[3:4][:9]) + ; + #pragma omp task depend(out: j2[30:10][5:4]) + ; +} diff --git a/gcc/testsuite/c-c++-common/gomp/depend-2.c b/gcc/testsuite/c-c++-common/gomp/depend-2.c new file mode 100644 index 0000000000000..723a05daf6938 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/depend-2.c @@ -0,0 +1,19 @@ +/* { dg-do compile { target c++ } } */ +/* { dg-options "-fopenmp" } */ + +void bar (int a[10][10][10]); +void +foo (int a[10][10][10], int **b) +{ + int c[10][10][10]; + #pragma omp task depend(out: a[2:4][3:][:7], b[1:7][2:8]) + bar (a); + int i = 1, j = 3, k = 2, l = 6; + #pragma omp task depend(in: a[++i:++j][++k:][:++l]) + bar (a); + #pragma omp task depend(out: a[7:2][:][:], c[5:2][:][:]) + { + bar (c); + bar (a); + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/map-1.c b/gcc/testsuite/c-c++-common/gomp/map-1.c new file mode 100644 index 0000000000000..0fda207bc0702 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/map-1.c @@ -0,0 +1,103 @@ +/* { dg-do compile { target c++ } } */ +/* { dg-options "-fopenmp" } */ + +extern int a[][10], a2[][10]; +int b[10], c[10][2], d[10], e[10], f[10]; +int b2[10], c2[10][2], d2[10], e2[10], f2[10]; +int k[10], l[10], m[10], n[10], o; +int *p; +int **q; +int r[4][4][4][4][4]; +int t[10]; +#pragma omp threadprivate (t) +#pragma omp declare target +void bar (int *); +#pragma omp end declare target + +void +foo (int g[3][10], int h[4][8], int i[2][10], int j[][9], + int g2[3][10], int h2[4][8], int i2[2][10], int j2[][9]) +{ + #pragma omp target map(to: bar[2:5]) /* { dg-error "is not a variable" } */ + ; + #pragma omp target map(from: t[2:5]) /* { dg-error "is threadprivate variable" } */ + ; + #pragma omp target map(tofrom: k[0.5:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */ + ; + #pragma omp target map(from: l[:7.5f]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */ + ; + #pragma omp target map(to: m[p:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */ + ; + #pragma omp target map(tofrom: n[:p]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */ + ; + #pragma omp target map(to: o[2:5]) /* { dg-error "does not have pointer or array type" } */ + ; + #pragma omp target map(to: a[:][:]) /* { dg-error "array type length expression is not optional" } */ + bar (&a[0][0]); + #pragma omp target map(tofrom: b[-1:]) /* { dg-error "negative low bound in array section" } */ + bar (b); + #pragma omp target map(tofrom: c[:-3][:]) /* { dg-error "negative length in array section" } */ + bar (&c[0][0]); + #pragma omp target map(from: d[11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */ + bar (d); + #pragma omp target map(to: e[:11]) /* { dg-error "length \[^\n\r]* above array section size" } */ + bar (e); + #pragma omp target map(to: f[1:10]) /* { dg-error "high bound \[^\n\r]* above array section size" } */ + bar (f); + #pragma omp target map(from: g[:][0:10]) /* { dg-error "for pointer type length expression is not optional" } */ + bar (&g[0][0]); + #pragma omp target map(from: h[2:1][-1:]) /* { dg-error "negative low bound in array section" } */ + bar (&h[0][0]); + #pragma omp target map(tofrom: h[:1][:-3]) /* { dg-error "negative length in array section" } */ + bar (&h[0][0]); + #pragma omp target map(i[:1][11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */ + bar (&i[0][0]); + #pragma omp target map(from: j[3:1][:10]) /* { dg-error "length \[^\n\r]* above array section size" } */ + bar (&j[0][0]); + #pragma omp target map(to: j[30:1][5:5]) /* { dg-error "high bound \[^\n\r]* above array section size" } */ + bar (&j[0][0]); + #pragma omp target map(to: a2[:1][2:4]) + bar (&a2[0][0]); + #pragma omp target map(a2[3:5][:]) + bar (&a2[0][0]); + #pragma omp target map(to: a2[3:5][:10]) + bar (&a2[0][0]); + #pragma omp target map(tofrom: b2[0:]) + bar (b2); + #pragma omp target map(tofrom: c2[:3][:]) + bar (&c2[0][0]); + #pragma omp target map(from: d2[9:]) + bar (d2); + #pragma omp target map(to: e2[:10]) + bar (e2); + #pragma omp target map(to: f2[1:9]) + bar (f2); + #pragma omp target map(g2[:1][2:4]) + bar (&g2[0][0]); + #pragma omp target map(from: h2[2:2][0:]) + bar (&h2[0][0]); + #pragma omp target map(tofrom: h2[:1][:3]) + bar (&h2[0][0]); + #pragma omp target map(to: i2[:1][9:]) + bar (&i2[0][0]); + #pragma omp target map(from: j2[3:4][:9]) + bar (&j2[0][0]); + #pragma omp target map(to: j2[30:1][5:4]) + bar (&j2[0][0]); + #pragma omp target map(q[1:2]) + ; + #pragma omp target map(tofrom: q[3:5][:10]) /* { dg-error "array section is not contiguous" } */ + ; + #pragma omp target map(r[3:][2:1][1:2]) + ; + #pragma omp target map(r[3:][2:1][1:2][:][0:4]) + ; + #pragma omp target map(r[3:][2:1][1:2][1:][0:4]) /* { dg-error "array section is not contiguous" } */ + ; + #pragma omp target map(r[3:][2:1][1:2][:3][0:4]) /* { dg-error "array section is not contiguous" } */ + ; + #pragma omp target map(r[3:][2:1][1:2][:][1:]) /* { dg-error "array section is not contiguous" } */ + ; + #pragma omp target map(r[3:][2:1][1:2][:][:3]) /* { dg-error "array section is not contiguous" } */ + ; +} diff --git a/gcc/testsuite/c-c++-common/gomp/simd1.c b/gcc/testsuite/c-c++-common/gomp/simd1.c new file mode 100644 index 0000000000000..29e464ca035bd --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/simd1.c @@ -0,0 +1,31 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ +/* { dg-additional-options "-std=c99" { target c } } */ + +extern int a[1024], b[1024], k, l, m; + +void +foo () +{ + int i; + #pragma omp simd safelen(16) aligned(a, b : 32) + for (i = 0; i < 1024; i++) + a[i] *= b[i]; +} + +void +bar (int *p) +{ + int i; + #pragma omp simd safelen(16) aligned(a, p : 32) linear(k, l : m + 1) + for (i = 0; i < 1024; i++) + a[i] *= p[i], k += m + 1; +} + +void +baz (int *p) +{ + #pragma omp simd safelen(16) aligned(a, p : 32) linear(k, l : m + 1) + for (int i = 0; i < 1024; i++) + a[i] *= p[i], k += m + 1; +} diff --git a/gcc/testsuite/c-c++-common/gomp/simd2.c b/gcc/testsuite/c-c++-common/gomp/simd2.c new file mode 100644 index 0000000000000..dda9c62d6d131 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/simd2.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ +/* { dg-additional-options "-std=c99" { target c } } */ + +extern int a[13][13][13][13], k, l, m; + +void +foo (int *q, float *p) +{ + int i, j, n, o; +#pragma omp simd collapse (4) linear(k : m + 1) aligned(p, q) + for (i = 0; i < 13; i++) + for (j = 0; j < 13; j++) + for (n = 0; n < 13; n++) + for (o = 0; o < 13; o += 2) + q[k] *= p[k] + 7 * i + 14 * j + 21 * n + 28 * o, k += m + 1; +} + +void +bar (float *p) +{ + int i, j, n, o; +#pragma omp simd collapse (4) linear(k : m + 1) + for (i = 0; i < 13; i++) + for (j = 0; j < 13; j++) + for (n = 0; n < 13; n++) + for (o = 0; o < 13; o += 2) + a[i][j][n][o] *= p[k], k += m + 1; +} diff --git a/gcc/testsuite/c-c++-common/gomp/simd3.c b/gcc/testsuite/c-c++-common/gomp/simd3.c new file mode 100644 index 0000000000000..e8270fc452131 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/simd3.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ +/* { dg-additional-options "-std=c99" { target c } } */ + +extern int a[13*13*13*13*2], b[1024], *k, l, m; + +void +foo (int *q, float *p) +{ + int *i, *j, *n, *o; +#pragma omp simd collapse (4) linear(k : m + 1) aligned(p, q) + for (i = &a[0]; i < &a[13*13*13*13*2]; i += 13*13*13*2) + for (j = &a[0]; j < &a[13*13*13*2]; j += 13*13*2) + for (n = &a[0]; n < &a[13*13*2]; n += 13*2) + for (o = &a[0]; o < &a[13*2]; o += 2) + q[k - &a[0]] *= p[k - &a[0]] + 7 * (i-&a[0]) + 14 * (j-&a[0]) + 21 * (n-&a[0]) + 28 * (o-&a[0]), k += m + 1; +} + +void +bar () +{ + int *i; + #pragma omp simd safelen(16) aligned(a, b : 32) + for (i = &a[0]; i < &a[1024]; i++) + *i *= b[i - &a[0]]; +} diff --git a/gcc/testsuite/c-c++-common/gomp/simd4.c b/gcc/testsuite/c-c++-common/gomp/simd4.c new file mode 100644 index 0000000000000..37901b6a07f24 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/simd4.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ +/* { dg-additional-options "-std=c99" { target c } } */ + +struct S *p; /* { dg-error "forward declaration" "" { target c++ } } */ +float f; +int j; + +void +foo (void) +{ +#pragma omp simd linear(p) linear(f : 1) + for (int i = 0; i < 10; i++) + ; +#pragma omp simd linear(j : 7.0) /* { dg-error "step expression must be integral" } */ + for (int i = 0; i < 10; i++) + ; +} + +/* { dg-error "linear clause applied to" "" { target *-*-* } 12 } */ +/* { dg-error "(incomplete|undefined) type" "" { target *-*-* } 12 } */ diff --git a/gcc/testsuite/c-c++-common/gomp/simd5.c b/gcc/testsuite/c-c++-common/gomp/simd5.c new file mode 100644 index 0000000000000..a57896d870469 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/simd5.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ +/* { dg-additional-options "-std=c99" { target c } } */ + +void baz (void) __attribute__((noreturn)); + +void +foo (int x) +{ + if (x) + #pragma omp simd + for (int i = 0; i < 10; i++) + baz (); +#pragma omp simd collapse(3) + for (int i = 0; i < 10; i++) + for (int j = 0; j < 10; j++) + for (int k = 0; k < 10; k++) + baz (); +} diff --git a/gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp b/gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp index a1535290a5c02..3accc99234333 100644 --- a/gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp +++ b/gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp @@ -16,9 +16,15 @@ # Written by Balaji V. Iyer - load_lib g++-dg.exp +dg-init +# Run the tests that are shared with C. +g++-dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/PS/*.c]] "" +# Run the C++ only tests. +g++-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C]] "" +dg-finish + dg-init dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -fcilkplus" " " dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O0 -fcilkplus" " " diff --git a/gcc/testsuite/g++.dg/cilk-plus/for.C b/gcc/testsuite/g++.dg/cilk-plus/for.C new file mode 100644 index 0000000000000..2295d214620ab --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/for.C @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-ftree-vectorize -fcilkplus" } */ + +int *a, *b; + +void foo() +{ + int i; +#pragma simd + for (i=0; i < 10000; ++i) /* { dg-error "initializer does not declare a var" } */ + a[i] = b[i]; +} diff --git a/gcc/testsuite/g++.dg/cilk-plus/for2.C b/gcc/testsuite/g++.dg/cilk-plus/for2.C new file mode 100644 index 0000000000000..d30e05787e43c --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/for2.C @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fcilkplus" } */ + +// Test storage classes in the initialization of a <#pragma simd> for +// loop. + +int *a, *b; + +void foo() +{ +#pragma simd + for (static int tt=5; tt < 10; ++tt) /* { dg-error "storage class is not allowed" } */ + a[tt] = b[tt]; + +#pragma simd + for (extern int var=0; var < 1000; ++var) /* { dg-error "storage class is not allowed" } */ + a[var] = var; + +#pragma simd + for (register int regj = 0; regj < 1000; ++regj) /* { dg-error "storage class is not allowed" } */ + b[regj] = a[regj] * 2; + +#pragma simd + for (volatile int vj=0; vj<1000; ++vj) /* { dg-error "induction variable cannot be volatile" } */ + a[vj] = b[vj]; +} diff --git a/gcc/testsuite/g++.dg/dg.exp b/gcc/testsuite/g++.dg/dg.exp index 710218e67c5f2..e9d0428ffeeac 100644 --- a/gcc/testsuite/g++.dg/dg.exp +++ b/gcc/testsuite/g++.dg/dg.exp @@ -49,6 +49,7 @@ set tests [prune $tests $srcdir/$subdir/tree-prof/*] set tests [prune $tests $srcdir/$subdir/torture/*] set tests [prune $tests $srcdir/$subdir/graphite/*] set tests [prune $tests $srcdir/$subdir/tm/*] +set tests [prune $tests $srcdir/$subdir/cilk-plus/*] set tests [prune $tests $srcdir/$subdir/guality/*] set tests [prune $tests $srcdir/$subdir/simulate-thread/*] set tests [prune $tests $srcdir/$subdir/asan/*] diff --git a/gcc/testsuite/g++.dg/gomp/declare-simd-1.C b/gcc/testsuite/g++.dg/gomp/declare-simd-1.C new file mode 100644 index 0000000000000..669b0e475583a --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/declare-simd-1.C @@ -0,0 +1,224 @@ +// Test parsing of #pragma omp declare simd +// { dg-do compile } + +#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) \ + linear (c : 4) simdlen (8) notinbranch +#pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a \ + : 4) simdlen (4) inbranch +int f1 (int a, int *b, int c); + +#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) +int f2 (int a, int *b, int c) +{ + return a + *b + c; +} + +#pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) +template +T f3 (int a, int *b, T c); + +template <> +int f3 (int, int *, int); + +#pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) notinbranch simdlen (4) +template +int f4 (int a, int *b, T c) +{ + return a + *b + c; +} + +template <> +int f4 (int, int *, int); + +template +int f5 (int a, int *b, T c); + +#pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) +template <> +int f5 (int a, int *b, int c); + +template +int f6 (int a, int *b, int c); + +#pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) inbranch simdlen (4) +template <> +int f6<3> (int a, int *b, int c); + +#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (long long)) linear (c : 4) simdlen (8) +__extension__ +long long f7 (long long a, long long *b, long long c); + +#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) notinbranch simdlen (8) +extern "C" +int f8 (int a, int *b, int c); + +extern "C" +{ + #pragma omp declare simd + int f9 (int a, int *b, int c); +} + +namespace N1 +{ + namespace N2 + { + #pragma omp declare simd simdlen (2) aligned (b : sizeof (long long) * 2) + __extension__ long long + f10 (long long *b) + { + return *b; + } + } +} + +struct A +{ + #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) + #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) + int f11 (int a, int *b, int c); + + #pragma omp declare simd + template + int f12 (int a, int *b, int c); + + #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) notinbranch simdlen (8) + #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) inbranch + static int f13 (int a, int *b, int c); + + #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) + #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) + int f14 (int a, int *b, int c) { return a + *b + c; } + + #pragma omp declare simd + template + int f15 (int a, int *b, int c) { return a + *b + c; } + + #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) + #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) + static int f16 (int a, int *b, int c) { return a + *b + c; } +}; + +template <> +int A::f12<2> (int, int *, int); + +template <> +int A::f15<2> (int, int *, int); + +template +struct B +{ + #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) notinbranch + #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) inbranch + int f17 (int a, int *b, int c); + + #pragma omp declare simd + template + int f18 (int a, int *b, int c); + + #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) + #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) + static int f19 (int a, int *b, int c); + + #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) + #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) + int f20 (int a, int *b, int c) { return a + *b + c; } + + #pragma omp declare simd + template + int f21 (int a, int *b, int c) { return a + *b + c; } + + #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) + #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) + static int f22 (int a, int *b, int c) { return a + *b + c; } + + template + int f23 (int, int *, int); + + template + static int f24 (int, int *, int); + + template + int f25 (int, int *, int); + + template + static int f26 (int, int *, int); +}; + +B b; + +template <> +template <> +int B::f18<0> (int, int *, int); + +template <> +template <> +int B::f21<9> (int, int *, int); + +#pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) uniform (a, c) +template <> +template <> +int B::f23<7> (int a, int *b, int c); + +#pragma omp declare simd simdlen (4) aligned (b : 8 * sizeof (int)) linear (a, c : 2) +template <> +template <> +int B::f24<-1> (int a, int *b, int c); + +#pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) uniform (a, c) +template <> +template <> +int B::f25<7> (int a, int *b, int c) +{ + return a + *b + c; +} + +#pragma omp declare simd simdlen (4) aligned (b : 8 * sizeof (int)) linear (a, c : 2) +template <> +template <> +int B::f26<-1> (int a, int *b, int c) +{ + return a + *b + c; +} + +int +f27 (int x) +{ + #pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) + extern int f28 (int a, int *b, int c); + { + x++; + #pragma omp declare simd simdlen (4) linear (c) + extern int f29 (int a, int *b, int c); + } + return x; +} + +#pragma omp declare simd simdlen (16) +int +f30 (int x) +{ + #pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) + extern int f31 (int a, int *b, int c); + return x; +} + +template +struct C +{ + #pragma omp declare simd simdlen (N) aligned (a : N * sizeof (int)) linear (c : N) notinbranch + int f32 (int a, int *b, int c); +}; + +C <2> c; + +int +f33 (int x) +{ + if (x) + #pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) + extern int f34 (int a, int *b, int c); + while (x < 10) + #pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) + extern int f35 (int a, int *b, int c); + return x; +} diff --git a/gcc/testsuite/g++.dg/gomp/declare-simd-2.C b/gcc/testsuite/g++.dg/gomp/declare-simd-2.C new file mode 100644 index 0000000000000..eb449fe2fb6fc --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/declare-simd-2.C @@ -0,0 +1,60 @@ +// Test parsing of #pragma omp declare simd +// { dg-do compile } + +#pragma omp declare simd +int a; // { dg-error "not immediately followed by function declaration or definition" } + +#pragma omp declare simd +int fn1 (int a), fn2 (int a); // { dg-error "not immediately followed by a single function declaration or definition" } + +#pragma omp declare simd +int b, fn3 (int a); // { dg-error "not immediately followed by function declaration or definition" } + +#pragma omp declare simd linear (a) +int fn4 (int a), c; // { dg-error "not immediately followed by function declaration or definition" } + +#pragma omp declare simd +extern "C" // { dg-error "not immediately followed by function declaration or definition" } +{ + int fn5 (int a); +} + +#pragma omp declare simd // { dg-error "not immediately followed by function declaration or definition" } +namespace N1 +{ + int fn6 (int a); +} + +#pragma omp declare simd simdlen (4) +struct A +{ // { dg-error "not immediately followed by function declaration or definition" } + int fn7 (int a); +}; + +#pragma omp declare simd +template +struct B +{ // { dg-error "not immediately followed by function declaration or definition" } + int fn8 (int a); +}; + +struct C +{ +#pragma omp declare simd // { dg-error "not immediately followed by function declaration or definition" } + public: // { dg-error "expected unqualified-id before" } + int fn9 (int a); +}; + +int t; + +#pragma omp declare simd +#pragma omp declare simd +#pragma omp threadprivate(t) // { dg-error "not immediately followed by function declaration or definition" } +int fn10 (int a); + +#pragma omp declare simd inbranch notinbranch +int fn11 (int); // { dg-error "clause is incompatible with" } + +#pragma omp declare simd simdlen (N) // { dg-error "was not declared in this scope" } +template +int fn12 (int); diff --git a/gcc/testsuite/g++.dg/gomp/depend-1.C b/gcc/testsuite/g++.dg/gomp/depend-1.C new file mode 100644 index 0000000000000..2084546db70ac --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/depend-1.C @@ -0,0 +1,70 @@ +// { dg-do compile } +// { dg-options "-fopenmp" } + +extern int a[][10], a2[][10]; +int b[10], c[10][2], d[10], e[10], f[10]; +int b2[10], c2[10][2], d2[10], e2[10], f2[10]; +int k[10], l[10], m[10], n[10], o; +int *p; +void bar (void); +int t[10]; +#pragma omp threadprivate (t) + +template +void +foo (int g[3][10], int h[4][8], int i[2][10], int j[][9], + int g2[3][10], int h2[4][8], int i2[2][10], int j2[][9]) +{ + #pragma omp task depend(out: t[2:5]) + ; + #pragma omp task depend(inout: k[0.5:]) // { dg-error "low bound \[^\n\r]* of array section does not have integral type" } + ; + #pragma omp task depend(in: l[:7.5f]) // { dg-error "length \[^\n\r]* of array section does not have integral type" } + ; + #pragma omp task depend(out: m[p:]) // { dg-error "low bound \[^\n\r]* of array section does not have integral type" } + ; + #pragma omp task depend(inout: n[:p]) // { dg-error "length \[^\n\r]* of array section does not have integral type" } + ; + #pragma omp task depend(in: o[2:5]) // { dg-error "does not have pointer or array type" } + ; + #pragma omp task depend(out: a[:][2:4]) // { dg-error "array type length expression is not optional" } + ; + #pragma omp task depend(in: d[11:]) // { dg-error "low bound \[^\n\r]* above array section size" } + ; + #pragma omp task depend(out: e[:11]) // { dg-error "length \[^\n\r]* above array section size" } + ; + #pragma omp task depend(out: f[1:10]) // { dg-error "high bound \[^\n\r]* above array section size" } + ; + #pragma omp task depend(in: g[:][2:4]) // { dg-error "for pointer type length expression is not optional" } + ; + #pragma omp task depend(out: i[:1][11:]) // { dg-error "low bound \[^\n\r]* above array section size" } + ; + #pragma omp task depend(in: j[3:4][:10]) // { dg-error "length \[^\n\r]* above array section size" } + ; + #pragma omp task depend(out: j[30:10][5:5]) // { dg-error "high bound \[^\n\r]* above array section size" } + ; + #pragma omp task depend(out: a2[:3][2:4]) + ; + #pragma omp task depend(inout: b2[0:]) + ; + #pragma omp task depend(inout: c2[:3][1:1]) + ; + #pragma omp task depend(in: d2[9:]) + ; + #pragma omp task depend(out: e2[:10]) + ; + #pragma omp task depend(out: f2[1:9]) + ; + #pragma omp task depend(in: g2[:2][2:4]) + ; + #pragma omp task depend(in: h2[2:2][0:]) + ; + #pragma omp task depend(inout: h2[:1][:3]) + ; + #pragma omp task depend(out: i2[:1][9:]) + ; + #pragma omp task depend(in: j2[3:4][:9]) + ; + #pragma omp task depend(out: j2[30:10][5:4]) + ; +} diff --git a/gcc/testsuite/g++.dg/gomp/depend-2.C b/gcc/testsuite/g++.dg/gomp/depend-2.C new file mode 100644 index 0000000000000..eb3f05c20053f --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/depend-2.C @@ -0,0 +1,87 @@ +// { dg-do compile } +// { dg-options "-fopenmp" } + +extern int a[][10], a2[][10]; +int b[10], c[10][2], d[10], e[10], f[10]; +int b2[10], c2[10][2], d2[10], e2[10], f2[10]; +int k[10], l[10], m[10], n[10], o; +int *p; +void bar (void); +int t[10]; +#pragma omp threadprivate (t) + +template +void +foo (int g[3][10], int h[4][8], int i[2][10], int j[][9], + int g2[3][10], int h2[4][8], int i2[2][10], int j2[][9]) +{ + #pragma omp task depend(in: bar[2:5]) // { dg-error "is not a variable" } + ; + #pragma omp task depend(out: t[2:5]) + ; + #pragma omp task depend(inout: k[0.5:]) // { dg-error "low bound \[^\n\r]* of array section does not have integral type" } + ; + #pragma omp task depend(in: l[:7.5f]) // { dg-error "length \[^\n\r]* of array section does not have integral type" } + ; + #pragma omp task depend(out: m[p:]) // { dg-error "low bound \[^\n\r]* of array section does not have integral type" } + ; + #pragma omp task depend(inout: n[:p]) // { dg-error "length \[^\n\r]* of array section does not have integral type" } + ; + #pragma omp task depend(in: o[2:5]) // { dg-error "does not have pointer or array type" } + ; + #pragma omp task depend(out: a[:][2:4]) // { dg-error "array type length expression is not optional" } + ; + #pragma omp task depend(inout: b[-1:]) // { dg-error "negative low bound in array section" } + ; + #pragma omp task depend(inout: c[:-3][1:1]) // { dg-error "negative length in array section" } + ; + #pragma omp task depend(in: d[11:]) // { dg-error "low bound \[^\n\r]* above array section size" } + ; + #pragma omp task depend(out: e[:11]) // { dg-error "length \[^\n\r]* above array section size" } + ; + #pragma omp task depend(out: f[1:10]) // { dg-error "high bound \[^\n\r]* above array section size" } + ; + #pragma omp task depend(in: g[:][2:4]) // { dg-error "for pointer type length expression is not optional" } + ; + #pragma omp task depend(in: h[2:2][-1:]) // { dg-error "negative low bound in array section" } + ; + #pragma omp task depend(inout: h[:1][:-3]) // { dg-error "negative length in array section" } + ; + #pragma omp task depend(out: i[:1][11:]) // { dg-error "low bound \[^\n\r]* above array section size" } + ; + #pragma omp task depend(in: j[3:4][:10]) // { dg-error "length \[^\n\r]* above array section size" } + ; + #pragma omp task depend(out: j[30:10][5:5]) // { dg-error "high bound \[^\n\r]* above array section size" } + ; + #pragma omp task depend(out: a2[:3][2:4]) + ; + #pragma omp task depend(inout: b2[0:]) + ; + #pragma omp task depend(inout: c2[:3][1:1]) + ; + #pragma omp task depend(in: d2[9:]) + ; + #pragma omp task depend(out: e2[:10]) + ; + #pragma omp task depend(out: f2[1:9]) + ; + #pragma omp task depend(in: g2[:2][2:4]) + ; + #pragma omp task depend(in: h2[2:2][0:]) + ; + #pragma omp task depend(inout: h2[:1][:3]) + ; + #pragma omp task depend(out: i2[:1][9:]) + ; + #pragma omp task depend(in: j2[3:4][:9]) + ; + #pragma omp task depend(out: j2[30:10][5:4]) + ; +} + +void +baz (int g[3][10], int h[4][8], int i[2][10], int j[][9], + int g2[3][10], int h2[4][8], int i2[2][10], int j2[][9]) +{ + foo<0> (g, h, i, j, g2, h2, i2, j2); +} diff --git a/gcc/testsuite/gcc.dg/cilk-plus/auto.c b/gcc/testsuite/gcc.dg/cilk-plus/auto.c new file mode 100644 index 0000000000000..253acee1e0858 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/auto.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ + +int *a, *b; + +void foo() +{ + // This seems like it should be ok. + // Must check with standards people. +#pragma simd + for (auto int autoi = 0; autoi < 1000; ++autoi) + b[autoi] = a[autoi] * 2; + // Similarly here. + auto int autoj; +#pragma simd + for (auto int autoj = 0; autoj < 1000; ++autoj) + b[autoj] = a[autoj] * 2; +} diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp b/gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp index 59b23056c722f..e109c717ad39a 100644 --- a/gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp @@ -20,6 +20,13 @@ load_lib gcc-dg.exp dg-init + +# Run the tests that are shared with C++. +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/PS/*.c]] " -ftree-vectorize -fcilkplus -std=c99" " " +# Run the C-only tests. +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] \ + "-ftree-vectorize -fcilkplus -std=c99" " " + dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -fcilkplus" " " dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O0 -fcilkplus" " " dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O1 -fcilkplus" " " diff --git a/gcc/testsuite/gcc.dg/cilk-plus/for1.c b/gcc/testsuite/gcc.dg/cilk-plus/for1.c new file mode 100644 index 0000000000000..4fb534286d9a6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/for1.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ + +int *a, *b, *c; + +void foo() +{ + int i, j; + // The initialization shall declare or initialize a *SINGLE* variable. +#pragma simd + for (i=0, j=5; i < 1000; i++) // { dg-error "expected ';' before ','" } + a[i] = b[j]; +} diff --git a/gcc/testsuite/gcc.dg/cilk-plus/for2.c b/gcc/testsuite/gcc.dg/cilk-plus/for2.c new file mode 100644 index 0000000000000..dc0a41e4be5c3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/for2.c @@ -0,0 +1,66 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fcilkplus" } */ + +// Test storage classes in the initialization of a <#pragma simd> for +// loop. + +int *a, *b; + +void foo() +{ +#pragma simd + for (static int foo=5; foo < 10; ++foo) + a[foo] = b[foo]; + /* { dg-error "declaration of static variable" "storage class1" { target *-*-* } 12 } */ + /* { dg-error "induction variable cannot be static" "storage class2" { target *-*-* } 12 } */ + + static int bar; +#pragma simd + for (bar=0; bar < 1000; ++bar) /* { dg-error "induction variable cannot be static" } */ + a[bar] = bar; + +#pragma simd + for (extern int var=0; var < 1000; ++var) + a[var] = var; + /* { dg-error "has both 'extern' and initializer" "extern" { target *-*-* } 23 } */ + /* { dg-error "declaration of static variable" "" { target *-*-* } 23 } */ + /* { dg-error "induction variable cannot be static" "" { target *-*-* } 23 } */ + + extern int extvar; +#pragma simd + for (extvar = 0; extvar < 1000; ++extvar) /* { dg-error "induction variable cannot be extern" } */ + b[extvar] = a[extvar]; + + // This seems like it should be ok. + // Must check with standards people. +#pragma simd + for (auto int autoi = 0; autoi < 1000; ++autoi) + b[autoi] = a[autoi] * 2; + // Similarly here. + auto int autoj; +#pragma simd + for (auto int autoj = 0; autoj < 1000; ++autoj) + b[autoj] = a[autoj] * 2; + + register int regi; +#pragma simd + for (regi = 0; regi < 1000; ++regi) /* { dg-error "induction variable cannot be declared register" } */ + b[regi] = a[regi] * 2; + +#pragma simd + for (register int regj = 0; regj < 1000; ++regj) /* { dg-error "induction variable cannot be declared register" } */ + b[regj] = a[regj] * 2; + + volatile int vi; +#pragma simd + for (vi=0; vi<1000; ++vi) /* { dg-error "induction variable cannot be volatile" } */ + a[vi] = b[vi]; + +#pragma simd + for (volatile int vj=0; vj<1000; ++vj) /* { dg-error "induction variable cannot be volatile" } */ + a[vj] = b[vj]; + +#pragma simd + for (const int ci=0; ci<1000; ++ci) /* { dg-error "increment of read-only var" } */ + a[ci] = b[ci]; +} diff --git a/gcc/testsuite/gcc.dg/cilk-plus/jump.c b/gcc/testsuite/gcc.dg/cilk-plus/jump.c new file mode 100644 index 0000000000000..9ec3293cc9791 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/jump.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-fcilkplus" } */ + +int *a, *b, c; + +void foo() +{ +#pragma simd + for (int i=0; i < 1000; ++i) + { + a[i] = b[i]; + if (c == 5) + return; /* { dg-error "invalid branch to.from a Cilk" } */ + } +} + +void bar() +{ +#pragma simd + for (int i=0; i < 1000; ++i) + { + lab: + a[i] = b[i]; + } + if (c == 6) + goto lab; /* { dg-error "invalid entry to Cilk Plus" } */ +} diff --git a/gcc/testsuite/gcc.dg/gomp/combined-1.c b/gcc/testsuite/gcc.dg/gomp/combined-1.c index dfed647371f5b..7e23c3256cb8d 100644 --- a/gcc/testsuite/gcc.dg/gomp/combined-1.c +++ b/gcc/testsuite/gcc.dg/gomp/combined-1.c @@ -20,5 +20,5 @@ int foo (void) } } -/* { dg-final { scan-tree-dump-times "GOMP_parallel_loop_runtime_start" 3 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "GOMP_parallel_loop_runtime" 3 "optimized" } } */ /* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/gomp/declare-simd-1.c b/gcc/testsuite/gcc.dg/gomp/declare-simd-1.c new file mode 100644 index 0000000000000..1decd3f1f4064 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gomp/declare-simd-1.c @@ -0,0 +1,82 @@ +/* Test parsing of #pragma omp declare simd */ +/* { dg-do compile } */ + +#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) \ + linear (c : 4) simdlen (8) notinbranch +#pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a \ + : 4) simdlen (4) inbranch +int f1 (int a, int *b, int c); + +#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) +int f2 (int a, int *b, int c) +{ + return a + *b + c; +} + +#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (long long)) linear (c : 4) simdlen (8) +__extension__ +long long f3 (long long a, long long *b, long long c); + +int +f4 (int x) +{ + #pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) + __extension__ __extension__ __extension__ + extern int f5 (int a, int *b, int c); + { + x++; + #pragma omp declare simd simdlen (4) linear (c) + extern int f6 (int a, int *b, int c); + } + return x; +} + +#pragma omp declare simd simdlen (16) +int +f7 (int x) +{ + #pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) + extern int f8 (int a, int *b, int c); + return x; +} + +int +f9 (int x) +{ + if (x) + #pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) + extern int f10 (int a, int *b, int c); + while (x < 10) + #pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) + extern int f11 (int a, int *b, int c); + return x; +} + +#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) +int f12 (int c; int *b; int a; int a, int *b, int c); + +#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) +int +f13 (int c; int *b; int a; int a, int *b, int c) +{ + return a + *b + c; +} + +#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) +int +f14 (a, b, c) + int a, c; + int *b; +{ + return a + *b + c; +} + +#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) +int +f15 (int a, int *b, int c) +{ + return a + *b + c; +} + +#pragma omp declare simd uniform (d) aligned (e : 8 * sizeof (int)) linear (f : 4) simdlen (8) +int f15 (int d, int *e, int f); diff --git a/gcc/testsuite/gcc.dg/gomp/declare-simd-2.c b/gcc/testsuite/gcc.dg/gomp/declare-simd-2.c new file mode 100644 index 0000000000000..118549be908dc --- /dev/null +++ b/gcc/testsuite/gcc.dg/gomp/declare-simd-2.c @@ -0,0 +1,24 @@ +/* Test parsing of #pragma omp declare simd */ +/* { dg-do compile } */ + +#pragma omp declare simd +int a; /* { dg-error "not immediately followed by a function declaration or definition" } */ + +#pragma omp declare simd +int fn1 (int a), fn2 (int a); /* { dg-error "not immediately followed by a single function declaration or definition" } */ + +#pragma omp declare simd +int b, fn3 (int a); /* { dg-error "not immediately followed by a function declaration or definition" } */ + +#pragma omp declare simd linear (a) +int fn4 (int a), c; /* { dg-error "not immediately followed by a function declaration or definition" } */ + +int t; + +#pragma omp declare simd +#pragma omp declare simd +#pragma omp threadprivate(t) /* { dg-error "must be followed by function declaration or definition or another" } */ +int fn5 (int a); + +#pragma omp declare simd inbranch notinbranch /* { dg-error "clause is incompatible with" } */ +int fn6 (int); diff --git a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.35.5.f90 b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.35.5.f90 index 083c0b3b7232e..a580a3baf663c 100644 --- a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.35.5.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.35.5.f90 @@ -6,7 +6,7 @@ SUBROUTINE WRONG5(N) !$OMP CRITICAL CALL WORK(N,1) ! incorrect nesting of barrier region in a critical region -!$OMP BARRIER +!$OMP BARRIER ! { dg-error "region may not be closely nested inside of" } CALL WORK(N,2) !$OMP END CRITICAL !$OMP END PARALLEL diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 4b91a35f17d46..4e18693250a18 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -593,6 +593,8 @@ make_edges (void) case GIMPLE_OMP_TASK: case GIMPLE_OMP_FOR: case GIMPLE_OMP_SINGLE: + case GIMPLE_OMP_TARGET: + case GIMPLE_OMP_TEAMS: case GIMPLE_OMP_MASTER: case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_CRITICAL: diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c index 10431c092371f..5bd7719516b33 100644 --- a/gcc/tree-data-ref.c +++ b/gcc/tree-data-ref.c @@ -4331,10 +4331,25 @@ get_references_in_stmt (gimple stmt, vec *references) /* ASM_EXPR and CALL_EXPR may embed arbitrary side effects. As we cannot model data-references to not spelled out accesses give up if they may occur. */ - if ((stmt_code == GIMPLE_CALL - && !(gimple_call_flags (stmt) & ECF_CONST)) - || (stmt_code == GIMPLE_ASM - && (gimple_asm_volatile_p (stmt) || gimple_vuse (stmt)))) + if (stmt_code == GIMPLE_CALL + && !(gimple_call_flags (stmt) & ECF_CONST)) + { + /* Allow IFN_GOMP_SIMD_LANE in their own loops. */ + if (gimple_call_internal_p (stmt) + && gimple_call_internal_fn (stmt) == IFN_GOMP_SIMD_LANE) + { + struct loop *loop = gimple_bb (stmt)->loop_father; + tree uid = gimple_call_arg (stmt, 0); + gcc_assert (TREE_CODE (uid) == SSA_NAME); + if (loop == NULL + || loop->simduid != SSA_NAME_VAR (uid)) + clobbers_memory = true; + } + else + clobbers_memory = true; + } + else if (stmt_code == GIMPLE_ASM + && (gimple_asm_volatile_p (stmt) || gimple_vuse (stmt))) clobbers_memory = true; if (!gimple_vuse (stmt)) diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h index caa8d7457fbf5..fe9ecee86d59a 100644 --- a/gcc/tree-flow.h +++ b/gcc/tree-flow.h @@ -344,7 +344,6 @@ extern struct omp_region *new_omp_region (basic_block, enum gimple_code, struct omp_region *); extern void free_omp_regions (void); void omp_expand_local (basic_block); -extern tree find_omp_clause (tree, enum omp_clause_code); tree copy_var_decl (tree, tree, tree); /*--------------------------------------------------------------------------- diff --git a/gcc/tree-if-conv.c b/gcc/tree-if-conv.c index 0ebb8c36cea7e..eb3a3fa78d3ea 100644 --- a/gcc/tree-if-conv.c +++ b/gcc/tree-if-conv.c @@ -1822,6 +1822,10 @@ main_tree_if_conversion (void) return 0; FOR_EACH_LOOP (li, loop, 0) + if (flag_tree_loop_if_convert == 1 + || flag_tree_loop_if_convert_stores == 1 + || flag_tree_vectorize + || loop->force_vect) changed |= tree_if_conversion (loop); if (changed) @@ -1848,7 +1852,8 @@ main_tree_if_conversion (void) static bool gate_tree_if_conversion (void) { - return ((flag_tree_vectorize && flag_tree_loop_if_convert != 0) + return (((flag_tree_vectorize || cfun->has_force_vect_loops) + && flag_tree_loop_if_convert != 0) || flag_tree_loop_if_convert == 1 || flag_tree_loop_if_convert_stores == 1); } diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index f5247716c952f..6ff3e03b49e31 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -1298,7 +1298,8 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id) case GIMPLE_OMP_FOR: s1 = remap_gimple_seq (gimple_omp_body (stmt), id); s2 = remap_gimple_seq (gimple_omp_for_pre_body (stmt), id); - copy = gimple_build_omp_for (s1, gimple_omp_for_clauses (stmt), + copy = gimple_build_omp_for (s1, gimple_omp_for_kind (stmt), + gimple_omp_for_clauses (stmt), gimple_omp_for_collapse (stmt), s2); { size_t i; @@ -1345,6 +1346,19 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id) (s1, gimple_omp_single_clauses (stmt)); break; + case GIMPLE_OMP_TARGET: + s1 = remap_gimple_seq (gimple_omp_body (stmt), id); + copy = gimple_build_omp_target + (s1, gimple_omp_target_kind (stmt), + gimple_omp_target_clauses (stmt)); + break; + + case GIMPLE_OMP_TEAMS: + s1 = remap_gimple_seq (gimple_omp_body (stmt), id); + copy = gimple_build_omp_teams + (s1, gimple_omp_teams_clauses (stmt)); + break; + case GIMPLE_OMP_CRITICAL: s1 = remap_gimple_seq (gimple_omp_body (stmt), id); copy @@ -2331,6 +2345,8 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency_scale, get_loop (src_cfun, 0)); /* Defer to cfgcleanup to update loop-father fields of basic-blocks. */ loops_state_set (LOOPS_NEED_FIXUP); + cfun->has_force_vect_loops |= src_cfun->has_force_vect_loops; + cfun->has_simduid_loops |= src_cfun->has_simduid_loops; } /* If the loop tree in the source function needed fixup, mark the @@ -3716,6 +3732,8 @@ estimate_num_insns (gimple stmt, eni_weights *weights) case GIMPLE_OMP_SECTION: case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SINGLE: + case GIMPLE_OMP_TARGET: + case GIMPLE_OMP_TEAMS: return (weights->omp_cost + estimate_num_insns_seq (gimple_omp_body (stmt), weights)); diff --git a/gcc/tree-nested.c b/gcc/tree-nested.c index fe44679a0132b..41548821acf0f 100644 --- a/gcc/tree-nested.c +++ b/gcc/tree-nested.c @@ -1291,6 +1291,22 @@ convert_nonlocal_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, info->suppress_expansion = save_suppress; break; + case GIMPLE_OMP_TARGET: + save_suppress = info->suppress_expansion; + convert_nonlocal_omp_clauses (gimple_omp_target_clauses_ptr (stmt), wi); + walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op, + info, gimple_omp_body_ptr (stmt)); + info->suppress_expansion = save_suppress; + break; + + case GIMPLE_OMP_TEAMS: + save_suppress = info->suppress_expansion; + convert_nonlocal_omp_clauses (gimple_omp_teams_clauses_ptr (stmt), wi); + walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op, + info, gimple_omp_body_ptr (stmt)); + info->suppress_expansion = save_suppress; + break; + case GIMPLE_OMP_SECTION: case GIMPLE_OMP_MASTER: case GIMPLE_OMP_ORDERED: @@ -1714,6 +1730,22 @@ convert_local_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, info->suppress_expansion = save_suppress; break; + case GIMPLE_OMP_TARGET: + save_suppress = info->suppress_expansion; + convert_local_omp_clauses (gimple_omp_target_clauses_ptr (stmt), wi); + walk_body (convert_local_reference_stmt, convert_local_reference_op, + info, gimple_omp_body_ptr (stmt)); + info->suppress_expansion = save_suppress; + break; + + case GIMPLE_OMP_TEAMS: + save_suppress = info->suppress_expansion; + convert_local_omp_clauses (gimple_omp_teams_clauses_ptr (stmt), wi); + walk_body (convert_local_reference_stmt, convert_local_reference_op, + info, gimple_omp_body_ptr (stmt)); + info->suppress_expansion = save_suppress; + break; + case GIMPLE_OMP_SECTION: case GIMPLE_OMP_MASTER: case GIMPLE_OMP_ORDERED: @@ -2071,6 +2103,8 @@ convert_gimple_call (gimple_stmt_iterator *gsi, bool *handled_ops_p, case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SECTION: case GIMPLE_OMP_SINGLE: + case GIMPLE_OMP_TARGET: + case GIMPLE_OMP_TEAMS: case GIMPLE_OMP_MASTER: case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_CRITICAL: diff --git a/gcc/tree-parloops.c b/gcc/tree-parloops.c index cea6f030c0ac8..1e6bb07b39813 100644 --- a/gcc/tree-parloops.c +++ b/gcc/tree-parloops.c @@ -1686,7 +1686,7 @@ create_parallel_loop (struct loop *loop, tree loop_fn, tree data, t = build_omp_clause (loc, OMP_CLAUSE_SCHEDULE); OMP_CLAUSE_SCHEDULE_KIND (t) = OMP_CLAUSE_SCHEDULE_STATIC; - for_stmt = gimple_build_omp_for (NULL, t, 1, NULL); + for_stmt = gimple_build_omp_for (NULL, GF_OMP_FOR_KIND_FOR, t, 1, NULL); gimple_set_location (for_stmt, loc); gimple_omp_for_set_index (for_stmt, 0, initvar); gimple_omp_for_set_initial (for_stmt, 0, cvar_init); diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 7745f73210bd8..cb49cf10a300a 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -314,11 +314,17 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags) case OMP_CLAUSE_COPYPRIVATE: name = "copyprivate"; goto print_remap; + case OMP_CLAUSE_UNIFORM: + name = "uniform"; + goto print_remap; + case OMP_CLAUSE__LOOPTEMP_: + name = "_looptemp_"; + goto print_remap; print_remap: pp_string (buffer, name); pp_character (buffer, '('); dump_generic_node (buffer, OMP_CLAUSE_DECL (clause), - spc, flags, false); + spc, flags, false); pp_character (buffer, ')'); break; @@ -327,21 +333,21 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags) pp_string (buffer, op_symbol_code (OMP_CLAUSE_REDUCTION_CODE (clause))); pp_character (buffer, ':'); dump_generic_node (buffer, OMP_CLAUSE_DECL (clause), - spc, flags, false); + spc, flags, false); pp_character (buffer, ')'); break; case OMP_CLAUSE_IF: pp_string (buffer, "if("); dump_generic_node (buffer, OMP_CLAUSE_IF_EXPR (clause), - spc, flags, false); + spc, flags, false); pp_character (buffer, ')'); break; case OMP_CLAUSE_NUM_THREADS: pp_string (buffer, "num_threads("); dump_generic_node (buffer, OMP_CLAUSE_NUM_THREADS_EXPR (clause), - spc, flags, false); + spc, flags, false); pp_character (buffer, ')'); break; @@ -380,30 +386,29 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags) pp_string (buffer, "schedule("); switch (OMP_CLAUSE_SCHEDULE_KIND (clause)) { - case OMP_CLAUSE_SCHEDULE_STATIC: - pp_string (buffer, "static"); - break; - case OMP_CLAUSE_SCHEDULE_DYNAMIC: - pp_string (buffer, "dynamic"); - break; - case OMP_CLAUSE_SCHEDULE_GUIDED: - pp_string (buffer, "guided"); - break; - case OMP_CLAUSE_SCHEDULE_RUNTIME: - pp_string (buffer, "runtime"); - break; - case OMP_CLAUSE_SCHEDULE_AUTO: - pp_string (buffer, "auto"); - break; - default: - gcc_unreachable (); + case OMP_CLAUSE_SCHEDULE_STATIC: + pp_string (buffer, "static"); + break; + case OMP_CLAUSE_SCHEDULE_DYNAMIC: + pp_string (buffer, "dynamic"); + break; + case OMP_CLAUSE_SCHEDULE_GUIDED: + pp_string (buffer, "guided"); + break; + case OMP_CLAUSE_SCHEDULE_RUNTIME: + pp_string (buffer, "runtime"); + break; + case OMP_CLAUSE_SCHEDULE_AUTO: + pp_string (buffer, "auto"); + break; + default: + gcc_unreachable (); } if (OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clause)) { pp_character (buffer, ','); - dump_generic_node (buffer, - OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clause), - spc, flags, false); + dump_generic_node (buffer, OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clause), + spc, flags, false); } pp_character (buffer, ')'); break; @@ -414,8 +419,7 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags) case OMP_CLAUSE_COLLAPSE: pp_string (buffer, "collapse("); - dump_generic_node (buffer, - OMP_CLAUSE_COLLAPSE_EXPR (clause), + dump_generic_node (buffer, OMP_CLAUSE_COLLAPSE_EXPR (clause), spc, flags, false); pp_character (buffer, ')'); break; @@ -423,7 +427,7 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags) case OMP_CLAUSE_FINAL: pp_string (buffer, "final("); dump_generic_node (buffer, OMP_CLAUSE_FINAL_EXPR (clause), - spc, flags, false); + spc, flags, false); pp_character (buffer, ')'); break; @@ -431,6 +435,192 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags) pp_string (buffer, "mergeable"); break; + case OMP_CLAUSE_LINEAR: + pp_string (buffer, "linear("); + dump_generic_node (buffer, OMP_CLAUSE_DECL (clause), + spc, flags, false); + pp_character (buffer, ':'); + dump_generic_node (buffer, OMP_CLAUSE_LINEAR_STEP (clause), + spc, flags, false); + pp_character (buffer, ')'); + break; + + case OMP_CLAUSE_ALIGNED: + pp_string (buffer, "aligned("); + dump_generic_node (buffer, OMP_CLAUSE_DECL (clause), + spc, flags, false); + if (OMP_CLAUSE_ALIGNED_ALIGNMENT (clause)) + { + pp_character (buffer, ':'); + dump_generic_node (buffer, OMP_CLAUSE_ALIGNED_ALIGNMENT (clause), + spc, flags, false); + } + pp_character (buffer, ')'); + break; + + case OMP_CLAUSE_DEPEND: + pp_string (buffer, "depend("); + switch (OMP_CLAUSE_DEPEND_KIND (clause)) + { + case OMP_CLAUSE_DEPEND_IN: + pp_string (buffer, "in"); + break; + case OMP_CLAUSE_DEPEND_OUT: + pp_string (buffer, "out"); + break; + case OMP_CLAUSE_DEPEND_INOUT: + pp_string (buffer, "inout"); + break; + default: + gcc_unreachable (); + } + pp_character (buffer, ':'); + dump_generic_node (buffer, OMP_CLAUSE_DECL (clause), + spc, flags, false); + pp_character (buffer, ')'); + break; + + case OMP_CLAUSE_MAP: + pp_string (buffer, "map("); + switch (OMP_CLAUSE_MAP_KIND (clause)) + { + case OMP_CLAUSE_MAP_ALLOC: + case OMP_CLAUSE_MAP_POINTER: + pp_string (buffer, "alloc"); + break; + case OMP_CLAUSE_MAP_TO: + pp_string (buffer, "to"); + break; + case OMP_CLAUSE_MAP_FROM: + pp_string (buffer, "from"); + break; + case OMP_CLAUSE_MAP_TOFROM: + pp_string (buffer, "tofrom"); + break; + default: + gcc_unreachable (); + } + pp_character (buffer, ':'); + dump_generic_node (buffer, OMP_CLAUSE_DECL (clause), + spc, flags, false); + print_clause_size: + if (OMP_CLAUSE_SIZE (clause)) + { + if (OMP_CLAUSE_MAP_KIND (clause) == OMP_CLAUSE_MAP_POINTER) + pp_string (buffer, " [pointer assign, bias: "); + else + pp_string (buffer, " [len: "); + dump_generic_node (buffer, OMP_CLAUSE_SIZE (clause), + spc, flags, false); + pp_character (buffer, ']'); + } + pp_character (buffer, ')'); + break; + + case OMP_CLAUSE_FROM: + pp_string (buffer, "from("); + dump_generic_node (buffer, OMP_CLAUSE_DECL (clause), + spc, flags, false); + goto print_clause_size; + + case OMP_CLAUSE_TO: + pp_string (buffer, "to("); + dump_generic_node (buffer, OMP_CLAUSE_DECL (clause), + spc, flags, false); + goto print_clause_size; + + case OMP_CLAUSE_NUM_TEAMS: + pp_string (buffer, "num_teams("); + dump_generic_node (buffer, OMP_CLAUSE_NUM_TEAMS_EXPR (clause), + spc, flags, false); + pp_character (buffer, ')'); + break; + + case OMP_CLAUSE_THREAD_LIMIT: + pp_string (buffer, "thread_limit("); + dump_generic_node (buffer, OMP_CLAUSE_THREAD_LIMIT_EXPR (clause), + spc, flags, false); + pp_character (buffer, ')'); + break; + + case OMP_CLAUSE_DEVICE: + pp_string (buffer, "device("); + dump_generic_node (buffer, OMP_CLAUSE_DEVICE_ID (clause), + spc, flags, false); + pp_character (buffer, ')'); + break; + + case OMP_CLAUSE_DIST_SCHEDULE: + pp_string (buffer, "dist_schedule(static"); + if (OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (clause)) + { + pp_character (buffer, ','); + dump_generic_node (buffer, + OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (clause), + spc, flags, false); + } + pp_character (buffer, ')'); + break; + + case OMP_CLAUSE_PROC_BIND: + pp_string (buffer, "proc_bind("); + switch (OMP_CLAUSE_PROC_BIND_KIND (clause)) + { + case OMP_CLAUSE_PROC_BIND_MASTER: + pp_string (buffer, "master"); + break; + case OMP_CLAUSE_PROC_BIND_CLOSE: + pp_string (buffer, "close"); + break; + case OMP_CLAUSE_PROC_BIND_SPREAD: + pp_string (buffer, "spread"); + break; + default: + gcc_unreachable (); + } + pp_character (buffer, ')'); + break; + + case OMP_CLAUSE_SAFELEN: + pp_string (buffer, "safelen("); + dump_generic_node (buffer, OMP_CLAUSE_SAFELEN_EXPR (clause), + spc, flags, false); + pp_character (buffer, ')'); + break; + + case OMP_CLAUSE_SIMDLEN: + pp_string (buffer, "simdlen("); + dump_generic_node (buffer, OMP_CLAUSE_SIMDLEN_EXPR (clause), + spc, flags, false); + pp_character (buffer, ')'); + break; + + case OMP_CLAUSE__SIMDUID_: + pp_string (buffer, "_simduid_("); + dump_generic_node (buffer, OMP_CLAUSE__SIMDUID__DECL (clause), + spc, flags, false); + pp_character (buffer, ')'); + break; + + case OMP_CLAUSE_INBRANCH: + pp_string (buffer, "inbranch"); + break; + case OMP_CLAUSE_NOTINBRANCH: + pp_string (buffer, "notinbranch"); + break; + case OMP_CLAUSE_FOR: + pp_string (buffer, "for"); + break; + case OMP_CLAUSE_PARALLEL: + pp_string (buffer, "parallel"); + break; + case OMP_CLAUSE_SECTIONS: + pp_string (buffer, "sections"); + break; + case OMP_CLAUSE_TASKGROUP: + pp_string (buffer, "taskgroup"); + break; + default: /* Should never happen. */ dump_generic_node (buffer, clause, spc, flags, false); @@ -2178,6 +2368,42 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, case OMP_FOR: pp_string (buffer, "#pragma omp for"); + goto dump_omp_loop; + + case OMP_SIMD: + pp_string (buffer, "#pragma omp simd"); + goto dump_omp_loop; + + case CILK_SIMD: + pp_string (buffer, "#pragma simd"); + goto dump_omp_loop; + + case OMP_DISTRIBUTE: + pp_string (buffer, "#pragma omp distribute"); + goto dump_omp_loop; + + case OMP_TEAMS: + pp_string (buffer, "#pragma omp teams"); + dump_omp_clauses (buffer, OMP_TEAMS_CLAUSES (node), spc, flags); + goto dump_omp_body; + + case OMP_TARGET_DATA: + pp_string (buffer, "#pragma omp target data"); + dump_omp_clauses (buffer, OMP_TARGET_DATA_CLAUSES (node), spc, flags); + goto dump_omp_body; + + case OMP_TARGET: + pp_string (buffer, "#pragma omp target"); + dump_omp_clauses (buffer, OMP_TARGET_CLAUSES (node), spc, flags); + goto dump_omp_body; + + case OMP_TARGET_UPDATE: + pp_string (buffer, "#pragma omp target update"); + dump_omp_clauses (buffer, OMP_TARGET_UPDATE_CLAUSES (node), spc, flags); + is_expr = false; + break; + + dump_omp_loop: dump_omp_clauses (buffer, OMP_FOR_CLAUSES (node), spc, flags); if (!(flags & TDF_SLIM)) @@ -2193,21 +2419,27 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, dump_generic_node (buffer, OMP_FOR_PRE_BODY (node), spc, flags, false); } - spc -= 2; - for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (node)); i++) + if (OMP_FOR_INIT (node)) { - spc += 2; - newline_and_indent (buffer, spc); - pp_string (buffer, "for ("); - dump_generic_node (buffer, TREE_VEC_ELT (OMP_FOR_INIT (node), i), - spc, flags, false); - pp_string (buffer, "; "); - dump_generic_node (buffer, TREE_VEC_ELT (OMP_FOR_COND (node), i), - spc, flags, false); - pp_string (buffer, "; "); - dump_generic_node (buffer, TREE_VEC_ELT (OMP_FOR_INCR (node), i), - spc, flags, false); - pp_string (buffer, ")"); + spc -= 2; + for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (node)); i++) + { + spc += 2; + newline_and_indent (buffer, spc); + pp_string (buffer, "for ("); + dump_generic_node (buffer, + TREE_VEC_ELT (OMP_FOR_INIT (node), i), + spc, flags, false); + pp_string (buffer, "; "); + dump_generic_node (buffer, + TREE_VEC_ELT (OMP_FOR_COND (node), i), + spc, flags, false); + pp_string (buffer, "; "); + dump_generic_node (buffer, + TREE_VEC_ELT (OMP_FOR_INCR (node), i), + spc, flags, false); + pp_string (buffer, ")"); + } } if (OMP_FOR_BODY (node)) { @@ -2219,7 +2451,8 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, newline_and_indent (buffer, spc + 2); pp_character (buffer, '}'); } - spc -= 2 * TREE_VEC_LENGTH (OMP_FOR_INIT (node)) - 2; + if (OMP_FOR_INIT (node)) + spc -= 2 * TREE_VEC_LENGTH (OMP_FOR_INIT (node)) - 2; if (OMP_FOR_PRE_BODY (node)) { spc -= 4; @@ -2261,6 +2494,8 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, case OMP_ATOMIC: pp_string (buffer, "#pragma omp atomic"); + if (OMP_ATOMIC_SEQ_CST (node)) + pp_string (buffer, " seq_cst"); newline_and_indent (buffer, spc + 2); dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); pp_space (buffer); @@ -2271,6 +2506,8 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, case OMP_ATOMIC_READ: pp_string (buffer, "#pragma omp atomic read"); + if (OMP_ATOMIC_SEQ_CST (node)) + pp_string (buffer, " seq_cst"); newline_and_indent (buffer, spc + 2); dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); pp_space (buffer); @@ -2279,6 +2516,8 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, case OMP_ATOMIC_CAPTURE_OLD: case OMP_ATOMIC_CAPTURE_NEW: pp_string (buffer, "#pragma omp atomic capture"); + if (OMP_ATOMIC_SEQ_CST (node)) + pp_string (buffer, " seq_cst"); newline_and_indent (buffer, spc + 2); dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); pp_space (buffer); diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index 2ecd13915bc87..4da9f7db29697 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -1513,6 +1513,7 @@ ref_maybe_used_by_call_p_1 (gimple call, ao_ref *ref) case BUILT_IN_GOMP_ATOMIC_END: case BUILT_IN_GOMP_BARRIER: case BUILT_IN_GOMP_TASKWAIT: + case BUILT_IN_GOMP_TASKGROUP_END: case BUILT_IN_GOMP_CRITICAL_START: case BUILT_IN_GOMP_CRITICAL_END: case BUILT_IN_GOMP_CRITICAL_NAME_START: @@ -1520,7 +1521,6 @@ ref_maybe_used_by_call_p_1 (gimple call, ao_ref *ref) case BUILT_IN_GOMP_LOOP_END: case BUILT_IN_GOMP_ORDERED_START: case BUILT_IN_GOMP_ORDERED_END: - case BUILT_IN_GOMP_PARALLEL_END: case BUILT_IN_GOMP_SECTIONS_END: case BUILT_IN_GOMP_SINGLE_COPY_START: case BUILT_IN_GOMP_SINGLE_COPY_END: @@ -1857,6 +1857,7 @@ call_may_clobber_ref_p_1 (gimple call, ao_ref *ref) case BUILT_IN_GOMP_ATOMIC_END: case BUILT_IN_GOMP_BARRIER: case BUILT_IN_GOMP_TASKWAIT: + case BUILT_IN_GOMP_TASKGROUP_END: case BUILT_IN_GOMP_CRITICAL_START: case BUILT_IN_GOMP_CRITICAL_END: case BUILT_IN_GOMP_CRITICAL_NAME_START: @@ -1864,7 +1865,6 @@ call_may_clobber_ref_p_1 (gimple call, ao_ref *ref) case BUILT_IN_GOMP_LOOP_END: case BUILT_IN_GOMP_ORDERED_START: case BUILT_IN_GOMP_ORDERED_END: - case BUILT_IN_GOMP_PARALLEL_END: case BUILT_IN_GOMP_SECTIONS_END: case BUILT_IN_GOMP_SINGLE_COPY_START: case BUILT_IN_GOMP_SINGLE_COPY_END: diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index 1bc4c2fb7b5d7..7f66bdaf54f62 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -626,6 +626,22 @@ likely_value (gimple stmt) if (has_constant_operand) all_undefined_operands = false; + if (has_undefined_operand + && code == GIMPLE_CALL + && gimple_call_internal_p (stmt)) + switch (gimple_call_internal_fn (stmt)) + { + /* These 3 builtins use the first argument just as a magic + way how to find out a decl uid. */ + case IFN_GOMP_SIMD_LANE: + case IFN_GOMP_SIMD_VF: + case IFN_GOMP_SIMD_LAST_LANE: + has_undefined_operand = false; + break; + default: + break; + } + /* If the operation combines operands like COMPLEX_EXPR make sure to not mark the result UNDEFINED if only one part of the result is undefined. */ diff --git a/gcc/tree-ssa-loop-ivcanon.c b/gcc/tree-ssa-loop-ivcanon.c index 91cf8c16a3234..abe455754a98c 100644 --- a/gcc/tree-ssa-loop-ivcanon.c +++ b/gcc/tree-ssa-loop-ivcanon.c @@ -1125,6 +1125,11 @@ tree_unroll_loops_completely_1 (bool may_increase_size, bool unroll_outer, if (changed) return true; + /* Don't unroll #pragma omp simd loops until the vectorizer + attempts to vectorize those. */ + if (loop->force_vect) + return false; + /* Try to unroll this loop. */ loop_father = loop_outer (loop); if (!loop_father) diff --git a/gcc/tree-ssa-loop.c b/gcc/tree-ssa-loop.c index 99e27a1359a60..2160318c47ce6 100644 --- a/gcc/tree-ssa-loop.c +++ b/gcc/tree-ssa-loop.c @@ -225,7 +225,7 @@ tree_vectorize (void) static bool gate_tree_vectorize (void) { - return flag_tree_vectorize; + return flag_tree_vectorize || cfun->has_force_vect_loops; } struct gimple_opt_pass pass_vectorize = diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c index 47ecad3528dc1..f6e21315ed5a4 100644 --- a/gcc/tree-vect-data-refs.c +++ b/gcc/tree-vect-data-refs.c @@ -255,6 +255,15 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr, /* Unknown data dependence. */ if (DDR_ARE_DEPENDENT (ddr) == chrec_dont_know) { + /* If user asserted safelen consecutive iterations can be + executed concurrently, assume independence. */ + if (loop->safelen >= 2) + { + if (loop->safelen < *max_vf) + *max_vf = loop->safelen; + return false; + } + if (STMT_VINFO_GATHER_P (stmtinfo_a) || STMT_VINFO_GATHER_P (stmtinfo_b)) { @@ -291,6 +300,15 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr, /* Known data dependence. */ if (DDR_NUM_DIST_VECTS (ddr) == 0) { + /* If user asserted safelen consecutive iterations can be + executed concurrently, assume independence. */ + if (loop->safelen >= 2) + { + if (loop->safelen < *max_vf) + *max_vf = loop->safelen; + return false; + } + if (STMT_VINFO_GATHER_P (stmtinfo_a) || STMT_VINFO_GATHER_P (stmtinfo_b)) { @@ -2859,6 +2877,7 @@ vect_analyze_data_refs (loop_vec_info loop_vinfo, stmt_vec_info stmt_info; tree base, offset, init; bool gather = false; + bool simd_lane_access = false; int vf; again: @@ -2890,12 +2909,17 @@ vect_analyze_data_refs (loop_vec_info loop_vinfo, if (!DR_BASE_ADDRESS (dr) || !DR_OFFSET (dr) || !DR_INIT (dr) || !DR_STEP (dr)) { - /* If target supports vector gather loads, see if they can't - be used. */ - if (loop_vinfo - && DR_IS_READ (dr) + bool maybe_gather + = DR_IS_READ (dr) && !TREE_THIS_VOLATILE (DR_REF (dr)) - && targetm.vectorize.builtin_gather != NULL + && targetm.vectorize.builtin_gather != NULL; + bool maybe_simd_lane_access + = loop_vinfo && loop->simduid; + + /* If target supports vector gather loads, or if this might be + a SIMD lane access, see if they can't be used. */ + if (loop_vinfo + && (maybe_gather || maybe_simd_lane_access) && !nested_in_vect_loop_p (loop, stmt)) { struct data_reference *newdr @@ -2908,14 +2932,59 @@ vect_analyze_data_refs (loop_vec_info loop_vinfo, && DR_STEP (newdr) && integer_zerop (DR_STEP (newdr))) { - dr = newdr; - gather = true; + if (maybe_simd_lane_access) + { + tree off = DR_OFFSET (newdr); + STRIP_NOPS (off); + if (TREE_CODE (DR_INIT (newdr)) == INTEGER_CST + && TREE_CODE (off) == MULT_EXPR + && host_integerp (TREE_OPERAND (off, 1), 1)) + { + tree step = TREE_OPERAND (off, 1); + off = TREE_OPERAND (off, 0); + STRIP_NOPS (off); + if (CONVERT_EXPR_P (off) + && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (off, + 0))) + < TYPE_PRECISION (TREE_TYPE (off))) + off = TREE_OPERAND (off, 0); + if (TREE_CODE (off) == SSA_NAME) + { + gimple def = SSA_NAME_DEF_STMT (off); + tree reft = TREE_TYPE (DR_REF (newdr)); + if (gimple_call_internal_p (def) + && gimple_call_internal_fn (def) + == IFN_GOMP_SIMD_LANE) + { + tree arg = gimple_call_arg (def, 0); + gcc_assert (TREE_CODE (arg) == SSA_NAME); + arg = SSA_NAME_VAR (arg); + if (arg == loop->simduid + /* For now. */ + && tree_int_cst_equal + (TYPE_SIZE_UNIT (reft), + step)) + { + DR_OFFSET (newdr) = ssize_int (0); + DR_STEP (newdr) = step; + dr = newdr; + simd_lane_access = true; + } + } + } + } + } + if (!simd_lane_access && maybe_gather) + { + dr = newdr; + gather = true; + } } - else + if (!gather && !simd_lane_access) free_data_ref (newdr); } - if (!gather) + if (!gather && !simd_lane_access) { if (dump_enabled_p ()) { @@ -2942,7 +3011,7 @@ vect_analyze_data_refs (loop_vec_info loop_vinfo, if (bb_vinfo) break; - if (gather) + if (gather || simd_lane_access) free_data_ref (dr); return false; } @@ -2975,7 +3044,7 @@ vect_analyze_data_refs (loop_vec_info loop_vinfo, if (bb_vinfo) break; - if (gather) + if (gather || simd_lane_access) free_data_ref (dr); return false; } @@ -2994,7 +3063,7 @@ vect_analyze_data_refs (loop_vec_info loop_vinfo, if (bb_vinfo) break; - if (gather) + if (gather || simd_lane_access) free_data_ref (dr); return false; } @@ -3015,7 +3084,7 @@ vect_analyze_data_refs (loop_vec_info loop_vinfo, if (bb_vinfo) break; - if (gather) + if (gather || simd_lane_access) free_data_ref (dr); return false; } @@ -3150,12 +3219,17 @@ vect_analyze_data_refs (loop_vec_info loop_vinfo, if (bb_vinfo) break; - if (gather) + if (gather || simd_lane_access) free_data_ref (dr); return false; } STMT_VINFO_DATA_REF (stmt_info) = dr; + if (simd_lane_access) + { + STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) = true; + datarefs[i] = dr; + } /* Set vectype for STMT. */ scalar_type = TREE_TYPE (DR_REF (dr)); @@ -3176,7 +3250,7 @@ vect_analyze_data_refs (loop_vec_info loop_vinfo, if (bb_vinfo) break; - if (gather) + if (gather || simd_lane_access) { STMT_VINFO_DATA_REF (stmt_info) = NULL; free_data_ref (dr); diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index c9b102132578f..3346dbf84333a 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -5361,7 +5361,7 @@ vectorizable_induction (gimple phi, gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED, bool vectorizable_live_operation (gimple stmt, gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED, - gimple *vec_stmt ATTRIBUTE_UNUSED) + gimple *vec_stmt) { stmt_vec_info stmt_info = vinfo_for_stmt (stmt); loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info); @@ -5381,7 +5381,41 @@ vectorizable_live_operation (gimple stmt, return false; if (!is_gimple_assign (stmt)) - return false; + { + if (gimple_call_internal_p (stmt) + && gimple_call_internal_fn (stmt) == IFN_GOMP_SIMD_LANE + && gimple_call_lhs (stmt) + && loop->simduid + && TREE_CODE (gimple_call_arg (stmt, 0)) == SSA_NAME + && loop->simduid + == SSA_NAME_VAR (gimple_call_arg (stmt, 0))) + { + edge e = single_exit (loop); + basic_block merge_bb = e->dest; + imm_use_iterator imm_iter; + use_operand_p use_p; + tree lhs = gimple_call_lhs (stmt); + + FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs) + { + gimple use_stmt = USE_STMT (use_p); + if (gimple_code (use_stmt) == GIMPLE_PHI + || gimple_bb (use_stmt) == merge_bb) + { + if (vec_stmt) + { + tree vfm1 + = build_int_cst (unsigned_type_node, + loop_vinfo->vectorization_factor - 1); + SET_PHI_ARG_DEF (use_stmt, e->dest_idx, vfm1); + } + return true; + } + } + } + + return false; + } if (TREE_CODE (gimple_assign_lhs (stmt)) != SSA_NAME) return false; diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index 0580f7dfadca4..3768dcd114bc0 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -1755,6 +1755,14 @@ vectorizable_call (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, if (nargs == 0 || nargs > 3) return false; + /* Ignore the argument of IFN_GOMP_SIMD_LANE, it is magic. */ + if (gimple_call_internal_p (stmt) + && gimple_call_internal_fn (stmt) == IFN_GOMP_SIMD_LANE) + { + nargs = 0; + rhs_type = unsigned_type_node; + } + for (i = 0; i < nargs; i++) { tree opvectype; @@ -1830,11 +1838,26 @@ vectorizable_call (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, fndecl = vectorizable_function (stmt, vectype_out, vectype_in); if (fndecl == NULL_TREE) { - if (dump_enabled_p ()) - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, - "function is not vectorizable."); - - return false; + if (gimple_call_internal_p (stmt) + && gimple_call_internal_fn (stmt) == IFN_GOMP_SIMD_LANE + && !slp_node + && loop_vinfo + && LOOP_VINFO_LOOP (loop_vinfo)->simduid + && TREE_CODE (gimple_call_arg (stmt, 0)) == SSA_NAME + && LOOP_VINFO_LOOP (loop_vinfo)->simduid + == SSA_NAME_VAR (gimple_call_arg (stmt, 0))) + { + /* We can handle IFN_GOMP_SIMD_LANE by returning a + { 0, 1, 2, ... vf - 1 } vector. */ + gcc_assert (nargs == 0); + } + else + { + if (dump_enabled_p ()) + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, + "function is not vectorizable."); + return false; + } } gcc_assert (!gimple_vuse (stmt)); @@ -1932,9 +1955,30 @@ vectorizable_call (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, vargs.quick_push (vec_oprnd0); } - new_stmt = gimple_build_call_vec (fndecl, vargs); - new_temp = make_ssa_name (vec_dest, new_stmt); - gimple_call_set_lhs (new_stmt, new_temp); + if (gimple_call_internal_p (stmt) + && gimple_call_internal_fn (stmt) == IFN_GOMP_SIMD_LANE) + { + tree *v = XALLOCAVEC (tree, nunits_out); + int k; + for (k = 0; k < nunits_out; ++k) + v[k] = build_int_cst (unsigned_type_node, j * nunits_out + k); + tree cst = build_vector (vectype_out, v); + tree new_var + = vect_get_new_vect_var (vectype_out, vect_simple_var, "cst_"); + gimple init_stmt = gimple_build_assign (new_var, cst); + new_temp = make_ssa_name (new_var, init_stmt); + gimple_assign_set_lhs (init_stmt, new_temp); + vect_init_vector_1 (stmt, init_stmt, NULL); + new_temp = make_ssa_name (vec_dest, NULL); + new_stmt = gimple_build_assign (new_temp, + gimple_assign_lhs (init_stmt)); + } + else + { + new_stmt = gimple_build_call_vec (fndecl, vargs); + new_temp = make_ssa_name (vec_dest, new_stmt); + gimple_call_set_lhs (new_stmt, new_temp); + } vect_finish_stmt_generation (stmt, new_stmt, gsi); if (j == 0) @@ -3796,6 +3840,7 @@ vectorizable_store (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, enum vect_def_type dt; stmt_vec_info prev_stmt_info = NULL; tree dataref_ptr = NULL_TREE; + tree dataref_offset = NULL_TREE; gimple ptr_incr = NULL; int nunits = TYPE_VECTOR_SUBPARTS (vectype); int ncopies; @@ -4085,9 +4130,26 @@ vectorizable_store (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, /* We should have catched mismatched types earlier. */ gcc_assert (useless_type_conversion_p (vectype, TREE_TYPE (vec_oprnd))); - dataref_ptr = vect_create_data_ref_ptr (first_stmt, aggr_type, NULL, - NULL_TREE, &dummy, gsi, - &ptr_incr, false, &inv_p); + bool simd_lane_access_p + = STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info); + if (simd_lane_access_p + && TREE_CODE (DR_BASE_ADDRESS (first_dr)) == ADDR_EXPR + && VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (first_dr), 0)) + && integer_zerop (DR_OFFSET (first_dr)) + && integer_zerop (DR_INIT (first_dr)) + && alias_sets_conflict_p (get_alias_set (aggr_type), + get_alias_set (DR_REF (first_dr)))) + { + dataref_ptr = unshare_expr (DR_BASE_ADDRESS (first_dr)); + dataref_offset = build_int_cst (reference_alias_ptr_type + (DR_REF (first_dr)), 0); + } + else + dataref_ptr + = vect_create_data_ref_ptr (first_stmt, aggr_type, + simd_lane_access_p ? loop : NULL, + NULL_TREE, &dummy, gsi, &ptr_incr, + simd_lane_access_p, &inv_p); gcc_assert (bb_vinfo || !inv_p); } else @@ -4108,8 +4170,13 @@ vectorizable_store (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, dr_chain[i] = vec_oprnd; oprnds[i] = vec_oprnd; } - dataref_ptr = bump_vector_ptr (dataref_ptr, ptr_incr, gsi, stmt, - TYPE_SIZE_UNIT (aggr_type)); + if (dataref_offset) + dataref_offset + = int_const_binop (PLUS_EXPR, dataref_offset, + TYPE_SIZE_UNIT (aggr_type)); + else + dataref_ptr = bump_vector_ptr (dataref_ptr, ptr_incr, gsi, stmt, + TYPE_SIZE_UNIT (aggr_type)); } if (store_lanes_p) @@ -4161,8 +4228,10 @@ vectorizable_store (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, vec_oprnd = result_chain[i]; data_ref = build2 (MEM_REF, TREE_TYPE (vec_oprnd), dataref_ptr, - build_int_cst (reference_alias_ptr_type - (DR_REF (first_dr)), 0)); + dataref_offset + ? dataref_offset + : build_int_cst (reference_alias_ptr_type + (DR_REF (first_dr)), 0)); align = TYPE_ALIGN_UNIT (vectype); if (aligned_access_p (first_dr)) misalign = 0; @@ -4181,8 +4250,9 @@ vectorizable_store (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, TYPE_ALIGN (elem_type)); misalign = DR_MISALIGNMENT (first_dr); } - set_ptr_info_alignment (get_ptr_info (dataref_ptr), align, - misalign); + if (dataref_offset == NULL_TREE) + set_ptr_info_alignment (get_ptr_info (dataref_ptr), align, + misalign); /* Arguments are ready. Create the new vector stmt. */ new_stmt = gimple_build_assign (data_ref, vec_oprnd); @@ -4314,6 +4384,7 @@ vectorizable_load (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, tree dummy; enum dr_alignment_support alignment_support_scheme; tree dataref_ptr = NULL_TREE; + tree dataref_offset = NULL_TREE; gimple ptr_incr = NULL; int nunits = TYPE_VECTOR_SUBPARTS (vectype); int ncopies; @@ -4947,9 +5018,32 @@ vectorizable_load (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, { /* 1. Create the vector or array pointer update chain. */ if (j == 0) - dataref_ptr = vect_create_data_ref_ptr (first_stmt, aggr_type, at_loop, - offset, &dummy, gsi, - &ptr_incr, false, &inv_p); + { + bool simd_lane_access_p + = STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info); + if (simd_lane_access_p + && TREE_CODE (DR_BASE_ADDRESS (first_dr)) == ADDR_EXPR + && VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (first_dr), 0)) + && integer_zerop (DR_OFFSET (first_dr)) + && integer_zerop (DR_INIT (first_dr)) + && alias_sets_conflict_p (get_alias_set (aggr_type), + get_alias_set (DR_REF (first_dr))) + && (alignment_support_scheme == dr_aligned + || alignment_support_scheme == dr_unaligned_supported)) + { + dataref_ptr = unshare_expr (DR_BASE_ADDRESS (first_dr)); + dataref_offset = build_int_cst (reference_alias_ptr_type + (DR_REF (first_dr)), 0); + } + else + dataref_ptr + = vect_create_data_ref_ptr (first_stmt, aggr_type, at_loop, + offset, &dummy, gsi, &ptr_incr, + simd_lane_access_p, &inv_p); + } + else if (dataref_offset) + dataref_offset = int_const_binop (PLUS_EXPR, dataref_offset, + TYPE_SIZE_UNIT (aggr_type)); else dataref_ptr = bump_vector_ptr (dataref_ptr, ptr_incr, gsi, stmt, TYPE_SIZE_UNIT (aggr_type)); @@ -4999,8 +5093,10 @@ vectorizable_load (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, data_ref = build2 (MEM_REF, vectype, dataref_ptr, - build_int_cst (reference_alias_ptr_type - (DR_REF (first_dr)), 0)); + dataref_offset + ? dataref_offset + : build_int_cst (reference_alias_ptr_type + (DR_REF (first_dr)), 0)); align = TYPE_ALIGN_UNIT (vectype); if (alignment_support_scheme == dr_aligned) { @@ -5022,8 +5118,9 @@ vectorizable_load (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, TYPE_ALIGN (elem_type)); misalign = DR_MISALIGNMENT (first_dr); } - set_ptr_info_alignment (get_ptr_info (dataref_ptr), - align, misalign); + if (dataref_offset == NULL_TREE) + set_ptr_info_alignment (get_ptr_info (dataref_ptr), + align, misalign); break; } case dr_explicit_realign: diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c index 1ef31eefd1d16..6de914f73f285 100644 --- a/gcc/tree-vectorizer.c +++ b/gcc/tree-vectorizer.c @@ -66,13 +66,209 @@ along with GCC; see the file COPYING3. If not see #include "cfgloop.h" #include "tree-vectorizer.h" #include "tree-pass.h" +#include "hash-table.h" +#include "tree-ssa-propagate.h" /* Loop or bb location. */ LOC vect_location; /* Vector mapping GIMPLE stmt to stmt_vec_info. */ vec stmt_vec_info_vec; + +/* For mapping simduid to vectorization factor. */ + +struct simduid_to_vf : typed_free_remove +{ + unsigned int simduid; + int vf; + + /* hash_table support. */ + typedef simduid_to_vf value_type; + typedef simduid_to_vf compare_type; + static inline hashval_t hash (const value_type *); + static inline int equal (const value_type *, const compare_type *); +}; + +inline hashval_t +simduid_to_vf::hash (const value_type *p) +{ + return p->simduid; +} + +inline int +simduid_to_vf::equal (const value_type *p1, const value_type *p2) +{ + return p1->simduid == p2->simduid; +} + +/* For mapping decl to simduid. */ + +struct decl_to_simduid : typed_free_remove +{ + tree decl; + unsigned int simduid; + + /* hash_table support. */ + typedef decl_to_simduid value_type; + typedef decl_to_simduid compare_type; + static inline hashval_t hash (const value_type *); + static inline int equal (const value_type *, const compare_type *); +}; + +inline hashval_t +decl_to_simduid::hash (const value_type *p) +{ + return DECL_UID (p->decl); +} + +inline int +decl_to_simduid::equal (const value_type *p1, const value_type *p2) +{ + return p1->decl == p2->decl; +} + +/* Fold IFN_GOMP_SIMD_LANE, IFN_GOMP_SIMD_VF and IFN_GOMP_SIMD_LAST_LANE + into their corresponding constants. */ + +static void +adjust_simduid_builtins (hash_table &htab) +{ + basic_block bb; + + FOR_EACH_BB (bb) + { + gimple_stmt_iterator i; + + for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i)) + { + unsigned int vf = 1; + enum internal_fn ifn; + gimple stmt = gsi_stmt (i); + tree t; + if (!is_gimple_call (stmt) + || !gimple_call_internal_p (stmt)) + continue; + ifn = gimple_call_internal_fn (stmt); + switch (ifn) + { + case IFN_GOMP_SIMD_LANE: + case IFN_GOMP_SIMD_VF: + case IFN_GOMP_SIMD_LAST_LANE: + break; + default: + continue; + } + tree arg = gimple_call_arg (stmt, 0); + gcc_assert (arg != NULL_TREE); + gcc_assert (TREE_CODE (arg) == SSA_NAME); + simduid_to_vf *p = NULL, data; + data.simduid = DECL_UID (SSA_NAME_VAR (arg)); + if (htab.is_created ()) + p = htab.find (&data); + if (p) + vf = p->vf; + switch (ifn) + { + case IFN_GOMP_SIMD_VF: + t = build_int_cst (unsigned_type_node, vf); + break; + case IFN_GOMP_SIMD_LANE: + t = build_int_cst (unsigned_type_node, 0); + break; + case IFN_GOMP_SIMD_LAST_LANE: + t = gimple_call_arg (stmt, 1); + break; + default: + gcc_unreachable (); + } + update_call_from_tree (&i, t); + } + } +} +/* Helper structure for note_simd_array_uses. */ + +struct note_simd_array_uses_struct +{ + hash_table *htab; + unsigned int simduid; +}; + +/* Callback for note_simd_array_uses, called through walk_gimple_op. */ + +static tree +note_simd_array_uses_cb (tree *tp, int *walk_subtrees, void *data) +{ + struct walk_stmt_info *wi = (struct walk_stmt_info *) data; + struct note_simd_array_uses_struct *ns + = (struct note_simd_array_uses_struct *) wi->info; + + if (TYPE_P (*tp)) + *walk_subtrees = 0; + else if (VAR_P (*tp) + && lookup_attribute ("omp simd array", DECL_ATTRIBUTES (*tp)) + && DECL_CONTEXT (*tp) == current_function_decl) + { + decl_to_simduid data; + if (!ns->htab->is_created ()) + ns->htab->create (15); + data.decl = *tp; + data.simduid = ns->simduid; + decl_to_simduid **slot = ns->htab->find_slot (&data, INSERT); + if (*slot == NULL) + { + decl_to_simduid *p = XNEW (decl_to_simduid); + *p = data; + *slot = p; + } + else if ((*slot)->simduid != ns->simduid) + (*slot)->simduid = -1U; + *walk_subtrees = 0; + } + return NULL_TREE; +} + +/* Find "omp simd array" temporaries and map them to corresponding + simduid. */ + +static void +note_simd_array_uses (hash_table *htab) +{ + basic_block bb; + gimple_stmt_iterator gsi; + struct walk_stmt_info wi; + struct note_simd_array_uses_struct ns; + + memset (&wi, 0, sizeof (wi)); + wi.info = &ns; + ns.htab = htab; + + FOR_EACH_BB (bb) + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple stmt = gsi_stmt (gsi); + if (!is_gimple_call (stmt) || !gimple_call_internal_p (stmt)) + continue; + switch (gimple_call_internal_fn (stmt)) + { + case IFN_GOMP_SIMD_LANE: + case IFN_GOMP_SIMD_VF: + case IFN_GOMP_SIMD_LAST_LANE: + break; + default: + continue; + } + tree lhs = gimple_call_lhs (stmt); + if (lhs == NULL_TREE) + continue; + imm_use_iterator use_iter; + gimple use_stmt; + ns.simduid = DECL_UID (SSA_NAME_VAR (gimple_call_arg (stmt, 0))); + FOR_EACH_IMM_USE_STMT (use_stmt, use_iter, lhs) + if (!is_gimple_debug (use_stmt)) + walk_gimple_op (use_stmt, note_simd_array_uses_cb, &wi); + } +} /* Function vectorize_loops. @@ -86,12 +282,21 @@ vectorize_loops (void) unsigned int vect_loops_num; loop_iterator li; struct loop *loop; + hash_table simduid_to_vf_htab; + hash_table decl_to_simduid_htab; vect_loops_num = number_of_loops (cfun); /* Bail out if there are no loops. */ if (vect_loops_num <= 1) - return 0; + { + if (cfun->has_simduid_loops) + adjust_simduid_builtins (simduid_to_vf_htab); + return 0; + } + + if (cfun->has_simduid_loops) + note_simd_array_uses (&decl_to_simduid_htab); init_stmt_vec_info_vec (); @@ -101,7 +306,8 @@ vectorize_loops (void) than all previously defined loops. This fact allows us to run only over initial loops skipping newly generated ones. */ FOR_EACH_LOOP (li, loop, 0) - if (optimize_loop_nest_for_speed_p (loop)) + if ((flag_tree_vectorize && optimize_loop_nest_for_speed_p (loop)) + || loop->force_vect) { loop_vec_info loop_vinfo; vect_location = find_loop_location (loop); @@ -122,6 +328,20 @@ vectorize_loops (void) "Vectorized loop\n"); vect_transform_loop (loop_vinfo); num_vectorized_loops++; + /* Now that the loop has been vectorized, allow it to be unrolled + etc. */ + loop->force_vect = false; + + if (loop->simduid) + { + simduid_to_vf *simduid_to_vf_data = XNEW (simduid_to_vf); + if (!simduid_to_vf_htab.is_created ()) + simduid_to_vf_htab.create (15); + simduid_to_vf_data->simduid = DECL_UID (loop->simduid); + simduid_to_vf_data->vf = loop_vinfo->vectorization_factor; + *simduid_to_vf_htab.find_slot (simduid_to_vf_data, INSERT) + = simduid_to_vf_data; + } } vect_location = UNKNOWN_LOC; @@ -149,6 +369,40 @@ vectorize_loops (void) free_stmt_vec_info_vec (); + /* Fold IFN_GOMP_SIMD_{VF,LANE,LAST_LANE} builtins. */ + if (cfun->has_simduid_loops) + adjust_simduid_builtins (simduid_to_vf_htab); + + /* Shrink any "omp array simd" temporary arrays to the + actual vectorization factors. */ + if (decl_to_simduid_htab.is_created ()) + { + for (hash_table ::iterator iter + = decl_to_simduid_htab.begin (); + iter != decl_to_simduid_htab.end (); ++iter) + if ((*iter).simduid != -1U) + { + tree decl = (*iter).decl; + int vf = 1; + if (simduid_to_vf_htab.is_created ()) + { + simduid_to_vf *p = NULL, data; + data.simduid = (*iter).simduid; + p = simduid_to_vf_htab.find (&data); + if (p) + vf = p->vf; + } + tree atype + = build_array_type_nelts (TREE_TYPE (TREE_TYPE (decl)), vf); + TREE_TYPE (decl) = atype; + relayout_decl (decl); + } + + decl_to_simduid_htab.dispose (); + } + if (simduid_to_vf_htab.is_created ()) + simduid_to_vf_htab.dispose (); + if (num_vectorized_loops > 0) { /* If we vectorized any loop only virtual SSA form needs to be updated. diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index 7c5dfe884dfb6..3570dc9d76adb 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -576,6 +576,9 @@ typedef struct _stmt_vec_info { /* For loads only, true if this is a gather load. */ bool gather_p; bool stride_load_p; + + /* For both loads and stores. */ + bool simd_lane_access_p; } *stmt_vec_info; /* Access Functions. */ @@ -591,6 +594,7 @@ typedef struct _stmt_vec_info { #define STMT_VINFO_DATA_REF(S) (S)->data_ref_info #define STMT_VINFO_GATHER_P(S) (S)->gather_p #define STMT_VINFO_STRIDE_LOAD_P(S) (S)->stride_load_p +#define STMT_VINFO_SIMD_LANE_ACCESS_P(S) (S)->simd_lane_access_p #define STMT_VINFO_DR_BASE_ADDRESS(S) (S)->dr_base_address #define STMT_VINFO_DR_INIT(S) (S)->dr_init diff --git a/gcc/tree.c b/gcc/tree.c index ab1173525c713..69d7a0897cb53 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -236,6 +236,14 @@ unsigned const char omp_clause_num_ops[] = 4, /* OMP_CLAUSE_REDUCTION */ 1, /* OMP_CLAUSE_COPYIN */ 1, /* OMP_CLAUSE_COPYPRIVATE */ + 2, /* OMP_CLAUSE_LINEAR */ + 2, /* OMP_CLAUSE_ALIGNED */ + 1, /* OMP_CLAUSE_DEPEND */ + 1, /* OMP_CLAUSE_UNIFORM */ + 2, /* OMP_CLAUSE_FROM */ + 2, /* OMP_CLAUSE_TO */ + 2, /* OMP_CLAUSE_MAP */ + 1, /* OMP_CLAUSE__LOOPTEMP_ */ 1, /* OMP_CLAUSE_IF */ 1, /* OMP_CLAUSE_NUM_THREADS */ 1, /* OMP_CLAUSE_SCHEDULE */ @@ -245,7 +253,21 @@ unsigned const char omp_clause_num_ops[] = 3, /* OMP_CLAUSE_COLLAPSE */ 0, /* OMP_CLAUSE_UNTIED */ 1, /* OMP_CLAUSE_FINAL */ - 0 /* OMP_CLAUSE_MERGEABLE */ + 0, /* OMP_CLAUSE_MERGEABLE */ + 1, /* OMP_CLAUSE_DEVICE */ + 1, /* OMP_CLAUSE_DIST_SCHEDULE */ + 0, /* OMP_CLAUSE_INBRANCH */ + 0, /* OMP_CLAUSE_NOTINBRANCH */ + 1, /* OMP_CLAUSE_NUM_TEAMS */ + 1, /* OMP_CLAUSE_THREAD_LIMIT */ + 0, /* OMP_CLAUSE_PROC_BIND */ + 1, /* OMP_CLAUSE_SAFELEN */ + 1, /* OMP_CLAUSE_SIMDLEN */ + 0, /* OMP_CLAUSE_FOR */ + 0, /* OMP_CLAUSE_PARALLEL */ + 0, /* OMP_CLAUSE_SECTIONS */ + 0, /* OMP_CLAUSE_TASKGROUP */ + 1, /* OMP_CLAUSE__SIMDUID_ */ }; const char * const omp_clause_code_name[] = @@ -258,6 +280,14 @@ const char * const omp_clause_code_name[] = "reduction", "copyin", "copyprivate", + "linear", + "aligned", + "depend", + "uniform", + "from", + "to", + "map", + "_looptemp_", "if", "num_threads", "schedule", @@ -267,7 +297,21 @@ const char * const omp_clause_code_name[] = "collapse", "untied", "final", - "mergeable" + "mergeable", + "device", + "dist_schedule", + "inbranch", + "notinbranch", + "num_teams", + "thread_limit", + "proc_bind", + "safelen", + "simdlen", + "for", + "parallel", + "sections", + "taskgroup", + "_simduid_" }; @@ -4570,6 +4614,48 @@ build_type_attribute_qual_variant (tree ttype, tree attribute, int quals) return ttype; } +/* Check if "omp declare simd" attribute arguments, CLAUSES1 and CLAUSES2, are + the same. */ + +bool +omp_declare_simd_clauses_equal (tree clauses1, tree clauses2) +{ + tree cl1, cl2; + for (cl1 = clauses1, cl2 = clauses2; + cl1 && cl2; + cl1 = OMP_CLAUSE_CHAIN (cl1), cl2 = OMP_CLAUSE_CHAIN (cl2)) + { + if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_CODE (cl2)) + return false; + if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_SIMDLEN) + { + if (simple_cst_equal (OMP_CLAUSE_DECL (cl1), + OMP_CLAUSE_DECL (cl2)) != 1) + return false; + } + switch (OMP_CLAUSE_CODE (cl1)) + { + case OMP_CLAUSE_ALIGNED: + if (simple_cst_equal (OMP_CLAUSE_ALIGNED_ALIGNMENT (cl1), + OMP_CLAUSE_ALIGNED_ALIGNMENT (cl2)) != 1) + return false; + break; + case OMP_CLAUSE_LINEAR: + if (simple_cst_equal (OMP_CLAUSE_LINEAR_STEP (cl1), + OMP_CLAUSE_LINEAR_STEP (cl2)) != 1) + return false; + break; + case OMP_CLAUSE_SIMDLEN: + if (simple_cst_equal (OMP_CLAUSE_SIMDLEN_EXPR (cl1), + OMP_CLAUSE_SIMDLEN_EXPR (cl2)) != 1) + return false; + default: + break; + } + } + return true; +} + /* Compare two attributes for their value identity. Return true if the attribute values are known to be equal; otherwise return false. */ @@ -4587,6 +4673,13 @@ attribute_value_equal (const_tree attr1, const_tree attr2) return (simple_cst_list_equal (TREE_VALUE (attr1), TREE_VALUE (attr2)) == 1); + if (flag_openmp + && TREE_VALUE (attr1) && TREE_VALUE (attr2) + && TREE_CODE (TREE_VALUE (attr1)) == OMP_CLAUSE + && TREE_CODE (TREE_VALUE (attr2)) == OMP_CLAUSE) + return omp_declare_simd_clauses_equal (TREE_VALUE (attr1), + TREE_VALUE (attr2)); + return (simple_cst_equal (TREE_VALUE (attr1), TREE_VALUE (attr2)) == 1); } @@ -11033,6 +11126,16 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, case OMP_CLAUSE_IF: case OMP_CLAUSE_NUM_THREADS: case OMP_CLAUSE_SCHEDULE: + case OMP_CLAUSE_UNIFORM: + case OMP_CLAUSE_DEPEND: + case OMP_CLAUSE_NUM_TEAMS: + case OMP_CLAUSE_THREAD_LIMIT: + case OMP_CLAUSE_DEVICE: + case OMP_CLAUSE_DIST_SCHEDULE: + case OMP_CLAUSE_SAFELEN: + case OMP_CLAUSE_SIMDLEN: + case OMP_CLAUSE__LOOPTEMP_: + case OMP_CLAUSE__SIMDUID_: WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, 0)); /* FALLTHRU */ @@ -11041,6 +11144,13 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, case OMP_CLAUSE_DEFAULT: case OMP_CLAUSE_UNTIED: case OMP_CLAUSE_MERGEABLE: + case OMP_CLAUSE_PROC_BIND: + case OMP_CLAUSE_INBRANCH: + case OMP_CLAUSE_NOTINBRANCH: + case OMP_CLAUSE_FOR: + case OMP_CLAUSE_PARALLEL: + case OMP_CLAUSE_SECTIONS: + case OMP_CLAUSE_TASKGROUP: WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp)); case OMP_CLAUSE_LASTPRIVATE: @@ -11056,6 +11166,15 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp)); } + case OMP_CLAUSE_ALIGNED: + case OMP_CLAUSE_LINEAR: + case OMP_CLAUSE_FROM: + case OMP_CLAUSE_TO: + case OMP_CLAUSE_MAP: + WALK_SUBTREE (OMP_CLAUSE_DECL (*tp)); + WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, 1)); + WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp)); + case OMP_CLAUSE_REDUCTION: { int i; diff --git a/gcc/tree.def b/gcc/tree.def index da30074b10925..75b4d8a491da8 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -1030,6 +1030,36 @@ DEFTREECODE (OMP_TASK, "omp_task", tcc_statement, 2) unspecified by the standard. */ DEFTREECODE (OMP_FOR, "omp_for", tcc_statement, 6) +/* OpenMP - #pragma omp simd [clause1 ... clauseN] + Operands like for OMP_FOR. */ +DEFTREECODE (OMP_SIMD, "omp_simd", tcc_statement, 6) + +/* Cilk Plus - #pragma simd [clause1 ... clauseN] + Operands like for OMP_FOR. + + NOTE: This must go between OMP_FOR and OMP_DISTRIBUTE, so + OMP_LOOP_CHECK works as expected. */ +DEFTREECODE (CILK_SIMD, "cilk_simd", tcc_statement, 6) + +/* OpenMP - #pragma omp distribute [clause1 ... clauseN] + Operands like for OMP_FOR. */ +DEFTREECODE (OMP_DISTRIBUTE, "omp_distribute", tcc_statement, 6) + +/* OpenMP - #pragma omp teams [clause1 ... clauseN] + Operand 0: OMP_TEAMS_BODY: Teams body. + Operand 1: OMP_TEAMS_CLAUSES: List of clauses. */ +DEFTREECODE (OMP_TEAMS, "omp_teams", tcc_statement, 2) + +/* OpenMP - #pragma omp target data [clause1 ... clauseN] + Operand 0: OMP_TARGET_DATA_BODY: Target data construct body. + Operand 1: OMP_TARGET_DATA_CLAUSES: List of clauses. */ +DEFTREECODE (OMP_TARGET_DATA, "omp_target_data", tcc_statement, 2) + +/* OpenMP - #pragma omp target [clause1 ... clauseN] + Operand 0: OMP_TARGET_BODY: Target construct body. + Operand 1: OMP_TARGET_CLAUSES: List of clauses. */ +DEFTREECODE (OMP_TARGET, "omp_target", tcc_statement, 2) + /* OpenMP - #pragma omp sections [clause1 ... clauseN] Operand 0: OMP_SECTIONS_BODY: Sections body. Operand 1: OMP_SECTIONS_CLAUSES: List of clauses. */ @@ -1057,6 +1087,13 @@ DEFTREECODE (OMP_ORDERED, "omp_ordered", tcc_statement, 1) Operand 1: OMP_CRITICAL_NAME: Identifier for critical section. */ DEFTREECODE (OMP_CRITICAL, "omp_critical", tcc_statement, 2) +/* OpenMP - #pragma omp target update [clause1 ... clauseN] + Operand 0: OMP_TARGET_UPDATE_CLAUSES: List of clauses. */ +DEFTREECODE (OMP_TARGET_UPDATE, "omp_target_update", tcc_statement, 1) + +/* OMP_ATOMIC through OMP_ATOMIC_CAPTURE_NEW must be consecutive, + or OMP_ATOMIC_SEQ_CST needs adjusting. */ + /* OpenMP - #pragma omp atomic Operand 0: The address at which the atomic operation is to be performed. This address should be stabilized with save_expr. diff --git a/gcc/tree.h b/gcc/tree.h index b4445170088e5..60d47ae19e2ef 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -365,6 +365,30 @@ enum omp_clause_code /* OpenMP clause: copyprivate (variable_list). */ OMP_CLAUSE_COPYPRIVATE, + /* OpenMP clause: linear (variable-list[:linear-step]). */ + OMP_CLAUSE_LINEAR, + + /* OpenMP clause: aligned (variable-list[:alignment]). */ + OMP_CLAUSE_ALIGNED, + + /* OpenMP clause: depend ({in,out,inout}:variable-list). */ + OMP_CLAUSE_DEPEND, + + /* OpenMP clause: uniform (argument-list). */ + OMP_CLAUSE_UNIFORM, + + /* OpenMP clause: from (variable-list). */ + OMP_CLAUSE_FROM, + + /* OpenMP clause: to (variable-list). */ + OMP_CLAUSE_TO, + + /* OpenMP clause: map ({alloc:,to:,from:,tofrom:,}variable-list). */ + OMP_CLAUSE_MAP, + + /* Internal clause: temporary for combined loops expansion. */ + OMP_CLAUSE__LOOPTEMP_, + /* OpenMP clause: if (scalar-expression). */ OMP_CLAUSE_IF, @@ -393,7 +417,49 @@ enum omp_clause_code OMP_CLAUSE_FINAL, /* OpenMP clause: mergeable. */ - OMP_CLAUSE_MERGEABLE + OMP_CLAUSE_MERGEABLE, + + /* OpenMP clause: device (integer-expression). */ + OMP_CLAUSE_DEVICE, + + /* OpenMP clause: dist_schedule (static[:chunk-size]). */ + OMP_CLAUSE_DIST_SCHEDULE, + + /* OpenMP clause: inbranch. */ + OMP_CLAUSE_INBRANCH, + + /* OpenMP clause: notinbranch. */ + OMP_CLAUSE_NOTINBRANCH, + + /* OpenMP clause: num_teams(integer-expression). */ + OMP_CLAUSE_NUM_TEAMS, + + /* OpenMP clause: thread_limit(integer-expression). */ + OMP_CLAUSE_THREAD_LIMIT, + + /* OpenMP clause: proc_bind ({master,close,spread}). */ + OMP_CLAUSE_PROC_BIND, + + /* OpenMP clause: safelen (constant-integer-expression). */ + OMP_CLAUSE_SAFELEN, + + /* OpenMP clause: simdlen (constant-integer-expression). */ + OMP_CLAUSE_SIMDLEN, + + /* OpenMP clause: for. */ + OMP_CLAUSE_FOR, + + /* OpenMP clause: parallel. */ + OMP_CLAUSE_PARALLEL, + + /* OpenMP clause: sections. */ + OMP_CLAUSE_SECTIONS, + + /* OpenMP clause: taskgroup. */ + OMP_CLAUSE_TASKGROUP, + + /* Internally used only clause, holding SIMD uid. */ + OMP_CLAUSE__SIMDUID_ }; /* The definition of tree nodes fills the next several pages. */ @@ -560,6 +626,9 @@ struct GTY(()) tree_base { OMP_CLAUSE_PRIVATE_DEBUG in OMP_CLAUSE_PRIVATE + OMP_CLAUSE_LINEAR_NO_COPYIN in + OMP_CLAUSE_LINEAR + TRANSACTION_EXPR_RELAXED in TRANSACTION_EXPR @@ -577,9 +646,15 @@ struct GTY(()) tree_base { OMP_PARALLEL_COMBINED in OMP_PARALLEL + OMP_ATOMIC_SEQ_CST in + OMP_ATOMIC* + OMP_CLAUSE_PRIVATE_OUTER_REF in OMP_CLAUSE_PRIVATE + OMP_CLAUSE_LINEAR_NO_COPYOUT in + OMP_CLAUSE_LINEAR + TYPE_REF_IS_RVALUE in REFERENCE_TYPE @@ -1774,12 +1849,13 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_TASKREG_BODY(NODE) TREE_OPERAND (OMP_TASKREG_CHECK (NODE), 0) #define OMP_TASKREG_CLAUSES(NODE) TREE_OPERAND (OMP_TASKREG_CHECK (NODE), 1) -#define OMP_FOR_BODY(NODE) TREE_OPERAND (OMP_FOR_CHECK (NODE), 0) -#define OMP_FOR_CLAUSES(NODE) TREE_OPERAND (OMP_FOR_CHECK (NODE), 1) -#define OMP_FOR_INIT(NODE) TREE_OPERAND (OMP_FOR_CHECK (NODE), 2) -#define OMP_FOR_COND(NODE) TREE_OPERAND (OMP_FOR_CHECK (NODE), 3) -#define OMP_FOR_INCR(NODE) TREE_OPERAND (OMP_FOR_CHECK (NODE), 4) -#define OMP_FOR_PRE_BODY(NODE) TREE_OPERAND (OMP_FOR_CHECK (NODE), 5) +#define OMP_LOOP_CHECK(NODE) TREE_RANGE_CHECK (NODE, OMP_FOR, OMP_DISTRIBUTE) +#define OMP_FOR_BODY(NODE) TREE_OPERAND (OMP_LOOP_CHECK (NODE), 0) +#define OMP_FOR_CLAUSES(NODE) TREE_OPERAND (OMP_LOOP_CHECK (NODE), 1) +#define OMP_FOR_INIT(NODE) TREE_OPERAND (OMP_LOOP_CHECK (NODE), 2) +#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) #define OMP_SECTIONS_BODY(NODE) TREE_OPERAND (OMP_SECTIONS_CHECK (NODE), 0) #define OMP_SECTIONS_CLAUSES(NODE) TREE_OPERAND (OMP_SECTIONS_CHECK (NODE), 1) @@ -1796,11 +1872,30 @@ extern void protected_set_expr_location (tree, location_t); #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_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_DATA_BODY(NODE) \ + TREE_OPERAND (OMP_TARGET_DATA_CHECK (NODE), 0) +#define OMP_TARGET_DATA_CLAUSES(NODE)\ + TREE_OPERAND (OMP_TARGET_DATA_CHECK (NODE), 1) + +#define OMP_TARGET_BODY(NODE) TREE_OPERAND (OMP_TARGET_CHECK (NODE), 0) +#define OMP_TARGET_CLAUSES(NODE) TREE_OPERAND (OMP_TARGET_CHECK (NODE), 1) + +#define OMP_TARGET_UPDATE_CLAUSES(NODE)\ + TREE_OPERAND (OMP_TARGET_UPDATE_CHECK (NODE), 0) + +#define OMP_CLAUSE_SIZE(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_RANGE_CHECK (OMP_CLAUSE_CHECK (NODE), \ + OMP_CLAUSE_FROM, \ + OMP_CLAUSE_MAP), 1) + #define OMP_CLAUSE_CHAIN(NODE) TREE_CHAIN (OMP_CLAUSE_CHECK (NODE)) #define OMP_CLAUSE_DECL(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_RANGE_CHECK (OMP_CLAUSE_CHECK (NODE), \ OMP_CLAUSE_PRIVATE, \ - OMP_CLAUSE_COPYPRIVATE), 0) + OMP_CLAUSE__LOOPTEMP_), 0) #define OMP_CLAUSE_HAS_LOCATION(NODE) \ (LOCATION_LOCUS ((OMP_CLAUSE_CHECK (NODE))->omp_clause.locus) \ != UNKNOWN_LOCATION) @@ -1816,6 +1911,12 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_PARALLEL_COMBINED(NODE) \ (OMP_PARALLEL_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) \ + (TREE_RANGE_CHECK (NODE, OMP_ATOMIC, \ + OMP_ATOMIC_CAPTURE_NEW)->base.private_flag) + /* True on a PRIVATE clause if its decl is kept around for debugging information only and its DECL_VALUE_EXPR is supposed to point to what it has been remapped to. */ @@ -1867,6 +1968,45 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_CLAUSE_REDUCTION_PLACEHOLDER(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_REDUCTION), 3) +/* True if a LINEAR clause doesn't need copy in. True for iterator vars which + are always initialized inside of the loop construct, false otherwise. */ +#define OMP_CLAUSE_LINEAR_NO_COPYIN(NODE) \ + (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_LINEAR)->base.public_flag) + +/* True if a LINEAR clause doesn't need copy out. True for iterator vars which + are declared inside of the simd construct. */ +#define OMP_CLAUSE_LINEAR_NO_COPYOUT(NODE) \ + TREE_PRIVATE (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_LINEAR)) + +#define OMP_CLAUSE_LINEAR_STEP(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_LINEAR), 1) + +#define OMP_CLAUSE_ALIGNED_ALIGNMENT(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_ALIGNED), 1) + +#define OMP_CLAUSE_NUM_TEAMS_EXPR(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_NUM_TEAMS), 0) + +#define OMP_CLAUSE_THREAD_LIMIT_EXPR(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, \ + OMP_CLAUSE_THREAD_LIMIT), 0) + +#define OMP_CLAUSE_DEVICE_ID(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_DEVICE), 0) + +#define OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, \ + OMP_CLAUSE_DIST_SCHEDULE), 0) + +#define OMP_CLAUSE_SAFELEN_EXPR(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_SAFELEN), 0) + +#define OMP_CLAUSE_SIMDLEN_EXPR(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_SIMDLEN), 0) + +#define OMP_CLAUSE__SIMDUID__DECL(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE__SIMDUID_), 0) + enum omp_clause_schedule_kind { OMP_CLAUSE_SCHEDULE_STATIC, @@ -1891,6 +2031,44 @@ enum omp_clause_default_kind #define OMP_CLAUSE_DEFAULT_KIND(NODE) \ (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_DEFAULT)->omp_clause.subcode.default_kind) +enum omp_clause_depend_kind +{ + OMP_CLAUSE_DEPEND_IN, + OMP_CLAUSE_DEPEND_OUT, + OMP_CLAUSE_DEPEND_INOUT +}; + +#define OMP_CLAUSE_DEPEND_KIND(NODE) \ + (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_DEPEND)->omp_clause.subcode.depend_kind) + +enum omp_clause_map_kind +{ + OMP_CLAUSE_MAP_ALLOC, + OMP_CLAUSE_MAP_TO, + OMP_CLAUSE_MAP_FROM, + OMP_CLAUSE_MAP_TOFROM, + /* This following is an internal only map kind, used for pointer based array + sections. OMP_CLAUSE_SIZE for these is not the pointer size, which is + implicitly POINTER_SIZE / BITS_PER_UNIT, but the bias. */ + OMP_CLAUSE_MAP_POINTER +}; + +#define OMP_CLAUSE_MAP_KIND(NODE) \ + (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)->omp_clause.subcode.map_kind) + +enum omp_clause_proc_bind_kind +{ + /* Numbers should match omp_proc_bind_t enum in omp.h. */ + OMP_CLAUSE_PROC_BIND_FALSE = 0, + OMP_CLAUSE_PROC_BIND_TRUE = 1, + OMP_CLAUSE_PROC_BIND_MASTER = 2, + OMP_CLAUSE_PROC_BIND_CLOSE = 3, + OMP_CLAUSE_PROC_BIND_SPREAD = 4 +}; + +#define OMP_CLAUSE_PROC_BIND_KIND(NODE) \ + (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_PROC_BIND)->omp_clause.subcode.proc_bind_kind) + struct GTY(()) tree_exp { struct tree_typed typed; location_t locus; @@ -2014,9 +2192,12 @@ struct GTY(()) tree_omp_clause { location_t locus; enum omp_clause_code code; union omp_clause_subcode { - enum omp_clause_default_kind default_kind; - enum omp_clause_schedule_kind schedule_kind; - enum tree_code reduction_code; + enum omp_clause_default_kind default_kind; + enum omp_clause_schedule_kind schedule_kind; + enum omp_clause_depend_kind depend_kind; + enum omp_clause_map_kind map_kind; + enum omp_clause_proc_bind_kind proc_bind_kind; + enum tree_code reduction_code; } GTY ((skip)) subcode; /* The gimplification of OMP_CLAUSE_REDUCTION_{INIT,MERGE} for omp-low's @@ -4783,6 +4964,7 @@ extern tree build_translation_unit_decl (tree); extern tree build_block (tree, tree, tree, tree); extern tree build_empty_stmt (location_t); extern tree build_omp_clause (location_t, enum omp_clause_code); +extern tree find_omp_clause (tree, enum omp_clause_code); extern tree build_vl_exp_stat (enum tree_code, int MEM_STAT_DECL); #define build_vl_exp(c,n) build_vl_exp_stat (c,n MEM_STAT_INFO) @@ -4918,6 +5100,10 @@ extern tree build_type_attribute_variant (tree, tree); extern tree build_decl_attribute_variant (tree, tree); extern tree build_type_attribute_qual_variant (tree, tree, int); +/* Check if "omp declare simd" attribute arguments, CLAUSES1 and CLAUSES2, are + the same. */ +extern bool omp_declare_simd_clauses_equal (tree, tree); + /* Return 0 if the attributes for two types are incompatible, 1 if they are compatible, and 2 if they are nearly compatible (which causes a warning to be generated). */ diff --git a/libgomp/ChangeLog.gomp b/libgomp/ChangeLog.gomp new file mode 100644 index 0000000000000..375801c5315f4 --- /dev/null +++ b/libgomp/ChangeLog.gomp @@ -0,0 +1,124 @@ +2013-06-28 Jakub Jelinek + + * testsuite/libgomp.c++/simd-1.C: New test. + * testsuite/libgomp.c++/simd-2.C: New test. + * testsuite/libgomp.c++/simd-3.C: New test. + +2013-06-21 Jakub Jelinek + + * testsuite/libgomp.c/for-1.h: New file. + * testsuite/libgomp.c/for-2.h: New file. + * testsuite/libgomp.c/for-1.c: New test. + * testsuite/libgomp.c/for-2.c: New test. + * testsuite/libgomp.c++/for-9.C: New test. + * testsuite/libgomp.c++/for-10.C: New test. + * testsuite/libgomp.c++/for-11.C: New test. + +2013-06-12 Jakub Jelinek + + * fortran.c (omp_is_initial_device): Add ialias_redirect. + (omp_is_initial_device_): New function. + * omp_lib.f90.in (omp_is_initial_device): New interface. + * omp.h.in (omp_is_initial_device): New prototype. + * libgomp.map (omp_is_initial_device, omp_is_initial_device_): + Export @@OMP_4.0. + * env.c (omp_is_initial_device): New function. Add ialias for it. + * omp_lib.h.in (omp_is_initial_device): New external. + + * omp_lib.f90.in (omp_get_dynamic, omp_get_nested, + omp_in_parallel, omp_get_max_threads, omp_get_num_procs, + omp_get_num_threads, omp_get_thread_num, omp_get_thread_limit, + omp_set_max_active_levels, omp_get_max_active_levels, + omp_get_level, omp_get_ancestor_thread_num, + omp_get_team_size, omp_get_active_level, omp_in_final, + omp_get_cancellation, omp_get_default_device, + omp_get_num_devices, omp_get_num_teams, omp_get_team_num): Remove + useless use omp_lib_kinds. + +2013-04-30 Jakub Jelinek + + * testsuite/libgomp.c/atomic-17.c: New test. + * testsuite/libgomp.c++/atomic-14.C: New test. + * testsuite/libgomp.c++/atomic-15.C: New test. + +2013-04-10 Jakub Jelinek + + * libgomp.map (omp_get_cancellation, omp_get_cancellation_, + omp_get_proc_bind, omp_get_proc_bind_, omp_set_default_device, + omp_set_default_device_, omp_set_default_device_8_, + omp_get_default_device, omp_get_default_device_, + omp_get_num_devices, omp_get_num_devices_, omp_get_num_teams, + omp_get_num_teams_, omp_get_team_num, omp_get_team_num_): Export + @@OMP_4.0. + (GOMP_cancel, GOMP_cancellation_point, GOMP_parallel_loop_dynamic, + GOMP_parallel_loop_guided, GOMP_parallel_loop_runtime, + GOMP_parallel_loop_static, GOMP_parallel_sections, GOMP_parallel, + GOMP_taskgroup_start, GOMP_taskgroup_end): Export @@GOMP_4.0. + * parallel.c (GOMP_parallel_end): Add ialias. + (GOMP_parallel, GOMP_cancel, GOMP_cancellation_point): New + functions. + * omp.h.in (omp_proc_bind_t): New typedef. + (omp_get_cancellation, omp_get_proc_bind, omp_set_default_device, + omp_get_default_device, omp_get_num_devices, omp_get_num_teams, + omp_get_team_num): New prototypes. + * env.c (omp_get_cancellation, omp_get_proc_bind, + omp_set_default_device, omp_get_default_device, omp_get_num_devices, + omp_get_num_teams, omp_get_team_num): New functions. + * fortran.c (ULP, STR1, STR2, ialias_redirect): Removed. + (omp_get_cancellation_, omp_get_proc_bind_, omp_set_default_device_, + omp_set_default_device_8_, omp_get_default_device_, + omp_get_num_devices_, omp_get_num_teams_, omp_get_team_num_): New + functions. + * libgomp.h (ialias_ulp, ialias_str1, ialias_str2, ialias_redirect, + ialias_call): Define. + * libgomp_g.h (GOMP_parallel_loop_static, GOMP_parallel_loop_dynamic, + GOMP_parallel_loop_guided, GOMP_parallel_loop_runtime, GOMP_parallel, + GOMP_cancel, GOMP_cancellation_point, GOMP_taskgroup_start, + GOMP_taskgroup_end, GOMP_parallel_sections): New prototypes. + * task.c (GOMP_taskgroup_start, GOMP_taskgroup_end): New functions. + * sections.c (GOMP_parallel_sections): New function. + * loop.c (GOMP_parallel_loop_static, GOMP_parallel_loop_dynamic, + GOMP_parallel_loop_guided, GOMP_parallel_loop_runtime): New + functions. + (GOMP_parallel_end): Add ialias_redirect. + * omp_lib.f90.in (omp_proc_bind_kind, omp_proc_bind_false, + omp_proc_bind_true, omp_proc_bind_master, omp_proc_bind_close, + omp_proc_bind_spread): New params. + (omp_get_cancellation, omp_get_proc_bind, omp_set_default_device, + omp_get_default_device, omp_get_num_devices, omp_get_num_teams, + omp_get_team_num): New interfaces. + * omp_lib.h.in (omp_proc_bind_kind, omp_proc_bind_false, + omp_proc_bind_true, omp_proc_bind_master, omp_proc_bind_close, + omp_proc_bind_spread): New params. + (omp_get_cancellation, omp_get_proc_bind, omp_set_default_device, + omp_get_default_device, omp_get_num_devices, omp_get_num_teams, + omp_get_team_num): New externals. + +2013-03-20 Tobias Burnus + + * libgomp.texi (Environment Variables): Minor cleanup, + update section refs to OpenMP 4.0rc2. + (OMP_DISPLAY_ENV, GOMP_SPINCOUNT): Document these + environment variables. + +2013-03-20 Tobias Burnus + + * env.c (handle_omp_display_env): New function. + (initialize_env): Use it. + +2013-03-20 Jakub Jelinek + + * testsuite/libgomp.c/atomic-14.c: Add parens to make it valid. + * testsuite/libgomp.c/atomic-15.c: New test. + * testsuite/libgomp.c/atomic-16.c: New test. + + * testsuite/libgomp.c++/atomic-10.C: New test. + * testsuite/libgomp.c++/atomic-11.C: New test. + * testsuite/libgomp.c++/atomic-12.C: New test. + * testsuite/libgomp.c++/atomic-13.C: New test. + +Copyright (C) 2013 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/libgomp/env.c b/libgomp/env.c index 65cbba83e6c02..dbbddbda98f64 100644 --- a/libgomp/env.c +++ b/libgomp/env.c @@ -29,6 +29,10 @@ #include "libgomp_f.h" #include #include +#include +#ifdef HAVE_INTTYPES_H +# include /* For PRIu64. */ +#endif #ifdef STRING_WITH_STRINGS # include # include @@ -565,6 +569,122 @@ parse_affinity (void) return false; } + +static void +handle_omp_display_env (bool proc_bind, unsigned long stacksize, + int wait_policy) +{ + const char *env; + bool display = false; + bool verbose = false; + int i; + + env = getenv ("OMP_DISPLAY_ENV"); + if (env == NULL) + return; + + while (isspace ((unsigned char) *env)) + ++env; + if (strncasecmp (env, "true", 4) == 0) + { + env += 4; + } + else if (strncasecmp (env, "false", 5) == 0) + { + display = false; + env += 5; + } + else if (strncasecmp (env, "verbose", 7) == 0) + { + display = true; + verbose = true; + env += 7; + } + else + env = "X"; + while (isspace ((unsigned char) *env)) + ++env; + if (*env != '\0') + gomp_error ("Invalid value for environment variable OMP_DISPLAY_ENV"); + + if (!display) + return; + + fputs ("\nOPENMP DISPLAY ENVIRONMENT BEGIN\n", stderr); + + fputs (" _OPENMP = '201107'\n", stderr); + fprintf (stderr, " OMP_DYNAMIC = '%s'\n", + gomp_global_icv.dyn_var ? "TRUE" : "FALSE"); + fprintf (stderr, " OMP_NESTED = '%s'\n", + gomp_global_icv.nest_var ? "TRUE" : "FALSE"); + + fprintf (stderr, " OMP_NUM_THREADS = '%lu", gomp_global_icv.nthreads_var); + for (i = 1; i < gomp_nthreads_var_list_len; i++) + fprintf (stderr, ",%lu", gomp_nthreads_var_list[i]); + fputs ("'\n", stderr); + + fprintf (stderr, " OMP_SCHEDULE = '"); + switch (gomp_global_icv.run_sched_var) + { + case GFS_RUNTIME: + fputs ("RUNTIME", stderr); + break; + case GFS_STATIC: + fputs ("STATIC", stderr); + break; + case GFS_DYNAMIC: + fputs ("DYNAMIC", stderr); + break; + case GFS_GUIDED: + fputs ("GUIDED", stderr); + break; + case GFS_AUTO: + fputs ("AUTO", stderr); + break; + } + fputs ("'\n", stderr); + + fprintf (stderr, " OMP_PROC_BIND = '%s'\n", + proc_bind ? "TRUE" : "FALSE"); + fprintf (stderr, " OMP_STACKSIZE = '%lu'\n", stacksize); + + /* GOMP's default value is actually neither active nor passive. */ + fprintf (stderr, " OMP_WAIT_POLICY = '%s'\n", + wait_policy > 0 ? "ACTIVE" : "PASSIVE"); + fprintf (stderr, " OMP_THREAD_LIMIT = '%lu'\n", + gomp_thread_limit_var); + fprintf (stderr, " OMP_MAX_ACTIVE_LEVELS = '%lu'\n", + gomp_max_active_levels_var); + +/* FIXME: Unimplemented OpenMP 4.0 environment variables. + fprintf (stderr, " OMP_PLACES = ''\n"); + fprintf (stderr, " OMP_CANCELLATION = ''\n"); + fprintf (stderr, " OMP_DEFAULT_DEVICE = ''\n"); */ + + if (verbose) + { + fputs (" GOMP_CPU_AFFINITY = '", stderr); + if (gomp_cpu_affinity_len) + { + fprintf (stderr, "%d", gomp_cpu_affinity[0]); + for (i = 1; i < gomp_cpu_affinity_len; i++) + fprintf (stderr, " %d", gomp_cpu_affinity[i]); + } + fputs ("'\n", stderr); + fprintf (stderr, " GOMP_STACKSIZE = '%lu'\n", stacksize); +#ifdef HAVE_INTTYPES_H + fprintf (stderr, " GOMP_SPINCOUNT = '%"PRIu64"'\n", + (uint64_t) gomp_spin_count_var); +#else + fprintf (stderr, " GOMP_SPINCOUNT = '%lu'\n", + (unsigned long) gomp_spin_count_var); +#endif + } + + fputs ("OPENMP DISPLAY ENVIRONMENT END\n", stderr); +} + + static void __attribute__((constructor)) initialize_env (void) { @@ -645,6 +765,8 @@ initialize_env (void) if (err != 0) gomp_error ("Stack size change failed: %s", strerror (err)); } + + handle_omp_display_env (bind_var, stacksize, wait_policy); } @@ -744,6 +866,54 @@ omp_get_max_active_levels (void) return gomp_max_active_levels_var; } +int +omp_get_cancellation (void) +{ + return 0; +} + +omp_proc_bind_t +omp_get_proc_bind (void) +{ + return omp_proc_bind_false; +} + +void +omp_set_default_device (int device_num) +{ + (void) device_num; +} + +int +omp_get_default_device (void) +{ + return 0; +} + +int +omp_get_num_devices (void) +{ + return 0; +} + +int +omp_get_num_teams (void) +{ + return 1; +} + +int +omp_get_team_num (void) +{ + return 0; +} + +int +omp_is_initial_device (void) +{ + return 1; +} + ialias (omp_set_dynamic) ialias (omp_set_nested) ialias (omp_set_num_threads) @@ -755,3 +925,11 @@ ialias (omp_get_max_threads) ialias (omp_get_thread_limit) ialias (omp_set_max_active_levels) ialias (omp_get_max_active_levels) +ialias (omp_get_cancellation) +ialias (omp_get_proc_bind) +ialias (omp_set_default_device) +ialias (omp_get_default_device) +ialias (omp_get_num_devices) +ialias (omp_get_num_teams) +ialias (omp_get_team_num) +ialias (omp_is_initial_device) diff --git a/libgomp/fortran.c b/libgomp/fortran.c index 3a4a42a4c618e..38b968a8d3965 100644 --- a/libgomp/fortran.c +++ b/libgomp/fortran.c @@ -31,11 +31,6 @@ #ifdef HAVE_ATTRIBUTE_ALIAS /* Use internal aliases if possible. */ -# define ULP STR1(__USER_LABEL_PREFIX__) -# define STR1(x) STR2(x) -# define STR2(x) #x -# define ialias_redirect(fn) \ - extern __typeof (fn) fn __asm__ (ULP "gomp_ialias_" #fn) attribute_hidden; # ifndef LIBGOMP_GNU_SYMBOL_VERSIONING ialias_redirect (omp_init_lock) ialias_redirect (omp_init_nest_lock) @@ -70,6 +65,14 @@ ialias_redirect (omp_get_ancestor_thread_num) ialias_redirect (omp_get_team_size) ialias_redirect (omp_get_active_level) ialias_redirect (omp_in_final) +ialias_redirect (omp_get_cancellation) +ialias_redirect (omp_get_proc_bind) +ialias_redirect (omp_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) #endif #ifndef LIBGOMP_GNU_SYMBOL_VERSIONING @@ -435,3 +438,57 @@ omp_in_final_ (void) { return omp_in_final (); } + +int32_t +omp_get_cancellation_ (void) +{ + return omp_get_cancellation (); +} + +int32_t +omp_get_proc_bind_ (void) +{ + return omp_get_proc_bind (); +} + +void +omp_set_default_device_ (const int32_t *device_num) +{ + return omp_set_default_device (*device_num); +} + +void +omp_set_default_device_8_ (const int64_t *device_num) +{ + return omp_set_default_device (TO_INT (*device_num)); +} + +int32_t +omp_get_default_device_ (void) +{ + return omp_get_default_device (); +} + +int32_t +omp_get_num_devices_ (void) +{ + return omp_get_num_devices (); +} + +int32_t +omp_get_num_teams_ (void) +{ + return omp_get_num_teams (); +} + +int32_t +omp_get_team_num_ (void) +{ + return omp_get_team_num (); +} + +int32_t +omp_is_initial_device_ (void) +{ + return omp_is_initial_device (); +} diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h index 322a43520ee79..fb6c1ba7c72a7 100644 --- a/libgomp/libgomp.h +++ b/libgomp/libgomp.h @@ -580,11 +580,19 @@ extern int gomp_test_nest_lock_25 (omp_nest_lock_25_t *) __GOMP_NOTHROW; #endif #ifdef HAVE_ATTRIBUTE_ALIAS +# define ialias_ulp ialias_str1(__USER_LABEL_PREFIX__) +# define ialias_str1(x) ialias_str2(x) +# define ialias_str2(x) #x # define ialias(fn) \ extern __typeof (fn) gomp_ialias_##fn \ __attribute__ ((alias (#fn))) attribute_hidden; +# define ialias_redirect(fn) \ + extern __typeof (fn) fn __asm__ (ialias_ulp "gomp_ialias_" #fn) attribute_hidden; +# define ialias_call(fn) gomp_ialias_ ## fn #else # define ialias(fn) +# define ialias_redirect(fn) +# define ialias_call(fn) fn #endif #endif /* LIBGOMP_H */ diff --git a/libgomp/libgomp.map b/libgomp/libgomp.map index 7b051f96aabb2..5060a4b94e171 100644 --- a/libgomp/libgomp.map +++ b/libgomp/libgomp.map @@ -113,6 +113,27 @@ OMP_3.1 { omp_in_final_; } OMP_3.0; +OMP_4.0 { + global: + omp_get_cancellation; + omp_get_cancellation_; + omp_get_proc_bind; + omp_get_proc_bind_; + omp_set_default_device; + omp_set_default_device_; + omp_set_default_device_8_; + omp_get_default_device; + omp_get_default_device_; + omp_get_num_devices; + omp_get_num_devices_; + omp_get_num_teams; + omp_get_num_teams_; + omp_get_team_num; + omp_get_team_num_; + omp_is_initial_device; + omp_is_initial_device_; +} OMP_3.1; + GOMP_1.0 { global: GOMP_atomic_end; @@ -184,3 +205,17 @@ GOMP_3.0 { global: GOMP_taskyield; } GOMP_2.0; + +GOMP_4.0 { + global: + GOMP_cancel; + GOMP_cancellation_point; + GOMP_parallel_loop_dynamic; + GOMP_parallel_loop_guided; + GOMP_parallel_loop_runtime; + GOMP_parallel_loop_static; + GOMP_parallel_sections; + GOMP_parallel; + GOMP_taskgroup_start; + GOMP_taskgroup_end; +} GOMP_3.0; diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi index 2985128f8ac8a..a6930cc318b41 100644 --- a/libgomp/libgomp.texi +++ b/libgomp/libgomp.texi @@ -1083,12 +1083,9 @@ guaranteed not to change during the execution of the program. @node Environment Variables @chapter Environment Variables -The variables @env{OMP_DYNAMIC}, @env{OMP_MAX_ACTIVE_LEVELS}, -@env{OMP_NESTED}, @env{OMP_NUM_THREADS}, @env{OMP_SCHEDULE}, -@env{OMP_STACKSIZE},@env{OMP_THREAD_LIMIT} and @env{OMP_WAIT_POLICY} -are defined by section 4 of the OpenMP specifications in version 3.1, -while @env{GOMP_CPU_AFFINITY} and @env{GOMP_STACKSIZE} are GNU -extensions. +The environment variables which beginning with @env{OMP_} are defined by +section 4 of the OpenMP specification in version 4.0, while those +beginning with @env{GOMP_} are GNU extensions. @menu * OMP_DYNAMIC:: Dynamic adjustment of threads @@ -1099,9 +1096,11 @@ extensions. * OMP_SCHEDULE:: How threads are scheduled * OMP_THREAD_LIMIT:: Set the maximum number of threads * OMP_WAIT_POLICY:: How waiting threads are handled +* OMP_DISPLAY_ENV:: Show OpenMP version and environment variables * OMP_PROC_BIND:: Whether theads may be moved between CPUs * GOMP_CPU_AFFINITY:: Bind threads to specific CPUs * GOMP_STACKSIZE:: Set default thread stack size +* GOMP_SPINCOUNT:: Set the busy-wait spin count @end menu @@ -1119,7 +1118,7 @@ disabled by default. @ref{omp_set_dynamic} @item @emph{Reference}: -@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 4.3 +@uref{http://www.openmp.org/, OpenMP specifications v4.0}, section 4.3 @end table @@ -1137,7 +1136,7 @@ If undefined, the number of active levels is unlimited. @ref{omp_set_max_active_levels} @item @emph{Reference}: -@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 4.8 +@uref{http://www.openmp.org/, OpenMP specifications v4.0}, section 4.9 @end table @@ -1157,7 +1156,7 @@ regions are disabled by default. @ref{omp_set_nested} @item @emph{Reference}: -@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 4.5 +@uref{http://www.openmp.org/, OpenMP specifications v4.0}, section 4.6 @end table @@ -1177,7 +1176,7 @@ level. If undefined one thread per CPU is used. @ref{omp_set_num_threads} @item @emph{Reference}: -@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 4.2 +@uref{http://www.openmp.org/, OpenMP specifications v4.0}, section 4.2 @end table @@ -1198,7 +1197,7 @@ dynamic scheduling and a chunk size of 1 is used. @ref{omp_set_schedule} @item @emph{Reference}: -@uref{http://www.openmp.org/, OpenMP specifications v3.1}, sections 2.5.1 and 4.1 +@uref{http://www.openmp.org/, OpenMP specifications v4.0}, sections 2.7.1 and 4.1 @end table @@ -1218,7 +1217,7 @@ stack size is left unchanged. If undefined, the stack size is system dependent. @item @emph{Reference}: -@uref{http://www.openmp.org/, OpenMP specifications v3.1}, sections 4.6 +@uref{http://www.openmp.org/, OpenMP specifications v4.0}, section 4.7 @end table @@ -1237,7 +1236,7 @@ the number of threads is not limited. @ref{omp_get_thread_limit} @item @emph{Reference}: -@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 4.9 +@uref{http://www.openmp.org/, OpenMP specifications v4.0}, section 4.10 @end table @@ -1250,10 +1249,14 @@ the number of threads is not limited. Specifies whether waiting threads should be active or passive. If the value is @code{PASSIVE}, waiting threads should not consume CPU power while waiting; while the value is @code{ACTIVE} specifies that -they should. +they should. If undefined, threads wait actively for a short time +before waiting passively. + +@item @emph{See also}: +@ref{GOMP_SPINCOUNT} @item @emph{Reference}: -@uref{http://www.openmp.org/, OpenMP specifications v3.1}, sections 4.7 +@uref{http://www.openmp.org/, OpenMP specifications v4.0}, section 4.8 @end table @@ -1264,14 +1267,32 @@ they should. @table @asis @item @emph{Description}: Specifies whether threads may be moved between processors. If set to -@code{true}, OpenMP theads should not be moved, if set to @code{false} -they may be moved. +@code{TRUE}, OpenMP theads should not be moved, if set to @code{FALSE} +they may be moved. If undefined, threads may move between processors. @item @emph{See also}: @ref{GOMP_CPU_AFFINITY} @item @emph{Reference}: -@uref{http://www.openmp.org/, OpenMP specifications v3.1}, sections 4.4 +@uref{http://www.openmp.org/, OpenMP specifications v4.0}, section 4.4 +@end table + + + +@node OMP_DISPLAY_ENV +@section @env{OMP_DISPLAY_ENV} -- Show OpenMP version and environment variables +@cindex Environment Variable +@table @asis +@item @emph{Description}: +If set to @code{TRUE}, the OpenMP version number and the values +associated with the OpenMP environment variables are printed to @code{stderr}. +If set to @code{VERBOSE}, it additionally shows the value of the environment +variables which are GNU extensions. If undefined or set to @code{FALSE}, +this information will not be shown. + + +@item @emph{Reference}: +@uref{http://www.openmp.org/, OpenMP specifications v4.0}, section 4.12 @end table @@ -1298,7 +1319,7 @@ Fortran, may be used to query the setting of the @code{GOMP_CPU_AFFINITY} environment variable. A defined CPU affinity on startup cannot be changed or disabled during the runtime of the application. -If this environment variable is omitted, the host system will handle the +If this environment variable is omitted, the host system will handle the assignment of threads to CPUs. @item @emph{See also}: @@ -1331,6 +1352,33 @@ GCC Patches Mailinglist} +@node GOMP_SPINCOUNT +@section @env{GOMP_SPINCOUNT} -- Set the busy-wait spin count +@cindex Environment Variable +@cindex Implementation specific setting +@table @asis +@item @emph{Description}: +Determines how long a threads waits actively with consuming CPU power +before waiting passively without consuming CPU power. The value may be +either @code{INFINITE}, @code{INFINITY} to always wait actively or an +integer which gives the number of spins of the busy-wait loop. The +integer may optionally be followed by the following suffixes acting +as multiplication factors: @code{k} (kilo, thousand), @code{M} (mega, +million), @code{G} (giga, billion), or @code{T} (tera, trillion). +If undefined, 0 is used when @env{OMP_WAIT_POLICY} is @code{PASSIVE}, +300,000 is used when @env{OMP_WAIT_POLICY} is undefined and +30 billion is used when @env{OMP_WAIT_POLICY} is @code{ACTIVE}. +If there are more OpenMP threads than available CPUs, 1000 and 100 +spins are used for @env{OMP_WAIT_POLICY} being @code{ACTIVE} or +undefined, respectively; unless the @env{GOMP_SPINCOUNT} is lower +or @env{OMP_WAIT_POLICY} is @code{PASSIVE}. + +@item @emph{See also}: +@ref{OMP_WAIT_POLICY} +@end table + + + @c --------------------------------------------------------------------- @c The libgomp ABI @c --------------------------------------------------------------------- diff --git a/libgomp/libgomp_g.h b/libgomp/libgomp_g.h index a31e3458c1beb..8d42548c9fb76 100644 --- a/libgomp/libgomp_g.h +++ b/libgomp/libgomp_g.h @@ -76,6 +76,18 @@ extern void GOMP_parallel_loop_guided_start (void (*)(void *), void *, unsigned, long, long, long, long); extern void GOMP_parallel_loop_runtime_start (void (*)(void *), void *, unsigned, long, long, long); +extern void GOMP_parallel_loop_static (void (*)(void *), void *, + unsigned, long, long, long, long, + unsigned); +extern void GOMP_parallel_loop_dynamic (void (*)(void *), void *, + unsigned, long, long, long, long, + unsigned); +extern void GOMP_parallel_loop_guided (void (*)(void *), void *, + unsigned, long, long, long, long, + unsigned); +extern void GOMP_parallel_loop_runtime (void (*)(void *), void *, + unsigned, long, long, long, + unsigned); extern void GOMP_loop_end (void); extern void GOMP_loop_end_nowait (void); @@ -157,6 +169,9 @@ extern void GOMP_ordered_end (void); extern void GOMP_parallel_start (void (*) (void *), void *, unsigned); extern void GOMP_parallel_end (void); +extern void GOMP_parallel (void (*) (void *), void *, unsigned, unsigned); +extern void GOMP_cancel (void); +extern void GOMP_cancellation_point (void); /* task.c */ @@ -164,6 +179,8 @@ extern void GOMP_task (void (*) (void *), void *, void (*) (void *, void *), long, long, bool, unsigned); extern void GOMP_taskwait (void); extern void GOMP_taskyield (void); +extern void GOMP_taskgroup_start (void); +extern void GOMP_taskgroup_end (void); /* sections.c */ @@ -171,6 +188,8 @@ extern unsigned GOMP_sections_start (unsigned); extern unsigned GOMP_sections_next (void); extern void GOMP_parallel_sections_start (void (*) (void *), void *, unsigned, unsigned); +extern void GOMP_parallel_sections (void (*) (void *), void *, + unsigned, unsigned, unsigned); extern void GOMP_sections_end (void); extern void GOMP_sections_end_nowait (void); diff --git a/libgomp/loop.c b/libgomp/loop.c index 12c818b011045..7de3e4c5dfeac 100644 --- a/libgomp/loop.c +++ b/libgomp/loop.c @@ -486,6 +486,57 @@ GOMP_parallel_loop_runtime_start (void (*fn) (void *), void *data, icv->run_sched_var, icv->run_sched_modifier); } +ialias_redirect (GOMP_parallel_end) + +void +GOMP_parallel_loop_static (void (*fn) (void *), void *data, + unsigned num_threads, long start, long end, + long incr, long chunk_size, unsigned flags) +{ + (void) flags; + gomp_parallel_loop_start (fn, data, num_threads, start, end, incr, + GFS_STATIC, chunk_size); + fn (data); + GOMP_parallel_end (); +} + +void +GOMP_parallel_loop_dynamic (void (*fn) (void *), void *data, + unsigned num_threads, long start, long end, + long incr, long chunk_size, unsigned flags) +{ + (void) flags; + gomp_parallel_loop_start (fn, data, num_threads, start, end, incr, + GFS_DYNAMIC, chunk_size); + fn (data); + GOMP_parallel_end (); +} + +void +GOMP_parallel_loop_guided (void (*fn) (void *), void *data, + unsigned num_threads, long start, long end, + long incr, long chunk_size, unsigned flags) +{ + (void) flags; + gomp_parallel_loop_start (fn, data, num_threads, start, end, incr, + GFS_GUIDED, chunk_size); + fn (data); + GOMP_parallel_end (); +} + +void +GOMP_parallel_loop_runtime (void (*fn) (void *), void *data, + unsigned num_threads, long start, long end, + long incr, unsigned flags) +{ + (void) flags; + 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); + fn (data); + GOMP_parallel_end (); +} + /* The GOMP_loop_end* routines are called after the thread is told that all loop iterations are complete. This first version synchronizes all threads; the nowait version does not. */ diff --git a/libgomp/omp.h.in b/libgomp/omp.h.in index 5db440785db9c..4fc123669ecad 100644 --- a/libgomp/omp.h.in +++ b/libgomp/omp.h.in @@ -52,6 +52,15 @@ typedef enum omp_sched_t omp_sched_auto = 4 } omp_sched_t; +typedef enum omp_proc_bind_t +{ + omp_proc_bind_false = 0, + omp_proc_bind_true = 1, + omp_proc_bind_master = 2, + omp_proc_bind_close = 3, + omp_proc_bind_spread = 4 +} omp_proc_bind_t; + #ifdef __cplusplus extern "C" { # define __GOMP_NOTHROW throw () @@ -88,17 +97,28 @@ extern int omp_test_nest_lock (omp_nest_lock_t *) __GOMP_NOTHROW; extern double omp_get_wtime (void) __GOMP_NOTHROW; extern double omp_get_wtick (void) __GOMP_NOTHROW; -void omp_set_schedule (omp_sched_t, int) __GOMP_NOTHROW; -void omp_get_schedule (omp_sched_t *, int *) __GOMP_NOTHROW; -int omp_get_thread_limit (void) __GOMP_NOTHROW; -void omp_set_max_active_levels (int) __GOMP_NOTHROW; -int omp_get_max_active_levels (void) __GOMP_NOTHROW; -int omp_get_level (void) __GOMP_NOTHROW; -int omp_get_ancestor_thread_num (int) __GOMP_NOTHROW; -int omp_get_team_size (int) __GOMP_NOTHROW; -int omp_get_active_level (void) __GOMP_NOTHROW; - -int omp_in_final (void) __GOMP_NOTHROW; +extern void omp_set_schedule (omp_sched_t, int) __GOMP_NOTHROW; +extern void omp_get_schedule (omp_sched_t *, int *) __GOMP_NOTHROW; +extern int omp_get_thread_limit (void) __GOMP_NOTHROW; +extern void omp_set_max_active_levels (int) __GOMP_NOTHROW; +extern int omp_get_max_active_levels (void) __GOMP_NOTHROW; +extern int omp_get_level (void) __GOMP_NOTHROW; +extern int omp_get_ancestor_thread_num (int) __GOMP_NOTHROW; +extern int omp_get_team_size (int) __GOMP_NOTHROW; +extern int omp_get_active_level (void) __GOMP_NOTHROW; + +extern int omp_in_final (void) __GOMP_NOTHROW; + +extern int omp_get_cancellation (void) __GOMP_NOTHROW; +extern omp_proc_bind_t omp_get_proc_bind (void) __GOMP_NOTHROW; + +extern void omp_set_default_device (int) __GOMP_NOTHROW; +extern int omp_get_default_device (void) __GOMP_NOTHROW; +extern int omp_get_num_devices (void) __GOMP_NOTHROW; +extern int omp_get_num_teams (void) __GOMP_NOTHROW; +extern int omp_get_team_num (void) __GOMP_NOTHROW; + +extern int omp_is_initial_device (void) __GOMP_NOTHROW; #ifdef __cplusplus } diff --git a/libgomp/omp_lib.f90.in b/libgomp/omp_lib.f90.in index c9bc5fd003ade..3c6deb6bbd51a 100644 --- a/libgomp/omp_lib.f90.in +++ b/libgomp/omp_lib.f90.in @@ -27,16 +27,22 @@ integer, parameter :: omp_lock_kind = @OMP_LOCK_KIND@ integer, parameter :: omp_nest_lock_kind = @OMP_NEST_LOCK_KIND@ integer, parameter :: omp_sched_kind = 4 + integer, parameter :: omp_proc_bind_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 end module module omp_lib use omp_lib_kinds implicit none integer, parameter :: openmp_version = 201107 - 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 interface subroutine omp_init_lock (svar) @@ -123,21 +129,18 @@ interface function omp_get_dynamic () - use omp_lib_kinds logical (4) :: omp_get_dynamic end function omp_get_dynamic end interface interface function omp_get_nested () - use omp_lib_kinds logical (4) :: omp_get_nested end function omp_get_nested end interface interface function omp_in_parallel () - use omp_lib_kinds logical (4) :: omp_in_parallel end function omp_in_parallel end interface @@ -152,28 +155,24 @@ interface function omp_get_max_threads () - use omp_lib_kinds integer (4) :: omp_get_max_threads end function omp_get_max_threads end interface interface function omp_get_num_procs () - use omp_lib_kinds integer (4) :: omp_get_num_procs end function omp_get_num_procs end interface interface function omp_get_num_threads () - use omp_lib_kinds integer (4) :: omp_get_num_threads end function omp_get_num_threads end interface interface function omp_get_thread_num () - use omp_lib_kinds integer (4) :: omp_get_thread_num end function omp_get_thread_num end interface @@ -226,44 +225,37 @@ interface function omp_get_thread_limit () - use omp_lib_kinds integer (4) :: omp_get_thread_limit end function omp_get_thread_limit end interface interface omp_set_max_active_levels subroutine omp_set_max_active_levels (max_levels) - use omp_lib_kinds integer (4), intent (in) :: max_levels end subroutine omp_set_max_active_levels subroutine omp_set_max_active_levels_8 (max_levels) - use omp_lib_kinds integer (8), intent (in) :: max_levels end subroutine omp_set_max_active_levels_8 end interface interface function omp_get_max_active_levels () - use omp_lib_kinds integer (4) :: omp_get_max_active_levels end function omp_get_max_active_levels end interface interface function omp_get_level () - use omp_lib_kinds integer (4) :: omp_get_level end function omp_get_level end interface interface omp_get_ancestor_thread_num function omp_get_ancestor_thread_num (level) - use omp_lib_kinds integer (4), intent (in) :: level integer (4) :: omp_get_ancestor_thread_num end function omp_get_ancestor_thread_num function omp_get_ancestor_thread_num_8 (level) - use omp_lib_kinds integer (8), intent (in) :: level integer (4) :: omp_get_ancestor_thread_num_8 end function omp_get_ancestor_thread_num_8 @@ -271,12 +263,10 @@ interface omp_get_team_size function omp_get_team_size (level) - use omp_lib_kinds integer (4), intent (in) :: level integer (4) :: omp_get_team_size end function omp_get_team_size function omp_get_team_size_8 (level) - use omp_lib_kinds integer (8), intent (in) :: level integer (4) :: omp_get_team_size_8 end function omp_get_team_size_8 @@ -284,16 +274,66 @@ interface function omp_get_active_level () - use omp_lib_kinds integer (4) :: omp_get_active_level end function omp_get_active_level end interface interface function omp_in_final () - use omp_lib_kinds logical (4) :: omp_in_final end function omp_in_final end interface + interface + function omp_get_cancellation () + logical (4) :: omp_get_cancellation + end function omp_get_cancellation + end interface + + interface + function omp_get_proc_bind () + use omp_lib_kinds + integer (omp_proc_bind_kind) :: omp_get_proc_bind + end function omp_get_proc_bind + end interface + + interface omp_set_default_device + subroutine omp_set_default_device (device_num) + integer (4), intent (in) :: device_num + end subroutine omp_set_default_device + subroutine omp_set_default_device_8 (device_num) + integer (8), intent (in) :: device_num + end subroutine omp_set_default_device_8 + end interface + + interface + function omp_get_default_device () + integer (4) :: omp_get_default_device + end function omp_get_default_device + end interface + + interface + function omp_get_num_devices () + integer (4) :: omp_get_num_devices + end function omp_get_num_devices + end interface + + interface + function omp_get_num_teams () + integer (4) :: omp_get_num_teams + end function omp_get_num_teams + end interface + + interface + function omp_get_team_num () + integer (4) :: omp_get_team_num + end function omp_get_team_num + end interface + + interface + function omp_is_initial_device () + logical (4) :: omp_is_initial_device + end function omp_is_initial_device + end interface + end module omp_lib diff --git a/libgomp/omp_lib.h.in b/libgomp/omp_lib.h.in index f188edcf6612d..804636df82f29 100644 --- a/libgomp/omp_lib.h.in +++ b/libgomp/omp_lib.h.in @@ -33,6 +33,18 @@ parameter (omp_sched_dynamic = 2) parameter (omp_sched_guided = 3) parameter (omp_sched_auto = 4) + integer omp_proc_bind_kind + parameter (omp_proc_bind_kind = 4) + integer (omp_proc_bind_kind) omp_proc_bind_false + integer (omp_proc_bind_kind) omp_proc_bind_true + integer (omp_proc_bind_kind) omp_proc_bind_master + integer (omp_proc_bind_kind) omp_proc_bind_close + integer (omp_proc_bind_kind) omp_proc_bind_spread + parameter (omp_proc_bind_false = 0) + parameter (omp_proc_bind_true = 1) + parameter (omp_proc_bind_master = 2) + parameter (omp_proc_bind_close = 3) + parameter (omp_proc_bind_spread = 4) parameter (openmp_version = 201107) external omp_init_lock, omp_init_nest_lock @@ -68,3 +80,18 @@ external omp_in_final logical(4) omp_in_final + + external omp_get_cancelllation + logical(4) omp_get_cancelllation + + external omp_get_proc_bind + integer(omp_proc_bind_kind) omp_get_proc_bind + + external omp_set_default_device, omp_get_default_device + external omp_get_num_devices, omp_get_num_teams + external omp_get_team_num + integer(4) omp_get_default_device, omp_get_num_devices + integer(4) omp_get_num_teams, omp_get_team_num + + external omp_is_initial_device + logical(4) omp_is_initial_device diff --git a/libgomp/parallel.c b/libgomp/parallel.c index 4573511902589..b034f92dc86f5 100644 --- a/libgomp/parallel.c +++ b/libgomp/parallel.c @@ -129,7 +129,28 @@ GOMP_parallel_end (void) } gomp_team_end (); } +ialias (GOMP_parallel_end) +void +GOMP_parallel (void (*fn) (void *), void *data, unsigned num_threads, unsigned int flags) +{ + (void) flags; + num_threads = gomp_resolve_num_threads (num_threads, 0); + gomp_team_start (fn, data, num_threads, gomp_new_team (num_threads)); + fn (data); + ialias_call (GOMP_parallel_end) (); +} + +void +GOMP_cancel (void) +{ + /* Nothing so far. */ +} + +void +GOMP_cancellation_point (void) +{ +} /* The public OpenMP API for thread and team related inquiries. */ diff --git a/libgomp/sections.c b/libgomp/sections.c index 369f7a4426fd7..5da87cd060918 100644 --- a/libgomp/sections.c +++ b/libgomp/sections.c @@ -142,6 +142,23 @@ GOMP_parallel_sections_start (void (*fn) (void *), void *data, gomp_team_start (fn, data, num_threads, team); } +ialias_redirect (GOMP_parallel_end) + +void +GOMP_parallel_sections (void (*fn) (void *), void *data, + unsigned num_threads, unsigned count, unsigned flags) +{ + struct gomp_team *team; + + (void) flags; + num_threads = gomp_resolve_num_threads (num_threads, count); + team = gomp_new_team (num_threads); + gomp_sections_init (&team->work_shares[0], count); + gomp_team_start (fn, data, num_threads, team); + fn (data); + GOMP_parallel_end (); +} + /* The GOMP_section_end* routines are called after the thread is told that all sections are complete. This first version synchronizes all threads; the nowait version does not. */ diff --git a/libgomp/task.c b/libgomp/task.c index 7de650a43f145..fb7dcf581da65 100644 --- a/libgomp/task.c +++ b/libgomp/task.c @@ -398,6 +398,16 @@ GOMP_taskyield (void) /* Nothing at the moment. */ } +void +GOMP_taskgroup_start (void) +{ +} + +void +GOMP_taskgroup_end (void) +{ +} + int omp_in_final (void) { diff --git a/libgomp/testsuite/libgomp.c++/atomic-10.C b/libgomp/testsuite/libgomp.c++/atomic-10.C new file mode 100644 index 0000000000000..2145f28823329 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/atomic-10.C @@ -0,0 +1,99 @@ +// { dg-do run } + +extern "C" void abort (void); +int x = 6; + +int +main () +{ + int v, l = 2, s = 1; + #pragma omp atomic + x = -3 + x; + #pragma omp atomic read + v = x; + if (v != 3) + abort (); + #pragma omp atomic update + x = 3 * 2 * 1 + x; + #pragma omp atomic read + v = x; + if (v != 9) + abort (); + #pragma omp atomic capture + v = x = x | 16; + if (v != 25) + abort (); + #pragma omp atomic capture + v = x = x + 14 * 2 / 4; + if (v != 32) + abort (); + #pragma omp atomic capture + v = x = 5 | x; + if (v != 37) + abort (); + #pragma omp atomic capture + v = x = 40 + 12 - 2 - 7 - x; + if (v != 6) + abort (); + #pragma omp atomic read + v = x; + if (v != 6) + abort (); + #pragma omp atomic capture + { v = x; x = 3 + x; } + if (v != 6) + abort (); + #pragma omp atomic capture + { v = x; x = -1 * -1 * -1 * -1 - x; } + if (v != 9) + abort (); + #pragma omp atomic read + v = x; + if (v != -8) + abort (); + #pragma omp atomic capture + { x = 2 * 2 - x; v = x; } + if (v != 12) + abort (); + #pragma omp atomic capture + { x = 7 & x; v = x; } + if (v != 4) + abort (); + #pragma omp atomic capture + { v = x; x = 6; } + if (v != 4) + abort (); + #pragma omp atomic read + v = x; + if (v != 6) + abort (); + #pragma omp atomic capture + { v = x; x = 7 * 8 + 23; } + if (v != 6) + abort (); + #pragma omp atomic read + v = x; + if (v != 79) + abort (); + #pragma omp atomic capture + { v = x; x = 23 + 6 * 4; } + if (v != 79) + abort (); + #pragma omp atomic read + v = x; + if (v != 47) + abort (); + #pragma omp atomic capture + { v = x; x = l ? 17 : 12; } + if (v != 47) + abort (); + #pragma omp atomic capture + { v = x; x = l = s++ + 3; } + if (v != 17 || l != 4 || s != 2) + abort (); + #pragma omp atomic read + v = x; + if (v != 4) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/atomic-11.C b/libgomp/testsuite/libgomp.c++/atomic-11.C new file mode 100644 index 0000000000000..c7101e01408bb --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/atomic-11.C @@ -0,0 +1,108 @@ +// { dg-do run } + +extern "C" void abort (void); + +template +void +foo () +{ + extern T x; + T v, l = 2, s = 1; + #pragma omp atomic + x = -3 + x; + #pragma omp atomic read + v = x; + if (v != 3) + abort (); + #pragma omp atomic update + x = 3 * 2 * 1 + x; + #pragma omp atomic read + v = x; + if (v != 9) + abort (); + #pragma omp atomic capture + v = x = x | 16; + if (v != 25) + abort (); + #pragma omp atomic capture + v = x = x + 14 * 2 / 4; + if (v != 32) + abort (); + #pragma omp atomic capture + v = x = 5 | x; + if (v != 37) + abort (); + #pragma omp atomic capture + v = x = 40 + 12 - 2 - 7 - x; + if (v != 6) + abort (); + #pragma omp atomic read + v = x; + if (v != 6) + abort (); + #pragma omp atomic capture + { v = x; x = 3 + x; } + if (v != 6) + abort (); + #pragma omp atomic capture + { v = x; x = -1 * -1 * -1 * -1 - x; } + if (v != 9) + abort (); + #pragma omp atomic read + v = x; + if (v != -8) + abort (); + #pragma omp atomic capture + { x = 2 * 2 - x; v = x; } + if (v != 12) + abort (); + #pragma omp atomic capture + { x = 7 & x; v = x; } + if (v != 4) + abort (); + #pragma omp atomic capture + { v = x; x = 6; } + if (v != 4) + abort (); + #pragma omp atomic read + v = x; + if (v != 6) + abort (); + #pragma omp atomic capture + { v = x; x = 7 * 8 + 23; } + if (v != 6) + abort (); + #pragma omp atomic read + v = x; + if (v != 79) + abort (); + #pragma omp atomic capture + { v = x; x = 23 + 6 * 4; } + if (v != 79) + abort (); + #pragma omp atomic read + v = x; + if (v != 47) + abort (); + #pragma omp atomic capture + { v = x; x = l ? 17 : 12; } + if (v != 47) + abort (); + #pragma omp atomic capture + { v = x; x = l = s++ + 3; } + if (v != 17 || l != 4 || s != 2) + abort (); + #pragma omp atomic read + v = x; + if (v != 4) + abort (); +} + +int x = 6; + +int +main () +{ + foo (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/atomic-12.C b/libgomp/testsuite/libgomp.c++/atomic-12.C new file mode 100644 index 0000000000000..d1ae9d8c88ca0 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/atomic-12.C @@ -0,0 +1,58 @@ +// { dg-do run } + +extern "C" void abort (); +int x = 6, cnt; + +int +foo () +{ + return cnt++; +} + +int +main () +{ + int v, *p; + p = &x; + #pragma omp atomic update + p[foo (), 0] = 16 + 6 - p[foo (), 0]; + #pragma omp atomic read + v = x; + if (cnt != 2 || v != 16) + abort (); + #pragma omp atomic capture + v = p[foo () + foo (), 0] = p[foo () + foo (), 0] + 3; + if (cnt != 6 || v != 19) + abort (); + #pragma omp atomic capture + v = p[foo (), 0] = 12 * 1 / 2 + (foo (), 0) + p[foo (), 0]; + if (cnt != 9 || v != 25) + abort (); + #pragma omp atomic capture + { + v = p[foo () & 0]; p[foo () & 0] = (foo (), 1) * 9 - p[foo () & 0]; + } + if (cnt != 13 || v != 25) + abort (); + #pragma omp atomic read + v = x; + if (v != -16) + abort (); + #pragma omp atomic capture + { + p[0 & foo ()] = 16 - 2 + 3 + p[0 & foo ()]; v = p[0 & foo ()]; + } + if (cnt != 16 || v != 1) + abort (); + #pragma omp atomic capture + { + v = p[foo (), 0]; p[foo (), 0] = (foo (), 7) ? 13 : foo () + 6; + } + if (cnt != 19 || v != 1) + abort (); + #pragma omp atomic read + v = x; + if (v != 13) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/atomic-13.C b/libgomp/testsuite/libgomp.c++/atomic-13.C new file mode 100644 index 0000000000000..0569d1c6deb43 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/atomic-13.C @@ -0,0 +1,68 @@ +// { dg-do run } + +extern "C" void abort (); +int cnt; + +int +foo () +{ + return cnt++; +} + +template +void +bar () +{ + extern T x; + T v, *p; + p = &x; + #pragma omp atomic update + p[foo (), 0] = 16 + 6 - p[foo (), 0]; + #pragma omp atomic read + v = x; + if (cnt != 2 || v != 16) + abort (); + #pragma omp atomic capture + v = p[foo () + foo (), 0] = p[foo () + foo (), 0] + 3; + if (cnt != 6 || v != 19) + abort (); + #pragma omp atomic capture + v = p[foo (), 0] = 12 * 1 / 2 + (foo (), 0) + p[foo (), 0]; + if (cnt != 9 || v != 25) + abort (); + #pragma omp atomic capture + { + v = p[foo () & 0]; p[foo () & 0] = (foo (), 1) * 9 - p[foo () & 0]; + } + if (cnt != 13 || v != 25) + abort (); + #pragma omp atomic read + v = x; + if (v != -16) + abort (); + #pragma omp atomic capture + { + p[0 & foo ()] = 16 - 2 + 3 + p[0 & foo ()]; v = p[0 & foo ()]; + } + if (cnt != 16 || v != 1) + abort (); + #pragma omp atomic capture + { + v = p[foo (), 0]; p[foo (), 0] = (foo (), 7) ? 13 : foo () + 6; + } + if (cnt != 19 || v != 1) + abort (); + #pragma omp atomic read + v = x; + if (v != 13) + abort (); +} + +int x = 6; + +int +main () +{ + bar (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/atomic-14.C b/libgomp/testsuite/libgomp.c++/atomic-14.C new file mode 100644 index 0000000000000..dccea3acd803a --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/atomic-14.C @@ -0,0 +1,99 @@ +// { dg-do run } + +extern "C" void abort (void); +int x = 6; + +int +main () +{ + int v, l = 2, s = 1; + #pragma omp atomic seq_cst + x = -3 + x; + #pragma omp atomic read seq_cst + v = x; + if (v != 3) + abort (); + #pragma omp atomic seq_cst update + x = 3 * 2 * 1 + x; + #pragma omp atomic read, seq_cst + v = x; + if (v != 9) + abort (); + #pragma omp atomic seq_cst, capture + v = x = x | 16; + if (v != 25) + abort (); + #pragma omp atomic capture seq_cst + v = x = x + 14 * 2 / 4; + if (v != 32) + abort (); + #pragma omp atomic seq_cst capture + v = x = 5 | x; + if (v != 37) + abort (); + #pragma omp atomic capture, seq_cst + v = x = 40 + 12 - 2 - 7 - x; + if (v != 6) + abort (); + #pragma omp atomic seq_cst read + v = x; + if (v != 6) + abort (); + #pragma omp atomic capture seq_cst + { v = x; x = 3 + x; } + if (v != 6) + abort (); + #pragma omp atomic seq_cst capture + { v = x; x = -1 * -1 * -1 * -1 - x; } + if (v != 9) + abort (); + #pragma omp atomic read seq_cst + v = x; + if (v != -8) + abort (); + #pragma omp atomic capture, seq_cst + { x = 2 * 2 - x; v = x; } + if (v != 12) + abort (); + #pragma omp atomic seq_cst capture + { x = 7 & x; v = x; } + if (v != 4) + abort (); + #pragma omp atomic capture seq_cst + { v = x; x = 6; } + if (v != 4) + abort (); + #pragma omp atomic read, seq_cst + v = x; + if (v != 6) + abort (); + #pragma omp atomic capture seq_cst + { v = x; x = 7 * 8 + 23; } + if (v != 6) + abort (); + #pragma omp atomic seq_cst, read + v = x; + if (v != 79) + abort (); + #pragma omp atomic capture , seq_cst + { v = x; x = 23 + 6 * 4; } + if (v != 79) + abort (); + #pragma omp atomic read seq_cst + v = x; + if (v != 47) + abort (); + #pragma omp atomic seq_cst capture + { v = x; x = l ? 17 : 12; } + if (v != 47) + abort (); + #pragma omp atomic capture seq_cst + { v = x; x = l = s++ + 3; } + if (v != 17 || l != 4 || s != 2) + abort (); + #pragma omp atomic read seq_cst + v = x; + if (v != 4) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/atomic-15.C b/libgomp/testsuite/libgomp.c++/atomic-15.C new file mode 100644 index 0000000000000..9abefb6468897 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/atomic-15.C @@ -0,0 +1,108 @@ +// { dg-do run } + +extern "C" void abort (void); + +template +void +foo () +{ + extern T x; + T v, l = 2, s = 1; + #pragma omp atomic seq_cst + x = -3 + x; + #pragma omp atomic read seq_cst + v = x; + if (v != 3) + abort (); + #pragma omp atomic seq_cst update + x = 3 * 2 * 1 + x; + #pragma omp atomic read, seq_cst + v = x; + if (v != 9) + abort (); + #pragma omp atomic seq_cst, capture + v = x = x | 16; + if (v != 25) + abort (); + #pragma omp atomic capture seq_cst + v = x = x + 14 * 2 / 4; + if (v != 32) + abort (); + #pragma omp atomic seq_cst capture + v = x = 5 | x; + if (v != 37) + abort (); + #pragma omp atomic capture, seq_cst + v = x = 40 + 12 - 2 - 7 - x; + if (v != 6) + abort (); + #pragma omp atomic seq_cst read + v = x; + if (v != 6) + abort (); + #pragma omp atomic capture seq_cst + { v = x; x = 3 + x; } + if (v != 6) + abort (); + #pragma omp atomic seq_cst capture + { v = x; x = -1 * -1 * -1 * -1 - x; } + if (v != 9) + abort (); + #pragma omp atomic read seq_cst + v = x; + if (v != -8) + abort (); + #pragma omp atomic capture, seq_cst + { x = 2 * 2 - x; v = x; } + if (v != 12) + abort (); + #pragma omp atomic seq_cst capture + { x = 7 & x; v = x; } + if (v != 4) + abort (); + #pragma omp atomic capture seq_cst + { v = x; x = 6; } + if (v != 4) + abort (); + #pragma omp atomic read, seq_cst + v = x; + if (v != 6) + abort (); + #pragma omp atomic capture seq_cst + { v = x; x = 7 * 8 + 23; } + if (v != 6) + abort (); + #pragma omp atomic seq_cst, read + v = x; + if (v != 79) + abort (); + #pragma omp atomic capture , seq_cst + { v = x; x = 23 + 6 * 4; } + if (v != 79) + abort (); + #pragma omp atomic read seq_cst + v = x; + if (v != 47) + abort (); + #pragma omp atomic seq_cst capture + { v = x; x = l ? 17 : 12; } + if (v != 47) + abort (); + #pragma omp atomic capture seq_cst + { v = x; x = l = s++ + 3; } + if (v != 17 || l != 4 || s != 2) + abort (); + #pragma omp atomic read seq_cst + v = x; + if (v != 4) + abort (); +} + +int x = 6; + +int +main () +{ + foo (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/for-10.C b/libgomp/testsuite/libgomp.c++/for-10.C new file mode 100644 index 0000000000000..fb1a3e952b177 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/for-10.C @@ -0,0 +1,44 @@ +extern "C" void abort (); + +#define M(x, y, z) O(x, y, z) +#define O(x, y, z) x ## _ ## y ## _ ## z + +#define F simd +#define G 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 parallel for simd +#define G pf_simd +#include "../libgomp.c/for-1.h" +#undef F +#undef G + +#define F for simd +#define G f_simd +#include "../libgomp.c/for-1.h" +#undef F +#undef G + +int +main () +{ + if (test_simd_normal () + || test_pf_simd_static () + || test_pf_simd_static32 () + || test_pf_simd_auto () + || test_pf_simd_guided32 () + || test_pf_simd_runtime () + || test_f_simd_static () + || test_f_simd_static32 () + || test_f_simd_auto () + || test_f_simd_guided32 () + || test_f_simd_runtime ()) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/for-11.C b/libgomp/testsuite/libgomp.c++/for-11.C new file mode 100644 index 0000000000000..848fc04d81ced --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/for-11.C @@ -0,0 +1,111 @@ +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 distribute +#define G d +#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 distribute +#define G d_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 distribute simd +#define G ds +#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 distribute simd +#define G ds_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 distribute parallel for +#define G dpf +#include "../libgomp.c/for-1.h" +#undef F +#undef G + +#define F distribute parallel for dist_schedule(static, 128) +#define G dpf_ds128 +#include "../libgomp.c/for-1.h" +#undef F +#undef G + +#define F distribute parallel for simd +#define G dpfs +#include "../libgomp.c/for-1.h" +#undef F +#undef G + +#define F distribute parallel for simd dist_schedule(static, 128) +#define G dpfs_ds128 +#include "../libgomp.c/for-1.h" +#undef F +#undef G + +#pragma omp end declare target + +int +main () +{ + int err = 0; +// FIXME: distribute construct must be closely nested +// in teams region, but we don't handle target expansions +// yet. Enable when it works. +// #pragma omp target teams reduction(|:err) + { + err |= test_d_normal (); + err |= test_d_ds128_normal (); + err |= test_ds_normal (); + err |= test_ds_ds128_normal (); + err |= test_dpf_static (); + err |= test_dpf_static32 (); + err |= test_dpf_auto (); + err |= test_dpf_guided32 (); + err |= test_dpf_runtime (); + err |= test_dpf_ds128_static (); + err |= test_dpf_ds128_static32 (); + err |= test_dpf_ds128_auto (); + err |= test_dpf_ds128_guided32 (); + err |= test_dpf_ds128_runtime (); + err |= test_dpfs_static (); + err |= test_dpfs_static32 (); + err |= test_dpfs_auto (); + err |= test_dpfs_guided32 (); + err |= test_dpfs_runtime (); + err |= test_dpfs_ds128_static (); + err |= test_dpfs_ds128_static32 (); + err |= test_dpfs_ds128_auto (); + err |= test_dpfs_ds128_guided32 (); + err |= test_dpfs_ds128_runtime (); + } + if (err) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/for-9.C b/libgomp/testsuite/libgomp.c++/for-9.C new file mode 100644 index 0000000000000..86b9d9318cb9f --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/for-9.C @@ -0,0 +1,33 @@ +extern "C" void abort (); + +#define M(x, y, z) O(x, y, z) +#define O(x, y, z) x ## _ ## y ## _ ## z + +#define F parallel for +#define G pf +#include "../libgomp.c/for-1.h" +#undef F +#undef G + +#define F for +#define G f +#include "../libgomp.c/for-1.h" +#undef F +#undef G + +int +main () +{ + if (test_pf_static () + || test_pf_static32 () + || test_pf_auto () + || test_pf_guided32 () + || test_pf_runtime () + || test_f_static () + || test_f_static32 () + || test_f_auto () + || test_f_guided32 () + || test_f_runtime ()) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/simd-1.C b/libgomp/testsuite/libgomp.c++/simd-1.C new file mode 100644 index 0000000000000..16ef159b82747 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/simd-1.C @@ -0,0 +1,79 @@ +// { dg-do run } +// { dg-options "-O2" } +// { dg-additional-options "-msse2" { target sse2_runtime } } +// { dg-additional-options "-mavx" { target avx_runtime } } + +extern "C" void abort (); +int a[1024] __attribute__((aligned (32))) = { 1 }; +int b[1024] __attribute__((aligned (32))) = { 1 }; +int k, m; +struct U { U (); ~U (); int u; }; +struct V +{ + V () : v (8) {} + ~V () + { + if (v > 38 + 4 + 3 * 1024 + 1) + abort (); + } + V &operator= (const V &x) { v = x.v + 1; return *this; } + int v; +}; + +__attribute__((noinline, noclone)) +U::U () : u (6) +{ +} + +__attribute__((noinline, noclone)) +U::~U () +{ + if (u > 38 + 4 + 3 * 1023) + abort (); +} + +__attribute__((noinline, noclone)) int +foo (int *p) +{ + int i, s = 0; + U u; + V v; + #pragma omp simd aligned(a, p : 32) linear(k: m + 1) \ + reduction(+:s) lastprivate(u, v) + for (i = 0; i < 1024; i++) + { + a[i] *= p[i]; + u.u = p[i] + k; + k += m + 1; + v.v = p[i] + k; + s += p[i] + k; + } + if (u.u != 36 + 4 + 3 * 1023 || v.v != 36 + 4 + 3 * 1024 + 1) + abort (); + return s; +} + +int +main () +{ +#if __SIZEOF_INT__ >= 4 + int i; + k = 4; + m = 2; + for (i = 0; i < 1024; i++) + { + a[i] = i - 512; + b[i] = (i - 51) % 39; + } + int s = foo (b); + for (i = 0; i < 1024; i++) + { + if (b[i] != (i - 51) % 39 + || a[i] != (i - 512) * b[i]) + abort (); + } + if (k != 4 + 3 * 1024 || s != 1596127) + abort (); +#endif + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/simd-2.C b/libgomp/testsuite/libgomp.c++/simd-2.C new file mode 100644 index 0000000000000..6b12415bdceb1 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/simd-2.C @@ -0,0 +1,36 @@ +// { dg-do run } +// { dg-options "-O2" } +// { dg-additional-options "-msse2" { target sse2_runtime } } +// { dg-additional-options "-mavx" { target avx_runtime } } + +extern "C" void abort (); +__UINTPTR_TYPE__ arr[1027]; + +__attribute__((noinline, noclone)) void +foo () +{ + int i, v; + #pragma omp simd private (v) safelen(16) + for (i = 0; i < 1027; i++) + arr[i] = (__UINTPTR_TYPE__) &v; +} + +int +main () +{ + int i, j, cnt = 0; + __UINTPTR_TYPE__ arr2[16]; + foo (); + for (i = 0; i < 1027; i++) + { + for (j = 0; j < cnt; j++) + if (arr[i] == arr2[j]) + break; + if (j != cnt) + continue; + if (cnt == 16) + abort (); + arr2[cnt++] = arr[i]; + } + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/simd-3.C b/libgomp/testsuite/libgomp.c++/simd-3.C new file mode 100644 index 0000000000000..1c6d8e01af908 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/simd-3.C @@ -0,0 +1,131 @@ +// { dg-do run } +// { dg-options "-O2" } +// { dg-additional-options "-msse2" { target sse2_runtime } } +// { dg-additional-options "-mavx" { target avx_runtime } } + +extern "C" void abort (); +int a[1024] __attribute__((aligned (32))) = { 1 }; +int b[1024] __attribute__((aligned (32))) = { 1 }; +unsigned char c[1024] __attribute__((aligned (32))) = { 1 }; +int k, m; +__UINTPTR_TYPE__ u, u2, u3; + +__attribute__((noinline, noclone)) int +foo (int *p) +{ + int i, s = 0, s2 = 0, t, t2; + #pragma omp simd aligned(a, b, p : 32) linear(k: m + 1) reduction(+:s) \ + lastprivate (t2) + for (i = 0; i < 512; i++) + { + a[i] *= p[i]; + t2 = k + p[i]; + k += m + 1; + s += p[i] + k; + c[i]++; + } + #pragma omp simd aligned(a, b, p : 32) linear(k: m + 1) reduction(+:s2) \ + lastprivate (t, u, u2, u3) + for (i = 512; i < 1024; i++) + { + a[i] *= p[i]; + k += m + 1; + t = k + p[i]; + u = (__UINTPTR_TYPE__) &k; + u2 = (__UINTPTR_TYPE__) &s2; + u3 = (__UINTPTR_TYPE__) &t; + s2 += t; + c[i]++; + } + return s + s2 + t + t2; +} + +__attribute__((noinline, noclone)) long int +bar (int *p, long int n, long int o) +{ + long int i, s = 0, s2 = 0, t, t2; + #pragma omp simd aligned(a, b, p : 32) linear(k: m + 1) reduction(+:s) \ + lastprivate (t2) + for (i = 0; i < n; i++) + { + a[i] *= p[i]; + t2 = k + p[i]; + k += m + 1; + s += p[i] + k; + c[i]++; + } + #pragma omp simd aligned(a, b, p : 32) linear(k: m + 1) reduction(+:s2) \ + lastprivate (t, u, u2, u3) + for (i = n; i < o; i++) + { + a[i] *= p[i]; + k += m + 1; + t = k + p[i]; + u = (__UINTPTR_TYPE__) &k; + u2 = (__UINTPTR_TYPE__) &s2; + u3 = (__UINTPTR_TYPE__) &t; + s2 += t; + c[i]++; + } + return s + s2 + t + t2; +} + +int +main () +{ +#if __SIZEOF_INT__ >= 4 + int i; + k = 4; + m = 2; + for (i = 0; i < 1024; i++) + { + a[i] = i - 512; + b[i] = (i - 51) % 39; + c[i] = (unsigned char) i; + } + int s = foo (b); + for (i = 0; i < 1024; i++) + { + if (b[i] != (i - 51) % 39 + || a[i] != (i - 512) * b[i] + || c[i] != (unsigned char) (i + 1)) + abort (); + a[i] = i - 512; + } + if (k != 4 + 3 * 1024 + || s != 1596127 + (4 + 3 * 511 + b[511]) + (4 + 3 * 1024 + b[1023])) + abort (); + k = 4; + s = bar (b, 512, 1024); + for (i = 0; i < 1024; i++) + { + if (b[i] != (i - 51) % 39 + || a[i] != (i - 512) * b[i] + || c[i] != (unsigned char) (i + 2)) + abort (); + a[i] = i - 512; + } + if (k != 4 + 3 * 1024 + || s != 1596127 + (4 + 3 * 511 + b[511]) + (4 + 3 * 1024 + b[1023])) + abort (); + k = 4; + s = bar (b, 511, 1021); + for (i = 0; i < 1021; i++) + { + if (b[i] != (i - 51) % 39 + || a[i] != (i - 512) * b[i] + || c[i] != (unsigned char) (i + 3)) + abort (); + a[i] = i - 512; + } + for (i = 1021; i < 1024; i++) + if (b[i] != (i - 51) % 39 + || a[i] != i - 512 + || c[i] != (unsigned char) (i + 2)) + abort (); + if (k != 4 + 3 * 1021 + || s != 1586803 + (4 + 3 * 510 + b[510]) + (4 + 3 * 1021 + b[1020])) + abort (); +#endif + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/atomic-14.c b/libgomp/testsuite/libgomp.c/atomic-14.c index 593665046c5c3..9046d80220d4c 100644 --- a/libgomp/testsuite/libgomp.c/atomic-14.c +++ b/libgomp/testsuite/libgomp.c/atomic-14.c @@ -16,7 +16,7 @@ main () #pragma omp atomic update x = x + 7; #pragma omp atomic - x = x + 7 + 6; + x = x + (7 + 6); #pragma omp atomic update x = x + 2 * 3; #pragma omp atomic @@ -65,7 +65,7 @@ main () if (v != -8) abort (); #pragma omp atomic - x = x * -4 / 2; + x = x * (-4 / 2); #pragma omp atomic read v = x; if (v != 16) diff --git a/libgomp/testsuite/libgomp.c/atomic-15.c b/libgomp/testsuite/libgomp.c/atomic-15.c new file mode 100644 index 0000000000000..58331f4a90bfd --- /dev/null +++ b/libgomp/testsuite/libgomp.c/atomic-15.c @@ -0,0 +1,99 @@ +// { dg-do run } + +extern void abort (void); +int x = 6; + +int +main () +{ + int v, l = 2, s = 1; + #pragma omp atomic + x = -3 + x; + #pragma omp atomic read + v = x; + if (v != 3) + abort (); + #pragma omp atomic update + x = 3 * 2 * 1 + x; + #pragma omp atomic read + v = x; + if (v != 9) + abort (); + #pragma omp atomic capture + v = x = x | 16; + if (v != 25) + abort (); + #pragma omp atomic capture + v = x = x + 14 * 2 / 4; + if (v != 32) + abort (); + #pragma omp atomic capture + v = x = 5 | x; + if (v != 37) + abort (); + #pragma omp atomic capture + v = x = 40 + 12 - 2 - 7 - x; + if (v != 6) + abort (); + #pragma omp atomic read + v = x; + if (v != 6) + abort (); + #pragma omp atomic capture + { v = x; x = 3 + x; } + if (v != 6) + abort (); + #pragma omp atomic capture + { v = x; x = -1 * -1 * -1 * -1 - x; } + if (v != 9) + abort (); + #pragma omp atomic read + v = x; + if (v != -8) + abort (); + #pragma omp atomic capture + { x = 2 * 2 - x; v = x; } + if (v != 12) + abort (); + #pragma omp atomic capture + { x = 7 & x; v = x; } + if (v != 4) + abort (); + #pragma omp atomic capture + { v = x; x = 6; } + if (v != 4) + abort (); + #pragma omp atomic read + v = x; + if (v != 6) + abort (); + #pragma omp atomic capture + { v = x; x = 7 * 8 + 23; } + if (v != 6) + abort (); + #pragma omp atomic read + v = x; + if (v != 79) + abort (); + #pragma omp atomic capture + { v = x; x = 23 + 6 * 4; } + if (v != 79) + abort (); + #pragma omp atomic read + v = x; + if (v != 47) + abort (); + #pragma omp atomic capture + { v = x; x = l ? 17 : 12; } + if (v != 47) + abort (); + #pragma omp atomic capture + { v = x; x = l = s++ + 3; } + if (v != 17 || l != 4 || s != 2) + abort (); + #pragma omp atomic read + v = x; + if (v != 4) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/atomic-16.c b/libgomp/testsuite/libgomp.c/atomic-16.c new file mode 100644 index 0000000000000..d33f670ec1f5a --- /dev/null +++ b/libgomp/testsuite/libgomp.c/atomic-16.c @@ -0,0 +1,58 @@ +// { dg-do run } + +extern void abort (void); +int x = 6, cnt; + +int +foo (void) +{ + return cnt++; +} + +int +main () +{ + int v, *p; + p = &x; + #pragma omp atomic update + p[foo (), 0] = 16 + 6 - p[foo (), 0]; + #pragma omp atomic read + v = x; + if (cnt != 2 || v != 16) + abort (); + #pragma omp atomic capture + v = p[foo () + foo (), 0] = p[foo () + foo (), 0] + 3; + if (cnt != 6 || v != 19) + abort (); + #pragma omp atomic capture + v = p[foo (), 0] = 12 * 1 / 2 + (foo (), 0) + p[foo (), 0]; + if (cnt != 9 || v != 25) + abort (); + #pragma omp atomic capture + { + v = p[foo () & 0]; p[foo () & 0] = (foo (), 1) * 9 - p[foo () & 0]; + } + if (cnt != 13 || v != 25) + abort (); + #pragma omp atomic read + v = x; + if (v != -16) + abort (); + #pragma omp atomic capture + { + p[0 & foo ()] = 16 - 2 + 3 + p[0 & foo ()]; v = p[0 & foo ()]; + } + if (cnt != 16 || v != 1) + abort (); + #pragma omp atomic capture + { + v = p[foo (), 0]; p[foo (), 0] = (foo (), 7) ? 13 : foo () + 6; + } + if (cnt != 19 || v != 1) + abort (); + #pragma omp atomic read + v = x; + if (v != 13) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/atomic-17.c b/libgomp/testsuite/libgomp.c/atomic-17.c new file mode 100644 index 0000000000000..147ab26a95302 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/atomic-17.c @@ -0,0 +1,99 @@ +// { dg-do run } + +extern void abort (void); +int x = 6; + +int +main () +{ + int v, l = 2, s = 1; + #pragma omp atomic seq_cst + x = -3 + x; + #pragma omp atomic read seq_cst + v = x; + if (v != 3) + abort (); + #pragma omp atomic seq_cst update + x = 3 * 2 * 1 + x; + #pragma omp atomic read, seq_cst + v = x; + if (v != 9) + abort (); + #pragma omp atomic seq_cst, capture + v = x = x | 16; + if (v != 25) + abort (); + #pragma omp atomic capture seq_cst + v = x = x + 14 * 2 / 4; + if (v != 32) + abort (); + #pragma omp atomic seq_cst capture + v = x = 5 | x; + if (v != 37) + abort (); + #pragma omp atomic capture, seq_cst + v = x = 40 + 12 - 2 - 7 - x; + if (v != 6) + abort (); + #pragma omp atomic seq_cst read + v = x; + if (v != 6) + abort (); + #pragma omp atomic capture seq_cst + { v = x; x = 3 + x; } + if (v != 6) + abort (); + #pragma omp atomic seq_cst capture + { v = x; x = -1 * -1 * -1 * -1 - x; } + if (v != 9) + abort (); + #pragma omp atomic read seq_cst + v = x; + if (v != -8) + abort (); + #pragma omp atomic capture, seq_cst + { x = 2 * 2 - x; v = x; } + if (v != 12) + abort (); + #pragma omp atomic seq_cst capture + { x = 7 & x; v = x; } + if (v != 4) + abort (); + #pragma omp atomic capture seq_cst + { v = x; x = 6; } + if (v != 4) + abort (); + #pragma omp atomic read, seq_cst + v = x; + if (v != 6) + abort (); + #pragma omp atomic capture seq_cst + { v = x; x = 7 * 8 + 23; } + if (v != 6) + abort (); + #pragma omp atomic seq_cst, read + v = x; + if (v != 79) + abort (); + #pragma omp atomic capture , seq_cst + { v = x; x = 23 + 6 * 4; } + if (v != 79) + abort (); + #pragma omp atomic read seq_cst + v = x; + if (v != 47) + abort (); + #pragma omp atomic seq_cst capture + { v = x; x = l ? 17 : 12; } + if (v != 47) + abort (); + #pragma omp atomic capture seq_cst + { v = x; x = l = s++ + 3; } + if (v != 17 || l != 4 || s != 2) + abort (); + #pragma omp atomic read seq_cst + v = x; + if (v != 4) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/for-1.c b/libgomp/testsuite/libgomp.c/for-1.c new file mode 100644 index 0000000000000..e702453fb1a63 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/for-1.c @@ -0,0 +1,35 @@ +/* { 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 parallel for +#define G pf +#include "for-1.h" +#undef F +#undef G + +#define F for +#define G f +#include "for-1.h" +#undef F +#undef G + +int +main () +{ + if (test_pf_static () + || test_pf_static32 () + || test_pf_auto () + || test_pf_guided32 () + || test_pf_runtime () + || test_f_static () + || test_f_static32 () + || test_f_auto () + || test_f_guided32 () + || test_f_runtime ()) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/for-1.h b/libgomp/testsuite/libgomp.c/for-1.h new file mode 100644 index 0000000000000..fa82c5b20d743 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/for-1.h @@ -0,0 +1,25 @@ +#define S +#define N(x) M(x, G, static) +#include "for-2.h" +#undef S +#undef N +#define S schedule(static, 32) +#define N(x) M(x, G, static32) +#include "for-2.h" +#undef S +#undef N +#define S schedule(auto) +#define N(x) M(x, G, auto) +#include "for-2.h" +#undef S +#undef N +#define S schedule(guided, 32) +#define N(x) M(x, G, guided32) +#include "for-2.h" +#undef S +#undef N +#define S schedule(runtime) +#define N(x) M(x, G, runtime) +#include "for-2.h" +#undef S +#undef N diff --git a/libgomp/testsuite/libgomp.c/for-2.c b/libgomp/testsuite/libgomp.c/for-2.c new file mode 100644 index 0000000000000..f5a01ab05ec32 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/for-2.c @@ -0,0 +1,46 @@ +/* { 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 simd +#define G simd +#define S +#define N(x) M(x, G, normal) +#include "for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F parallel for simd +#define G pf_simd +#include "for-1.h" +#undef F +#undef G + +#define F for simd +#define G f_simd +#include "for-1.h" +#undef F +#undef G + +int +main () +{ + if (test_simd_normal () + || test_pf_simd_static () + || test_pf_simd_static32 () + || test_pf_simd_auto () + || test_pf_simd_guided32 () + || test_pf_simd_runtime () + || test_f_simd_static () + || test_f_simd_static32 () + || test_f_simd_auto () + || test_f_simd_guided32 () + || test_f_simd_runtime ()) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/for-2.h b/libgomp/testsuite/libgomp.c/for-2.h new file mode 100644 index 0000000000000..57c385ec87640 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/for-2.h @@ -0,0 +1,269 @@ +#ifndef VARS +#define VARS +int a[1500]; +float b[10][15][10]; +__attribute__((noreturn)) void +noreturn (void) +{ + for (;;); +} +#endif + +__attribute__((noinline, noclone)) void +N(f0) (void) +{ + int i; +#pragma omp F S + for (i = 0; i < 1500; i++) + a[i] += 2; +} + +__attribute__((noinline, noclone)) void +N(f1) (void) +{ +#pragma omp F S + for (unsigned int i = __INT_MAX__; i < 3000U + __INT_MAX__; i += 2) + a[(i - __INT_MAX__) >> 1] -= 2; +} + +__attribute__((noinline, noclone)) void +N(f2) (void) +{ + unsigned long long i; +#pragma omp F S + for (i = __LONG_LONG_MAX__ + 4500ULL - 27; + i > __LONG_LONG_MAX__ - 27ULL; i -= 3) + a[(i + 26LL - __LONG_LONG_MAX__) / 3] -= 4; +} + +__attribute__((noinline, noclone)) void +N(f3) (long long n1, long long n2, long long s3) +{ +#pragma omp F S + for (long long i = n1 + 23; i > n2 - 25; i -= s3) + a[i + 48] += 7; +} + +__attribute__((noinline, noclone)) void +N(f4) (void) +{ + unsigned int i; +#pragma omp F S + for (i = 30; i < 20; i += 2) + a[i] += 10; +} + +__attribute__((noinline, noclone)) void +N(f5) (int n11, int n12, int n21, int n22, int n31, int n32, + int s1, int s2, int s3) +{ + int v1, v2, v3; +#pragma omp F S collapse(3) + for (v1 = n11; v1 < n12; v1 += s1) + for (v2 = n21; v2 < n22; v2 += s2) + for (v3 = n31; v3 < n32; v3 += s3) + b[v1][v2][v3] += 2.5; +} + +__attribute__((noinline, noclone)) void +N(f6) (int n11, int n12, int n21, int n22, long long n31, long long n32, + int s1, int s2, long long int s3) +{ + int v1, v2; + long long v3; +#pragma omp F S collapse(3) + for (v1 = n11; v1 > n12; v1 += s1) + for (v2 = n21; v2 > n22; v2 += s2) + for (v3 = n31; v3 > n32; v3 += s3) + b[v1][v2 / 2][v3] -= 4.5; +} + +__attribute__((noinline, noclone)) void +N(f7) (void) +{ + unsigned int v1, v3; + unsigned long long v2; +#pragma omp F S collapse(3) + for (v1 = 0; v1 < 20; v1 += 2) + for (v2 = __LONG_LONG_MAX__ + 16ULL; + v2 > __LONG_LONG_MAX__ - 29ULL; v2 -= 3) + for (v3 = 10; v3 > 0; v3--) + b[v1 >> 1][(v2 - __LONG_LONG_MAX__ + 64) / 3 - 12][v3 - 1] += 5.5; +} + +__attribute__((noinline, noclone)) void +N(f8) (void) +{ + long long v1, v2, v3; +#pragma omp F S collapse(3) + for (v1 = 0; v1 < 20; v1 += 2) + for (v2 = 30; v2 < 20; v2++) + for (v3 = 10; v3 < 0; v3--) + b[v1][v2][v3] += 5.5; +} + +__attribute__((noinline, noclone)) void +N(f9) (void) +{ + int i; +#pragma omp F S + for (i = 20; i < 10; i++) + { + a[i] += 2; + noreturn (); + a[i] -= 4; + } +} + +__attribute__((noinline, noclone)) void +N(f10) (void) +{ + int i; +#pragma omp F S collapse(3) + for (i = 0; i < 10; i++) + for (int j = 10; j < 8; j++) + for (long k = -10; k < 10; k++) + { + b[i][j][k] += 4; + noreturn (); + b[i][j][k] -= 8; + } +} + +__attribute__((noinline, noclone)) void +N(f11) (int n) +{ + int i; +#pragma omp F S + for (i = 20; i < n; i++) + { + a[i] += 8; + noreturn (); + a[i] -= 16; + } +} + +__attribute__((noinline, noclone)) void +N(f12) (int n) +{ + int i; +#pragma omp F S collapse(3) + for (i = 0; i < 10; i++) + for (int j = n; j < 8; j++) + for (long k = -10; k < 10; k++) + { + b[i][j][k] += 16; + noreturn (); + b[i][j][k] -= 32; + } +} + +__attribute__((noinline, noclone)) void +N(f13) (void) +{ + int *i; +#pragma omp F S + for (i = a; i < &a[1500]; i++) + i[0] += 2; +} + +__attribute__((noinline, noclone)) void +N(f14) (void) +{ + float *i; +#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) + for (float *k = &b[0][0][10]; k > &b[0][0][0]; --k) + b[i - &b[0][0][0]][(j - &b[0][0][0]) / 10 - 1][(k - &b[0][0][0]) - 1] + -= 3.5; +} + +__attribute__((noinline, noclone)) int +N(test) (void) +{ + int i, j, k; + for (i = 0; i < 1500; i++) + a[i] = i - 25; + N(f0) (); + for (i = 0; i < 1500; i++) + if (a[i] != i - 23) + return 1; + N(f1) (); + for (i = 0; i < 1500; i++) + if (a[i] != i - 25) + return 1; + N(f2) (); + for (i = 0; i < 1500; i++) + if (a[i] != i - 29) + return 1; + N(f3) (1500LL - 1 - 23 - 48, -1LL + 25 - 48, 1LL); + for (i = 0; i < 1500; i++) + if (a[i] != i - 22) + return 1; + N(f3) (1500LL - 1 - 23 - 48, 1500LL - 1, 7LL); + for (i = 0; i < 1500; i++) + if (a[i] != i - 22) + return 1; + N(f4) (); + for (i = 0; i < 1500; i++) + if (a[i] != i - 22) + return 1; + for (i = 0; i < 10; i++) + 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; + N(f5) (0, 10, 0, 15, 0, 10, 1, 1, 1); + 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); + 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); + 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) (); + 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) (); + 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(f9) (); + N(f10) (); + N(f11) (10); + N(f12) (12); + for (i = 0; i < 1500; i++) + if (a[i] != i - 22) + return 1; + 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(f13) (); + N(f14) (); + for (i = 0; i < 1500; i++) + if (a[i] != i - 20) + return 1; + for (i = 0; i < 10; i++) + for (j = 0; j < 15; j++) + for (k = 0; k < 10; k++) + if (b[i][j][k] != i - 2.5 + 1.5 * j - 1.5 * k) + return 1; + return 0; +}