summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog242
-rw-r--r--gcc/ada/ChangeLog4
-rw-r--r--gcc/ada/gcc-interface/utils.c6
-rw-r--r--gcc/builtin-types.def35
-rw-r--r--gcc/c-family/ChangeLog52
-rw-r--r--gcc/c-family/c-common.c32
-rw-r--r--gcc/c-family/c-common.h148
-rw-r--r--gcc/c-family/c-cppbuiltin.c2
-rw-r--r--gcc/c-family/c-omp.c408
-rw-r--r--gcc/c-family/c-pragma.c9
-rw-r--r--gcc/c-family/c-pragma.h39
-rw-r--r--gcc/c/ChangeLog111
-rw-r--r--gcc/c/c-decl.c176
-rw-r--r--gcc/c/c-lang.h3
-rw-r--r--gcc/c/c-parser.c2526
-rw-r--r--gcc/c/c-tree.h9
-rw-r--r--gcc/c/c-typeck.c1016
-rw-r--r--gcc/cp/ChangeLog169
-rw-r--r--gcc/cp/cp-array-notation.c1
-rw-r--r--gcc/cp/cp-gimplify.c25
-rw-r--r--gcc/cp/cp-objcp-common.h2
-rw-r--r--gcc/cp/cp-tree.h34
-rw-r--r--gcc/cp/decl.c52
-rw-r--r--gcc/cp/decl2.c73
-rw-r--r--gcc/cp/parser.c2569
-rw-r--r--gcc/cp/parser.h18
-rw-r--r--gcc/cp/pt.c293
-rw-r--r--gcc/cp/semantics.c1564
-rw-r--r--gcc/fortran/ChangeLog18
-rw-r--r--gcc/fortran/f95-lang.c18
-rw-r--r--gcc/fortran/trans-openmp.c6
-rw-r--r--gcc/fortran/types.def36
-rw-r--r--gcc/gimple-low.c3
-rw-r--r--gcc/gimple-pretty-print.c119
-rw-r--r--gcc/gimple.c79
-rw-r--r--gcc/gimple.def24
-rw-r--r--gcc/gimple.h266
-rw-r--r--gcc/gimplify.c603
-rw-r--r--gcc/langhooks-def.h3
-rw-r--r--gcc/langhooks.c9
-rw-r--r--gcc/langhooks.h3
-rw-r--r--gcc/lto/ChangeLog4
-rw-r--r--gcc/lto/lto-lang.c6
-rw-r--r--gcc/omp-builtins.def70
-rw-r--r--gcc/omp-low.c2600
-rw-r--r--gcc/testsuite/ChangeLog61
-rw-r--r--gcc/testsuite/c-c++-common/gomp/atomic-15.c34
-rw-r--r--gcc/testsuite/c-c++-common/gomp/atomic-16.c34
-rw-r--r--gcc/testsuite/c-c++-common/gomp/cancel-1.c396
-rw-r--r--gcc/testsuite/c-c++-common/gomp/depend-1.c79
-rw-r--r--gcc/testsuite/c-c++-common/gomp/depend-2.c19
-rw-r--r--gcc/testsuite/c-c++-common/gomp/map-1.c103
-rw-r--r--gcc/testsuite/c-c++-common/gomp/pr58472.c16
-rw-r--r--gcc/testsuite/c-c++-common/gomp/sections1.c73
-rw-r--r--gcc/testsuite/c-c++-common/gomp/simd1.c31
-rw-r--r--gcc/testsuite/c-c++-common/gomp/simd2.c29
-rw-r--r--gcc/testsuite/c-c++-common/gomp/simd3.c26
-rw-r--r--gcc/testsuite/c-c++-common/gomp/simd4.c21
-rw-r--r--gcc/testsuite/c-c++-common/gomp/simd5.c19
-rw-r--r--gcc/testsuite/c-c++-common/gomp/single1.c15
-rw-r--r--gcc/testsuite/g++.dg/gomp/block-0.C6
-rw-r--r--gcc/testsuite/g++.dg/gomp/block-3.C6
-rw-r--r--gcc/testsuite/g++.dg/gomp/clause-3.C10
-rw-r--r--gcc/testsuite/g++.dg/gomp/declare-simd-1.C243
-rw-r--r--gcc/testsuite/g++.dg/gomp/declare-simd-2.C67
-rw-r--r--gcc/testsuite/g++.dg/gomp/depend-1.C70
-rw-r--r--gcc/testsuite/g++.dg/gomp/depend-2.C87
-rw-r--r--gcc/testsuite/g++.dg/gomp/target-1.C32
-rw-r--r--gcc/testsuite/g++.dg/gomp/target-2.C32
-rw-r--r--gcc/testsuite/g++.dg/gomp/taskgroup-1.C32
-rw-r--r--gcc/testsuite/g++.dg/gomp/teams-1.C66
-rw-r--r--gcc/testsuite/g++.dg/gomp/udr-1.C119
-rw-r--r--gcc/testsuite/g++.dg/gomp/udr-2.C119
-rw-r--r--gcc/testsuite/g++.dg/gomp/udr-3.C191
-rw-r--r--gcc/testsuite/g++.dg/gomp/udr-4.C14
-rw-r--r--gcc/testsuite/g++.dg/gomp/udr-5.C41
-rw-r--r--gcc/testsuite/g++.dg/gomp/udr-6.C59
-rw-r--r--gcc/testsuite/gcc.dg/autopar/outer-1.c2
-rw-r--r--gcc/testsuite/gcc.dg/autopar/outer-2.c2
-rw-r--r--gcc/testsuite/gcc.dg/autopar/outer-3.c2
-rw-r--r--gcc/testsuite/gcc.dg/autopar/outer-4.c2
-rw-r--r--gcc/testsuite/gcc.dg/autopar/outer-5.c2
-rw-r--r--gcc/testsuite/gcc.dg/autopar/outer-6.c2
-rw-r--r--gcc/testsuite/gcc.dg/autopar/parallelization-1.c2
-rw-r--r--gcc/testsuite/gcc.dg/gomp/block-3.c7
-rw-r--r--gcc/testsuite/gcc.dg/gomp/clause-1.c8
-rw-r--r--gcc/testsuite/gcc.dg/gomp/combined-1.c2
-rw-r--r--gcc/testsuite/gcc.dg/gomp/declare-simd-1.c100
-rw-r--r--gcc/testsuite/gcc.dg/gomp/declare-simd-2.c24
-rw-r--r--gcc/testsuite/gcc.dg/gomp/nesting-1.c41
-rw-r--r--gcc/testsuite/gcc.dg/gomp/target-1.c29
-rw-r--r--gcc/testsuite/gcc.dg/gomp/target-2.c29
-rw-r--r--gcc/testsuite/gcc.dg/gomp/taskgroup-1.c29
-rw-r--r--gcc/testsuite/gcc.dg/gomp/teams-1.c61
-rw-r--r--gcc/testsuite/gcc.dg/gomp/udr-1.c46
-rw-r--r--gcc/testsuite/gcc.dg/gomp/udr-2.c42
-rw-r--r--gcc/testsuite/gcc.dg/gomp/udr-3.c77
-rw-r--r--gcc/testsuite/gcc.dg/gomp/udr-4.c6
-rw-r--r--gcc/testsuite/gfortran.dg/gomp/appendix-a/a.35.5.f902
-rw-r--r--gcc/tree-cfg.c9
-rw-r--r--gcc/tree-core.h101
-rw-r--r--gcc/tree-inline.c21
-rw-r--r--gcc/tree-nested.c37
-rw-r--r--gcc/tree-pretty-print.c304
-rw-r--r--gcc/tree-ssa-alias.c10
-rw-r--r--gcc/tree-vectorizer.c3
-rw-r--r--gcc/tree.c142
-rw-r--r--gcc/tree.def30
-rw-r--r--gcc/tree.h85
-rw-r--r--libgomp/ChangeLog364
-rw-r--r--libgomp/Makefile.am2
-rw-r--r--libgomp/Makefile.in5
-rw-r--r--libgomp/barrier.c12
-rw-r--r--libgomp/config/linux/affinity.c351
-rw-r--r--libgomp/config/linux/bar.c106
-rw-r--r--libgomp/config/linux/bar.h62
-rw-r--r--libgomp/config/linux/proc.c96
-rw-r--r--libgomp/config/linux/proc.h5
-rw-r--r--libgomp/config/posix/affinity.c79
-rw-r--r--libgomp/config/posix/bar.c132
-rw-r--r--libgomp/config/posix/bar.h58
-rw-r--r--libgomp/env.c797
-rw-r--r--libgomp/fortran.c67
-rw-r--r--libgomp/hashtab.h443
-rw-r--r--libgomp/libgomp.h140
-rw-r--r--libgomp/libgomp.map43
-rw-r--r--libgomp/libgomp.texi86
-rw-r--r--libgomp/libgomp_g.h35
-rw-r--r--libgomp/loop.c68
-rw-r--r--libgomp/omp.h.in42
-rw-r--r--libgomp/omp_lib.f90.in84
-rw-r--r--libgomp/omp_lib.h.in27
-rw-r--r--libgomp/parallel.c153
-rw-r--r--libgomp/sections.c26
-rw-r--r--libgomp/target.c96
-rw-r--r--libgomp/task.c719
-rw-r--r--libgomp/team.c476
-rw-r--r--libgomp/testsuite/libgomp.c++/affinity-1.C4
-rw-r--r--libgomp/testsuite/libgomp.c++/atomic-10.C99
-rw-r--r--libgomp/testsuite/libgomp.c++/atomic-11.C108
-rw-r--r--libgomp/testsuite/libgomp.c++/atomic-12.C58
-rw-r--r--libgomp/testsuite/libgomp.c++/atomic-13.C68
-rw-r--r--libgomp/testsuite/libgomp.c++/atomic-14.C99
-rw-r--r--libgomp/testsuite/libgomp.c++/atomic-15.C108
-rw-r--r--libgomp/testsuite/libgomp.c++/cancel-for-1.C29
-rw-r--r--libgomp/testsuite/libgomp.c++/cancel-for-2.C126
-rw-r--r--libgomp/testsuite/libgomp.c++/cancel-parallel-1.C18
-rw-r--r--libgomp/testsuite/libgomp.c++/cancel-parallel-2.C57
-rw-r--r--libgomp/testsuite/libgomp.c++/cancel-parallel-3.C50
-rw-r--r--libgomp/testsuite/libgomp.c++/cancel-sections-1.C43
-rw-r--r--libgomp/testsuite/libgomp.c++/cancel-taskgroup-1.C4
-rw-r--r--libgomp/testsuite/libgomp.c++/cancel-taskgroup-2.C4
-rw-r--r--libgomp/testsuite/libgomp.c++/cancel-taskgroup-3.C58
-rw-r--r--libgomp/testsuite/libgomp.c++/cancel-test.h47
-rw-r--r--libgomp/testsuite/libgomp.c++/for-10.C44
-rw-r--r--libgomp/testsuite/libgomp.c++/for-11.C108
-rw-r--r--libgomp/testsuite/libgomp.c++/for-9.C33
-rw-r--r--libgomp/testsuite/libgomp.c++/simd-1.C79
-rw-r--r--libgomp/testsuite/libgomp.c++/simd-2.C36
-rw-r--r--libgomp/testsuite/libgomp.c++/simd-3.C131
-rw-r--r--libgomp/testsuite/libgomp.c++/simd-4.C45
-rw-r--r--libgomp/testsuite/libgomp.c++/simd-5.C47
-rw-r--r--libgomp/testsuite/libgomp.c++/simd-6.C70
-rw-r--r--libgomp/testsuite/libgomp.c++/simd-7.C72
-rw-r--r--libgomp/testsuite/libgomp.c++/simd-8.C47
-rw-r--r--libgomp/testsuite/libgomp.c++/target-1.C1
-rw-r--r--libgomp/testsuite/libgomp.c++/target-2-aux.cc5
-rw-r--r--libgomp/testsuite/libgomp.c++/target-2.C58
-rw-r--r--libgomp/testsuite/libgomp.c++/target-3.C1
-rw-r--r--libgomp/testsuite/libgomp.c++/taskgroup-1.C1
-rw-r--r--libgomp/testsuite/libgomp.c++/udr-1.C82
-rw-r--r--libgomp/testsuite/libgomp.c++/udr-2.C88
-rw-r--r--libgomp/testsuite/libgomp.c++/udr-3.C149
-rw-r--r--libgomp/testsuite/libgomp.c++/udr-4.C32
-rw-r--r--libgomp/testsuite/libgomp.c++/udr-5.C49
-rw-r--r--libgomp/testsuite/libgomp.c++/udr-6.C68
-rw-r--r--libgomp/testsuite/libgomp.c++/udr-7.C72
-rw-r--r--libgomp/testsuite/libgomp.c++/udr-8.C39
-rw-r--r--libgomp/testsuite/libgomp.c++/udr-9.C3
-rw-r--r--libgomp/testsuite/libgomp.c/affinity-1.c1146
-rw-r--r--libgomp/testsuite/libgomp.c/atomic-14.c4
-rw-r--r--libgomp/testsuite/libgomp.c/atomic-15.c99
-rw-r--r--libgomp/testsuite/libgomp.c/atomic-16.c58
-rw-r--r--libgomp/testsuite/libgomp.c/atomic-17.c99
-rw-r--r--libgomp/testsuite/libgomp.c/cancel-for-1.c22
-rw-r--r--libgomp/testsuite/libgomp.c/cancel-for-2.c95
-rw-r--r--libgomp/testsuite/libgomp.c/cancel-parallel-1.c17
-rw-r--r--libgomp/testsuite/libgomp.c/cancel-parallel-2.c53
-rw-r--r--libgomp/testsuite/libgomp.c/cancel-parallel-3.c39
-rw-r--r--libgomp/testsuite/libgomp.c/cancel-sections-1.c38
-rw-r--r--libgomp/testsuite/libgomp.c/cancel-taskgroup-1.c70
-rw-r--r--libgomp/testsuite/libgomp.c/cancel-taskgroup-2.c37
-rw-r--r--libgomp/testsuite/libgomp.c/depend-1.c215
-rw-r--r--libgomp/testsuite/libgomp.c/depend-2.c71
-rw-r--r--libgomp/testsuite/libgomp.c/depend-3.c51
-rw-r--r--libgomp/testsuite/libgomp.c/depend-4.c56
-rw-r--r--libgomp/testsuite/libgomp.c/for-1.c35
-rw-r--r--libgomp/testsuite/libgomp.c/for-1.h25
-rw-r--r--libgomp/testsuite/libgomp.c/for-2.c46
-rw-r--r--libgomp/testsuite/libgomp.c/for-2.h269
-rw-r--r--libgomp/testsuite/libgomp.c/for-3.c110
-rw-r--r--libgomp/testsuite/libgomp.c/pr58392.c58
-rw-r--r--libgomp/testsuite/libgomp.c/simd-1.c57
-rw-r--r--libgomp/testsuite/libgomp.c/simd-2.c36
-rw-r--r--libgomp/testsuite/libgomp.c/simd-3.c131
-rw-r--r--libgomp/testsuite/libgomp.c/simd-4.c42
-rw-r--r--libgomp/testsuite/libgomp.c/simd-5.c44
-rw-r--r--libgomp/testsuite/libgomp.c/simd-6.c44
-rw-r--r--libgomp/testsuite/libgomp.c/target-1.c90
-rw-r--r--libgomp/testsuite/libgomp.c/target-2.c88
-rw-r--r--libgomp/testsuite/libgomp.c/target-3.c17
-rw-r--r--libgomp/testsuite/libgomp.c/target-4.c14
-rw-r--r--libgomp/testsuite/libgomp.c/target-5.c83
-rw-r--r--libgomp/testsuite/libgomp.c/target-6.c68
-rw-r--r--libgomp/testsuite/libgomp.c/target-7.c111
-rw-r--r--libgomp/testsuite/libgomp.c/taskgroup-1.c83
-rw-r--r--libgomp/testsuite/libgomp.c/thread-limit-1.c41
-rw-r--r--libgomp/testsuite/libgomp.c/thread-limit-2.c57
-rw-r--r--libgomp/testsuite/libgomp.c/thread-limit-3.c12
-rw-r--r--libgomp/testsuite/libgomp.c/udr-1.c81
-rw-r--r--libgomp/testsuite/libgomp.c/udr-2.c27
-rw-r--r--libgomp/testsuite/libgomp.c/udr-3.c32
-rw-r--r--libgomp/work.c36
223 files changed, 26100 insertions, 1615 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 00ef1a8d8b0..07f8daf3123 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,245 @@
+2013-10-11 Jakub Jelinek <jakub@redhat.com>
+
+ * tree-pretty-print.c (dump_omp_clause): Handle OMP_CLAUSE__LOOPTEMP_
+ and new OpenMP 4.0 clauses, handle UDR OMP_CLAUSE_REDUCTION,
+ formatting fixes, use pp_colon instead of pp_character (..., ':'),
+ similarly pp_right_paren.
+ (dump_generic_node): Handle OMP_DISTRIBUTE, OMP_TEAMS,
+ OMP_TARGET_DATA, OMP_TARGET, OMP_TARGET_UPDATE, OMP_TASKGROUP,
+ allow OMP_FOR_INIT to be NULL, handle OMP_ATOMIC_SEQ_CST.
+ * tree.c (omp_clause_num_ops, omp_clause_code_name): Add OpenMP 4.0
+ clauses.
+ (omp_declare_simd_clauses_equal,
+ omp_remove_redundant_declare_simd_attrs): New functions.
+ (attribute_value_equal): Use omp_declare_simd_clauses_equal.
+ (walk_tree_1): Handle new OpenMP 4.0 clauses.
+ * tree.h (OMP_LOOP_CHECK): Define.
+ (OMP_FOR_BODY, OMP_FOR_CLAUSES, OMP_FOR_INIT, OMP_FOR_COND,
+ OMP_FOR_INCR, OMP_FOR_PRE_BODY): Use it.
+ (OMP_TASKGROUP_BODY, OMP_TEAMS_BODY, OMP_TEAMS_CLAUSES,
+ OMP_TARGET_DATA_BODY, OMP_TARGET_DATA_CLAUSES, OMP_TARGET_BODY,
+ OMP_TARGET_CLAUSES, OMP_TARGET_UPDATE_CLAUSES, OMP_CLAUSE_SIZE,
+ OMP_ATOMIC_SEQ_CST, OMP_CLAUSE_DEPEND_KIND, OMP_CLAUSE_MAP_KIND,
+ OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION, OMP_CLAUSE_PROC_BIND_KIND,
+ OMP_CLAUSE_REDUCTION_OMP_ORIG_REF, OMP_CLAUSE_ALIGNED_ALIGNMENT,
+ OMP_CLAUSE_NUM_TEAMS_EXPR, OMP_CLAUSE_THREAD_LIMIT_EXPR,
+ OMP_CLAUSE_DEVICE_ID, OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR,
+ OMP_CLAUSE_SIMDLEN_EXPR): Define.
+ (OMP_CLAUSE_DECL): Change range up to OMP_CLAUSE__LOOPTEMP_.
+ (omp_remove_redundant_declare_simd_attrs): New prototype.
+ * gimple.def (GIMPLE_OMP_TASKGROUP, GIMPLE_OMP_TARGET,
+ GIMPLE_OMP_TEAMS): New codes.
+ (GIMPLE_OMP_RETURN): Use GSS_OMP_ATOMIC_STORE instead of GSS_BASE.
+ * omp-low.c (struct omp_context): Add cancel_label and cancellable
+ fields.
+ (target_nesting_level): New variable.
+ (extract_omp_for_data): Handle GF_OMP_FOR_KIND_DISTRIBUTE and
+ OMP_CLAUSE_DIST_SCHEDULE. Don't fallback to library implementation
+ for collapse > 1 static schedule unless ordered.
+ (get_ws_args_for): Add par_stmt argument. Handle combined loops.
+ (determine_parallel_type): Adjust get_ws_args_for caller.
+ (install_var_field): Handle mask & 4 for double indirection.
+ (scan_sharing_clauses): Ignore shared clause on teams construct.
+ Handle OMP_CLAUSE__LOOPTEMP_ and new OpenMP 4.0 clauses.
+ (create_omp_child_function): If inside target or declare target
+ constructs, set "omp declare target" attribute on the child
+ function.
+ (find_combined_for): New function.
+ (scan_omp_parallel): Handle combined loops.
+ (scan_omp_target, scan_omp_teams): New functions.
+ (check_omp_nesting_restrictions): Check new OpenMP 4.0 nesting
+ restrictions and set ctx->cancellable for cancellable constructs.
+ (scan_omp_1_stmt): Call check_omp_nesting_restrictions also on
+ selected builtin calls. Handle GIMPLE_OMP_TASKGROUP,
+ GIMPLE_OMP_TARGET, GIMPLE_OMP_TEAMS.
+ (build_omp_barrier): Add lhs argument, return gimple rather than
+ tree.
+ (omp_clause_aligned_alignment): New function.
+ (lower_rec_simd_input_clauses): Only call SET_DECL_VALUE_EXPR
+ on decls.
+ (lower_rec_input_clauses): Add FD argument. Ignore shared clauses
+ on teams constructs. Handle user defined reductions and new
+ OpenMP 4.0 clauses.
+ (lower_reduction_clauses): Don't set placeholder to address of ref
+ if it has already the right type.
+ (lower_send_clauses): Handle OMP_CLAUSE__LOOPTEMP_.
+ (expand_parallel_call): Use the new non-_start suffixed builtins,
+ handle OMP_CLAUSE_PROC_BIND, don't call the outlined function
+ and GOMP_parallel_end after the call.
+ (expand_task_call): Handle OMP_CLAUSE_DEPEND.
+ (expand_omp_for_init_counts): Handle combined loops.
+ (expand_omp_for_init_vars): Add inner_stmt argument, handle combined
+ loops.
+ (expand_omp_for_generic): Likewise. Use GOMP_loop_end_cancel at the
+ end of cancellable loops.
+ (expand_omp_for_static_nochunk, expand_omp_for_static_chunk):
+ Likewise. Handle collapse > 1 loops.
+ (expand_omp_simd): Handle combined loops.
+ (expand_omp_for): Add inner_stmt argument, adjust callers of
+ expand_omp_for* functions, use expand_omp_for_static*chunk even
+ for collapse > 1 unless ordered.
+ (expand_omp_sections): Use GOMP_sections_end_cancel at the end
+ of cancellable sections.
+ (expand_omp_single): Remove need_barrier variable, just rely on
+ gimple_omp_return_nowait_p. Adjust build_omp_barrier caller.
+ (expand_omp_synch): Allow GIMPLE_OMP_TASKGROUP and GIMPLE_OMP_TEAMS.
+ (expand_omp_atomic_load, expand_omp_atomic_store,
+ expand_omp_atomic_fetch_op): Handle gimple_omp_atomic_seq_cst_p.
+ (expand_omp_target): New function.
+ (expand_omp): Handle combined loops. Handle GIMPLE_OMP_TASKGROUP,
+ GIMPLE_OMP_TEAMS, GIMPLE_OMP_TARGET.
+ (build_omp_regions_1): Immediately close region for
+ GF_OMP_TARGET_KIND_UPDATE.
+ (maybe_add_implicit_barrier_cancel): New function.
+ (lower_omp_sections): Adjust lower_rec_input_clauses caller. Handle
+ cancellation.
+ (lower_omp_single): Likewise. Add clobber after the barrier.
+ (lower_omp_taskgroup): New function.
+ (lower_omp_for): Handle combined loops. Adjust
+ lower_rec_input_clauses caller. Handle cancellation.
+ (lower_depend_clauses): New function.
+ (lower_omp_taskreg): Lower depend clauses. Adjust
+ lower_rec_input_clauses caller. Add clobber after the call. Handle
+ cancellation.
+ (lower_omp_target, lower_omp_teams): New functions.
+ (lower_omp_1): Handle cancellation. Handle GIMPLE_OMP_TASKGROUP,
+ GIMPLE_OMP_TARGET, GIMPLE_OMP_TEAMS and GOMP_barrier, GOMP_cancel
+ and GOMP_cancellation_point calls.
+ (lower_omp): Fold stmts inside of target region.
+ (diagnose_sb_1, diagnose_sb_2): Handle GIMPLE_OMP_TASKGROUP,
+ GIMPLE_OMP_TARGET and GIMPLE_OMP_TEAMS.
+ * 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,
+ BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT): 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,
+ BT_FN_BOOL_INT, BT_FN_BOOL_INT_BOOL, BT_FN_VOID_UINT_UINT,
+ BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR,
+ BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR,
+ BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR): New.
+ * tree-ssa-alias.c (ref_maybe_used_by_call_p_1,
+ call_may_clobber_ref_p_1): Handle BUILT_IN_GOMP_BARRIER_CANCEL,
+ BUILT_IN_GOMP_TASKGROUP_END, BUILT_IN_GOMP_LOOP_END_CANCEL,
+ BUILT_IN_GOMP_SECTIONS_END_CANCEL. Don't handle
+ BUILT_IN_GOMP_PARALLEL_END.
+ * gimple-low.c (lower_stmt): Handle GIMPLE_OMP_TASKGROUP,
+ GIMPLE_OMP_TARGET and GIMPLE_OMP_TEAMS.
+ * gimple-pretty-print.c (dump_gimple_omp_for): Handle
+ GF_OMP_FOR_KIND_DISTRIBUTE.
+ (dump_gimple_omp_target, dump_gimple_omp_teams): New functions.
+ (dump_gimple_omp_block): Handle GIMPLE_OMP_TASKGROUP.
+ (dump_gimple_omp_return): Print lhs if it has any.
+ (dump_gimple_omp_atomic_load, dump_gimple_omp_atomic_store): Handle
+ gimple_omp_atomic_seq_cst_p.
+ (pp_gimple_stmt_1): Handle GIMPLE_OMP_TASKGROUP, GIMPLE_OMP_TARGET
+ and GIMPLE_OMP_TEAMS.
+ * langhooks.c (lhd_omp_mappable_type): New function.
+ * tree-vectorizer.c (struct simd_array_to_simduid): Fix up comment.
+ * langhooks.h (struct lang_hooks_for_types): Add omp_mappable_type
+ hook.
+ * gimplify.c (enum gimplify_omp_var_data): Add GOVD_MAP,
+ GOVD_ALIGNED and GOVD_MAP_TO_ONLY.
+ (enum omp_region_type): Add ORT_TEAMS, ORT_TARGET_DATA and
+ ORT_TARGET.
+ (struct gimplify_omp_ctx): Add combined_loop field.
+ (gimplify_call_expr, gimplify_modify_expr): Don't call fold_stmt
+ on stmts inside of target region.
+ (is_gimple_stmt): Return true for OMP_DISTRIBUTE and OMP_TASKGROUP.
+ (omp_firstprivatize_variable): Handle GOVD_MAP, GOVD_ALIGNED,
+ ORT_TARGET and ORT_TARGET_DATA.
+ (omp_add_variable): Avoid checks on readding var for GOVD_ALIGNED.
+ Handle GOVD_MAP.
+ (omp_notice_threadprivate_variable): Complain about threadprivate
+ variables in target region.
+ (omp_notice_variable): Complain about vars with non-mappable type
+ in target region. Handle ORT_TEAMS, ORT_TARGET and ORT_TARGET_DATA.
+ (omp_check_private): Ignore ORT_TARGET* regions.
+ (gimplify_scan_omp_clauses, gimplify_adjust_omp_clauses_1,
+ gimplify_adjust_omp_clauses): Handle new OpenMP 4.0 clauses.
+ (find_combined_omp_for): New function.
+ (gimplify_omp_for): Handle gimplification of combined loops.
+ (gimplify_omp_workshare): Gimplify also OMP_TARGET, OMP_TARGET_DATA,
+ OMP_TEAMS.
+ (gimplify_omp_target_update): New function.
+ (gimplify_omp_atomic): Handle OMP_ATOMIC_SEQ_CST.
+ (gimplify_expr): Handle OMP_DISTRIBUTE, OMP_TARGET, OMP_TARGET_DATA,
+ OMP_TARGET_UPDATE, OMP_TEAMS, OMP_TASKGROUP.
+ (gimplify_body): If fndecl has "omp declare target" attribute, add
+ implicit ORT_TARGET context around it.
+ * tree.def (OMP_DISTRIBUTE, OMP_TEAMS, OMP_TARGET_DATA, OMP_TARGET,
+ OMP_TASKGROUP, OMP_TARGET_UPDATE): New tree codes.
+ * tree-nested.c (convert_nonlocal_reference_stmt,
+ convert_local_reference_stmt, convert_gimple_call): Handle
+ GIMPLE_OMP_TARGET, GIMPLE_OMP_TEAMS and GIMPLE_OMP_TASKGROUP.
+ * omp-builtins.def (BUILT_IN_GOMP_TASK): Use
+ BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR
+ instead of BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT.
+ (BUILT_IN_GOMP_TARGET, BUILT_IN_GOMP_TARGET_DATA,
+ BUILT_IN_GOMP_TARGET_END_DATA, BUILT_IN_GOMP_TARGET_UPDATE,
+ BUILT_IN_GOMP_TEAMS, BUILT_IN_BARRIER_CANCEL,
+ BUILT_IN_GOMP_LOOP_END_CANCEL,
+ BUILT_IN_GOMP_SECTIONS_END_CANCEL, BUILT_IN_OMP_GET_TEAM_NUM,
+ BUILT_IN_OMP_GET_NUM_TEAMS, 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, BUILT_IN_GOMP_CANCEL,
+ BUILT_IN_GOMP_CANCELLATION_POINT): 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.
+ * tree-inline.c (remap_gimple_stmt, estimate_num_insns):
+ Handle GIMPLE_OMP_TARGET, GIMPLE_OMP_TEAMS and GIMPLE_OMP_TASKGROUP.
+ * gimple.c (gimple_build_omp_taskgroup, gimple_build_omp_target,
+ gimple_build_omp_teams): New functions.
+ (walk_gimple_op): Handle GIMPLE_OMP_TARGET, GIMPLE_OMP_TEAMS and
+ GIMPLE_OMP_TASKGROUP. Walk optional lhs on GIMPLE_OMP_RETURN.
+ (walk_gimple_stmt, gimple_copy): Handle GIMPLE_OMP_TARGET,
+ GIMPLE_OMP_TEAMS and GIMPLE_OMP_TASKGROUP.
+ * gimple.h (enum gf_mask): GF_OMP_FOR_KIND_DISTRIBUTE,
+ GF_OMP_FOR_COMBINED, GF_OMP_FOR_COMBINED_INTO,
+ GF_OMP_TARGET_KIND_MASK, GF_OMP_TARGET_KIND_REGION,
+ GF_OMP_TARGET_KIND_DATA, GF_OMP_TARGET_KIND_UPDATE,
+ GF_OMP_ATOMIC_SEQ_CST): New.
+ (gimple_build_omp_taskgroup, gimple_build_omp_target,
+ gimple_build_omp_teams): New prototypes.
+ (gimple_has_substatements): Handle GIMPLE_OMP_TARGET,
+ GIMPLE_OMP_TEAMS and GIMPLE_OMP_TASKGROUP.
+ (gimple_omp_subcode): Use GIMPLE_OMP_TEAMS instead of
+ GIMPLE_OMP_SINGLE as end of range.
+ (gimple_omp_return_set_lhs, gimple_omp_return_lhs,
+ gimple_omp_return_lhs_ptr, gimple_omp_atomic_seq_cst_p,
+ gimple_omp_atomic_set_seq_cst, gimple_omp_for_combined_p,
+ gimple_omp_for_set_combined_p, gimple_omp_for_combined_into_p,
+ gimple_omp_for_set_combined_into_p, 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_target_child_fn, gimple_omp_target_child_fn_ptr,
+ gimple_omp_target_set_child_fn, gimple_omp_target_data_arg,
+ gimple_omp_target_data_arg_ptr, gimple_omp_target_set_data_arg,
+ gimple_omp_teams_clauses, gimple_omp_teams_clauses_ptr,
+ gimple_omp_teams_set_clauses): New inlines.
+ (CASE_GIMPLE_OMP): Add GIMPLE_OMP_TARGET, GIMPLE_OMP_TEAMS
+ and GIMPLE_OMP_TASKGROUP.
+ * tree-core.h (enum omp_clause_code): Add new OpenMP 4.0 clause
+ codes.
+ (enum omp_clause_depend_kind, enum omp_clause_map_kind,
+ enum omp_clause_proc_bind_kind): New.
+ (union omp_clause_subcode): Add depend_kind, map_kind and
+ proc_bind_kind fields.
+ * tree-cfg.c (make_edges): Handle GIMPLE_OMP_TARGET,
+ GIMPLE_OMP_TEAMS and GIMPLE_OMP_TASKGROUP.
+ * langhooks-def.h (lhd_omp_mappable_type): New prototype.
+ (LANG_HOOKS_OMP_MAPPABLE_TYPE): Define.
+ (LANG_HOOKS_FOR_TYPES_INITIALIZER): Add it.
+
2013-10-10 Teresa Johnson <tejohnson@google.com>
* predict.c (tree_estimate_probability): Add new parameter
diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog
index 434a0723a8f..2ed3e37f8bf 100644
--- a/gcc/ada/ChangeLog
+++ b/gcc/ada/ChangeLog
@@ -1,3 +1,7 @@
+2013-10-11 Jakub Jelinek <jakub@redhat.com>
+
+ * gcc-interface/utils.c (DEF_FUNCTION_TYPE_8): Define.
+
2013-10-10 Robert Dewar <dewar@adacore.com>
* par-ch6.adb (Check_Junk_Semicolon_Before_Return): Remove
diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c
index 2c3e096f120..210b0921107 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 2634eccabab..3deedba5b78 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,
@@ -230,6 +232,7 @@ DEF_FUNCTION_TYPE_1 (BT_FN_ULONGLONG_ULONGLONG, BT_ULONGLONG, BT_ULONGLONG)
DEF_FUNCTION_TYPE_1 (BT_FN_UINT16_UINT16, BT_UINT16, BT_UINT16)
DEF_FUNCTION_TYPE_1 (BT_FN_UINT32_UINT32, BT_UINT32, BT_UINT32)
DEF_FUNCTION_TYPE_1 (BT_FN_UINT64_UINT64, BT_UINT64, BT_UINT64)
+DEF_FUNCTION_TYPE_1 (BT_FN_BOOL_INT, BT_BOOL, BT_INT)
DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR, BT_FN_VOID_PTR)
@@ -341,6 +344,8 @@ DEF_FUNCTION_TYPE_2 (BT_FN_VOID_VPTR_INT, BT_VOID, BT_VOLATILE_PTR, BT_INT)
DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_VPTR_INT, BT_BOOL, BT_VOLATILE_PTR, BT_INT)
DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_SIZE_CONST_VPTR, BT_BOOL, BT_SIZE,
BT_CONST_VOLATILE_PTR)
+DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_INT_BOOL, BT_BOOL, BT_INT, BT_BOOL)
+DEF_FUNCTION_TYPE_2 (BT_FN_VOID_UINT_UINT, BT_VOID, BT_UINT, BT_UINT)
DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR)
@@ -411,8 +416,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 +470,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 +480,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)
@@ -497,19 +500,27 @@ DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_VPTR_PTR_I16_BOOL_INT_INT,
BT_INT)
DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_SIZE_VPTR_PTR_PTR_INT_INT, BT_BOOL, BT_SIZE,
BT_VOLATILE_PTR, BT_PTR, BT_PTR, BT_INT, BT_INT)
+DEF_FUNCTION_TYPE_6 (BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR,
+ BT_VOID, BT_INT, BT_PTR, BT_SIZE, BT_PTR, BT_PTR, BT_PTR)
-
-DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_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)
-DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT,
- BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR,
- BT_PTR_FN_VOID_PTR_PTR, BT_LONG, BT_LONG,
- BT_BOOL, BT_UINT)
+ BT_LONG, BT_LONG, BT_LONG, BT_UINT)
DEF_FUNCTION_TYPE_7 (BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULL_ULLPTR_ULLPTR,
BT_BOOL, BT_BOOL, BT_ULONGLONG, BT_ULONGLONG,
BT_ULONGLONG, BT_ULONGLONG,
BT_PTR_ULONGLONG, BT_PTR_ULONGLONG)
+DEF_FUNCTION_TYPE_7 (BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR,
+ BT_VOID, BT_INT, BT_PTR_FN_VOID_PTR, BT_PTR, BT_SIZE,
+ BT_PTR, BT_PTR, BT_PTR)
+
+DEF_FUNCTION_TYPE_8 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT,
+ BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT,
+ BT_LONG, BT_LONG, BT_LONG, BT_LONG, BT_UINT)
+DEF_FUNCTION_TYPE_8 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR,
+ BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR,
+ BT_PTR_FN_VOID_PTR_PTR, BT_LONG, BT_LONG,
+ BT_BOOL, BT_UINT, BT_PTR)
DEF_FUNCTION_TYPE_VAR_0 (BT_FN_VOID_VAR, BT_VOID)
DEF_FUNCTION_TYPE_VAR_0 (BT_FN_INT_VAR, BT_INT)
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index d94921b456d..5febbe5e735 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,55 @@
+2013-10-11 Jakub Jelinek <jakub@redhat.com>
+
+ * c-cppbuiltin.c (c_cpp_builtins): Predefine _OPENMP to
+ 201307 instead of 201107.
+ * c-common.c (DEF_FUNCTION_TYPE_8): Define.
+ (c_common_attribute_table): Add "omp declare target" and
+ "omp declare simd" attributes.
+ (handle_omp_declare_target_attribute,
+ handle_omp_declare_simd_attribute): New functions.
+ * c-omp.c: Include c-pragma.h.
+ (c_finish_omp_taskgroup): New function.
+ (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_finish_omp_for): Add code argument, pass it down to make_code.
+ (c_omp_split_clauses): New function.
+ (c_split_parallel_clauses): Removed.
+ (c_omp_declare_simd_clause_cmp, c_omp_declare_simd_clauses_to_numbers,
+ c_omp_declare_simd_clauses_to_decls): New functions.
+ * c-common.h (omp_clause_mask): New type.
+ (OMP_CLAUSE_MASK_1): Define.
+ (omp_clause_mask::omp_clause_mask, omp_clause_mask::operator &=,
+ omp_clause_mask::operator |=, omp_clause_mask::operator ~,
+ omp_clause_mask::operator |, omp_clause_mask::operator &,
+ omp_clause_mask::operator <<, omp_clause_mask::operator >>,
+ omp_clause_mask::operator ==): New methods.
+ (enum c_omp_clause_split): New.
+ (c_finish_omp_taskgroup): New prototype.
+ (c_finish_omp_atomic): Add swapped argument.
+ (c_finish_omp_for): Add code argument.
+ (c_omp_split_clauses): New prototype.
+ (c_split_parallel_clauses): Removed.
+ (c_omp_declare_simd_clauses_to_numbers,
+ c_omp_declare_simd_clauses_to_decls): New prototypes.
+ * c-pragma.c (omp_pragmas): Add new OpenMP 4.0 constructs.
+ * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_CANCEL,
+ PRAGMA_OMP_CANCELLATION_POINT, PRAGMA_OMP_DECLARE_REDUCTION,
+ PRAGMA_OMP_DISTRIBUTE, PRAGMA_OMP_END_DECLARE_TARGET, PRAGMA_OMP_SIMD,
+ PRAGMA_OMP_TARGET, PRAGMA_OMP_TASKGROUP and PRAGMA_OMP_TEAMS.
+ Remove PRAGMA_OMP_PARALLEL_FOR and PRAGMA_OMP_PARALLEL_SECTIONS.
+ (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_THREAD_LIMIT, PRAGMA_OMP_CLAUSE_TO and
+ PRAGMA_OMP_CLAUSE_UNIFORM.
+
2013-10-09 Marc Glisse <marc.glisse@inria.fr>
PR tree-optimization/20318
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 5fe7cab0f8b..5fd7b855115 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -372,6 +372,10 @@ 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_warn_unused_attribute (tree *, tree, tree, int, bool *);
static tree handle_returns_nonnull_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);
@@ -750,6 +754,10 @@ const struct attribute_spec c_common_attribute_table[] =
handle_warn_unused_attribute, false },
{ "returns_nonnull", 0, 0, false, true, true,
handle_returns_nonnull_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 }
};
@@ -5057,6 +5065,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,
@@ -5075,6 +5084,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
@@ -5157,6 +5167,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) \
@@ -8024,6 +8038,24 @@ handle_warn_unused_attribute (tree *node, tree 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 722ba6e5c15..2649248ed95 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1034,17 +1034,159 @@ 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_taskgroup (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. */
diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c
index 94078c00460..ed4c82caa46 100644
--- a/gcc/c-family/c-cppbuiltin.c
+++ b/gcc/c-family/c-cppbuiltin.c
@@ -896,7 +896,7 @@ c_cpp_builtins (cpp_reader *pfile)
cpp_define (pfile, "__SSP__=1");
if (flag_openmp)
- cpp_define (pfile, "_OPENMP=201107");
+ cpp_define (pfile, "_OPENMP=201307");
if (int128_integer_type_node != NULL_TREE)
builtin_define_type_sizeof ("__SIZEOF_INT128__",
diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c
index f05b60a4035..dac127ed339 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"
@@ -41,6 +42,17 @@ c_finish_omp_master (location_t loc, tree stmt)
return t;
}
+/* Complete a #pragma omp taskgroup construct. STMT is the structured-block
+ that follows the pragma. LOC is the l*/
+
+tree
+c_finish_omp_taskgroup (location_t loc, tree stmt)
+{
+ tree t = add_stmt (build1 (OMP_TASKGROUP, void_type_node, stmt));
+ SET_EXPR_LOCATION (t, loc);
+ return t;
+}
+
/* Complete a #pragma omp critical construct. STMT is the structured-block
that follows the pragma, NAME is the identifier in the pragma, or null
if it was omitted. LOC is the location of the #pragma. */
@@ -122,7 +134,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 +180,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 +189,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 +205,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 +357,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 +583,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 +597,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 +653,326 @@ 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_REDUCTION_PLACEHOLDER (c)
+ = OMP_CLAUSE_REDUCTION_PLACEHOLDER (clauses);
+ OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_SIMD];
+ cclauses[C_OMP_CLAUSE_SPLIT_SIMD] = c;
+ }
+ if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE))
+ {
+ 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_REDUCTION_PLACEHOLDER (c)
+ = OMP_CLAUSE_REDUCTION_PLACEHOLDER (clauses);
+ OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL];
+ cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] = c;
+ s = C_OMP_CLAUSE_SPLIT_TEAMS;
+ }
+ else 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 parms, tree clauses)
+{
+ tree c;
+ vec<tree> 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 = parms, 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 function argument", decl);
+ 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 309859fc8ec..4ff187bcb6f 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 }
};
diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h
index 41215db00a0..c421284a5c4 100644
--- a/gcc/c-family/c-pragma.h
+++ b/gcc/c-family/c-pragma.h
@@ -29,21 +29,28 @@ 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_DISTRIBUTE,
+ PRAGMA_OMP_END_DECLARE_TARGET,
PRAGMA_OMP_FLUSH,
PRAGMA_OMP_FOR,
PRAGMA_OMP_MASTER,
PRAGMA_OMP_ORDERED,
PRAGMA_OMP_PARALLEL,
- PRAGMA_OMP_PARALLEL_FOR,
- PRAGMA_OMP_PARALLEL_SECTIONS,
PRAGMA_OMP_SECTION,
PRAGMA_OMP_SECTIONS,
+ PRAGMA_OMP_SIMD,
PRAGMA_OMP_SINGLE,
+ PRAGMA_OMP_TARGET,
PRAGMA_OMP_TASK,
+ PRAGMA_OMP_TASKGROUP,
PRAGMA_OMP_TASKWAIT,
PRAGMA_OMP_TASKYIELD,
PRAGMA_OMP_THREADPRIVATE,
+ PRAGMA_OMP_TEAMS,
PRAGMA_GCC_PCH_PREPROCESS,
@@ -51,28 +58,48 @@ 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;
extern struct cpp_reader* parse_in;
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index a22d51d8121..e6efc317315 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,114 @@
+2013-10-11 Jakub Jelinek <jakub@redhat.com>
+
+ * c-lang.h (current_omp_declare_target_attribute): New extern
+ decl.
+ * c-parser.c: Include c-lang.h.
+ (struct c_parser): Change tokens to c_token *.
+ Add tokens_buf field. Change tokens_avail type to unsigned int.
+ (c_parser_consume_token): If parser->tokens isn't
+ &parser->tokens_buf[0], increment parser->tokens.
+ (c_parser_consume_pragma): Likewise.
+ (enum pragma_context): Add pragma_struct and pragma_param.
+ (c_parser_external_declaration): Adjust
+ c_parser_declaration_or_fndef caller.
+ (c_parser_declaration_or_fndef): Add omp_declare_simd_clauses
+ argument, if it is non-vNULL vector, call c_finish_omp_declare_simd.
+ Adjust recursive call.
+ (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_compound_statement_nostart, c_parser_label,
+ c_parser_for_statement): Adjust
+ c_parser_declaration_or_fndef callers.
+ (c_parser_expr_no_commas): Add omp_atomic_lhs argument, pass
+ it through to c_parser_conditional_expression.
+ (c_parser_conditional_expression): Add omp_atomic_lhs argument,
+ pass it through to c_parser_binary_expression. Adjust recursive
+ call.
+ (c_parser_binary_expression): Remove prec argument, add
+ omp_atomic_lhs argument instead. 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_pragma): Handle PRAGMA_OMP_CANCEL,
+ PRAGMA_OMP_CANCELLATION_POINT, PRAGMA_OMP_TARGET,
+ PRAGMA_OMP_END_DECLARE_TARGET, PRAGMA_OMP_DECLARE_REDUCTION.
+ Handle pragma_struct and pragma_param the same as pragma_external.
+ (c_parser_omp_clause_name): Parse new OpenMP 4.0 clause names.
+ (c_parser_omp_variable_list): Parse array sections for
+ OMP_CLAUSE_{DEPEND,MAP,TO,FROM} clauses.
+ (c_parser_omp_clause_collapse): Fully fold collapse expression.
+ (c_parser_omp_clause_reduction): Handle user defined reductions.
+ (c_parser_omp_clause_branch, c_parser_omp_clause_cancelkind,
+ c_parser_omp_clause_num_teams, c_parser_omp_clause_thread_limit,
+ 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): Add finish_p argument. Don't call
+ c_finish_omp_clauses if it is false. Handle new OpenMP 4.0 clauses.
+ (c_parser_omp_atomic): Parse seq_cst clause, pass true if it is
+ present to c_finish_omp_atomic. Handle OpenMP 4.0 atomic forms.
+ (c_parser_omp_for_loop): Add CODE argument, pass it through
+ to c_finish_omp_for. Change last argument to cclauses,
+ and adjust uses to grab parallel clauses from the array of all
+ the split clauses. Adjust c_parser_binary_expression,
+ c_parser_declaration_or_fndef and c_finish_omp_for callers.
+ (omp_split_clauses): New function.
+ (c_parser_omp_simd): New function.
+ (c_parser_omp_for): Add p_name, mask and cclauses arguments.
+ Allow the function to be called also when parsing combined constructs,
+ and call c_parser_omp_simd when parsing for simd.
+ (c_parser_omp_sections_scope): If section-sequence doesn't start with
+ #pragma omp section, require exactly one structured-block instead of
+ sequence of statements.
+ (c_parser_omp_sections): Add p_name, mask and cclauses arguments.
+ Allow the function to be called also when parsing combined constructs.
+ (c_parser_omp_parallel): Add p_name, mask and cclauses arguments.
+ Allow the function to be called also when parsing combined
+ constructs.
+ (c_parser_omp_taskgroup, c_parser_omp_cancel,
+ c_parser_omp_cancellation_point, c_parser_omp_distribute,
+ c_parser_omp_teams, c_parser_omp_target_data,
+ c_parser_omp_target_update, c_parser_omp_target,
+ c_parser_omp_declare_simd, c_finish_omp_declare_simd,
+ c_parser_omp_declare_target, c_parser_omp_end_declare_target,
+ c_parser_omp_declare_reduction, c_parser_omp_declare): New functions.
+ (c_parser_omp_construct): Add p_name and mask vars. Handle
+ PRAGMA_OMP_DISTRIBUTE, PRAGMA_OMP_SIMD, PRAGMA_OMP_TASKGROUP,
+ PRAGMA_OMP_TEAMS. Adjust c_parser_omp_for, c_parser_omp_parallel
+ and c_parser_omp_sections callers.
+ (c_parse_file): Initialize tparser.tokens and the_parser->tokens here.
+ (OMP_FOR_CLAUSE_MASK, OMP_SECTIONS_CLAUSE_MASK,
+ OMP_SINGLE_CLAUSE_MASK): Use OMP_CLAUSE_MASK_1 instead of 1.
+ (OMP_PARALLEL_CLAUSE_MASK): Likewise. Add OMP_CLAUSE_PROC_BIND.
+ (OMP_TASK_CLAUSE_MASK): Use OMP_CLAUSE_MASK_1 instead of 1. Add
+ OMP_CLAUSE_DEPEND.
+ (OMP_SIMD_CLAUSE_MASK, OMP_CANCEL_CLAUSE_MASK,
+ OMP_CANCELLATION_POINT_CLAUSE_MASK, OMP_DISTRIBUTE_CLAUSE_MASK,
+ OMP_TEAMS_CLAUSE_MASK, OMP_TARGET_DATA_CLAUSE_MASK,
+ OMP_TARGET_UPDATE_CLAUSE_MASK, OMP_TARGET_CLAUSE_MASK,
+ OMP_DECLARE_SIMD_CLAUSE_MASK): Define.
+ * c-typeck.c: Include tree-inline.h.
+ (c_finish_omp_cancel, c_finish_omp_cancellation_point,
+ handle_omp_array_sections_1, handle_omp_array_sections,
+ c_clone_omp_udr, c_find_omp_placeholder_r): New functions.
+ (c_finish_omp_clauses): Handle new OpenMP 4.0 clauses and
+ user defined reductions.
+ (c_tree_equal): New function.
+ * c-tree.h (temp_store_parm_decls, temp_pop_parm_decls,
+ c_finish_omp_cancel, c_finish_omp_cancellation_point, c_tree_equal,
+ c_omp_reduction_id, c_omp_reduction_decl, c_omp_reduction_lookup,
+ c_check_omp_declare_reduction_r): New prototypes.
+ * c-decl.c (current_omp_declare_target_attribute): New variable.
+ (c_decl_attributes): New function.
+ (start_decl, start_function): Use it instead of decl_attributes.
+ (temp_store_parm_decls, temp_pop_parm_decls, c_omp_reduction_id,
+ c_omp_reduction_decl, c_omp_reduction_lookup,
+ c_check_omp_declare_reduction_r): New functions.
+
2013-09-25 Tom Tromey <tromey@redhat.com>
* Make-lang.in (c/gccspec.o): Remove.
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index f26334829d8..0554e72703f 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -147,6 +147,9 @@ static bool undef_nested_function;
enum machine_mode c_default_pointer_mode = VOIDmode;
+/* If non-zero, implicit "omp declare target" attribute is added into the
+ attribute lists. */
+int current_omp_declare_target_attribute;
/* Each c_binding structure describes one binding of an identifier to
a decl. All the decls in a scope - irrespective of namespace - are
@@ -3971,6 +3974,35 @@ groktypename (struct c_type_name *type_name, tree *expr,
return type;
}
+/* Wrapper for decl_attributes that adds some implicit attributes
+ to VAR_DECLs or FUNCTION_DECLs. */
+
+static tree
+c_decl_attributes (tree *node, tree attributes, int flags)
+{
+ /* Add implicit "omp declare target" attribute if requested. */
+ if (current_omp_declare_target_attribute
+ && ((TREE_CODE (*node) == VAR_DECL && TREE_STATIC (*node))
+ || TREE_CODE (*node) == FUNCTION_DECL))
+ {
+ if (TREE_CODE (*node) == VAR_DECL
+ && ((DECL_CONTEXT (*node)
+ && TREE_CODE (DECL_CONTEXT (*node)) == FUNCTION_DECL)
+ || (current_function_decl && !DECL_EXTERNAL (*node))))
+ error ("%q+D in block scope inside of declare target directive",
+ *node);
+ else if (TREE_CODE (*node) == VAR_DECL
+ && !COMPLETE_TYPE_P (TREE_TYPE (*node)))
+ error ("%q+D in declare target directive does not have mappable type",
+ *node);
+ else
+ attributes = tree_cons (get_identifier ("omp declare target"),
+ NULL_TREE, attributes);
+ }
+ return decl_attributes (node, attributes, flags);
+}
+
+
/* Decode a declarator in an ordinary declaration or data definition.
This is called as soon as the type information and variable name
have been parsed, before parsing the initializer if any.
@@ -4105,7 +4137,7 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs,
DECL_COMMON (decl) = 1;
/* Set attributes here so if duplicate decl, will have proper attributes. */
- decl_attributes (&decl, attributes, 0);
+ c_decl_attributes (&decl, attributes, 0);
/* Handle gnu_inline attribute. */
if (declspecs->inline_p
@@ -7727,7 +7759,7 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
loc = DECL_SOURCE_LOCATION (decl1);
- decl_attributes (&decl1, attributes, 0);
+ c_decl_attributes (&decl1, attributes, 0);
if (DECL_DECLARED_INLINE_P (decl1)
&& DECL_UNINLINABLE (decl1)
@@ -8324,6 +8356,44 @@ store_parm_decls (void)
if (arg_info->pending_sizes)
add_stmt (arg_info->pending_sizes);
}
+
+/* Store PARM_DECLs in PARMS into scope temporarily. Used for
+ c_finish_omp_declare_simd for function prototypes. No diagnostics
+ should be done. */
+
+void
+temp_store_parm_decls (tree fndecl, tree parms)
+{
+ push_scope ();
+ for (tree p = parms; p; p = DECL_CHAIN (p))
+ {
+ DECL_CONTEXT (p) = fndecl;
+ if (DECL_NAME (p))
+ bind (DECL_NAME (p), p, current_scope,
+ /*invisible=*/false, /*nested=*/false,
+ UNKNOWN_LOCATION);
+ }
+}
+
+/* Undo what temp_store_parm_decls did. */
+
+void
+temp_pop_parm_decls (void)
+{
+ /* Clear all bindings in this temporary scope, so that
+ pop_scope doesn't create a BLOCK. */
+ struct c_binding *b = current_scope->bindings;
+ current_scope->bindings = NULL;
+ for (; b; b = free_binding_and_advance (b))
+ {
+ gcc_assert (TREE_CODE (b->decl) == PARM_DECL);
+ gcc_assert (I_SYMBOL_BINDING (b->id) == b);
+ I_SYMBOL_BINDING (b->id) = b->shadowed;
+ if (b->shadowed && b->shadowed->u.type)
+ TREE_TYPE (b->shadowed->decl) = b->shadowed->u.type;
+ }
+ pop_scope ();
+}
/* Finish up a function declaration and compile that function
@@ -10158,4 +10228,106 @@ c_register_addr_space (const char *word, addr_space_t as)
ridpointers [rid] = id;
}
+/* Return identifier to look up for omp declare reduction. */
+
+tree
+c_omp_reduction_id (enum tree_code reduction_code, tree reduction_id)
+{
+ const char *p = NULL;
+ switch (reduction_code)
+ {
+ case PLUS_EXPR: p = "+"; break;
+ case MULT_EXPR: p = "*"; break;
+ case MINUS_EXPR: p = "-"; break;
+ case BIT_AND_EXPR: p = "&"; break;
+ case BIT_XOR_EXPR: p = "^"; break;
+ case BIT_IOR_EXPR: p = "|"; break;
+ case TRUTH_ANDIF_EXPR: p = "&&"; break;
+ case TRUTH_ORIF_EXPR: p = "||"; break;
+ case MIN_EXPR: p = "min"; break;
+ case MAX_EXPR: p = "max"; break;
+ default:
+ break;
+ }
+
+ if (p == NULL)
+ {
+ if (TREE_CODE (reduction_id) != IDENTIFIER_NODE)
+ return error_mark_node;
+ p = IDENTIFIER_POINTER (reduction_id);
+ }
+
+ const char prefix[] = "omp declare reduction ";
+ size_t lenp = sizeof (prefix);
+ size_t len = strlen (p);
+ char *name = XALLOCAVEC (char, lenp + len);
+ memcpy (name, prefix, lenp - 1);
+ memcpy (name + lenp - 1, p, len + 1);
+ return get_identifier (name);
+}
+
+/* Lookup REDUCTION_ID in the current scope, or create an artificial
+ VAR_DECL, bind it into the current scope and return it. */
+
+tree
+c_omp_reduction_decl (tree reduction_id)
+{
+ struct c_binding *b = I_SYMBOL_BINDING (reduction_id);
+ if (b != NULL && B_IN_CURRENT_SCOPE (b))
+ return b->decl;
+
+ tree decl = build_decl (BUILTINS_LOCATION, VAR_DECL,
+ reduction_id, integer_type_node);
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_EXTERNAL (decl) = 1;
+ TREE_STATIC (decl) = 1;
+ TREE_PUBLIC (decl) = 0;
+ bind (reduction_id, decl, current_scope, true, false, BUILTINS_LOCATION);
+ return decl;
+}
+
+/* Lookup REDUCTION_ID in the first scope where it has entry for TYPE. */
+
+tree
+c_omp_reduction_lookup (tree reduction_id, tree type)
+{
+ struct c_binding *b = I_SYMBOL_BINDING (reduction_id);
+ while (b)
+ {
+ tree t;
+ for (t = DECL_INITIAL (b->decl); t; t = TREE_CHAIN (t))
+ if (comptypes (TREE_PURPOSE (t), type))
+ return TREE_VALUE (t);
+ b = b->shadowed;
+ }
+ return error_mark_node;
+}
+
+/* Helper function called via walk_tree, to diagnose invalid
+ #pragma omp declare reduction combiners or initializers. */
+
+tree
+c_check_omp_declare_reduction_r (tree *tp, int *, void *data)
+{
+ tree *vars = (tree *) data;
+ if (SSA_VAR_P (*tp)
+ && !DECL_ARTIFICIAL (*tp)
+ && *tp != vars[0]
+ && *tp != vars[1])
+ {
+ location_t loc = DECL_SOURCE_LOCATION (vars[0]);
+ if (strcmp (IDENTIFIER_POINTER (DECL_NAME (vars[0])), "omp_out") == 0)
+ error_at (loc, "%<#pragma omp declare reduction%> combiner refers to "
+ "variable %qD which is not %<omp_out%> nor %<omp_in%>",
+ *tp);
+ else
+ error_at (loc, "%<#pragma omp declare reduction%> initializer refers "
+ "to variable %qD which is not %<omp_priv%> nor "
+ "%<omp_orig%>",
+ *tp);
+ return *tp;
+ }
+ return NULL_TREE;
+}
+
#include "gt-c-c-decl.h"
diff --git a/gcc/c/c-lang.h b/gcc/c/c-lang.h
index 5ff7cd5422e..cbd5d1fa643 100644
--- a/gcc/c/c-lang.h
+++ b/gcc/c/c-lang.h
@@ -55,5 +55,8 @@ struct GTY(()) language_function {
int warn_about_return_type;
};
+/* If non-zero, implicit "omp declare target" attribute is added into the
+ attribute lists. */
+extern GTY(()) int current_omp_declare_target_attribute;
#endif /* ! GCC_C_LANG_H */
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index b612e29c852..8d609936107 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see
#include "timevar.h"
#include "c-family/c-pragma.h"
#include "c-tree.h"
+#include "c-lang.h"
#include "flags.h"
#include "ggc.h"
#include "c-family/c-common.h"
@@ -162,9 +163,12 @@ typedef struct GTY (()) c_token {
tokens of look-ahead; more are not needed for C. */
typedef struct GTY(()) c_parser {
/* The look-ahead tokens. */
- c_token tokens[2];
- /* How many look-ahead tokens are available (0, 1 or 2). */
- short tokens_avail;
+ c_token * GTY((skip)) tokens;
+ /* Buffer for look-ahead tokens. */
+ c_token tokens_buf[2];
+ /* How many look-ahead tokens are available (0, 1 or 2, or
+ more if parsing from pre-lexed tokens). */
+ unsigned int tokens_avail;
/* True if a syntax error is being recovered from; false otherwise.
c_parser_error sets this flag. It should clear this flag when
enough tokens have been consumed to recover from the error. */
@@ -736,7 +740,9 @@ c_parser_consume_token (c_parser *parser)
gcc_assert (parser->tokens[0].type != CPP_EOF);
gcc_assert (!parser->in_pragma || parser->tokens[0].type != CPP_PRAGMA_EOL);
gcc_assert (parser->error || parser->tokens[0].type != CPP_PRAGMA);
- if (parser->tokens_avail == 2)
+ if (parser->tokens != &parser->tokens_buf[0])
+ parser->tokens++;
+ else if (parser->tokens_avail == 2)
parser->tokens[0] = parser->tokens[1];
parser->tokens_avail--;
}
@@ -750,7 +756,9 @@ c_parser_consume_pragma (c_parser *parser)
gcc_assert (!parser->in_pragma);
gcc_assert (parser->tokens_avail >= 1);
gcc_assert (parser->tokens[0].type == CPP_PRAGMA);
- if (parser->tokens_avail == 2)
+ if (parser->tokens != &parser->tokens_buf[0])
+ parser->tokens++;
+ else if (parser->tokens_avail == 2)
parser->tokens[0] = parser->tokens[1];
parser->tokens_avail--;
parser->in_pragma = true;
@@ -1112,7 +1120,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<c_token>);
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 +1163,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 +1194,15 @@ 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 bool c_parser_omp_target (c_parser *, enum pragma_context);
+static void c_parser_omp_end_declare_target (c_parser *);
+static void c_parser_omp_declare (c_parser *, enum pragma_context);
/* These Objective-C parser functions are only ever called when
compiling Objective-C. */
@@ -1360,11 +1375,14 @@ 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;
}
}
+static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token>);
+
/* Parse a declaration or function definition (C90 6.5, 6.7.1, C99
6.7, 6.9.1). If FNDEF_OK is true, a function definition is
accepted; otherwise (old-style parameter declarations) only other
@@ -1440,7 +1458,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<c_token> omp_declare_simd_clauses)
{
struct c_declspecs *specs;
tree prefix_attrs;
@@ -1610,6 +1629,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 (parser, NULL_TREE, NULL_TREE,
+ omp_declare_simd_clauses);
c_parser_skip_to_end_of_block_or_statement (parser);
return;
}
@@ -1646,6 +1668,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 (parser, 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 +1687,28 @@ 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;
+ }
+ if (parms)
+ temp_store_parm_decls (d, parms);
+ c_finish_omp_declare_simd (parser, d, parms,
+ omp_declare_simd_clauses);
+ if (parms)
+ temp_pop_parm_decls ();
+ }
if (d)
finish_decl (d, UNKNOWN_LOCATION, NULL_TREE,
NULL_TREE, asm_name);
@@ -1751,8 +1798,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 (parser, 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 +2531,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 +3379,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 +4124,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 +4233,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 +4262,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 +4400,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 +4464,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 +4482,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 +4497,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 +5047,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 +5076,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 +5464,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 +5545,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 +5605,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;
@@ -5568,8 +5638,13 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after)
/* Parse a binary expression; that is, a logical-OR-expression (C90
6.3.5-6.3.14, C99 6.5.5-6.5.14). If AFTER is not NULL then it is
an Objective-C message expression which is the primary-expression
- starting the expression as an initializer. PREC is the starting
- precedence, usually PREC_NONE.
+ starting the expression as an initializer.
+
+ OMP_ATOMIC_LHS is NULL, unless parsing OpenMP #pragma omp atomic,
+ when it should be the unfolded lhs. In a valid OpenMP source,
+ one of the operands of the toplevel binary expression must be equal
+ to it. In that case, just return a build2 created binary operation
+ rather than result of parser_build_binary_op.
multiplicative-expression:
cast-expression
@@ -5622,7 +5697,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 +5755,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 +5867,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)
{
@@ -7955,7 +8040,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;
}
}
@@ -8936,10 +9021,39 @@ 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;
+ case PRAGMA_OMP_TARGET:
+ return c_parser_omp_target (parser, context);
+
+ case PRAGMA_OMP_END_DECLARE_TARGET:
+ c_parser_omp_end_declare_target (parser);
+ return false;
+
case PRAGMA_OMP_SECTION:
error_at (c_parser_peek_token (parser)->location,
"%<#pragma omp section%> may only be used in "
@@ -8947,6 +9061,10 @@ 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);
@@ -8955,7 +9073,7 @@ c_parser_pragma (c_parser *parser, enum pragma_context context)
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");
@@ -9020,7 +9138,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
@@ -9036,12 +9154,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;
@@ -9050,23 +9174,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;
@@ -9075,21 +9221,41 @@ 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 ("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;
}
@@ -9133,8 +9299,7 @@ check_no_duplicate_clause (tree clauses, enum omp_clause_code code,
static tree
c_parser_omp_variable_list (c_parser *parser,
location_t clause_loc,
- enum omp_clause_code kind,
- tree list)
+ enum omp_clause_code kind, tree list)
{
if (c_parser_next_token_is_not (parser, CPP_NAME)
|| c_parser_peek_token (parser)->id_kind != C_ID_ID)
@@ -9146,22 +9311,70 @@ c_parser_omp_variable_list (c_parser *parser,
tree t = lookup_name (c_parser_peek_token (parser)->value);
if (t == NULL_TREE)
- undeclared_variable (c_parser_peek_token (parser)->location,
- c_parser_peek_token (parser)->value);
- else if (t == error_mark_node)
+ {
+ undeclared_variable (c_parser_peek_token (parser)->location,
+ c_parser_peek_token (parser)->value);
+ t = error_mark_node;
+ }
+
+ c_parser_consume_token (parser);
+
+ if (t == error_mark_node)
;
else if (kind != 0)
{
- tree u = build_omp_clause (clause_loc, kind);
- OMP_CLAUSE_DECL (u) = t;
- OMP_CLAUSE_CHAIN (u) = list;
- list = u;
+ switch (kind)
+ {
+ case OMP_CLAUSE_MAP:
+ case OMP_CLAUSE_FROM:
+ case OMP_CLAUSE_TO:
+ case OMP_CLAUSE_DEPEND:
+ while (c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
+ {
+ tree low_bound = NULL_TREE, length = NULL_TREE;
+
+ c_parser_consume_token (parser);
+ if (!c_parser_next_token_is (parser, CPP_COLON))
+ low_bound = c_parser_expression (parser).value;
+ if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
+ length = integer_one_node;
+ else
+ {
+ /* Look for `:'. */
+ if (!c_parser_require (parser, CPP_COLON,
+ "expected %<:%>"))
+ {
+ t = error_mark_node;
+ break;
+ }
+ if (!c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
+ length = c_parser_expression (parser).value;
+ }
+ /* Look for the closing `]'. */
+ if (!c_parser_require (parser, CPP_CLOSE_SQUARE,
+ "expected %<]%>"))
+ {
+ t = error_mark_node;
+ break;
+ }
+ t = tree_cons (low_bound, length, t);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (t != error_mark_node)
+ {
+ tree u = build_omp_clause (clause_loc, kind);
+ OMP_CLAUSE_DECL (u) = t;
+ OMP_CLAUSE_CHAIN (u) = list;
+ list = u;
+ }
}
else
list = tree_cons (t, NULL_TREE, list);
- c_parser_consume_token (parser);
-
if (c_parser_next_token_is_not (parser, CPP_COMMA))
break;
@@ -9209,6 +9422,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
@@ -9474,11 +9689,17 @@ c_parser_omp_clause_private (c_parser *parser, tree list)
reduction-operator:
One of: + * - & ^ | && ||
-
+
OpenMP 3.1:
reduction-operator:
- One of: + * - & ^ | && || max min */
+ One of: + * - & ^ | && || max min
+
+ OpenMP 4.0:
+
+ reduction-operator:
+ One of: + * - & ^ | && ||
+ identifier */
static tree
c_parser_omp_clause_reduction (c_parser *parser, tree list)
@@ -9486,7 +9707,8 @@ c_parser_omp_clause_reduction (c_parser *parser, tree list)
location_t clause_loc = c_parser_peek_token (parser)->location;
if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
{
- enum tree_code code;
+ enum tree_code code = ERROR_MARK;
+ tree reduc_id = NULL_TREE;
switch (c_parser_peek_token (parser)->type)
{
@@ -9528,8 +9750,9 @@ c_parser_omp_clause_reduction (c_parser *parser, tree list)
code = MAX_EXPR;
break;
}
+ reduc_id = c_parser_peek_token (parser)->value;
+ break;
}
- /* FALLTHRU */
default:
c_parser_error (parser,
"expected %<+%>, %<*%>, %<-%>, %<&%>, "
@@ -9538,6 +9761,7 @@ c_parser_omp_clause_reduction (c_parser *parser, tree list)
return list;
}
c_parser_consume_token (parser);
+ reduc_id = c_omp_reduction_id (code, reduc_id);
if (c_parser_require (parser, CPP_COLON, "expected %<:%>"))
{
tree nl, c;
@@ -9545,7 +9769,17 @@ c_parser_omp_clause_reduction (c_parser *parser, tree list)
nl = c_parser_omp_variable_list (parser, clause_loc,
OMP_CLAUSE_REDUCTION, list);
for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
- OMP_CLAUSE_REDUCTION_CODE (c) = code;
+ {
+ tree type = TREE_TYPE (OMP_CLAUSE_DECL (c));
+ OMP_CLAUSE_REDUCTION_CODE (c) = code;
+ if (code == ERROR_MARK
+ || !(INTEGRAL_TYPE_P (type)
+ || TREE_CODE (type) == REAL_TYPE
+ || TREE_CODE (type) == COMPLEX_TYPE))
+ OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)
+ = c_omp_reduction_lookup (reduc_id,
+ TYPE_MAIN_VARIANT (type));
+ }
list = nl;
}
@@ -9675,13 +9909,544 @@ c_parser_omp_clause_untied (c_parser *parser ATTRIBUTE_UNUSED, tree list)
return c;
}
+/* OpenMP 4.0:
+ inbranch
+ notinbranch */
+
+static tree
+c_parser_omp_clause_branch (c_parser *parser ATTRIBUTE_UNUSED,
+ enum omp_clause_code code, tree list)
+{
+ check_no_duplicate_clause (list, code, omp_clause_code_name[code]);
+
+ tree c = build_omp_clause (c_parser_peek_token (parser)->location, code);
+ OMP_CLAUSE_CHAIN (c) = list;
+
+ return c;
+}
+
+/* OpenMP 4.0:
+ parallel
+ for
+ sections
+ taskgroup */
+
+static tree
+c_parser_omp_clause_cancelkind (c_parser *parser ATTRIBUTE_UNUSED,
+ enum omp_clause_code code, tree list)
+{
+ tree c = build_omp_clause (c_parser_peek_token (parser)->location, code);
+ OMP_CLAUSE_CHAIN (c) = list;
+
+ return c;
+}
+
+/* OpenMP 4.0:
+ num_teams ( expression ) */
+
+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)))
+ {
+ c_parser_error (parser, "expected integer expression");
+ return list;
+ }
+
+ /* Attempt to statically determine when the number isn't positive. */
+ c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t,
+ build_int_cst (TREE_TYPE (t), 0));
+ if (CAN_HAVE_LOCATION_P (c))
+ SET_EXPR_LOCATION (c, expr_loc);
+ if (c == boolean_true_node)
+ {
+ warning_at (expr_loc, 0, "%<num_teams%> value must be positive");
+ t = integer_one_node;
+ }
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_NUM_TEAMS, "num_teams");
+
+ 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;
+ }
+
+ return list;
+}
+
+/* OpenMP 4.0:
+ thread_limit ( expression ) */
+
+static tree
+c_parser_omp_clause_thread_limit (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)))
+ {
+ c_parser_error (parser, "expected integer expression");
+ return list;
+ }
+
+ /* Attempt to statically determine when the number isn't positive. */
+ c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t,
+ build_int_cst (TREE_TYPE (t), 0));
+ if (CAN_HAVE_LOCATION_P (c))
+ SET_EXPR_LOCATION (c, expr_loc);
+ if (c == boolean_true_node)
+ {
+ warning_at (expr_loc, 0, "%<thread_limit%> value must be positive");
+ t = integer_one_node;
+ }
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_THREAD_LIMIT,
+ "thread_limit");
+
+ c = build_omp_clause (num_teams_loc, OMP_CLAUSE_THREAD_LIMIT);
+ OMP_CLAUSE_THREAD_LIMIT_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+ list = c;
+ }
+
+ return list;
+}
+
+/* OpenMP 4.0:
+ aligned ( variable-list )
+ aligned ( variable-list : constant-expression ) */
+
+static tree
+c_parser_omp_clause_aligned (c_parser *parser, tree list)
+{
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+ tree nl, c;
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return list;
+
+ nl = c_parser_omp_variable_list (parser, clause_loc,
+ OMP_CLAUSE_ALIGNED, list);
+
+ 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, "%<aligned%> clause alignment expression must "
+ "be positive constant integer expression");
+ alignment = NULL_TREE;
+ }
+
+ for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+ OMP_CLAUSE_ALIGNED_ALIGNMENT (c) = alignment;
+ }
+
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ return nl;
+}
+
+/* OpenMP 4.0:
+ linear ( variable-list )
+ linear ( variable-list : expression ) */
+
+static tree
+c_parser_omp_clause_linear (c_parser *parser, tree list)
+{
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+ tree nl, c, step;
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return list;
+
+ nl = c_parser_omp_variable_list (parser, clause_loc,
+ OMP_CLAUSE_LINEAR, list);
+
+ 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, "%<linear%> clause step expression must "
+ "be integral");
+ step = integer_one_node;
+ }
+
+ }
+ else
+ step = integer_one_node;
+
+ for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+ {
+ 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, "%<safelen%> 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, "%<simdlen%> 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);
+
+ 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);
+
+ 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);
+ 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, unsigned int mask,
- const char *where)
+c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask,
+ const char *where, bool finish_p = true)
{
tree clauses = NULL;
bool first = true;
@@ -9696,7 +10461,6 @@ c_parser_omp_all_clauses (c_parser *parser, unsigned int mask,
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);
@@ -9770,11 +10534,116 @@ c_parser_omp_all_clauses (c_parser *parser, unsigned int mask,
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";
+ if (!first)
+ {
+ clause_not_first:
+ error_at (here, "%qs must be the first clause of %qs",
+ c_name, where);
+ clauses = prev;
+ }
+ break;
+ case PRAGMA_OMP_CLAUSE_FOR:
+ clauses
+ = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_FOR,
+ clauses);
+ c_name = "for";
+ if (!first)
+ goto clause_not_first;
+ break;
+ case PRAGMA_OMP_CLAUSE_SECTIONS:
+ clauses
+ = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_SECTIONS,
+ clauses);
+ c_name = "sections";
+ if (!first)
+ goto clause_not_first;
+ break;
+ case PRAGMA_OMP_CLAUSE_TASKGROUP:
+ clauses
+ = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_TASKGROUP,
+ clauses);
+ c_name = "taskgroup";
+ if (!first)
+ goto clause_not_first;
+ 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_THREAD_LIMIT:
+ clauses = c_parser_omp_clause_thread_limit (parser, clauses);
+ c_name = "thread_limit";
+ break;
+ case PRAGMA_OMP_CLAUSE_ALIGNED:
+ clauses = c_parser_omp_clause_aligned (parser, clauses);
+ c_name = "aligned";
+ break;
+ case PRAGMA_OMP_CLAUSE_LINEAR:
+ clauses = c_parser_omp_clause_linear (parser, clauses);
+ 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;
}
+ first = false;
+
if (((mask >> c_kind) & 1) == 0 && !parser->error)
{
/* Remove the invalid clause(s) from the list to avoid
@@ -9787,7 +10656,10 @@ c_parser_omp_all_clauses (c_parser *parser, unsigned int mask,
saw_error:
c_parser_skip_to_pragma_eol (parser);
- return c_finish_omp_clauses (clauses);
+ if (finish_p)
+ return c_finish_omp_clauses (clauses);
+
+ return clauses;
}
/* OpenMP 2.5:
@@ -9843,10 +10715,18 @@ c_parser_omp_structured_block (c_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.
LOC is the location of the #pragma token. */
@@ -9856,10 +10736,13 @@ 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;
+ tree stmt, orig_lhs, unfolded_lhs = NULL_TREE, unfolded_lhs1 = NULL_TREE;
enum tree_code code = OMP_ATOMIC, opcode = NOP_EXPR;
- struct c_expr rhs_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))
{
@@ -9878,6 +10761,15 @@ c_parser_omp_atomic (location_t loc, c_parser *parser)
if (p)
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)
@@ -9931,7 +10823,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))
@@ -9958,6 +10854,7 @@ restart:
/* FALLTHROUGH */
case PREINCREMENT_EXPR:
lhs = TREE_OPERAND (lhs, 0);
+ unfolded_lhs = NULL_TREE;
opcode = PLUS_EXPR;
rhs = integer_one_node;
break;
@@ -9968,6 +10865,7 @@ restart:
/* FALLTHROUGH */
case PREDECREMENT_EXPR:
lhs = TREE_OPERAND (lhs, 0);
+ unfolded_lhs = NULL_TREE;
opcode = MINUS_EXPR;
rhs = integer_one_node;
break;
@@ -9993,6 +10891,7 @@ restart:
/* 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
@@ -10007,6 +10906,7 @@ restart:
/* 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
@@ -10047,87 +10947,67 @@ restart:
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;
}
- 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 */
+ 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;
+ }
+ }
+ c_parser_error (parser, "invalid form of %<#pragma omp atomic%>");
+ goto saw_error;
default:
c_parser_error (parser,
"invalid operator for %<#pragma omp atomic%>");
@@ -10138,12 +11018,10 @@ restart:
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;
}
@@ -10158,7 +11036,11 @@ stmt_done:
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;
@@ -10169,7 +11051,16 @@ stmt_done:
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);
@@ -10249,8 +11140,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 *cclauses)
{
tree decl, cond, incr, save_break, save_cont, body, init, stmt, cl;
tree declv, condv, incrv, initv, ret = NULL;
@@ -10290,7 +11181,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;
@@ -10337,8 +11229,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);
@@ -10477,13 +11369,15 @@ 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)
+ if (cclauses != NULL
+ && cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] != NULL)
{
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_CODE (*c) != OMP_CLAUSE_LASTPRIVATE)
c = &OMP_CLAUSE_CHAIN (*c);
@@ -10532,33 +11426,128 @@ pop_scopes:
return ret;
}
+/* Helper function for OpenMP parsing, split clauses and call
+ finish_omp_clauses on each of the set of clauses afterwards. */
+
+static void
+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] = c_finish_omp_clauses (cclauses[i]);
+}
+
+/* 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,
+ char *p_name, omp_clause_mask mask, tree *cclauses)
+{
+ tree block, clauses, ret;
+
+ strcat (p_name, " simd");
+ mask |= OMP_SIMD_CLAUSE_MASK;
+ mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED);
+
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+ if (cclauses)
+ {
+ omp_split_clauses (loc, OMP_SIMD, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_SIMD];
+ }
+
+ block = c_begin_compound_stmt (true);
+ ret = c_parser_omp_for_loop (loc, parser, OMP_SIMD, clauses, cclauses);
+ 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)
+c_parser_omp_for (location_t loc, c_parser *parser,
+ char *p_name, omp_clause_mask mask, tree *cclauses)
{
tree block, clauses, ret;
- clauses = c_parser_omp_all_clauses (parser, OMP_FOR_CLAUSE_MASK,
- "#pragma omp for");
+ strcat (p_name, " for");
+ mask |= OMP_FOR_CLAUSE_MASK;
+ if (cclauses)
+ 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)
+ {
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+
+ c_parser_consume_token (parser);
+ block = c_begin_compound_stmt (true);
+ ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses);
+ block = c_end_compound_stmt (loc, block, true);
+ if (ret == NULL_TREE)
+ return ret;
+ ret = make_node (OMP_FOR);
+ TREE_TYPE (ret) = void_type_node;
+ OMP_FOR_BODY (ret) = block;
+ OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_FOR];
+ SET_EXPR_LOCATION (ret, loc);
+ add_stmt (ret);
+ return ret;
+ }
+ }
+
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+ if (cclauses)
+ {
+ omp_split_clauses (loc, OMP_FOR, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_FOR];
+ }
block = c_begin_compound_stmt (true);
- ret = c_parser_omp_for_loop (loc, parser, clauses, NULL);
+ ret = c_parser_omp_for_loop (loc, parser, OMP_FOR, clauses, cclauses);
block = c_end_compound_stmt (loc, block, true);
add_stmt (block);
@@ -10623,21 +11612,7 @@ c_parser_omp_sections_scope (location_t sections_loc, c_parser *parser)
if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_SECTION)
{
- substmt = push_stmt_list ();
-
- while (1)
- {
- c_parser_statement (parser);
-
- if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION)
- break;
- if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
- break;
- if (c_parser_next_token_is (parser, CPP_EOF))
- break;
- }
-
- substmt = pop_stmt_list (substmt);
+ substmt = c_parser_omp_structured_block (parser);
substmt = build1 (OMP_SECTION, void_type_node, substmt);
SET_EXPR_LOCATION (substmt, loc);
add_stmt (substmt);
@@ -10688,20 +11663,30 @@ 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)
+c_parser_omp_sections (location_t loc, c_parser *parser,
+ char *p_name, omp_clause_mask mask, tree *cclauses)
{
tree block, clauses, ret;
- clauses = c_parser_omp_all_clauses (parser, OMP_SECTIONS_CLAUSE_MASK,
- "#pragma omp sections");
+ strcat (p_name, " sections");
+ mask |= OMP_SECTIONS_CLAUSE_MASK;
+ if (cclauses)
+ mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT);
+
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+ if (cclauses)
+ {
+ omp_split_clauses (loc, OMP_SECTIONS, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_SECTIONS];
+ }
block = c_begin_compound_stmt (true);
ret = c_parser_omp_sections_scope (loc, parser);
@@ -10721,76 +11706,72 @@ 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)
+c_parser_omp_parallel (location_t loc, c_parser *parser,
+ 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 stmt, clauses, block;
+
+ strcat (p_name, " parallel");
+ mask |= OMP_PARALLEL_CLAUSE_MASK;
if (c_parser_next_token_is_keyword (parser, RID_FOR))
{
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+
c_parser_consume_token (parser);
- p_kind = PRAGMA_OMP_PARALLEL_FOR;
- p_name = "#pragma omp parallel for";
- mask |= OMP_FOR_CLAUSE_MASK;
- mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT);
+ block = c_begin_omp_parallel ();
+ c_parser_omp_for (loc, parser, p_name, mask, cclauses);
+ stmt
+ = c_finish_omp_parallel (loc, cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL],
+ block);
+ OMP_PARALLEL_COMBINED (stmt) = 1;
+ return stmt;
+ }
+ else if (cclauses)
+ {
+ error_at (loc, "expected %<for%> after %qs", p_name);
+ c_parser_skip_to_pragma_eol (parser);
+ return NULL_TREE;
}
else if (c_parser_next_token_is (parser, CPP_NAME))
{
const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
if (strcmp (p, "sections") == 0)
{
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+
c_parser_consume_token (parser);
- p_kind = PRAGMA_OMP_PARALLEL_SECTIONS;
- p_name = "#pragma omp parallel sections";
- mask |= OMP_SECTIONS_CLAUSE_MASK;
- mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT);
+ block = c_begin_omp_parallel ();
+ c_parser_omp_sections (loc, parser, p_name, mask, cclauses);
+ stmt = c_finish_omp_parallel (loc,
+ cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL],
+ block);
+ OMP_PARALLEL_COMBINED (stmt) = 1;
+ return stmt;
}
}
- clauses = c_parser_omp_all_clauses (parser, mask, p_name);
-
- switch (p_kind)
- {
- case PRAGMA_OMP_PARALLEL:
- block = c_begin_omp_parallel ();
- c_parser_statement (parser);
- stmt = c_finish_omp_parallel (loc, clauses, block);
- break;
-
- 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);
- stmt = c_finish_omp_parallel (loc, par_clause, block);
- OMP_PARALLEL_COMBINED (stmt) = 1;
- break;
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
- case PRAGMA_OMP_PARALLEL_SECTIONS:
- block = c_begin_omp_parallel ();
- c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause);
- stmt = c_parser_omp_sections_scope (loc, parser);
- if (stmt)
- OMP_SECTIONS_CLAUSES (stmt) = ws_clause;
- stmt = c_finish_omp_parallel (loc, par_clause, block);
- OMP_PARALLEL_COMBINED (stmt) = 1;
- break;
-
- default:
- gcc_unreachable ();
- }
+ block = c_begin_omp_parallel ();
+ c_parser_statement (parser);
+ stmt = c_finish_omp_parallel (loc, clauses, block);
return stmt;
}
@@ -10802,11 +11783,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)
@@ -10829,15 +11810,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)
@@ -10880,6 +11862,983 @@ c_parser_omp_taskyield (c_parser *parser)
c_finish_omp_taskyield (loc);
}
+/* OpenMP 4.0:
+ # pragma omp taskgroup new-line
+*/
+
+static tree
+c_parser_omp_taskgroup (c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_skip_to_pragma_eol (parser);
+ return c_finish_omp_taskgroup (loc, c_parser_omp_structured_block (parser));
+}
+
+/* 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");
+
+ 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 %<point%>");
+ c_parser_skip_to_pragma_eol (parser);
+ return;
+ }
+
+ clauses
+ = c_parser_omp_all_clauses (parser, OMP_CANCELLATION_POINT_CLAUSE_MASK,
+ "#pragma omp cancellation point");
+
+ c_finish_omp_cancellation_point (loc, clauses);
+}
+
+/* OpenMP 4.0:
+ #pragma omp distribute distribute-clause[optseq] new-line
+ for-loop */
+
+#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
+c_parser_omp_distribute (location_t loc, c_parser *parser,
+ char *p_name, omp_clause_mask mask, tree *cclauses)
+{
+ tree clauses, block, ret;
+
+ strcat (p_name, " distribute");
+ mask |= OMP_DISTRIBUTE_CLAUSE_MASK;
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ 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;
+ c_parser_consume_token (parser);
+ block = c_begin_compound_stmt (true);
+ if (simd)
+ ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses);
+ else
+ ret = c_parser_omp_parallel (loc, parser, p_name, mask, cclauses);
+ block = c_end_compound_stmt (loc, block, true);
+ if (ret == NULL)
+ return ret;
+ ret = make_node (OMP_DISTRIBUTE);
+ TREE_TYPE (ret) = void_type_node;
+ OMP_FOR_BODY (ret) = block;
+ OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE];
+ SET_EXPR_LOCATION (ret, loc);
+ add_stmt (ret);
+ return ret;
+ }
+ }
+
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+ if (cclauses)
+ {
+ omp_split_clauses (loc, OMP_DISTRIBUTE, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE];
+ }
+
+ block = c_begin_compound_stmt (true);
+ ret = c_parser_omp_for_loop (loc, parser, OMP_DISTRIBUTE, clauses, NULL);
+ block = c_end_compound_stmt (loc, block, true);
+ add_stmt (block);
+
+ return ret;
+}
+
+/* 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
+c_parser_omp_teams (location_t loc, c_parser *parser,
+ char *p_name, omp_clause_mask mask, tree *cclauses)
+{
+ tree clauses, block, ret;
+
+ strcat (p_name, " teams");
+ mask |= OMP_TEAMS_CLAUSE_MASK;
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "distribute") == 0)
+ {
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+
+ c_parser_consume_token (parser);
+ block = c_begin_compound_stmt (true);
+ ret = c_parser_omp_distribute (loc, parser, p_name, mask, cclauses);
+ block = c_end_compound_stmt (loc, block, true);
+ 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) = block;
+ return add_stmt (ret);
+ }
+ }
+
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+ if (cclauses)
+ {
+ omp_split_clauses (loc, OMP_TEAMS, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS];
+ }
+
+ tree stmt = make_node (OMP_TEAMS);
+ TREE_TYPE (stmt) = void_type_node;
+ OMP_TEAMS_CLAUSES (stmt) = clauses;
+ OMP_TEAMS_BODY (stmt) = c_parser_omp_structured_block (parser);
+
+ return add_stmt (stmt);
+}
+
+/* OpenMP 4.0:
+ # pragma omp target data target-data-clause[optseq] new-line
+ structured-block */
+
+#define OMP_TARGET_DATA_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF))
+
+static tree
+c_parser_omp_target_data (location_t loc, c_parser *parser)
+{
+ tree stmt = make_node (OMP_TARGET_DATA);
+ TREE_TYPE (stmt) = void_type_node;
+
+ OMP_TARGET_DATA_CLAUSES (stmt)
+ = c_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK,
+ "#pragma omp target data");
+ keep_next_level ();
+ tree block = c_begin_compound_stmt (true);
+ add_stmt (c_parser_omp_structured_block (parser));
+ OMP_TARGET_DATA_BODY (stmt) = c_end_compound_stmt (loc, block, true);
+
+ SET_EXPR_LOCATION (stmt, loc);
+ return add_stmt (stmt);
+}
+
+/* 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
+c_parser_omp_target_update (location_t loc, c_parser *parser,
+ enum pragma_context context)
+{
+ if (context == pragma_stmt)
+ {
+ error_at (loc,
+ "%<#pragma omp target update%> may only be "
+ "used in compound statements");
+ c_parser_skip_to_pragma_eol (parser);
+ return false;
+ }
+
+ tree clauses
+ = c_parser_omp_all_clauses (parser, OMP_TARGET_UPDATE_CLAUSE_MASK,
+ "#pragma omp target update");
+ if (find_omp_clause (clauses, OMP_CLAUSE_TO) == NULL_TREE
+ && find_omp_clause (clauses, OMP_CLAUSE_FROM) == NULL_TREE)
+ {
+ error_at (loc,
+ "%<#pragma omp target update must contain at least one "
+ "%<from%> or %<to%> 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, loc);
+ add_stmt (stmt);
+ return false;
+}
+
+/* OpenMP 4.0:
+ # pragma omp target target-clause[optseq] new-line
+ structured-block */
+
+#define OMP_TARGET_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF))
+
+static bool
+c_parser_omp_target (c_parser *parser, enum pragma_context context)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_pragma (parser);
+
+ if (context != pragma_stmt && context != pragma_compound)
+ {
+ c_parser_error (parser, "expected declaration specifiers");
+ c_parser_skip_to_pragma_eol (parser);
+ return false;
+ }
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+ if (strcmp (p, "data") == 0)
+ {
+ c_parser_consume_token (parser);
+ c_parser_omp_target_data (loc, parser);
+ return true;
+ }
+ else if (strcmp (p, "update") == 0)
+ {
+ c_parser_consume_token (parser);
+ return c_parser_omp_target_update (loc, parser, 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")];
+
+ c_parser_consume_token (parser);
+ strcpy (p_name, "#pragma omp target");
+ keep_next_level ();
+ tree block = c_begin_compound_stmt (true);
+ tree ret = c_parser_omp_teams (loc, parser, p_name,
+ OMP_TARGET_CLAUSE_MASK, cclauses);
+ block = c_end_compound_stmt (loc, block, true);
+ 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) = block;
+ add_stmt (stmt);
+ return true;
+ }
+ }
+
+ tree stmt = make_node (OMP_TARGET);
+ TREE_TYPE (stmt) = void_type_node;
+
+ OMP_TARGET_CLAUSES (stmt)
+ = c_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK,
+ "#pragma omp target");
+ keep_next_level ();
+ tree block = c_begin_compound_stmt (true);
+ add_stmt (c_parser_omp_structured_block (parser));
+ OMP_TARGET_BODY (stmt) = c_end_compound_stmt (loc, block, true);
+
+ SET_EXPR_LOCATION (stmt, loc);
+ add_stmt (stmt);
+ return true;
+}
+
+/* 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_INBRANCH) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOTINBRANCH))
+
+static void
+c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
+{
+ vec<c_token> clauses = vNULL;
+ while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+ {
+ c_token *token = c_parser_peek_token (parser);
+ if (token->type == CPP_EOF)
+ {
+ c_parser_skip_to_pragma_eol (parser);
+ clauses.release ();
+ return;
+ }
+ clauses.safe_push (*token);
+ c_parser_consume_token (parser);
+ }
+ clauses.safe_push (*c_parser_peek_token (parser));
+ c_parser_skip_to_pragma_eol (parser);
+
+ 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);
+ while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+ {
+ c_token *token = c_parser_peek_token (parser);
+ if (token->type == CPP_EOF)
+ {
+ c_parser_skip_to_pragma_eol (parser);
+ clauses.release ();
+ return;
+ }
+ clauses.safe_push (*token);
+ c_parser_consume_token (parser);
+ }
+ clauses.safe_push (*c_parser_peek_token (parser));
+ c_parser_skip_to_pragma_eol (parser);
+ }
+
+ /* Make sure nothing tries to read past the end of the tokens. */
+ c_token eof_token;
+ memset (&eof_token, 0, sizeof (eof_token));
+ eof_token.type = CPP_EOF;
+ clauses.safe_push (eof_token);
+ clauses.safe_push (eof_token);
+
+ 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 ();
+}
+
+/* Finalize #pragma omp declare simd clauses after FNDECL has been parsed,
+ and put that into "omp declare simd" attribute. */
+
+static void
+c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms,
+ vec<c_token> clauses)
+{
+ /* Normally first token is CPP_NAME "simd". CPP_EOF there indicates
+ error has been reported and CPP_PRAGMA that c_finish_omp_declare_simd
+ has already processed the tokens. */
+ if (clauses[0].type == CPP_EOF)
+ 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].type = CPP_EOF;
+ return;
+ }
+ if (clauses[0].type != CPP_NAME)
+ {
+ error_at (DECL_SOURCE_LOCATION (fndecl),
+ "%<#pragma omp declare simd%> not immediately followed by "
+ "a single function declaration or definition");
+ clauses[0].type = CPP_EOF;
+ return;
+ }
+
+ if (parms == NULL_TREE)
+ parms = DECL_ARGUMENTS (fndecl);
+
+ unsigned int tokens_avail = parser->tokens_avail;
+ gcc_assert (parser->tokens == &parser->tokens_buf[0]);
+ parser->tokens = clauses.address ();
+ parser->tokens_avail = clauses.length ();
+
+ /* c_parser_omp_declare_simd pushed 2 extra CPP_EOF tokens at the end. */
+ while (parser->tokens_avail > 3)
+ {
+ c_token *token = c_parser_peek_token (parser);
+ gcc_assert (token->type == CPP_NAME
+ && strcmp (IDENTIFIER_POINTER (token->value), "simd") == 0);
+ c_parser_consume_token (parser);
+ parser->in_pragma = true;
+
+ tree c = c_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK,
+ "#pragma omp declare simd");
+ c = c_omp_declare_simd_clauses_to_numbers (parms, c);
+ if (c != NULL_TREE)
+ c = tree_cons (NULL_TREE, c, NULL_TREE);
+ c = build_tree_list (get_identifier ("omp declare simd"), c);
+ TREE_CHAIN (c) = DECL_ATTRIBUTES (fndecl);
+ DECL_ATTRIBUTES (fndecl) = c;
+ }
+
+ parser->tokens = &parser->tokens_buf[0];
+ parser->tokens_avail = tokens_avail;
+ clauses[0].type = CPP_PRAGMA;
+}
+
+
+/* OpenMP 4.0:
+ # pragma omp declare target new-line
+ declarations and definitions
+ # pragma omp end declare target new-line */
+
+static void
+c_parser_omp_declare_target (c_parser *parser)
+{
+ c_parser_skip_to_pragma_eol (parser);
+ current_omp_declare_target_attribute++;
+}
+
+static void
+c_parser_omp_end_declare_target (c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_pragma (parser);
+ if (c_parser_next_token_is (parser, CPP_NAME)
+ && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value),
+ "declare") == 0)
+ {
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_NAME)
+ && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value),
+ "target") == 0)
+ c_parser_consume_token (parser);
+ else
+ {
+ c_parser_error (parser, "expected %<target%>");
+ c_parser_skip_to_pragma_eol (parser);
+ return;
+ }
+ }
+ else
+ {
+ c_parser_error (parser, "expected %<declare%>");
+ c_parser_skip_to_pragma_eol (parser);
+ return;
+ }
+ c_parser_skip_to_pragma_eol (parser);
+ if (!current_omp_declare_target_attribute)
+ error_at (loc, "%<#pragma omp end declare target%> without corresponding "
+ "%<#pragma omp declare target%>");
+ else
+ current_omp_declare_target_attribute--;
+}
+
+
+/* OpenMP 4.0
+ #pragma omp declare reduction (reduction-id : typename-list : expression) \
+ initializer-clause[opt] new-line
+
+ initializer-clause:
+ initializer (omp_priv = initializer)
+ initializer (function-name (argument-list)) */
+
+static void
+c_parser_omp_declare_reduction (c_parser *parser, enum pragma_context context)
+{
+ unsigned int tokens_avail = 0, i;
+ vec<tree> types = vNULL;
+ vec<c_token> clauses = vNULL;
+ enum tree_code reduc_code = ERROR_MARK;
+ tree reduc_id = NULL_TREE;
+ tree type;
+ location_t rloc = c_parser_peek_token (parser)->location;
+
+ if (context == pragma_struct || context == pragma_param)
+ {
+ error ("%<#pragma omp declare reduction%> not at file or block scope");
+ goto fail;
+ }
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ goto fail;
+
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_PLUS:
+ reduc_code = PLUS_EXPR;
+ break;
+ case CPP_MULT:
+ reduc_code = MULT_EXPR;
+ break;
+ case CPP_MINUS:
+ reduc_code = MINUS_EXPR;
+ break;
+ case CPP_AND:
+ reduc_code = BIT_AND_EXPR;
+ break;
+ case CPP_XOR:
+ reduc_code = BIT_XOR_EXPR;
+ break;
+ case CPP_OR:
+ reduc_code = BIT_IOR_EXPR;
+ break;
+ case CPP_AND_AND:
+ reduc_code = TRUTH_ANDIF_EXPR;
+ break;
+ case CPP_OR_OR:
+ reduc_code = TRUTH_ORIF_EXPR;
+ break;
+ case CPP_NAME:
+ const char *p;
+ p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "min") == 0)
+ {
+ reduc_code = MIN_EXPR;
+ break;
+ }
+ if (strcmp (p, "max") == 0)
+ {
+ reduc_code = MAX_EXPR;
+ break;
+ }
+ reduc_id = c_parser_peek_token (parser)->value;
+ break;
+ default:
+ c_parser_error (parser,
+ "expected %<+%>, %<*%>, %<-%>, %<&%>, "
+ "%<^%>, %<|%>, %<&&%>, %<||%>, %<min%> or identifier");
+ goto fail;
+ }
+
+ tree orig_reduc_id, reduc_decl;
+ orig_reduc_id = reduc_id;
+ reduc_id = c_omp_reduction_id (reduc_code, reduc_id);
+ reduc_decl = c_omp_reduction_decl (reduc_id);
+ c_parser_consume_token (parser);
+
+ if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ goto fail;
+
+ while (true)
+ {
+ location_t loc = c_parser_peek_token (parser)->location;
+ struct c_type_name *ctype = c_parser_type_name (parser);
+ if (ctype != NULL)
+ {
+ type = groktypename (ctype, NULL, NULL);
+ if (type == error_mark_node)
+ ;
+ else if ((INTEGRAL_TYPE_P (type)
+ || TREE_CODE (type) == REAL_TYPE
+ || TREE_CODE (type) == COMPLEX_TYPE)
+ && orig_reduc_id == NULL_TREE)
+ error_at (loc, "predeclared arithmetic type in "
+ "%<#pragma omp declare reduction%>");
+ else if (TREE_CODE (type) == FUNCTION_TYPE
+ || TREE_CODE (type) == ARRAY_TYPE)
+ error_at (loc, "function or array type in "
+ "%<#pragma omp declare reduction%>");
+ else if (TYPE_QUALS_NO_ADDR_SPACE (type))
+ error_at (loc, "const, volatile or restrict qualified type in "
+ "%<#pragma omp declare reduction%>");
+ else
+ {
+ tree t;
+ for (t = DECL_INITIAL (reduc_decl); t; t = TREE_CHAIN (t))
+ if (comptypes (TREE_PURPOSE (t), type))
+ {
+ error_at (loc, "redeclaration of %qs "
+ "%<#pragma omp declare reduction%> for "
+ "type %qT",
+ IDENTIFIER_POINTER (reduc_id)
+ + sizeof ("omp declare reduction ") - 1,
+ type);
+ location_t ploc
+ = DECL_SOURCE_LOCATION (TREE_VEC_ELT (TREE_VALUE (t),
+ 0));
+ error_at (ploc, "previous %<#pragma omp declare "
+ "reduction%>");
+ break;
+ }
+ if (t == NULL_TREE)
+ types.safe_push (type);
+ }
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else
+ break;
+ }
+ else
+ break;
+ }
+
+ if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")
+ || types.is_empty ())
+ {
+ fail:
+ clauses.release ();
+ types.release ();
+ while (true)
+ {
+ c_token *token = c_parser_peek_token (parser);
+ if (token->type == CPP_EOF || token->type == CPP_PRAGMA_EOL)
+ break;
+ c_parser_consume_token (parser);
+ }
+ c_parser_skip_to_pragma_eol (parser);
+ return;
+ }
+
+ if (types.length () > 1)
+ {
+ while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+ {
+ c_token *token = c_parser_peek_token (parser);
+ if (token->type == CPP_EOF)
+ goto fail;
+ clauses.safe_push (*token);
+ c_parser_consume_token (parser);
+ }
+ clauses.safe_push (*c_parser_peek_token (parser));
+ c_parser_skip_to_pragma_eol (parser);
+
+ /* Make sure nothing tries to read past the end of the tokens. */
+ c_token eof_token;
+ memset (&eof_token, 0, sizeof (eof_token));
+ eof_token.type = CPP_EOF;
+ clauses.safe_push (eof_token);
+ clauses.safe_push (eof_token);
+ }
+
+ int errs = errorcount;
+ FOR_EACH_VEC_ELT (types, i, type)
+ {
+ tokens_avail = parser->tokens_avail;
+ gcc_assert (parser->tokens == &parser->tokens_buf[0]);
+ if (!clauses.is_empty ())
+ {
+ parser->tokens = clauses.address ();
+ parser->tokens_avail = clauses.length ();
+ parser->in_pragma = true;
+ }
+
+ bool nested = current_function_decl != NULL_TREE;
+ if (nested)
+ c_push_function_context ();
+ tree fndecl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
+ reduc_id, default_function_type);
+ current_function_decl = fndecl;
+ allocate_struct_function (fndecl, true);
+ push_scope ();
+ tree stmt = push_stmt_list ();
+ /* Intentionally BUILTINS_LOCATION, so that -Wshadow doesn't
+ warn about these. */
+ tree omp_out = build_decl (BUILTINS_LOCATION, VAR_DECL,
+ get_identifier ("omp_out"), type);
+ DECL_ARTIFICIAL (omp_out) = 1;
+ DECL_CONTEXT (omp_out) = fndecl;
+ pushdecl (omp_out);
+ tree omp_in = build_decl (BUILTINS_LOCATION, VAR_DECL,
+ get_identifier ("omp_in"), type);
+ DECL_ARTIFICIAL (omp_in) = 1;
+ DECL_CONTEXT (omp_in) = fndecl;
+ pushdecl (omp_in);
+ struct c_expr combiner = c_parser_expression (parser);
+ struct c_expr initializer;
+ tree omp_priv = NULL_TREE, omp_orig = NULL_TREE;
+ bool bad = false;
+ initializer.value = error_mark_node;
+ if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+ bad = true;
+ else if (c_parser_next_token_is (parser, CPP_NAME)
+ && strcmp (IDENTIFIER_POINTER
+ (c_parser_peek_token (parser)->value),
+ "initializer") == 0)
+ {
+ c_parser_consume_token (parser);
+ pop_scope ();
+ push_scope ();
+ omp_priv = build_decl (BUILTINS_LOCATION, VAR_DECL,
+ get_identifier ("omp_priv"), type);
+ DECL_ARTIFICIAL (omp_priv) = 1;
+ DECL_INITIAL (omp_priv) = error_mark_node;
+ DECL_CONTEXT (omp_priv) = fndecl;
+ pushdecl (omp_priv);
+ omp_orig = build_decl (BUILTINS_LOCATION, VAR_DECL,
+ get_identifier ("omp_orig"), type);
+ DECL_ARTIFICIAL (omp_orig) = 1;
+ DECL_CONTEXT (omp_orig) = fndecl;
+ pushdecl (omp_orig);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ bad = true;
+ else if (!c_parser_next_token_is (parser, CPP_NAME))
+ {
+ c_parser_error (parser, "expected %<omp_priv%> or "
+ "function-name");
+ bad = true;
+ }
+ else if (strcmp (IDENTIFIER_POINTER
+ (c_parser_peek_token (parser)->value),
+ "omp_priv") != 0)
+ {
+ if (c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN
+ || c_parser_peek_token (parser)->id_kind != C_ID_ID)
+ {
+ c_parser_error (parser, "expected function-name %<(%>");
+ bad = true;
+ }
+ else
+ initializer = c_parser_postfix_expression (parser);
+ if (initializer.value
+ && TREE_CODE (initializer.value) == CALL_EXPR)
+ {
+ int j;
+ tree c = initializer.value;
+ for (j = 0; j < call_expr_nargs (c); j++)
+ if (TREE_CODE (CALL_EXPR_ARG (c, j)) == ADDR_EXPR
+ && TREE_OPERAND (CALL_EXPR_ARG (c, j), 0) == omp_priv)
+ break;
+ if (j == call_expr_nargs (c))
+ error ("one of the initializer call arguments should be "
+ "%<&omp_priv%>");
+ }
+ }
+ else
+ {
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+ bad = true;
+ else
+ {
+ tree st = push_stmt_list ();
+ start_init (omp_priv, NULL_TREE, 0);
+ location_t loc = c_parser_peek_token (parser)->location;
+ struct c_expr init = c_parser_initializer (parser);
+ finish_init ();
+ finish_decl (omp_priv, loc, init.value,
+ init.original_type, NULL_TREE);
+ pop_stmt_list (st);
+ }
+ }
+ if (!bad
+ && !c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+ bad = true;
+ }
+
+ if (!bad)
+ {
+ c_parser_skip_to_pragma_eol (parser);
+
+ tree t = tree_cons (type, make_tree_vec (omp_priv ? 6 : 3),
+ DECL_INITIAL (reduc_decl));
+ DECL_INITIAL (reduc_decl) = t;
+ DECL_SOURCE_LOCATION (omp_out) = rloc;
+ TREE_VEC_ELT (TREE_VALUE (t), 0) = omp_out;
+ TREE_VEC_ELT (TREE_VALUE (t), 1) = omp_in;
+ TREE_VEC_ELT (TREE_VALUE (t), 2) = combiner.value;
+ walk_tree (&combiner.value, c_check_omp_declare_reduction_r,
+ &TREE_VEC_ELT (TREE_VALUE (t), 0), NULL);
+ if (omp_priv)
+ {
+ DECL_SOURCE_LOCATION (omp_priv) = rloc;
+ TREE_VEC_ELT (TREE_VALUE (t), 3) = omp_priv;
+ TREE_VEC_ELT (TREE_VALUE (t), 4) = omp_orig;
+ TREE_VEC_ELT (TREE_VALUE (t), 5) = initializer.value;
+ walk_tree (&initializer.value, c_check_omp_declare_reduction_r,
+ &TREE_VEC_ELT (TREE_VALUE (t), 3), NULL);
+ walk_tree (&DECL_INITIAL (omp_priv),
+ c_check_omp_declare_reduction_r,
+ &TREE_VEC_ELT (TREE_VALUE (t), 3), NULL);
+ }
+ }
+
+ pop_stmt_list (stmt);
+ pop_scope ();
+ if (cfun->language != NULL)
+ {
+ ggc_free (cfun->language);
+ cfun->language = NULL;
+ }
+ set_cfun (NULL);
+ current_function_decl = NULL_TREE;
+ if (nested)
+ c_pop_function_context ();
+
+ if (!clauses.is_empty ())
+ {
+ parser->tokens = &parser->tokens_buf[0];
+ parser->tokens_avail = tokens_avail;
+ }
+ if (bad)
+ goto fail;
+ if (errs != errorcount)
+ break;
+ }
+
+ clauses.release ();
+ types.release ();
+}
+
+
+/* OpenMP 4.0
+ #pragma omp declare simd declare-simd-clauses[optseq] new-line
+ #pragma omp declare reduction (reduction-id : typename-list : expression) \
+ initializer-clause[opt] new-line
+ #pragma omp declare target new-line */
+
+static void
+c_parser_omp_declare (c_parser *parser, enum pragma_context context)
+{
+ 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, "simd") == 0)
+ {
+ /* c_parser_consume_token (parser); done in
+ c_parser_omp_declare_simd. */
+ c_parser_omp_declare_simd (parser, context);
+ return;
+ }
+ if (strcmp (p, "reduction") == 0)
+ {
+ c_parser_consume_token (parser);
+ c_parser_omp_declare_reduction (parser, context);
+ return;
+ }
+ if (strcmp (p, "target") == 0)
+ {
+ c_parser_consume_token (parser);
+ c_parser_omp_declare_target (parser);
+ return;
+ }
+ }
+
+ c_parser_error (parser, "expected %<simd%> or %<reduction%> "
+ "or %<target%>");
+ c_parser_skip_to_pragma_eol (parser);
+}
+
/* Main entry point to parsing most OpenMP pragmas. */
static void
@@ -10888,6 +12847,8 @@ c_parser_omp_construct (c_parser *parser)
enum pragma_kind p_kind;
location_t loc;
tree stmt;
+ char p_name[sizeof "#pragma omp teams distribute parallel for simd"];
+ omp_clause_mask mask (0);
loc = c_parser_peek_token (parser)->location;
p_kind = c_parser_peek_token (parser)->pragma_kind;
@@ -10901,8 +12862,13 @@ c_parser_omp_construct (c_parser *parser)
case PRAGMA_OMP_CRITICAL:
stmt = c_parser_omp_critical (loc, parser);
break;
+ case PRAGMA_OMP_DISTRIBUTE:
+ strcpy (p_name, "#pragma omp");
+ stmt = c_parser_omp_distribute (loc, parser, p_name, mask, NULL);
+ break;
case PRAGMA_OMP_FOR:
- stmt = c_parser_omp_for (loc, parser);
+ strcpy (p_name, "#pragma omp");
+ stmt = c_parser_omp_for (loc, parser, p_name, mask, NULL);
break;
case PRAGMA_OMP_MASTER:
stmt = c_parser_omp_master (loc, parser);
@@ -10911,10 +12877,16 @@ c_parser_omp_construct (c_parser *parser)
stmt = c_parser_omp_ordered (loc, parser);
break;
case PRAGMA_OMP_PARALLEL:
- stmt = c_parser_omp_parallel (loc, parser);
+ strcpy (p_name, "#pragma omp");
+ stmt = c_parser_omp_parallel (loc, parser, p_name, mask, NULL);
break;
case PRAGMA_OMP_SECTIONS:
- stmt = c_parser_omp_sections (loc, parser);
+ strcpy (p_name, "#pragma omp");
+ stmt = c_parser_omp_sections (loc, parser, p_name, mask, NULL);
+ break;
+ case PRAGMA_OMP_SIMD:
+ strcpy (p_name, "#pragma omp");
+ stmt = c_parser_omp_simd (loc, parser, p_name, mask, NULL);
break;
case PRAGMA_OMP_SINGLE:
stmt = c_parser_omp_single (loc, parser);
@@ -10922,6 +12894,13 @@ c_parser_omp_construct (c_parser *parser)
case PRAGMA_OMP_TASK:
stmt = c_parser_omp_task (loc, parser);
break;
+ case PRAGMA_OMP_TASKGROUP:
+ stmt = c_parser_omp_taskgroup (parser);
+ break;
+ case PRAGMA_OMP_TEAMS:
+ strcpy (p_name, "#pragma omp");
+ stmt = c_parser_omp_teams (loc, parser, p_name, mask, NULL);
+ break;
default:
gcc_unreachable ();
}
@@ -11148,7 +13127,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;
@@ -11208,6 +13187,7 @@ c_parse_file (void)
c_parser tparser;
memset (&tparser, 0, sizeof tparser);
+ tparser.tokens = &tparser.tokens_buf[0];
the_parser = &tparser;
if (c_parser_peek_token (&tparser)->pragma_kind == PRAGMA_GCC_PCH_PREPROCESS)
@@ -11215,6 +13195,8 @@ c_parse_file (void)
the_parser = ggc_alloc_c_parser ();
*the_parser = tparser;
+ if (tparser.tokens == &tparser.tokens_buf[0])
+ the_parser->tokens = &the_parser->tokens_buf[0];
/* Initialize EH, if we've been told to do so. */
if (flag_exceptions)
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index d1a871daa68..2565ccb4f15 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -526,6 +526,8 @@ extern tree start_struct (location_t, enum tree_code, tree,
struct c_struct_parse_info **);
extern void store_parm_decls (void);
extern void store_parm_decls_from (struct c_arg_info *);
+extern void temp_store_parm_decls (tree, tree);
+extern void temp_pop_parm_decls (void);
extern tree xref_tag (enum tree_code, tree);
extern struct c_typespec parser_xref_tag (location_t, enum tree_code, tree);
extern struct c_parm *build_c_parm (struct c_declspecs *, tree,
@@ -637,9 +639,12 @@ 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 void c_finish_omp_cancel (location_t, tree);
+extern void c_finish_omp_cancellation_point (location_t, tree);
extern tree c_finish_omp_clauses (tree);
extern tree c_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. */
@@ -663,6 +668,10 @@ extern enum machine_mode c_default_pointer_mode;
/* In c-decl.c */
extern void c_finish_incomplete_decl (tree);
extern void c_write_global_declarations (void);
+extern tree c_omp_reduction_id (enum tree_code, tree);
+extern tree c_omp_reduction_decl (tree);
+extern tree c_omp_reduction_lookup (tree, tree);
+extern tree c_check_omp_declare_reduction_r (tree *, int *, void *);
/* In c-errors.c */
extern void pedwarn_c90 (location_t, int opt, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4);
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 7ecafe4894c..16e39b2ad70 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-iterator.h"
#include "bitmap.h"
#include "gimple.h"
+#include "tree-inline.h"
#include "c-family/c-objc.h"
#include "c-family/c-common.h"
#include "c-family/c-ubsan.h"
@@ -10692,6 +10693,537 @@ c_finish_omp_task (location_t loc, tree clauses, tree block)
return 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 "
+ "%<parallel%>, %<for%>, %<sections%> or %<taskgroup%> "
+ "clauses");
+ return;
+ }
+ tree ifc = find_omp_clause (clauses, OMP_CLAUSE_IF);
+ if (ifc != NULL_TREE)
+ {
+ tree type = TREE_TYPE (OMP_CLAUSE_IF_EXPR (ifc));
+ ifc = fold_build2_loc (OMP_CLAUSE_LOCATION (ifc), NE_EXPR,
+ boolean_type_node, OMP_CLAUSE_IF_EXPR (ifc),
+ build_zero_cst (type));
+ }
+ else
+ ifc = boolean_true_node;
+ tree stmt = build_call_expr_loc (loc, fn, 2,
+ build_int_cst (integer_type_node, mask),
+ ifc);
+ 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 "
+ "%<parallel%>, %<for%>, %<sections%> or %<taskgroup%> "
+ "clauses");
+ return;
+ }
+ tree stmt = build_call_expr_loc (loc, fn, 1,
+ build_int_cst (integer_type_node, mask));
+ add_stmt (stmt);
+}
+
+/* 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<tree> &types,
+ bool &maybe_zero_len, unsigned int &first_non_one)
+{
+ tree ret, low_bound, length, type;
+ if (TREE_CODE (t) != TREE_LIST)
+ {
+ if (t == error_mark_node || TREE_TYPE (t) == error_mark_node)
+ return error_mark_node;
+ if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
+ {
+ 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;
+ }
+ return t;
+ }
+
+ ret = handle_omp_array_sections_1 (c, TREE_CHAIN (t), types,
+ maybe_zero_len, first_non_one);
+ 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 == 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 must "
+ "be specified");
+ 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 = c_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 must be specified");
+ 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));
+ /* We will need to evaluate lb more than once. */
+ tree lb = c_save_expr (low_bound);
+ if (lb != low_bound)
+ {
+ TREE_PURPOSE (t) = lb;
+ low_bound = lb;
+ }
+ ret = build_array_ref (OMP_CLAUSE_LOCATION (c), ret, low_bound);
+ return ret;
+}
+
+/* Handle array sections for clause C. */
+
+static bool
+handle_omp_array_sections (tree c)
+{
+ bool maybe_zero_len = false;
+ unsigned int first_non_one = 0;
+ vec<tree> types = vNULL;
+ tree first = handle_omp_array_sections_1 (c, OMP_CLAUSE_DECL (c), types,
+ maybe_zero_len, first_non_one);
+ 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 ();
+ /* 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);
+ first = c_fully_fold (first, false, NULL);
+ 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;
+
+ 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 (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
+ {
+ 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 (side_effects)
+ size = build2 (COMPOUND_EXPR, sizetype, side_effects, size);
+ first = c_fully_fold (first, false, NULL);
+ OMP_CLAUSE_DECL (c) = first;
+ if (size)
+ size = c_fully_fold (size, false, NULL);
+ OMP_CLAUSE_SIZE (c) = size;
+ if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP)
+ return false;
+ tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP);
+ OMP_CLAUSE_MAP_KIND (c2) = OMP_CLAUSE_MAP_POINTER;
+ if (!c_mark_addressable (t))
+ return false;
+ OMP_CLAUSE_DECL (c2) = t;
+ t = build_fold_addr_expr (first);
+ t = fold_convert_loc (OMP_CLAUSE_LOCATION (c), ptrdiff_type_node, t);
+ tree ptr = OMP_CLAUSE_DECL (c2);
+ if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
+ ptr = build_fold_addr_expr (ptr);
+ t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR,
+ ptrdiff_type_node, t,
+ fold_convert_loc (OMP_CLAUSE_LOCATION (c),
+ ptrdiff_type_node, ptr));
+ t = c_fully_fold (t, false, NULL);
+ OMP_CLAUSE_SIZE (c2) = t;
+ OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c);
+ OMP_CLAUSE_CHAIN (c) = c2;
+ }
+ return false;
+}
+
+/* Helper function of finish_omp_clauses. Clone STMT as if we were making
+ an inline call. But, remap
+ the OMP_DECL1 VAR_DECL (omp_out resp. omp_orig) to PLACEHOLDER
+ and OMP_DECL2 VAR_DECL (omp_in resp. omp_priv) to DECL. */
+
+static tree
+c_clone_omp_udr (tree stmt, tree omp_decl1, tree omp_decl2,
+ tree decl, tree placeholder)
+{
+ copy_body_data id;
+ struct pointer_map_t *decl_map = pointer_map_create ();
+
+ *pointer_map_insert (decl_map, omp_decl1) = placeholder;
+ *pointer_map_insert (decl_map, omp_decl2) = decl;
+ memset (&id, 0, sizeof (id));
+ id.src_fn = DECL_CONTEXT (omp_decl1);
+ id.dst_fn = current_function_decl;
+ id.src_cfun = DECL_STRUCT_FUNCTION (id.src_fn);
+ id.decl_map = decl_map;
+
+ id.copy_decl = copy_decl_no_change;
+ id.transform_call_graph_edges = CB_CGE_DUPLICATE;
+ id.transform_new_cfg = true;
+ id.transform_return_to_modify = false;
+ id.transform_lang_insert_block = NULL;
+ id.eh_lp_nr = 0;
+ walk_tree (&stmt, copy_tree_body_r, &id, NULL);
+ pointer_map_destroy (decl_map);
+ return stmt;
+}
+
+/* Helper function of c_finish_omp_clauses, called via walk_tree.
+ Find OMP_CLAUSE_PLACEHOLDER (passed in DATA) in *TP. */
+
+static tree
+c_find_omp_placeholder_r (tree *tp, int *, void *data)
+{
+ if (*tp == (tree) data)
+ return *tp;
+ return NULL_TREE;
+}
+
/* For all elements of CLAUSES, validate them vs OpenMP constraints.
Remove any elements from the list that are invalid. */
@@ -10699,13 +11231,17 @@ 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;
+ bool copyprivate_seen = false;
+ tree *nowait_clause = NULL;
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)
{
@@ -10716,28 +11252,19 @@ c_finish_omp_clauses (tree clauses)
switch (OMP_CLAUSE_CODE (c))
{
case OMP_CLAUSE_SHARED:
- name = "shared";
need_implicitly_determined = true;
goto check_dup_generic;
case OMP_CLAUSE_PRIVATE:
- name = "private";
need_complete = true;
need_implicitly_determined = true;
goto check_dup_generic;
case OMP_CLAUSE_REDUCTION:
- name = "reduction";
need_implicitly_determined = true;
t = OMP_CLAUSE_DECL (c);
- if (AGGREGATE_TYPE_P (TREE_TYPE (t))
- || POINTER_TYPE_P (TREE_TYPE (t)))
- {
- error_at (OMP_CLAUSE_LOCATION (c),
- "%qE has invalid type for %<reduction%>", t);
- remove = true;
- }
- else if (FLOAT_TYPE_P (TREE_TYPE (t)))
+ if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) == NULL_TREE
+ && FLOAT_TYPE_P (TREE_TYPE (t)))
{
enum tree_code r_code = OMP_CLAUSE_REDUCTION_CODE (c);
const char *r_name = NULL;
@@ -10776,14 +11303,88 @@ c_finish_omp_clauses (tree clauses)
remove = true;
}
}
+ else if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) == error_mark_node)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "user defined reduction not found for %qD", t);
+ remove = true;
+ }
+ else if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
+ {
+ tree list = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c);
+ tree type = TYPE_MAIN_VARIANT (TREE_TYPE (t));
+ tree placeholder = build_decl (OMP_CLAUSE_LOCATION (c),
+ VAR_DECL, NULL_TREE, type);
+ OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = placeholder;
+ DECL_ARTIFICIAL (placeholder) = 1;
+ DECL_IGNORED_P (placeholder) = 1;
+ if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 0)))
+ c_mark_addressable (placeholder);
+ if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 1)))
+ c_mark_addressable (OMP_CLAUSE_DECL (c));
+ OMP_CLAUSE_REDUCTION_MERGE (c)
+ = c_clone_omp_udr (TREE_VEC_ELT (list, 2),
+ TREE_VEC_ELT (list, 0),
+ TREE_VEC_ELT (list, 1),
+ OMP_CLAUSE_DECL (c), placeholder);
+ OMP_CLAUSE_REDUCTION_MERGE (c)
+ = build3_loc (OMP_CLAUSE_LOCATION (c), BIND_EXPR,
+ void_type_node, NULL_TREE,
+ OMP_CLAUSE_REDUCTION_MERGE (c), NULL_TREE);
+ TREE_SIDE_EFFECTS (OMP_CLAUSE_REDUCTION_MERGE (c)) = 1;
+ if (TREE_VEC_LENGTH (list) == 6)
+ {
+ if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 3)))
+ c_mark_addressable (OMP_CLAUSE_DECL (c));
+ if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 4)))
+ c_mark_addressable (placeholder);
+ tree init = TREE_VEC_ELT (list, 5);
+ if (init == error_mark_node)
+ init = DECL_INITIAL (TREE_VEC_ELT (list, 3));
+ OMP_CLAUSE_REDUCTION_INIT (c)
+ = c_clone_omp_udr (init, TREE_VEC_ELT (list, 4),
+ TREE_VEC_ELT (list, 3),
+ OMP_CLAUSE_DECL (c), placeholder);
+ if (TREE_VEC_ELT (list, 5) == error_mark_node)
+ OMP_CLAUSE_REDUCTION_INIT (c)
+ = build2 (INIT_EXPR, TREE_TYPE (t), t,
+ OMP_CLAUSE_REDUCTION_INIT (c));
+ if (walk_tree (&OMP_CLAUSE_REDUCTION_INIT (c),
+ c_find_omp_placeholder_r,
+ placeholder, NULL))
+ OMP_CLAUSE_REDUCTION_OMP_ORIG_REF (c) = 1;
+ }
+ else
+ {
+ tree init;
+ if (AGGREGATE_TYPE_P (TREE_TYPE (t)))
+ init = build_constructor (TREE_TYPE (t), NULL);
+ else
+ init = fold_convert (TREE_TYPE (t), integer_zero_node);
+ OMP_CLAUSE_REDUCTION_INIT (c)
+ = build2 (INIT_EXPR, TREE_TYPE (t), t, init);
+ }
+ OMP_CLAUSE_REDUCTION_INIT (c)
+ = build3_loc (OMP_CLAUSE_LOCATION (c), BIND_EXPR,
+ void_type_node, NULL_TREE,
+ OMP_CLAUSE_REDUCTION_INIT (c), NULL_TREE);
+ TREE_SIDE_EFFECTS (OMP_CLAUSE_REDUCTION_INIT (c)) = 1;
+ }
goto check_dup_generic;
case OMP_CLAUSE_COPYPRIVATE:
- name = "copyprivate";
+ copyprivate_seen = true;
+ if (nowait_clause)
+ {
+ error_at (OMP_CLAUSE_LOCATION (*nowait_clause),
+ "%<nowait%> clause must not be used together "
+ "with %<copyprivate%>");
+ *nowait_clause = OMP_CLAUSE_CHAIN (*nowait_clause);
+ nowait_clause = NULL;
+ }
goto check_dup_generic;
case OMP_CLAUSE_COPYIN:
- name = "copyin";
t = OMP_CLAUSE_DECL (c);
if (TREE_CODE (t) != VAR_DECL || !DECL_THREAD_LOCAL_P (t))
{
@@ -10793,12 +11394,37 @@ c_finish_omp_clauses (tree clauses)
}
goto check_dup_generic;
+ case OMP_CLAUSE_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 "
+ "variable with type %qT", TREE_TYPE (t));
+ 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)
{
error_at (OMP_CLAUSE_LOCATION (c),
- "%qE is not a variable in clause %qs", t, name);
+ "%qE is not a variable in clause %qs", t,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
remove = true;
}
else if (bitmap_bit_p (&generic_head, DECL_UID (t))
@@ -10814,7 +11440,6 @@ c_finish_omp_clauses (tree clauses)
break;
case OMP_CLAUSE_FIRSTPRIVATE:
- name = "firstprivate";
t = OMP_CLAUSE_DECL (c);
need_complete = true;
need_implicitly_determined = true;
@@ -10836,7 +11461,6 @@ c_finish_omp_clauses (tree clauses)
break;
case OMP_CLAUSE_LASTPRIVATE:
- name = "lastprivate";
t = OMP_CLAUSE_DECL (c);
need_complete = true;
need_implicitly_determined = true;
@@ -10857,16 +11481,167 @@ 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 %<aligned%> 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 %<aligned%> clauses",
+ t);
+ remove = true;
+ }
+ else
+ bitmap_set_bit (&aligned_head, DECL_UID (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)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%qE is not a variable in %<depend%> clause", t);
+ remove = true;
+ }
+ else if (!c_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 (!COMPLETE_TYPE_P (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)
+ {
+ 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;
+ }
+ else if (!c_mark_addressable (t))
+ remove = true;
+ else if (!COMPLETE_TYPE_P (TREE_TYPE (t))
+ && !(OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+ && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER))
+ {
+ 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 (bitmap_bit_p (&generic_head, DECL_UID (t)))
+ {
+ if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP)
+ error ("%qD appears more than once in motion clauses", t);
+ else
+ error ("%qD appears more than once in map clauses", t);
+ remove = true;
+ }
+ else
+ bitmap_set_bit (&generic_head, DECL_UID (t));
+ 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 %<uniform%> clause", t);
+ else
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%qE is not an argument in %<uniform%> clause", t);
+ remove = true;
+ }
+ break;
+
+ case OMP_CLAUSE_NOWAIT:
+ if (copyprivate_seen)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%<nowait%> clause must not be used together "
+ "with %<copyprivate%>");
+ remove = true;
+ break;
+ }
+ nowait_clause = pc;
+ pc = &OMP_CLAUSE_CHAIN (c);
+ continue;
+
case OMP_CLAUSE_IF:
case OMP_CLAUSE_NUM_THREADS:
+ case OMP_CLAUSE_NUM_TEAMS:
+ case OMP_CLAUSE_THREAD_LIMIT:
case OMP_CLAUSE_SCHEDULE:
- case OMP_CLAUSE_NOWAIT:
case OMP_CLAUSE_ORDERED:
case OMP_CLAUSE_DEFAULT:
case OMP_CLAUSE_UNTIED:
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),
+ "%<inbranch%> clause is incompatible with "
+ "%<notinbranch%>");
+ remove = true;
+ break;
+ }
+ branch_seen = true;
pc = &OMP_CLAUSE_CHAIN (c);
continue;
@@ -10912,7 +11687,8 @@ c_finish_omp_clauses (tree clauses)
{
error_at (OMP_CLAUSE_LOCATION (c),
"%qE is predetermined %qs for %qs",
- t, share_name, name);
+ t, share_name,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
remove = true;
}
}
@@ -11016,3 +11792,205 @@ c_build_va_arg (location_t loc, tree expr, tree type)
"C++ requires promoted type, not enum type, in %<va_arg%>");
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/cp/ChangeLog b/gcc/cp/ChangeLog
index b3bde109a0f..da49d12c629 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,172 @@
+2013-10-11 Jakub Jelinek <jakub@redhat.com>
+
+ * decl.c (duplicate_decls): Error out for redeclaration of UDRs.
+ (declare_simd_adjust_this): New function.
+ (grokfndecl): If "omp declare simd" attribute is present,
+ call declare_simd_adjust_this if needed and
+ c_omp_declare_simd_clauses_to_numbers.
+ * cp-array-notation.c (expand_array_notation_exprs): Handle
+ OMP_TASKGROUP.
+ * cp-gimplify.c (cp_gimplify_expr): Handle OMP_SIMD and
+ OMP_DISTRIBUTE. Handle is_invisiref_parm decls in
+ OMP_CLAUSE_REDUCTION.
+ (cp_genericize_r): Handle OMP_SIMD and OMP_DISTRIBUTE like
+ OMP_FOR.
+ (cxx_omp_privatize_by_reference): Return true for
+ is_invisiref_parm decls.
+ (cxx_omp_finish_clause): Adjust cxx_omp_create_clause_info
+ caller.
+ * pt.c (apply_late_template_attributes): For "omp declare simd"
+ attribute call tsubst_omp_clauses,
+ c_omp_declare_simd_clauses_to_decls, finish_omp_clauses
+ and c_omp_declare_simd_clauses_to_numbers.
+ (instantiate_class_template_1): Call cp_check_omp_declare_reduction
+ for UDRs.
+ (tsubst_decl): Handle UDRs.
+ (tsubst_omp_clauses): Add declare_simd argument, if true don't
+ call finish_omp_clauses. Handle new OpenMP 4.0 clauses.
+ Handle non-NULL OMP_CLAUSE_REDUCTION_PLACEHOLDER on
+ OMP_CLAUSE_REDUCTION.
+ (tsubst_expr): For UDRs call pushdecl and
+ cp_check_omp_declare_reduction. Adjust tsubst_omp_clauses
+ callers. Handle OMP_SIMD, OMP_DISTRIBUTE, OMP_TEAMS,
+ OMP_TARGET_DATA, OMP_TARGET_UPDATE, OMP_TARGET, OMP_TASKGROUP.
+ Adjust finish_omp_atomic caller.
+ (tsubst_omp_udr): New function.
+ (instantiate_decl): For UDRs at block scope, don't call
+ start_preparsed_function/finish_function. Call tsubst_omp_udr.
+ * semantics.c (cxx_omp_create_clause_info): Add need_dtor argument,
+ use it instead of need_default_ctor || need_copy_ctor.
+ (struct cp_check_omp_declare_reduction_data): New type.
+ (handle_omp_array_sections_1, handle_omp_array_sections,
+ omp_reduction_id, omp_reduction_lookup,
+ cp_remove_omp_priv_cleanup_stmt, cp_check_omp_declare_reduction_r,
+ cp_check_omp_declare_reduction, clone_omp_udr,
+ find_omp_placeholder_r, finish_omp_reduction_clause): New functions.
+ (finish_omp_clauses): Handle new OpenMP 4.0 clauses and user defined
+ reductions.
+ (finish_omp_for): Add CODE argument, use it instead of hardcoded
+ OMP_FOR. Adjust c_finish_omp_for caller.
+ (finish_omp_atomic): Add seq_cst argument, adjust
+ c_finish_omp_atomic callers, handle seq_cst and new OpenMP 4.0
+ atomic variants.
+ (finish_omp_cancel, finish_omp_cancellation_point): New functions.
+ * decl2.c (mark_used): Force immediate instantiation of
+ DECL_OMP_DECLARE_REDUCTION_P decls.
+ (is_late_template_attribute): Return true for "omp declare simd"
+ attribute.
+ (cp_omp_mappable_type): New function.
+ (cplus_decl_attributes): Add implicit "omp declare target" attribute
+ if requested.
+ * parser.c (cp_debug_parser): Print
+ parser->colon_doesnt_start_class_def_p.
+ (cp_ensure_no_omp_declare_simd, cp_finalize_omp_declare_simd): New
+ functions.
+ (enum pragma_context): Add pragma_member and pragma_objc_icode.
+ (cp_parser_binary_expression): Handle no_toplevel_fold_p
+ even for binary operations other than comparison.
+ (cp_parser_linkage_specification): Call
+ cp_ensure_no_omp_declare_simd if needed.
+ (cp_parser_namespace_definition): Likewise.
+ (cp_parser_init_declarator): Call cp_finalize_omp_declare_simd.
+ (cp_parser_direct_declarator): Pass declarator to
+ cp_parser_late_return_type_opt.
+ (cp_parser_late_return_type_opt): Add declarator argument,
+ call cp_parser_late_parsing_omp_declare_simd for declare simd.
+ (cp_parser_class_specifier_1): Call cp_ensure_no_omp_declare_simd.
+ Parse UDRs before all other methods.
+ (cp_parser_member_specification_opt): Use pragma_member instead of
+ pragma_external.
+ (cp_parser_member_declaration): Call cp_finalize_omp_declare_simd.
+ (cp_parser_function_definition_from_specifiers_and_declarator,
+ cp_parser_save_member_function_body): Likewise.
+ (cp_parser_late_parsing_for_member): Handle UDRs specially.
+ (cp_parser_next_token_starts_class_definition_p): Don't allow
+ CPP_COLON if colon_doesnt_start_class_def_p flag is true.
+ (cp_parser_objc_interstitial_code): Use pragma_objc_icode
+ instead of pragma_external.
+ (cp_parser_omp_clause_name): Parse new OpenMP 4.0 clause names.
+ (cp_parser_omp_var_list_no_open): Parse array sections for
+ OMP_CLAUSE_{DEPEND,MAP,TO,FROM} clauses. Add COLON argument,
+ if non-NULL, allow parsing to end with a colon rather than close
+ paren.
+ (cp_parser_omp_var_list): Adjust cp_parser_omp_var_list_no_open
+ caller.
+ (cp_parser_omp_clause_reduction): Handle user defined reductions.
+ (cp_parser_omp_clause_branch, cp_parser_omp_clause_cancelkind,
+ cp_parser_omp_clause_num_teams, cp_parser_omp_clause_thread_limit,
+ cp_parser_omp_clause_aligned, cp_parser_omp_clause_linear,
+ cp_parser_omp_clause_safelen, cp_parser_omp_clause_simdlen,
+ 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, cp_parser_omp_clause_to,
+ cp_parser_omp_clause_from, cp_parser_omp_clause_uniform): New
+ functions.
+ (cp_parser_omp_all_clauses): Add finish_p argument. Don't call
+ finish_omp_clauses if it is false. Handle new OpenMP 4.0 clauses.
+ (cp_parser_omp_atomic): Parse seq_cst clause, pass
+ true if it is present to finish_omp_atomic. Handle new OpenMP 4.0
+ atomic forms.
+ (cp_parser_omp_for_loop): Add CODE argument, pass it through
+ to finish_omp_for. 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): New function.
+ (cp_parser_omp_for): Add p_name, mask and cclauses arguments.
+ Allow the function to be called also when parsing combined constructs,
+ and call c_parser_omp_simd when parsing for simd.
+ (cp_parser_omp_sections_scope): If section-sequence doesn't start with
+ #pragma omp section, require exactly one structured-block instead of
+ sequence of statements.
+ (cp_parser_omp_sections): Add p_name, mask and cclauses arguments.
+ Allow the function to be called also when parsing combined constructs.
+ (cp_parser_omp_parallel): Add p_name, mask and cclauses arguments.
+ Allow the function to be called also when parsing combined
+ constructs.
+ (cp_parser_omp_taskgroup, cp_parser_omp_cancel,
+ cp_parser_omp_cancellation_point, cp_parser_omp_distribute,
+ cp_parser_omp_teams, cp_parser_omp_target_data,
+ cp_parser_omp_target_update, cp_parser_omp_target,
+ cp_parser_omp_declare_simd, cp_parser_late_parsing_omp_declare_simd,
+ cp_parser_omp_declare_target, cp_parser_omp_end_declare_target,
+ cp_parser_omp_declare_reduction_exprs, cp_parser_omp_declare_reduction,
+ cp_parser_omp_declare): New functions.
+ (cp_parser_omp_construct): Add p_name and mask vars. Handle
+ PRAGMA_OMP_DISTRIBUTE, PRAGMA_OMP_SIMD, PRAGMA_OMP_TASKGROUP,
+ PRAGMA_OMP_TEAMS. Adjust cp_parser_omp_for, cp_parser_omp_parallel
+ and cp_parser_omp_sections callers.
+ (cp_parser_pragma): Handle PRAGMA_OMP_CANCEL,
+ PRAGMA_OMP_CANCELLATION_POINT, PRAGMA_OMP_DECLARE_REDUCTION,
+ PRAGMA_OMP_DISTRIBUTE, PRAGMA_OMP_SIMD, PRAGMA_OMP_TASKGROUP,
+ PRAGMA_OMP_TEAMS, PRAGMA_OMP_TARGET, PRAGMA_OMP_END_DECLARE_TARGET.
+ Handle pragma_member and pragma_objc_icode like pragma_external.
+ (OMP_FOR_CLAUSE_MASK, OMP_SECTIONS_CLAUSE_MASK,
+ OMP_SINGLE_CLAUSE_MASK): Use OMP_CLAUSE_MASK_1 instead of 1.
+ (OMP_PARALLEL_CLAUSE_MASK): Likewise. Add OMP_CLAUSE_PROC_BIND.
+ (OMP_TASK_CLAUSE_MASK): Use OMP_CLAUSE_MASK_1 instead of 1. Add
+ OMP_CLAUSE_DEPEND.
+ (OMP_SIMD_CLAUSE_MASK, OMP_CANCEL_CLAUSE_MASK,
+ OMP_CANCELLATION_POINT_CLAUSE_MASK, OMP_DISTRIBUTE_CLAUSE_MASK,
+ OMP_TEAMS_CLAUSE_MASK, OMP_TARGET_DATA_CLAUSE_MASK,
+ OMP_TARGET_UPDATE_CLAUSE_MASK, OMP_TARGET_CLAUSE_MASK,
+ OMP_DECLARE_SIMD_CLAUSE_MASK): Define.
+ * parser.h (struct cp_omp_declare_simd_data): New type.
+ (struct cp_parser): Add colon_doesnt_start_class_def_p and
+ omp_declare_simd fields.
+ * cp-objcp-common.h (LANG_HOOKS_OMP_MAPPABLE_TYPE): Define.
+ * cp-tree.h (struct lang_decl_fn): Add omp_declare_reduction_p
+ bit.
+ (DECL_OMP_DECLARE_REDUCTION_P): Define.
+ (OMP_FOR_GIMPLIFYING_P): Use OMP_LOOP_CHECK macro.
+ (struct saved_scope): Add omp_declare_target_attribute field.
+ (cp_omp_mappable_type, omp_reduction_id,
+ cp_remove_omp_priv_cleanup_stmt, cp_check_omp_declare_reduction,
+ finish_omp_cancel, finish_omp_cancellation_point): New prototypes.
+ (finish_omp_for): Add CODE argument.
+ (finish_omp_atomic): Add seq_cst argument.
+ (cxx_omp_create_clause_info): Add need_dtor argument.
+
2013-10-09 Marek Polacek <polacek@redhat.com>
PR c++/58635
diff --git a/gcc/cp/cp-array-notation.c b/gcc/cp/cp-array-notation.c
index f4581f01e57..c700f58f69f 100644
--- a/gcc/cp/cp-array-notation.c
+++ b/gcc/cp/cp-array-notation.c
@@ -1193,6 +1193,7 @@ expand_array_notation_exprs (tree t)
case OMP_SECTION:
case OMP_SECTIONS:
case OMP_MASTER:
+ case OMP_TASKGROUP:
case OMP_ORDERED:
case OMP_CRITICAL:
case OMP_ATOMIC:
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index 590d8577fdc..53b0ca8f928 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -669,6 +669,8 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
gcc_unreachable ();
case OMP_FOR:
+ case OMP_SIMD:
+ case OMP_DISTRIBUTE:
ret = cp_gimplify_omp_for (expr_p, pre_p);
break;
@@ -934,7 +936,19 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
*walk_subtrees = 0;
break;
case OMP_CLAUSE_REDUCTION:
- gcc_assert (!is_invisiref_parm (OMP_CLAUSE_DECL (stmt)));
+ /* Don't dereference an invisiref in reduction clause's
+ OMP_CLAUSE_DECL either. OMP_CLAUSE_REDUCTION_{INIT,MERGE}
+ still needs to be genericized. */
+ if (is_invisiref_parm (OMP_CLAUSE_DECL (stmt)))
+ {
+ *walk_subtrees = 0;
+ if (OMP_CLAUSE_REDUCTION_INIT (stmt))
+ cp_walk_tree (&OMP_CLAUSE_REDUCTION_INIT (stmt),
+ cp_genericize_r, data, NULL);
+ if (OMP_CLAUSE_REDUCTION_MERGE (stmt))
+ cp_walk_tree (&OMP_CLAUSE_REDUCTION_MERGE (stmt),
+ cp_genericize_r, data, NULL);
+ }
break;
default:
break;
@@ -1116,7 +1130,9 @@ 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) == OMP_DISTRIBUTE)
genericize_omp_for_stmt (stmt_p, walk_subtrees, data);
else if (TREE_CODE (stmt) == SIZEOF_EXPR)
{
@@ -1402,7 +1418,8 @@ cxx_omp_clause_dtor (tree clause, tree decl)
bool
cxx_omp_privatize_by_reference (const_tree decl)
{
- return is_invisiref_parm (decl);
+ return (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE
+ || is_invisiref_parm (decl));
}
/* Return true if DECL is const qualified var having no mutable member. */
@@ -1505,7 +1522,7 @@ cxx_omp_finish_clause (tree c)
for making these queries. */
if (!make_shared
&& CLASS_TYPE_P (inner_type)
- && cxx_omp_create_clause_info (c, inner_type, false, true, false))
+ && cxx_omp_create_clause_info (c, inner_type, false, true, false, true))
make_shared = true;
if (make_shared)
diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h
index 47fb20a7870..ee22423ebd4 100644
--- a/gcc/cp/cp-objcp-common.h
+++ b/gcc/cp/cp-objcp-common.h
@@ -145,6 +145,8 @@ extern void cp_common_init_ts (void);
#define LANG_HOOKS_OMP_FINISH_CLAUSE cxx_omp_finish_clause
#undef LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE
#define LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE cxx_omp_privatize_by_reference
+#undef LANG_HOOKS_OMP_MAPPABLE_TYPE
+#define LANG_HOOKS_OMP_MAPPABLE_TYPE cp_omp_mappable_type
#undef LANG_HOOKS_EH_USE_CXA_END_CLEANUP
#define LANG_HOOKS_EH_USE_CXA_END_CLEANUP true
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index d7840aff89f..b1347e20dd6 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)
@@ -1037,6 +1037,9 @@ struct GTY(()) saved_scope {
int unevaluated_operand;
int inhibit_evaluation_warnings;
+ /* If non-zero, implicit "omp declare target" attribute is added into the
+ attribute lists. */
+ int omp_declare_target_attribute;
struct stmt_tree_s x_stmt_tree;
@@ -1979,7 +1982,8 @@ struct GTY(()) lang_decl_fn {
unsigned thunk_p : 1;
unsigned this_thunk_p : 1;
unsigned hidden_friend_p : 1;
- /* 1 spare bit. */
+ unsigned omp_declare_reduction_p : 1;
+ /* No spare bits on 32-bit hosts, 32 on 64-bit hosts. */
/* For a non-thunk function decl, this is a tree list of
friendly classes. For a thunk function decl, it is the
@@ -3181,6 +3185,11 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
#define DECL_HIDDEN_FRIEND_P(NODE) \
(LANG_DECL_FN_CHECK (DECL_COMMON_CHECK (NODE))->hidden_friend_p)
+/* Nonzero if NODE is an artificial FUNCTION_DECL for
+ #pragma omp declare reduction. */
+#define DECL_OMP_DECLARE_REDUCTION_P(NODE) \
+ (LANG_DECL_FN_CHECK (DECL_COMMON_CHECK (NODE))->omp_declare_reduction_p)
+
/* Nonzero if DECL has been declared threadprivate by
#pragma omp threadprivate. */
#define CP_DECL_THREADPRIVATE_P(DECL) \
@@ -4011,7 +4020,7 @@ 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=.
@@ -5299,6 +5308,7 @@ extern bool possibly_inlined_p (tree);
extern int parm_index (tree);
extern tree vtv_start_verification_constructor_init_function (void);
extern tree vtv_finish_verification_constructor_init_function (tree);
+extern bool cp_omp_mappable_type (tree);
/* in error.c */
extern void init_error (void);
@@ -5774,6 +5784,9 @@ extern tree finish_qualified_id_expr (tree, tree, bool, bool,
extern void simplify_aggr_init_expr (tree *);
extern void finalize_nrv (tree *, tree, tree);
extern void note_decl_for_pch (tree);
+extern tree omp_reduction_id (enum tree_code, tree, tree);
+extern tree cp_remove_omp_priv_cleanup_stmt (tree *, int *, void *);
+extern void cp_check_omp_declare_reduction (tree);
extern tree finish_omp_clauses (tree);
extern void finish_omp_threadprivate (tree);
extern tree begin_omp_structured_block (void);
@@ -5782,18 +5795,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_cancel (tree);
+extern void finish_omp_cancellation_point (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 bool cxx_omp_create_clause_info (tree, tree, bool, bool,
+ bool, bool);
extern tree baselink_for_fns (tree);
extern void finish_static_assert (tree, tree, location_t,
bool);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 5f17a056079..fe8fe4ee52c 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -1341,6 +1341,15 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
}
return NULL_TREE;
}
+ else if (DECL_OMP_DECLARE_REDUCTION_P (olddecl))
+ {
+ gcc_assert (DECL_OMP_DECLARE_REDUCTION_P (newdecl));
+ error_at (DECL_SOURCE_LOCATION (newdecl),
+ "redeclaration of %<pragma omp declare reduction%>");
+ error_at (DECL_SOURCE_LOCATION (olddecl),
+ "previous %<pragma omp declare reduction%> declaration");
+ return error_mark_node;
+ }
else if (!types_match)
{
/* Avoid warnings redeclaring built-ins which have not been
@@ -7302,6 +7311,22 @@ check_static_quals (tree decl, cp_cv_quals quals)
decl);
}
+/* Helper function. Replace the temporary this parameter injected
+ during cp_finish_omp_declare_simd with the real this parameter. */
+
+static tree
+declare_simd_adjust_this (tree *tp, int *walk_subtrees, void *data)
+{
+ tree this_parm = (tree) data;
+ if (TREE_CODE (*tp) == PARM_DECL
+ && DECL_NAME (*tp) == this_identifier
+ && *tp != this_parm)
+ *tp = this_parm;
+ else if (TYPE_P (*tp))
+ *walk_subtrees = 0;
+ return NULL_TREE;
+}
+
/* CTYPE is class type, or null if non-class.
TYPE is type this FUNCTION_DECL should have, either FUNCTION_TYPE
or METHOD_TYPE.
@@ -7620,6 +7645,33 @@ grokfndecl (tree ctype,
if (TYPE_NOTHROW_P (type) || nothrow_libfn_p (decl))
TREE_NOTHROW (decl) = 1;
+ if (flag_openmp)
+ {
+ /* Adjust "omp declare simd" attributes. */
+ tree ods = lookup_attribute ("omp declare simd", *attrlist);
+ if (ods)
+ {
+ tree attr;
+ for (attr = ods; attr;
+ attr = lookup_attribute ("omp declare simd", TREE_CHAIN (attr)))
+ {
+ if (TREE_CODE (type) == METHOD_TYPE)
+ walk_tree (&TREE_VALUE (attr), declare_simd_adjust_this,
+ DECL_ARGUMENTS (decl), NULL);
+ if (TREE_VALUE (attr) != NULL_TREE)
+ {
+ tree cl = TREE_VALUE (TREE_VALUE (attr));
+ cl = c_omp_declare_simd_clauses_to_numbers
+ (DECL_ARGUMENTS (decl), cl);
+ if (cl)
+ TREE_VALUE (TREE_VALUE (attr)) = cl;
+ else
+ TREE_VALUE (attr) = NULL_TREE;
+ }
+ }
+ }
+ }
+
/* Caller will do the rest of this. */
if (check < 0)
return decl;
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 53e6bc9da1b..4ebc1555909 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -101,7 +101,6 @@ static GTY(()) vec<tree, va_gc> *no_linkage_decls;
/* Nonzero if we're done parsing and into end-of-file activities. */
int at_eof;
-
/* Return a member function type (a METHOD_TYPE), given FNTYPE (a
@@ -1135,6 +1134,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 deferred. */
+ 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))
@@ -1336,6 +1340,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
@@ -1345,6 +1377,30 @@ cplus_decl_attributes (tree *decl, tree attributes, int flags)
|| *decl == error_mark_node)
return;
+ /* Add implicit "omp declare target" attribute if requested. */
+ if (scope_chain->omp_declare_target_attribute
+ && ((TREE_CODE (*decl) == VAR_DECL && TREE_STATIC (*decl))
+ || TREE_CODE (*decl) == FUNCTION_DECL))
+ {
+ if (TREE_CODE (*decl) == VAR_DECL
+ && DECL_CLASS_SCOPE_P (*decl))
+ error ("%q+D static data member inside of declare target directive",
+ *decl);
+ else if (TREE_CODE (*decl) == VAR_DECL
+ && (DECL_FUNCTION_SCOPE_P (*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))
@@ -4623,13 +4679,16 @@ mark_used (tree decl, tsubst_flags_t complain)
or a constexpr function, we need it right now because a reference to
such a data member or a call to such function is not value-dependent.
For a function that uses auto in the return type, we need to instantiate
- it to find out its type. */
- if ((decl_maybe_constant_var_p (decl)
- || (TREE_CODE (decl) == FUNCTION_DECL
- && DECL_DECLARED_CONSTEXPR_P (decl))
- || undeduced_auto_decl (decl))
- && DECL_LANG_SPECIFIC (decl)
+ it to find out its type. For OpenMP user defined reductions, we need
+ them instantiated for reduction clauses which inline them by hand
+ directly. */
+ if (DECL_LANG_SPECIFIC (decl)
&& DECL_TEMPLATE_INFO (decl)
+ && (decl_maybe_constant_var_p (decl)
+ || (TREE_CODE (decl) == FUNCTION_DECL
+ && (DECL_DECLARED_CONSTEXPR_P (decl)
+ || DECL_OMP_DECLARE_REDUCTION_P (decl)))
+ || undeduced_auto_decl (decl))
&& !uses_template_parms (DECL_TI_ARGS (decl)))
{
/* Instantiating a function will result in garbage collection. We
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 90c17757c4c..83fdfaba40f 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -232,6 +232,9 @@ static void cp_parser_initial_pragma
static tree cp_literal_operator_id
(const char *);
+static bool cp_parser_omp_declare_reduction_exprs
+ (tree, cp_parser *);
+
/* Manifest constants. */
#define CP_LEXER_BUFFER_SIZE ((256 * 1024) / sizeof (cp_token))
#define CP_SAVED_TOKEN_STACK 5
@@ -542,6 +545,8 @@ cp_debug_parser (FILE *file, cp_parser *parser)
"local class", parser->in_function_body);
cp_debug_print_flag (file, "Auto correct a colon to a scope operator",
parser->colon_corrects_to_scope_p);
+ cp_debug_print_flag (file, "Colon doesn't start a class definition",
+ parser->colon_doesnt_start_class_def_p);
if (parser->type_definition_forbidden_message)
fprintf (file, "Error message for forbidden type definitions: %s\n",
parser->type_definition_forbidden_message);
@@ -1222,6 +1227,40 @@ 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 && !parser->omp_declare_simd->error_seen)
+ {
+ error ("%<#pragma omp declare simd%> not immediately followed by "
+ "function declaration or definition");
+ parser->omp_declare_simd = NULL;
+ }
+}
+
+/* Finalize #pragma omp declare simd clauses after FNDECL has been parsed,
+ and put that into "omp declare simd" attribute. */
+
+static inline void
+cp_finalize_omp_declare_simd (cp_parser *parser, tree fndecl)
+{
+ if (__builtin_expect (parser->omp_declare_simd != NULL, 0))
+ {
+ if (fndecl == error_mark_node)
+ {
+ parser->omp_declare_simd = NULL;
+ return;
+ }
+ if (TREE_CODE (fndecl) != FUNCTION_DECL)
+ {
+ cp_ensure_no_omp_declare_simd (parser);
+ return;
+ }
+ }
+}
/* Decl-specifiers. */
@@ -2030,7 +2069,7 @@ static cp_virt_specifiers cp_parser_virt_specifier_seq_opt
static cp_ref_qualifier cp_parser_ref_qualifier_opt
(cp_parser *);
static tree cp_parser_late_return_type_opt
- (cp_parser *, cp_cv_quals);
+ (cp_parser *, cp_declarator *, cp_cv_quals);
static tree cp_parser_declarator_id
(cp_parser *, bool);
static tree cp_parser_type_id
@@ -2064,6 +2103,9 @@ static vec<constructor_elt, va_gc> *cp_parser_initializer_list
static bool cp_parser_ctor_initializer_opt_and_function_body
(cp_parser *, bool);
+static tree cp_parser_late_parsing_omp_declare_simd
+ (cp_parser *, tree);
+
static tree add_implicit_template_parms
(cp_parser *, size_t, tree);
static tree finish_fully_implicit_template
@@ -2211,7 +2253,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);
@@ -7807,9 +7855,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,
@@ -11522,6 +11572,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. */
@@ -15509,6 +15561,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);
@@ -16449,8 +16502,8 @@ cp_parser_init_declarator (cp_parser* parser,
decl_specifiers->storage_class = sc_extern;
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_finalize_omp_declare_simd (parser, 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. */
@@ -16560,6 +16613,7 @@ cp_parser_init_declarator (cp_parser* parser,
chainon (attributes, prefix_attributes));
if (decl && TREE_CODE (decl) == FUNCTION_DECL)
cp_parser_save_default_args (parser, decl);
+ cp_finalize_omp_declare_simd (parser, decl);
}
/* Finish processing the declaration. But, skip member
@@ -16871,7 +16925,9 @@ cp_parser_direct_declarator (cp_parser* parser,
attrs = cp_parser_std_attribute_spec_seq (parser);
late_return = (cp_parser_late_return_type_opt
- (parser, memfn ? cv_quals : -1));
+ (parser, declarator,
+ memfn ? cv_quals : -1));
+
/* Parse the virt-specifier-seq. */
virt_specifiers = cp_parser_virt_specifier_seq_opt (parser);
@@ -17575,24 +17631,28 @@ parsing_nsdmi (void)
Returns the type indicated by the type-id.
+ In addition to this this parses any queued up omp declare simd
+ clauses.
+
QUALS is either a bitmask of cv_qualifiers or -1 for a non-member
function. */
static tree
-cp_parser_late_return_type_opt (cp_parser* parser, cp_cv_quals quals)
+cp_parser_late_return_type_opt (cp_parser* parser, cp_declarator *declarator,
+ cp_cv_quals quals)
{
cp_token *token;
- tree type;
+ tree type = NULL_TREE;
+ bool declare_simd_p = (parser->omp_declare_simd
+ && declarator
+ && declarator->kind == cdk_id);
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* A late-specified return type is indicated by an initial '->'. */
- if (token->type != CPP_DEREF)
+ if (token->type != CPP_DEREF && !declare_simd_p)
return NULL_TREE;
- /* Consume the ->. */
- cp_lexer_consume_token (parser->lexer);
-
tree save_ccp = current_class_ptr;
tree save_ccr = current_class_ref;
if (quals >= 0)
@@ -17601,7 +17661,18 @@ cp_parser_late_return_type_opt (cp_parser* parser, cp_cv_quals quals)
inject_this_parameter (current_class_type, quals);
}
- type = cp_parser_trailing_type_id (parser);
+ if (token->type == CPP_DEREF)
+ {
+ /* Consume the ->. */
+ cp_lexer_consume_token (parser->lexer);
+
+ type = cp_parser_trailing_type_id (parser);
+ }
+
+ if (declare_simd_p)
+ declarator->std_attributes
+ = cp_parser_late_parsing_omp_declare_simd (parser,
+ declarator->std_attributes);
if (quals >= 0)
{
@@ -18856,6 +18927,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. */
@@ -19083,8 +19156,19 @@ cp_parser_class_specifier_1 (cp_parser* parser)
if (pushed_scope)
pop_scope (pushed_scope);
/* Now parse the body of the functions. */
- FOR_EACH_VEC_SAFE_ELT (unparsed_funs_with_definitions, ix, decl)
- cp_parser_late_parsing_for_member (parser, decl);
+ if (flag_openmp)
+ {
+ /* OpenMP UDRs need to be parsed before all other functions. */
+ FOR_EACH_VEC_SAFE_ELT (unparsed_funs_with_definitions, ix, decl)
+ if (DECL_OMP_DECLARE_REDUCTION_P (decl))
+ cp_parser_late_parsing_for_member (parser, decl);
+ FOR_EACH_VEC_SAFE_ELT (unparsed_funs_with_definitions, ix, decl)
+ if (!DECL_OMP_DECLARE_REDUCTION_P (decl))
+ cp_parser_late_parsing_for_member (parser, decl);
+ }
+ else
+ FOR_EACH_VEC_SAFE_ELT (unparsed_funs_with_definitions, ix, decl)
+ cp_parser_late_parsing_for_member (parser, decl);
vec_safe_truncate (unparsed_funs_with_definitions, 0);
}
@@ -19631,7 +19715,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;
}
@@ -20087,15 +20171,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 = grokfield (declarator, &decl_specifiers,
+ initializer, /*init_const_expr_p=*/true,
+ asm_specification, attributes);
if (parser->fully_implicit_function_template_p)
decl = finish_fully_implicit_template (parser, decl);
}
+ cp_finalize_omp_declare_simd (parser, decl);
+
/* Reset PREFIX_ATTRIBUTES. */
while (attributes && TREE_CHAIN (attributes) != first_attribute)
attributes = TREE_CHAIN (attributes);
@@ -22244,6 +22329,12 @@ cp_parser_function_definition_from_specifiers_and_declarator
might be a friend. */
perform_deferred_access_checks (tf_warning_or_error);
+ if (success_p)
+ {
+ cp_finalize_omp_declare_simd (parser, current_function_decl);
+ parser->omp_declare_simd = NULL;
+ }
+
if (!success_p)
{
/* Skip the entire function. */
@@ -22775,6 +22866,7 @@ cp_parser_save_member_function_body (cp_parser* parser,
/* Create the FUNCTION_DECL. */
fn = grokmethod (decl_specifiers, declarator, attributes);
+ cp_finalize_omp_declare_simd (parser, fn);
/* If something went badly wrong, bail out now. */
if (fn == error_mark_node)
{
@@ -23001,9 +23093,18 @@ cp_parser_late_parsing_for_member (cp_parser* parser, tree member_function)
if (processing_template_decl)
push_deferring_access_checks (dk_no_check);
- /* Now, parse the body of the function. */
- cp_parser_function_definition_after_declarator (parser,
- /*inline_p=*/true);
+ /* #pragma omp declare reduction needs special parsing. */
+ if (DECL_OMP_DECLARE_REDUCTION_P (member_function))
+ {
+ parser->lexer->in_pragma = true;
+ cp_parser_omp_declare_reduction_exprs (member_function, parser);
+ finish_function (0);
+ cp_check_omp_declare_reduction (member_function);
+ }
+ else
+ /* Now, parse the body of the function. */
+ cp_parser_function_definition_after_declarator (parser,
+ /*inline_p=*/true);
if (processing_template_decl)
pop_deferring_access_checks ();
@@ -23923,7 +24024,9 @@ cp_parser_next_token_starts_class_definition_p (cp_parser *parser)
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
- return (token->type == CPP_OPEN_BRACE || token->type == CPP_COLON);
+ return (token->type == CPP_OPEN_BRACE
+ || (token->type == CPP_COLON
+ && !parser->colon_doesnt_start_class_def_p));
}
/* Returns TRUE iff the next token is the "," or ">" (or `>>', in
@@ -25176,7 +25279,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);
@@ -26341,7 +26444,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
@@ -26359,6 +26462,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;
@@ -26366,6 +26471,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;
@@ -26374,23 +26483,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;
@@ -26398,18 +26529,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;
}
@@ -26442,20 +26595,30 @@ 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;
@@ -26475,6 +26638,48 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
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;
@@ -26489,6 +26694,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;
@@ -26496,6 +26711,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,
@@ -26514,7 +26731,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;
}
@@ -26762,77 +26979,102 @@ cp_parser_omp_clause_ordered (cp_parser * /*parser*/,
OpenMP 3.1:
reduction-operator:
- One of: + * - & ^ | && || min max */
+ One of: + * - & ^ | && || min max
+
+ OpenMP 4.0:
+
+ reduction-operator:
+ One of: + * - & ^ | && ||
+ id-expression */
static tree
cp_parser_omp_clause_reduction (cp_parser *parser, tree list)
{
- enum tree_code code;
- tree nlist, c;
+ enum tree_code code = ERROR_MARK;
+ tree nlist, c, id = NULL_TREE;
if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
return list;
switch (cp_lexer_peek_token (parser->lexer)->type)
{
- case CPP_PLUS:
- code = PLUS_EXPR;
- break;
- case CPP_MULT:
- code = MULT_EXPR;
- break;
- case CPP_MINUS:
- code = MINUS_EXPR;
- break;
- case CPP_AND:
- code = BIT_AND_EXPR;
- break;
- case CPP_XOR:
- code = BIT_XOR_EXPR;
- break;
- case CPP_OR:
- code = BIT_IOR_EXPR;
- break;
- case CPP_AND_AND:
- code = TRUTH_ANDIF_EXPR;
- break;
- case CPP_OR_OR:
- code = TRUTH_ORIF_EXPR;
- break;
- case CPP_NAME:
- {
- tree id = cp_lexer_peek_token (parser->lexer)->u.value;
- const char *p = IDENTIFIER_POINTER (id);
+ case CPP_PLUS: code = PLUS_EXPR; break;
+ case CPP_MULT: code = MULT_EXPR; break;
+ case CPP_MINUS: code = MINUS_EXPR; break;
+ case CPP_AND: code = BIT_AND_EXPR; break;
+ case CPP_XOR: code = BIT_XOR_EXPR; break;
+ case CPP_OR: code = BIT_IOR_EXPR; break;
+ case CPP_AND_AND: code = TRUTH_ANDIF_EXPR; break;
+ case CPP_OR_OR: code = TRUTH_ORIF_EXPR; break;
+ default: break;
+ }
- if (strcmp (p, "min") == 0)
- {
+ if (code != ERROR_MARK)
+ cp_lexer_consume_token (parser->lexer);
+ else
+ {
+ bool saved_colon_corrects_to_scope_p;
+ saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
+ parser->colon_corrects_to_scope_p = false;
+ id = cp_parser_id_expression (parser, /*template_p=*/false,
+ /*check_dependency_p=*/true,
+ /*template_p=*/NULL,
+ /*declarator_p=*/false,
+ /*optional_p=*/false);
+ parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
+ if (identifier_p (id))
+ {
+ const char *p = IDENTIFIER_POINTER (id);
+
+ if (strcmp (p, "min") == 0)
code = MIN_EXPR;
- break;
- }
- if (strcmp (p, "max") == 0)
- {
+ else if (strcmp (p, "max") == 0)
code = MAX_EXPR;
- break;
- }
- }
- /* FALLTHROUGH */
- default:
- cp_parser_error (parser, "expected %<+%>, %<*%>, %<-%>, %<&%>, %<^%>, "
- "%<|%>, %<&&%>, %<||%>, %<min%> or %<max%>");
- resync_fail:
- cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
- /*or_comma=*/false,
- /*consume_paren=*/true);
- return list;
+ else if (id == ansi_opname (PLUS_EXPR))
+ code = PLUS_EXPR;
+ else if (id == ansi_opname (MULT_EXPR))
+ code = MULT_EXPR;
+ else if (id == ansi_opname (MINUS_EXPR))
+ code = MINUS_EXPR;
+ else if (id == ansi_opname (BIT_AND_EXPR))
+ code = BIT_AND_EXPR;
+ else if (id == ansi_opname (BIT_IOR_EXPR))
+ code = BIT_IOR_EXPR;
+ else if (id == ansi_opname (BIT_XOR_EXPR))
+ code = BIT_XOR_EXPR;
+ else if (id == ansi_opname (TRUTH_ANDIF_EXPR))
+ code = TRUTH_ANDIF_EXPR;
+ else if (id == ansi_opname (TRUTH_ORIF_EXPR))
+ code = TRUTH_ORIF_EXPR;
+ id = omp_reduction_id (code, id, NULL_TREE);
+ tree scope = parser->scope;
+ if (scope)
+ id = build_qualified_name (NULL_TREE, scope, id, false);
+ parser->scope = NULL_TREE;
+ parser->qualifying_scope = NULL_TREE;
+ parser->object_scope = NULL_TREE;
+ }
+ else
+ {
+ error ("invalid reduction-identifier");
+ resync_fail:
+ cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+ return list;
+ }
}
- 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_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;
+ {
+ OMP_CLAUSE_REDUCTION_CODE (c) = code;
+ OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = id;
+ }
return nlist;
}
@@ -26945,13 +27187,468 @@ cp_parser_omp_clause_untied (cp_parser * /*parser*/,
return c;
}
+/* OpenMP 4.0:
+ inbranch
+ notinbranch */
+
+static tree
+cp_parser_omp_clause_branch (cp_parser * /*parser*/, enum omp_clause_code code,
+ tree list, location_t location)
+{
+ check_no_duplicate_clause (list, code, omp_clause_code_name[code], location);
+ tree c = build_omp_clause (location, code);
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+}
+
+/* OpenMP 4.0:
+ parallel
+ for
+ sections
+ taskgroup */
+
+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;
+}
+
+/* OpenMP 4.0:
+ num_teams ( expression ) */
+
+static tree
+cp_parser_omp_clause_num_teams (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_NUM_TEAMS,
+ "num_teams", location);
+
+ c = build_omp_clause (location, OMP_CLAUSE_NUM_TEAMS);
+ OMP_CLAUSE_NUM_TEAMS_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+
+ return c;
+}
+
+/* OpenMP 4.0:
+ thread_limit ( expression ) */
+
+static tree
+cp_parser_omp_clause_thread_limit (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_THREAD_LIMIT,
+ "thread_limit", location);
+
+ c = build_omp_clause (location, OMP_CLAUSE_THREAD_LIMIT);
+ OMP_CLAUSE_THREAD_LIMIT_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+
+ 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, unsigned int mask,
- const char *where, cp_token *pragma_tok)
+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;
@@ -26968,7 +27665,6 @@ cp_parser_omp_all_clauses (cp_parser *parser, unsigned int mask,
token = cp_lexer_peek_token (parser->lexer);
c_kind = cp_parser_omp_clause_name (parser);
- first = false;
switch (c_kind)
{
@@ -27050,13 +27746,125 @@ cp_parser_omp_all_clauses (cp_parser *parser, unsigned int mask,
case PRAGMA_OMP_CLAUSE_UNTIED:
clauses = cp_parser_omp_clause_untied (parser, clauses,
token->location);
- c_name = "nowait";
+ 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
@@ -27067,7 +27875,9 @@ cp_parser_omp_all_clauses (cp_parser *parser, unsigned int mask,
}
saw_error:
cp_parser_skip_to_pragma_eol (parser, pragma_tok);
- return finish_omp_clauses (clauses);
+ if (finish_p)
+ return finish_omp_clauses (clauses);
+ return clauses;
}
/* OpenMP 2.5:
@@ -27152,10 +27962,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
@@ -27165,6 +27983,7 @@ 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))
{
@@ -27184,6 +28003,18 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok)
if (p)
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)
@@ -27322,75 +28153,139 @@ restart:
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;
}
- 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;
+ 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;
+ }
+ 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,
@@ -27426,7 +28321,7 @@ stmt_done:
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;
@@ -27635,7 +28530,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;
@@ -27845,10 +28741,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)
{
@@ -27994,7 +28892,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)
@@ -28027,33 +28925,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;
- clauses = cp_parser_omp_all_clauses (parser, OMP_FOR_CLAUSE_MASK,
- "#pragma omp for", pragma_tok);
+ 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, 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));
@@ -28108,26 +29110,7 @@ cp_parser_omp_sections_scope (cp_parser *parser)
if (cp_lexer_peek_token (parser->lexer)->pragma_kind != PRAGMA_OMP_SECTION)
{
- unsigned save;
-
- substmt = begin_omp_structured_block ();
- save = cp_parser_begin_omp_structured_block (parser);
-
- while (1)
- {
- cp_parser_statement (parser, NULL_TREE, false, NULL);
-
- tok = cp_lexer_peek_token (parser->lexer);
- if (tok->pragma_kind == PRAGMA_OMP_SECTION)
- break;
- if (tok->type == CPP_CLOSE_BRACE)
- break;
- if (tok->type == CPP_EOF)
- break;
- }
-
- cp_parser_end_omp_structured_block (parser, save);
- substmt = finish_omp_structured_block (substmt);
+ substmt = cp_parser_omp_structured_block (parser);
substmt = build1 (OMP_SECTION, void_type_node, substmt);
add_stmt (substmt);
}
@@ -28172,20 +29155,32 @@ cp_parser_omp_sections_scope (cp_parser *parser)
# pragma omp sections sections-clause[optseq] newline
sections-scope */
-#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
-cp_parser_omp_sections (cp_parser *parser, cp_token *pragma_tok)
+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;
- clauses = cp_parser_omp_all_clauses (parser, OMP_SECTIONS_CLAUSE_MASK,
- "#pragma omp sections", pragma_tok);
+ 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)
@@ -28197,35 +29192,54 @@ cp_parser_omp_sections (cp_parser *parser, cp_token *pragma_tok)
/* 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))
+ # 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)
+cp_parser_omp_parallel (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 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);
- p_kind = PRAGMA_OMP_PARALLEL_FOR;
- p_name = "#pragma omp parallel for";
- mask |= OMP_FOR_CLAUSE_MASK;
- mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT);
+ 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 %<for%> 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))
{
@@ -28233,45 +29247,28 @@ cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok)
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);
- p_kind = PRAGMA_OMP_PARALLEL_SECTIONS;
- p_name = "#pragma omp parallel sections";
- mask |= OMP_SECTIONS_CLAUSE_MASK;
- mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT);
+ 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);
-
- switch (p_kind)
- {
- 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_parser_statement (parser, NULL_TREE, false, NULL);
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;
+ stmt = finish_omp_parallel (clauses, block);
return stmt;
}
@@ -28279,11 +29276,11 @@ cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok)
# pragma omp single single-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_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)
@@ -28303,15 +29300,16 @@ cp_parser_omp_single (cp_parser *parser, cp_token *pragma_tok)
# pragma omp task task-clause[optseq] new-line
structured-block */
-#define OMP_TASK_CLAUSE_MASK \
- ( (1u << PRAGMA_OMP_CLAUSE_IF) \
- | (1u << PRAGMA_OMP_CLAUSE_UNTIED) \
- | (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \
- | (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \
- | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
- | (1u << PRAGMA_OMP_CLAUSE_SHARED) \
- | (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
cp_parser_omp_task (cp_parser *parser, cp_token *pragma_tok)
@@ -28348,6 +29346,19 @@ cp_parser_omp_taskyield (cp_parser *parser, cp_token *pragma_tok)
finish_omp_taskyield ();
}
+/* OpenMP 4.0:
+ # pragma omp taskgroup new-line
+ structured-block */
+
+static tree
+cp_parser_omp_taskgroup (cp_parser *parser, cp_token *pragma_tok)
+{
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+ return c_finish_omp_taskgroup (input_location,
+ cp_parser_omp_structured_block (parser));
+}
+
+
/* OpenMP 2.5:
# pragma omp threadprivate (variable-list) */
@@ -28362,12 +29373,957 @@ cp_parser_omp_threadprivate (cp_parser *parser, cp_token *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);
+ point_seen = true;
+ }
+ }
+ if (!point_seen)
+ {
+ cp_parser_error (parser, "expected %<point%>");
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+ return;
+ }
+
+ clauses = cp_parser_omp_all_clauses (parser,
+ OMP_CANCELLATION_POINT_CLAUSE_MASK,
+ "#pragma omp cancellation point",
+ pragma_tok);
+ finish_omp_cancellation_point (clauses);
+}
+
+/* OpenMP 4.0:
+ #pragma omp distribute distribute-clause[optseq] new-line
+ for-loop */
+
+#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_distribute (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, " distribute");
+ mask |= OMP_DISTRIBUTE_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);
+ 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 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_teams (cp_parser *parser, cp_token *pragma_tok,
+ char *p_name, omp_clause_mask mask, tree *cclauses)
+{
+ tree clauses, sb, ret;
+ unsigned int save;
+ location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+
+ strcat (p_name, " teams");
+ mask |= OMP_TEAMS_CLAUSE_MASK;
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ const char *p = IDENTIFIER_POINTER (id);
+ if (strcmp (p, "distribute") == 0)
+ {
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+
+ cp_lexer_consume_token (parser->lexer);
+ 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,
+ cclauses == NULL);
+ if (cclauses)
+ {
+ cp_omp_split_clauses (loc, OMP_TEAMS, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS];
+ }
+
+ tree stmt = make_node (OMP_TEAMS);
+ TREE_TYPE (stmt) = void_type_node;
+ OMP_TEAMS_CLAUSES (stmt) = clauses;
+ OMP_TEAMS_BODY (stmt) = cp_parser_omp_structured_block (parser);
+
+ return add_stmt (stmt);
+}
+
+/* OpenMP 4.0:
+ # pragma omp target data target-data-clause[optseq] new-line
+ structured-block */
+
+#define OMP_TARGET_DATA_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF))
+
+static tree
+cp_parser_omp_target_data (cp_parser *parser, cp_token *pragma_tok)
+{
+ tree stmt = make_node (OMP_TARGET_DATA);
+ TREE_TYPE (stmt) = void_type_node;
+
+ OMP_TARGET_DATA_CLAUSES (stmt)
+ = cp_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK,
+ "#pragma omp target data", pragma_tok);
+ keep_next_level (true);
+ OMP_TARGET_DATA_BODY (stmt) = cp_parser_omp_structured_block (parser);
+
+ SET_EXPR_LOCATION (stmt, pragma_tok->location);
+ return add_stmt (stmt);
+}
+
+/* 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 "
+ "%<from%> or %<to%> 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_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 bool
+cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok,
+ enum pragma_context context)
+{
+ if (context != pragma_stmt && context != pragma_compound)
+ {
+ cp_parser_error (parser, "expected declaration specifiers");
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ return false;
+ }
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ const char *p = IDENTIFIER_POINTER (id);
+
+ if (strcmp (p, "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");
+ keep_next_level (true);
+ 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);
+ keep_next_level (true);
+ OMP_TARGET_BODY (stmt) = cp_parser_omp_structured_block (parser);
+
+ SET_EXPR_LOCATION (stmt, pragma_tok->location);
+ add_stmt (stmt);
+ return true;
+}
+
+/* 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_INBRANCH) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOTINBRANCH))
+
+static void
+cp_parser_omp_declare_simd (cp_parser *parser, cp_token *pragma_tok,
+ enum pragma_context context)
+{
+ bool first_p = parser->omp_declare_simd == NULL;
+ cp_omp_declare_simd_data data;
+ if (first_p)
+ {
+ data.error_seen = false;
+ data.fndecl_seen = false;
+ data.tokens = vNULL;
+ parser->omp_declare_simd = &data;
+ }
+ while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)
+ && cp_lexer_next_token_is_not (parser->lexer, CPP_EOF))
+ cp_lexer_consume_token (parser->lexer);
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL))
+ parser->omp_declare_simd->error_seen = true;
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+ struct cp_token_cache *cp
+ = cp_token_cache_new (pragma_tok, cp_lexer_peek_token (parser->lexer));
+ parser->omp_declare_simd->tokens.safe_push (cp);
+ 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
+ && !parser->omp_declare_simd->error_seen
+ && !parser->omp_declare_simd->fndecl_seen)
+ error_at (pragma_tok->location,
+ "%<#pragma omp declare simd%> not immediately followed by "
+ "function declaration or definition");
+ data.tokens.release ();
+ parser->omp_declare_simd = NULL;
+ }
+}
+
+/* Finalize #pragma omp declare simd clauses after direct declarator has
+ been parsed, and put that into "omp declare simd" attribute. */
+
+static tree
+cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs)
+{
+ struct cp_token_cache *ce;
+ cp_omp_declare_simd_data *data = parser->omp_declare_simd;
+ int i;
+
+ if (!data->error_seen && data->fndecl_seen)
+ {
+ error ("%<#pragma omp declare simd%> not immediately followed by "
+ "a single function declaration or definition");
+ data->error_seen = true;
+ return attrs;
+ }
+ if (data->error_seen)
+ return attrs;
+
+ FOR_EACH_VEC_ELT (data->tokens, i, ce)
+ {
+ tree c, cl;
+
+ cp_parser_push_lexer_for_tokens (parser, ce);
+ parser->lexer->in_pragma = true;
+ gcc_assert (cp_lexer_peek_token (parser->lexer)->type == CPP_PRAGMA);
+ cp_token *pragma_tok = cp_lexer_consume_token (parser->lexer);
+ cp_lexer_consume_token (parser->lexer);
+ cl = cp_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK,
+ "#pragma omp declare simd", pragma_tok);
+ cp_parser_pop_lexer (parser);
+ if (cl)
+ cl = tree_cons (NULL_TREE, cl, NULL_TREE);
+ c = build_tree_list (get_identifier ("omp declare simd"), cl);
+ TREE_CHAIN (c) = attrs;
+ if (processing_template_decl)
+ ATTR_IS_DEPENDENT (c) = 1;
+ attrs = c;
+ }
+
+ data->fndecl_seen = true;
+ return attrs;
+}
+
+
+/* OpenMP 4.0:
+ # pragma omp declare target new-line
+ declarations and definitions
+ # pragma omp end declare target new-line */
+
+static void
+cp_parser_omp_declare_target (cp_parser *parser, cp_token *pragma_tok)
+{
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ scope_chain->omp_declare_target_attribute++;
+}
+
+static void
+cp_parser_omp_end_declare_target (cp_parser *parser, cp_token *pragma_tok)
+{
+ const char *p = "";
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ p = IDENTIFIER_POINTER (id);
+ }
+ if (strcmp (p, "declare") == 0)
+ {
+ cp_lexer_consume_token (parser->lexer);
+ p = "";
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ p = IDENTIFIER_POINTER (id);
+ }
+ if (strcmp (p, "target") == 0)
+ cp_lexer_consume_token (parser->lexer);
+ else
+ {
+ cp_parser_error (parser, "expected %<target%>");
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ return;
+ }
+ }
+ else
+ {
+ cp_parser_error (parser, "expected %<declare%>");
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ return;
+ }
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ if (!scope_chain->omp_declare_target_attribute)
+ error_at (pragma_tok->location,
+ "%<#pragma omp end declare target%> without corresponding "
+ "%<#pragma omp declare target%>");
+ else
+ scope_chain->omp_declare_target_attribute--;
+}
+
+/* Helper function of cp_parser_omp_declare_reduction. Parse the combiner
+ expression and optional initializer clause of
+ #pragma omp declare reduction. We store the expression(s) as
+ either 3, 6 or 7 special statements inside of the artificial function's
+ body. The first two statements are DECL_EXPRs for the artificial
+ OMP_OUT resp. OMP_IN variables, followed by a statement with the combiner
+ expression that uses those variables.
+ If there was any INITIALIZER clause, this is followed by further statements,
+ the fourth and fifth statements are DECL_EXPRs for the artificial
+ OMP_PRIV resp. OMP_ORIG variables. If the INITIALIZER clause wasn't the
+ constructor variant (first token after open paren is not omp_priv),
+ then the sixth statement is a statement with the function call expression
+ that uses the OMP_PRIV and optionally OMP_ORIG variable.
+ Otherwise, the sixth statement is whatever statement cp_finish_decl emits
+ to initialize the OMP_PRIV artificial variable and there is seventh
+ statement, a DECL_EXPR of the OMP_PRIV statement again. */
+
+static bool
+cp_parser_omp_declare_reduction_exprs (tree fndecl, cp_parser *parser)
+{
+ tree type = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (fndecl)));
+ gcc_assert (TREE_CODE (type) == REFERENCE_TYPE);
+ type = TREE_TYPE (type);
+ tree omp_out = build_lang_decl (VAR_DECL, get_identifier ("omp_out"), type);
+ DECL_ARTIFICIAL (omp_out) = 1;
+ pushdecl (omp_out);
+ add_decl_expr (omp_out);
+ tree omp_in = build_lang_decl (VAR_DECL, get_identifier ("omp_in"), type);
+ DECL_ARTIFICIAL (omp_in) = 1;
+ pushdecl (omp_in);
+ add_decl_expr (omp_in);
+ tree combiner;
+ tree omp_priv = NULL_TREE, omp_orig = NULL_TREE, initializer = NULL_TREE;
+
+ keep_next_level (true);
+ tree block = begin_omp_structured_block ();
+ combiner = cp_parser_expression (parser, false, NULL);
+ finish_expr_stmt (combiner);
+ block = finish_omp_structured_block (block);
+ add_stmt (block);
+
+ if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
+ return false;
+
+ const char *p = "";
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ p = IDENTIFIER_POINTER (id);
+ }
+
+ if (strcmp (p, "initializer") == 0)
+ {
+ cp_lexer_consume_token (parser->lexer);
+ if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
+ return false;
+
+ p = "";
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ p = IDENTIFIER_POINTER (id);
+ }
+
+ omp_priv = build_lang_decl (VAR_DECL, get_identifier ("omp_priv"), type);
+ DECL_ARTIFICIAL (omp_priv) = 1;
+ pushdecl (omp_priv);
+ add_decl_expr (omp_priv);
+ omp_orig = build_lang_decl (VAR_DECL, get_identifier ("omp_orig"), type);
+ DECL_ARTIFICIAL (omp_orig) = 1;
+ pushdecl (omp_orig);
+ add_decl_expr (omp_orig);
+
+ keep_next_level (true);
+ block = begin_omp_structured_block ();
+
+ bool ctor = false;
+ if (strcmp (p, "omp_priv") == 0)
+ {
+ bool is_direct_init, is_non_constant_init;
+ ctor = true;
+ cp_lexer_consume_token (parser->lexer);
+ /* Reject initializer (omp_priv) and initializer (omp_priv ()). */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)
+ || (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)
+ && cp_lexer_peek_nth_token (parser->lexer, 2)->type
+ == CPP_CLOSE_PAREN
+ && cp_lexer_peek_nth_token (parser->lexer, 3)->type
+ == CPP_CLOSE_PAREN))
+ {
+ finish_omp_structured_block (block);
+ error ("invalid initializer clause");
+ return false;
+ }
+ initializer = cp_parser_initializer (parser, &is_direct_init,
+ &is_non_constant_init);
+ cp_finish_decl (omp_priv, initializer, !is_non_constant_init,
+ NULL_TREE, LOOKUP_ONLYCONVERTING);
+ }
+ else
+ {
+ cp_parser_parse_tentatively (parser);
+ tree fn_name = cp_parser_id_expression (parser, /*template_p=*/false,
+ /*check_dependency_p=*/true,
+ /*template_p=*/NULL,
+ /*declarator_p=*/false,
+ /*optional_p=*/false);
+ vec<tree, va_gc> *args;
+ if (fn_name == error_mark_node
+ || cp_parser_error_occurred (parser)
+ || !cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)
+ || ((args = cp_parser_parenthesized_expression_list
+ (parser, non_attr, /*cast_p=*/false,
+ /*allow_expansion_p=*/true,
+ /*non_constant_p=*/NULL)),
+ cp_parser_error_occurred (parser)))
+ {
+ finish_omp_structured_block (block);
+ cp_parser_abort_tentative_parse (parser);
+ cp_parser_error (parser, "expected id-expression (arguments)");
+ return false;
+ }
+ unsigned int i;
+ tree arg;
+ FOR_EACH_VEC_SAFE_ELT (args, i, arg)
+ if (arg == omp_priv
+ || (TREE_CODE (arg) == ADDR_EXPR
+ && TREE_OPERAND (arg, 0) == omp_priv))
+ break;
+ cp_parser_abort_tentative_parse (parser);
+ if (arg == NULL_TREE)
+ error ("one of the initializer call arguments should be %<omp_priv%>"
+ " or %<&omp_priv%>");
+ initializer = cp_parser_postfix_expression (parser, false, false, false,
+ false, NULL);
+ finish_expr_stmt (initializer);
+ }
+
+ block = finish_omp_structured_block (block);
+ cp_walk_tree (&block, cp_remove_omp_priv_cleanup_stmt, omp_priv, NULL);
+ finish_expr_stmt (block);
+
+ if (ctor)
+ add_decl_expr (omp_orig);
+
+ if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
+ return false;
+ }
+
+ if (!cp_lexer_next_token_is (parser->lexer, CPP_PRAGMA_EOL))
+ cp_parser_required_error (parser, RT_PRAGMA_EOL, /*keyword=*/false);
+
+ return true;
+}
+
+/* OpenMP 4.0
+ #pragma omp declare reduction (reduction-id : typename-list : expression) \
+ initializer-clause[opt] new-line
+
+ initializer-clause:
+ initializer (omp_priv initializer)
+ initializer (function-name (argument-list)) */
+
+static void
+cp_parser_omp_declare_reduction (cp_parser *parser, cp_token *pragma_tok,
+ enum pragma_context)
+{
+ vec<tree> types = vNULL;
+ enum tree_code reduc_code = ERROR_MARK;
+ tree reduc_id = NULL_TREE, orig_reduc_id = NULL_TREE, type;
+ unsigned int i;
+ cp_token *first_token;
+ cp_token_cache *cp;
+ int errs;
+
+ if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
+ goto fail;
+
+ switch (cp_lexer_peek_token (parser->lexer)->type)
+ {
+ case CPP_PLUS:
+ reduc_code = PLUS_EXPR;
+ break;
+ case CPP_MULT:
+ reduc_code = MULT_EXPR;
+ break;
+ case CPP_MINUS:
+ reduc_code = MINUS_EXPR;
+ break;
+ case CPP_AND:
+ reduc_code = BIT_AND_EXPR;
+ break;
+ case CPP_XOR:
+ reduc_code = BIT_XOR_EXPR;
+ break;
+ case CPP_OR:
+ reduc_code = BIT_IOR_EXPR;
+ break;
+ case CPP_AND_AND:
+ reduc_code = TRUTH_ANDIF_EXPR;
+ break;
+ case CPP_OR_OR:
+ reduc_code = TRUTH_ORIF_EXPR;
+ break;
+ case CPP_NAME:
+ reduc_id = orig_reduc_id = cp_parser_identifier (parser);
+ break;
+ default:
+ cp_parser_error (parser, "expected %<+%>, %<*%>, %<-%>, %<&%>, %<^%>, "
+ "%<|%>, %<&&%>, %<||%> or identifier");
+ goto fail;
+ }
+
+ if (reduc_code != ERROR_MARK)
+ cp_lexer_consume_token (parser->lexer);
+
+ reduc_id = omp_reduction_id (reduc_code, reduc_id, NULL_TREE);
+ if (reduc_id == error_mark_node)
+ goto fail;
+
+ if (!cp_parser_require (parser, CPP_COLON, RT_COLON))
+ goto fail;
+
+ /* Types may not be defined in declare reduction type list. */
+ const char *saved_message;
+ saved_message = parser->type_definition_forbidden_message;
+ parser->type_definition_forbidden_message
+ = G_("types may not be defined in declare reduction type list");
+ bool saved_colon_corrects_to_scope_p;
+ saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
+ parser->colon_corrects_to_scope_p = false;
+ bool saved_colon_doesnt_start_class_def_p;
+ saved_colon_doesnt_start_class_def_p
+ = parser->colon_doesnt_start_class_def_p;
+ parser->colon_doesnt_start_class_def_p = true;
+
+ while (true)
+ {
+ location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+ type = cp_parser_type_id (parser);
+ if (type == error_mark_node)
+ ;
+ else if (ARITHMETIC_TYPE_P (type)
+ && (orig_reduc_id == NULL_TREE
+ || (TREE_CODE (type) != COMPLEX_TYPE
+ && (strcmp (IDENTIFIER_POINTER (orig_reduc_id),
+ "min") == 0
+ || strcmp (IDENTIFIER_POINTER (orig_reduc_id),
+ "max") == 0))))
+ error_at (loc, "predeclared arithmetic type %qT in "
+ "%<#pragma omp declare reduction%>", type);
+ else if (TREE_CODE (type) == FUNCTION_TYPE
+ || TREE_CODE (type) == METHOD_TYPE
+ || TREE_CODE (type) == ARRAY_TYPE)
+ error_at (loc, "function or array type %qT in "
+ "%<#pragma omp declare reduction%>", type);
+ else if (TREE_CODE (type) == REFERENCE_TYPE)
+ error_at (loc, "reference type %qT in "
+ "%<#pragma omp declare reduction%>", type);
+ else if (TYPE_QUALS_NO_ADDR_SPACE (type))
+ error_at (loc, "const, volatile or __restrict qualified type %qT in "
+ "%<#pragma omp declare reduction%>", type);
+ else
+ types.safe_push (type);
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+ cp_lexer_consume_token (parser->lexer);
+ else
+ break;
+ }
+
+ /* Restore the saved message. */
+ parser->type_definition_forbidden_message = saved_message;
+ parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
+ parser->colon_doesnt_start_class_def_p
+ = saved_colon_doesnt_start_class_def_p;
+
+ if (!cp_parser_require (parser, CPP_COLON, RT_COLON)
+ || types.is_empty ())
+ {
+ fail:
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ types.release ();
+ return;
+ }
+
+ first_token = cp_lexer_peek_token (parser->lexer);
+ cp = NULL;
+ errs = errorcount;
+ FOR_EACH_VEC_ELT (types, i, type)
+ {
+ tree fntype
+ = build_function_type_list (void_type_node,
+ cp_build_reference_type (type, false),
+ NULL_TREE);
+ tree this_reduc_id = reduc_id;
+ if (!dependent_type_p (type))
+ this_reduc_id = omp_reduction_id (ERROR_MARK, reduc_id, type);
+ tree fndecl = build_lang_decl (FUNCTION_DECL, this_reduc_id, fntype);
+ DECL_SOURCE_LOCATION (fndecl) = pragma_tok->location;
+ DECL_ARTIFICIAL (fndecl) = 1;
+ DECL_EXTERNAL (fndecl) = 1;
+ DECL_DECLARED_INLINE_P (fndecl) = 1;
+ DECL_IGNORED_P (fndecl) = 1;
+ DECL_OMP_DECLARE_REDUCTION_P (fndecl) = 1;
+ DECL_ATTRIBUTES (fndecl)
+ = tree_cons (get_identifier ("gnu_inline"), NULL_TREE,
+ DECL_ATTRIBUTES (fndecl));
+ if (processing_template_decl)
+ fndecl = push_template_decl (fndecl);
+ bool block_scope = false;
+ tree block = NULL_TREE;
+ if (current_function_decl)
+ {
+ block_scope = true;
+ DECL_CONTEXT (fndecl) = global_namespace;
+ if (!processing_template_decl)
+ pushdecl (fndecl);
+ }
+ else if (current_class_type)
+ {
+ if (cp == NULL)
+ {
+ while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)
+ && cp_lexer_next_token_is_not (parser->lexer, CPP_EOF))
+ cp_lexer_consume_token (parser->lexer);
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL))
+ goto fail;
+ cp = cp_token_cache_new (first_token,
+ cp_lexer_peek_nth_token (parser->lexer,
+ 2));
+ }
+ DECL_STATIC_FUNCTION_P (fndecl) = 1;
+ finish_member_declaration (fndecl);
+ DECL_PENDING_INLINE_INFO (fndecl) = cp;
+ DECL_PENDING_INLINE_P (fndecl) = 1;
+ vec_safe_push (unparsed_funs_with_definitions, fndecl);
+ continue;
+ }
+ else
+ {
+ DECL_CONTEXT (fndecl) = current_namespace;
+ pushdecl (fndecl);
+ }
+ if (!block_scope)
+ start_preparsed_function (fndecl, NULL_TREE, SF_PRE_PARSED);
+ else
+ block = begin_omp_structured_block ();
+ if (cp)
+ {
+ cp_parser_push_lexer_for_tokens (parser, cp);
+ parser->lexer->in_pragma = true;
+ }
+ if (!cp_parser_omp_declare_reduction_exprs (fndecl, parser))
+ {
+ if (!block_scope)
+ finish_function (0);
+ else
+ DECL_CONTEXT (fndecl) = current_function_decl;
+ if (cp)
+ cp_parser_pop_lexer (parser);
+ goto fail;
+ }
+ if (cp)
+ cp_parser_pop_lexer (parser);
+ if (!block_scope)
+ finish_function (0);
+ else
+ {
+ DECL_CONTEXT (fndecl) = current_function_decl;
+ block = finish_omp_structured_block (block);
+ if (TREE_CODE (block) == BIND_EXPR)
+ DECL_SAVED_TREE (fndecl) = BIND_EXPR_BODY (block);
+ else if (TREE_CODE (block) == STATEMENT_LIST)
+ DECL_SAVED_TREE (fndecl) = block;
+ if (processing_template_decl)
+ add_decl_expr (fndecl);
+ }
+ cp_check_omp_declare_reduction (fndecl);
+ if (cp == NULL && types.length () > 1)
+ cp = cp_token_cache_new (first_token,
+ cp_lexer_peek_nth_token (parser->lexer, 2));
+ if (errs != errorcount)
+ break;
+ }
+
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+ types.release ();
+}
+
+/* OpenMP 4.0
+ #pragma omp declare simd declare-simd-clauses[optseq] new-line
+ #pragma omp declare reduction (reduction-id : typename-list : expression) \
+ initializer-clause[opt] new-line
+ #pragma omp declare target new-line */
+
+static void
+cp_parser_omp_declare (cp_parser *parser, cp_token *pragma_tok,
+ enum pragma_context context)
+{
+ 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)
+ {
+ 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 %<simd%> or %<reduction%> "
+ "or %<target%>");
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+}
+
/* Main entry point to OpenMP statement pragmas. */
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)
{
@@ -28377,8 +30333,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);
@@ -28387,10 +30348,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);
@@ -28398,6 +30365,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:
+ stmt = cp_parser_omp_taskgroup (parser, pragma_tok);
+ break;
+ 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 ();
}
@@ -28754,6 +30728,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:
@@ -28823,24 +30799,71 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context)
}
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 cancel%> may only be "
+ "used in compound statements");
+ break;
+ default:
+ goto bad_stmt;
+ }
+ break;
+
+ case PRAGMA_OMP_CANCELLATION_POINT:
+ switch (context)
+ {
+ case pragma_compound:
+ cp_parser_omp_cancellation_point (parser, pragma_tok);
+ return false;
+ case pragma_stmt:
+ error_at (pragma_tok->location,
+ "%<#pragma omp cancellation point%> may only be "
+ "used in compound statements");
+ break;
+ default:
+ goto bad_stmt;
+ }
+ break;
+
case PRAGMA_OMP_THREADPRIVATE:
cp_parser_omp_threadprivate (parser, pragma_tok);
return false;
+ 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 "
diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index ffdddaf4a08..75f327b1d8b 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -196,6 +196,14 @@ typedef struct GTY (()) cp_parser_context {
} cp_parser_context;
+/* Control structure for #pragma omp declare simd parsing. */
+struct cp_omp_declare_simd_data {
+ bool error_seen; /* Set if error has been reported. */
+ bool fndecl_seen; /* Set if one fn decl/definition has been seen already. */
+ vec<cp_token_cache_ptr> tokens;
+};
+
+
/* The cp_parser structure represents the C++ parser. */
typedef struct GTY(()) cp_parser {
@@ -324,6 +332,12 @@ typedef struct GTY(()) cp_parser {
/* TRUE if we can auto-correct a colon to a scope operator. */
bool colon_corrects_to_scope_p;
+ /* TRUE if : doesn't start a class definition. Should be only used
+ together with type_definition_forbidden_message non-NULL, in
+ contexts where new types may not be defined, and the type list
+ is terminated by colon. */
+ bool colon_doesnt_start_class_def_p;
+
/* If non-NULL, then we are parsing a construct where new type
definitions are not permitted. The string stored here will be
issued as an error message if a type is defined. */
@@ -342,6 +356,10 @@ typedef struct GTY(()) cp_parser {
current declaration. */
unsigned num_template_parameter_lists;
+ /* When parsing #pragma omp declare simd, this is a pointer to a
+ data structure with everything needed for parsing the clauses. */
+ cp_omp_declare_simd_data * GTY((skip)) omp_declare_simd;
+
/* TRUE if the function being declared was made a template due to its
parameter list containing generic type specifiers (`auto' or concept
identifiers) rather than an explicit template parameter list. */
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index a35000728aa..5721a681a4a 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -8545,6 +8545,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. */
@@ -8586,14 +8588,32 @@ 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 (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 parms = DECL_ARGUMENTS (*decl_p);
+ clauses
+ = c_omp_declare_simd_clauses_to_numbers (parms, clauses);
+ if (clauses)
+ TREE_VALUE (TREE_VALUE (t)) = clauses;
+ else
+ TREE_VALUE (t) = NULL_TREE;
+ }
/* 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,
@@ -8915,6 +8935,9 @@ instantiate_class_template_1 (tree type)
/* Instantiate members marked with attribute used. */
if (r != error_mark_node && DECL_PRESERVE_P (r))
mark_used (r);
+ if (TREE_CODE (r) == FUNCTION_DECL
+ && DECL_OMP_DECLARE_REDUCTION_P (r))
+ cp_check_omp_declare_reduction (r);
}
else
{
@@ -10383,6 +10406,24 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
DECL_INITIAL (r) = NULL_TREE;
DECL_CONTEXT (r) = ctx;
+ /* OpenMP UDRs have the only argument a reference to the declared
+ type. We want to diagnose if the declared type is a reference,
+ which is invalid, but as references to references are usually
+ quietly merged, diagnose it here. */
+ if (DECL_OMP_DECLARE_REDUCTION_P (t))
+ {
+ tree argtype
+ = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (t))));
+ argtype = tsubst (argtype, args, complain, in_decl);
+ if (TREE_CODE (argtype) == REFERENCE_TYPE)
+ error_at (DECL_SOURCE_LOCATION (t),
+ "reference type %qT in "
+ "%<#pragma omp declare reduction%>", argtype);
+ if (strchr (IDENTIFIER_POINTER (DECL_NAME (t)), '~') == NULL)
+ DECL_NAME (r) = omp_reduction_id (ERROR_MARK, DECL_NAME (t),
+ argtype);
+ }
+
if (member && DECL_CONV_FN_P (r))
/* Type-conversion operator. Reconstruct the name, in
case it's the name of one of the template's parameters. */
@@ -12815,8 +12856,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;
@@ -12841,7 +12882,6 @@ tsubst_omp_clauses (tree clauses, tree args, tsubst_flags_t complain,
case OMP_CLAUSE_PRIVATE:
case OMP_CLAUSE_SHARED:
case OMP_CLAUSE_FIRSTPRIVATE:
- case OMP_CLAUSE_REDUCTION:
case OMP_CLAUSE_COPYIN:
case OMP_CLAUSE_COPYPRIVATE:
case OMP_CLAUSE_IF:
@@ -12849,22 +12889,73 @@ 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_REDUCTION:
+ if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (oc))
+ {
+ tree placeholder = OMP_CLAUSE_REDUCTION_PLACEHOLDER (oc);
+ if (TREE_CODE (placeholder) == SCOPE_REF)
+ {
+ tree scope = tsubst (TREE_OPERAND (placeholder, 0), args,
+ complain, in_decl);
+ OMP_CLAUSE_REDUCTION_PLACEHOLDER (nc)
+ = build_qualified_name (NULL_TREE, scope,
+ TREE_OPERAND (placeholder, 1),
+ false);
+ }
+ else
+ gcc_assert (identifier_p (placeholder));
+ }
+ 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. */
@@ -13169,6 +13260,15 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
}
else if (DECL_IMPLICIT_TYPEDEF_P (t))
/* We already did a pushtag. */;
+ else if (TREE_CODE (decl) == FUNCTION_DECL
+ && DECL_OMP_DECLARE_REDUCTION_P (decl)
+ && DECL_FUNCTION_SCOPE_P (pattern_decl))
+ {
+ DECL_CONTEXT (decl) = NULL_TREE;
+ pushdecl (decl);
+ DECL_CONTEXT (decl) = current_function_decl;
+ cp_check_omp_declare_reduction (decl);
+ }
else
{
int const_init = false;
@@ -13440,7 +13540,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));
@@ -13449,7 +13549,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));
@@ -13457,17 +13557,23 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
break;
case OMP_FOR:
+ case OMP_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 ();
@@ -13475,17 +13581,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));
}
@@ -13493,7 +13611,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);
@@ -13504,9 +13626,18 @@ 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:
+ case OMP_TASKGROUP:
case OMP_ORDERED:
stmt = push_stmt_list ();
RECUR (OMP_BODY (t));
@@ -13532,7 +13663,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
{
@@ -13560,6 +13692,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
{
@@ -13567,7 +13701,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;
@@ -13639,6 +13774,73 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
#undef RETURN
}
+/* Instantiate the special body of the artificial DECL_OMP_DECLARE_REDUCTION
+ function. For description of the body see comment above
+ cp_parser_omp_declare_reduction_exprs. */
+
+static void
+tsubst_omp_udr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+{
+ if (t == NULL_TREE || t == error_mark_node)
+ return;
+
+ gcc_assert (TREE_CODE (t) == STATEMENT_LIST);
+
+ tree_stmt_iterator tsi;
+ int i;
+ tree stmts[7];
+ memset (stmts, 0, sizeof stmts);
+ for (i = 0, tsi = tsi_start (t);
+ i < 7 && !tsi_end_p (tsi);
+ i++, tsi_next (&tsi))
+ stmts[i] = tsi_stmt (tsi);
+ gcc_assert (tsi_end_p (tsi));
+
+ if (i >= 3)
+ {
+ gcc_assert (TREE_CODE (stmts[0]) == DECL_EXPR
+ && TREE_CODE (stmts[1]) == DECL_EXPR);
+ tree omp_out = tsubst (DECL_EXPR_DECL (stmts[0]),
+ args, complain, in_decl);
+ tree omp_in = tsubst (DECL_EXPR_DECL (stmts[1]),
+ args, complain, in_decl);
+ DECL_CONTEXT (omp_out) = current_function_decl;
+ DECL_CONTEXT (omp_in) = current_function_decl;
+ keep_next_level (true);
+ tree block = begin_omp_structured_block ();
+ tsubst_expr (stmts[2], args, complain, in_decl, false);
+ block = finish_omp_structured_block (block);
+ block = maybe_cleanup_point_expr_void (block);
+ add_decl_expr (omp_out);
+ if (TREE_NO_WARNING (DECL_EXPR_DECL (stmts[0])))
+ TREE_NO_WARNING (omp_out) = 1;
+ add_decl_expr (omp_in);
+ finish_expr_stmt (block);
+ }
+ if (i >= 6)
+ {
+ gcc_assert (TREE_CODE (stmts[3]) == DECL_EXPR
+ && TREE_CODE (stmts[4]) == DECL_EXPR);
+ tree omp_priv = tsubst (DECL_EXPR_DECL (stmts[3]),
+ args, complain, in_decl);
+ tree omp_orig = tsubst (DECL_EXPR_DECL (stmts[4]),
+ args, complain, in_decl);
+ DECL_CONTEXT (omp_priv) = current_function_decl;
+ DECL_CONTEXT (omp_orig) = current_function_decl;
+ keep_next_level (true);
+ tree block = begin_omp_structured_block ();
+ tsubst_expr (stmts[5], args, complain, in_decl, false);
+ block = finish_omp_structured_block (block);
+ block = maybe_cleanup_point_expr_void (block);
+ cp_walk_tree (&block, cp_remove_omp_priv_cleanup_stmt, omp_priv, NULL);
+ add_decl_expr (omp_priv);
+ add_decl_expr (omp_orig);
+ finish_expr_stmt (block);
+ if (i == 7)
+ add_decl_expr (omp_orig);
+ }
+}
+
/* T is a postfix-expression that is not being used in a function
call. Return the substituted version of T. */
@@ -19340,6 +19542,7 @@ instantiate_decl (tree d, int defer_ok,
tree subst_decl;
tree tmpl_parm;
tree spec_parm;
+ tree block = NULL_TREE;
/* Save away the current list, in case we are instantiating one
template from within the body of another. */
@@ -19349,7 +19552,11 @@ instantiate_decl (tree d, int defer_ok,
local_specializations = pointer_map_create ();
/* Set up context. */
- start_preparsed_function (d, NULL_TREE, SF_PRE_PARSED);
+ if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern)
+ && TREE_CODE (DECL_CONTEXT (code_pattern)) == FUNCTION_DECL)
+ block = push_stmt_list ();
+ else
+ start_preparsed_function (d, NULL_TREE, SF_PRE_PARSED);
/* Some typedefs referenced from within the template code need to be
access checked at template instantiation time, i.e now. These
@@ -19386,21 +19593,37 @@ instantiate_decl (tree d, int defer_ok,
gcc_assert (!spec_parm);
/* Substitute into the body of the function. */
- tsubst_expr (DECL_SAVED_TREE (code_pattern), args,
- tf_warning_or_error, tmpl,
- /*integral_constant_expression_p=*/false);
-
- /* Set the current input_location to the end of the function
- so that finish_function knows where we are. */
- input_location = DECL_STRUCT_FUNCTION (code_pattern)->function_end_locus;
+ if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern))
+ tsubst_omp_udr (DECL_SAVED_TREE (code_pattern), args,
+ tf_warning_or_error, tmpl);
+ else
+ {
+ tsubst_expr (DECL_SAVED_TREE (code_pattern), args,
+ tf_warning_or_error, tmpl,
+ /*integral_constant_expression_p=*/false);
+
+ /* Set the current input_location to the end of the function
+ so that finish_function knows where we are. */
+ input_location
+ = DECL_STRUCT_FUNCTION (code_pattern)->function_end_locus;
+ }
/* We don't need the local specializations any more. */
pointer_map_destroy (local_specializations);
local_specializations = saved_local_specializations;
/* Finish the function. */
- d = finish_function (0);
- expand_or_defer_fn (d);
+ if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern)
+ && TREE_CODE (DECL_CONTEXT (code_pattern)) == FUNCTION_DECL)
+ DECL_SAVED_TREE (d) = pop_stmt_list (block);
+ else
+ {
+ d = finish_function (0);
+ expand_or_defer_fn (d);
+ }
+
+ if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern))
+ cp_check_omp_declare_reduction (d);
}
/* We're not deferring instantiation any more. */
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index aa0490e2765..9bfd263776e 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -4047,7 +4047,8 @@ finalize_nrv (tree *tp, tree var, tree result)
bool
cxx_omp_create_clause_info (tree c, tree type, bool need_default_ctor,
- bool need_copy_ctor, bool need_copy_assignment)
+ bool need_copy_ctor, bool need_copy_assignment,
+ bool need_dtor)
{
int save_errorcount = errorcount;
tree info, t;
@@ -4071,8 +4072,7 @@ cxx_omp_create_clause_info (tree c, tree type, bool need_default_ctor,
TREE_VEC_ELT (info, 0) = t;
}
- if ((need_default_ctor || need_copy_ctor)
- && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
+ if (need_dtor && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
TREE_VEC_ELT (info, 1) = get_dtor (type, tf_warning_or_error);
if (need_copy_assignment)
@@ -4086,6 +4086,1037 @@ 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<tree> &types,
+ bool &maybe_zero_len, unsigned int &first_non_one)
+{
+ 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);
+ return t;
+ }
+
+ ret = handle_omp_array_sections_1 (c, TREE_CHAIN (t), types,
+ maybe_zero_len, first_non_one);
+ 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 must "
+ "be specified");
+ 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 must be specified");
+ 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));
+ /* We will need to evaluate lb more than once. */
+ 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;
+ unsigned int first_non_one = 0;
+ vec<tree> types = vNULL;
+ tree first = handle_omp_array_sections_1 (c, OMP_CLAUSE_DECL (c), types,
+ maybe_zero_len, first_non_one);
+ 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 (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP)
+ return false;
+ 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),
+ ptrdiff_type_node, t);
+ tree ptr = OMP_CLAUSE_DECL (c2);
+ ptr = convert_from_reference (ptr);
+ if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
+ ptr = build_fold_addr_expr (ptr);
+ t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR,
+ ptrdiff_type_node, t,
+ fold_convert_loc (OMP_CLAUSE_LOCATION (c),
+ ptrdiff_type_node, ptr));
+ OMP_CLAUSE_SIZE (c2) = t;
+ OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c);
+ OMP_CLAUSE_CHAIN (c) = c2;
+ ptr = OMP_CLAUSE_DECL (c2);
+ if (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE
+ && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (ptr))))
+ {
+ tree c3 = build_omp_clause (OMP_CLAUSE_LOCATION (c),
+ OMP_CLAUSE_MAP);
+ OMP_CLAUSE_MAP_KIND (c3) = OMP_CLAUSE_MAP_POINTER;
+ OMP_CLAUSE_DECL (c3) = ptr;
+ OMP_CLAUSE_DECL (c2) = convert_from_reference (ptr);
+ OMP_CLAUSE_SIZE (c3) = size_zero_node;
+ OMP_CLAUSE_CHAIN (c3) = OMP_CLAUSE_CHAIN (c2);
+ OMP_CLAUSE_CHAIN (c2) = c3;
+ }
+ }
+ }
+ return false;
+}
+
+/* Return identifier to look up for omp declare reduction. */
+
+tree
+omp_reduction_id (enum tree_code reduction_code, tree reduction_id, tree type)
+{
+ const char *p = NULL;
+ const char *m = NULL;
+ switch (reduction_code)
+ {
+ case PLUS_EXPR:
+ case MULT_EXPR:
+ case MINUS_EXPR:
+ case BIT_AND_EXPR:
+ case BIT_XOR_EXPR:
+ case BIT_IOR_EXPR:
+ case TRUTH_ANDIF_EXPR:
+ case TRUTH_ORIF_EXPR:
+ reduction_id = ansi_opname (reduction_code);
+ break;
+ case MIN_EXPR:
+ p = "min";
+ break;
+ case MAX_EXPR:
+ p = "max";
+ break;
+ default:
+ break;
+ }
+
+ if (p == NULL)
+ {
+ if (TREE_CODE (reduction_id) != IDENTIFIER_NODE)
+ return error_mark_node;
+ p = IDENTIFIER_POINTER (reduction_id);
+ }
+
+ if (type != NULL_TREE)
+ m = mangle_type_string (TYPE_MAIN_VARIANT (type));
+
+ const char prefix[] = "omp declare reduction ";
+ size_t lenp = sizeof (prefix);
+ if (strncmp (p, prefix, lenp - 1) == 0)
+ lenp = 1;
+ size_t len = strlen (p);
+ size_t lenm = m ? strlen (m) + 1 : 0;
+ char *name = XALLOCAVEC (char, lenp + len + lenm);
+ if (lenp > 1)
+ memcpy (name, prefix, lenp - 1);
+ memcpy (name + lenp - 1, p, len + 1);
+ if (m)
+ {
+ name[lenp + len - 1] = '~';
+ memcpy (name + lenp + len, m, lenm);
+ }
+ return get_identifier (name);
+}
+
+/* Lookup OpenMP UDR ID for TYPE, return the corresponding artificial
+ FUNCTION_DECL or NULL_TREE if not found. */
+
+static tree
+omp_reduction_lookup (location_t loc, tree id, tree type, tree *baselinkp,
+ vec<tree> *ambiguousp)
+{
+ tree orig_id = id;
+ tree baselink = NULL_TREE;
+ if (identifier_p (id))
+ {
+ cp_id_kind idk;
+ bool nonint_cst_expression_p;
+ const char *error_msg;
+ id = omp_reduction_id (ERROR_MARK, id, type);
+ tree decl = lookup_name (id);
+ if (decl == NULL_TREE)
+ decl = error_mark_node;
+ id = finish_id_expression (id, decl, NULL_TREE, &idk, false, true,
+ &nonint_cst_expression_p, false, true, false,
+ false, &error_msg, loc);
+ if (idk == CP_ID_KIND_UNQUALIFIED
+ && identifier_p (id))
+ {
+ vec<tree, va_gc> *args = NULL;
+ vec_safe_push (args, build_reference_type (type));
+ id = perform_koenig_lookup (id, args, false, tf_none);
+ }
+ }
+ else if (TREE_CODE (id) == SCOPE_REF)
+ id = lookup_qualified_name (TREE_OPERAND (id, 0),
+ omp_reduction_id (ERROR_MARK,
+ TREE_OPERAND (id, 1),
+ type),
+ false, false);
+ tree fns = id;
+ if (id && is_overloaded_fn (id))
+ id = get_fns (id);
+ for (; id; id = OVL_NEXT (id))
+ {
+ tree fndecl = OVL_CURRENT (id);
+ if (TREE_CODE (fndecl) == FUNCTION_DECL)
+ {
+ tree argtype = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (fndecl)));
+ if (same_type_p (TREE_TYPE (argtype), type))
+ break;
+ }
+ }
+ if (id && BASELINK_P (fns))
+ {
+ if (baselinkp)
+ *baselinkp = fns;
+ else
+ baselink = fns;
+ }
+ if (id == NULL_TREE && CLASS_TYPE_P (type) && TYPE_BINFO (type))
+ {
+ vec<tree> ambiguous = vNULL;
+ tree binfo = TYPE_BINFO (type), base_binfo, ret = NULL_TREE;
+ unsigned int ix;
+ if (ambiguousp == NULL)
+ ambiguousp = &ambiguous;
+ for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++)
+ {
+ id = omp_reduction_lookup (loc, orig_id, BINFO_TYPE (base_binfo),
+ baselinkp ? baselinkp : &baselink,
+ ambiguousp);
+ if (id == NULL_TREE)
+ continue;
+ if (!ambiguousp->is_empty ())
+ ambiguousp->safe_push (id);
+ else if (ret != NULL_TREE)
+ {
+ ambiguousp->safe_push (ret);
+ ambiguousp->safe_push (id);
+ ret = NULL_TREE;
+ }
+ else
+ ret = id;
+ }
+ if (ambiguousp != &ambiguous)
+ return ret;
+ if (!ambiguous.is_empty ())
+ {
+ const char *str = _("candidates are:");
+ unsigned int idx;
+ tree udr;
+ error_at (loc, "user defined reduction lookup is ambiguous");
+ FOR_EACH_VEC_ELT (ambiguous, idx, udr)
+ {
+ inform (DECL_SOURCE_LOCATION (udr), "%s %#D", str, udr);
+ if (idx == 0)
+ str = get_spaces (str);
+ }
+ ambiguous.release ();
+ ret = error_mark_node;
+ baselink = NULL_TREE;
+ }
+ id = ret;
+ }
+ if (id && baselink)
+ perform_or_defer_access_check (BASELINK_BINFO (baselink),
+ id, id, tf_warning_or_error);
+ return id;
+}
+
+/* Helper function for cp_parser_omp_declare_reduction_exprs
+ and tsubst_omp_udr.
+ Remove CLEANUP_STMT for data (omp_priv variable).
+ Also append INIT_EXPR for DECL_INITIAL of omp_priv after its
+ DECL_EXPR. */
+
+tree
+cp_remove_omp_priv_cleanup_stmt (tree *tp, int *walk_subtrees, void *data)
+{
+ if (TYPE_P (*tp))
+ *walk_subtrees = 0;
+ else if (TREE_CODE (*tp) == CLEANUP_STMT && CLEANUP_DECL (*tp) == (tree) data)
+ *tp = CLEANUP_BODY (*tp);
+ else if (TREE_CODE (*tp) == DECL_EXPR)
+ {
+ tree decl = DECL_EXPR_DECL (*tp);
+ if (!processing_template_decl
+ && decl == (tree) data
+ && DECL_INITIAL (decl)
+ && DECL_INITIAL (decl) != error_mark_node)
+ {
+ tree list = NULL_TREE;
+ append_to_statement_list_force (*tp, &list);
+ tree init_expr = build2 (INIT_EXPR, void_type_node,
+ decl, DECL_INITIAL (decl));
+ DECL_INITIAL (decl) = NULL_TREE;
+ append_to_statement_list_force (init_expr, &list);
+ *tp = list;
+ }
+ }
+ return NULL_TREE;
+}
+
+/* Data passed from cp_check_omp_declare_reduction to
+ cp_check_omp_declare_reduction_r. */
+
+struct cp_check_omp_declare_reduction_data
+{
+ location_t loc;
+ tree stmts[7];
+ bool combiner_p;
+};
+
+/* Helper function for cp_check_omp_declare_reduction, called via
+ cp_walk_tree. */
+
+static tree
+cp_check_omp_declare_reduction_r (tree *tp, int *, void *data)
+{
+ struct cp_check_omp_declare_reduction_data *udr_data
+ = (struct cp_check_omp_declare_reduction_data *) data;
+ if (SSA_VAR_P (*tp)
+ && !DECL_ARTIFICIAL (*tp)
+ && *tp != DECL_EXPR_DECL (udr_data->stmts[udr_data->combiner_p ? 0 : 3])
+ && *tp != DECL_EXPR_DECL (udr_data->stmts[udr_data->combiner_p ? 1 : 4]))
+ {
+ location_t loc = udr_data->loc;
+ if (udr_data->combiner_p)
+ error_at (loc, "%<#pragma omp declare reduction%> combiner refers to "
+ "variable %qD which is not %<omp_out%> nor %<omp_in%>",
+ *tp);
+ else
+ error_at (loc, "%<#pragma omp declare reduction%> initializer refers "
+ "to variable %qD which is not %<omp_priv%> nor "
+ "%<omp_orig%>",
+ *tp);
+ return *tp;
+ }
+ return NULL_TREE;
+}
+
+/* Diagnose violation of OpenMP #pragma omp declare reduction restrictions. */
+
+void
+cp_check_omp_declare_reduction (tree udr)
+{
+ tree type = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (udr)));
+ gcc_assert (TREE_CODE (type) == REFERENCE_TYPE);
+ type = TREE_TYPE (type);
+ int i;
+ location_t loc = DECL_SOURCE_LOCATION (udr);
+
+ if (type == error_mark_node)
+ return;
+ if (ARITHMETIC_TYPE_P (type))
+ {
+ static enum tree_code predef_codes[]
+ = { PLUS_EXPR, MULT_EXPR, MINUS_EXPR, BIT_AND_EXPR, BIT_XOR_EXPR,
+ BIT_IOR_EXPR, TRUTH_ANDIF_EXPR, TRUTH_ORIF_EXPR };
+ for (i = 0; i < 8; i++)
+ {
+ tree id = omp_reduction_id (predef_codes[i], NULL_TREE, NULL_TREE);
+ const char *n1 = IDENTIFIER_POINTER (DECL_NAME (udr));
+ const char *n2 = IDENTIFIER_POINTER (id);
+ if (strncmp (n1, n2, IDENTIFIER_LENGTH (id)) == 0
+ && (n1[IDENTIFIER_LENGTH (id)] == '~'
+ || n1[IDENTIFIER_LENGTH (id)] == '\0'))
+ break;
+ }
+
+ if (i == 8
+ && TREE_CODE (type) != COMPLEX_EXPR)
+ {
+ const char prefix_minmax[] = "omp declare reduction m";
+ size_t prefix_size = sizeof (prefix_minmax) - 1;
+ const char *n = IDENTIFIER_POINTER (DECL_NAME (udr));
+ if (strncmp (IDENTIFIER_POINTER (DECL_NAME (udr)),
+ prefix_minmax, prefix_size) == 0
+ && ((n[prefix_size] == 'i' && n[prefix_size + 1] == 'n')
+ || (n[prefix_size] == 'a' && n[prefix_size + 1] == 'x'))
+ && (n[prefix_size + 2] == '~' || n[prefix_size + 2] == '\0'))
+ i = 0;
+ }
+ if (i < 8)
+ {
+ error_at (loc, "predeclared arithmetic type %qT in "
+ "%<#pragma omp declare reduction%>", type);
+ return;
+ }
+ }
+ else if (TREE_CODE (type) == FUNCTION_TYPE
+ || TREE_CODE (type) == METHOD_TYPE
+ || TREE_CODE (type) == ARRAY_TYPE)
+ {
+ error_at (loc, "function or array type %qT in "
+ "%<#pragma omp declare reduction%>", type);
+ return;
+ }
+ else if (TREE_CODE (type) == REFERENCE_TYPE)
+ {
+ error_at (loc, "reference type %qT in %<#pragma omp declare reduction%>",
+ type);
+ return;
+ }
+ else if (TYPE_QUALS_NO_ADDR_SPACE (type))
+ {
+ error_at (loc, "const, volatile or __restrict qualified type %qT in "
+ "%<#pragma omp declare reduction%>", type);
+ return;
+ }
+
+ tree body = DECL_SAVED_TREE (udr);
+ if (body == NULL_TREE || TREE_CODE (body) != STATEMENT_LIST)
+ return;
+
+ tree_stmt_iterator tsi;
+ struct cp_check_omp_declare_reduction_data data;
+ memset (data.stmts, 0, sizeof data.stmts);
+ for (i = 0, tsi = tsi_start (body);
+ i < 7 && !tsi_end_p (tsi);
+ i++, tsi_next (&tsi))
+ data.stmts[i] = tsi_stmt (tsi);
+ data.loc = loc;
+ gcc_assert (tsi_end_p (tsi));
+ if (i >= 3)
+ {
+ gcc_assert (TREE_CODE (data.stmts[0]) == DECL_EXPR
+ && TREE_CODE (data.stmts[1]) == DECL_EXPR);
+ if (TREE_NO_WARNING (DECL_EXPR_DECL (data.stmts[0])))
+ return;
+ data.combiner_p = true;
+ if (cp_walk_tree (&data.stmts[2], cp_check_omp_declare_reduction_r,
+ &data, NULL))
+ TREE_NO_WARNING (DECL_EXPR_DECL (data.stmts[0])) = 1;
+ }
+ if (i >= 6)
+ {
+ gcc_assert (TREE_CODE (data.stmts[3]) == DECL_EXPR
+ && TREE_CODE (data.stmts[4]) == DECL_EXPR);
+ data.combiner_p = false;
+ if (cp_walk_tree (&data.stmts[5], cp_check_omp_declare_reduction_r,
+ &data, NULL)
+ || cp_walk_tree (&DECL_INITIAL (DECL_EXPR_DECL (data.stmts[3])),
+ cp_check_omp_declare_reduction_r, &data, NULL))
+ TREE_NO_WARNING (DECL_EXPR_DECL (data.stmts[0])) = 1;
+ if (i == 7)
+ gcc_assert (TREE_CODE (data.stmts[6]) == DECL_EXPR);
+ }
+}
+
+/* Helper function of finish_omp_clauses. Clone STMT as if we were making
+ an inline call. But, remap
+ the OMP_DECL1 VAR_DECL (omp_out resp. omp_orig) to PLACEHOLDER
+ and OMP_DECL2 VAR_DECL (omp_in resp. omp_priv) to DECL. */
+
+static tree
+clone_omp_udr (tree stmt, tree omp_decl1, tree omp_decl2,
+ tree decl, tree placeholder)
+{
+ copy_body_data id;
+ struct pointer_map_t *decl_map = pointer_map_create ();
+
+ *pointer_map_insert (decl_map, omp_decl1) = placeholder;
+ *pointer_map_insert (decl_map, omp_decl2) = decl;
+ memset (&id, 0, sizeof (id));
+ id.src_fn = DECL_CONTEXT (omp_decl1);
+ id.dst_fn = current_function_decl;
+ id.src_cfun = DECL_STRUCT_FUNCTION (id.src_fn);
+ id.decl_map = decl_map;
+
+ id.copy_decl = copy_decl_no_change;
+ id.transform_call_graph_edges = CB_CGE_DUPLICATE;
+ id.transform_new_cfg = true;
+ id.transform_return_to_modify = false;
+ id.transform_lang_insert_block = NULL;
+ id.eh_lp_nr = 0;
+ walk_tree (&stmt, copy_tree_body_r, &id, NULL);
+ pointer_map_destroy (decl_map);
+ return stmt;
+}
+
+/* Helper function of finish_omp_clauses, called via cp_walk_tree.
+ Find OMP_CLAUSE_PLACEHOLDER (passed in DATA) in *TP. */
+
+static tree
+find_omp_placeholder_r (tree *tp, int *, void *data)
+{
+ if (*tp == (tree) data)
+ return *tp;
+ return NULL_TREE;
+}
+
+/* Helper function of finish_omp_clauses. Handle OMP_CLAUSE_REDUCTION C.
+ Return true if there is some error and the clause should be removed. */
+
+static bool
+finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor)
+{
+ tree t = OMP_CLAUSE_DECL (c);
+ bool predefined = false;
+ tree type = TREE_TYPE (t);
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ type = TREE_TYPE (type);
+ if (ARITHMETIC_TYPE_P (type))
+ switch (OMP_CLAUSE_REDUCTION_CODE (c))
+ {
+ case PLUS_EXPR:
+ case MULT_EXPR:
+ case MINUS_EXPR:
+ predefined = true;
+ break;
+ case MIN_EXPR:
+ case MAX_EXPR:
+ if (TREE_CODE (type) == COMPLEX_TYPE)
+ break;
+ predefined = true;
+ break;
+ case BIT_AND_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ case TRUTH_ANDIF_EXPR:
+ case TRUTH_ORIF_EXPR:
+ if (FLOAT_TYPE_P (type))
+ break;
+ predefined = true;
+ break;
+ default:
+ break;
+ }
+ else if (TREE_CODE (type) == ARRAY_TYPE || TYPE_READONLY (type))
+ {
+ error ("%qE has invalid type for %<reduction%>", t);
+ return true;
+ }
+ else if (!processing_template_decl)
+ {
+ t = require_complete_type (t);
+ if (t == error_mark_node)
+ return true;
+ OMP_CLAUSE_DECL (c) = t;
+ }
+
+ if (predefined)
+ {
+ OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = NULL_TREE;
+ return false;
+ }
+ else if (processing_template_decl)
+ return false;
+
+ tree id = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c);
+
+ type = TYPE_MAIN_VARIANT (TREE_TYPE (t));
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ type = TREE_TYPE (type);
+ OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = NULL_TREE;
+ if (id == NULL_TREE)
+ id = omp_reduction_id (OMP_CLAUSE_REDUCTION_CODE (c),
+ NULL_TREE, NULL_TREE);
+ id = omp_reduction_lookup (OMP_CLAUSE_LOCATION (c), id, type, NULL, NULL);
+ if (id)
+ {
+ if (id == error_mark_node)
+ return true;
+ id = OVL_CURRENT (id);
+ mark_used (id);
+ tree body = DECL_SAVED_TREE (id);
+ if (TREE_CODE (body) == STATEMENT_LIST)
+ {
+ tree_stmt_iterator tsi;
+ tree placeholder = NULL_TREE;
+ int i;
+ tree stmts[7];
+ tree atype = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (id)));
+ atype = TREE_TYPE (atype);
+ bool need_static_cast = !same_type_p (type, atype);
+ memset (stmts, 0, sizeof stmts);
+ for (i = 0, tsi = tsi_start (body);
+ i < 7 && !tsi_end_p (tsi);
+ i++, tsi_next (&tsi))
+ stmts[i] = tsi_stmt (tsi);
+ gcc_assert (tsi_end_p (tsi));
+
+ if (i >= 3)
+ {
+ gcc_assert (TREE_CODE (stmts[0]) == DECL_EXPR
+ && TREE_CODE (stmts[1]) == DECL_EXPR);
+ placeholder = build_lang_decl (VAR_DECL, NULL_TREE, type);
+ DECL_ARTIFICIAL (placeholder) = 1;
+ DECL_IGNORED_P (placeholder) = 1;
+ OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = placeholder;
+ if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[0])))
+ cxx_mark_addressable (placeholder);
+ if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[1]))
+ && TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c)))
+ != REFERENCE_TYPE)
+ cxx_mark_addressable (OMP_CLAUSE_DECL (c));
+ tree omp_out = placeholder;
+ tree omp_in = convert_from_reference (OMP_CLAUSE_DECL (c));
+ if (need_static_cast)
+ {
+ tree rtype = build_reference_type (atype);
+ omp_out = build_static_cast (rtype, omp_out,
+ tf_warning_or_error);
+ omp_in = build_static_cast (rtype, omp_in,
+ tf_warning_or_error);
+ if (omp_out == error_mark_node || omp_in == error_mark_node)
+ return true;
+ omp_out = convert_from_reference (omp_out);
+ omp_in = convert_from_reference (omp_in);
+ }
+ OMP_CLAUSE_REDUCTION_MERGE (c)
+ = clone_omp_udr (stmts[2], DECL_EXPR_DECL (stmts[0]),
+ DECL_EXPR_DECL (stmts[1]), omp_in, omp_out);
+ }
+ if (i >= 6)
+ {
+ gcc_assert (TREE_CODE (stmts[3]) == DECL_EXPR
+ && TREE_CODE (stmts[4]) == DECL_EXPR);
+ if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[3])))
+ cxx_mark_addressable (OMP_CLAUSE_DECL (c));
+ if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[4])))
+ cxx_mark_addressable (placeholder);
+ tree omp_priv = convert_from_reference (OMP_CLAUSE_DECL (c));
+ tree omp_orig = placeholder;
+ if (need_static_cast)
+ {
+ if (i == 7)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "user defined reduction with constructor "
+ "initializer for base class %qT", atype);
+ return true;
+ }
+ tree rtype = build_reference_type (atype);
+ omp_priv = build_static_cast (rtype, omp_priv,
+ tf_warning_or_error);
+ omp_orig = build_static_cast (rtype, omp_orig,
+ tf_warning_or_error);
+ if (omp_priv == error_mark_node
+ || omp_orig == error_mark_node)
+ return true;
+ omp_priv = convert_from_reference (omp_priv);
+ omp_orig = convert_from_reference (omp_orig);
+ }
+ if (i == 6)
+ *need_default_ctor = true;
+ OMP_CLAUSE_REDUCTION_INIT (c)
+ = clone_omp_udr (stmts[5], DECL_EXPR_DECL (stmts[4]),
+ DECL_EXPR_DECL (stmts[3]),
+ omp_priv, omp_orig);
+ if (cp_walk_tree (&OMP_CLAUSE_REDUCTION_INIT (c),
+ find_omp_placeholder_r, placeholder, NULL))
+ OMP_CLAUSE_REDUCTION_OMP_ORIG_REF (c) = 1;
+ }
+ else if (i >= 3)
+ {
+ if (CLASS_TYPE_P (type) && !pod_type_p (type))
+ *need_default_ctor = true;
+ else
+ {
+ tree init;
+ tree v = convert_from_reference (t);
+ if (AGGREGATE_TYPE_P (TREE_TYPE (v)))
+ init = build_constructor (TREE_TYPE (v), NULL);
+ else
+ init = fold_convert (TREE_TYPE (v), integer_zero_node);
+ OMP_CLAUSE_REDUCTION_INIT (c)
+ = build2 (INIT_EXPR, TREE_TYPE (v), v, init);
+ }
+ }
+ }
+ }
+ if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
+ *need_dtor = true;
+ else
+ {
+ error ("user defined reduction not found for %qD", t);
+ return true;
+ }
+ return false;
+}
+
/* For all elements of CLAUSES, validate them vs OpenMP constraints.
Remove any elements from the list that are invalid. */
@@ -4093,13 +5124,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;
+ bool copyprivate_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)
{
@@ -4108,19 +5142,58 @@ finish_omp_clauses (tree clauses)
switch (OMP_CLAUSE_CODE (c))
{
case OMP_CLAUSE_SHARED:
- name = "shared";
goto check_dup_generic;
case OMP_CLAUSE_PRIVATE:
- name = "private";
goto check_dup_generic;
case OMP_CLAUSE_REDUCTION:
- name = "reduction";
goto check_dup_generic;
case OMP_CLAUSE_COPYPRIVATE:
- name = "copyprivate";
+ copyprivate_seen = true;
goto check_dup_generic;
case OMP_CLAUSE_COPYIN:
- name = "copyin";
+ goto check_dup_generic;
+ case OMP_CLAUSE_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 "
+ "variable with %qT type", TREE_TYPE (t));
+ 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);
@@ -4129,9 +5202,11 @@ finish_omp_clauses (tree clauses)
if (processing_template_decl)
break;
if (DECL_P (t))
- error ("%qD is not a variable in clause %qs", t, name);
+ error ("%qD is not a variable in clause %qs", t,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
else
- error ("%qE is not a variable in clause %qs", t, name);
+ error ("%qE is not a variable in clause %qs", t,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
remove = true;
}
else if (bitmap_bit_p (&generic_head, DECL_UID (t))
@@ -4249,12 +5324,299 @@ 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 ("%<num_teams%> 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 ("%<thread_limit%> 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 ("%<device%> 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 ("%<dist_schedule%> 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 %<aligned%> clause", t);
+ else
+ error ("%qE is not a variable in %<aligned%> clause", t);
+ remove = true;
+ }
+ else if (bitmap_bit_p (&aligned_head, DECL_UID (t)))
+ {
+ error ("%qD appears more than once in %<aligned%> 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 ("%<aligned%> 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 ("%<aligned%> 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 %<depend%> clause", t);
+ else
+ error ("%qE is not a variable in %<depend%> 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 (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+ && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER)
+ 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 (!(OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+ && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER)
+ && !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 (bitmap_bit_p (&generic_head, DECL_UID (t)))
+ {
+ if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP)
+ error ("%qD appears more than once in motion clauses", t);
+ else
+ error ("%qD appears more than once in map clauses", t);
+ remove = true;
+ }
+ else
+ bitmap_set_bit (&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 %<uniform%> clause", t);
+ else
+ error ("%qE is not an argument in %<uniform%> 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 ("%<inbranch%> clause is incompatible with "
+ "%<notinbranch%>");
+ remove = true;
+ }
+ branch_seen = true;
break;
default:
@@ -4276,44 +5638,50 @@ finish_omp_clauses (tree clauses)
bool need_copy_ctor = false;
bool need_copy_assignment = false;
bool need_implicitly_determined = false;
+ bool need_dtor = false;
tree type, inner_type;
switch (c_kind)
{
case OMP_CLAUSE_SHARED:
- name = "shared";
need_implicitly_determined = true;
break;
case OMP_CLAUSE_PRIVATE:
- name = "private";
need_complete_non_reference = true;
need_default_ctor = true;
+ need_dtor = true;
need_implicitly_determined = true;
break;
case OMP_CLAUSE_FIRSTPRIVATE:
- name = "firstprivate";
need_complete_non_reference = true;
need_copy_ctor = true;
+ need_dtor = true;
need_implicitly_determined = true;
break;
case OMP_CLAUSE_LASTPRIVATE:
- name = "lastprivate";
need_complete_non_reference = true;
need_copy_assignment = true;
need_implicitly_determined = true;
break;
case OMP_CLAUSE_REDUCTION:
- name = "reduction";
need_implicitly_determined = true;
break;
case OMP_CLAUSE_COPYPRIVATE:
- name = "copyprivate";
need_copy_assignment = true;
break;
case OMP_CLAUSE_COPYIN:
- name = "copyin";
need_copy_assignment = true;
break;
+ case OMP_CLAUSE_NOWAIT:
+ if (copyprivate_seen)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%<nowait%> clause must not be used together "
+ "with %<copyprivate%>");
+ *pc = OMP_CLAUSE_CHAIN (c);
+ continue;
+ }
+ /* FALLTHRU */
default:
pc = &OMP_CLAUSE_CHAIN (c);
continue;
@@ -4331,33 +5699,18 @@ finish_omp_clauses (tree clauses)
{
case OMP_CLAUSE_LASTPRIVATE:
if (!bitmap_bit_p (&firstprivate_head, DECL_UID (t)))
- need_default_ctor = true;
+ {
+ need_default_ctor = true;
+ need_dtor = true;
+ }
break;
case OMP_CLAUSE_REDUCTION:
- if (AGGREGATE_TYPE_P (TREE_TYPE (t))
- || POINTER_TYPE_P (TREE_TYPE (t)))
- {
- error ("%qE has invalid type for %<reduction%>", t);
- remove = true;
- }
- else if (FLOAT_TYPE_P (TREE_TYPE (t)))
- {
- enum tree_code r_code = OMP_CLAUSE_REDUCTION_CODE (c);
- switch (r_code)
- {
- case PLUS_EXPR:
- case MULT_EXPR:
- case MINUS_EXPR:
- case MIN_EXPR:
- case MAX_EXPR:
- break;
- default:
- error ("%qE has invalid type for %<reduction(%s)%>",
- t, operator_name_info[r_code].name);
- remove = true;
- }
- }
+ if (finish_omp_reduction_clause (c, &need_default_ctor,
+ &need_dtor))
+ remove = true;
+ else
+ t = OMP_CLAUSE_DECL (c);
break;
case OMP_CLAUSE_COPYIN:
@@ -4380,7 +5733,8 @@ finish_omp_clauses (tree clauses)
else if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE
&& need_complete_non_reference)
{
- error ("%qE has reference type for %qs", t, name);
+ error ("%qE has reference type for %qs", t,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
remove = true;
}
}
@@ -4410,7 +5764,7 @@ finish_omp_clauses (tree clauses)
if (share_name)
{
error ("%qE is predetermined %qs for %qs",
- t, share_name, name);
+ t, share_name, omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
remove = true;
}
}
@@ -4420,15 +5774,21 @@ finish_omp_clauses (tree clauses)
while (TREE_CODE (inner_type) == ARRAY_TYPE)
inner_type = TREE_TYPE (inner_type);
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
+ && TREE_CODE (inner_type) == REFERENCE_TYPE)
+ inner_type = TREE_TYPE (inner_type);
+
/* Check for special function availability by building a call to one.
Save the results, because later we won't be in the right context
for making these queries. */
if (CLASS_TYPE_P (inner_type)
&& COMPLETE_TYPE_P (inner_type)
- && (need_default_ctor || need_copy_ctor || need_copy_assignment)
+ && (need_default_ctor || need_copy_ctor
+ || need_copy_assignment || need_dtor)
&& !type_dependent_expression_p (t)
&& cxx_omp_create_clause_info (c, inner_type, need_default_ctor,
- need_copy_ctor, need_copy_assignment))
+ need_copy_ctor, need_copy_assignment,
+ need_dtor))
remove = true;
if (remove)
@@ -4809,8 +6169,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;
@@ -4879,7 +6239,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++)
{
@@ -4937,6 +6297,12 @@ finish_omp_for (location_t locus, tree declv, tree initv, tree condv,
if (CLASS_TYPE_P (TREE_TYPE (decl)))
{
+ if (code == OMP_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;
@@ -4991,7 +6357,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)
@@ -5036,7 +6402,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;
@@ -5078,8 +6444,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;
}
@@ -5089,6 +6483,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
@@ -5104,10 +6499,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);
}
@@ -5151,6 +6548,69 @@ finish_omp_taskyield (void)
release_tree_vector (vec);
finish_expr_stmt (stmt);
}
+
+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 "
+ "%<parallel%>, %<for%>, %<sections%> or %<taskgroup%> clauses");
+ return;
+ }
+ vec<tree, va_gc> *vec = make_tree_vector ();
+ tree ifc = find_omp_clause (clauses, OMP_CLAUSE_IF);
+ if (ifc != NULL_TREE)
+ {
+ tree type = TREE_TYPE (OMP_CLAUSE_IF_EXPR (ifc));
+ ifc = fold_build2_loc (OMP_CLAUSE_LOCATION (ifc), NE_EXPR,
+ boolean_type_node, OMP_CLAUSE_IF_EXPR (ifc),
+ build_zero_cst (type));
+ }
+ else
+ ifc = boolean_true_node;
+ vec->quick_push (build_int_cst (integer_type_node, mask));
+ vec->quick_push (ifc);
+ tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error);
+ release_tree_vector (vec);
+ 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 "
+ "%<parallel%>, %<for%>, %<sections%> or %<taskgroup%> clauses");
+ return;
+ }
+ vec<tree, va_gc> *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);
+}
/* 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 b/gcc/fortran/ChangeLog
index 2a3be8d64f2..583baa64309 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,21 @@
+2013-10-11 Jakub Jelinek <jakub@redhat.com>
+
+ * trans-openmp.c (gfc_omp_clause_default_ctor,
+ gfc_omp_clause_dtor): Return NULL for OMP_CLAUSE_REDUCTION.
+ * f95-lang.c (ATTR_NULL, 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,
+ BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT): 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,
+ BT_FN_BOOL_INT, BT_FN_BOOL_INT_BOOL, BT_FN_VOID_UINT_UINT,
+ BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR,
+ BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR,
+ BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR): New.
+
2013-10-10 Tobias Burnus <burnus@net-b.de>
PR fortran/58226
diff --git a/gcc/fortran/f95-lang.c b/gcc/fortran/f95-lang.c
index 7bb2913552c..873c137e581 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/trans-openmp.c b/gcc/fortran/trans-openmp.c
index 2765561e889..1c4ae62a3d9 100644
--- a/gcc/fortran/trans-openmp.c
+++ b/gcc/fortran/trans-openmp.c
@@ -159,6 +159,9 @@ gfc_omp_clause_default_ctor (tree clause, tree decl, tree outer)
|| GFC_TYPE_ARRAY_AKIND (type) != GFC_ARRAY_ALLOCATABLE)
return NULL;
+ if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_REDUCTION)
+ return NULL;
+
gcc_assert (outer != NULL);
gcc_assert (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_PRIVATE
|| OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_LASTPRIVATE);
@@ -323,6 +326,9 @@ gfc_omp_clause_dtor (tree clause ATTRIBUTE_UNUSED, tree decl)
|| GFC_TYPE_ARRAY_AKIND (type) != GFC_ARRAY_ALLOCATABLE)
return NULL;
+ if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_REDUCTION)
+ return NULL;
+
/* Allocatable arrays in FIRSTPRIVATE/LASTPRIVATE etc. clauses need
to be deallocated if they were allocated. */
return gfc_trans_dealloc_allocated (decl, false, NULL);
diff --git a/gcc/fortran/types.def b/gcc/fortran/types.def
index e4cd1d18eb9..9bbee3504fe 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,
@@ -89,7 +91,7 @@ DEF_FUNCTION_TYPE_1 (BT_FN_VOID_VPTR, BT_VOID, BT_VOLATILE_PTR)
DEF_FUNCTION_TYPE_1 (BT_FN_UINT_UINT, BT_UINT, BT_UINT)
DEF_FUNCTION_TYPE_1 (BT_FN_PTR_PTR, BT_PTR, BT_PTR)
DEF_FUNCTION_TYPE_1 (BT_FN_VOID_INT, BT_VOID, BT_INT)
-
+DEF_FUNCTION_TYPE_1 (BT_FN_BOOL_INT, BT_BOOL, BT_INT)
DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR, BT_FN_VOID_PTR)
@@ -117,7 +119,8 @@ DEF_FUNCTION_TYPE_2 (BT_FN_VOID_VPTR_INT, BT_VOID, BT_VOLATILE_PTR, BT_INT)
DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_VPTR_INT, BT_BOOL, BT_VOLATILE_PTR, BT_INT)
DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_SIZE_CONST_VPTR, BT_BOOL, BT_SIZE,
BT_CONST_VOLATILE_PTR)
-
+DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_INT_BOOL, BT_BOOL, BT_INT, BT_BOOL)
+DEF_FUNCTION_TYPE_2 (BT_FN_VOID_UINT_UINT, BT_VOID, BT_UINT, BT_UINT)
DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR)
@@ -137,8 +140,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 +160,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 +172,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)
@@ -191,17 +192,26 @@ DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_VPTR_PTR_I16_BOOL_INT_INT,
BT_INT)
DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_SIZE_VPTR_PTR_PTR_INT_INT, BT_BOOL, BT_SIZE,
BT_VOLATILE_PTR, BT_PTR, BT_PTR, BT_INT, BT_INT)
+DEF_FUNCTION_TYPE_6 (BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR,
+ BT_VOID, BT_INT, BT_PTR, BT_SIZE, BT_PTR, BT_PTR, BT_PTR)
-DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_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)
-DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT,
- BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR,
- BT_PTR_FN_VOID_PTR_PTR, BT_LONG, BT_LONG,
- BT_BOOL, BT_UINT)
+ BT_LONG, BT_LONG, BT_LONG, BT_UINT)
DEF_FUNCTION_TYPE_7 (BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULL_ULLPTR_ULLPTR,
BT_BOOL, BT_BOOL, BT_ULONGLONG, BT_ULONGLONG,
BT_ULONGLONG, BT_ULONGLONG,
BT_PTR_ULONGLONG, BT_PTR_ULONGLONG)
+DEF_FUNCTION_TYPE_7 (BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR,
+ BT_VOID, BT_INT, BT_PTR_FN_VOID_PTR, BT_PTR, BT_SIZE,
+ BT_PTR, BT_PTR, BT_PTR)
+
+DEF_FUNCTION_TYPE_8 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT,
+ BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT,
+ BT_LONG, BT_LONG, BT_LONG, BT_LONG, BT_UINT)
+DEF_FUNCTION_TYPE_8 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR,
+ BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR,
+ BT_PTR_FN_VOID_PTR_PTR, BT_LONG, BT_LONG,
+ BT_BOOL, BT_UINT, BT_PTR)
DEF_FUNCTION_TYPE_VAR_0 (BT_FN_VOID_VAR, BT_VOID)
diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c
index 8e083aeb4d7..aa4c024b1ce 100644
--- a/gcc/gimple-low.c
+++ b/gcc/gimple-low.c
@@ -425,6 +425,7 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
case GIMPLE_OMP_SECTION:
case GIMPLE_OMP_SINGLE:
case GIMPLE_OMP_MASTER:
+ case GIMPLE_OMP_TASKGROUP:
case GIMPLE_OMP_ORDERED:
case GIMPLE_OMP_CRITICAL:
case GIMPLE_OMP_RETURN:
@@ -466,6 +467,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 1e985e0dbd7..f0f816671ec 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -1097,6 +1097,9 @@ dump_gimple_omp_for (pretty_printer *buffer, gimple gs, int spc, int flags)
case GF_OMP_FOR_KIND_SIMD:
kind = " simd";
break;
+ case GF_OMP_FOR_KIND_DISTRIBUTE:
+ kind = " distribute";
+ break;
default:
gcc_unreachable ();
}
@@ -1125,6 +1128,9 @@ dump_gimple_omp_for (pretty_printer *buffer, gimple gs, int spc, int flags)
case GF_OMP_FOR_KIND_SIMD:
pp_string (buffer, "#pragma omp simd");
break;
+ case GF_OMP_FOR_KIND_DISTRIBUTE:
+ pp_string (buffer, "#pragma omp distribute");
+ break;
default:
gcc_unreachable ();
}
@@ -1239,6 +1245,85 @@ 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_omp_target_child_fn (gs))
+ {
+ pp_string (buffer, " [child fn: ");
+ dump_generic_node (buffer, gimple_omp_target_child_fn (gs),
+ spc, flags, false);
+ pp_right_bracket (buffer);
+ }
+ 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
@@ -1275,8 +1360,8 @@ dump_gimple_omp_sections (pretty_printer *buffer, gimple gs, int spc,
}
}
-/* Dump a GIMPLE_OMP_{MASTER,ORDERED,SECTION} tuple on the pretty_printer
- BUFFER. */
+/* Dump a GIMPLE_OMP_{MASTER,TASKGROUP,ORDERED,SECTION} tuple on the
+ pretty_printer BUFFER. */
static void
dump_gimple_omp_block (pretty_printer *buffer, gimple gs, int spc, int flags)
@@ -1291,6 +1376,9 @@ dump_gimple_omp_block (pretty_printer *buffer, gimple gs, int spc, int flags)
case GIMPLE_OMP_MASTER:
pp_string (buffer, "#pragma omp master");
break;
+ case GIMPLE_OMP_TASKGROUP:
+ pp_string (buffer, "#pragma omp taskgroup");
+ break;
case GIMPLE_OMP_ORDERED:
pp_string (buffer, "#pragma omp ordered");
break;
@@ -1350,14 +1438,26 @@ dump_gimple_omp_return (pretty_printer *buffer, gimple gs, int spc, int flags)
{
if (flags & TDF_RAW)
{
- dump_gimple_fmt (buffer, spc, flags, "%G <nowait=%d>", gs,
+ dump_gimple_fmt (buffer, spc, flags, "%G <nowait=%d", gs,
(int) gimple_omp_return_nowait_p (gs));
+ if (gimple_omp_return_lhs (gs))
+ dump_gimple_fmt (buffer, spc, flags, ", lhs=%T>",
+ gimple_omp_return_lhs (gs));
+ else
+ dump_gimple_fmt (buffer, spc, flags, ">");
}
else
{
pp_string (buffer, "#pragma omp return");
if (gimple_omp_return_nowait_p (gs))
pp_string (buffer, "(nowait)");
+ if (gimple_omp_return_lhs (gs))
+ {
+ pp_string (buffer, " (set ");
+ dump_generic_node (buffer, gimple_omp_return_lhs (gs),
+ spc, flags, false);
+ pp_character (buffer, ')');
+ }
}
}
@@ -1826,6 +1926,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);
@@ -1856,6 +1958,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_left_paren (buffer);
@@ -2023,6 +2127,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;
@@ -2036,6 +2148,7 @@ pp_gimple_stmt_1 (pretty_printer *buffer, gimple gs, int spc, int flags)
break;
case GIMPLE_OMP_MASTER:
+ case GIMPLE_OMP_TASKGROUP:
case GIMPLE_OMP_ORDERED:
case GIMPLE_OMP_SECTION:
dump_gimple_omp_block (buffer, gs, spc, flags);
diff --git a/gcc/gimple.c b/gcc/gimple.c
index dbcfa3ab3d1..37a8123ada1 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -1007,6 +1007,22 @@ gimple_build_omp_master (gimple_seq body)
}
+/* Build a GIMPLE_OMP_TASKGROUP statement.
+
+ BODY is the sequence of statements to be executed by the taskgroup
+ construct. */
+
+gimple
+gimple_build_omp_taskgroup (gimple_seq body)
+{
+ gimple p = gimple_alloc (GIMPLE_OMP_TASKGROUP, 0);
+ if (body)
+ gimple_omp_set_body (p, body);
+
+ return p;
+}
+
+
/* Build a GIMPLE_OMP_CONTINUE statement.
CONTROL_DEF is the definition of the control variable.
@@ -1096,6 +1112,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
@@ -1612,6 +1663,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);
@@ -1638,10 +1703,16 @@ walk_gimple_op (gimple stmt, walk_tree_fn callback_op,
return ret;
break;
+ case GIMPLE_OMP_RETURN:
+ ret = walk_tree (gimple_omp_return_lhs_ptr (stmt), callback_op, wi,
+ pset);
+ if (ret)
+ return ret;
+ break;
+
/* Tuples that do not have operands. */
case GIMPLE_NOP:
case GIMPLE_RESX:
- case GIMPLE_OMP_RETURN:
case GIMPLE_PREDICT:
break;
@@ -1782,12 +1853,15 @@ walk_gimple_stmt (gimple_stmt_iterator *gsi, walk_stmt_fn callback_stmt,
/* FALL THROUGH. */
case GIMPLE_OMP_CRITICAL:
case GIMPLE_OMP_MASTER:
+ case GIMPLE_OMP_TASKGROUP:
case GIMPLE_OMP_ORDERED:
case GIMPLE_OMP_SECTION:
case GIMPLE_OMP_PARALLEL:
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)
@@ -2277,8 +2351,11 @@ 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_TASKGROUP:
case GIMPLE_OMP_ORDERED:
copy_omp_body:
new_seq = gimple_seq_copy (gimple_omp_body (stmt));
diff --git a/gcc/gimple.def b/gcc/gimple.def
index f3652f4e78f..07370aedd29 100644
--- a/gcc/gimple.def
+++ b/gcc/gimple.def
@@ -276,6 +276,10 @@ DEFGSCODE(GIMPLE_OMP_FOR, "gimple_omp_for", GSS_OMP_FOR)
BODY is the sequence of statements to execute in the master section. */
DEFGSCODE(GIMPLE_OMP_MASTER, "gimple_omp_master", GSS_OMP)
+/* GIMPLE_OMP_TASKGROUP <BODY> represents #pragma omp taskgroup.
+ BODY is the sequence of statements to execute in the taskgroup section. */
+DEFGSCODE(GIMPLE_OMP_TASKGROUP, "gimple_omp_taskgroup", GSS_OMP)
+
/* GIMPLE_OMP_ORDERED <BODY> represents #pragma omp ordered.
BODY is the sequence of statements to execute in the ordered section. */
DEFGSCODE(GIMPLE_OMP_ORDERED, "gimple_omp_ordered", GSS_OMP)
@@ -325,7 +329,7 @@ DEFGSCODE(GIMPLE_OMP_PARALLEL, "gimple_omp_parallel", GSS_OMP_PARALLEL)
DEFGSCODE(GIMPLE_OMP_TASK, "gimple_omp_task", GSS_OMP_TASK)
/* OMP_RETURN marks the end of an OpenMP directive. */
-DEFGSCODE(GIMPLE_OMP_RETURN, "gimple_omp_return", GSS_BASE)
+DEFGSCODE(GIMPLE_OMP_RETURN, "gimple_omp_return", GSS_OMP_ATOMIC_STORE)
/* OMP_SECTION <BODY> represents #pragma omp section.
BODY is the sequence of statements in the section body. */
@@ -349,6 +353,24 @@ DEFGSCODE(GIMPLE_OMP_SECTIONS_SWITCH, "gimple_omp_sections_switch", GSS_BASE)
CLAUSES is an OMP_CLAUSE chain holding the associated clauses. */
DEFGSCODE(GIMPLE_OMP_SINGLE, "gimple_omp_single", GSS_OMP_SINGLE)
+/* GIMPLE_OMP_TARGET <BODY, CLAUSES, CHILD_FN> 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.
+ CHILD_FN is set when outlining the body of the target region.
+ All the statements in BODY are moved into this newly created
+ function when converting OMP constructs into low-GIMPLE.
+ DATA_ARG is a vec of 3 local variables in the parent function
+ containing data to be mapped to CHILD_FN. This is used to
+ implement the MAP clauses. */
+DEFGSCODE(GIMPLE_OMP_TARGET, "gimple_omp_target", GSS_OMP_PARALLEL)
+
+/* GIMPLE_OMP_TEAMS <BODY, CLAUSES> 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 <PREDICT, OUTCOME> specifies a hint for branch prediction.
PREDICT is one of the predictors from predict.def.
diff --git a/gcc/gimple.h b/gcc/gimple.h
index ca7e39405e8..2af4ff932a8 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -105,6 +105,13 @@ enum gf_mask {
GF_OMP_FOR_KIND_MASK = 3 << 0,
GF_OMP_FOR_KIND_FOR = 0 << 0,
GF_OMP_FOR_KIND_SIMD = 1 << 0,
+ GF_OMP_FOR_KIND_DISTRIBUTE = 2 << 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
@@ -114,6 +121,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
};
@@ -607,7 +615,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 ] */
@@ -786,11 +794,14 @@ gimple gimple_build_omp_critical (gimple_seq, tree);
gimple gimple_build_omp_section (gimple_seq);
gimple gimple_build_omp_continue (tree, tree);
gimple gimple_build_omp_master (gimple_seq);
+gimple gimple_build_omp_taskgroup (gimple_seq);
gimple gimple_build_omp_return (bool);
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);
@@ -1250,12 +1261,15 @@ gimple_has_substatements (gimple g)
case GIMPLE_TRY:
case GIMPLE_OMP_FOR:
case GIMPLE_OMP_MASTER:
+ case GIMPLE_OMP_TASKGROUP:
case GIMPLE_OMP_ORDERED:
case GIMPLE_OMP_SECTION:
case GIMPLE_OMP_PARALLEL:
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:
@@ -1634,7 +1648,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;
}
@@ -1670,6 +1684,36 @@ gimple_omp_return_nowait_p (const_gimple g)
}
+/* Set the LHS of OMP return. */
+
+static inline void
+gimple_omp_return_set_lhs (gimple g, tree lhs)
+{
+ GIMPLE_CHECK (g, GIMPLE_OMP_RETURN);
+ g->gimple_omp_atomic_store.val = lhs;
+}
+
+
+/* Get the LHS of OMP return. */
+
+static inline tree
+gimple_omp_return_lhs (const_gimple g)
+{
+ GIMPLE_CHECK (g, GIMPLE_OMP_RETURN);
+ return g->gimple_omp_atomic_store.val;
+}
+
+
+/* Return a pointer to the LHS of OMP return. */
+
+static inline tree *
+gimple_omp_return_lhs_ptr (gimple g)
+{
+ GIMPLE_CHECK (g, GIMPLE_OMP_RETURN);
+ return &g->gimple_omp_atomic_store.val;
+}
+
+
/* Return true if OMP section statement G has the GF_OMP_SECTION_LAST
flag set. */
@@ -1739,6 +1783,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
@@ -4022,6 +4089,56 @@ gimple_omp_for_set_kind (gimple g, int kind)
}
+/* 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
@@ -4631,6 +4748,148 @@ 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_parallel.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_parallel.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_parallel.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 child function used to hold the body of OMP_TARGET GS. */
+
+static inline tree
+gimple_omp_target_child_fn (const_gimple gs)
+{
+ GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
+ return gs->gimple_omp_parallel.child_fn;
+}
+
+/* Return a pointer to the child function used to hold the body of
+ OMP_TARGET GS. */
+
+static inline tree *
+gimple_omp_target_child_fn_ptr (gimple gs)
+{
+ GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
+ return &gs->gimple_omp_parallel.child_fn;
+}
+
+
+/* Set CHILD_FN to be the child function for OMP_TARGET GS. */
+
+static inline void
+gimple_omp_target_set_child_fn (gimple gs, tree child_fn)
+{
+ GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
+ gs->gimple_omp_parallel.child_fn = child_fn;
+}
+
+
+/* Return the artificial argument used to send variables and values
+ from the parent to the children threads in OMP_TARGET GS. */
+
+static inline tree
+gimple_omp_target_data_arg (const_gimple gs)
+{
+ GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
+ return gs->gimple_omp_parallel.data_arg;
+}
+
+
+/* Return a pointer to the data argument for OMP_TARGET GS. */
+
+static inline tree *
+gimple_omp_target_data_arg_ptr (gimple gs)
+{
+ GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
+ return &gs->gimple_omp_parallel.data_arg;
+}
+
+
+/* Set DATA_ARG to be the data argument for OMP_TARGET GS. */
+
+static inline void
+gimple_omp_target_set_data_arg (gimple gs, tree data_arg)
+{
+ GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
+ gs->gimple_omp_parallel.data_arg = data_arg;
+}
+
+
+/* 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
@@ -4973,8 +5232,11 @@ 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_TASKGROUP: \
case GIMPLE_OMP_ORDERED: \
case GIMPLE_OMP_CRITICAL: \
case GIMPLE_OMP_RETURN: \
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 449e6eebc61..9bc42e46a7d 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -59,9 +59,12 @@ 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_MAP_TO_ONLY = 8192,
GOVD_DATA_SHARE_CLASS = (GOVD_SHARED | GOVD_PRIVATE | GOVD_FIRSTPRIVATE
| GOVD_LASTPRIVATE | GOVD_REDUCTION | GOVD_LINEAR
| GOVD_LOCAL)
@@ -75,7 +78,10 @@ enum omp_region_type
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
@@ -86,6 +92,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;
@@ -2701,7 +2708,14 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value)
notice_special_calls (call);
gimplify_seq_add_stmt (pre_p, call);
gsi = gsi_last (*pre_p);
- fold_stmt (&gsi);
+ /* Don't fold stmts inside of target construct. We'll do it
+ during omplower pass instead. */
+ struct gimplify_omp_ctx *ctx;
+ for (ctx = gimplify_omp_ctxp; ctx; ctx = ctx->outer_context)
+ if (ctx->region_type == ORT_TARGET)
+ break;
+ if (ctx == NULL)
+ fold_stmt (&gsi);
*expr_p = NULL_TREE;
}
else
@@ -4591,10 +4605,12 @@ is_gimple_stmt (tree t)
case OMP_PARALLEL:
case OMP_FOR:
case OMP_SIMD:
+ case OMP_DISTRIBUTE:
case OMP_SECTIONS:
case OMP_SECTION:
case OMP_SINGLE:
case OMP_MASTER:
+ case OMP_TASKGROUP:
case OMP_ORDERED:
case OMP_CRITICAL:
case OMP_TASK:
@@ -4835,7 +4851,14 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
gimplify_seq_add_stmt (pre_p, assign);
gsi = gsi_last (*pre_p);
- fold_stmt (&gsi);
+ /* Don't fold stmts inside of target construct. We'll do it
+ during omplower pass instead. */
+ struct gimplify_omp_ctx *ctx;
+ for (ctx = gimplify_omp_ctxp; ctx; ctx = ctx->outer_context)
+ if (ctx->region_type == ORT_TARGET)
+ break;
+ if (ctx == NULL)
+ fold_stmt (&gsi);
if (want_value)
{
@@ -5610,11 +5633,16 @@ omp_firstprivatize_variable (struct gimplify_omp_ctx *ctx, tree decl)
{
if (n->value & GOVD_SHARED)
n->value = GOVD_FIRSTPRIVATE | (n->value & GOVD_SEEN);
+ else if (n->value & GOVD_MAP)
+ n->value |= GOVD_MAP_TO_ONLY;
else
return;
}
+ else if (ctx->region_type == ORT_TARGET)
+ omp_add_variable (ctx, decl, GOVD_MAP | GOVD_MAP_TO_ONLY);
else if (ctx->region_type != ORT_WORKSHARE
- && ctx->region_type != ORT_SIMD)
+ && ctx->region_type != ORT_SIMD
+ && ctx->region_type != ORT_TARGET_DATA)
omp_add_variable (ctx, decl, GOVD_FIRSTPRIVATE);
ctx = ctx->outer_context;
@@ -5697,7 +5725,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. */
@@ -5723,7 +5751,9 @@ omp_add_variable (struct gimplify_omp_ctx *ctx, tree decl, unsigned int flags)
copy into or out of the context. */
if (!(flags & GOVD_LOCAL))
{
- nflags = flags & GOVD_PRIVATE ? GOVD_PRIVATE : GOVD_FIRSTPRIVATE;
+ nflags = flags & GOVD_MAP
+ ? GOVD_MAP | GOVD_MAP_TO_ONLY | GOVD_EXPLICIT
+ : flags & GOVD_PRIVATE ? GOVD_PRIVATE : GOVD_FIRSTPRIVATE;
nflags |= flags & GOVD_SEEN;
t = DECL_VALUE_EXPR (decl);
gcc_assert (TREE_CODE (t) == INDIRECT_REF);
@@ -5752,13 +5782,13 @@ omp_add_variable (struct gimplify_omp_ctx *ctx, tree decl, unsigned int flags)
For local variables TYPE_SIZE_UNIT might not be gimplified yet,
in this case omp_notice_variable will be called later
on when it is gimplified. */
- else if (! (flags & GOVD_LOCAL)
+ else if (! (flags & (GOVD_LOCAL | GOVD_MAP))
&& DECL_P (TYPE_SIZE_UNIT (TREE_TYPE (decl))))
omp_notice_variable (ctx, TYPE_SIZE_UNIT (TREE_TYPE (decl)), true);
}
- else if (lang_hooks.decls.omp_privatize_by_reference (decl))
+ else if ((flags & (GOVD_MAP | GOVD_LOCAL)) == 0
+ && lang_hooks.decls.omp_privatize_by_reference (decl))
{
- gcc_assert ((flags & GOVD_LOCAL) == 0);
omp_firstprivatize_type_sizes (ctx, TREE_TYPE (decl));
/* Similar to the direct variable sized case above, we'll need the
@@ -5787,6 +5817,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;
@@ -5835,13 +5881,33 @@ 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)
+ {
+ if (!lang_hooks.types.omp_mappable_type (TREE_TYPE (decl)))
+ {
+ error ("%qD referenced in target region does not have "
+ "a mappable type", decl);
+ omp_add_variable (ctx, decl, GOVD_MAP | GOVD_EXPLICIT | flags);
+ }
+ else
+ 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
- || ctx->region_type == ORT_SIMD)
+ || ctx->region_type == ORT_SIMD
+ || ctx->region_type == ORT_TARGET_DATA)
goto do_outer;
/* ??? Some compiler-generated variables (like SAVE_EXPRs) could be
@@ -5855,12 +5921,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;
@@ -5880,13 +5958,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)
@@ -6028,6 +6108,9 @@ 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;
@@ -6086,15 +6169,87 @@ 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_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;
+ 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);
@@ -6183,9 +6338,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:
@@ -6193,9 +6352,22 @@ 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:
ctx->default_kind = OMP_CLAUSE_DEFAULT_KIND (c);
break;
@@ -6235,12 +6407,16 @@ 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)
+ code = OMP_CLAUSE_MAP;
else if (flags & GOVD_SHARED)
{
if (is_global_var (decl))
@@ -6267,6 +6443,8 @@ gimplify_adjust_omp_clauses_1 (splay_tree_node n, void *data)
code = OMP_CLAUSE_FIRSTPRIVATE;
else if (flags & GOVD_LASTPRIVATE)
code = OMP_CLAUSE_LASTPRIVATE;
+ else if (flags & GOVD_ALIGNED)
+ return 0;
else
gcc_unreachable ();
@@ -6277,6 +6455,36 @@ 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) = flags & GOVD_MAP_TO_ONLY
+ ? OMP_CLAUSE_MAP_TO
+ : OMP_CLAUSE_MAP_TOFROM;
+ if (DECL_SIZE (decl)
+ && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
+ {
+ tree decl2 = DECL_VALUE_EXPR (decl);
+ gcc_assert (TREE_CODE (decl2) == INDIRECT_REF);
+ decl2 = TREE_OPERAND (decl2, 0);
+ gcc_assert (DECL_P (decl2));
+ tree mem = build_simple_mem_ref (decl2);
+ OMP_CLAUSE_DECL (clause) = mem;
+ OMP_CLAUSE_SIZE (clause) = TYPE_SIZE_UNIT (TREE_TYPE (decl));
+ if (gimplify_omp_ctxp->outer_context)
+ {
+ struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp->outer_context;
+ omp_notice_variable (ctx, decl2, true);
+ omp_notice_variable (ctx, OMP_CLAUSE_SIZE (clause), true);
+ }
+ tree nc = build_omp_clause (OMP_CLAUSE_LOCATION (clause),
+ OMP_CLAUSE_MAP);
+ OMP_CLAUSE_DECL (nc) = decl;
+ OMP_CLAUSE_SIZE (nc) = size_zero_node;
+ OMP_CLAUSE_MAP_KIND (nc) = OMP_CLAUSE_MAP_POINTER;
+ OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (clause);
+ OMP_CLAUSE_CHAIN (clause) = nc;
+ }
+ }
*list_p = clause;
lang_hooks.decls.omp_finish_clause (clause);
@@ -6352,11 +6560,116 @@ 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_SIZE (decl)
+ && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST
+ && OMP_CLAUSE_MAP_KIND (c) != OMP_CLAUSE_MAP_POINTER)
+ {
+ tree decl2 = DECL_VALUE_EXPR (decl);
+ gcc_assert (TREE_CODE (decl2) == INDIRECT_REF);
+ decl2 = TREE_OPERAND (decl2, 0);
+ gcc_assert (DECL_P (decl2));
+ tree mem = build_simple_mem_ref (decl2);
+ OMP_CLAUSE_DECL (c) = mem;
+ OMP_CLAUSE_SIZE (c) = TYPE_SIZE_UNIT (TREE_TYPE (decl));
+ if (ctx->outer_context)
+ {
+ omp_notice_variable (ctx->outer_context, decl2, true);
+ omp_notice_variable (ctx->outer_context,
+ OMP_CLAUSE_SIZE (c), true);
+ }
+ tree nc = build_omp_clause (OMP_CLAUSE_LOCATION (c),
+ OMP_CLAUSE_MAP);
+ OMP_CLAUSE_DECL (nc) = decl;
+ OMP_CLAUSE_SIZE (nc) = size_zero_node;
+ OMP_CLAUSE_MAP_KIND (nc) = OMP_CLAUSE_MAP_POINTER;
+ OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (c);
+ OMP_CLAUSE_CHAIN (c) = nc;
+ c = nc;
+ }
+ break;
+
+ case OMP_CLAUSE_TO:
+ case OMP_CLAUSE_FROM:
+ decl = OMP_CLAUSE_DECL (c);
+ if (!DECL_P (decl))
+ break;
+ if (DECL_SIZE (decl)
+ && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
+ {
+ tree decl2 = DECL_VALUE_EXPR (decl);
+ gcc_assert (TREE_CODE (decl2) == INDIRECT_REF);
+ decl2 = TREE_OPERAND (decl2, 0);
+ gcc_assert (DECL_P (decl2));
+ tree mem = build_simple_mem_ref (decl2);
+ OMP_CLAUSE_DECL (c) = mem;
+ OMP_CLAUSE_SIZE (c) = TYPE_SIZE_UNIT (TREE_TYPE (decl));
+ if (ctx->outer_context)
+ {
+ omp_notice_variable (ctx->outer_context, decl2, true);
+ omp_notice_variable (ctx->outer_context,
+ OMP_CLAUSE_SIZE (c), true);
+ }
+ }
+ 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_THREAD_LIMIT:
+ case OMP_CLAUSE_DIST_SCHEDULE:
+ case OMP_CLAUSE_DEVICE:
case OMP_CLAUSE_SCHEDULE:
case OMP_CLAUSE_NOWAIT:
case OMP_CLAUSE_ORDERED:
@@ -6365,7 +6678,9 @@ 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_DEPEND:
break;
default:
@@ -6458,12 +6773,39 @@ 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;
@@ -6472,9 +6814,9 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
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;
+ simd = TREE_CODE (for_stmt) == OMP_SIMD;
gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p,
simd ? ORT_SIMD : ORT_WORKSHARE);
@@ -6485,7 +6827,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
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)
+ == VAR_DECL)
{
t = OMP_FOR_PRE_BODY (for_stmt);
bitmap_set_bit (has_decl_expr, DECL_UID (DECL_EXPR_DECL (t)));
@@ -6506,6 +6848,14 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
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)));
@@ -6522,7 +6872,9 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
/* Make sure the iteration variable is private. */
tree c = NULL_TREE;
- if (simd)
+ 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);
@@ -6566,7 +6918,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;
@@ -6599,6 +6953,8 @@ 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;
@@ -6609,6 +6965,8 @@ 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;
@@ -6665,9 +7023,9 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
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
@@ -6691,21 +7049,49 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
BITMAP_FREE (has_decl_expr);
- gimplify_and_add (OMP_FOR_BODY (for_stmt), &for_body);
+ gimplify_and_add (OMP_FOR_BODY (orig_for_stmt), &for_body);
- gimplify_adjust_omp_clauses (&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 (for_stmt))
+ 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 OMP_DISTRIBUTE: kind = GF_OMP_FOR_KIND_DISTRIBUTE; break;
default:
gcc_unreachable ();
}
- gfor = gimple_build_omp_for (for_body, kind, OMP_FOR_CLAUSES (for_stmt),
+ 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++)
{
@@ -6726,8 +7112,9 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
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)
@@ -6735,19 +7122,93 @@ 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);
- gimplify_and_add (OMP_BODY (expr), &body);
+ 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);
+ if (ort == ORT_TARGET || ort == ORT_TARGET_DATA)
+ {
+ struct gimplify_ctx gctx;
+ push_gimplify_context (&gctx);
+ gimple g = gimplify_and_return_first (OMP_BODY (expr), &body);
+ if (gimple_code (g) == GIMPLE_BIND)
+ pop_gimplify_context (g);
+ else
+ pop_gimplify_context (NULL);
+ if (ort == ORT_TARGET_DATA)
+ {
+ gimple_seq cleanup = NULL;
+ tree fn = builtin_decl_explicit (BUILT_IN_GOMP_TARGET_END_DATA);
+ g = gimple_build_call (fn, 0);
+ gimple_seq_add_stmt (&cleanup, g);
+ g = gimple_build_try (body, cleanup, GIMPLE_TRY_FINALLY);
+ body = NULL;
+ gimple_seq_add_stmt (&body, g);
+ }
+ }
+ else
+ 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
@@ -6886,6 +7347,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:
@@ -6902,7 +7368,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
@@ -7642,17 +8108,27 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
case OMP_FOR:
case OMP_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_TASKGROUP:
case OMP_ORDERED:
case OMP_CRITICAL:
{
@@ -7668,6 +8144,19 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
case OMP_MASTER:
g = gimple_build_omp_master (body);
break;
+ case OMP_TASKGROUP:
+ {
+ gimple_seq cleanup = NULL;
+ tree fn
+ = builtin_decl_explicit (BUILT_IN_GOMP_TASKGROUP_END);
+ g = gimple_build_call (fn, 0);
+ gimple_seq_add_stmt (&cleanup, g);
+ g = gimple_build_try (body, cleanup, GIMPLE_TRY_FINALLY);
+ body = NULL;
+ gimple_seq_add_stmt (&body, g);
+ g = gimple_build_omp_taskgroup (body);
+ }
+ break;
case OMP_ORDERED:
g = gimple_build_omp_ordered (body);
break;
@@ -8000,6 +8489,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
&& code != OMP_CRITICAL
&& code != OMP_FOR
&& code != OMP_MASTER
+ && code != OMP_TASKGROUP
&& code != OMP_ORDERED
&& code != OMP_PARALLEL
&& code != OMP_SECTIONS
@@ -8224,6 +8714,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
@@ -8286,6 +8783,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/langhooks-def.h b/gcc/langhooks-def.h
index 7bd2e9930da..b7be47200a8 100644
--- a/gcc/langhooks-def.h
+++ b/gcc/langhooks-def.h
@@ -77,6 +77,7 @@ extern tree lhd_omp_assignment (tree, tree, tree);
struct gimplify_omp_ctx;
extern void lhd_omp_firstprivatize_type_sizes (struct gimplify_omp_ctx *,
tree);
+extern bool lhd_omp_mappable_type (tree);
#define LANG_HOOKS_NAME "GNU unknown"
#define LANG_HOOKS_IDENTIFIER_SIZE sizeof (struct lang_identifier)
@@ -166,6 +167,7 @@ extern tree lhd_make_node (enum tree_code);
#define LANG_HOOKS_TYPE_MAX_SIZE lhd_return_null_const_tree
#define LANG_HOOKS_OMP_FIRSTPRIVATIZE_TYPE_SIZES \
lhd_omp_firstprivatize_type_sizes
+#define LANG_HOOKS_OMP_MAPPABLE_TYPE lhd_omp_mappable_type
#define LANG_HOOKS_TYPE_HASH_EQ NULL
#define LANG_HOOKS_GET_ARRAY_DESCR_INFO NULL
#define LANG_HOOKS_GET_SUBRANGE_BOUNDS NULL
@@ -184,6 +186,7 @@ extern tree lhd_make_node (enum tree_code);
LANG_HOOKS_INCOMPLETE_TYPE_ERROR, \
LANG_HOOKS_TYPE_MAX_SIZE, \
LANG_HOOKS_OMP_FIRSTPRIVATIZE_TYPE_SIZES, \
+ LANG_HOOKS_OMP_MAPPABLE_TYPE, \
LANG_HOOKS_TYPE_HASH_EQ, \
LANG_HOOKS_GET_ARRAY_DESCR_INFO, \
LANG_HOOKS_GET_SUBRANGE_BOUNDS, \
diff --git a/gcc/langhooks.c b/gcc/langhooks.c
index fbf545b466a..559d5c1beac 100644
--- a/gcc/langhooks.c
+++ b/gcc/langhooks.c
@@ -523,6 +523,15 @@ lhd_omp_firstprivatize_type_sizes (struct gimplify_omp_ctx *c ATTRIBUTE_UNUSED,
{
}
+/* Return true if TYPE is an OpenMP mappable type. By default return true
+ if type is complete. */
+
+bool
+lhd_omp_mappable_type (tree type)
+{
+ return COMPLETE_TYPE_P (type);
+}
+
/* Common function for add_builtin_function and
add_builtin_function_ext_scope. */
static tree
diff --git a/gcc/langhooks.h b/gcc/langhooks.h
index 80d4ef3b8a6..a83bf7b71ed 100644
--- a/gcc/langhooks.h
+++ b/gcc/langhooks.h
@@ -111,6 +111,9 @@ struct lang_hooks_for_types
firstprivate variables. */
void (*omp_firstprivatize_type_sizes) (struct gimplify_omp_ctx *, tree);
+ /* Return true if TYPE is a mappable type. */
+ bool (*omp_mappable_type) (tree type);
+
/* Return TRUE if TYPE1 and TYPE2 are identical for type hashing purposes.
Called only after doing all language independent checks.
At present, this function is only called when both TYPE1 and TYPE2 are
diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog
index f4a57b2f8cd..eaa69306f67 100644
--- a/gcc/lto/ChangeLog
+++ b/gcc/lto/ChangeLog
@@ -1,3 +1,7 @@
+2013-10-11 Jakub Jelinek <jakub@redhat.com>
+
+ * lto-lang.c (DEF_FUNCTION_TYPE_8): Define.
+
2013-09-25 Tom Tromey <tromey@redhat.com>
* Make-lang.in (LTO_H, LINKER_PLUGIN_API_H, LTO_TREE_H)
diff --git a/gcc/lto/lto-lang.c b/gcc/lto/lto-lang.c
index 87a756d5763..79cc5609994 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 83c26c44fc9..8fd99548e7e 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)
@@ -35,10 +39,20 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_ATOMIC_END, "GOMP_atomic_end",
BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_BARRIER, "GOMP_barrier",
BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_BARRIER_CANCEL, "GOMP_barrier_cancel",
+ BT_FN_BOOL, ATTR_NOTHROW_LEAF_LIST)
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_BOOL_INT_BOOL, ATTR_NOTHROW_LEAF_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_CANCELLATION_POINT, "GOMP_cancellation_point",
+ BT_FN_BOOL_INT, ATTR_NOTHROW_LEAF_LIST)
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,49 +170,52 @@ 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)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_END_CANCEL, "GOMP_loop_end_cancel",
+ BT_FN_BOOL, ATTR_NOTHROW_LEAF_LIST)
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_END_NOWAIT, "GOMP_loop_end_nowait",
BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
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,
+ BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR,
ATTR_NOTHROW_LIST)
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_CANCEL,
+ "GOMP_sections_end_cancel",
+ BT_FN_BOOL, ATTR_NOTHROW_LEAF_LIST)
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SECTIONS_END_NOWAIT,
"GOMP_sections_end_nowait",
BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
@@ -208,3 +225,14 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SINGLE_COPY_START, "GOMP_single_copy_start",
BT_FN_PTR, ATTR_NOTHROW_LEAF_LIST)
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SINGLE_COPY_END, "GOMP_single_copy_end",
BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TARGET, "GOMP_target",
+ BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR,
+ ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TARGET_DATA, "GOMP_target_data",
+ BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR, ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TARGET_END_DATA, "GOMP_target_end_data",
+ BT_FN_VOID, ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TARGET_UPDATE, "GOMP_target_update",
+ BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR, ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TEAMS, "GOMP_teams",
+ BT_FN_VOID_UINT_UINT, ATTR_NOTHROW_LIST)
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index 84b2357b754..26f0c35e285 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -90,6 +90,10 @@ typedef struct omp_context
construct. In the case of a parallel, this is in the child function. */
tree block_vars;
+ /* Label to which GOMP_cancel{,llation_point} and explicit and implicit
+ barriers should jump to during omplower pass. */
+ tree cancel_label;
+
/* What to do with variables with implicitly determined sharing
attributes. */
enum omp_clause_default_kind default_kind;
@@ -101,6 +105,9 @@ typedef struct omp_context
/* True if this parallel directive is nested within another. */
bool is_nested;
+
+ /* True if this construct can be cancelled. */
+ bool cancellable;
} omp_context;
@@ -127,6 +134,7 @@ struct omp_for_data
static splay_tree all_contexts;
static int taskreg_nesting_level;
+static int target_nesting_level;
struct omp_region *root_omp_region;
static bitmap task_shared_vars;
@@ -224,6 +232,8 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd,
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;
@@ -233,7 +243,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 || simd;
+ fd->have_ordered = false;
fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC;
fd->chunk_size = NULL_TREE;
collapse_iter = NULL;
@@ -249,9 +260,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)
{
@@ -279,8 +295,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;
}
@@ -294,7 +309,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
@@ -351,7 +365,9 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd,
gcc_unreachable ();
}
- if (simd)
+ if (simd
+ || (fd->sched_kind == OMP_CLAUSE_SCHEDULE_STATIC
+ && !fd->have_ordered))
{
if (fd->collapse == 1)
iter_type = TREE_TYPE (loop->v);
@@ -360,7 +376,7 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd,
< TYPE_PRECISION (TREE_TYPE (loop->v)))
iter_type
= build_nonstandard_integer_type
- (TYPE_PRECISION (TREE_TYPE (loop->v)), 1);
+ (TYPE_PRECISION (TREE_TYPE (loop->v)), 1);
}
else if (iter_type != long_long_unsigned_type_node)
{
@@ -459,7 +475,9 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd,
}
if (count
- && !simd)
+ && !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;
@@ -570,7 +588,7 @@ workshare_safe_to_combine_p (basic_block ws_entry_bb)
expanded. */
static vec<tree, va_gc> *
-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);
@@ -579,15 +597,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);
@@ -650,6 +684,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)
@@ -677,7 +712,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);
}
}
@@ -984,7 +1019,12 @@ install_var_field (tree var, bool by_ref, int mask, omp_context *ctx)
|| !splay_tree_lookup (ctx->sfield_map, (splay_tree_key) var));
type = TREE_TYPE (var);
- if (by_ref)
+ if (mask & 4)
+ {
+ gcc_assert (TREE_CODE (type) == ARRAY_TYPE);
+ type = build_pointer_type (build_pointer_type (type));
+ }
+ else if (by_ref)
type = build_pointer_type (type);
else if ((mask & 3) == 1 && is_reference (var))
type = TREE_TYPE (type);
@@ -1421,6 +1461,9 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
break;
case OMP_CLAUSE_SHARED:
+ /* Ignore shared directives in teams construct. */
+ if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS)
+ break;
gcc_assert (is_taskreg_ctx (ctx));
decl = OMP_CLAUSE_DECL (c);
gcc_assert (!COMPLETE_TYPE_P (TREE_TYPE (decl))
@@ -1480,6 +1523,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);
@@ -1494,19 +1544,113 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
case OMP_CLAUSE_FINAL:
case OMP_CLAUSE_IF:
case OMP_CLAUSE_NUM_THREADS:
+ case OMP_CLAUSE_NUM_TEAMS:
+ case OMP_CLAUSE_THREAD_LIMIT:
+ case OMP_CLAUSE_DEVICE:
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;
+ case OMP_CLAUSE_TO:
+ case OMP_CLAUSE_FROM:
+ case OMP_CLAUSE_MAP:
+ if (ctx->outer)
+ scan_omp_op (&OMP_CLAUSE_SIZE (c), ctx->outer);
+ decl = OMP_CLAUSE_DECL (c);
+ /* Global variables with "omp declare target" attribute
+ don't need to be copied, the receiver side will use them
+ directly. */
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+ && DECL_P (decl)
+ && is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx))
+ && lookup_attribute ("omp declare target",
+ DECL_ATTRIBUTES (decl)))
+ break;
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+ && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER)
+ {
+ /* Ignore OMP_CLAUSE_MAP_POINTER kind for arrays in
+ #pragma omp target data, there is nothing to map for
+ those. */
+ if (gimple_omp_target_kind (ctx->stmt) == GF_OMP_TARGET_KIND_DATA
+ && !POINTER_TYPE_P (TREE_TYPE (decl)))
+ break;
+ }
+ if (DECL_P (decl))
+ {
+ if (DECL_SIZE (decl)
+ && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
+ {
+ tree decl2 = DECL_VALUE_EXPR (decl);
+ gcc_assert (TREE_CODE (decl2) == INDIRECT_REF);
+ decl2 = TREE_OPERAND (decl2, 0);
+ gcc_assert (DECL_P (decl2));
+ install_var_field (decl2, true, 3, ctx);
+ install_var_local (decl2, ctx);
+ install_var_local (decl, ctx);
+ }
+ else
+ {
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+ && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER
+ && !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c)
+ && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
+ install_var_field (decl, true, 7, ctx);
+ else
+ install_var_field (decl, true, 3, ctx);
+ if (gimple_omp_target_kind (ctx->stmt)
+ == GF_OMP_TARGET_KIND_REGION)
+ install_var_local (decl, ctx);
+ }
+ }
+ else
+ {
+ tree base = get_base_address (decl);
+ tree nc = OMP_CLAUSE_CHAIN (c);
+ if (DECL_P (base)
+ && nc != NULL_TREE
+ && OMP_CLAUSE_CODE (nc) == OMP_CLAUSE_MAP
+ && OMP_CLAUSE_DECL (nc) == base
+ && OMP_CLAUSE_MAP_KIND (nc) == OMP_CLAUSE_MAP_POINTER
+ && integer_zerop (OMP_CLAUSE_SIZE (nc)))
+ {
+ OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c) = 1;
+ OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (nc) = 1;
+ }
+ else
+ {
+ gcc_assert (!splay_tree_lookup (ctx->field_map,
+ (splay_tree_key) decl));
+ tree field
+ = build_decl (OMP_CLAUSE_LOCATION (c),
+ FIELD_DECL, NULL_TREE, ptr_type_node);
+ DECL_ALIGN (field) = TYPE_ALIGN (ptr_type_node);
+ insert_field_into_struct (ctx->record_type, field);
+ splay_tree_insert (ctx->field_map, (splay_tree_key) decl,
+ (splay_tree_value) field);
+ }
+ }
+ break;
+
case OMP_CLAUSE_NOWAIT:
case OMP_CLAUSE_ORDERED:
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:
gcc_unreachable ();
}
@@ -1541,24 +1685,71 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
break;
case OMP_CLAUSE_SHARED:
+ /* Ignore shared directives in teams construct. */
+ if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS)
+ break;
decl = OMP_CLAUSE_DECL (c);
if (! is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx)))
fixup_remapped_decl (decl, ctx, false);
break;
+ case OMP_CLAUSE_MAP:
+ if (gimple_omp_target_kind (ctx->stmt) == GF_OMP_TARGET_KIND_DATA)
+ break;
+ decl = OMP_CLAUSE_DECL (c);
+ if (DECL_P (decl)
+ && is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx))
+ && lookup_attribute ("omp declare target",
+ DECL_ATTRIBUTES (decl)))
+ break;
+ if (DECL_P (decl))
+ {
+ if (OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER
+ && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
+ && !COMPLETE_TYPE_P (TREE_TYPE (decl)))
+ {
+ tree new_decl = lookup_decl (decl, ctx);
+ TREE_TYPE (new_decl)
+ = remap_type (TREE_TYPE (decl), &ctx->cb);
+ }
+ else if (DECL_SIZE (decl)
+ && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
+ {
+ tree decl2 = DECL_VALUE_EXPR (decl);
+ gcc_assert (TREE_CODE (decl2) == INDIRECT_REF);
+ decl2 = TREE_OPERAND (decl2, 0);
+ gcc_assert (DECL_P (decl2));
+ fixup_remapped_decl (decl2, ctx, false);
+ fixup_remapped_decl (decl, ctx, true);
+ }
+ else
+ fixup_remapped_decl (decl, ctx, false);
+ }
+ break;
+
case OMP_CLAUSE_COPYPRIVATE:
case OMP_CLAUSE_COPYIN:
case OMP_CLAUSE_DEFAULT:
case OMP_CLAUSE_IF:
case OMP_CLAUSE_NUM_THREADS:
+ case OMP_CLAUSE_NUM_TEAMS:
+ case OMP_CLAUSE_THREAD_LIMIT:
+ case OMP_CLAUSE_DEVICE:
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_:
+ case OMP_CLAUSE_TO:
+ case OMP_CLAUSE_FROM:
break;
default:
@@ -1623,6 +1814,26 @@ create_omp_child_function (omp_context *ctx, bool task_copy)
DECL_EXTERNAL (decl) = 0;
DECL_CONTEXT (decl) = NULL_TREE;
DECL_INITIAL (decl) = make_node (BLOCK);
+ bool target_p = false;
+ if (lookup_attribute ("omp declare target",
+ DECL_ATTRIBUTES (current_function_decl)))
+ target_p = true;
+ else
+ {
+ omp_context *octx;
+ for (octx = ctx; octx; octx = octx->outer)
+ if (gimple_code (octx->stmt) == GIMPLE_OMP_TARGET
+ && gimple_omp_target_kind (octx->stmt)
+ == GF_OMP_TARGET_KIND_REGION)
+ {
+ target_p = true;
+ break;
+ }
+ }
+ if (target_p)
+ DECL_ATTRIBUTES (decl)
+ = tree_cons (get_identifier ("omp declare target"),
+ NULL_TREE, DECL_ATTRIBUTES (decl));
t = build_decl (DECL_SOURCE_LOCATION (decl),
RESULT_DECL, NULL_TREE, void_type_node);
@@ -1664,6 +1875,35 @@ create_omp_child_function (omp_context *ctx, bool task_copy)
pop_cfun ();
}
+/* 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
@@ -1684,6 +1924,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;
@@ -1858,6 +2132,63 @@ scan_omp_single (gimple stmt, omp_context *outer_ctx)
layout_type (ctx->record_type);
}
+/* Scan an OpenMP target{, data, update} directive. */
+
+static void
+scan_omp_target (gimple stmt, omp_context *outer_ctx)
+{
+ omp_context *ctx;
+ tree name;
+ int kind = gimple_omp_target_kind (stmt);
+
+ ctx = new_omp_context (stmt, outer_ctx);
+ ctx->field_map = splay_tree_new (splay_tree_compare_pointers, 0, 0);
+ ctx->default_kind = OMP_CLAUSE_DEFAULT_SHARED;
+ ctx->record_type = lang_hooks.types.make_type (RECORD_TYPE);
+ name = create_tmp_var_name (".omp_data_t");
+ name = build_decl (gimple_location (stmt),
+ TYPE_DECL, name, ctx->record_type);
+ DECL_ARTIFICIAL (name) = 1;
+ DECL_NAMELESS (name) = 1;
+ TYPE_NAME (ctx->record_type) = name;
+ if (kind == GF_OMP_TARGET_KIND_REGION)
+ {
+ create_omp_child_function (ctx, false);
+ gimple_omp_target_set_child_fn (stmt, ctx->cb.dst_fn);
+ }
+
+ scan_sharing_clauses (gimple_omp_target_clauses (stmt), ctx);
+ scan_omp (gimple_omp_body_ptr (stmt), ctx);
+
+ if (TYPE_FIELDS (ctx->record_type) == NULL)
+ ctx->record_type = ctx->receiver_decl = NULL;
+ else
+ {
+ TYPE_FIELDS (ctx->record_type)
+ = nreverse (TYPE_FIELDS (ctx->record_type));
+#ifdef ENABLE_CHECKING
+ tree field;
+ unsigned int align = DECL_ALIGN (TYPE_FIELDS (ctx->record_type));
+ for (field = TYPE_FIELDS (ctx->record_type);
+ field;
+ field = DECL_CHAIN (field))
+ gcc_assert (DECL_ALIGN (field) == align);
+#endif
+ layout_type (ctx->record_type);
+ if (kind == GF_OMP_TARGET_KIND_REGION)
+ fixup_child_record_type (ctx);
+ }
+}
+
+/* Scan an OpenMP teams directive. */
+
+static void
+scan_omp_teams (gimple stmt, omp_context *outer_ctx)
+{
+ omp_context *ctx = new_omp_context (stmt, outer_ctx);
+ scan_sharing_clauses (gimple_omp_teams_clauses (stmt), ctx);
+ scan_omp (gimple_omp_body_ptr (stmt), ctx);
+}
/* Check OpenMP nesting restrictions. */
static bool
@@ -1872,16 +2203,149 @@ check_omp_nesting_restrictions (gimple stmt, omp_context *ctx)
"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 (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_CALL:
+ if (is_gimple_call (stmt)
+ && (DECL_FUNCTION_CODE (gimple_call_fndecl (stmt))
+ == BUILT_IN_GOMP_CANCEL
+ || DECL_FUNCTION_CODE (gimple_call_fndecl (stmt))
+ == BUILT_IN_GOMP_CANCELLATION_POINT))
+ {
+ const char *bad = NULL;
+ const char *kind = NULL;
+ if (ctx == NULL)
+ {
+ error_at (gimple_location (stmt), "orphaned %qs construct",
+ DECL_FUNCTION_CODE (gimple_call_fndecl (stmt))
+ == BUILT_IN_GOMP_CANCEL
+ ? "#pragma omp cancel"
+ : "#pragma omp cancellation point");
+ return false;
+ }
+ switch (host_integerp (gimple_call_arg (stmt, 0), 0)
+ ? tree_low_cst (gimple_call_arg (stmt, 0), 0)
+ : 0)
+ {
+ case 1:
+ if (gimple_code (ctx->stmt) != GIMPLE_OMP_PARALLEL)
+ bad = "#pragma omp parallel";
+ else if (DECL_FUNCTION_CODE (gimple_call_fndecl (stmt))
+ == BUILT_IN_GOMP_CANCEL
+ && !integer_zerop (gimple_call_arg (stmt, 1)))
+ ctx->cancellable = true;
+ kind = "parallel";
+ break;
+ case 2:
+ if (gimple_code (ctx->stmt) != GIMPLE_OMP_FOR
+ || gimple_omp_for_kind (ctx->stmt) != GF_OMP_FOR_KIND_FOR)
+ bad = "#pragma omp for";
+ else if (DECL_FUNCTION_CODE (gimple_call_fndecl (stmt))
+ == BUILT_IN_GOMP_CANCEL
+ && !integer_zerop (gimple_call_arg (stmt, 1)))
+ {
+ ctx->cancellable = true;
+ if (find_omp_clause (gimple_omp_for_clauses (ctx->stmt),
+ OMP_CLAUSE_NOWAIT))
+ warning_at (gimple_location (stmt), 0,
+ "%<#pragma omp cancel for%> inside "
+ "%<nowait%> for construct");
+ if (find_omp_clause (gimple_omp_for_clauses (ctx->stmt),
+ OMP_CLAUSE_ORDERED))
+ warning_at (gimple_location (stmt), 0,
+ "%<#pragma omp cancel for%> inside "
+ "%<ordered%> for construct");
+ }
+ kind = "for";
+ break;
+ case 4:
+ if (gimple_code (ctx->stmt) != GIMPLE_OMP_SECTIONS
+ && gimple_code (ctx->stmt) != GIMPLE_OMP_SECTION)
+ bad = "#pragma omp sections";
+ else if (DECL_FUNCTION_CODE (gimple_call_fndecl (stmt))
+ == BUILT_IN_GOMP_CANCEL
+ && !integer_zerop (gimple_call_arg (stmt, 1)))
+ {
+ if (gimple_code (ctx->stmt) == GIMPLE_OMP_SECTIONS)
+ {
+ ctx->cancellable = true;
+ if (find_omp_clause (gimple_omp_sections_clauses
+ (ctx->stmt),
+ OMP_CLAUSE_NOWAIT))
+ warning_at (gimple_location (stmt), 0,
+ "%<#pragma omp cancel sections%> inside "
+ "%<nowait%> sections construct");
+ }
+ else
+ {
+ gcc_assert (ctx->outer
+ && gimple_code (ctx->outer->stmt)
+ == GIMPLE_OMP_SECTIONS);
+ ctx->outer->cancellable = true;
+ if (find_omp_clause (gimple_omp_sections_clauses
+ (ctx->outer->stmt),
+ OMP_CLAUSE_NOWAIT))
+ warning_at (gimple_location (stmt), 0,
+ "%<#pragma omp cancel sections%> inside "
+ "%<nowait%> sections construct");
+ }
+ }
+ kind = "sections";
+ break;
+ case 8:
+ if (gimple_code (ctx->stmt) != GIMPLE_OMP_TASK)
+ bad = "#pragma omp task";
+ else
+ ctx->cancellable = true;
+ kind = "taskgroup";
+ break;
+ default:
+ error_at (gimple_location (stmt), "invalid arguments");
+ return false;
+ }
+ if (bad)
+ {
+ error_at (gimple_location (stmt),
+ "%<%s %s%> construct not closely nested inside of %qs",
+ DECL_FUNCTION_CODE (gimple_call_fndecl (stmt))
+ == BUILT_IN_GOMP_CANCEL
+ ? "#pragma omp cancel"
+ : "#pragma omp cancellation point", kind, bad);
+ return false;
+ }
+ }
/* FALLTHRU */
case GIMPLE_OMP_SECTIONS:
case GIMPLE_OMP_SINGLE:
- case GIMPLE_CALL:
for (; ctx != NULL; ctx = ctx->outer)
switch (gimple_code (ctx->stmt))
{
@@ -1891,8 +2355,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 "
@@ -1949,7 +2417,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;
}
@@ -1966,6 +2437,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;
}
@@ -2038,23 +2520,33 @@ scan_omp_1_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
input_location = gimple_location (stmt);
/* Check the OpenMP nesting restrictions. */
- if (ctx != NULL)
- {
- bool remove = false;
- if (is_gimple_omp (stmt))
- remove = !check_omp_nesting_restrictions (stmt, ctx);
- 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)
+ bool remove = false;
+ if (is_gimple_omp (stmt))
+ remove = !check_omp_nesting_restrictions (stmt, ctx);
+ else if (is_gimple_call (stmt))
+ {
+ tree fndecl = gimple_call_fndecl (stmt);
+ 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);
- }
- if (remove)
- {
- stmt = gimple_build_nop ();
- gsi_replace (gsi, stmt, false);
- }
+ break;
+ default:
+ break;
+ }
+ }
+ if (remove)
+ {
+ stmt = gimple_build_nop ();
+ gsi_replace (gsi, stmt, false);
}
*handled_ops_p = true;
@@ -2087,12 +2579,21 @@ scan_omp_1_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
case GIMPLE_OMP_SECTION:
case GIMPLE_OMP_MASTER:
+ case GIMPLE_OMP_TASKGROUP:
case GIMPLE_OMP_ORDERED:
case GIMPLE_OMP_CRITICAL:
ctx = new_omp_context (stmt, ctx);
scan_omp (gimple_omp_body_ptr (stmt), ctx);
break;
+ case GIMPLE_OMP_TARGET:
+ scan_omp_target (stmt, ctx);
+ break;
+
+ case GIMPLE_OMP_TEAMS:
+ scan_omp_teams (stmt, ctx);
+ break;
+
case GIMPLE_BIND:
{
tree var;
@@ -2135,10 +2636,15 @@ scan_omp (gimple_seq *body_p, omp_context *ctx)
/* Build a call to GOMP_barrier. */
-static tree
-build_omp_barrier (void)
-{
- return build_call_expr (builtin_decl_explicit (BUILT_IN_GOMP_BARRIER), 0);
+static gimple
+build_omp_barrier (tree lhs)
+{
+ tree fndecl = builtin_decl_explicit (lhs ? BUILT_IN_GOMP_BARRIER_CANCEL
+ : BUILT_IN_GOMP_BARRIER);
+ gimple g = gimple_build_call (fndecl, 0);
+ if (lhs)
+ gimple_call_set_lhs (g, lhs);
+ return g;
}
/* If a context was created for STMT when it was scanned, return it. */
@@ -2299,6 +2805,49 @@ 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
@@ -2362,8 +2911,11 @@ lower_rec_simd_input_clauses (tree new_var, omp_context *ctx, int &max_vf,
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;
+ if (DECL_P (new_var))
+ {
+ SET_DECL_VALUE_EXPR (new_var, lvar);
+ DECL_HAS_VALUE_EXPR_P (new_var) = 1;
+ }
return true;
}
@@ -2374,11 +2926,12 @@ lower_rec_simd_input_clauses (tree new_var, omp_context *ctx, int &max_vf,
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;
+ bool reduction_omp_orig_ref = false;
int pass;
bool is_simd = (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR
&& gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD);
@@ -2398,9 +2951,6 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
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:
@@ -2432,6 +2982,9 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
continue;
break;
case OMP_CLAUSE_SHARED:
+ /* Ignore shared directives in teams construct. */
+ if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS)
+ continue;
if (maybe_lookup_decl (OMP_CLAUSE_DECL (c), ctx) == NULL)
{
gcc_assert (is_global_var (OMP_CLAUSE_DECL (c)));
@@ -2439,9 +2992,16 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
}
case OMP_CLAUSE_FIRSTPRIVATE:
case OMP_CLAUSE_COPYIN:
+ case OMP_CLAUSE_LINEAR:
+ break;
case OMP_CLAUSE_REDUCTION:
+ if (OMP_CLAUSE_REDUCTION_OMP_ORIG_REF (c))
+ reduction_omp_orig_ref = true;
break;
- case OMP_CLAUSE_LINEAR:
+ case OMP_CLAUSE__LOOPTEMP_:
+ /* Handle _looptemp_ clauses only on parallel. */
+ if (fd)
+ continue;
break;
case OMP_CLAUSE_LASTPRIVATE:
if (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c))
@@ -2451,6 +3011,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;
}
@@ -2502,10 +3098,7 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
allocate new backing storage for the new pointer
variable. This allows us to avoid changing all the
code that expects a pointer to something that expects
- a direct variable. Note that this doesn't apply to
- C++, since reference types are disallowed in data
- sharing clauses there, except for NRV optimized
- return values. */
+ a direct variable. */
if (pass == 0)
continue;
@@ -2550,6 +3143,9 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
switch (OMP_CLAUSE_CODE (c))
{
case OMP_CLAUSE_SHARED:
+ /* Ignore shared directives in teams construct. */
+ if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS)
+ continue;
/* Shared global vars are just accessed directly. */
if (is_global_var (new_var))
break;
@@ -2588,19 +3184,20 @@ 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);
+ tree nx;
+ nx = 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
+ if ((TREE_ADDRESSABLE (new_var) || nx || y
|| OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE)
&& lower_rec_simd_input_clauses (new_var, ctx, max_vf,
idx, lane, ivar, lvar))
{
- if (x)
+ if (nx)
x = lang_hooks.decls.omp_clause_default_ctor
(c, unshare_expr (ivar), x);
- if (x)
+ if (nx && x)
gimplify_and_add (x, &llist[0]);
if (y)
{
@@ -2617,8 +3214,8 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
break;
}
}
- if (x)
- gimplify_and_add (x, ilist);
+ if (nx)
+ gimplify_and_add (nx, ilist);
/* FALLTHRU */
do_dtor:
@@ -2661,6 +3258,44 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
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,
@@ -2708,6 +3343,13 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
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:
by_ref = use_pointer_for_field (var, NULL);
x = build_receiver_ref (var, by_ref, ctx);
@@ -2720,19 +3362,89 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
{
tree placeholder = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c);
+ gimple tseq;
x = build_outer_var_ref (var, ctx);
- /* FIXME: Not handled yet. */
- gcc_assert (!is_simd);
- if (is_reference (var))
+ if (is_reference (var)
+ && !useless_type_conversion_p (TREE_TYPE (placeholder),
+ TREE_TYPE (x)))
x = build_fold_addr_expr_loc (clause_loc, x);
SET_DECL_VALUE_EXPR (placeholder, x);
DECL_HAS_VALUE_EXPR_P (placeholder) = 1;
- lower_omp (&OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c), ctx);
- gimple_seq_add_seq (ilist,
- OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c));
+ tree new_vard = new_var;
+ if (is_reference (var))
+ {
+ gcc_assert (TREE_CODE (new_var) == MEM_REF);
+ new_vard = TREE_OPERAND (new_var, 0);
+ gcc_assert (DECL_P (new_vard));
+ }
+ if (is_simd
+ && lower_rec_simd_input_clauses (new_var, ctx, max_vf,
+ idx, lane, ivar, lvar))
+ {
+ if (new_vard == new_var)
+ {
+ gcc_assert (DECL_VALUE_EXPR (new_var) == lvar);
+ SET_DECL_VALUE_EXPR (new_var, ivar);
+ }
+ else
+ {
+ SET_DECL_VALUE_EXPR (new_vard,
+ build_fold_addr_expr (ivar));
+ DECL_HAS_VALUE_EXPR_P (new_vard) = 1;
+ }
+ x = lang_hooks.decls.omp_clause_default_ctor
+ (c, unshare_expr (ivar),
+ build_outer_var_ref (var, ctx));
+ if (x)
+ gimplify_and_add (x, &llist[0]);
+ if (OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c))
+ {
+ tseq = OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c);
+ lower_omp (&tseq, ctx);
+ gimple_seq_add_seq (&llist[0], tseq);
+ }
+ OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c) = NULL;
+ tseq = OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c);
+ lower_omp (&tseq, ctx);
+ gimple_seq_add_seq (&llist[1], tseq);
+ OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c) = NULL;
+ DECL_HAS_VALUE_EXPR_P (placeholder) = 0;
+ if (new_vard == new_var)
+ SET_DECL_VALUE_EXPR (new_var, lvar);
+ else
+ SET_DECL_VALUE_EXPR (new_vard,
+ build_fold_addr_expr (lvar));
+ x = lang_hooks.decls.omp_clause_dtor (c, ivar);
+ if (x)
+ {
+ tseq = NULL;
+ dtor = x;
+ gimplify_stmt (&dtor, &tseq);
+ gimple_seq_add_seq (&llist[1], tseq);
+ }
+ break;
+ }
+ x = lang_hooks.decls.omp_clause_default_ctor
+ (c, new_var, unshare_expr (x));
+ if (x)
+ gimplify_and_add (x, ilist);
+ if (OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c))
+ {
+ tseq = OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c);
+ lower_omp (&tseq, ctx);
+ gimple_seq_add_seq (ilist, tseq);
+ }
OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c) = NULL;
+ if (is_simd)
+ {
+ tseq = OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c);
+ lower_omp (&tseq, ctx);
+ gimple_seq_add_seq (dlist, tseq);
+ OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c) = NULL;
+ }
DECL_HAS_VALUE_EXPR_P (placeholder) = 0;
+ goto do_dtor;
}
else
{
@@ -2835,14 +3547,15 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
master thread doesn't modify it before it is copied over in all
threads. Similarly for variables in both firstprivate and
lastprivate clauses we need to ensure the lastprivate copying
- happens after firstprivate copying in all threads. */
- if (copyin_by_ref || lastprivate_firstprivate)
+ happens after firstprivate copying in all threads. And similarly
+ for UDRs if initializer expression refers to omp_orig. */
+ if (copyin_by_ref || lastprivate_firstprivate || reduction_omp_orig_ref)
{
/* 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);
+ gimple_seq_add_stmt (ilist, build_omp_barrier (NULL_TREE));
}
/* If max_vf is non-zero, then we can use only a vectorization factor
@@ -2871,7 +3584,7 @@ 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, orig_clauses = clauses;
bool par_clauses = false;
@@ -3025,7 +3738,7 @@ lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp, omp_context *ctx)
{
if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
{
- /* Never use OMP_ATOMIC for array reductions. */
+ /* Never use OMP_ATOMIC for array reductions or UDRs. */
count = -1;
break;
}
@@ -3072,7 +3785,9 @@ lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp, omp_context *ctx)
{
tree placeholder = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c);
- if (is_reference (var))
+ if (is_reference (var)
+ && !useless_type_conversion_p (TREE_TYPE (placeholder),
+ TREE_TYPE (ref)))
ref = build_fold_addr_expr_loc (clause_loc, ref);
SET_DECL_VALUE_EXPR (placeholder, ref);
DECL_HAS_VALUE_EXPR_P (placeholder) = 1;
@@ -3175,6 +3890,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;
@@ -3195,6 +3911,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;
@@ -3317,7 +4034,7 @@ static void
expand_parallel_call (struct omp_region *region, basic_block bb,
gimple entry_stmt, vec<tree, va_gc> *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;
@@ -3327,23 +4044,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 ();
@@ -3354,6 +4071,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)
@@ -3368,6 +4086,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);
@@ -3459,34 +4181,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);
}
@@ -3496,7 +4203,7 @@ expand_parallel_call (struct omp_region *region, basic_block bb,
static void
expand_task_call (basic_block bb, gimple entry_stmt)
{
- tree t, t1, t2, t3, flags, cond, c, c2, clauses;
+ tree t, t1, t2, t3, flags, cond, c, c2, clauses, depend;
gimple_stmt_iterator gsi;
location_t loc = gimple_location (entry_stmt);
@@ -3510,8 +4217,9 @@ expand_task_call (basic_block bb, gimple entry_stmt)
c = find_omp_clause (clauses, OMP_CLAUSE_UNTIED);
c2 = find_omp_clause (clauses, OMP_CLAUSE_MERGEABLE);
+ depend = find_omp_clause (clauses, OMP_CLAUSE_DEPEND);
flags = build_int_cst (unsigned_type_node,
- (c ? 1 : 0) + (c2 ? 4 : 0));
+ (c ? 1 : 0) + (c2 ? 4 : 0) + (depend ? 8 : 0));
c = find_omp_clause (clauses, OMP_CLAUSE_FINAL);
if (c)
@@ -3522,6 +4230,10 @@ expand_task_call (basic_block bb, gimple entry_stmt)
build_int_cst (unsigned_type_node, 0));
flags = fold_build2_loc (loc, PLUS_EXPR, unsigned_type_node, flags, c);
}
+ if (depend)
+ depend = OMP_CLAUSE_DECL (depend);
+ else
+ depend = build_int_cst (ptr_type_node, 0);
gsi = gsi_last_bb (bb);
t = gimple_omp_task_data_arg (entry_stmt);
@@ -3537,9 +4249,10 @@ expand_task_call (basic_block bb, gimple entry_stmt)
t3 = build_fold_addr_expr_loc (loc, t);
t = build_call_expr (builtin_decl_explicit (BUILT_IN_GOMP_TASK),
- 7, t1, t2, t3,
+ 8, t1, t2, t3,
gimple_omp_task_arg_size (entry_stmt),
- gimple_omp_task_arg_align (entry_stmt), cond, flags);
+ gimple_omp_task_arg_align (entry_stmt), cond, flags,
+ depend);
force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
false, GSI_CONTINUE_LINKING);
@@ -4064,7 +4777,9 @@ expand_omp_taskreg (struct omp_region *region)
count = count1 * count2 * count3;
Furthermore, if ZERO_ITER_BB is NULL, create a BB which does:
count = 0;
- and set ZERO_ITER_BB to that bb. */
+ 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. */
/* NOTE: It *could* be better to moosh all of the BBs together,
creating one larger BB with all the computation and the unexpected
@@ -4106,6 +4821,28 @@ expand_omp_for_init_counts (struct omp_for_data *fd, gimple_stmt_iterator *gsi,
/* Collapsed loops need work for expansion into 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);
@@ -4209,13 +4946,49 @@ expand_omp_for_init_counts (struct omp_for_data *fd, gimple_stmt_iterator *gsi,
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 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, tree startvar)
+ 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);
@@ -4368,6 +5141,10 @@ extract_omp_for_update_vars (struct omp_for_data *fd, basic_block cont_bb,
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)
@@ -4437,7 +5214,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;
@@ -4552,6 +5330,17 @@ expand_omp_for_generic (struct omp_region *region,
t2 = fold_convert (fd->iter_type, fd->loop.step);
t1 = fd->loop.n2;
t0 = fd->loop.n1;
+ if (gimple_omp_for_combined_into_p (fd->for_stmt))
+ {
+ tree innerc = find_omp_clause (gimple_omp_for_clauses (fd->for_stmt),
+ OMP_CLAUSE__LOOPTEMP_);
+ gcc_assert (innerc);
+ t0 = OMP_CLAUSE_DECL (innerc);
+ innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc),
+ OMP_CLAUSE__LOOPTEMP_);
+ gcc_assert (innerc);
+ t1 = OMP_CLAUSE_DECL (innerc);
+ }
if (POINTER_TYPE_P (TREE_TYPE (t0))
&& TYPE_PRECISION (TREE_TYPE (t0))
!= TYPE_PRECISION (fd->iter_type))
@@ -4622,6 +5411,21 @@ expand_omp_for_generic (struct omp_region *region,
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)
@@ -4650,7 +5454,7 @@ expand_omp_for_generic (struct omp_region *region,
gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
}
if (fd->collapse > 1)
- expand_omp_for_init_vars (fd, &gsi, counts, startvar);
+ expand_omp_for_init_vars (fd, &gsi, counts, inner_stmt, startvar);
if (!broken_loop)
{
@@ -4662,8 +5466,7 @@ expand_omp_for_generic (struct omp_region *region,
vmain = gimple_omp_continue_control_use (stmt);
vback = gimple_omp_continue_control_def (stmt);
- /* OMP4 placeholder: if (!gimple_omp_for_combined_p (fd->for_stmt)). */
- if (1)
+ if (!gimple_omp_for_combined_p (fd->for_stmt))
{
if (POINTER_TYPE_P (type))
t = fold_build_pointer_plus (vmain, fd->loop.step);
@@ -4686,7 +5489,7 @@ expand_omp_for_generic (struct omp_region *region,
/* Remove GIMPLE_OMP_CONTINUE. */
gsi_remove (&gsi, true);
- if (fd->collapse > 1)
+ 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. */
@@ -4708,9 +5511,13 @@ expand_omp_for_generic (struct omp_region *region,
gsi = gsi_last_bb (exit_bb);
if (gimple_omp_return_nowait_p (gsi_stmt (gsi)))
t = builtin_decl_explicit (BUILT_IN_GOMP_LOOP_END_NOWAIT);
+ else if (gimple_omp_return_lhs (gsi_stmt (gsi)))
+ t = builtin_decl_explicit (BUILT_IN_GOMP_LOOP_END_CANCEL);
else
t = builtin_decl_explicit (BUILT_IN_GOMP_LOOP_END);
stmt = gimple_build_call (t, 0);
+ if (gimple_omp_return_lhs (gsi_stmt (gsi)))
+ gimple_call_set_lhs (stmt, gimple_omp_return_lhs (gsi_stmt (gsi)));
gsi_insert_after (&gsi, stmt, GSI_SAME_STMT);
gsi_remove (&gsi, true);
@@ -4738,9 +5545,11 @@ expand_omp_for_generic (struct omp_region *region,
if (current_loops)
add_bb_to_loop (l2_bb, cont_bb->loop_father);
e = find_edge (cont_bb, l1_bb);
- /* OMP4 placeholder for gimple_omp_for_combined_p (fd->for_stmt). */
- if (0)
- ;
+ if (gimple_omp_for_combined_p (fd->for_stmt))
+ {
+ remove_edge (e);
+ e = NULL;
+ }
else if (fd->collapse > 1)
{
remove_edge (e);
@@ -4774,8 +5583,7 @@ expand_omp_for_generic (struct omp_region *region,
outer_loop->latch = l2_bb;
add_loop (outer_loop, l0_bb->loop_father);
- /* OMP4 placeholder: if (!gimple_omp_for_combined_p (fd->for_stmt)). */
- if (1)
+ if (!gimple_omp_for_combined_p (fd->for_stmt))
{
struct loop *loop = alloc_loop ();
loop->header = l1_bb;
@@ -4825,16 +5633,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))
@@ -4843,25 +5657,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);
@@ -4899,36 +5737,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);
@@ -4976,58 +5825,96 @@ 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)))
- force_gimple_operand_gsi (&gsi, build_omp_barrier (), false, NULL_TREE,
- false, GSI_SAME_STMT);
+ {
+ t = gimple_omp_return_lhs (gsi_stmt (gsi));
+ gsi_insert_after (&gsi, build_omp_barrier (t), GSI_SAME_STMT);
+ }
gsi_remove (&gsi, true);
/* Connect all the blocks. */
@@ -5039,21 +5926,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);
+ }
}
@@ -5096,16 +6004,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))
@@ -5117,27 +6031,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);
@@ -5175,39 +6112,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);
@@ -5230,11 +6178,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);
@@ -5261,77 +6209,130 @@ 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)))
- force_gimple_operand_gsi (&si, build_omp_barrier (), false, NULL_TREE,
- false, GSI_SAME_STMT);
+ {
+ t = gimple_omp_return_lhs (gsi_stmt (si));
+ gsi_insert_after (&si, build_omp_barrier (t), GSI_SAME_STMT);
+ }
gsi_remove (&si, true);
/* Connect the new blocks. */
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))
{
@@ -5342,6 +6343,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. */
@@ -5391,7 +6394,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,
@@ -5401,17 +6405,24 @@ 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:
@@ -5487,7 +6498,7 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd)
OMP_CLAUSE_SAFELEN);
tree simduid = find_omp_clause (gimple_omp_for_clauses (fd->for_stmt),
OMP_CLAUSE__SIMDUID_);
- tree n2;
+ tree n1, n2;
type = TREE_TYPE (fd->loop.v);
entry_bb = region->entry;
@@ -5530,10 +6541,27 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd)
if (l2_dom_bb == NULL)
l2_dom_bb = l1_bb;
+ n1 = fd->loop.n1;
n2 = fd->loop.n2;
- if (0)
- /* Place holder for gimple_omp_for_combined_into_p() in
- the upcoming gomp-4_0-branch merge. */;
+ 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,
@@ -5706,7 +6734,7 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd)
/* 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;
@@ -5736,14 +6764,12 @@ expand_omp_for (struct omp_region *region)
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
- && fd.collapse == 1
- && region->cont != NULL)
+ && !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
{
@@ -5768,7 +6794,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))
@@ -5983,9 +7009,13 @@ expand_omp_sections (struct omp_region *region)
si = gsi_last_bb (l2_bb);
if (gimple_omp_return_nowait_p (gsi_stmt (si)))
t = builtin_decl_explicit (BUILT_IN_GOMP_SECTIONS_END_NOWAIT);
+ else if (gimple_omp_return_lhs (gsi_stmt (si)))
+ t = builtin_decl_explicit (BUILT_IN_GOMP_SECTIONS_END_CANCEL);
else
t = builtin_decl_explicit (BUILT_IN_GOMP_SECTIONS_END);
stmt = gimple_build_call (t, 0);
+ if (gimple_omp_return_lhs (gsi_stmt (si)))
+ gimple_call_set_lhs (stmt, gimple_omp_return_lhs (gsi_stmt (si)));
gsi_insert_after (&si, stmt, GSI_SAME_STMT);
gsi_remove (&si, true);
@@ -6001,26 +7031,21 @@ expand_omp_single (struct omp_region *region)
{
basic_block entry_bb, exit_bb;
gimple_stmt_iterator si;
- bool need_barrier = false;
entry_bb = region->entry;
exit_bb = region->exit;
si = gsi_last_bb (entry_bb);
- /* The terminal barrier at the end of a GOMP_single_copy sequence cannot
- be removed. We need to ensure that the thread that entered the single
- does not exit before the data is copied out by the other threads. */
- if (find_omp_clause (gimple_omp_single_clauses (gsi_stmt (si)),
- OMP_CLAUSE_COPYPRIVATE))
- need_barrier = true;
gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SINGLE);
gsi_remove (&si, true);
single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
si = gsi_last_bb (exit_bb);
- if (!gimple_omp_return_nowait_p (gsi_stmt (si)) || need_barrier)
- force_gimple_operand_gsi (&si, build_omp_barrier (), false, NULL_TREE,
- false, GSI_SAME_STMT);
+ if (!gimple_omp_return_nowait_p (gsi_stmt (si)))
+ {
+ tree t = gimple_omp_return_lhs (gsi_stmt (si));
+ gsi_insert_after (&si, build_omp_barrier (t), GSI_SAME_STMT);
+ }
gsi_remove (&si, true);
single_succ_edge (exit_bb)->flags = EDGE_FALLTHRU;
}
@@ -6042,8 +7067,10 @@ expand_omp_synch (struct omp_region *region)
si = gsi_last_bb (entry_bb);
gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SINGLE
|| gimple_code (gsi_stmt (si)) == GIMPLE_OMP_MASTER
+ || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_TASKGROUP
|| gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ORDERED
- || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_CRITICAL);
+ || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_CRITICAL
+ || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_TEAMS);
gsi_remove (&si, true);
single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
@@ -6088,7 +7115,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);
@@ -6160,7 +7190,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))
@@ -6201,6 +7234,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:
@@ -6226,6 +7260,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))
@@ -6292,7 +7327,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)
{
@@ -6622,6 +7659,321 @@ expand_omp_atomic (struct omp_region *region)
}
+/* Expand the OpenMP target{, data, update} directive starting at REGION. */
+
+static void
+expand_omp_target (struct omp_region *region)
+{
+ basic_block entry_bb, exit_bb, new_bb;
+ struct function *child_cfun = NULL;
+ tree child_fn = NULL_TREE, block, t;
+ gimple_stmt_iterator gsi;
+ gimple entry_stmt, stmt;
+ edge e;
+
+ entry_stmt = last_stmt (region->entry);
+ new_bb = region->entry;
+ int kind = gimple_omp_target_kind (entry_stmt);
+ if (kind == GF_OMP_TARGET_KIND_REGION)
+ {
+ child_fn = gimple_omp_target_child_fn (entry_stmt);
+ child_cfun = DECL_STRUCT_FUNCTION (child_fn);
+ }
+
+ entry_bb = region->entry;
+ exit_bb = region->exit;
+
+ if (kind == GF_OMP_TARGET_KIND_REGION)
+ {
+ unsigned srcidx, dstidx, num;
+
+ /* If the target region needs data sent from the parent
+ function, then the very first statement (except possible
+ tree profile counter updates) of the parallel body
+ is a copy assignment .OMP_DATA_I = &.OMP_DATA_O. Since
+ &.OMP_DATA_O is passed as an argument to the child function,
+ we need to replace it with the argument as seen by the child
+ function.
+
+ In most cases, this will end up being the identity assignment
+ .OMP_DATA_I = .OMP_DATA_I. However, if the parallel body had
+ a function call that has been inlined, the original PARM_DECL
+ .OMP_DATA_I may have been converted into a different local
+ variable. In which case, we need to keep the assignment. */
+ if (gimple_omp_target_data_arg (entry_stmt))
+ {
+ basic_block entry_succ_bb = single_succ (entry_bb);
+ gimple_stmt_iterator gsi;
+ tree arg;
+ gimple tgtcopy_stmt = NULL;
+ tree sender
+ = TREE_VEC_ELT (gimple_omp_target_data_arg (entry_stmt), 0);
+
+ for (gsi = gsi_start_bb (entry_succ_bb); ; gsi_next (&gsi))
+ {
+ gcc_assert (!gsi_end_p (gsi));
+ stmt = gsi_stmt (gsi);
+ if (gimple_code (stmt) != GIMPLE_ASSIGN)
+ continue;
+
+ if (gimple_num_ops (stmt) == 2)
+ {
+ tree arg = gimple_assign_rhs1 (stmt);
+
+ /* We're ignoring the subcode because we're
+ effectively doing a STRIP_NOPS. */
+
+ if (TREE_CODE (arg) == ADDR_EXPR
+ && TREE_OPERAND (arg, 0) == sender)
+ {
+ tgtcopy_stmt = stmt;
+ break;
+ }
+ }
+ }
+
+ gcc_assert (tgtcopy_stmt != NULL);
+ arg = DECL_ARGUMENTS (child_fn);
+
+ gcc_assert (gimple_assign_lhs (tgtcopy_stmt) == arg);
+ gsi_remove (&gsi, true);
+ }
+
+ /* Declare local variables needed in CHILD_CFUN. */
+ block = DECL_INITIAL (child_fn);
+ BLOCK_VARS (block) = vec2chain (child_cfun->local_decls);
+ /* The gimplifier could record temporaries in target block
+ rather than in containing function's local_decls chain,
+ which would mean cgraph missed finalizing them. Do it now. */
+ for (t = BLOCK_VARS (block); t; t = DECL_CHAIN (t))
+ if (TREE_CODE (t) == VAR_DECL
+ && TREE_STATIC (t)
+ && !DECL_EXTERNAL (t))
+ varpool_finalize_decl (t);
+ DECL_SAVED_TREE (child_fn) = NULL;
+ /* We'll create a CFG for child_fn, so no gimple body is needed. */
+ gimple_set_body (child_fn, NULL);
+ TREE_USED (block) = 1;
+
+ /* Reset DECL_CONTEXT on function arguments. */
+ for (t = DECL_ARGUMENTS (child_fn); t; t = DECL_CHAIN (t))
+ DECL_CONTEXT (t) = child_fn;
+
+ /* Split ENTRY_BB at GIMPLE_OMP_TARGET,
+ so that it can be moved to the child function. */
+ gsi = gsi_last_bb (entry_bb);
+ stmt = gsi_stmt (gsi);
+ gcc_assert (stmt && gimple_code (stmt) == GIMPLE_OMP_TARGET
+ && gimple_omp_target_kind (stmt)
+ == GF_OMP_TARGET_KIND_REGION);
+ gsi_remove (&gsi, true);
+ e = split_block (entry_bb, stmt);
+ entry_bb = e->dest;
+ single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
+
+ /* Convert GIMPLE_OMP_RETURN into a RETURN_EXPR. */
+ if (exit_bb)
+ {
+ gsi = gsi_last_bb (exit_bb);
+ gcc_assert (!gsi_end_p (gsi)
+ && gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
+ stmt = gimple_build_return (NULL);
+ gsi_insert_after (&gsi, stmt, GSI_SAME_STMT);
+ gsi_remove (&gsi, true);
+ }
+
+ /* Move the target region into CHILD_CFUN. */
+
+ block = gimple_block (entry_stmt);
+
+ new_bb = move_sese_region_to_fn (child_cfun, entry_bb, exit_bb, block);
+ if (exit_bb)
+ single_succ_edge (new_bb)->flags = EDGE_FALLTHRU;
+ /* When the OMP expansion process cannot guarantee an up-to-date
+ loop tree arrange for the child function to fixup loops. */
+ if (loops_state_satisfies_p (LOOPS_NEED_FIXUP))
+ child_cfun->x_current_loops->state |= LOOPS_NEED_FIXUP;
+
+ /* Remove non-local VAR_DECLs from child_cfun->local_decls list. */
+ num = vec_safe_length (child_cfun->local_decls);
+ for (srcidx = 0, dstidx = 0; srcidx < num; srcidx++)
+ {
+ t = (*child_cfun->local_decls)[srcidx];
+ if (DECL_CONTEXT (t) == cfun->decl)
+ continue;
+ if (srcidx != dstidx)
+ (*child_cfun->local_decls)[dstidx] = t;
+ dstidx++;
+ }
+ if (dstidx != num)
+ vec_safe_truncate (child_cfun->local_decls, dstidx);
+
+ /* Inform the callgraph about the new function. */
+ DECL_STRUCT_FUNCTION (child_fn)->curr_properties = cfun->curr_properties;
+ cgraph_add_new_function (child_fn, true);
+
+ /* Fix the callgraph edges for child_cfun. Those for cfun will be
+ fixed in a following pass. */
+ push_cfun (child_cfun);
+ rebuild_cgraph_edges ();
+
+ /* Some EH regions might become dead, see PR34608. If
+ pass_cleanup_cfg isn't the first pass to happen with the
+ new child, these dead EH edges might cause problems.
+ Clean them up now. */
+ if (flag_exceptions)
+ {
+ basic_block bb;
+ bool changed = false;
+
+ FOR_EACH_BB (bb)
+ changed |= gimple_purge_dead_eh_edges (bb);
+ if (changed)
+ cleanup_tree_cfg ();
+ }
+ pop_cfun ();
+ }
+
+ /* Emit a library call to launch the target region, or do data
+ transfers. */
+ tree t1, t2, t3, t4, device, cond, c, clauses;
+ enum built_in_function start_ix;
+ location_t clause_loc;
+
+ clauses = gimple_omp_target_clauses (entry_stmt);
+
+ if (kind == GF_OMP_TARGET_KIND_REGION)
+ start_ix = BUILT_IN_GOMP_TARGET;
+ else if (kind == GF_OMP_TARGET_KIND_DATA)
+ start_ix = BUILT_IN_GOMP_TARGET_DATA;
+ else
+ start_ix = BUILT_IN_GOMP_TARGET_UPDATE;
+
+ /* By default, the value of DEVICE is -1 (let runtime library choose)
+ and there is no conditional. */
+ cond = NULL_TREE;
+ device = build_int_cst (integer_type_node, -1);
+
+ c = find_omp_clause (clauses, OMP_CLAUSE_IF);
+ if (c)
+ cond = OMP_CLAUSE_IF_EXPR (c);
+
+ c = find_omp_clause (clauses, OMP_CLAUSE_DEVICE);
+ if (c)
+ {
+ device = OMP_CLAUSE_DEVICE_ID (c);
+ clause_loc = OMP_CLAUSE_LOCATION (c);
+ }
+ else
+ clause_loc = gimple_location (entry_stmt);
+
+ /* Ensure 'device' is of the correct type. */
+ device = fold_convert_loc (clause_loc, integer_type_node, device);
+
+ /* If we found the clause 'if (cond)', build
+ (cond ? device : -2). */
+ if (cond)
+ {
+ cond = gimple_boolify (cond);
+
+ basic_block cond_bb, then_bb, else_bb;
+ edge e;
+ tree tmp_var;
+
+ tmp_var = create_tmp_var (TREE_TYPE (device), NULL);
+ if (kind != GF_OMP_TARGET_KIND_REGION)
+ {
+ gsi = gsi_last_bb (new_bb);
+ gsi_prev (&gsi);
+ e = split_block (new_bb, gsi_stmt (gsi));
+ }
+ else
+ e = split_block (new_bb, NULL);
+ cond_bb = e->src;
+ new_bb = e->dest;
+ remove_edge (e);
+
+ then_bb = create_empty_bb (cond_bb);
+ else_bb = create_empty_bb (then_bb);
+ set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);
+ set_immediate_dominator (CDI_DOMINATORS, else_bb, cond_bb);
+
+ stmt = gimple_build_cond_empty (cond);
+ gsi = gsi_last_bb (cond_bb);
+ gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
+
+ gsi = gsi_start_bb (then_bb);
+ stmt = gimple_build_assign (tmp_var, device);
+ gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
+
+ gsi = gsi_start_bb (else_bb);
+ stmt = gimple_build_assign (tmp_var,
+ build_int_cst (integer_type_node, -2));
+ gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
+
+ make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE);
+ make_edge (cond_bb, else_bb, EDGE_FALSE_VALUE);
+ if (current_loops)
+ {
+ add_bb_to_loop (then_bb, cond_bb->loop_father);
+ add_bb_to_loop (else_bb, cond_bb->loop_father);
+ }
+ make_edge (then_bb, new_bb, EDGE_FALLTHRU);
+ make_edge (else_bb, new_bb, EDGE_FALLTHRU);
+
+ device = tmp_var;
+ }
+
+ gsi = gsi_last_bb (new_bb);
+ t = gimple_omp_target_data_arg (entry_stmt);
+ if (t == NULL)
+ {
+ t1 = size_zero_node;
+ t2 = build_zero_cst (ptr_type_node);
+ t3 = t2;
+ t4 = t2;
+ }
+ else
+ {
+ t1 = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (TREE_VEC_ELT (t, 1))));
+ t1 = size_binop (PLUS_EXPR, t1, size_int (1));
+ t2 = build_fold_addr_expr (TREE_VEC_ELT (t, 0));
+ t3 = build_fold_addr_expr (TREE_VEC_ELT (t, 1));
+ t4 = build_fold_addr_expr (TREE_VEC_ELT (t, 2));
+ }
+
+ gimple g;
+ /* FIXME: This will be address of
+ extern char __OPENMP_TARGET__[] __attribute__((visibility ("hidden")))
+ symbol, as soon as the linker plugin is able to create it for us. */
+ tree openmp_target = build_zero_cst (ptr_type_node);
+ if (kind == GF_OMP_TARGET_KIND_REGION)
+ {
+ tree fnaddr = build_fold_addr_expr (child_fn);
+ g = gimple_build_call (builtin_decl_explicit (start_ix), 7,
+ device, fnaddr, openmp_target, t1, t2, t3, t4);
+ }
+ else
+ g = gimple_build_call (builtin_decl_explicit (start_ix), 6,
+ device, openmp_target, t1, t2, t3, t4);
+ gimple_set_location (g, gimple_location (entry_stmt));
+ gsi_insert_before (&gsi, g, GSI_SAME_STMT);
+ if (kind != GF_OMP_TARGET_KIND_REGION)
+ {
+ g = gsi_stmt (gsi);
+ gcc_assert (g && gimple_code (g) == GIMPLE_OMP_TARGET);
+ gsi_remove (&gsi, true);
+ }
+ if (kind == GF_OMP_TARGET_KIND_DATA && region->exit)
+ {
+ gsi = gsi_last_bb (region->exit);
+ g = gsi_stmt (gsi);
+ gcc_assert (g && gimple_code (g) == GIMPLE_OMP_RETURN);
+ gsi_remove (&gsi, true);
+ }
+}
+
+
/* Expand the parallel region tree rooted at REGION. Expansion
proceeds in depth-first order. Innermost regions are expanded
first. This way, parallel regions that require a new function to
@@ -6634,12 +7986,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);
@@ -6655,7 +8012,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:
@@ -6672,8 +8029,10 @@ expand_omp (struct omp_region *region)
break;
case GIMPLE_OMP_MASTER:
+ case GIMPLE_OMP_TASKGROUP:
case GIMPLE_OMP_ORDERED:
case GIMPLE_OMP_CRITICAL:
+ case GIMPLE_OMP_TEAMS:
expand_omp_synch (region);
break;
@@ -6681,6 +8040,10 @@ expand_omp (struct omp_region *region)
expand_omp_atomic (region);
break;
+ case GIMPLE_OMP_TARGET:
+ expand_omp_target (region);
+ break;
+
default:
gcc_unreachable ();
}
@@ -6745,6 +8108,9 @@ build_omp_regions_1 (basic_block bb, struct omp_region *parent,
GIMPLE_OMP_SECTIONS, and we do nothing for it. */
;
}
+ else if (code == GIMPLE_OMP_TARGET
+ && gimple_omp_target_kind (stmt) == GF_OMP_TARGET_KIND_UPDATE)
+ new_omp_region (bb, code, parent);
else
{
/* Otherwise, this directive becomes the parent for a new
@@ -6880,6 +8246,32 @@ make_pass_expand_omp (gcc::context *ctxt)
/* Routines to lower OpenMP directives into OMP-GIMPLE. */
+/* If ctx is a worksharing context inside of a cancellable parallel
+ region and it isn't nowait, add lhs to its GIMPLE_OMP_RETURN
+ and conditional branch to parallel's cancel_label to handle
+ cancellation in the implicit barrier. */
+
+static void
+maybe_add_implicit_barrier_cancel (omp_context *ctx, gimple_seq *body)
+{
+ gimple omp_return = gimple_seq_last_stmt (*body);
+ gcc_assert (gimple_code (omp_return) == GIMPLE_OMP_RETURN);
+ if (gimple_omp_return_nowait_p (omp_return))
+ return;
+ if (ctx->outer
+ && gimple_code (ctx->outer->stmt) == GIMPLE_OMP_PARALLEL
+ && ctx->outer->cancellable)
+ {
+ tree lhs = create_tmp_var (boolean_type_node, NULL);
+ gimple_omp_return_set_lhs (omp_return, lhs);
+ tree fallthru_label = create_artificial_label (UNKNOWN_LOCATION);
+ gimple g = gimple_build_cond (NE_EXPR, lhs, boolean_false_node,
+ ctx->outer->cancel_label, fallthru_label);
+ gimple_seq_add_stmt (body, g);
+ gimple_seq_add_stmt (body, gimple_build_label (fallthru_label));
+ }
+}
+
/* Lower the OpenMP sections directive in the current statement in GSI_P.
CTX is the enclosing OMP context for the current statement. */
@@ -6899,7 +8291,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);
@@ -6959,6 +8351,8 @@ lower_omp_sections (gimple_stmt_iterator *gsi_p, omp_context *ctx)
gimple_seq_add_stmt (&new_body, t);
gimple_seq_add_seq (&new_body, olist);
+ if (ctx->cancellable)
+ gimple_seq_add_stmt (&new_body, gimple_build_label (ctx->cancel_label));
gimple_seq_add_seq (&new_body, dlist);
new_body = maybe_catch_exception (new_body);
@@ -6967,6 +8361,7 @@ lower_omp_sections (gimple_stmt_iterator *gsi_p, omp_context *ctx)
(!!find_omp_clause (gimple_omp_sections_clauses (stmt),
OMP_CLAUSE_NOWAIT));
gimple_seq_add_stmt (&new_body, t);
+ maybe_add_implicit_barrier_cancel (ctx, &new_body);
gimple_bind_set_body (new_stmt, new_body);
}
@@ -7096,7 +8491,7 @@ lower_omp_single (gimple_stmt_iterator *gsi_p, omp_context *ctx)
{
tree block;
gimple t, bind, single_stmt = gsi_stmt (*gsi_p);
- gimple_seq bind_body, dlist;
+ gimple_seq bind_body, bind_body_tail = NULL, dlist;
struct gimplify_ctx gctx;
push_gimplify_context (&gctx);
@@ -7107,7 +8502,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);
@@ -7126,7 +8521,17 @@ lower_omp_single (gimple_stmt_iterator *gsi_p, omp_context *ctx)
t = gimple_build_omp_return
(!!find_omp_clause (gimple_omp_single_clauses (single_stmt),
OMP_CLAUSE_NOWAIT));
- gimple_seq_add_stmt (&bind_body, t);
+ gimple_seq_add_stmt (&bind_body_tail, t);
+ maybe_add_implicit_barrier_cancel (ctx, &bind_body_tail);
+ if (ctx->record_type)
+ {
+ gimple_stmt_iterator gsi = gsi_start (bind_body_tail);
+ tree clobber = build_constructor (ctx->record_type, NULL);
+ TREE_THIS_VOLATILE (clobber) = 1;
+ gsi_insert_after (&gsi, gimple_build_assign (ctx->sender_decl,
+ clobber), GSI_SAME_STMT);
+ }
+ gimple_seq_add_seq (&bind_body, bind_body_tail);
gimple_bind_set_body (bind, bind_body);
pop_gimplify_context (bind);
@@ -7180,6 +8585,33 @@ lower_omp_master (gimple_stmt_iterator *gsi_p, omp_context *ctx)
}
+/* Expand code for an OpenMP taskgroup directive. */
+
+static void
+lower_omp_taskgroup (gimple_stmt_iterator *gsi_p, omp_context *ctx)
+{
+ gimple stmt = gsi_stmt (*gsi_p), bind, x;
+ tree block = make_node (BLOCK);
+
+ bind = gimple_build_bind (NULL, NULL, block);
+ gsi_replace (gsi_p, bind, true);
+ gimple_bind_add_stmt (bind, stmt);
+
+ x = gimple_build_call (builtin_decl_explicit (BUILT_IN_GOMP_TASKGROUP_START),
+ 0);
+ gimple_bind_add_stmt (bind, x);
+
+ lower_omp (gimple_omp_body_ptr (stmt), ctx);
+ gimple_bind_add_seq (bind, gimple_omp_body (stmt));
+ gimple_omp_set_body (stmt, NULL);
+
+ gimple_bind_add_stmt (bind, gimple_build_omp_return (true));
+
+ gimple_bind_append_vars (bind, ctx->block_vars);
+ BLOCK_VARS (block) = ctx->block_vars;
+}
+
+
/* Expand code for an OpenMP ordered directive. */
static void
@@ -7372,7 +8804,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;
@@ -7399,10 +8831,50 @@ 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);
@@ -7442,13 +8914,17 @@ 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);
+
+ if (ctx->cancellable)
+ gimple_seq_add_stmt (&body, gimple_build_label (ctx->cancel_label));
+
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));
-
+ maybe_add_implicit_barrier_cancel (ctx, &body);
pop_gimplify_context (new_stmt);
gimple_bind_append_vars (new_stmt, ctx->block_vars);
@@ -7769,6 +9245,68 @@ create_task_copyfn (gimple task_stmt, omp_context *ctx)
pop_cfun ();
}
+static void
+lower_depend_clauses (gimple stmt, gimple_seq *iseq, gimple_seq *oseq)
+{
+ tree c, clauses;
+ gimple g;
+ size_t n_in = 0, n_out = 0, idx = 2, i;
+
+ clauses = find_omp_clause (gimple_omp_task_clauses (stmt),
+ OMP_CLAUSE_DEPEND);
+ gcc_assert (clauses);
+ for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND)
+ switch (OMP_CLAUSE_DEPEND_KIND (c))
+ {
+ case OMP_CLAUSE_DEPEND_IN:
+ n_in++;
+ break;
+ case OMP_CLAUSE_DEPEND_OUT:
+ case OMP_CLAUSE_DEPEND_INOUT:
+ n_out++;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ tree type = build_array_type_nelts (ptr_type_node, n_in + n_out + 2);
+ tree array = create_tmp_var (type, NULL);
+ tree r = build4 (ARRAY_REF, ptr_type_node, array, size_int (0), NULL_TREE,
+ NULL_TREE);
+ g = gimple_build_assign (r, build_int_cst (ptr_type_node, n_in + n_out));
+ gimple_seq_add_stmt (iseq, g);
+ r = build4 (ARRAY_REF, ptr_type_node, array, size_int (1), NULL_TREE,
+ NULL_TREE);
+ g = gimple_build_assign (r, build_int_cst (ptr_type_node, n_out));
+ gimple_seq_add_stmt (iseq, g);
+ for (i = 0; i < 2; i++)
+ {
+ if ((i ? n_in : n_out) == 0)
+ continue;
+ for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND
+ && ((OMP_CLAUSE_DEPEND_KIND (c) != OMP_CLAUSE_DEPEND_IN) ^ i))
+ {
+ tree t = OMP_CLAUSE_DECL (c);
+ t = fold_convert (ptr_type_node, t);
+ gimplify_expr (&t, iseq, NULL, is_gimple_val, fb_rvalue);
+ r = build4 (ARRAY_REF, ptr_type_node, array, size_int (idx++),
+ NULL_TREE, NULL_TREE);
+ g = gimple_build_assign (r, t);
+ gimple_seq_add_stmt (iseq, g);
+ }
+ }
+ tree *p = gimple_omp_task_clauses_ptr (stmt);
+ c = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE_DEPEND);
+ OMP_CLAUSE_DECL (c) = build_fold_addr_expr (array);
+ OMP_CLAUSE_CHAIN (c) = *p;
+ *p = c;
+ tree clobber = build_constructor (type, NULL);
+ TREE_THIS_VOLATILE (clobber) = 1;
+ g = gimple_build_assign (array, clobber);
+ gimple_seq_add_stmt (oseq, g);
+}
+
/* Lower the OpenMP parallel or task directive in the current statement
in GSI_P. CTX holds context information for the directive. */
@@ -7778,9 +9316,9 @@ lower_omp_taskreg (gimple_stmt_iterator *gsi_p, omp_context *ctx)
tree clauses;
tree child_fn, t;
gimple stmt = gsi_stmt (*gsi_p);
- gimple par_bind, bind;
- gimple_seq par_body, olist, ilist, par_olist, par_ilist, new_body;
- struct gimplify_ctx gctx;
+ gimple par_bind, bind, dep_bind = NULL;
+ gimple_seq par_body, olist, ilist, par_olist, par_rlist, par_ilist, new_body;
+ struct gimplify_ctx gctx, dep_gctx;
location_t loc = gimple_location (stmt);
clauses = gimple_omp_taskreg_clauses (stmt);
@@ -7800,6 +9338,16 @@ lower_omp_taskreg (gimple_stmt_iterator *gsi_p, omp_context *ctx)
if (ws_num == 1)
gimple_omp_parallel_set_combined_p (stmt, true);
}
+ gimple_seq dep_ilist = NULL;
+ gimple_seq dep_olist = NULL;
+ if (gimple_code (stmt) == GIMPLE_OMP_TASK
+ && find_omp_clause (clauses, OMP_CLAUSE_DEPEND))
+ {
+ push_gimplify_context (&dep_gctx);
+ dep_bind = gimple_build_bind (NULL, NULL, make_node (BLOCK));
+ lower_depend_clauses (stmt, &dep_ilist, &dep_olist);
+ }
+
if (ctx->srecord_type)
create_task_copyfn (stmt, ctx);
@@ -7807,10 +9355,11 @@ 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);
+ par_rlist = NULL;
+ 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);
+ lower_reduction_clauses (clauses, &par_rlist, ctx);
/* Declare all the variables created by mapping and the variables
declared in the scope of the parallel body. */
@@ -7832,6 +9381,14 @@ lower_omp_taskreg (gimple_stmt_iterator *gsi_p, omp_context *ctx)
lower_send_clauses (clauses, &ilist, &olist, ctx);
lower_send_shared_vars (&ilist, &olist, ctx);
+ if (ctx->record_type)
+ {
+ tree clobber = build_constructor (TREE_TYPE (ctx->sender_decl), NULL);
+ TREE_THIS_VOLATILE (clobber) = 1;
+ gimple_seq_add_stmt (&olist, gimple_build_assign (ctx->sender_decl,
+ clobber));
+ }
+
/* Once all the expansions are done, sequence all the different
fragments inside gimple_omp_body. */
@@ -7848,12 +9405,329 @@ lower_omp_taskreg (gimple_stmt_iterator *gsi_p, omp_context *ctx)
gimple_seq_add_seq (&new_body, par_ilist);
gimple_seq_add_seq (&new_body, par_body);
+ gimple_seq_add_seq (&new_body, par_rlist);
+ if (ctx->cancellable)
+ gimple_seq_add_stmt (&new_body, gimple_build_label (ctx->cancel_label));
gimple_seq_add_seq (&new_body, par_olist);
new_body = maybe_catch_exception (new_body);
gimple_seq_add_stmt (&new_body, gimple_build_omp_return (false));
gimple_omp_set_body (stmt, new_body);
bind = gimple_build_bind (NULL, NULL, gimple_bind_block (par_bind));
+ gsi_replace (gsi_p, dep_bind ? dep_bind : bind, true);
+ gimple_bind_add_seq (bind, ilist);
+ gimple_bind_add_stmt (bind, stmt);
+ gimple_bind_add_seq (bind, olist);
+
+ pop_gimplify_context (NULL);
+
+ if (dep_bind)
+ {
+ gimple_bind_add_seq (dep_bind, dep_ilist);
+ gimple_bind_add_stmt (dep_bind, bind);
+ gimple_bind_add_seq (dep_bind, dep_olist);
+ pop_gimplify_context (dep_bind);
+ }
+}
+
+/* Lower the OpenMP target directive in the current statement
+ in GSI_P. CTX holds context information for the directive. */
+
+static void
+lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
+{
+ tree clauses;
+ tree child_fn, t, c;
+ gimple stmt = gsi_stmt (*gsi_p);
+ gimple tgt_bind = NULL, bind;
+ gimple_seq tgt_body = NULL, olist, ilist, new_body;
+ struct gimplify_ctx gctx;
+ location_t loc = gimple_location (stmt);
+ int kind = gimple_omp_target_kind (stmt);
+ unsigned int map_cnt = 0;
+
+ clauses = gimple_omp_target_clauses (stmt);
+ if (kind == GF_OMP_TARGET_KIND_REGION)
+ {
+ tgt_bind = gimple_seq_first_stmt (gimple_omp_body (stmt));
+ tgt_body = gimple_bind_body (tgt_bind);
+ }
+ else if (kind == GF_OMP_TARGET_KIND_DATA)
+ tgt_body = gimple_omp_body (stmt);
+ child_fn = ctx->cb.dst_fn;
+
+ push_gimplify_context (&gctx);
+
+ for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+ switch (OMP_CLAUSE_CODE (c))
+ {
+ tree var, x;
+
+ default:
+ break;
+ case OMP_CLAUSE_MAP:
+ case OMP_CLAUSE_TO:
+ case OMP_CLAUSE_FROM:
+ var = OMP_CLAUSE_DECL (c);
+ if (!DECL_P (var))
+ {
+ if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP
+ || !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c))
+ map_cnt++;
+ continue;
+ }
+
+ if (DECL_SIZE (var)
+ && TREE_CODE (DECL_SIZE (var)) != INTEGER_CST)
+ {
+ tree var2 = DECL_VALUE_EXPR (var);
+ gcc_assert (TREE_CODE (var2) == INDIRECT_REF);
+ var2 = TREE_OPERAND (var2, 0);
+ gcc_assert (DECL_P (var2));
+ var = var2;
+ }
+
+ if (!maybe_lookup_field (var, ctx))
+ continue;
+
+ if (kind == GF_OMP_TARGET_KIND_REGION)
+ {
+ x = build_receiver_ref (var, true, ctx);
+ tree new_var = lookup_decl (var, ctx);
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+ && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER
+ && !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c)
+ && TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE)
+ x = build_simple_mem_ref (x);
+ SET_DECL_VALUE_EXPR (new_var, x);
+ DECL_HAS_VALUE_EXPR_P (new_var) = 1;
+ }
+ map_cnt++;
+ }
+
+ if (kind == GF_OMP_TARGET_KIND_REGION)
+ {
+ target_nesting_level++;
+ lower_omp (&tgt_body, ctx);
+ target_nesting_level--;
+ }
+ else if (kind == GF_OMP_TARGET_KIND_DATA)
+ lower_omp (&tgt_body, ctx);
+
+ if (kind == GF_OMP_TARGET_KIND_REGION)
+ {
+ /* Declare all the variables created by mapping and the variables
+ declared in the scope of the target body. */
+ record_vars_into (ctx->block_vars, child_fn);
+ record_vars_into (gimple_bind_vars (tgt_bind), child_fn);
+ }
+
+ olist = NULL;
+ ilist = NULL;
+ if (ctx->record_type)
+ {
+ ctx->sender_decl
+ = create_tmp_var (ctx->record_type, ".omp_data_arr");
+ DECL_NAMELESS (ctx->sender_decl) = 1;
+ TREE_ADDRESSABLE (ctx->sender_decl) = 1;
+ t = make_tree_vec (3);
+ TREE_VEC_ELT (t, 0) = ctx->sender_decl;
+ TREE_VEC_ELT (t, 1)
+ = create_tmp_var (build_array_type_nelts (size_type_node, map_cnt),
+ ".omp_data_sizes");
+ DECL_NAMELESS (TREE_VEC_ELT (t, 1)) = 1;
+ TREE_ADDRESSABLE (TREE_VEC_ELT (t, 1)) = 1;
+ TREE_STATIC (TREE_VEC_ELT (t, 1)) = 1;
+ TREE_VEC_ELT (t, 2)
+ = create_tmp_var (build_array_type_nelts (unsigned_char_type_node,
+ map_cnt),
+ ".omp_data_kinds");
+ DECL_NAMELESS (TREE_VEC_ELT (t, 2)) = 1;
+ TREE_ADDRESSABLE (TREE_VEC_ELT (t, 2)) = 1;
+ TREE_STATIC (TREE_VEC_ELT (t, 2)) = 1;
+ gimple_omp_target_set_data_arg (stmt, t);
+
+ vec<constructor_elt, va_gc> *vsize;
+ vec<constructor_elt, va_gc> *vkind;
+ vec_alloc (vsize, map_cnt);
+ vec_alloc (vkind, map_cnt);
+ unsigned int map_idx = 0;
+
+ for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+ switch (OMP_CLAUSE_CODE (c))
+ {
+ tree ovar, nc;
+
+ default:
+ break;
+ case OMP_CLAUSE_MAP:
+ case OMP_CLAUSE_TO:
+ case OMP_CLAUSE_FROM:
+ nc = c;
+ ovar = OMP_CLAUSE_DECL (c);
+ if (!DECL_P (ovar))
+ {
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+ && OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c))
+ {
+ gcc_checking_assert (OMP_CLAUSE_DECL (OMP_CLAUSE_CHAIN (c))
+ == get_base_address (ovar));
+ nc = OMP_CLAUSE_CHAIN (c);
+ ovar = OMP_CLAUSE_DECL (nc);
+ }
+ else
+ {
+ tree x = build_sender_ref (ovar, ctx);
+ tree v
+ = build_fold_addr_expr_with_type (ovar, ptr_type_node);
+ gimplify_assign (x, v, &ilist);
+ nc = NULL_TREE;
+ }
+ }
+ else
+ {
+ if (DECL_SIZE (ovar)
+ && TREE_CODE (DECL_SIZE (ovar)) != INTEGER_CST)
+ {
+ tree ovar2 = DECL_VALUE_EXPR (ovar);
+ gcc_assert (TREE_CODE (ovar2) == INDIRECT_REF);
+ ovar2 = TREE_OPERAND (ovar2, 0);
+ gcc_assert (DECL_P (ovar2));
+ ovar = ovar2;
+ }
+ if (!maybe_lookup_field (ovar, ctx))
+ continue;
+ }
+
+ if (nc)
+ {
+ tree var = lookup_decl_in_outer_ctx (ovar, ctx);
+ tree x = build_sender_ref (ovar, ctx);
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+ && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER
+ && !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c)
+ && TREE_CODE (TREE_TYPE (ovar)) == ARRAY_TYPE)
+ {
+ gcc_assert (kind == GF_OMP_TARGET_KIND_REGION);
+ tree avar
+ = create_tmp_var (TREE_TYPE (TREE_TYPE (x)), NULL);
+ mark_addressable (avar);
+ gimplify_assign (avar, build_fold_addr_expr (var), &ilist);
+ avar = build_fold_addr_expr (avar);
+ gimplify_assign (x, avar, &ilist);
+ }
+ else if (is_gimple_reg (var))
+ {
+ gcc_assert (kind == GF_OMP_TARGET_KIND_REGION);
+ tree avar = create_tmp_var (TREE_TYPE (var), NULL);
+ mark_addressable (avar);
+ if (OMP_CLAUSE_MAP_KIND (c) != OMP_CLAUSE_MAP_ALLOC
+ && OMP_CLAUSE_MAP_KIND (c) != OMP_CLAUSE_MAP_FROM)
+ gimplify_assign (avar, var, &ilist);
+ avar = build_fold_addr_expr (avar);
+ gimplify_assign (x, avar, &ilist);
+ if ((OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_FROM
+ || OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_TOFROM)
+ && !TYPE_READONLY (TREE_TYPE (var)))
+ {
+ x = build_sender_ref (ovar, ctx);
+ x = build_simple_mem_ref (x);
+ gimplify_assign (var, x, &olist);
+ }
+ }
+ else
+ {
+ var = build_fold_addr_expr (var);
+ gimplify_assign (x, var, &ilist);
+ }
+ }
+ tree s = OMP_CLAUSE_SIZE (c);
+ if (s == NULL_TREE)
+ s = TYPE_SIZE_UNIT (TREE_TYPE (ovar));
+ s = fold_convert (size_type_node, s);
+ tree purpose = size_int (map_idx++);
+ CONSTRUCTOR_APPEND_ELT (vsize, purpose, s);
+ if (TREE_CODE (s) != INTEGER_CST)
+ TREE_STATIC (TREE_VEC_ELT (t, 1)) = 0;
+
+ unsigned char tkind = 0;
+ switch (OMP_CLAUSE_CODE (c))
+ {
+ case OMP_CLAUSE_MAP:
+ tkind = OMP_CLAUSE_MAP_KIND (c);
+ break;
+ case OMP_CLAUSE_TO:
+ tkind = OMP_CLAUSE_MAP_TO;
+ break;
+ case OMP_CLAUSE_FROM:
+ tkind = OMP_CLAUSE_MAP_FROM;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ unsigned int talign = TYPE_ALIGN_UNIT (TREE_TYPE (ovar));
+ if (DECL_P (ovar) && DECL_ALIGN_UNIT (ovar) > talign)
+ talign = DECL_ALIGN_UNIT (ovar);
+ talign = ceil_log2 (talign);
+ tkind |= talign << 3;
+ CONSTRUCTOR_APPEND_ELT (vkind, purpose,
+ build_int_cst (unsigned_char_type_node,
+ tkind));
+ if (nc && nc != c)
+ c = nc;
+ }
+
+ gcc_assert (map_idx == map_cnt);
+
+ DECL_INITIAL (TREE_VEC_ELT (t, 1))
+ = build_constructor (TREE_TYPE (TREE_VEC_ELT (t, 1)), vsize);
+ DECL_INITIAL (TREE_VEC_ELT (t, 2))
+ = build_constructor (TREE_TYPE (TREE_VEC_ELT (t, 2)), vkind);
+ if (!TREE_STATIC (TREE_VEC_ELT (t, 1)))
+ {
+ gimple_seq initlist = NULL;
+ force_gimple_operand (build1 (DECL_EXPR, void_type_node,
+ TREE_VEC_ELT (t, 1)),
+ &initlist, true, NULL_TREE);
+ gimple_seq_add_seq (&ilist, initlist);
+ }
+
+ tree clobber = build_constructor (ctx->record_type, NULL);
+ TREE_THIS_VOLATILE (clobber) = 1;
+ gimple_seq_add_stmt (&olist, gimple_build_assign (ctx->sender_decl,
+ clobber));
+ }
+
+ /* Once all the expansions are done, sequence all the different
+ fragments inside gimple_omp_body. */
+
+ new_body = NULL;
+
+ if (ctx->record_type && kind == GF_OMP_TARGET_KIND_REGION)
+ {
+ t = build_fold_addr_expr_loc (loc, ctx->sender_decl);
+ /* fixup_child_record_type might have changed receiver_decl's type. */
+ t = fold_convert_loc (loc, TREE_TYPE (ctx->receiver_decl), t);
+ gimple_seq_add_stmt (&new_body,
+ gimple_build_assign (ctx->receiver_decl, t));
+ }
+
+ if (kind == GF_OMP_TARGET_KIND_REGION)
+ {
+ gimple_seq_add_seq (&new_body, tgt_body);
+ new_body = maybe_catch_exception (new_body);
+ }
+ else if (kind == GF_OMP_TARGET_KIND_DATA)
+ new_body = tgt_body;
+ if (kind != GF_OMP_TARGET_KIND_UPDATE)
+ {
+ gimple_seq_add_stmt (&new_body, gimple_build_omp_return (false));
+ gimple_omp_set_body (stmt, new_body);
+ }
+
+ bind = gimple_build_bind (NULL, NULL,
+ tgt_bind ? gimple_bind_block (tgt_bind)
+ : NULL_TREE);
gsi_replace (gsi_p, bind, true);
gimple_bind_add_seq (bind, ilist);
gimple_bind_add_stmt (bind, stmt);
@@ -7862,6 +9736,72 @@ lower_omp_taskreg (gimple_stmt_iterator *gsi_p, omp_context *ctx)
pop_gimplify_context (NULL);
}
+/* Expand code for an OpenMP teams directive. */
+
+static void
+lower_omp_teams (gimple_stmt_iterator *gsi_p, omp_context *ctx)
+{
+ gimple teams_stmt = gsi_stmt (*gsi_p);
+ struct gimplify_ctx gctx;
+ push_gimplify_context (&gctx);
+
+ tree block = make_node (BLOCK);
+ gimple bind = gimple_build_bind (NULL, NULL, block);
+ gsi_replace (gsi_p, bind, true);
+ gimple_seq bind_body = NULL;
+ gimple_seq dlist = NULL;
+ gimple_seq olist = NULL;
+
+ tree num_teams = find_omp_clause (gimple_omp_teams_clauses (teams_stmt),
+ OMP_CLAUSE_NUM_TEAMS);
+ if (num_teams == NULL_TREE)
+ num_teams = build_int_cst (unsigned_type_node, 0);
+ else
+ {
+ num_teams = OMP_CLAUSE_NUM_TEAMS_EXPR (num_teams);
+ num_teams = fold_convert (unsigned_type_node, num_teams);
+ gimplify_expr (&num_teams, &bind_body, NULL, is_gimple_val, fb_rvalue);
+ }
+ tree thread_limit = find_omp_clause (gimple_omp_teams_clauses (teams_stmt),
+ OMP_CLAUSE_THREAD_LIMIT);
+ if (thread_limit == NULL_TREE)
+ thread_limit = build_int_cst (unsigned_type_node, 0);
+ else
+ {
+ thread_limit = OMP_CLAUSE_THREAD_LIMIT_EXPR (thread_limit);
+ thread_limit = fold_convert (unsigned_type_node, thread_limit);
+ gimplify_expr (&thread_limit, &bind_body, NULL, is_gimple_val,
+ fb_rvalue);
+ }
+
+ lower_rec_input_clauses (gimple_omp_teams_clauses (teams_stmt),
+ &bind_body, &dlist, ctx, NULL);
+ lower_omp (gimple_omp_body_ptr (teams_stmt), ctx);
+ lower_reduction_clauses (gimple_omp_teams_clauses (teams_stmt), &olist, ctx);
+ gimple_seq_add_stmt (&bind_body, teams_stmt);
+
+ location_t loc = gimple_location (teams_stmt);
+ tree decl = builtin_decl_explicit (BUILT_IN_GOMP_TEAMS);
+ gimple call = gimple_build_call (decl, 2, num_teams, thread_limit);
+ gimple_set_location (call, loc);
+ gimple_seq_add_stmt (&bind_body, call);
+
+ gimple_seq_add_seq (&bind_body, gimple_omp_body (teams_stmt));
+ gimple_omp_set_body (teams_stmt, NULL);
+ gimple_seq_add_seq (&bind_body, olist);
+ gimple_seq_add_seq (&bind_body, dlist);
+ gimple_seq_add_stmt (&bind_body, gimple_build_omp_return (true));
+ gimple_bind_set_body (bind, bind_body);
+
+ pop_gimplify_context (bind);
+
+ gimple_bind_append_vars (bind, ctx->block_vars);
+ BLOCK_VARS (block) = ctx->block_vars;
+ if (BLOCK_VARS (block))
+ TREE_USED (block) = 1;
+}
+
+
/* Callback for lower_omp_1. Return non-NULL if *tp needs to be
regimplified. If DATA is non-NULL, lower_omp_1 is outside
of OpenMP context, but with task_shared_vars set. */
@@ -7940,16 +9880,23 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p, omp_context *ctx)
case GIMPLE_OMP_PARALLEL:
case GIMPLE_OMP_TASK:
ctx = maybe_lookup_ctx (stmt);
+ gcc_assert (ctx);
+ if (ctx->cancellable)
+ ctx->cancel_label = create_artificial_label (UNKNOWN_LOCATION);
lower_omp_taskreg (gsi_p, ctx);
break;
case GIMPLE_OMP_FOR:
ctx = maybe_lookup_ctx (stmt);
gcc_assert (ctx);
+ if (ctx->cancellable)
+ ctx->cancel_label = create_artificial_label (UNKNOWN_LOCATION);
lower_omp_for (gsi_p, ctx);
break;
case GIMPLE_OMP_SECTIONS:
ctx = maybe_lookup_ctx (stmt);
gcc_assert (ctx);
+ if (ctx->cancellable)
+ ctx->cancel_label = create_artificial_label (UNKNOWN_LOCATION);
lower_omp_sections (gsi_p, ctx);
break;
case GIMPLE_OMP_SINGLE:
@@ -7962,6 +9909,11 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p, omp_context *ctx)
gcc_assert (ctx);
lower_omp_master (gsi_p, ctx);
break;
+ case GIMPLE_OMP_TASKGROUP:
+ ctx = maybe_lookup_ctx (stmt);
+ gcc_assert (ctx);
+ lower_omp_taskgroup (gsi_p, ctx);
+ break;
case GIMPLE_OMP_ORDERED:
ctx = maybe_lookup_ctx (stmt);
gcc_assert (ctx);
@@ -7978,6 +9930,66 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p, omp_context *ctx)
lower_omp_regimplify_p, ctx ? NULL : &wi, NULL))
gimple_regimplify_operands (stmt, gsi_p);
break;
+ case GIMPLE_OMP_TARGET:
+ ctx = maybe_lookup_ctx (stmt);
+ gcc_assert (ctx);
+ lower_omp_target (gsi_p, ctx);
+ break;
+ case GIMPLE_OMP_TEAMS:
+ ctx = maybe_lookup_ctx (stmt);
+ gcc_assert (ctx);
+ lower_omp_teams (gsi_p, ctx);
+ break;
+ case GIMPLE_CALL:
+ tree fndecl;
+ fndecl = gimple_call_fndecl (stmt);
+ if (fndecl
+ && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+ switch (DECL_FUNCTION_CODE (fndecl))
+ {
+ case BUILT_IN_GOMP_BARRIER:
+ if (ctx == NULL)
+ break;
+ /* FALLTHRU */
+ case BUILT_IN_GOMP_CANCEL:
+ case BUILT_IN_GOMP_CANCELLATION_POINT:
+ omp_context *cctx;
+ cctx = ctx;
+ if (gimple_code (cctx->stmt) == GIMPLE_OMP_SECTION)
+ cctx = cctx->outer;
+ gcc_assert (gimple_call_lhs (stmt) == NULL_TREE);
+ if (!cctx->cancellable)
+ {
+ if (DECL_FUNCTION_CODE (fndecl)
+ == BUILT_IN_GOMP_CANCELLATION_POINT)
+ {
+ stmt = gimple_build_nop ();
+ gsi_replace (gsi_p, stmt, false);
+ }
+ break;
+ }
+ tree lhs;
+ lhs = create_tmp_var (boolean_type_node, NULL);
+ if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_GOMP_BARRIER)
+ {
+ fndecl = builtin_decl_explicit (BUILT_IN_GOMP_BARRIER_CANCEL);
+ gimple_call_set_fndecl (stmt, fndecl);
+ gimple_call_set_fntype (stmt, TREE_TYPE (fndecl));
+ }
+ gimple_call_set_lhs (stmt, lhs);
+ tree fallthru_label;
+ fallthru_label = create_artificial_label (UNKNOWN_LOCATION);
+ gimple g;
+ g = gimple_build_label (fallthru_label);
+ gsi_insert_after (gsi_p, g, GSI_SAME_STMT);
+ g = gimple_build_cond (NE_EXPR, lhs, boolean_false_node,
+ cctx->cancel_label, fallthru_label);
+ gsi_insert_after (gsi_p, g, GSI_SAME_STMT);
+ break;
+ default:
+ break;
+ }
+ /* FALLTHRU */
default:
if ((ctx || task_shared_vars)
&& walk_gimple_op (stmt, lower_omp_regimplify_p,
@@ -7994,6 +10006,12 @@ lower_omp (gimple_seq *body, omp_context *ctx)
gimple_stmt_iterator gsi;
for (gsi = gsi_start (*body); !gsi_end_p (gsi); gsi_next (&gsi))
lower_omp_1 (&gsi, ctx);
+ /* Inside target region we haven't called fold_stmt during gimplification,
+ because it can break code by adding decl references that weren't in the
+ source. Call fold_stmt now. */
+ if (target_nesting_level)
+ for (gsi = gsi_start (*body); !gsi_end_p (gsi); gsi_next (&gsi))
+ fold_stmt (&gsi);
input_location = saved_location;
}
@@ -8162,6 +10180,9 @@ diagnose_sb_1 (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
case GIMPLE_OMP_MASTER:
case GIMPLE_OMP_ORDERED:
case GIMPLE_OMP_CRITICAL:
+ case GIMPLE_OMP_TARGET:
+ case GIMPLE_OMP_TEAMS:
+ case GIMPLE_OMP_TASKGROUP:
/* The minimal context here is just the current OMP construct. */
inner_context = stmt;
wi->info = inner_context;
@@ -8217,6 +10238,9 @@ diagnose_sb_2 (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
case GIMPLE_OMP_MASTER:
case GIMPLE_OMP_ORDERED:
case GIMPLE_OMP_CRITICAL:
+ case GIMPLE_OMP_TARGET:
+ case GIMPLE_OMP_TEAMS:
+ case GIMPLE_OMP_TASKGROUP:
wi->info = stmt;
walk_gimple_seq_mod (gimple_omp_body_ptr (stmt), diagnose_sb_2, NULL, wi);
wi->info = context;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 92b24ea8fa8..c58d9ea7eec 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,64 @@
+2013-10-11 Jakub Jelinek <jakub@redhat.com>
+
+ * c-c++-common/gomp/atomic-15.c: Adjust for C diagnostics.
+ Remove error test that is now valid in OpenMP 4.0.
+ * c-c++-common/gomp/atomic-16.c: New test.
+ * c-c++-common/gomp/cancel-1.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.
+ * c-c++-common/gomp/pr58472.c: New test.
+ * c-c++-common/gomp/sections1.c: New test.
+ * c-c++-common/gomp/simd1.c: New test.
+ * c-c++-common/gomp/simd2.c: New test.
+ * c-c++-common/gomp/simd3.c: New test.
+ * c-c++-common/gomp/simd4.c: New test.
+ * c-c++-common/gomp/simd5.c: New test.
+ * c-c++-common/gomp/single1.c: New test.
+ * g++.dg/gomp/block-0.C: Adjust for stricter #pragma omp sections
+ parser.
+ * g++.dg/gomp/block-3.C: Likewise.
+ * g++.dg/gomp/clause-3.C: Adjust error messages.
+ * g++.dg/gomp/declare-simd-1.C: New test.
+ * g++.dg/gomp/declare-simd-2.C: New test.
+ * g++.dg/gomp/depend-1.C: New test.
+ * g++.dg/gomp/depend-2.C: New test.
+ * g++.dg/gomp/target-1.C: New test.
+ * g++.dg/gomp/target-2.C: New test.
+ * g++.dg/gomp/taskgroup-1.C: New test.
+ * g++.dg/gomp/teams-1.C: New test.
+ * g++.dg/gomp/udr-1.C: New test.
+ * g++.dg/gomp/udr-2.C: New test.
+ * g++.dg/gomp/udr-3.C: New test.
+ * g++.dg/gomp/udr-4.C: New test.
+ * g++.dg/gomp/udr-5.C: New test.
+ * g++.dg/gomp/udr-6.C: New test.
+ * gcc.dg/autopar/outer-1.c: Expect 4 instead of 5 loopfn matches.
+ * gcc.dg/autopar/outer-2.c: Likewise.
+ * gcc.dg/autopar/outer-3.c: Likewise.
+ * gcc.dg/autopar/outer-4.c: Likewise.
+ * gcc.dg/autopar/outer-5.c: Likewise.
+ * gcc.dg/autopar/outer-6.c: Likewise.
+ * gcc.dg/autopar/parallelization-1.c: Likewise.
+ * gcc.dg/gomp/block-3.c: Adjust for stricter #pragma omp sections
+ parser.
+ * gcc.dg/gomp/clause-1.c: Adjust error messages.
+ * gcc.dg/gomp/combined-1.c: Look for GOMP_parallel_loop_runtime
+ instead of GOMP_parallel_loop_runtime_start.
+ * gcc.dg/gomp/declare-simd-1.c: New test.
+ * gcc.dg/gomp/declare-simd-2.c: New test.
+ * gcc.dg/gomp/nesting-1.c: Adjust for stricter #pragma omp sections
+ parser. Add further #pragma omp sections nesting tests.
+ * gcc.dg/gomp/target-1.c: New test.
+ * gcc.dg/gomp/target-2.c: New test.
+ * gcc.dg/gomp/taskgroup-1.c: New test.
+ * gcc.dg/gomp/teams-1.c: New test.
+ * gcc.dg/gomp/udr-1.c: New test.
+ * gcc.dg/gomp/udr-2.c: New test.
+ * gcc.dg/gomp/udr-3.c: New test.
+ * gcc.dg/gomp/udr-4.c: New test.
+ * gfortran.dg/gomp/appendix-a/a.35.5.f90: Add dg-error.
+
2013-10-10 Jan Hubicka <jh@suse.cz>
* gcc.target/i386/avx256-unaligned-store-3.c: Update template for
diff --git a/gcc/testsuite/c-c++-common/gomp/atomic-15.c b/gcc/testsuite/c-c++-common/gomp/atomic-15.c
index 13a9e0ce48a..5e669fa3543 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/atomic-16.c b/gcc/testsuite/c-c++-common/gomp/atomic-16.c
new file mode 100644
index 00000000000..87fbaa23317
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/atomic-16.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+int x = 6;
+
+void
+foo ()
+{
+ int v;
+ #pragma omp atomic seq_cst load /* { dg-error "expected end of line" } */
+ v = x; /* { dg-error "invalid form" } */
+ #pragma omp atomic seq_cst, load /* { dg-error "expected end of line" } */
+ v = x; /* { dg-error "invalid form" } */
+ #pragma omp atomic seq_cst store /* { dg-error "expected end of line" } */
+ x = v; /* { dg-error "invalid form" } */
+ #pragma omp atomic seq_cst ,store /* { dg-error "expected end of line" } */
+ x = v; /* { dg-error "invalid form" } */
+ #pragma omp atomic seq_cst update /* { dg-error "expected end of line" } */
+ x += v;
+ #pragma omp atomic seq_cst , update /* { dg-error "expected end of line" } */
+ x += v;
+ #pragma omp atomic seq_cst capture /* { dg-error "expected end of line" } */
+ v = x += 2; /* { dg-error "invalid form" } */
+ #pragma omp atomic seq_cst, capture /* { dg-error "expected end of line" } */
+ v = x += 2; /* { dg-error "invalid form" } */
+ #pragma omp atomic load , seq_cst /* { dg-error "expected end of line" } */
+ v = x; /* { dg-error "invalid form" } */
+ #pragma omp atomic store ,seq_cst /* { dg-error "expected end of line" } */
+ x = v; /* { dg-error "invalid form" } */
+ #pragma omp atomic update, seq_cst /* { dg-error "expected end of line" } */
+ x += v;
+ #pragma omp atomic capture, seq_cst /* { dg-error "expected end of line" } */
+ v = x += 2;
+}
diff --git a/gcc/testsuite/c-c++-common/gomp/cancel-1.c b/gcc/testsuite/c-c++-common/gomp/cancel-1.c
new file mode 100644
index 00000000000..d8f7bc1b8fa
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/cancel-1.c
@@ -0,0 +1,396 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+void
+f1 (void)
+{
+ #pragma omp cancel parallel /* { dg-error "orphaned" } */
+ #pragma omp cancel for /* { dg-error "orphaned" } */
+ #pragma omp cancel sections /* { dg-error "orphaned" } */
+ #pragma omp cancel taskgroup /* { dg-error "orphaned" } */
+ #pragma omp cancellation point parallel /* { dg-error "orphaned" } */
+ #pragma omp cancellation point for /* { dg-error "orphaned" } */
+ #pragma omp cancellation point sections /* { dg-error "orphaned" } */
+ #pragma omp cancellation point taskgroup /* { dg-error "orphaned" } */
+}
+
+void
+f2 (void)
+{
+ int i;
+ #pragma omp parallel
+ {
+ #pragma omp cancel parallel
+ #pragma omp cancel for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point parallel
+ #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point taskgroup /* { dg-error "not closely nested inside" } */
+ #pragma omp master
+ {
+ #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point taskgroup /* { dg-error "not closely nested inside" } */
+ }
+ #pragma omp single
+ {
+ #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point taskgroup /* { dg-error "not closely nested inside" } */
+ }
+ #pragma omp critical
+ {
+ #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point taskgroup /* { dg-error "not closely nested inside" } */
+ }
+ #pragma omp taskgroup
+ {
+ #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point taskgroup /* { dg-error "not closely nested inside" } */
+ }
+ #pragma omp task
+ {
+ #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel taskgroup
+ #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point taskgroup
+ }
+ #pragma omp for
+ for (i = 0; i < 10; i++)
+ {
+ #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel for
+ #pragma omp cancel sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point for
+ #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point taskgroup/* { dg-error "not closely nested inside" } */
+ }
+ #pragma omp for ordered
+ for (i = 0; i < 10; i++)
+ #pragma omp ordered
+ {
+ #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point taskgroup/* { dg-error "not closely nested inside" } */
+ }
+ #pragma omp sections
+ {
+ {
+ #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel sections
+ #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point sections
+ #pragma omp cancellation point taskgroup/* { dg-error "not closely nested inside" } */
+ }
+ #pragma omp section
+ {
+ #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel sections
+ #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point sections
+ #pragma omp cancellation point taskgroup/* { dg-error "not closely nested inside" } */
+ }
+ }
+ #pragma omp target data
+ {
+ #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point taskgroup /* { dg-error "not closely nested inside" } */
+ }
+ #pragma omp target
+ {
+ #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point taskgroup /* { dg-error "not closely nested inside" } */
+ }
+ }
+ #pragma omp target data
+ {
+ #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point taskgroup /* { dg-error "not closely nested inside" } */
+ }
+ #pragma omp target
+ {
+ #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point taskgroup /* { dg-error "not closely nested inside" } */
+ }
+ #pragma omp target teams
+ {
+ #pragma omp cancel parallel /* { dg-error "only distribute or parallel constructs are allowed to be closely nested" } */
+ #pragma omp cancel for /* { dg-error "only distribute or parallel constructs are allowed to be closely nested" } */
+ #pragma omp cancel sections /* { dg-error "only distribute or parallel constructs are allowed to be closely nested" } */
+ #pragma omp cancel taskgroup /* { dg-error "only distribute or parallel constructs are allowed to be closely nested" } */
+ #pragma omp cancellation point parallel /* { dg-error "only distribute or parallel constructs are allowed to be closely nested" } */
+ #pragma omp cancellation point for /* { dg-error "only distribute or parallel constructs are allowed to be closely nested" } */
+ #pragma omp cancellation point sections /* { dg-error "only distribute or parallel constructs are allowed to be closely nested" } */
+ #pragma omp cancellation point taskgroup /* { dg-error "only distribute or parallel constructs are allowed to be closely nested" } */
+ }
+ #pragma omp target teams distribute
+ for (i = 0; i < 10; i++)
+ {
+ #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point taskgroup /* { dg-error "not closely nested inside" } */
+ }
+ #pragma omp for
+ for (i = 0; i < 10; i++)
+ {
+ #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel for
+ #pragma omp cancel sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point for
+ #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point taskgroup /* { dg-error "not closely nested inside" } */
+ }
+ #pragma omp for
+ for (i = 0; i < 10; i++)
+ #pragma omp target data
+ {
+ #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point taskgroup /* { dg-error "not closely nested inside" } */
+ }
+ #pragma omp for
+ for (i = 0; i < 10; i++)
+ #pragma omp target
+ {
+ #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point taskgroup /* { dg-error "not closely nested inside" } */
+ }
+ #pragma omp for ordered
+ for (i = 0; i < 10; i++)
+ #pragma omp ordered
+ #pragma omp target data
+ {
+ #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point taskgroup/* { dg-error "not closely nested inside" } */
+ }
+ #pragma omp for ordered
+ for (i = 0; i < 10; i++)
+ #pragma omp ordered
+ #pragma omp target
+ {
+ #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point taskgroup/* { dg-error "not closely nested inside" } */
+ }
+ #pragma omp sections
+ {
+ {
+ #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel sections
+ #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point sections
+ #pragma omp cancellation point taskgroup /* { dg-error "not closely nested inside" } */
+ }
+ #pragma omp section
+ {
+ #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel sections
+ #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point sections
+ #pragma omp cancellation point taskgroup /* { dg-error "not closely nested inside" } */
+ }
+ }
+ #pragma omp sections
+ {
+ #pragma omp target data
+ {
+ #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point taskgroup /* { dg-error "not closely nested inside" } */
+ }
+ #pragma omp section
+ #pragma omp target data
+ {
+ #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point taskgroup /* { dg-error "not closely nested inside" } */
+ }
+ }
+ #pragma omp sections
+ {
+ #pragma omp target
+ {
+ #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point taskgroup /* { dg-error "not closely nested inside" } */
+ }
+ #pragma omp section
+ #pragma omp target
+ {
+ #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point taskgroup /* { dg-error "not closely nested inside" } */
+ }
+ }
+ #pragma omp task
+ {
+ #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel taskgroup
+ #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point taskgroup
+ #pragma omp taskgroup
+ {
+ #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */
+ #pragma omp cancellation point taskgroup /* { dg-error "not closely nested inside" } */
+ }
+ }
+}
+
+void
+f3 (void)
+{
+ int i;
+ #pragma omp for nowait
+ for (i = 0; i < 10; i++)
+ {
+ #pragma omp cancel for /* { dg-warning "nowait" } */
+ }
+ #pragma omp sections nowait
+ {
+ {
+ #pragma omp cancel sections /* { dg-warning "nowait" } */
+ }
+ #pragma omp section
+ {
+ #pragma omp cancel sections /* { dg-warning "nowait" } */
+ }
+ }
+ #pragma omp for ordered
+ for (i = 0; i < 10; i++)
+ {
+ #pragma omp cancel for /* { dg-warning "ordered" } */
+ #pragma omp ordered
+ {
+ }
+ }
+}
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 00000000000..8a5850e45fe
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/depend-1.c
@@ -0,0 +1,79 @@
+/* { 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)
+
+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 must be specified" } */
+ ;
+ #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 must be specified" } */
+ ;
+ #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 00000000000..99bf8ae1b83
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/depend-2.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { 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 00000000000..694d88cc795
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/map-1.c
@@ -0,0 +1,103 @@
+/* { 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;
+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 must be specified" } */
+ bar (&a[0][0]); /* { dg-error "referenced in target region does not have a mappable type" } */
+ #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 must be specified" } */
+ 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/pr58472.c b/gcc/testsuite/c-c++-common/gomp/pr58472.c
new file mode 100644
index 00000000000..355ca4008bf
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/pr58472.c
@@ -0,0 +1,16 @@
+/* PR tree-optimization/58472 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wall -fopenmp" } */
+
+float a[1024], b[1024];
+
+float
+foo ()
+{
+ float s = 0.f;
+ unsigned int i;
+#pragma omp simd reduction(+:s)
+ for (i = 0; i < 1024; ++i)
+ s += a[i] * b[i];
+ return s;
+}
diff --git a/gcc/testsuite/c-c++-common/gomp/sections1.c b/gcc/testsuite/c-c++-common/gomp/sections1.c
new file mode 100644
index 00000000000..8c8ab91f7f1
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/sections1.c
@@ -0,0 +1,73 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+void bar (int);
+
+void
+foo ()
+{
+ #pragma omp sections
+ {
+ bar (1);
+ #pragma omp section
+ {
+ bar (2);
+ }
+ }
+ #pragma omp sections
+ {
+ #pragma omp section
+ bar (3);
+ #pragma omp section
+ {
+ bar (4);
+ bar (5);
+ }
+ }
+ #pragma omp sections
+ {
+ {
+ bar (6);
+ bar (7);
+ }
+ #pragma omp section
+ bar (8);
+ }
+ #pragma omp sections
+ {
+ #pragma omp section
+ {
+ bar (9);
+ }
+ #pragma omp section
+ bar (10);
+ #pragma omp section
+ bar (11);
+ }
+ #pragma omp sections
+ {
+ } /* { dg-error "expression before" } */
+ #pragma omp sections
+ {
+ bar (12);
+ bar (13); /* { dg-error "pragma omp section" } */
+ #pragma omp section
+ bar (14);
+ }
+ #pragma omp sections
+ {
+ #pragma omp section
+ } /* { dg-error "expression before" } */
+ #pragma omp sections
+ {
+ bar (15);
+ #pragma omp section
+ bar (16);
+ bar (17); /* { dg-error "pragma omp section" } */
+ }
+ #pragma omp sections
+ {
+ bar (18);
+ #pragma omp section
+ } /* { dg-error "expression before" } */
+}
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 00000000000..29e464ca035
--- /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 00000000000..dda9c62d6d1
--- /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 00000000000..e8270fc4521
--- /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 00000000000..37901b6a07f
--- /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 00000000000..a57896d8704
--- /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/c-c++-common/gomp/single1.c b/gcc/testsuite/c-c++-common/gomp/single1.c
new file mode 100644
index 00000000000..c080a8804cf
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/single1.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+void
+foo (int i)
+{
+ #pragma omp single copyprivate (i)
+ ;
+ #pragma omp single nowait
+ ;
+ #pragma omp single copyprivate (i) nowait /* { dg-error "clause must not be used together with" } */
+ ;
+ #pragma omp single nowait copyprivate (i) /* { dg-error "clause must not be used together with" } */
+ ;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/block-0.C b/gcc/testsuite/g++.dg/gomp/block-0.C
index fa7865d8b93..86af0404ab3 100644
--- a/gcc/testsuite/g++.dg/gomp/block-0.C
+++ b/gcc/testsuite/g++.dg/gomp/block-0.C
@@ -22,8 +22,10 @@ void foo()
bar ();
#pragma omp parallel sections
{
- bar ();
- bar ();
+ {
+ bar ();
+ bar ();
+ }
#pragma omp section
bar ();
}
diff --git a/gcc/testsuite/g++.dg/gomp/block-3.C b/gcc/testsuite/g++.dg/gomp/block-3.C
index aeb0c7795a0..ff281752843 100644
--- a/gcc/testsuite/g++.dg/gomp/block-3.C
+++ b/gcc/testsuite/g++.dg/gomp/block-3.C
@@ -35,8 +35,10 @@ void foo()
#pragma omp sections
{
- goto ok1;
- ok1:;
+ {
+ goto ok1;
+ ok1:;
+ }
#pragma omp section
for (i = 0; i < 10; ++i)
diff --git a/gcc/testsuite/g++.dg/gomp/clause-3.C b/gcc/testsuite/g++.dg/gomp/clause-3.C
index a048c60b8af..1a20440d7c2 100644
--- a/gcc/testsuite/g++.dg/gomp/clause-3.C
+++ b/gcc/testsuite/g++.dg/gomp/clause-3.C
@@ -11,7 +11,7 @@ int t;
void
foo (int x)
{
- char *p;
+ char *pp;
struct S { int i; int j; } s;
char a[32];
double d;
@@ -42,18 +42,18 @@ foo (int x)
;
#pragma omp p firstprivate (bar) // { dg-error "is not a variable" }
;
-#pragma omp p reduction (+:p) // { dg-error "has invalid type for" }
+#pragma omp p reduction (+:pp) // { dg-error "user defined reduction not found for" }
;
-#pragma omp p reduction (*:s) // { dg-error "has invalid type for" }
+#pragma omp p reduction (*:s) // { dg-error "user defined reduction not found for" }
;
#pragma omp p reduction (-:a) // { dg-error "has invalid type for" }
;
d = 0;
#pragma omp p reduction (*:d)
;
-#pragma omp p reduction (|:d) // { dg-error "has invalid type for" }
+#pragma omp p reduction (|:d) // { dg-error "user defined reduction not found for" }
;
-#pragma omp p reduction (&&:d) // { dg-error "has invalid type for" }
+#pragma omp p reduction (&&:d) // { dg-error "user defined reduction not found for" }
;
#pragma omp p copyin (d) // { dg-error "must be 'threadprivate'" }
;
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 00000000000..1fd88b7efab
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/declare-simd-1.C
@@ -0,0 +1,243 @@
+// 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 <typename T>
+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 <typename T>
+int f4 (int a, int *b, T c)
+{
+ return a + *b + c;
+}
+
+template <>
+int f4 (int, int *, int);
+
+template <typename T>
+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 N>
+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 N>
+ 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 N>
+ 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 <typename T>
+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 N>
+ 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 N>
+ 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 N>
+ int f23 (int, int *, int);
+
+ template <int N>
+ static int f24 (int, int *, int);
+
+ template <int N>
+ int f25 (int, int *, int);
+
+ template <int N>
+ static int f26 (int, int *, int);
+};
+
+B <int> b;
+
+template <>
+template <>
+int B<int>::f18<0> (int, int *, int);
+
+template <>
+template <>
+int B<int>::f21<9> (int, int *, int);
+
+#pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) uniform (a, c)
+template <>
+template <>
+int B<int>::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<int>::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<int>::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<int>::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 <int N>
+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;
+}
+
+#pragma omp declare simd simdlen (N)
+template <int N>
+int f36 (int);
+
+struct D
+{
+ int d;
+ #pragma omp declare simd simdlen (N) linear (a : sizeof (a) + sizeof (d) + sizeof (this) + sizeof (this->d))
+ template <int N>
+ int f37 (int a);
+ int e;
+};
+
+void
+f38 (D &d)
+{
+ d.f37 <12> (6);
+}
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 00000000000..f64004fb012
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/declare-simd-2.C
@@ -0,0 +1,67 @@
+// 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 <typename T>
+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 // { dg-error "clause is incompatible with" }
+int fn11 (int);
+
+struct D
+{
+ int d;
+ #pragma omp declare simd simdlen (N) linear (a : sizeof (e) + sizeof (this->e)) // { dg-error "was not declared" }
+ template <int N>
+ int fn12 (int a);
+ int e;
+};
+
+// { dg-error "has no member" "" { target *-*-* } 61 }
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 00000000000..33027de552a
--- /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 <int N>
+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 must be specified" }
+ ;
+ #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 must be specified" }
+ ;
+ #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 00000000000..c3f19658c5a
--- /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 <int N>
+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 must be specified" }
+ ;
+ #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 must be specified" }
+ ;
+ #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/g++.dg/gomp/target-1.C b/gcc/testsuite/g++.dg/gomp/target-1.C
new file mode 100644
index 00000000000..b6ed4f89cd8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/target-1.C
@@ -0,0 +1,32 @@
+// { dg-do compile }
+
+void
+foo (int x)
+{
+ bad1: // { dg-error "jump to label" }
+ #pragma omp target
+ goto bad1; // { dg-error "from here|exits OpenMP" }
+
+ goto bad2; // { dg-error "from here" }
+ #pragma omp target
+ {
+ bad2: ; // { dg-error "jump to label|enters OpenMP" }
+ }
+
+ #pragma omp target
+ {
+ int i;
+ goto ok1;
+ for (i = 0; i < 10; ++i)
+ { ok1: break; }
+ }
+
+ switch (x)
+ {
+ #pragma omp target
+ { case 0:; } // { dg-error "jump|enters" }
+ }
+}
+
+// { dg-error "invalid branch to/from an OpenMP structured block" "" { target *-*-* } 8 }
+// { dg-error "invalid entry to OpenMP structured block" "" { target *-*-* } 10 }
diff --git a/gcc/testsuite/g++.dg/gomp/target-2.C b/gcc/testsuite/g++.dg/gomp/target-2.C
new file mode 100644
index 00000000000..6a14f53cff6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/target-2.C
@@ -0,0 +1,32 @@
+// { dg-do compile }
+
+void
+foo (int x, int y)
+{
+ bad1: // { dg-error "jump to label" }
+ #pragma omp target data map(tofrom: y)
+ goto bad1; // { dg-error "from here|exits OpenMP" }
+
+ goto bad2; // { dg-error "from here" }
+ #pragma omp target data map(tofrom: y)
+ {
+ bad2: ; // { dg-error "jump to label|enters OpenMP" }
+ }
+
+ #pragma omp target data map(tofrom: y)
+ {
+ int i;
+ goto ok1;
+ for (i = 0; i < 10; ++i)
+ { ok1: break; }
+ }
+
+ switch (x)
+ {
+ #pragma omp target data map(tofrom: y)
+ { case 0:; } // { dg-error "jump|enters" }
+ }
+}
+
+// { dg-error "invalid branch to/from an OpenMP structured block" "" { target *-*-* } 8 }
+// { dg-error "invalid entry to OpenMP structured block" "" { target *-*-* } 10 }
diff --git a/gcc/testsuite/g++.dg/gomp/taskgroup-1.C b/gcc/testsuite/g++.dg/gomp/taskgroup-1.C
new file mode 100644
index 00000000000..dcab0bb6466
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/taskgroup-1.C
@@ -0,0 +1,32 @@
+// { dg-do compile }
+
+void
+foo (int x)
+{
+ bad1: // { dg-error "jump to label" }
+ #pragma omp taskgroup
+ goto bad1; // { dg-error "from here|exits OpenMP" }
+
+ goto bad2; // { dg-error "from here" }
+ #pragma omp taskgroup
+ {
+ bad2: ; // { dg-error "jump to label|enters OpenMP" }
+ }
+
+ #pragma omp taskgroup
+ {
+ int i;
+ goto ok1;
+ for (i = 0; i < 10; ++i)
+ { ok1: break; }
+ }
+
+ switch (x)
+ {
+ #pragma omp taskgroup
+ { case 0:; } // { dg-error "jump|enters" }
+ }
+}
+
+// { dg-error "invalid branch to/from an OpenMP structured block" "" { target *-*-* } 8 }
+// { dg-error "invalid entry to OpenMP structured block" "" { target *-*-* } 10 }
diff --git a/gcc/testsuite/g++.dg/gomp/teams-1.C b/gcc/testsuite/g++.dg/gomp/teams-1.C
new file mode 100644
index 00000000000..ce40b55ca15
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/teams-1.C
@@ -0,0 +1,66 @@
+// { dg-do compile }
+
+void
+foo (int x)
+{
+ bad1: // { dg-error "jump to label" }
+ #pragma omp target teams
+ goto bad1; // { dg-error "from here|exits OpenMP" }
+
+ goto bad2; // { dg-error "from here" }
+ #pragma omp target teams
+ {
+ bad2: ; // { dg-error "jump to label|enters OpenMP" }
+ }
+
+ #pragma omp target teams
+ {
+ int i;
+ goto ok1;
+ for (i = 0; i < 10; ++i)
+ { ok1: break; }
+ }
+
+ switch (x)
+ {
+ #pragma omp target teams
+ { case 0:; } // { dg-error "jump|enters" }
+ }
+}
+
+void
+bar (int x)
+{
+ bad1: // { dg-error "jump to label" }
+ #pragma omp target
+ #pragma omp teams
+ goto bad1; // { dg-error "from here|exits OpenMP" }
+
+ goto bad2; // { dg-error "from here" }
+ #pragma omp target
+ #pragma omp teams
+ {
+ bad2: ; // { dg-error "jump to label|enters OpenMP" }
+ }
+
+ #pragma omp target
+ #pragma omp teams
+ {
+ int i;
+ goto ok1;
+ for (i = 0; i < 10; ++i)
+ { ok1: break; }
+ }
+
+ switch (x)
+ {
+ #pragma omp target
+ #pragma omp teams
+ { case 0:; } // { dg-error "jump|enters" }
+ }
+}
+
+// { dg-error "invalid branch to/from an OpenMP structured block" "" { target *-*-* } 8 }
+// { dg-error "invalid entry to OpenMP structured block" "" { target *-*-* } 10 }
+// { dg-error "invalid branch to/from an OpenMP structured block" "" { target *-*-* } 37 }
+// { dg-error "invalid entry to OpenMP structured block" "" { target *-*-* } 39 }
diff --git a/gcc/testsuite/g++.dg/gomp/udr-1.C b/gcc/testsuite/g++.dg/gomp/udr-1.C
new file mode 100644
index 00000000000..10c1c8dab92
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/udr-1.C
@@ -0,0 +1,119 @@
+// { dg-do compile }
+// { dg-options "-fopenmp" }
+
+namespace N1
+{
+ #pragma omp declare reduction (| : long int : omp_out |= omp_in) // { dg-error "predeclared arithmetic type" }
+ #pragma omp declare reduction (+ : char : omp_out += omp_in) // { dg-error "predeclared arithmetic type" }
+ typedef short T;
+ #pragma omp declare reduction (min : T : omp_out += omp_in) // { dg-error "predeclared arithmetic type" }
+ #pragma omp declare reduction (* : _Complex double : omp_out *= omp_in)// { dg-error "predeclared arithmetic type" }
+}
+namespace N2
+{
+ template <typename T1, typename T2, typename T3, typename T4>
+ struct S
+ {
+ #pragma omp declare reduction (| : T1 : omp_out |= omp_in) // { dg-error "predeclared arithmetic type" }
+ #pragma omp declare reduction (+ : T2 : omp_out += omp_in) // { dg-error "predeclared arithmetic type" }
+ typedef T3 T;
+ #pragma omp declare reduction (min : T : omp_out += omp_in) // { dg-error "predeclared arithmetic type" }
+ #pragma omp declare reduction (* : T4 : omp_out *= omp_in) // { dg-error "predeclared arithmetic type" }
+ };
+ S<long int, char, short, _Complex double> s;
+ template <typename T1, typename T2, typename T3, typename T4>
+ int foo ()
+ {
+ #pragma omp declare reduction (| : T1 : omp_out |= omp_in) // { dg-error "predeclared arithmetic type" }
+ #pragma omp declare reduction (+ : T2 : omp_out += omp_in) // { dg-error "predeclared arithmetic type" }
+ typedef T3 T;
+ #pragma omp declare reduction (min : T : omp_out += omp_in) // { dg-error "predeclared arithmetic type" }
+ #pragma omp declare reduction (* : T4 : omp_out *= omp_in) // { dg-error "predeclared arithmetic type" }
+ return 0;
+ }
+ int x = foo <long int, char, short, _Complex double> ();
+}
+namespace N3
+{
+ void bar ();
+ #pragma omp declare reduction (| : __typeof (bar) : omp_out |= omp_in)// { dg-error "function or array type" }
+ #pragma omp declare reduction (+ : char () : omp_out += omp_in) // { dg-error "function or array type" }
+ typedef short T;
+ #pragma omp declare reduction (min : T[2] : omp_out += omp_in) // { dg-error "function or array type" }
+ #pragma omp declare reduction (baz : char & : omp_out *= omp_in) // { dg-error "reference type" }
+}
+namespace N4
+{
+ void bar ();
+ template <typename T1, typename T2, typename T3, typename T4>
+ struct S
+ {
+ #pragma omp declare reduction (| : T1 : omp_out |= omp_in) // { dg-error "function or array type" }
+ #pragma omp declare reduction (+ : T2 : omp_out += omp_in) // { dg-error "function or array type" }
+ typedef T3 T;
+ #pragma omp declare reduction (min : T : omp_out += omp_in) // { dg-error "function or array type" }
+ #pragma omp declare reduction (baz : T4 : omp_out *= omp_in) // { dg-error "function or array type" }
+ };
+ S<__typeof (bar), char (), short [3], char []> s;
+ template <typename T1, typename T2, typename T3, typename T4>
+ int foo ()
+ {
+ #pragma omp declare reduction (| : T1 : omp_out |= omp_in) // { dg-error "function or array type" }
+ #pragma omp declare reduction (+ : T2 : omp_out += omp_in) // { dg-error "function or array type" }
+ typedef T3 T;
+ #pragma omp declare reduction (min : T : omp_out += omp_in) // { dg-error "function or array type" }
+ #pragma omp declare reduction (baz : T4 : omp_out *= omp_in) // { dg-error "function or array type" }
+ return 0;
+ }
+ int x = foo <__typeof (bar), char (), short[], char [2]> ();
+}
+namespace N5
+{
+ template <typename T>
+ struct S
+ {
+ #pragma omp declare reduction (baz : T : omp_out *= omp_in) // { dg-error "reference type" }
+ };
+ S<char &> s;
+ template <typename T>
+ int foo ()
+ {
+ #pragma omp declare reduction (baz : T : omp_out *= omp_in) // { dg-error "reference type" }
+ return 0;
+ }
+ int x = foo <char &> ();
+}
+namespace N6
+{
+ struct A { int a; A () : a (0) {} };
+ #pragma omp declare reduction (| : const A : omp_out.a |= omp_in.a) // { dg-error "const, volatile or __restrict" }
+ #pragma omp declare reduction (+ : __const A : omp_out.a += omp_in.a) // { dg-error "const, volatile or __restrict" }
+ typedef volatile A T;
+ #pragma omp declare reduction (min : T : omp_out.a += omp_in.a) // { dg-error "const, volatile or __restrict" }
+ #pragma omp declare reduction (* : A *__restrict : omp_out->a *= omp_in->a)// { dg-error "const, volatile or __restrict" }
+}
+namespace N7
+{
+ struct A { int a; A () : a (0) {} };
+ template <typename T1, typename T2, typename T3, typename T4>
+ struct S
+ {
+ #pragma omp declare reduction (| : T1 : omp_out |= omp_in) // { dg-error "const, volatile or __restrict" }
+ #pragma omp declare reduction (+ : T2 : omp_out += omp_in) // { dg-error "const, volatile or __restrict" }
+ typedef T3 T;
+ #pragma omp declare reduction (min : T : omp_out += omp_in) // { dg-error "const, volatile or __restrict" }
+ #pragma omp declare reduction (* : T4 : omp_out *= omp_in) // { dg-error "const, volatile or __restrict" }
+ };
+ S<const A, __const A, volatile A, A *__restrict> s;
+ template <typename T1, typename T2, typename T3, typename T4>
+ int foo ()
+ {
+ #pragma omp declare reduction (| : T1 : omp_out |= omp_in) // { dg-error "const, volatile or __restrict" }
+ #pragma omp declare reduction (+ : T2 : omp_out += omp_in) // { dg-error "const, volatile or __restrict" }
+ typedef T3 T;
+ #pragma omp declare reduction (min : T : omp_out += omp_in) // { dg-error "const, volatile or __restrict" }
+ #pragma omp declare reduction (* : T4 : omp_out *= omp_in) // { dg-error "const, volatile or __restrict" }
+ return 0;
+ }
+ int x = foo <const A, __const A, volatile A, A *__restrict> ();
+}
diff --git a/gcc/testsuite/g++.dg/gomp/udr-2.C b/gcc/testsuite/g++.dg/gomp/udr-2.C
new file mode 100644
index 00000000000..48451c4fc0a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/udr-2.C
@@ -0,0 +1,119 @@
+// { dg-do compile }
+// { dg-options "-fopenmp" }
+
+struct W { int w; W () : w (0) {} W (int x) : w (x) {} };
+namespace N1
+{
+ int v;
+ #pragma omp declare reduction (foo : long int : omp_out |= v) // { dg-error "combiner refers to variable" }
+ #pragma omp declare reduction (foo : char : omp_out = v) // { dg-error "combiner refers to variable" }
+ typedef short T;
+ #pragma omp declare reduction (foo : T : omp_out += N1::v) // { dg-error "combiner refers to variable" }
+ #pragma omp declare reduction (foo : int : v *= omp_in) // { dg-error "combiner refers to variable" }
+ #pragma omp declare reduction (foo : W : omp_out.w *= omp_in.w + v) // { dg-error "combiner refers to variable" }
+}
+namespace N2
+{
+ int v;
+ template <typename T1, typename T2, typename T3, typename T4, typename T5>
+ struct S
+ {
+ #pragma omp declare reduction (foo : T1 : omp_out |= v) // { dg-error "combiner refers to variable" }
+ #pragma omp declare reduction (foo : T2 : omp_out = v) // { dg-error "combiner refers to variable" }
+ typedef T3 T;
+ #pragma omp declare reduction (foo : T : omp_out += N1::v) // { dg-error "combiner refers to variable" }
+ #pragma omp declare reduction (foo : T4 : v *= omp_in) // { dg-error "combiner refers to variable" }
+ #pragma omp declare reduction (foo : T5 : omp_out.w *= omp_in.w + v) // { dg-error "combiner refers to variable" }
+ };
+ S<long int, char, short, _Complex double, W> s;
+ template <typename T1, typename T2, typename T3, typename T4, typename T5>
+ int foo ()
+ {
+ #pragma omp declare reduction (foo : T1 : omp_out |= v) // { dg-error "combiner refers to variable" }
+ #pragma omp declare reduction (foo : T2 : omp_out = v) // { dg-error "combiner refers to variable" }
+ typedef T3 T;
+ #pragma omp declare reduction (foo : T : omp_out += N1::v) // { dg-error "combiner refers to variable" }
+ #pragma omp declare reduction (foo : T4 : v *= omp_in) // { dg-error "combiner refers to variable" }
+ #pragma omp declare reduction (foo : T5 : omp_out.w *= omp_in.w + v) // { dg-error "combiner refers to variable" }
+ return 0;
+ }
+ int x = foo <long int, char, short, _Complex double, W> ();
+}
+namespace N3
+{
+ int v;
+ #pragma omp declare reduction (foo : long int : omp_out |= omp_in) initializer (omp_priv = v) // { dg-error "initializer refers to variable" }
+ #pragma omp declare reduction (foo : char : omp_out += omp_in) initializer (omp_priv ((char) N3::v)) // { dg-error "initializer refers to variable" }
+ typedef short T;
+ #pragma omp declare reduction (foo : T : omp_out += omp_in) initializer (omp_priv = (short) v) // { dg-error "initializer refers to variable" }
+ #pragma omp declare reduction (foo : _Complex double : omp_out *= omp_in) initializer (omp_priv (v)) // { dg-error "initializer refers to variable" }
+ #pragma omp declare reduction (foo : W : omp_out.w *= omp_in.w) initializer (omp_priv (N3::v)) // { dg-error "initializer refers to variable" }
+}
+namespace N4
+{
+ int v;
+ template <typename T1, typename T2, typename T3, typename T4, typename T5>
+ struct S
+ {
+ #pragma omp declare reduction (foo : T1 : omp_out |= omp_in) initializer (omp_priv = v) // { dg-error "initializer refers to variable" }
+ #pragma omp declare reduction (foo : T2 : omp_out += omp_in) initializer (omp_priv ((char) N3::v)) // { dg-error "initializer refers to variable" }
+ typedef T3 T;
+ #pragma omp declare reduction (foo : T : omp_out += omp_in) initializer (omp_priv = (short) v) // { dg-error "initializer refers to variable" }
+ #pragma omp declare reduction (foo : T4 : omp_out *= omp_in) initializer (omp_priv (v)) // { dg-error "initializer refers to variable" }
+ #pragma omp declare reduction (foo : T5 : omp_out.w *= omp_in.w) initializer (omp_priv (N3::v)) // { dg-error "initializer refers to variable" }
+ };
+ S<long int, char, short, _Complex double, W> s;
+ template <typename T1, typename T2, typename T3, typename T4, typename T5>
+ int foo ()
+ {
+ #pragma omp declare reduction (foo : T1 : omp_out |= omp_in) initializer (omp_priv = v) // { dg-error "initializer refers to variable" }
+ #pragma omp declare reduction (foo : T2 : omp_out += omp_in) initializer (omp_priv ((char) N3::v)) // { dg-error "initializer refers to variable" }
+ typedef T3 T;
+ #pragma omp declare reduction (foo : T : omp_out += omp_in) initializer (omp_priv = (short) v) // { dg-error "initializer refers to variable" }
+ #pragma omp declare reduction (foo : T4 : omp_out *= omp_in) initializer (omp_priv (v)) // { dg-error "initializer refers to variable" }
+ #pragma omp declare reduction (foo : T5 : omp_out.w *= omp_in.w) initializer (omp_priv (N3::v)) // { dg-error "initializer refers to variable" }
+ return 0;
+ }
+ int x = foo <long int, char, short, _Complex double, W> ();
+}
+template <typename T>
+void init (T &, int &);
+template <typename T>
+void initializer (T, int &);
+namespace N5
+{
+ int v;
+ #pragma omp declare reduction (foo : long int : omp_out |= omp_in) initializer (init (omp_priv, v)) // { dg-error "initializer refers to variable" }
+ #pragma omp declare reduction (foo : char : omp_out += omp_in) initializer (initializer (&omp_priv, N3::v)) // { dg-error "initializer refers to variable" }
+ typedef short T;
+ #pragma omp declare reduction (foo : T : omp_out += omp_in) initializer (init (omp_priv, v)) // { dg-error "initializer refers to variable" }
+ #pragma omp declare reduction (foo : _Complex double : omp_out *= omp_in) initializer (initializer (&omp_priv, v)) // { dg-error "initializer refers to variable" }
+ #pragma omp declare reduction (foo : W : omp_out.w *= omp_in.w) initializer (init (omp_priv, N3::v)) // { dg-error "initializer refers to variable" }
+}
+namespace N6
+{
+ int v;
+ template <typename T1, typename T2, typename T3, typename T4, typename T5>
+ struct S
+ {
+ #pragma omp declare reduction (foo : T1 : omp_out |= omp_in) initializer (initializer (&omp_priv, v)) // { dg-error "initializer refers to variable" }
+ #pragma omp declare reduction (foo : T2 : omp_out += omp_in) initializer (init (omp_priv, N3::v)) // { dg-error "initializer refers to variable" }
+ typedef T3 T;
+ #pragma omp declare reduction (foo : T : omp_out += omp_in) initializer (init (omp_priv, v)) // { dg-error "initializer refers to variable" }
+ #pragma omp declare reduction (foo : T4 : omp_out *= omp_in) initializer (init (omp_priv, v)) // { dg-error "initializer refers to variable" }
+ #pragma omp declare reduction (foo : T5 : omp_out.w *= omp_in.w) initializer (initializer (&omp_priv, N3::v)) // { dg-error "initializer refers to variable" }
+ };
+ S<long int, char, short, _Complex double, W> s;
+ template <typename T1, typename T2, typename T3, typename T4, typename T5>
+ int foo ()
+ {
+ #pragma omp declare reduction (foo : T1 : omp_out |= omp_in) initializer (init (omp_priv, v)) // { dg-error "initializer refers to variable" }
+ #pragma omp declare reduction (foo : T2 : omp_out += omp_in) initializer (init (omp_priv, N3::v)) // { dg-error "initializer refers to variable" }
+ typedef T3 T;
+ #pragma omp declare reduction (foo : T : omp_out += omp_in) initializer (initializer (&omp_priv, v)) // { dg-error "initializer refers to variable" }
+ #pragma omp declare reduction (foo : T4 : omp_out *= omp_in) initializer (init (omp_priv, v)) // { dg-error "initializer refers to variable" }
+ #pragma omp declare reduction (foo : T5 : omp_out.w *= omp_in.w) initializer (initializer (omp_priv, N3::v)) // { dg-error "initializer refers to variable" }
+ return 0;
+ }
+ int x = foo <long int, char, short, _Complex double, W> ();
+}
diff --git a/gcc/testsuite/g++.dg/gomp/udr-3.C b/gcc/testsuite/g++.dg/gomp/udr-3.C
new file mode 100644
index 00000000000..a560fc1b537
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/udr-3.C
@@ -0,0 +1,191 @@
+// { dg-do compile }
+// { dg-options "-fopenmp" }
+
+struct S { int s; S () : s (0) {} S (int x) : s (x) {} ~S () {} };
+struct T { int t; T () : t (0) {} T (int x) : t (x) {} ~T () {} };
+
+#pragma omp declare reduction (+: ::S: omp_out.s += omp_in.s)
+#pragma omp declare reduction (*: S: omp_out.s *= omp_in.s) \
+ initializer (omp_priv (1))
+#pragma omp declare reduction (foo: S: omp_out.s += omp_in.s)
+
+void
+f1 ()
+{
+ S s, s2;
+ T t;
+ #pragma omp declare reduction (+: T: omp_out.t += omp_in.t)
+ #pragma omp parallel reduction (+: t) reduction (foo: s) reduction (*: s2)
+ s.s = 1, t.t = 1, s2.s = 2;
+ #pragma omp parallel reduction (::operator +: s)
+ s.s = 1;
+ #pragma omp parallel reduction (+: s)
+ s.s = 1;
+}
+
+template <int N>
+int
+f2 ()
+{
+ S s, s2;
+ T t;
+ #pragma omp declare reduction (+: T: omp_out.t += omp_in.t)
+ #pragma omp parallel reduction (+: t) reduction (foo: s) reduction (*: s2)
+ s.s = 1, t.t = 1, s2.s = 2;
+ #pragma omp parallel reduction (::operator +: s)
+ s.s = 1;
+ #pragma omp parallel reduction (+: s)
+ s.s = 1;
+ return 0;
+}
+
+int x = f2<0> ();
+
+void bar (S &);
+
+void
+f3 ()
+{
+ #pragma omp declare reduction (foo: S: omp_out.s += omp_in.s) initializer (bar (omp_priv))
+ #pragma omp declare reduction (bar: S: omp_out.s += omp_in.s) initializer (bar (omp_orig)) // { dg-error "one of the initializer call arguments should be" }
+}
+
+template <typename T>
+int
+f4 ()
+{
+ #pragma omp declare reduction (foo: T: omp_out.s += omp_in.s) initializer (bar (omp_priv))
+ #pragma omp declare reduction (bar: T: omp_out.s += omp_in.s) initializer (bar (omp_orig)) // { dg-error "one of the initializer call arguments should be" }
+ return 0;
+}
+
+int y = f4 <S> ();
+
+namespace N1
+{
+ #pragma omp declare reduction (+: ::S: omp_out.s *= omp_in.s) // { dg-error "previous" }
+ #pragma omp declare reduction (+: S: omp_out.s += omp_in.s) // { dg-error "redeclaration of" }
+ void
+ f5 ()
+ {
+ #pragma omp declare reduction (f5: S: omp_out.s *= omp_in.s) // { dg-error "previous" }
+ #pragma omp declare reduction (f5: ::S: omp_out.s += omp_in.s) // { dg-error "redeclaration of" }
+ }
+}
+
+namespace N2
+{
+ struct U
+ {
+ #pragma omp declare reduction (bar: S: omp_out.s *= omp_in.s) // { dg-error "with" }
+ #pragma omp declare reduction (bar: S: omp_out.s += omp_in.s) // { dg-error "cannot be overloaded" }
+ };
+}
+
+namespace N3
+{
+ #pragma omp declare reduction (+: ::S: omp_out.s *= omp_in.s) // { dg-error "previous" }
+ #pragma omp declare reduction (+: T: omp_out.t += omp_in.t)
+ #pragma omp declare reduction (+: S: omp_out.s += omp_in.s) // { dg-error "redeclaration of" }
+ #pragma omp declare reduction (n3: long: omp_out += omp_in) // { dg-error "previous" }
+ #pragma omp declare reduction (n3: long int: omp_out += omp_in) // { dg-error "redeclaration of" }
+ #pragma omp declare reduction (n3: short unsigned: omp_out += omp_in)
+ #pragma omp declare reduction (n3: short int: omp_out += omp_in)
+ void
+ f6 ()
+ {
+ #pragma omp declare reduction (f6: T: omp_out.t += omp_in.t)
+ #pragma omp declare reduction (f6: S: omp_out.s *= omp_in.s) // { dg-error "previous" }
+ #pragma omp declare reduction (f6: ::S: omp_out.s += omp_in.s) // { dg-error "redeclaration of" }
+ #pragma omp declare reduction (f6: long: omp_out += omp_in) // { dg-error "previous" }
+ #pragma omp declare reduction (f6: long int: omp_out += omp_in) // { dg-error "redeclaration of" }
+ #pragma omp declare reduction (f6: short unsigned: omp_out += omp_in)
+ #pragma omp declare reduction (f6: short int: omp_out += omp_in)
+ }
+}
+
+namespace N4
+{
+ struct U
+ {
+ #pragma omp declare reduction (bar: T: omp_out.t += omp_in.t)
+ #pragma omp declare reduction (bar: S: omp_out.s *= omp_in.s) // { dg-error "with" }
+ #pragma omp declare reduction (bar: S: omp_out.s += omp_in.s) // { dg-error "cannot be overloaded" }
+ #pragma omp declare reduction (bar: long: omp_out += omp_in) // { dg-error "with" }
+ #pragma omp declare reduction (bar: long int: omp_out += omp_in) // { dg-error "cannot be overloaded" }
+ #pragma omp declare reduction (bar: short unsigned: omp_out += omp_in)
+ #pragma omp declare reduction (bar: short int: omp_out += omp_in)
+ };
+}
+
+namespace N5
+{
+ template <typename T>
+ int
+ f7 ()
+ {
+ #pragma omp declare reduction (f7: T: omp_out.s *= omp_in.s) // { dg-error "previous" }
+ #pragma omp declare reduction (f7: T: omp_out.s += omp_in.s) // { dg-error "redeclaration of" }
+ return 0;
+ }
+ int x = f7 <S> ();
+ template <typename T>
+ struct U
+ {
+ #pragma omp declare reduction (bar: T: omp_out.s *= omp_in.s) // { dg-error "with" }
+ #pragma omp declare reduction (bar: T: omp_out.s += omp_in.s) // { dg-error "cannot be overloaded" }
+ };
+ U<S> u;
+}
+
+namespace N6
+{
+ template <typename U>
+ int
+ f8 ()
+ {
+ #pragma omp declare reduction (f8: T: omp_out.t += omp_in.t)
+ #pragma omp declare reduction (f8: U: omp_out.s *= omp_in.s) // { dg-error "previous" }
+ #pragma omp declare reduction (f8: ::S: omp_out.s += omp_in.s) // { dg-error "redeclaration of" }
+ #pragma omp declare reduction (f8: long: omp_out += omp_in) // { dg-error "previous" }
+ #pragma omp declare reduction (f8: long int: omp_out += omp_in) // { dg-error "redeclaration of" }
+ #pragma omp declare reduction (f8: short unsigned: omp_out += omp_in)
+ #pragma omp declare reduction (f8: short int: omp_out += omp_in)
+ return 0;
+ }
+ int x = f8 <S> ();
+ template <typename V>
+ struct U
+ {
+ typedef V V2;
+ #pragma omp declare reduction (bar: T: omp_out.t += omp_in.t)
+ #pragma omp declare reduction (bar: V: omp_out.s *= omp_in.s) // { dg-error "with" }
+ #pragma omp declare reduction (bar: V2: omp_out.s += omp_in.s) // { dg-error "cannot be overloaded" }
+ #pragma omp declare reduction (bar: long: omp_out += omp_in) // { dg-error "with" }
+ #pragma omp declare reduction (bar: long int: omp_out += omp_in) // { dg-error "cannot be overloaded" }
+ #pragma omp declare reduction (bar: short unsigned: omp_out += omp_in)
+ #pragma omp declare reduction (bar: short int: omp_out += omp_in)
+ };
+ U<S> u;
+}
+
+namespace N7
+{
+ #pragma omp declare reduction (+: S: omp_out.s += omp_in.s) initializer (omp_priv) // { dg-error "invalid initializer clause" }
+ #pragma omp declare reduction (+: T: omp_out.t += omp_in.t) initializer (omp_priv ()) // { dg-error "invalid initializer clause" }
+}
+
+namespace N8
+{
+ struct A { int a; A (); ~A (); };
+ struct B { int b; B (); ~B (); B (int); };
+ struct C : public A, B { int c; C (); ~C (); };
+ #pragma omp declare reduction (+:B:omp_out.b += omp_in.b) initializer (omp_priv (4))
+ void bar (C &);
+ void baz ()
+ {
+ C a;
+ #pragma omp parallel reduction (+:a) // { dg-error "user defined reduction with constructor initializer for base class" }
+ bar (a);
+ }
+}
diff --git a/gcc/testsuite/g++.dg/gomp/udr-4.C b/gcc/testsuite/g++.dg/gomp/udr-4.C
new file mode 100644
index 00000000000..f1b388bbd91
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/udr-4.C
@@ -0,0 +1,14 @@
+// { dg-do compile }
+
+struct S; // { dg-error "forward declaration" }
+#pragma omp declare reduction (+:S:omp_out.s += omp_in.s) // { dg-error "invalid use of incomplete type" }
+struct S { int s; S () : s (1) {} };
+#pragma omp declare reduction (*:S:omp_out.s *= omp_in.s)
+
+void
+foo ()
+{
+ S s;
+ #pragma omp parallel reduction (S::~S:s) // { dg-error "invalid reduction-identifier" }
+ s.s = 1;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/udr-5.C b/gcc/testsuite/g++.dg/gomp/udr-5.C
new file mode 100644
index 00000000000..425f8e95cd9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/udr-5.C
@@ -0,0 +1,41 @@
+// { dg-do compile }
+
+struct S
+{
+ int s;
+ S () : s (0) {}
+private:
+ #pragma omp declare reduction (+:S:omp_out.s += omp_in.s) // { dg-error "is private" }
+protected:
+ #pragma omp declare reduction (-:S:omp_out.s += omp_in.s) // { dg-error "is protected" }
+};
+
+struct T : public S
+{
+ void foo ()
+ {
+ S s;
+ #pragma omp parallel reduction (S::operator +:s) // { dg-error "within this context" }
+ s.s = 1;
+ S t;
+ #pragma omp parallel reduction (S::operator -:t)
+ t.s = 1;
+ S u;
+ #pragma omp parallel reduction (+:u) // { dg-error "within this context" }
+ u.s = 1;
+ S v;
+ #pragma omp parallel reduction (-:v)
+ v.s = 1;
+ }
+};
+
+void
+foo ()
+{
+ S s;
+ #pragma omp parallel reduction (S::operator +:s) // { dg-error "within this context" }
+ s.s = 1;
+ S t;
+ #pragma omp parallel reduction (S::operator -:t) // { dg-error "within this context" }
+ t.s = 1;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/udr-6.C b/gcc/testsuite/g++.dg/gomp/udr-6.C
new file mode 100644
index 00000000000..9060c87a542
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/udr-6.C
@@ -0,0 +1,59 @@
+// { dg-do compile }
+
+struct A { int a; A () : a (0) {} };
+struct B { int b; B () : b (0) {} };
+struct C : public A, B { int c; C () : c (0) {} };
+struct D { int d; D () : d (0) {} };
+struct E { int e; E () : e (0) {} };
+struct F : public D, E { int f; F () : f (0) {} };
+struct G : public C, F { int g; G () : g (0) {} };
+
+#pragma omp declare reduction (+: A : omp_out.a += omp_in.a) // { dg-message "operator" }
+#pragma omp declare reduction (+: B : omp_out.b += omp_in.b) // { dg-message "operator" }
+#pragma omp declare reduction (+: D : omp_out.d += omp_in.d)
+#pragma omp declare reduction (+: E : omp_out.e += omp_in.e)
+#pragma omp declare reduction (+: F : omp_out.f += omp_in.f) // { dg-message "operator" }
+
+void
+f1 ()
+{
+ G g;
+ #pragma omp parallel reduction (+: g) // { dg-error "user defined reduction lookup is ambiguous" }
+ {
+ g.g++;
+ }
+}
+
+#pragma omp declare reduction (*: A : omp_out.a += omp_in.a)
+#pragma omp declare reduction (*: B : omp_out.b += omp_in.b)
+#pragma omp declare reduction (*: D : omp_out.d += omp_in.d)
+#pragma omp declare reduction (*: E : omp_out.e += omp_in.e)
+#pragma omp declare reduction (*: F : omp_out.f += omp_in.f)
+#pragma omp declare reduction (*: G : omp_out.g += omp_in.g)
+
+void
+f2 ()
+{
+ G g;
+ #pragma omp parallel reduction (*: g)
+ {
+ g.g++;
+ }
+}
+
+#pragma omp declare reduction (|: A : omp_out.a += omp_in.a)
+#pragma omp declare reduction (|: B : omp_out.b += omp_in.b)
+#pragma omp declare reduction (|: C : omp_out.c += omp_in.c) // { dg-message "operator" }
+#pragma omp declare reduction (|: D : omp_out.d += omp_in.d)
+#pragma omp declare reduction (|: E : omp_out.e += omp_in.e)
+#pragma omp declare reduction (|: F : omp_out.f += omp_in.f) // { dg-message "operator" }
+
+void
+f3 ()
+{
+ G g;
+ #pragma omp parallel reduction (|: g) // { dg-error "user defined reduction lookup is ambiguous" }
+ {
+ g.g++;
+ }
+}
diff --git a/gcc/testsuite/gcc.dg/autopar/outer-1.c b/gcc/testsuite/gcc.dg/autopar/outer-1.c
index 913d390f684..a9d2185f0ce 100644
--- a/gcc/testsuite/gcc.dg/autopar/outer-1.c
+++ b/gcc/testsuite/gcc.dg/autopar/outer-1.c
@@ -28,6 +28,6 @@ int main(void)
/* Check that outer loop is parallelized. */
/* { dg-final { scan-tree-dump-times "parallelizing outer loop" 1 "parloops" } } */
-/* { dg-final { scan-tree-dump-times "loopfn" 5 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "loopfn" 4 "optimized" } } */
/* { dg-final { cleanup-tree-dump "parloops" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/autopar/outer-2.c b/gcc/testsuite/gcc.dg/autopar/outer-2.c
index b2e51598203..e0a142f0d11 100644
--- a/gcc/testsuite/gcc.dg/autopar/outer-2.c
+++ b/gcc/testsuite/gcc.dg/autopar/outer-2.c
@@ -28,6 +28,6 @@ int main(void)
}
/* { dg-final { scan-tree-dump-times "parallelizing outer loop" 1 "parloops" } } */
-/* { dg-final { scan-tree-dump-times "loopfn" 5 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "loopfn" 4 "optimized" } } */
/* { dg-final { cleanup-tree-dump "parloops" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/autopar/outer-3.c b/gcc/testsuite/gcc.dg/autopar/outer-3.c
index 2f1033f9830..c6e0adbffdf 100644
--- a/gcc/testsuite/gcc.dg/autopar/outer-3.c
+++ b/gcc/testsuite/gcc.dg/autopar/outer-3.c
@@ -28,6 +28,6 @@ int main(void)
/* Check that outer loop is parallelized. */
/* { dg-final { scan-tree-dump-times "parallelizing outer loop" 1 "parloops" } } */
-/* { dg-final { scan-tree-dump-times "loopfn" 5 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "loopfn" 4 "optimized" } } */
/* { dg-final { cleanup-tree-dump "parloops" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/autopar/outer-4.c b/gcc/testsuite/gcc.dg/autopar/outer-4.c
index 56f6123385d..d60023f5d86 100644
--- a/gcc/testsuite/gcc.dg/autopar/outer-4.c
+++ b/gcc/testsuite/gcc.dg/autopar/outer-4.c
@@ -32,6 +32,6 @@ int main(void)
/* { dg-final { scan-tree-dump-times "parallelizing outer loop" 1 "parloops" { xfail *-*-* } } } */
-/* { dg-final { scan-tree-dump-times "loopfn" 5 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "loopfn" 4 "optimized" } } */
/* { dg-final { cleanup-tree-dump "parloops" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/autopar/outer-5.c b/gcc/testsuite/gcc.dg/autopar/outer-5.c
index 3a542988c26..fa80293263c 100644
--- a/gcc/testsuite/gcc.dg/autopar/outer-5.c
+++ b/gcc/testsuite/gcc.dg/autopar/outer-5.c
@@ -45,6 +45,6 @@ int main(void)
}
/* { dg-final { scan-tree-dump-times "parallelizing outer loop" 1 "parloops" { xfail *-*-* } } } */
-/* { dg-final { scan-tree-dump-times "loopfn" 5 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "loopfn" 4 "optimized" } } */
/* { dg-final { cleanup-tree-dump "parloops" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/autopar/outer-6.c b/gcc/testsuite/gcc.dg/autopar/outer-6.c
index 6e027d2f69a..b16366932fe 100644
--- a/gcc/testsuite/gcc.dg/autopar/outer-6.c
+++ b/gcc/testsuite/gcc.dg/autopar/outer-6.c
@@ -46,6 +46,6 @@ int main(void)
/* Check that outer loop is parallelized. */
/* { dg-final { scan-tree-dump-times "parallelizing outer loop" 1 "parloops" } } */
/* { dg-final { scan-tree-dump-times "parallelizing inner loop" 0 "parloops" } } */
-/* { dg-final { scan-tree-dump-times "loopfn" 5 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "loopfn" 4 "optimized" } } */
/* { dg-final { cleanup-tree-dump "parloops" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/autopar/parallelization-1.c b/gcc/testsuite/gcc.dg/autopar/parallelization-1.c
index f53be8598db..de2a0f3cc71 100644
--- a/gcc/testsuite/gcc.dg/autopar/parallelization-1.c
+++ b/gcc/testsuite/gcc.dg/autopar/parallelization-1.c
@@ -28,6 +28,6 @@ int main(void)
/* Check that the first loop in parloop got parallelized. */
/* { dg-final { scan-tree-dump-times "SUCCESS: may be parallelized" 1 "parloops" } } */
-/* { dg-final { scan-tree-dump-times "loopfn" 5 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "loopfn" 4 "optimized" } } */
/* { dg-final { cleanup-tree-dump "parloops" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/gomp/block-3.c b/gcc/testsuite/gcc.dg/gomp/block-3.c
index c72b04c35d0..b4530e9d06c 100644
--- a/gcc/testsuite/gcc.dg/gomp/block-3.c
+++ b/gcc/testsuite/gcc.dg/gomp/block-3.c
@@ -35,9 +35,10 @@ void foo()
#pragma omp sections
{
- goto ok1;
- ok1:;
-
+ {
+ goto ok1;
+ ok1:;
+ }
#pragma omp section
for (i = 0; i < 10; ++i)
if (test(i))
diff --git a/gcc/testsuite/gcc.dg/gomp/clause-1.c b/gcc/testsuite/gcc.dg/gomp/clause-1.c
index ba189896c62..fc7d72b7cd2 100644
--- a/gcc/testsuite/gcc.dg/gomp/clause-1.c
+++ b/gcc/testsuite/gcc.dg/gomp/clause-1.c
@@ -11,7 +11,7 @@ int t;
void
foo (int x)
{
- char *p;
+ char *pp;
struct S { int i; int j; } s;
char a[32];
double d;
@@ -42,11 +42,11 @@ foo (int x)
;
#pragma omp p firstprivate (bar) /* { dg-error "is not a variable" } */
;
-#pragma omp p reduction (+:p) /* { dg-error "has invalid type for" } */
+#pragma omp p reduction (+:pp) /* { dg-error "user defined reduction not found for" } */
;
-#pragma omp p reduction (*:s) /* { dg-error "has invalid type for" } */
+#pragma omp p reduction (*:s) /* { dg-error "user defined reduction not found for" } */
;
-#pragma omp p reduction (-:a) /* { dg-error "has invalid type for" } */
+#pragma omp p reduction (-:a) /* { dg-error "user defined reduction not found for" } */
;
d = 0;
#pragma omp p reduction (*:d)
diff --git a/gcc/testsuite/gcc.dg/gomp/combined-1.c b/gcc/testsuite/gcc.dg/gomp/combined-1.c
index dfed647371f..7e23c3256cb 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 00000000000..259e2c0ae92
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gomp/declare-simd-1.c
@@ -0,0 +1,100 @@
+/* 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);
+
+#pragma omp declare simd aligned (g : sizeof (*g)) linear (h : 2 * sizeof (g[0]) + sizeof (h)) simdlen (4)
+int f16 (long *g, int h);
+
+#pragma omp declare simd aligned (h : sizeof (*h)) linear (g : 2 * sizeof (h[0]) + sizeof (g)) simdlen (4)
+int f17 (int g, long *h)
+{
+ return g + h[0];
+}
+
+#pragma omp declare simd aligned (i : sizeof (*i)) linear (j : 2 * sizeof (i[0]) + sizeof (j)) simdlen (4)
+int
+f18 (j, i)
+ long *i;
+ int j;
+{
+ return j + i[0];
+}
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 00000000000..118549be908
--- /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/gcc.dg/gomp/nesting-1.c b/gcc/testsuite/gcc.dg/gomp/nesting-1.c
index df57ac845f7..52fcda741ea 100644
--- a/gcc/testsuite/gcc.dg/gomp/nesting-1.c
+++ b/gcc/testsuite/gcc.dg/gomp/nesting-1.c
@@ -28,17 +28,58 @@ f1 (void)
#pragma omp for /* { dg-error "may not be closely nested" } */
for (j = 0; j < 3; j++)
;
+ }
+ #pragma omp sections
+ {
#pragma omp sections /* { dg-error "may not be closely nested" } */
{
;
#pragma omp section
;
}
+ }
+ #pragma omp sections
+ {
#pragma omp single /* { dg-error "may not be closely nested" } */
;
+ }
+ #pragma omp sections
+ {
#pragma omp master /* { dg-error "may not be closely nested" } */
;
+ }
+ #pragma omp sections
+ {
+ #pragma omp section
+ ;
+ }
+ #pragma omp sections
+ {
#pragma omp section
+ #pragma omp for /* { dg-error "may not be closely nested" } */
+ for (j = 0; j < 3; j++)
+ ;
+ }
+ #pragma omp sections
+ {
+ #pragma omp section
+ #pragma omp sections /* { dg-error "may not be closely nested" } */
+ {
+ ;
+ #pragma omp section
+ ;
+ }
+ }
+ #pragma omp sections
+ {
+ #pragma omp section
+ #pragma omp single /* { dg-error "may not be closely nested" } */
+ ;
+ }
+ #pragma omp sections
+ {
+ #pragma omp section
+ #pragma omp master /* { dg-error "may not be closely nested" } */
;
}
#pragma omp single
diff --git a/gcc/testsuite/gcc.dg/gomp/target-1.c b/gcc/testsuite/gcc.dg/gomp/target-1.c
new file mode 100644
index 00000000000..09e65bd3115
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gomp/target-1.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+
+void
+foo (int x)
+{
+ bad1:
+ #pragma omp target
+ goto bad1; /* { dg-error "invalid branch" } */
+
+ goto bad2; /* { dg-error "invalid entry" } */
+ #pragma omp target
+ {
+ bad2: ;
+ }
+
+ #pragma omp target
+ {
+ int i;
+ goto ok1;
+ for (i = 0; i < 10; ++i)
+ { ok1: break; }
+ }
+
+ switch (x) /* { dg-error "invalid entry" } */
+ {
+ #pragma omp target
+ { case 0:; }
+ }
+}
diff --git a/gcc/testsuite/gcc.dg/gomp/target-2.c b/gcc/testsuite/gcc.dg/gomp/target-2.c
new file mode 100644
index 00000000000..546a1d0c157
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gomp/target-2.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+
+void
+foo (int x, int y)
+{
+ bad1:
+ #pragma omp target data map(tofrom: y)
+ goto bad1; /* { dg-error "invalid branch" } */
+
+ goto bad2; /* { dg-error "invalid entry" } */
+ #pragma omp target data map(tofrom: y)
+ {
+ bad2: ;
+ }
+
+ #pragma omp target data map(tofrom: y)
+ {
+ int i;
+ goto ok1;
+ for (i = 0; i < 10; ++i)
+ { ok1: break; }
+ }
+
+ switch (x) /* { dg-error "invalid entry" } */
+ {
+ #pragma omp target data map(tofrom: y)
+ { case 0:; }
+ }
+}
diff --git a/gcc/testsuite/gcc.dg/gomp/taskgroup-1.c b/gcc/testsuite/gcc.dg/gomp/taskgroup-1.c
new file mode 100644
index 00000000000..e301efc19c4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gomp/taskgroup-1.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+
+void
+foo (int x)
+{
+ bad1:
+ #pragma omp taskgroup
+ goto bad1; /* { dg-error "invalid branch" } */
+
+ goto bad2; /* { dg-error "invalid entry" } */
+ #pragma omp taskgroup
+ {
+ bad2: ;
+ }
+
+ #pragma omp taskgroup
+ {
+ int i;
+ goto ok1;
+ for (i = 0; i < 10; ++i)
+ { ok1: break; }
+ }
+
+ switch (x) /* { dg-error "invalid entry" } */
+ {
+ #pragma omp taskgroup
+ { case 0:; }
+ }
+}
diff --git a/gcc/testsuite/gcc.dg/gomp/teams-1.c b/gcc/testsuite/gcc.dg/gomp/teams-1.c
new file mode 100644
index 00000000000..73c00ded78b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gomp/teams-1.c
@@ -0,0 +1,61 @@
+/* { dg-do compile } */
+
+void
+foo (int x)
+{
+ bad1:
+ #pragma omp target teams
+ goto bad1; /* { dg-error "invalid branch" } */
+
+ goto bad2; /* { dg-error "invalid entry" } */
+ #pragma omp target teams
+ {
+ bad2: ;
+ }
+
+ #pragma omp target teams
+ {
+ int i;
+ goto ok1;
+ for (i = 0; i < 10; ++i)
+ { ok1: break; }
+ }
+
+ switch (x) /* { dg-error "invalid entry" } */
+ {
+ #pragma omp target teams
+ { case 0:; }
+ }
+}
+
+void
+bar (int x)
+{
+ bad1:
+ #pragma omp target
+ #pragma omp teams
+ goto bad1; /* { dg-error "invalid branch" } */
+
+ goto bad2; /* { dg-error "invalid entry" } */
+ #pragma omp target
+ #pragma omp teams
+ {
+ bad2: ;
+ }
+
+ #pragma omp target
+ #pragma omp teams
+ {
+ int i;
+ goto ok1;
+ for (i = 0; i < 10; ++i)
+ { ok1: break; }
+ }
+
+ switch (x) /* { dg-error "invalid entry" } */
+ {
+ #pragma omp target
+ #pragma omp teams
+ { case 0:; }
+ }
+}
diff --git a/gcc/testsuite/gcc.dg/gomp/udr-1.c b/gcc/testsuite/gcc.dg/gomp/udr-1.c
new file mode 100644
index 00000000000..4948a984f69
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gomp/udr-1.c
@@ -0,0 +1,46 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+#pragma omp declare reduction (| : long int : omp_out |= omp_in) /* { dg-error "predeclared arithmetic type" } */
+#pragma omp declare reduction (+ : char : omp_out += omp_in) /* { dg-error "predeclared arithmetic type" } */
+typedef short T;
+#pragma omp declare reduction (min : T : omp_out += omp_in) /* { dg-error "predeclared arithmetic type" } */
+#pragma omp declare reduction (* : _Complex double : omp_out *= omp_in) /* { dg-error "predeclared arithmetic type" } */
+
+void
+foo (void)
+{
+ #pragma omp declare reduction (| : long int : omp_out |= omp_in) /* { dg-error "predeclared arithmetic type" } */
+ #pragma omp declare reduction (+ : char : omp_out += omp_in) /* { dg-error "predeclared arithmetic type" } */
+ #pragma omp declare reduction (min : T : omp_out += omp_in) /* { dg-error "predeclared arithmetic type" } */
+ #pragma omp declare reduction (* : _Complex double : omp_out *= omp_in) /* { dg-error "predeclared arithmetic type" } */
+}
+
+#pragma omp declare reduction (| : __typeof (foo) : omp_out |= omp_in) /* { dg-error "function or array" } */
+#pragma omp declare reduction (+ : char () : omp_out += omp_in) /* { dg-error "function or array" } */
+#pragma omp declare reduction (min : T[2] : omp_out += omp_in) /* { dg-error "function or array" } */
+
+void
+bar (void)
+{
+ #pragma omp declare reduction (| : __typeof (foo) : omp_out |= omp_in)/* { dg-error "function or array" } */
+ #pragma omp declare reduction (+ : char () : omp_out += omp_in) /* { dg-error "function or array" } */
+ #pragma omp declare reduction (min : T[2] : omp_out += omp_in) /* { dg-error "function or array" } */
+}
+
+struct A { int a; };
+#pragma omp declare reduction (| : const struct A : omp_out.a |= omp_in.a) /* { dg-error "const, volatile or restrict" } */
+#pragma omp declare reduction (+ : __const struct A : omp_out.a += omp_in.a) /* { dg-error "const, volatile or restrict" } */
+typedef volatile struct A T2;
+#pragma omp declare reduction (min : T2 : omp_out.a += omp_in.a) /* { dg-error "const, volatile or restrict" } */
+#pragma omp declare reduction (* : struct A *__restrict : omp_out->a *= omp_in->a)/* { dg-error "const, volatile or restrict" } */
+
+void
+baz (void)
+{
+ #pragma omp declare reduction (| : const struct A : omp_out.a |= omp_in.a) /* { dg-error "const, volatile or restrict" } */
+ #pragma omp declare reduction (+ : __const struct A : omp_out.a += omp_in.a) /* { dg-error "const, volatile or restrict" } */
+ typedef volatile struct A T3;
+ #pragma omp declare reduction (min : T3 : omp_out.a += omp_in.a) /* { dg-error "const, volatile or restrict" } */
+ #pragma omp declare reduction (* : struct A *__restrict : omp_out->a *= omp_in->a)/* { dg-error "const, volatile or restrict" } */
+}
diff --git a/gcc/testsuite/gcc.dg/gomp/udr-2.c b/gcc/testsuite/gcc.dg/gomp/udr-2.c
new file mode 100644
index 00000000000..87992d7c6ed
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gomp/udr-2.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+struct W { int w; };
+void init (struct W *, int, int *);
+int v;
+#pragma omp declare reduction (foo : long int : omp_out |= v) /* { dg-error "combiner refers to variable" } */
+#pragma omp declare reduction (foo : char : omp_out = v) /* { dg-error "combiner refers to variable" } */
+typedef short T;
+#pragma omp declare reduction (foo : T : omp_out += v) /* { dg-error "combiner refers to variable" } */
+#pragma omp declare reduction (foo : int : v *= omp_in) /* { dg-error "combiner refers to variable" } */
+#pragma omp declare reduction (foo : struct W : omp_out.w *= omp_in.w + v) /* { dg-error "combiner refers to variable" } */
+
+void
+foo (int v)
+{
+ #pragma omp declare reduction (foo : long int : omp_out |= v) /* { dg-error "combiner refers to variable" } */
+ #pragma omp declare reduction (foo : char : omp_out = v) /* { dg-error "combiner refers to variable" } */
+ #pragma omp declare reduction (foo : T : omp_out += v) /* { dg-error "combiner refers to variable" } */
+ #pragma omp declare reduction (foo : int : v *= omp_in) /* { dg-error "combiner refers to variable" } */
+ #pragma omp declare reduction (foo : struct W : omp_out.w *= omp_in.w + v) /* { dg-error "combiner refers to variable" } */
+}
+
+#pragma omp declare reduction (bar : long int : omp_out |= omp_in) initializer (omp_priv = v) /* { dg-error "initializer refers to variable" } */
+#pragma omp declare reduction (bar : char : omp_out += omp_in) initializer (omp_priv = ((char) v)) /* { dg-error "initializer refers to variable" } */
+#pragma omp declare reduction (bar : T : omp_out += omp_in) initializer (omp_priv = (short) v) /* { dg-error "initializer refers to variable" } */
+#pragma omp declare reduction (bar : _Complex double : omp_out *= omp_in) initializer (omp_priv = (v)) /* { dg-error "initializer refers to variable" } */
+#pragma omp declare reduction (bar : struct W : omp_out.w *= omp_in.w) initializer (omp_priv = { v } ) /* { dg-error "initializer refers to variable" } */
+#pragma omp declare reduction (bar2 : struct W : omp_out.w *= omp_in.w) initializer (init (&omp_priv, v, (int *) 0)) /* { dg-error "initializer refers to variable" } */
+#pragma omp declare reduction (bar3 : struct W : omp_out.w *= omp_in.w) initializer (init (&omp_priv, 0, &v)) /* { dg-error "initializer refers to variable" } */
+
+void
+bar (int v)
+{
+ #pragma omp declare reduction (bar : long int : omp_out |= omp_in) initializer (omp_priv = v) /* { dg-error "initializer refers to variable" } */
+ #pragma omp declare reduction (bar : char : omp_out += omp_in) initializer (omp_priv = ((char) v)) /* { dg-error "initializer refers to variable" } */
+ #pragma omp declare reduction (bar : T : omp_out += omp_in) initializer (omp_priv = (short) v) /* { dg-error "initializer refers to variable" } */
+ #pragma omp declare reduction (bar : _Complex double : omp_out *= omp_in) initializer (omp_priv = (v)) /* { dg-error "initializer refers to variable" } */
+ #pragma omp declare reduction (bar : struct W : omp_out.w *= omp_in.w) initializer (omp_priv = { v }) /* { dg-error "initializer refers to variable" } */
+ #pragma omp declare reduction (bar2 : struct W : omp_out.w *= omp_in.w) initializer (init (&omp_priv, v, (int *) 0)) /* { dg-error "initializer refers to variable" } */
+ #pragma omp declare reduction (bar3 : struct W : omp_out.w *= omp_in.w) initializer (init (&omp_priv, 0, &v)) /* { dg-error "initializer refers to variable" } */
+}
diff --git a/gcc/testsuite/gcc.dg/gomp/udr-3.c b/gcc/testsuite/gcc.dg/gomp/udr-3.c
new file mode 100644
index 00000000000..bdfcce1d0b6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gomp/udr-3.c
@@ -0,0 +1,77 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+struct S { int s; };
+struct T { int t; };
+struct U { int u; };
+
+#pragma omp declare reduction (+: struct S: omp_out.s += omp_in.s)
+#pragma omp declare reduction (*: struct S: omp_out.s *= omp_in.s) \
+ initializer (omp_priv = {1})
+#pragma omp declare reduction (foo: struct S: omp_out.s += omp_in.s)
+
+void
+f1 ()
+{
+ struct S s, s2;
+ struct T t;
+ #pragma omp declare reduction (+: struct T: omp_out.t += omp_in.t)
+ #pragma omp parallel reduction (+: t) reduction (foo: s) reduction (*: s2)
+ s.s = 1, t.t = 1, s2.s = 2;
+ #pragma omp parallel reduction (+: s)
+ s.s = 1;
+}
+
+void bar (struct S *);
+
+void
+f2 ()
+{
+ #pragma omp declare reduction (foo: struct S: omp_out.s += omp_in.s) initializer (bar (&omp_priv))
+ #pragma omp declare reduction (bar: struct S: omp_out.s += omp_in.s) initializer (bar (&omp_orig)) /* { dg-error "one of the initializer call arguments should be" } */
+}
+
+#pragma omp declare reduction (+: struct U: omp_out.u *= omp_in.u) /* { dg-error "previous" } */
+#pragma omp declare reduction (+: struct U: omp_out.u += omp_in.u) /* { dg-error "redeclaration of" } */
+
+void
+f3 ()
+{
+ #pragma omp declare reduction (f3: struct U: omp_out.u *= omp_in.u) /* { dg-error "previous" } */
+ #pragma omp declare reduction (f3: struct U: omp_out.u += omp_in.u) /* { dg-error "redeclaration of" } */
+}
+
+struct V
+{
+ #pragma omp declare reduction (bar: struct S: omp_out.s *= omp_in.s) /* { dg-error "not at file or block scope" } */
+ #pragma omp declare reduction (bar: struct S: omp_out.s += omp_in.s) /* { dg-error "not at file or block scope" } */
+};
+
+#pragma omp declare reduction (n3: long: omp_out += omp_in) /* { dg-error "previous" } */
+#pragma omp declare reduction (n3: long int: omp_out += omp_in) /* { dg-error "redeclaration of" } */
+#pragma omp declare reduction (n3: short unsigned: omp_out += omp_in)
+#pragma omp declare reduction (n3: short int: omp_out += omp_in)
+
+void
+f4 (void)
+{
+ #pragma omp declare reduction (f4: long: omp_out += omp_in) /* { dg-error "previous" } */
+ #pragma omp declare reduction (f4: long int: omp_out += omp_in) /* { dg-error "redeclaration of" } */
+ #pragma omp declare reduction (f4: short unsigned: omp_out += omp_in)
+ #pragma omp declare reduction (f4: short int: omp_out += omp_in)
+}
+
+void
+f5 (void)
+{
+ #pragma omp declare reduction (+: struct S: omp_out.s += omp_in.s) initializer (omp_priv) /* { dg-error "expected" } */
+ #pragma omp declare reduction (+: struct T: omp_out.t += omp_in.t) initializer (omp_priv ()) /* { dg-error "expected" } */
+}
+
+void
+f6 (a, b)
+#pragma omp declare reduction (bar: struct S: omp_out.s *= omp_in.s) /* { dg-error "expected declaration specifiers before" } */
+ int a;
+ int b;
+{
+}
diff --git a/gcc/testsuite/gcc.dg/gomp/udr-4.c b/gcc/testsuite/gcc.dg/gomp/udr-4.c
new file mode 100644
index 00000000000..3758f91e851
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gomp/udr-4.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+
+struct S;
+#pragma omp declare reduction (+:struct S:omp_out.s += omp_in.s) /* { dg-error "invalid use of undefined type" } */
+struct S { int s; };
+#pragma omp declare reduction (*:struct S:omp_out.s *= omp_in.s)
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 083c0b3b723..a580a3baf66 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 @@
!$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 de66d07d8a2..8b667917747 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -611,7 +611,9 @@ make_edges (void)
case GIMPLE_OMP_TASK:
case GIMPLE_OMP_FOR:
case GIMPLE_OMP_SINGLE:
+ case GIMPLE_OMP_TEAMS:
case GIMPLE_OMP_MASTER:
+ case GIMPLE_OMP_TASKGROUP:
case GIMPLE_OMP_ORDERED:
case GIMPLE_OMP_CRITICAL:
case GIMPLE_OMP_SECTION:
@@ -619,6 +621,13 @@ make_edges (void)
fallthru = true;
break;
+ case GIMPLE_OMP_TARGET:
+ cur_region = new_omp_region (bb, code, cur_region);
+ fallthru = true;
+ if (gimple_omp_target_kind (last) == GF_OMP_TARGET_KIND_UPDATE)
+ cur_region = cur_region->outer;
+ break;
+
case GIMPLE_OMP_SECTIONS:
cur_region = new_omp_region (bb, code, cur_region);
fallthru = true;
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 0b3314bc55e..a14c7e079b3 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -243,9 +243,27 @@ enum omp_clause_code {
/* 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,
@@ -276,9 +294,45 @@ enum omp_clause_code {
/* OpenMP 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_
};
@@ -784,6 +838,12 @@ struct GTY(()) tree_base {
OMP_CLAUSE_LINEAR_NO_COPYIN in
OMP_CLAUSE_LINEAR
+ OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION in
+ OMP_CLAUSE_MAP
+
+ OMP_CLAUSE_REDUCTION_OMP_ORIG_REF in
+ OMP_CLAUSE_REDUCTION
+
TRANSACTION_EXPR_RELAXED in
TRANSACTION_EXPR
@@ -801,6 +861,9 @@ 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
@@ -1020,6 +1083,35 @@ struct GTY(()) tree_constructor {
vec<constructor_elt, va_gc> *elts;
};
+enum omp_clause_depend_kind
+{
+ OMP_CLAUSE_DEPEND_IN,
+ OMP_CLAUSE_DEPEND_OUT,
+ OMP_CLAUSE_DEPEND_INOUT
+};
+
+enum omp_clause_map_kind
+{
+ OMP_CLAUSE_MAP_ALLOC,
+ OMP_CLAUSE_MAP_TO,
+ OMP_CLAUSE_MAP_FROM,
+ OMP_CLAUSE_MAP_TOFROM,
+ /* The following kind 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
+};
+
+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
+};
+
struct GTY(()) tree_exp {
struct tree_typed typed;
location_t locus;
@@ -1077,9 +1169,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
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index ef8eba473a2..2221b9c5486 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -1345,6 +1345,11 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
copy = gimple_build_omp_master (s1);
break;
+ case GIMPLE_OMP_TASKGROUP:
+ s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
+ copy = gimple_build_omp_taskgroup (s1);
+ break;
+
case GIMPLE_OMP_ORDERED:
s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
copy = gimple_build_omp_ordered (s1);
@@ -1367,6 +1372,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
@@ -3831,10 +3849,13 @@ estimate_num_insns (gimple stmt, eni_weights *weights)
case GIMPLE_OMP_TASK:
case GIMPLE_OMP_CRITICAL:
case GIMPLE_OMP_MASTER:
+ case GIMPLE_OMP_TASKGROUP:
case GIMPLE_OMP_ORDERED:
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 c6703b78acf..7582289c1c2 100644
--- a/gcc/tree-nested.c
+++ b/gcc/tree-nested.c
@@ -1291,8 +1291,25 @@ 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_TASKGROUP:
case GIMPLE_OMP_ORDERED:
walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op,
info, gimple_omp_body_ptr (stmt));
@@ -1714,8 +1731,25 @@ 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_TASKGROUP:
case GIMPLE_OMP_ORDERED:
walk_body (convert_local_reference_stmt, convert_local_reference_op,
info, gimple_omp_body_ptr (stmt));
@@ -2071,7 +2105,10 @@ 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_TASKGROUP:
case GIMPLE_OMP_ORDERED:
case GIMPLE_OMP_CRITICAL:
walk_body (convert_gimple_call, NULL, info, gimple_omp_body_ptr (stmt));
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index c357b06f978..df0f8b52ec6 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -319,6 +319,9 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags)
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_left_paren (buffer);
@@ -329,24 +332,28 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags)
case OMP_CLAUSE_REDUCTION:
pp_string (buffer, "reduction(");
- pp_string (buffer, op_symbol_code (OMP_CLAUSE_REDUCTION_CODE (clause)));
- pp_colon (buffer);
+ if (OMP_CLAUSE_REDUCTION_CODE (clause) != ERROR_MARK)
+ {
+ pp_string (buffer,
+ op_symbol_code (OMP_CLAUSE_REDUCTION_CODE (clause)));
+ pp_colon (buffer);
+ }
dump_generic_node (buffer, OMP_CLAUSE_DECL (clause),
- spc, flags, false);
+ spc, flags, false);
pp_right_paren (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_right_paren (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_right_paren (buffer);
break;
@@ -385,30 +392,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_comma (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_right_paren (buffer);
break;
@@ -419,8 +425,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_right_paren (buffer);
break;
@@ -428,7 +433,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_right_paren (buffer);
break;
@@ -440,24 +445,187 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags)
pp_string (buffer, "linear(");
dump_generic_node (buffer, OMP_CLAUSE_DECL (clause),
spc, flags, false);
- pp_character (buffer, ':');
+ pp_colon (buffer);
dump_generic_node (buffer, OMP_CLAUSE_LINEAR_STEP (clause),
spc, flags, false);
- pp_character (buffer, ')');
+ pp_right_paren (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_colon (buffer);
+ dump_generic_node (buffer, OMP_CLAUSE_ALIGNED_ALIGNMENT (clause),
+ spc, flags, false);
+ }
+ pp_right_paren (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_colon (buffer);
+ dump_generic_node (buffer, OMP_CLAUSE_DECL (clause),
+ spc, flags, false);
+ pp_right_paren (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_colon (buffer);
+ dump_generic_node (buffer, OMP_CLAUSE_DECL (clause),
+ spc, flags, false);
+ print_clause_size:
+ if (OMP_CLAUSE_SIZE (clause))
+ {
+ if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_MAP
+ && 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_right_bracket (buffer);
+ }
+ pp_right_paren (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_right_paren (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_right_paren (buffer);
+ break;
+
+ case OMP_CLAUSE_DEVICE:
+ pp_string (buffer, "device(");
+ dump_generic_node (buffer, OMP_CLAUSE_DEVICE_ID (clause),
+ spc, flags, false);
+ pp_right_paren (buffer);
+ break;
+
+ case OMP_CLAUSE_DIST_SCHEDULE:
+ pp_string (buffer, "dist_schedule(static");
+ if (OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (clause))
+ {
+ pp_comma (buffer);
+ dump_generic_node (buffer,
+ OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (clause),
+ spc, flags, false);
+ }
+ pp_right_paren (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_right_paren (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, ')');
+ pp_right_paren (buffer);
+ break;
+
+ case OMP_CLAUSE_SIMDLEN:
+ pp_string (buffer, "simdlen(");
+ dump_generic_node (buffer, OMP_CLAUSE_SIMDLEN_EXPR (clause),
+ spc, flags, false);
+ pp_right_paren (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, ')');
+ pp_right_paren (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:
@@ -2192,6 +2360,31 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
pp_string (buffer, "#pragma omp 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);
@@ -2208,21 +2401,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_right_paren (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_right_paren (buffer);
+ }
}
if (OMP_FOR_BODY (node))
{
@@ -2234,7 +2433,8 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
newline_and_indent (buffer, spc + 2);
pp_right_brace (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;
@@ -2258,6 +2458,10 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
pp_string (buffer, "#pragma omp master");
goto dump_omp_body;
+ case OMP_TASKGROUP:
+ pp_string (buffer, "#pragma omp taskgroup");
+ goto dump_omp_body;
+
case OMP_ORDERED:
pp_string (buffer, "#pragma omp ordered");
goto dump_omp_body;
@@ -2276,6 +2480,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);
@@ -2286,6 +2492,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);
@@ -2294,6 +2502,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 4aaa98b11ae..3cce3315ba2 100644
--- a/gcc/tree-ssa-alias.c
+++ b/gcc/tree-ssa-alias.c
@@ -1514,16 +1514,19 @@ ref_maybe_used_by_call_p_1 (gimple call, ao_ref *ref)
case BUILT_IN_GOMP_ATOMIC_START:
case BUILT_IN_GOMP_ATOMIC_END:
case BUILT_IN_GOMP_BARRIER:
+ case BUILT_IN_GOMP_BARRIER_CANCEL:
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:
case BUILT_IN_GOMP_CRITICAL_NAME_END:
case BUILT_IN_GOMP_LOOP_END:
+ case BUILT_IN_GOMP_LOOP_END_CANCEL:
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_SECTIONS_END_CANCEL:
case BUILT_IN_GOMP_SINGLE_COPY_START:
case BUILT_IN_GOMP_SINGLE_COPY_END:
return true;
@@ -1858,16 +1861,19 @@ call_may_clobber_ref_p_1 (gimple call, ao_ref *ref)
case BUILT_IN_GOMP_ATOMIC_START:
case BUILT_IN_GOMP_ATOMIC_END:
case BUILT_IN_GOMP_BARRIER:
+ case BUILT_IN_GOMP_BARRIER_CANCEL:
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:
case BUILT_IN_GOMP_CRITICAL_NAME_END:
case BUILT_IN_GOMP_LOOP_END:
+ case BUILT_IN_GOMP_LOOP_END_CANCEL:
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_SECTIONS_END_CANCEL:
case BUILT_IN_GOMP_SINGLE_COPY_START:
case BUILT_IN_GOMP_SINGLE_COPY_END:
return true;
diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c
index 87404cf0536..511972ae313 100644
--- a/gcc/tree-vectorizer.c
+++ b/gcc/tree-vectorizer.c
@@ -111,7 +111,8 @@ simduid_to_vf::equal (const value_type *p1, const value_type *p2)
D.1737[_7] = stuff;
- This hash maps from the simduid.0 to OMP simd array (D.1737[]). */
+ This hash maps from the OMP simd array (D.1737[]) to DECL_UID of
+ simduid.0. */
struct simd_array_to_simduid : typed_free_remove<simd_array_to_simduid>
{
diff --git a/gcc/tree.c b/gcc/tree.c
index 50717f0c787..dd388602f32 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -237,7 +237,13 @@ unsigned const char omp_clause_num_ops[] =
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 */
@@ -248,7 +254,19 @@ unsigned const char omp_clause_num_ops[] =
0, /* OMP_CLAUSE_UNTIED */
1, /* OMP_CLAUSE_FINAL */
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_ */
};
@@ -263,7 +281,13 @@ const char * const omp_clause_code_name[] =
"copyin",
"copyprivate",
"linear",
+ "aligned",
+ "depend",
"uniform",
+ "from",
+ "to",
+ "map",
+ "_looptemp_",
"if",
"num_threads",
"schedule",
@@ -274,7 +298,19 @@ const char * const omp_clause_code_name[] =
"untied",
"final",
"mergeable",
+ "device",
+ "dist_schedule",
+ "inbranch",
+ "notinbranch",
+ "num_teams",
+ "thread_limit",
+ "proc_bind",
"safelen",
+ "simdlen",
+ "for",
+ "parallel",
+ "sections",
+ "taskgroup",
"_simduid_"
};
@@ -4560,6 +4596,87 @@ 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. */
+
+static 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;
+}
+
+/* Remove duplicate "omp declare simd" attributes. */
+
+void
+omp_remove_redundant_declare_simd_attrs (tree fndecl)
+{
+ tree attr, end_attr = NULL_TREE, last_attr = NULL_TREE;
+ for (attr = lookup_attribute ("omp declare simd", DECL_ATTRIBUTES (fndecl));
+ attr;
+ attr = lookup_attribute ("omp declare simd", TREE_CHAIN (attr)))
+ {
+ tree *pc;
+ for (pc = &TREE_CHAIN (attr); *pc && *pc != end_attr; )
+ {
+ if (is_attribute_p ("omp declare simd", TREE_PURPOSE (*pc)))
+ {
+ last_attr = TREE_CHAIN (*pc);
+ if (TREE_VALUE (attr) == NULL_TREE)
+ {
+ if (TREE_VALUE (*pc) == NULL_TREE)
+ {
+ *pc = TREE_CHAIN (*pc);
+ continue;
+ }
+ }
+ else if (TREE_VALUE (*pc) != NULL_TREE
+ && omp_declare_simd_clauses_equal
+ (TREE_VALUE (TREE_VALUE (*pc)),
+ TREE_VALUE (TREE_VALUE (attr))))
+ {
+ *pc = TREE_CHAIN (*pc);
+ continue;
+ }
+ }
+ pc = &TREE_CHAIN (*pc);
+ }
+ end_attr = last_attr;
+ }
+}
+
/* Compare two attributes for their value identity. Return true if the
attribute values are known to be equal; otherwise return false.
*/
@@ -4577,6 +4694,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);
}
@@ -11047,7 +11171,14 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data,
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 */
@@ -11057,6 +11188,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:
@@ -11072,7 +11210,11 @@ 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));
diff --git a/gcc/tree.def b/gcc/tree.def
index f825aad5355..88c850af120 100644
--- a/gcc/tree.def
+++ b/gcc/tree.def
@@ -1034,6 +1034,25 @@ DEFTREECODE (OMP_FOR, "omp_for", tcc_statement, 6)
Operands like for OMP_FOR. */
DEFTREECODE (OMP_SIMD, "omp_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. */
@@ -1052,6 +1071,10 @@ DEFTREECODE (OMP_SECTION, "omp_section", tcc_statement, 1)
Operand 0: OMP_MASTER_BODY: Master section body. */
DEFTREECODE (OMP_MASTER, "omp_master", tcc_statement, 1)
+/* OpenMP - #pragma omp taskgroup
+ Operand 0: OMP_TASKGROUP_BODY: Taskgroup body. */
+DEFTREECODE (OMP_TASKGROUP, "omp_taskgroup", tcc_statement, 1)
+
/* OpenMP - #pragma omp ordered
Operand 0: OMP_ORDERED_BODY: Master section body. */
DEFTREECODE (OMP_ORDERED, "omp_ordered", tcc_statement, 1)
@@ -1061,6 +1084,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 0fdebfbf009..8200c2e8757 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1167,12 +1167,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)
@@ -1184,16 +1185,37 @@ extern void protected_set_expr_location (tree, location_t);
#define OMP_MASTER_BODY(NODE) TREE_OPERAND (OMP_MASTER_CHECK (NODE), 0)
+#define OMP_TASKGROUP_BODY(NODE) TREE_OPERAND (OMP_TASKGROUP_CHECK (NODE), 0)
+
#define OMP_ORDERED_BODY(NODE) TREE_OPERAND (OMP_ORDERED_CHECK (NODE), 0)
#define OMP_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_UNIFORM), 0)
+ OMP_CLAUSE__LOOPTEMP_), 0)
#define OMP_CLAUSE_HAS_LOCATION(NODE) \
(LOCATION_LOCUS ((OMP_CLAUSE_CHECK (NODE))->omp_clause.locus) \
!= UNKNOWN_LOCATION)
@@ -1209,6 +1231,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. */
@@ -1240,6 +1268,21 @@ extern void protected_set_expr_location (tree, location_t);
#define OMP_CLAUSE_SCHEDULE_CHUNK_EXPR(NODE) \
OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_SCHEDULE), 0)
+#define OMP_CLAUSE_DEPEND_KIND(NODE) \
+ (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_DEPEND)->omp_clause.subcode.depend_kind)
+
+#define OMP_CLAUSE_MAP_KIND(NODE) \
+ (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)->omp_clause.subcode.map_kind)
+
+/* Nonzero if this map clause is for array (rather than pointer) based array
+ section with zero bias. Both the non-decl OMP_CLAUSE_MAP and
+ correspoidng OMP_CLAUSE_MAP_POINTER clause are marked with this flag. */
+#define OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION(NODE) \
+ (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)->base.public_flag)
+
+#define OMP_CLAUSE_PROC_BIND_KIND(NODE) \
+ (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_PROC_BIND)->omp_clause.subcode.proc_bind_kind)
+
#define OMP_CLAUSE_COLLAPSE_EXPR(NODE) \
OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_COLLAPSE), 0)
#define OMP_CLAUSE_COLLAPSE_ITERVAR(NODE) \
@@ -1260,6 +1303,11 @@ 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 REDUCTION clause may reference the original list item (omp_orig)
+ in its OMP_CLAUSE_REDUCTION_{,GIMPLE_}INIT. */
+#define OMP_CLAUSE_REDUCTION_OMP_ORIG_REF(NODE) \
+ (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_REDUCTION)->base.public_flag)
+
/* 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) \
@@ -1273,9 +1321,29 @@ extern void protected_set_expr_location (tree, location_t);
#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)
@@ -3624,6 +3692,9 @@ 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);
+/* Remove redundant "omp declare simd" attributes from fndecl. */
+extern void omp_remove_redundant_declare_simd_attrs (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 b/libgomp/ChangeLog
index 7646e5c05e2..557b80a7317 100644
--- a/libgomp/ChangeLog
+++ b/libgomp/ChangeLog
@@ -1,3 +1,367 @@
+2013-10-11 Jakub Jelinek <jakub@redhat.com>
+ Tobias Burnus <burnus@net-b.de>
+ Richard Henderson <rth@redhat.com>
+
+ * target.c: New file.
+ * Makefile.am (libgomp_la_SOURCES): Add target.c.
+ * Makefile.in: Regenerated.
+ * libgomp_g.h (GOMP_task): Add depend argument.
+ (GOMP_barrier_cancel, GOMP_loop_end_cancel,
+ GOMP_sections_end_cancel, GOMP_target, GOMP_target_data,
+ GOMP_target_end_data, GOMP_target_update, GOMP_teams,
+ 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.
+ * fortran.c (omp_is_initial_device): Add ialias_redirect.
+ (omp_is_initial_device_): New function.
+ (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.map (GOMP_barrier_cancel, GOMP_loop_end_cancel,
+ GOMP_sections_end_cancel, GOMP_target, GOMP_target_data,
+ GOMP_target_end_data, GOMP_target_update, GOMP_teams): Export
+ @@GOMP_4.0.
+ (omp_is_initial_device, omp_is_initial_device_, 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.
+ * team.c (struct gomp_thread_start_data): Add place field.
+ (gomp_thread_start): Clear thr->thread_pool and
+ thr->task before returning. Use gomp_team_barrier_wait_final
+ instead of gomp_team_barrier_wait. Initialize thr->place.
+ (gomp_new_team): Initialize work_shares_to_free, work_share_cancelled,
+ team_cancelled and task_queued_count fields.
+ (gomp_free_pool_helper): Clear thr->thread_pool and thr->task
+ before calling pthread_exit.
+ (gomp_free_thread): No longer static. Use
+ gomp_managed_threads_lock instead of gomp_remaining_threads_lock.
+ (gomp_team_start): Add flags argument. Set
+ thr->thread_pool->threads_busy to nthreads immediately after creating
+ new pool. Use gomp_managed_threads_lock instead of
+ gomp_remaining_threads_lock. Handle OpenMP 4.0 affinity.
+ (gomp_team_end): Use gomp_managed_threads_lock instead of
+ gomp_remaining_threads_lock. Use gomp_team_barrier_wait_final instead
+ of gomp_team_barrier_wait. If team->team_cancelled, call
+ gomp_fini_worshare on ws chain starting at team->work_shares_to_free
+ rather than thr->ts.work_share.
+ (initialize_team): Don't call gomp_sem_init here.
+ * sections.c (GOMP_parallel_sections_start): Adjust gomp_team_start
+ caller.
+ (GOMP_parallel_sections, GOMP_sections_end_cancel): New functions.
+ * env.c (gomp_global_icv): Add default_device_var, target_data and
+ bind_var initializers.
+ (gomp_cpu_affinity, gomp_cpu_affinity_len): Remove.
+ (gomp_bind_var_list, gomp_bind_var_list_len, gomp_places_list,
+ gomp_places_list_len): New variables.
+ (parse_bind_var, parse_one_place, parse_places_var): New functions.
+ (parse_affinity): Rewritten to construct OMP_PLACES list with unit
+ sized places.
+ (gomp_cancel_var): New global variable.
+ (parse_int): New function.
+ (handle_omp_display_env): New function.
+ (initialize_env): Use it. Initialize default_device_var.
+ Parse OMP_CANCELLATION env var. Use parse_bind_var to parse
+ OMP_PROC_BIND instead of parse_boolean. Use parse_places_var for
+ OMP_PLACES parsing. Don't call parse_affinity if OMP_PLACES has
+ been successfully parsed (and call gomp_init_affinity in that case).
+ (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, omp_is_initial_device): New functions.
+ * libgomp.h: Include stdlib.h.
+ (ialias_ulp, ialias_str1, ialias_str2, ialias_redirect, ialias_call):
+ Define.
+ (struct target_mem_desc): Forward declare.
+ (struct gomp_task_icv): Add default_device_var, target_data, bind_var
+ and thread_limit_var fields.
+ (gomp_get_num_devices): New prototype.
+ (gomp_cancel_var): New extern decl.
+ (struct gomp_team): Add work_shares_to_free, work_share_cancelled,
+ team_cancelled and task_queued_count fields. Add comments about
+ task_{,queued_,running_}count.
+ (gomp_cancel_kind): New enum.
+ (gomp_work_share_end_cancel): New prototype.
+ (struct gomp_task): Add next_taskgroup, prev_taskgroup, taskgroup,
+ copy_ctors_done, dependers, depend_hash, depend_count, num_dependees
+ and depend fields.
+ (struct gomp_taskgroup): New type.
+ (struct gomp_task_depend_entry,
+ struct gomp_dependers_vec): New types.
+ (gomp_finish_task): Free depend_hash if non-NULL.
+ (struct gomp_team_state): Add place_partition_off
+ and place_partition_len fields.
+ (gomp_bind_var_list, gomp_bind_var_list_len, gomp_places_list,
+ gomp_places_list_len): New extern decls.
+ (struct gomp_thread): Add place field.
+ (gomp_cpu_affinity, gomp_cpu_affinity_len): Remove.
+ (gomp_init_thread_affinity): Add place argument.
+ (gomp_affinity_alloc, gomp_affinity_init_place, gomp_affinity_add_cpus,
+ gomp_affinity_remove_cpu, gomp_affinity_copy_place,
+ gomp_affinity_same_place, gomp_affinity_finalize_place_list,
+ gomp_affinity_init_level, gomp_affinity_print_place): New
+ prototypes.
+ (gomp_team_start): Add flags argument.
+ (gomp_thread_limit_var, gomp_remaining_threads_count,
+ gomp_remaining_threads_lock): Remove.
+ (gomp_managed_threads_lock): New variable.
+ (struct gomp_thread_pool): Add threads_busy field.
+ (gomp_free_thread): New prototype.
+ * task.c: Include hashtab.h.
+ (hash_entry_type): New typedef.
+ (htab_alloc, htab_free, htab_hash, htab_eq): New inlines.
+ (gomp_init_task): Clear dependers, depend_hash, depend_count,
+ copy_ctors_done and taskgroup fields.
+ (GOMP_task): Add depend argument, handle depend clauses. If
+ gomp_team_barrier_cancelled or if it's taskgroup has been
+ cancelled, don't queue or start new tasks. Set copy_ctors_done
+ field if needed. Initialize taskgroup field. If copy_ctors_done
+ and already cancelled, don't discard the task. If taskgroup is
+ non-NULL, enqueue the task into taskgroup queue. Increment
+ num_children field in taskgroup. Increment task_queued_count.
+ (gomp_task_run_pre, gomp_task_run_post_remove_parent,
+ gomp_task_run_post_remove_taskgroup): New inline functions.
+ (gomp_task_run_post_handle_depend_hash,
+ gomp_task_run_post_handle_dependers,
+ gomp_task_run_post_handle_depend): New functions.
+ (GOMP_taskwait): Use them. If more than one new tasks
+ have been queued, wake other threads if needed.
+ (gomp_barrier_handle_tasks): Likewise. If
+ gomp_team_barrier_cancelled, don't start any new tasks, just free
+ all tasks.
+ (GOMP_taskgroup_start, GOMP_taskgroup_end): New functions.
+ * 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, omp_is_initial_device): New interfaces.
+ (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): Remove
+ useless use omp_lib_kinds.
+ * 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, omp_is_initial_device): New prototypes.
+ * loop.c (gomp_parallel_loop_start): Add flags argument, pass it
+ through to gomp_team_start.
+ (GOMP_parallel_loop_static_start, GOMP_parallel_loop_dynamic_start,
+ GOMP_parallel_loop_guided_start, GOMP_parallel_loop_runtime_start):
+ Adjust gomp_parallel_loop_start callers.
+ (GOMP_parallel_loop_static, GOMP_parallel_loop_dynamic,
+ GOMP_parallel_loop_guided, GOMP_parallel_loop_runtime,
+ GOMP_loop_end_cancel): New functions.
+ (GOMP_parallel_end): Add ialias_redirect.
+ * hashtab.h: New file.
+ * libgomp.texi (Environment Variables): Minor cleanup,
+ update section refs to OpenMP 4.0rc2.
+ (OMP_DISPLAY_ENV, GOMP_SPINCOUNT): Document these
+ environment variables.
+ * work.c (gomp_work_share_end, gomp_work_share_end_nowait): Set
+ team->work_shares_to_free to thr->ts.work_share before calling
+ free_work_share.
+ (gomp_work_share_end_cancel): New function.
+ * config/linux/proc.c: Include errno.h.
+ (gomp_get_cpuset_size, gomp_cpuset_size, gomp_cpusetp): New variables.
+ (gomp_cpuset_popcount): Add cpusetsize argument, use it instead of
+ sizeof (cpu_set_t) to determine number of iterations. Fix up check
+ extern decl. Use CPU_COUNT_S if available, or CPU_COUNT if
+ gomp_cpuset_size is sizeof (cpu_set_t).
+ (gomp_init_num_threads): Initialize gomp_cpuset_size,
+ gomp_get_cpuset_size and gomp_cpusetp here, use gomp_cpusetp instead
+ of &cpuset and pass gomp_cpuset_size instead of sizeof (cpu_set_t)
+ to pthread_getaffinity_np. Free and clear gomp_cpusetp if it didn't
+ contain any logical CPUs.
+ (get_num_procs): Don't call pthread_getaffinity_np if gomp_cpusetp
+ is NULL. Use gomp_cpusetp instead of &cpuset and pass
+ gomp_get_cpuset_size instead of sizeof (cpu_set_t) to
+ pthread_getaffinity_np. Check gomp_places_list instead of
+ gomp_cpu_affinity. Adjust gomp_cpuset_popcount caller.
+ * config/linux/bar.c (gomp_barrier_wait_end,
+ gomp_barrier_wait_last): Use BAR_* defines.
+ (gomp_team_barrier_wait_end): Likewise. Clear BAR_CANCELLED
+ from state where needed. Set work_share_cancelled to 0 on last
+ thread.
+ (gomp_team_barrier_wait_final, gomp_team_barrier_wait_cancel_end,
+ gomp_team_barrier_wait_cancel, gomp_team_barrier_cancel): New
+ functions.
+ * config/linux/proc.h (gomp_cpuset_popcount): Add attribute_hidden.
+ Add cpusetsize argument.
+ (gomp_cpuset_size, gomp_cpusetp): Declare.
+ * config/linux/affinity.c: Include errno.h, stdio.h and string.h.
+ (affinity_counter): Remove.
+ (CPU_ISSET_S, CPU_ZERO_S, CPU_SET_S, CPU_CLR_S): Define
+ if CPU_ALLOC_SIZE isn't defined.
+ (gomp_init_affinity): Rewritten, if gomp_places_list is NULL, try
+ silently create OMP_PLACES=threads, if it is non-NULL afterwards,
+ bind current thread to the first place.
+ (gomp_init_thread_affinity): Rewritten. Add place argument, just
+ pthread_setaffinity_np to gomp_places_list[place].
+ (gomp_affinity_alloc, gomp_affinity_init_place, gomp_affinity_add_cpus,
+ gomp_affinity_remove_cpu, gomp_affinity_copy_place,
+ gomp_affinity_same_place, gomp_affinity_finalize_place_list,
+ gomp_affinity_init_level, gomp_affinity_print_place): New functions.
+ * config/linux/bar.h (BAR_TASK_PENDING, BAR_WAS_LAST,
+ BAR_WAITING_FOR_TASK, BAR_INCR, BAR_CANCELLED): Define.
+ (gomp_barrier_t): Add awaited_final field.
+ (gomp_barrier_init): Initialize awaited_final field.
+ (gomp_team_barrier_wait_final, gomp_team_barrier_wait_cancel,
+ gomp_team_barrier_wait_cancel_end, gomp_team_barrier_cancel): New
+ prototypes.
+ (gomp_barrier_wait_start): Preserve BAR_CANCELLED bit. Use BAR_*
+ defines.
+ (gomp_barrier_wait_cancel_start, gomp_team_barrier_wait_final_start,
+ gomp_team_barrier_cancelled): New inline functions.
+ (gomp_barrier_last_thread,
+ gomp_team_barrier_set_task_pending,
+ gomp_team_barrier_clear_task_pending,
+ gomp_team_barrier_set_waiting_for_tasks,
+ gomp_team_barrier_waiting_for_tasks,
+ gomp_team_barrier_done): Use BAR_* defines.
+ * config/posix/bar.c (gomp_barrier_init): Clear cancellable field.
+ (gomp_barrier_wait_end): Use BAR_* defines.
+ (gomp_team_barrier_wait_end): Clear BAR_CANCELLED from state.
+ Set work_share_cancelled to 0 on last thread, use __atomic_load_n.
+ Use BAR_* defines.
+ (gomp_team_barrier_wait_cancel_end, gomp_team_barrier_wait_cancel,
+ gomp_team_barrier_cancel): New functions.
+ * config/posix/affinity.c (gomp_init_thread_affinity): Add place
+ argument.
+ (gomp_affinity_alloc, gomp_affinity_init_place, gomp_affinity_add_cpus,
+ gomp_affinity_remove_cpu, gomp_affinity_copy_place,
+ gomp_affinity_same_place, gomp_affinity_finalize_place_list,
+ gomp_affinity_init_level, gomp_affinity_print_place): New stubs.
+ * config/posix/bar.h (BAR_TASK_PENDING, BAR_WAS_LAST,
+ BAR_WAITING_FOR_TASK, BAR_INCR, BAR_CANCELLED): Define.
+ (gomp_barrier_t): Add cancellable field.
+ (gomp_team_barrier_wait_cancel, gomp_team_barrier_wait_cancel_end,
+ gomp_team_barrier_cancel): New prototypes.
+ (gomp_barrier_wait_start): Preserve BAR_CANCELLED bit.
+ (gomp_barrier_wait_cancel_start, gomp_team_barrier_wait_final,
+ gomp_team_barrier_cancelled): New inline functions.
+ (gomp_barrier_wait_start, gomp_barrier_last_thread,
+ gomp_team_barrier_set_task_pending,
+ gomp_team_barrier_clear_task_pending,
+ gomp_team_barrier_set_waiting_for_tasks,
+ gomp_team_barrier_waiting_for_tasks,
+ gomp_team_barrier_done): Use BAR_* defines.
+ * barrier.c (GOMP_barrier_cancel): New function.
+ * 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, omp_is_initial_device): New externals.
+ * parallel.c (GOMP_parallel, GOMP_cancel, GOMP_cancellation_point):
+ New functions.
+ (gomp_resolve_num_threads): Adjust for thread_limit now being in
+ icv->thread_limit_var. Use UINT_MAX instead of ULONG_MAX as
+ infinity. If not nested, just return minimum of max_num_threads
+ and icv->thread_limit_var and if thr->thread_pool, set threads_busy
+ to the returned value. Otherwise, don't update atomically
+ gomp_remaining_threads_count, but instead thr->thread_pool->threads_busy.
+ (GOMP_parallel_end): Adjust for thread_limit now being in
+ icv->thread_limit_var. Use UINT_MAX instead of ULONG_MAX as
+ infinity. Adjust threads_busy in the pool rather than
+ gomp_remaining_threads_count. Remember team->nthreads and call
+ gomp_team_end before adjusting threads_busy, if not nested
+ afterwards, just set it to 1 non-atomically. Add ialias.
+ (GOMP_parallel_start): Adjust gomp_team_start caller.
+ * testsuite/libgomp.c/atomic-14.c: Add parens to make it valid.
+ * testsuite/libgomp.c/affinity-1.c: New test.
+ * testsuite/libgomp.c/atomic-15.c: New test.
+ * testsuite/libgomp.c/atomic-16.c: New test.
+ * testsuite/libgomp.c/atomic-17.c: New test.
+ * testsuite/libgomp.c/cancel-for-1.c: New test.
+ * testsuite/libgomp.c/cancel-for-2.c: New test.
+ * testsuite/libgomp.c/cancel-parallel-1.c: New test.
+ * testsuite/libgomp.c/cancel-parallel-2.c: New test.
+ * testsuite/libgomp.c/cancel-parallel-3.c: New test.
+ * testsuite/libgomp.c/cancel-sections-1.c: New test.
+ * testsuite/libgomp.c/cancel-taskgroup-1.c: New test.
+ * testsuite/libgomp.c/cancel-taskgroup-2.c: New test.
+ * testsuite/libgomp.c/depend-1.c: New test.
+ * testsuite/libgomp.c/depend-2.c: New test.
+ * testsuite/libgomp.c/depend-3.c: New test.
+ * testsuite/libgomp.c/depend-4.c: New test.
+ * testsuite/libgomp.c/for-1.c: New test.
+ * testsuite/libgomp.c/for-1.h: New file.
+ * testsuite/libgomp.c/for-2.c: New test.
+ * testsuite/libgomp.c/for-2.h: New file.
+ * testsuite/libgomp.c/for-3.c: New test.
+ * testsuite/libgomp.c/pr58392.c: New test.
+ * testsuite/libgomp.c/simd-1.c: New test.
+ * testsuite/libgomp.c/simd-2.c: New test.
+ * testsuite/libgomp.c/simd-3.c: New test.
+ * testsuite/libgomp.c/simd-4.c: New test.
+ * testsuite/libgomp.c/simd-5.c: New test.
+ * testsuite/libgomp.c/simd-6.c: New test.
+ * testsuite/libgomp.c/target-1.c: New test.
+ * testsuite/libgomp.c/target-2.c: New test.
+ * testsuite/libgomp.c/target-3.c: New test.
+ * testsuite/libgomp.c/target-4.c: New test.
+ * testsuite/libgomp.c/target-5.c: New test.
+ * testsuite/libgomp.c/target-6.c: New test.
+ * testsuite/libgomp.c/target-7.c: New test.
+ * testsuite/libgomp.c/taskgroup-1.c: New test.
+ * testsuite/libgomp.c/thread-limit-1.c: New test.
+ * testsuite/libgomp.c/thread-limit-2.c: New test.
+ * testsuite/libgomp.c/thread-limit-3.c: New test.
+ * testsuite/libgomp.c/udr-1.c: New test.
+ * testsuite/libgomp.c/udr-2.c: New test.
+ * testsuite/libgomp.c/udr-3.c: New test.
+ * testsuite/libgomp.c++/affinity-1.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.
+ * testsuite/libgomp.c++/atomic-14.C: New test.
+ * testsuite/libgomp.c++/atomic-15.C: New test.
+ * testsuite/libgomp.c++/cancel-for-1.C: New test.
+ * testsuite/libgomp.c++/cancel-for-2.C: New test.
+ * testsuite/libgomp.c++/cancel-parallel-1.C: New test.
+ * testsuite/libgomp.c++/cancel-parallel-2.C: New test.
+ * testsuite/libgomp.c++/cancel-parallel-3.C: New test.
+ * testsuite/libgomp.c++/cancel-sections-1.C: New test.
+ * testsuite/libgomp.c++/cancel-taskgroup-1.C: New test.
+ * testsuite/libgomp.c++/cancel-taskgroup-2.C: New test.
+ * testsuite/libgomp.c++/cancel-taskgroup-3.C: New test.
+ * testsuite/libgomp.c++/cancel-test.h: New file.
+ * testsuite/libgomp.c++/for-9.C: New test.
+ * testsuite/libgomp.c++/for-10.C: New test.
+ * testsuite/libgomp.c++/for-11.C: New test.
+ * testsuite/libgomp.c++/simd-1.C: New test.
+ * testsuite/libgomp.c++/simd-2.C: New test.
+ * testsuite/libgomp.c++/simd-3.C: New test.
+ * testsuite/libgomp.c++/simd-4.C: New test.
+ * testsuite/libgomp.c++/simd-5.C: New test.
+ * testsuite/libgomp.c++/simd-6.C: New test.
+ * testsuite/libgomp.c++/simd-7.C: New test.
+ * testsuite/libgomp.c++/simd-8.C: New test.
+ * testsuite/libgomp.c++/target-1.C: New test.
+ * testsuite/libgomp.c++/target-2.C: New test.
+ * testsuite/libgomp.c++/target-2-aux.cc: New file.
+ * testsuite/libgomp.c++/target-3.C: New test.
+ * testsuite/libgomp.c++/taskgroup-1.C: New test.
+ * testsuite/libgomp.c++/udr-1.C: New test.
+ * testsuite/libgomp.c++/udr-2.C: New test.
+ * testsuite/libgomp.c++/udr-3.C: New test.
+ * testsuite/libgomp.c++/udr-4.C: New test.
+ * testsuite/libgomp.c++/udr-5.C: New test.
+ * testsuite/libgomp.c++/udr-6.C: New test.
+ * testsuite/libgomp.c++/udr-7.C: New test.
+ * testsuite/libgomp.c++/udr-8.C: New test.
+ * testsuite/libgomp.c++/udr-9.C: New test.
+
2013-09-20 Jakub Jelinek <jakub@redhat.com>
PR testsuite/57605
diff --git a/libgomp/Makefile.am b/libgomp/Makefile.am
index 2bc4986ad18..e546dbe425b 100644
--- a/libgomp/Makefile.am
+++ b/libgomp/Makefile.am
@@ -60,7 +60,7 @@ libgomp_la_LINK = $(LINK) $(libgomp_la_LDFLAGS)
libgomp_la_SOURCES = alloc.c barrier.c critical.c env.c error.c iter.c \
iter_ull.c loop.c loop_ull.c ordered.c parallel.c sections.c single.c \
task.c team.c work.c lock.c mutex.c proc.c sem.c bar.c ptrlock.c \
- time.c fortran.c affinity.c
+ time.c fortran.c affinity.c target.c
nodist_noinst_HEADERS = libgomp_f.h
nodist_libsubinclude_HEADERS = omp.h
diff --git a/libgomp/Makefile.in b/libgomp/Makefile.in
index ecc010eda4b..06048e7ce79 100644
--- a/libgomp/Makefile.in
+++ b/libgomp/Makefile.in
@@ -96,7 +96,7 @@ am_libgomp_la_OBJECTS = alloc.lo barrier.lo critical.lo env.lo \
error.lo iter.lo iter_ull.lo loop.lo loop_ull.lo ordered.lo \
parallel.lo sections.lo single.lo task.lo team.lo work.lo \
lock.lo mutex.lo proc.lo sem.lo bar.lo ptrlock.lo time.lo \
- fortran.lo affinity.lo
+ fortran.lo affinity.lo target.lo
libgomp_la_OBJECTS = $(am_libgomp_la_OBJECTS)
DEFAULT_INCLUDES = -I.@am__isrc@
depcomp = $(SHELL) $(top_srcdir)/../depcomp
@@ -317,7 +317,7 @@ libgomp_la_LINK = $(LINK) $(libgomp_la_LDFLAGS)
libgomp_la_SOURCES = alloc.c barrier.c critical.c env.c error.c iter.c \
iter_ull.c loop.c loop_ull.c ordered.c parallel.c sections.c single.c \
task.c team.c work.c lock.c mutex.c proc.c sem.c bar.c ptrlock.c \
- time.c fortran.c affinity.c
+ time.c fortran.c affinity.c target.c
nodist_noinst_HEADERS = libgomp_f.h
nodist_libsubinclude_HEADERS = omp.h
@@ -474,6 +474,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sections.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sem.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/single.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/target.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/task.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/team.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/time.Plo@am__quote@
diff --git a/libgomp/barrier.c b/libgomp/barrier.c
index dfd0bd49f50..2a9fe8f8b88 100644
--- a/libgomp/barrier.c
+++ b/libgomp/barrier.c
@@ -39,3 +39,15 @@ GOMP_barrier (void)
gomp_team_barrier_wait (&team->barrier);
}
+
+bool
+GOMP_barrier_cancel (void)
+{
+ struct gomp_thread *thr = gomp_thread ();
+ struct gomp_team *team = thr->ts.team;
+
+ /* The compiler transforms to barrier_cancel when it sees that the
+ barrier is within a construct that can cancel. Thus we should
+ never have an orphaned cancellable barrier. */
+ return gomp_team_barrier_wait_cancel (&team->barrier);
+}
diff --git a/libgomp/config/linux/affinity.c b/libgomp/config/linux/affinity.c
index dc6c7e5ed3b..789cdce077d 100644
--- a/libgomp/config/linux/affinity.c
+++ b/libgomp/config/linux/affinity.c
@@ -29,90 +29,327 @@
#endif
#include "libgomp.h"
#include "proc.h"
+#include <errno.h>
#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
#include <unistd.h>
#ifdef HAVE_PTHREAD_AFFINITY_NP
-static unsigned int affinity_counter;
+#ifndef CPU_ALLOC_SIZE
+#define CPU_ISSET_S(idx, size, set) CPU_ISSET(idx, set)
+#define CPU_ZERO_S(size, set) CPU_ZERO(set)
+#define CPU_SET_S(idx, size, set) CPU_SET(idx, set)
+#define CPU_CLR_S(idx, size, set) CPU_CLR(idx, set)
+#endif
void
gomp_init_affinity (void)
{
- cpu_set_t cpuset, cpusetnew;
- size_t idx, widx;
- unsigned long cpus = 0;
+ if (gomp_places_list == NULL)
+ {
+ if (!gomp_affinity_init_level (1, ULONG_MAX, true))
+ return;
+ }
+
+ struct gomp_thread *thr = gomp_thread ();
+ pthread_setaffinity_np (pthread_self (), gomp_cpuset_size,
+ (cpu_set_t *) gomp_places_list[0]);
+ thr->place = 1;
+ thr->ts.place_partition_off = 0;
+ thr->ts.place_partition_len = gomp_places_list_len;
+}
+
+void
+gomp_init_thread_affinity (pthread_attr_t *attr, unsigned int place)
+{
+ pthread_attr_setaffinity_np (attr, gomp_cpuset_size,
+ (cpu_set_t *) gomp_places_list[place]);
+}
+
+void **
+gomp_affinity_alloc (unsigned long count, bool quiet)
+{
+ unsigned long i;
+ void **ret;
+ char *p;
+
+ if (gomp_cpusetp == NULL)
+ {
+ if (!quiet)
+ gomp_error ("Could not get CPU affinity set");
+ return NULL;
+ }
- if (pthread_getaffinity_np (pthread_self (), sizeof (cpuset), &cpuset))
+ ret = malloc (count * sizeof (void *) + count * gomp_cpuset_size);
+ if (ret == NULL)
{
- gomp_error ("could not get CPU affinity set");
- free (gomp_cpu_affinity);
- gomp_cpu_affinity = NULL;
- gomp_cpu_affinity_len = 0;
- return;
+ if (!quiet)
+ gomp_error ("Out of memory trying to allocate places list");
+ return NULL;
}
- CPU_ZERO (&cpusetnew);
- if (gomp_cpu_affinity_len == 0)
+ p = (char *) (ret + count);
+ for (i = 0; i < count; i++, p += gomp_cpuset_size)
+ ret[i] = p;
+ return ret;
+}
+
+void
+gomp_affinity_init_place (void *p)
+{
+ cpu_set_t *cpusetp = (cpu_set_t *) p;
+ CPU_ZERO_S (gomp_cpuset_size, cpusetp);
+}
+
+bool
+gomp_affinity_add_cpus (void *p, unsigned long num,
+ unsigned long len, long stride, bool quiet)
+{
+ cpu_set_t *cpusetp = (cpu_set_t *) p;
+ unsigned long max = 8 * gomp_cpuset_size;
+ for (;;)
{
- unsigned long count = gomp_cpuset_popcount (&cpuset);
- if (count >= 65536)
- count = 65536;
- gomp_cpu_affinity = malloc (count * sizeof (unsigned short));
- if (gomp_cpu_affinity == NULL)
+ if (num >= max)
+ {
+ if (!quiet)
+ gomp_error ("Logical CPU number %lu out of range", num);
+ return false;
+ }
+ CPU_SET_S (num, gomp_cpuset_size, cpusetp);
+ if (--len == 0)
+ return true;
+ if ((stride < 0 && num + stride > num)
+ || (stride > 0 && num + stride < num))
{
- gomp_error ("not enough memory to store CPU affinity list");
- return;
+ if (!quiet)
+ gomp_error ("Logical CPU number %lu+%ld out of range",
+ num, stride);
+ return false;
}
- for (widx = idx = 0; widx < count && idx < 65536; idx++)
- if (CPU_ISSET (idx, &cpuset))
+ num += stride;
+ }
+}
+
+bool
+gomp_affinity_remove_cpu (void *p, unsigned long num)
+{
+ cpu_set_t *cpusetp = (cpu_set_t *) p;
+ if (num >= 8 * gomp_cpuset_size)
+ {
+ gomp_error ("Logical CPU number %lu out of range", num);
+ return false;
+ }
+ if (!CPU_ISSET_S (num, gomp_cpuset_size, cpusetp))
+ {
+ gomp_error ("Logical CPU %lu to be removed is not in the set", num);
+ return false;
+ }
+ CPU_CLR_S (num, gomp_cpuset_size, cpusetp);
+ return true;
+}
+
+bool
+gomp_affinity_copy_place (void *p, void *q, long stride)
+{
+ unsigned long i, max = 8 * gomp_cpuset_size;
+ cpu_set_t *destp = (cpu_set_t *) p;
+ cpu_set_t *srcp = (cpu_set_t *) q;
+
+ CPU_ZERO_S (gomp_cpuset_size, destp);
+ for (i = 0; i < max; i++)
+ if (CPU_ISSET_S (i, gomp_cpuset_size, srcp))
+ {
+ if ((stride < 0 && i + stride > i)
+ || (stride > 0 && (i + stride < i || i + stride >= max)))
+ {
+ gomp_error ("Logical CPU number %lu+%ld out of range", i, stride);
+ return false;
+ }
+ CPU_SET_S (i + stride, gomp_cpuset_size, destp);
+ }
+ return true;
+}
+
+bool
+gomp_affinity_same_place (void *p, void *q)
+{
+#ifdef CPU_EQUAL_S
+ return CPU_EQUAL_S (gomp_cpuset_size, (cpu_set_t *) p, (cpu_set_t *) q);
+#else
+ return memcmp (p, q, gomp_cpuset_size) == 0;
+#endif
+}
+
+bool
+gomp_affinity_finalize_place_list (bool quiet)
+{
+ unsigned long i, j;
+
+ for (i = 0, j = 0; i < gomp_places_list_len; i++)
+ {
+ cpu_set_t *cpusetp = (cpu_set_t *) gomp_places_list[i];
+ bool nonempty = false;
+#ifdef CPU_AND_S
+ CPU_AND_S (gomp_cpuset_size, cpusetp, cpusetp, gomp_cpusetp);
+ nonempty = gomp_cpuset_popcount (gomp_cpuset_size, cpusetp) != 0;
+#else
+ unsigned long k, max = gomp_cpuset_size / sizeof (cpusetp->__bits[0]);
+ for (k = 0; k < max; k++)
+ if ((cpusetp->__bits[k] &= gomp_cpusetp->__bits[k]) != 0)
+ nonempty = true;
+#endif
+ if (nonempty)
+ gomp_places_list[j++] = gomp_places_list[i];
+ }
+
+ if (j == 0)
+ {
+ if (!quiet)
+ gomp_error ("None of the places contain usable logical CPUs");
+ return false;
+ }
+ else if (j < gomp_places_list_len)
+ {
+ if (!quiet)
+ gomp_error ("Number of places reduced from %ld to %ld because some "
+ "places didn't contain any usable logical CPUs",
+ gomp_places_list_len, j);
+ gomp_places_list_len = j;
+ }
+ return true;
+}
+
+bool
+gomp_affinity_init_level (int level, unsigned long count, bool quiet)
+{
+ unsigned long i, max = 8 * gomp_cpuset_size;
+
+ if (gomp_cpusetp)
+ {
+ unsigned long maxcount
+ = gomp_cpuset_popcount (gomp_cpuset_size, gomp_cpusetp);
+ if (count > maxcount)
+ count = maxcount;
+ }
+ gomp_places_list = gomp_affinity_alloc (count, quiet);
+ gomp_places_list_len = 0;
+ if (gomp_places_list == NULL)
+ return false;
+ /* SMT (threads). */
+ if (level == 1)
+ {
+ for (i = 0; i < max && gomp_places_list_len < count; i++)
+ if (CPU_ISSET_S (i, gomp_cpuset_size, gomp_cpusetp))
{
- cpus++;
- gomp_cpu_affinity[widx++] = idx;
+ gomp_affinity_init_place (gomp_places_list[gomp_places_list_len]);
+ gomp_affinity_add_cpus (gomp_places_list[gomp_places_list_len],
+ i, 1, 0, true);
+ ++gomp_places_list_len;
}
+ return true;
}
else
- for (widx = idx = 0; idx < gomp_cpu_affinity_len; idx++)
- if (gomp_cpu_affinity[idx] < CPU_SETSIZE
- && CPU_ISSET (gomp_cpu_affinity[idx], &cpuset))
+ {
+ char name[sizeof ("/sys/devices/system/cpu/cpu/topology/"
+ "thread_siblings_list") + 3 * sizeof (unsigned long)];
+ size_t prefix_len = sizeof ("/sys/devices/system/cpu/cpu") - 1;
+ cpu_set_t *copy = gomp_alloca (gomp_cpuset_size);
+ FILE *f;
+ char *line = NULL;
+ size_t linelen = 0;
+
+ memcpy (name, "/sys/devices/system/cpu/cpu", prefix_len);
+ memcpy (copy, gomp_cpusetp, gomp_cpuset_size);
+ for (i = 0; i < max && gomp_places_list_len < count; i++)
+ if (CPU_ISSET_S (i, gomp_cpuset_size, copy))
+ {
+ sprintf (name + prefix_len, "%lu/topology/%s_siblings_list",
+ i, level == 2 ? "thread" : "core");
+ f = fopen (name, "r");
+ if (f != NULL)
+ {
+ if (getline (&line, &linelen, f) > 0)
+ {
+ char *p = line;
+ bool seen_i = false;
+ void *pl = gomp_places_list[gomp_places_list_len];
+ gomp_affinity_init_place (pl);
+ while (*p && *p != '\n')
+ {
+ unsigned long first, last;
+ errno = 0;
+ first = strtoul (p, &p, 10);
+ if (errno)
+ break;
+ last = first;
+ if (*p == '-')
+ {
+ errno = 0;
+ last = strtoul (p + 1, &p, 10);
+ if (errno || last < first)
+ break;
+ }
+ for (; first <= last; first++)
+ if (CPU_ISSET_S (first, gomp_cpuset_size, copy)
+ && gomp_affinity_add_cpus (pl, first, 1, 0,
+ true))
+ {
+ CPU_CLR_S (first, gomp_cpuset_size, copy);
+ if (first == i)
+ seen_i = true;
+ }
+ if (*p == ',')
+ ++p;
+ }
+ if (seen_i)
+ gomp_places_list_len++;
+ }
+ fclose (f);
+ }
+ }
+ if (gomp_places_list == 0)
{
- if (! CPU_ISSET (gomp_cpu_affinity[idx], &cpusetnew))
- {
- cpus++;
- CPU_SET (gomp_cpu_affinity[idx], &cpusetnew);
- }
- gomp_cpu_affinity[widx++] = gomp_cpu_affinity[idx];
+ if (!quiet)
+ gomp_error ("Error reading %s topology",
+ level == 2 ? "core" : "socket");
+ free (gomp_places_list);
+ gomp_places_list = NULL;
+ return false;
}
-
- if (widx == 0)
- {
- gomp_error ("no CPUs left for affinity setting");
- free (gomp_cpu_affinity);
- gomp_cpu_affinity = NULL;
- gomp_cpu_affinity_len = 0;
- return;
+ return true;
}
-
- gomp_cpu_affinity_len = widx;
- if (cpus < gomp_available_cpus)
- gomp_available_cpus = cpus;
- CPU_ZERO (&cpuset);
- CPU_SET (gomp_cpu_affinity[0], &cpuset);
- pthread_setaffinity_np (pthread_self (), sizeof (cpuset), &cpuset);
- affinity_counter = 1;
+ return false;
}
void
-gomp_init_thread_affinity (pthread_attr_t *attr)
+gomp_affinity_print_place (void *p)
{
- unsigned int cpu;
- cpu_set_t cpuset;
-
- cpu = __atomic_fetch_add (&affinity_counter, 1, MEMMODEL_RELAXED);
- cpu %= gomp_cpu_affinity_len;
- CPU_ZERO (&cpuset);
- CPU_SET (gomp_cpu_affinity[cpu], &cpuset);
- pthread_attr_setaffinity_np (attr, sizeof (cpu_set_t), &cpuset);
+ unsigned long i, max = 8 * gomp_cpuset_size, len;
+ cpu_set_t *cpusetp = (cpu_set_t *) p;
+ bool notfirst = false;
+
+ for (i = 0, len = 0; i < max; i++)
+ if (CPU_ISSET_S (i, gomp_cpuset_size, cpusetp))
+ {
+ if (len == 0)
+ {
+ if (notfirst)
+ fputc (',', stderr);
+ notfirst = true;
+ fprintf (stderr, "%lu", i);
+ }
+ ++len;
+ }
+ else
+ {
+ if (len > 1)
+ fprintf (stderr, ":%lu", len);
+ len = 0;
+ }
+ if (len > 1)
+ fprintf (stderr, ":%lu", len);
}
#else
diff --git a/libgomp/config/linux/bar.c b/libgomp/config/linux/bar.c
index 35baa886ab4..6b591e5a6c5 100644
--- a/libgomp/config/linux/bar.c
+++ b/libgomp/config/linux/bar.c
@@ -33,11 +33,11 @@
void
gomp_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state)
{
- if (__builtin_expect ((state & 1) != 0, 0))
+ if (__builtin_expect (state & BAR_WAS_LAST, 0))
{
/* Next time we'll be awaiting TOTAL threads again. */
bar->awaited = bar->total;
- __atomic_store_n (&bar->generation, bar->generation + 4,
+ __atomic_store_n (&bar->generation, bar->generation + BAR_INCR,
MEMMODEL_RELEASE);
futex_wake ((int *) &bar->generation, INT_MAX);
}
@@ -66,7 +66,7 @@ void
gomp_barrier_wait_last (gomp_barrier_t *bar)
{
gomp_barrier_state_t state = gomp_barrier_wait_start (bar);
- if (state & 1)
+ if (state & BAR_WAS_LAST)
gomp_barrier_wait_end (bar, state);
}
@@ -81,40 +81,43 @@ gomp_team_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state)
{
unsigned int generation, gen;
- if (__builtin_expect ((state & 1) != 0, 0))
+ if (__builtin_expect (state & BAR_WAS_LAST, 0))
{
/* Next time we'll be awaiting TOTAL threads again. */
struct gomp_thread *thr = gomp_thread ();
struct gomp_team *team = thr->ts.team;
bar->awaited = bar->total;
+ team->work_share_cancelled = 0;
if (__builtin_expect (team->task_count, 0))
{
gomp_barrier_handle_tasks (state);
- state &= ~1;
+ state &= ~BAR_WAS_LAST;
}
else
{
- __atomic_store_n (&bar->generation, state + 3, MEMMODEL_RELEASE);
+ state &= ~BAR_CANCELLED;
+ state += BAR_INCR - BAR_WAS_LAST;
+ __atomic_store_n (&bar->generation, state, MEMMODEL_RELEASE);
futex_wake ((int *) &bar->generation, INT_MAX);
return;
}
}
generation = state;
+ state &= ~BAR_CANCELLED;
do
{
do_wait ((int *) &bar->generation, generation);
gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
- if (__builtin_expect (gen & 1, 0))
+ if (__builtin_expect (gen & BAR_TASK_PENDING, 0))
{
gomp_barrier_handle_tasks (state);
gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
}
- if ((gen & 2) != 0)
- generation |= 2;
+ generation |= gen & BAR_WAITING_FOR_TASK;
}
- while (gen != state + 4);
+ while (gen != state + BAR_INCR);
}
void
@@ -122,3 +125,86 @@ gomp_team_barrier_wait (gomp_barrier_t *bar)
{
gomp_team_barrier_wait_end (bar, gomp_barrier_wait_start (bar));
}
+
+void
+gomp_team_barrier_wait_final (gomp_barrier_t *bar)
+{
+ gomp_barrier_state_t state = gomp_barrier_wait_final_start (bar);
+ if (__builtin_expect (state & BAR_WAS_LAST, 0))
+ bar->awaited_final = bar->total;
+ gomp_team_barrier_wait_end (bar, state);
+}
+
+bool
+gomp_team_barrier_wait_cancel_end (gomp_barrier_t *bar,
+ gomp_barrier_state_t state)
+{
+ unsigned int generation, gen;
+
+ if (__builtin_expect (state & BAR_WAS_LAST, 0))
+ {
+ /* Next time we'll be awaiting TOTAL threads again. */
+ /* BAR_CANCELLED should never be set in state here, because
+ cancellation means that at least one of the threads has been
+ cancelled, thus on a cancellable barrier we should never see
+ all threads to arrive. */
+ struct gomp_thread *thr = gomp_thread ();
+ struct gomp_team *team = thr->ts.team;
+
+ bar->awaited = bar->total;
+ team->work_share_cancelled = 0;
+ if (__builtin_expect (team->task_count, 0))
+ {
+ gomp_barrier_handle_tasks (state);
+ state &= ~BAR_WAS_LAST;
+ }
+ else
+ {
+ state += BAR_INCR - BAR_WAS_LAST;
+ __atomic_store_n (&bar->generation, state, MEMMODEL_RELEASE);
+ futex_wake ((int *) &bar->generation, INT_MAX);
+ return false;
+ }
+ }
+
+ if (__builtin_expect (state & BAR_CANCELLED, 0))
+ return true;
+
+ generation = state;
+ do
+ {
+ do_wait ((int *) &bar->generation, generation);
+ gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
+ if (__builtin_expect (gen & BAR_CANCELLED, 0))
+ return true;
+ if (__builtin_expect (gen & BAR_TASK_PENDING, 0))
+ {
+ gomp_barrier_handle_tasks (state);
+ gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
+ }
+ generation |= gen & BAR_WAITING_FOR_TASK;
+ }
+ while (gen != state + BAR_INCR);
+
+ return false;
+}
+
+bool
+gomp_team_barrier_wait_cancel (gomp_barrier_t *bar)
+{
+ return gomp_team_barrier_wait_cancel_end (bar, gomp_barrier_wait_start (bar));
+}
+
+void
+gomp_team_barrier_cancel (struct gomp_team *team)
+{
+ gomp_mutex_lock (&team->task_lock);
+ if (team->barrier.generation & BAR_CANCELLED)
+ {
+ gomp_mutex_unlock (&team->task_lock);
+ return;
+ }
+ team->barrier.generation |= BAR_CANCELLED;
+ gomp_mutex_unlock (&team->task_lock);
+ futex_wake ((int *) &team->barrier.generation, INT_MAX);
+}
diff --git a/libgomp/config/linux/bar.h b/libgomp/config/linux/bar.h
index 69b97069647..914c86778e5 100644
--- a/libgomp/config/linux/bar.h
+++ b/libgomp/config/linux/bar.h
@@ -38,13 +38,25 @@ typedef struct
unsigned total __attribute__((aligned (64)));
unsigned generation;
unsigned awaited __attribute__((aligned (64)));
+ unsigned awaited_final;
} gomp_barrier_t;
+
typedef unsigned int gomp_barrier_state_t;
+/* The generation field contains a counter in the high bits, with a few
+ low bits dedicated to flags. Note that TASK_PENDING and WAS_LAST can
+ share space because WAS_LAST is never stored back to generation. */
+#define BAR_TASK_PENDING 1
+#define BAR_WAS_LAST 1
+#define BAR_WAITING_FOR_TASK 2
+#define BAR_CANCELLED 4
+#define BAR_INCR 8
+
static inline void gomp_barrier_init (gomp_barrier_t *bar, unsigned count)
{
bar->total = count;
bar->awaited = count;
+ bar->awaited_final = count;
bar->generation = 0;
}
@@ -62,27 +74,55 @@ extern void gomp_barrier_wait (gomp_barrier_t *);
extern void gomp_barrier_wait_last (gomp_barrier_t *);
extern void gomp_barrier_wait_end (gomp_barrier_t *, gomp_barrier_state_t);
extern void gomp_team_barrier_wait (gomp_barrier_t *);
+extern void gomp_team_barrier_wait_final (gomp_barrier_t *);
extern void gomp_team_barrier_wait_end (gomp_barrier_t *,
gomp_barrier_state_t);
+extern bool gomp_team_barrier_wait_cancel (gomp_barrier_t *);
+extern bool gomp_team_barrier_wait_cancel_end (gomp_barrier_t *,
+ gomp_barrier_state_t);
extern void gomp_team_barrier_wake (gomp_barrier_t *, int);
+struct gomp_team;
+extern void gomp_team_barrier_cancel (struct gomp_team *);
static inline gomp_barrier_state_t
gomp_barrier_wait_start (gomp_barrier_t *bar)
{
- unsigned int ret = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE) & ~3;
+ unsigned int ret = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
+ ret &= -BAR_INCR | BAR_CANCELLED;
/* A memory barrier is needed before exiting from the various forms
of gomp_barrier_wait, to satisfy OpenMP API version 3.1 section
2.8.6 flush Construct, which says there is an implicit flush during
a barrier region. This is a convenient place to add the barrier,
so we use MEMMODEL_ACQ_REL here rather than MEMMODEL_ACQUIRE. */
- ret += __atomic_add_fetch (&bar->awaited, -1, MEMMODEL_ACQ_REL) == 0;
+ if (__atomic_add_fetch (&bar->awaited, -1, MEMMODEL_ACQ_REL) == 0)
+ ret |= BAR_WAS_LAST;
+ return ret;
+}
+
+static inline gomp_barrier_state_t
+gomp_barrier_wait_cancel_start (gomp_barrier_t *bar)
+{
+ return gomp_barrier_wait_start (bar);
+}
+
+/* This is like gomp_barrier_wait_start, except it decrements
+ bar->awaited_final rather than bar->awaited and should be used
+ for the gomp_team_end barrier only. */
+static inline gomp_barrier_state_t
+gomp_barrier_wait_final_start (gomp_barrier_t *bar)
+{
+ unsigned int ret = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
+ ret &= -BAR_INCR | BAR_CANCELLED;
+ /* See above gomp_barrier_wait_start comment. */
+ if (__atomic_add_fetch (&bar->awaited_final, -1, MEMMODEL_ACQ_REL) == 0)
+ ret |= BAR_WAS_LAST;
return ret;
}
static inline bool
gomp_barrier_last_thread (gomp_barrier_state_t state)
{
- return state & 1;
+ return state & BAR_WAS_LAST;
}
/* All the inlines below must be called with team->task_lock
@@ -91,31 +131,37 @@ gomp_barrier_last_thread (gomp_barrier_state_t state)
static inline void
gomp_team_barrier_set_task_pending (gomp_barrier_t *bar)
{
- bar->generation |= 1;
+ bar->generation |= BAR_TASK_PENDING;
}
static inline void
gomp_team_barrier_clear_task_pending (gomp_barrier_t *bar)
{
- bar->generation &= ~1;
+ bar->generation &= ~BAR_TASK_PENDING;
}
static inline void
gomp_team_barrier_set_waiting_for_tasks (gomp_barrier_t *bar)
{
- bar->generation |= 2;
+ bar->generation |= BAR_WAITING_FOR_TASK;
}
static inline bool
gomp_team_barrier_waiting_for_tasks (gomp_barrier_t *bar)
{
- return (bar->generation & 2) != 0;
+ return (bar->generation & BAR_WAITING_FOR_TASK) != 0;
+}
+
+static inline bool
+gomp_team_barrier_cancelled (gomp_barrier_t *bar)
+{
+ return __builtin_expect ((bar->generation & BAR_CANCELLED) != 0, 0);
}
static inline void
gomp_team_barrier_done (gomp_barrier_t *bar, gomp_barrier_state_t state)
{
- bar->generation = (state & ~3) + 4;
+ bar->generation = (state & -BAR_INCR) + BAR_INCR;
}
#endif /* GOMP_BARRIER_H */
diff --git a/libgomp/config/linux/proc.c b/libgomp/config/linux/proc.c
index cbb773e6e90..d4ae116e239 100644
--- a/libgomp/config/linux/proc.c
+++ b/libgomp/config/linux/proc.c
@@ -30,6 +30,7 @@
#endif
#include "libgomp.h"
#include "proc.h"
+#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#ifdef HAVE_GETLOADAVG
@@ -39,19 +40,28 @@
#endif
#ifdef HAVE_PTHREAD_AFFINITY_NP
+unsigned long gomp_cpuset_size;
+static unsigned long gomp_get_cpuset_size;
+cpu_set_t *gomp_cpusetp;
+
unsigned long
-gomp_cpuset_popcount (cpu_set_t *cpusetp)
+gomp_cpuset_popcount (unsigned long cpusetsize, cpu_set_t *cpusetp)
{
-#ifdef CPU_COUNT
- /* glibc 2.6 and above provide a macro for this. */
- return CPU_COUNT (cpusetp);
+#ifdef CPU_COUNT_S
+ /* glibc 2.7 and above provide a macro for this. */
+ return CPU_COUNT_S (cpusetsize, cpusetp);
#else
+#ifdef CPU_COUNT
+ if (cpusetsize == sizeof (cpu_set_t))
+ /* glibc 2.6 and above provide a macro for this. */
+ return CPU_COUNT (cpusetp);
+#endif
size_t i;
unsigned long ret = 0;
- extern int check[sizeof (cpusetp->__bits[0]) == sizeof (unsigned long int)];
+ extern int check[sizeof (cpusetp->__bits[0]) == sizeof (unsigned long int)
+ ? 1 : -1];
- (void) check;
- for (i = 0; i < sizeof (*cpusetp) / sizeof (cpusetp->__bits[0]); i++)
+ for (i = 0; i < cpusetsize / sizeof (cpusetp->__bits[0]); i++)
{
unsigned long int mask = cpusetp->__bits[i];
if (mask == 0)
@@ -70,16 +80,63 @@ void
gomp_init_num_threads (void)
{
#ifdef HAVE_PTHREAD_AFFINITY_NP
- cpu_set_t cpuset;
+#if defined (_SC_NPROCESSORS_CONF) && defined (CPU_ALLOC_SIZE)
+ gomp_cpuset_size = sysconf (_SC_NPROCESSORS_CONF);
+ gomp_cpuset_size = CPU_ALLOC_SIZE (gomp_cpuset_size);
+#else
+ gomp_cpuset_size = sizeof (cpu_set_t);
+#endif
- if (pthread_getaffinity_np (pthread_self (), sizeof (cpuset), &cpuset) == 0)
+ gomp_cpusetp = (cpu_set_t *) gomp_malloc (gomp_cpuset_size);
+ do
{
- /* Count only the CPUs this process can use. */
- gomp_global_icv.nthreads_var = gomp_cpuset_popcount (&cpuset);
- if (gomp_global_icv.nthreads_var == 0)
- gomp_global_icv.nthreads_var = 1;
- return;
+ int ret = pthread_getaffinity_np (pthread_self (), gomp_cpuset_size,
+ gomp_cpusetp);
+ if (ret == 0)
+ {
+ unsigned long i;
+ /* Count only the CPUs this process can use. */
+ gomp_global_icv.nthreads_var
+ = gomp_cpuset_popcount (gomp_cpuset_size, gomp_cpusetp);
+ if (gomp_global_icv.nthreads_var == 0)
+ break;
+ gomp_get_cpuset_size = gomp_cpuset_size;
+#ifdef CPU_ALLOC_SIZE
+ for (i = gomp_cpuset_size * 8; i; i--)
+ if (CPU_ISSET_S (i - 1, gomp_cpuset_size, gomp_cpusetp))
+ break;
+ gomp_cpuset_size = CPU_ALLOC_SIZE (i);
+#endif
+ return;
+ }
+ if (ret != EINVAL)
+ break;
+#ifdef CPU_ALLOC_SIZE
+ if (gomp_cpuset_size < sizeof (cpu_set_t))
+ gomp_cpuset_size = sizeof (cpu_set_t);
+ else
+ gomp_cpuset_size = gomp_cpuset_size * 2;
+ if (gomp_cpuset_size < 8 * sizeof (cpu_set_t))
+ gomp_cpusetp
+ = (cpu_set_t *) gomp_realloc (gomp_cpusetp, gomp_cpuset_size);
+ else
+ {
+ /* Avoid gomp_fatal if too large memory allocation would be
+ requested, e.g. kernel returning EINVAL all the time. */
+ void *p = realloc (gomp_cpusetp, gomp_cpuset_size);
+ if (p == NULL)
+ break;
+ gomp_cpusetp = (cpu_set_t *) p;
+ }
+#else
+ break;
+#endif
}
+ while (1);
+ gomp_cpuset_size = 0;
+ gomp_global_icv.nthreads_var = 1;
+ free (gomp_cpusetp);
+ gomp_cpusetp = NULL;
#endif
#ifdef _SC_NPROCESSORS_ONLN
gomp_global_icv.nthreads_var = sysconf (_SC_NPROCESSORS_ONLN);
@@ -90,15 +147,14 @@ static int
get_num_procs (void)
{
#ifdef HAVE_PTHREAD_AFFINITY_NP
- cpu_set_t cpuset;
-
- if (gomp_cpu_affinity == NULL)
+ if (gomp_places_list == NULL)
{
/* Count only the CPUs this process can use. */
- if (pthread_getaffinity_np (pthread_self (), sizeof (cpuset),
- &cpuset) == 0)
+ if (gomp_cpusetp
+ && pthread_getaffinity_np (pthread_self (), gomp_get_cpuset_size,
+ gomp_cpusetp) == 0)
{
- int ret = gomp_cpuset_popcount (&cpuset);
+ int ret = gomp_cpuset_popcount (gomp_get_cpuset_size, gomp_cpusetp);
return ret != 0 ? ret : 1;
}
}
diff --git a/libgomp/config/linux/proc.h b/libgomp/config/linux/proc.h
index cba7f4a09e6..bdc85dba99e 100644
--- a/libgomp/config/linux/proc.h
+++ b/libgomp/config/linux/proc.h
@@ -28,7 +28,10 @@
#include <sched.h>
#ifdef HAVE_PTHREAD_AFFINITY_NP
-extern unsigned long gomp_cpuset_popcount (cpu_set_t *);
+extern unsigned long gomp_cpuset_size attribute_hidden;
+extern cpu_set_t *gomp_cpusetp attribute_hidden;
+extern unsigned long gomp_cpuset_popcount (unsigned long, cpu_set_t *)
+ attribute_hidden;
#endif
#endif /* GOMP_PROC_H */
diff --git a/libgomp/config/posix/affinity.c b/libgomp/config/posix/affinity.c
index ac3d14e830c..e7f97ab08d6 100644
--- a/libgomp/config/posix/affinity.c
+++ b/libgomp/config/posix/affinity.c
@@ -32,7 +32,84 @@ gomp_init_affinity (void)
}
void
-gomp_init_thread_affinity (pthread_attr_t *attr)
+gomp_init_thread_affinity (pthread_attr_t *attr, unsigned int place)
{
(void) attr;
+ (void) place;
+}
+
+void **
+gomp_affinity_alloc (unsigned long count, bool quiet)
+{
+ (void) count;
+ if (!quiet)
+ gomp_error ("Affinity not supported on this configuration");
+ return NULL;
+}
+
+void
+gomp_affinity_init_place (void *p)
+{
+ (void) p;
+}
+
+bool
+gomp_affinity_add_cpus (void *p, unsigned long num,
+ unsigned long len, long stride, bool quiet)
+{
+ (void) p;
+ (void) num;
+ (void) len;
+ (void) stride;
+ (void) quiet;
+ return false;
+}
+
+bool
+gomp_affinity_remove_cpu (void *p, unsigned long num)
+{
+ (void) p;
+ (void) num;
+ return false;
+}
+
+bool
+gomp_affinity_copy_place (void *p, void *q, long stride)
+{
+ (void) p;
+ (void) q;
+ (void) stride;
+ return false;
+}
+
+bool
+gomp_affinity_same_place (void *p, void *q)
+{
+ (void) p;
+ (void) q;
+ return false;
+}
+
+bool
+gomp_affinity_finalize_place_list (bool quiet)
+{
+ (void) quiet;
+ return false;
+}
+
+bool
+gomp_affinity_init_level (int level, unsigned long count, bool quiet)
+{
+ (void) level;
+ (void) count;
+ (void) quiet;
+ if (!quiet)
+ gomp_error ("Affinity not supported on this configuration");
+ return NULL;
+}
+
+void
+gomp_affinity_print_place (void *p)
+{
+ (void) p;
}
diff --git a/libgomp/config/posix/bar.c b/libgomp/config/posix/bar.c
index 06a3185c286..bdf3978caee 100644
--- a/libgomp/config/posix/bar.c
+++ b/libgomp/config/posix/bar.c
@@ -42,6 +42,7 @@ gomp_barrier_init (gomp_barrier_t *bar, unsigned count)
bar->total = count;
bar->arrived = 0;
bar->generation = 0;
+ bar->cancellable = false;
}
void
@@ -72,7 +73,7 @@ gomp_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state)
{
unsigned int n;
- if (state & 1)
+ if (state & BAR_WAS_LAST)
{
n = --bar->arrived;
if (n > 0)
@@ -113,12 +114,14 @@ gomp_team_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state)
{
unsigned int n;
- if (state & 1)
+ state &= ~BAR_CANCELLED;
+ if (state & BAR_WAS_LAST)
{
n = --bar->arrived;
struct gomp_thread *thr = gomp_thread ();
struct gomp_team *team = thr->ts.team;
+ team->work_share_cancelled = 0;
if (team->task_count)
{
gomp_barrier_handle_tasks (state);
@@ -128,7 +131,7 @@ gomp_team_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state)
return;
}
- bar->generation = state + 3;
+ bar->generation = state + BAR_INCR - BAR_WAS_LAST;
if (n > 0)
{
do
@@ -141,13 +144,18 @@ gomp_team_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state)
else
{
gomp_mutex_unlock (&bar->mutex1);
+ int gen;
do
{
gomp_sem_wait (&bar->sem1);
- if (bar->generation & 1)
- gomp_barrier_handle_tasks (state);
+ gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
+ if (gen & BAR_TASK_PENDING)
+ {
+ gomp_barrier_handle_tasks (state);
+ gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
+ }
}
- while (bar->generation != state + 4);
+ while (gen != state + BAR_INCR);
#ifdef HAVE_SYNC_BUILTINS
n = __sync_add_and_fetch (&bar->arrived, -1);
@@ -162,6 +170,81 @@ gomp_team_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state)
}
}
+bool
+gomp_team_barrier_wait_cancel_end (gomp_barrier_t *bar,
+ gomp_barrier_state_t state)
+{
+ unsigned int n;
+
+ if (state & BAR_WAS_LAST)
+ {
+ bar->cancellable = false;
+ n = --bar->arrived;
+ struct gomp_thread *thr = gomp_thread ();
+ struct gomp_team *team = thr->ts.team;
+
+ team->work_share_cancelled = 0;
+ if (team->task_count)
+ {
+ gomp_barrier_handle_tasks (state);
+ if (n > 0)
+ gomp_sem_wait (&bar->sem2);
+ gomp_mutex_unlock (&bar->mutex1);
+ return false;
+ }
+
+ bar->generation = state + BAR_INCR - BAR_WAS_LAST;
+ if (n > 0)
+ {
+ do
+ gomp_sem_post (&bar->sem1);
+ while (--n != 0);
+ gomp_sem_wait (&bar->sem2);
+ }
+ gomp_mutex_unlock (&bar->mutex1);
+ }
+ else
+ {
+ if (state & BAR_CANCELLED)
+ {
+ gomp_mutex_unlock (&bar->mutex1);
+ return true;
+ }
+ bar->cancellable = true;
+ gomp_mutex_unlock (&bar->mutex1);
+ int gen;
+ do
+ {
+ gomp_sem_wait (&bar->sem1);
+ gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
+ if (gen & BAR_CANCELLED)
+ break;
+ if (gen & BAR_TASK_PENDING)
+ {
+ gomp_barrier_handle_tasks (state);
+ gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
+ if (gen & BAR_CANCELLED)
+ break;
+ }
+ }
+ while (gen != state + BAR_INCR);
+
+#ifdef HAVE_SYNC_BUILTINS
+ n = __sync_add_and_fetch (&bar->arrived, -1);
+#else
+ gomp_mutex_lock (&bar->mutex2);
+ n = --bar->arrived;
+ gomp_mutex_unlock (&bar->mutex2);
+#endif
+
+ if (n == 0)
+ gomp_sem_post (&bar->sem2);
+ if (gen & BAR_CANCELLED)
+ return true;
+ }
+ return false;
+}
+
void
gomp_team_barrier_wait (gomp_barrier_t *barrier)
{
@@ -176,3 +259,40 @@ gomp_team_barrier_wake (gomp_barrier_t *bar, int count)
while (count-- > 0)
gomp_sem_post (&bar->sem1);
}
+
+bool
+gomp_team_barrier_wait_cancel (gomp_barrier_t *bar)
+{
+ gomp_barrier_state_t state = gomp_barrier_wait_cancel_start (bar);
+ return gomp_team_barrier_wait_cancel_end (bar, state);
+}
+
+void
+gomp_team_barrier_cancel (struct gomp_team *team)
+{
+ if (team->barrier.generation & BAR_CANCELLED)
+ return;
+ gomp_mutex_lock (&team->barrier.mutex1);
+ gomp_mutex_lock (&team->task_lock);
+ if (team->barrier.generation & BAR_CANCELLED)
+ {
+ gomp_mutex_unlock (&team->task_lock);
+ gomp_mutex_unlock (&team->barrier.mutex1);
+ return;
+ }
+ team->barrier.generation |= BAR_CANCELLED;
+ gomp_mutex_unlock (&team->task_lock);
+ if (team->barrier.cancellable)
+ {
+ int n = team->barrier.arrived;
+ if (n > 0)
+ {
+ do
+ gomp_sem_post (&team->barrier.sem1);
+ while (--n != 0);
+ gomp_sem_wait (&team->barrier.sem2);
+ }
+ team->barrier.cancellable = false;
+ }
+ gomp_mutex_unlock (&team->barrier.mutex1);
+}
diff --git a/libgomp/config/posix/bar.h b/libgomp/config/posix/bar.h
index 1a16ca86bba..9fcd4da6723 100644
--- a/libgomp/config/posix/bar.h
+++ b/libgomp/config/posix/bar.h
@@ -43,9 +43,20 @@ typedef struct
unsigned total;
unsigned arrived;
unsigned generation;
+ bool cancellable;
} gomp_barrier_t;
+
typedef unsigned int gomp_barrier_state_t;
+/* The generation field contains a counter in the high bits, with a few
+ low bits dedicated to flags. Note that TASK_PENDING and WAS_LAST can
+ share space because WAS_LAST is never stored back to generation. */
+#define BAR_TASK_PENDING 1
+#define BAR_WAS_LAST 1
+#define BAR_WAITING_FOR_TASK 2
+#define BAR_CANCELLED 4
+#define BAR_INCR 8
+
extern void gomp_barrier_init (gomp_barrier_t *, unsigned);
extern void gomp_barrier_reinit (gomp_barrier_t *, unsigned);
extern void gomp_barrier_destroy (gomp_barrier_t *);
@@ -55,22 +66,47 @@ extern void gomp_barrier_wait_end (gomp_barrier_t *, gomp_barrier_state_t);
extern void gomp_team_barrier_wait (gomp_barrier_t *);
extern void gomp_team_barrier_wait_end (gomp_barrier_t *,
gomp_barrier_state_t);
+extern bool gomp_team_barrier_wait_cancel (gomp_barrier_t *);
+extern bool gomp_team_barrier_wait_cancel_end (gomp_barrier_t *,
+ gomp_barrier_state_t);
extern void gomp_team_barrier_wake (gomp_barrier_t *, int);
+struct gomp_team;
+extern void gomp_team_barrier_cancel (struct gomp_team *);
static inline gomp_barrier_state_t
gomp_barrier_wait_start (gomp_barrier_t *bar)
{
unsigned int ret;
gomp_mutex_lock (&bar->mutex1);
- ret = bar->generation & ~3;
- ret += ++bar->arrived == bar->total;
+ ret = bar->generation & (-BAR_INCR | BAR_CANCELLED);
+ if (++bar->arrived == bar->total)
+ ret |= BAR_WAS_LAST;
+ return ret;
+}
+
+static inline gomp_barrier_state_t
+gomp_barrier_wait_cancel_start (gomp_barrier_t *bar)
+{
+ unsigned int ret;
+ gomp_mutex_lock (&bar->mutex1);
+ ret = bar->generation & (-BAR_INCR | BAR_CANCELLED);
+ if (ret & BAR_CANCELLED)
+ return ret;
+ if (++bar->arrived == bar->total)
+ ret |= BAR_WAS_LAST;
return ret;
}
+static inline void
+gomp_team_barrier_wait_final (gomp_barrier_t *bar)
+{
+ gomp_team_barrier_wait (bar);
+}
+
static inline bool
gomp_barrier_last_thread (gomp_barrier_state_t state)
{
- return state & 1;
+ return state & BAR_WAS_LAST;
}
static inline void
@@ -85,31 +121,37 @@ gomp_barrier_wait_last (gomp_barrier_t *bar)
static inline void
gomp_team_barrier_set_task_pending (gomp_barrier_t *bar)
{
- bar->generation |= 1;
+ bar->generation |= BAR_TASK_PENDING;
}
static inline void
gomp_team_barrier_clear_task_pending (gomp_barrier_t *bar)
{
- bar->generation &= ~1;
+ bar->generation &= ~BAR_TASK_PENDING;
}
static inline void
gomp_team_barrier_set_waiting_for_tasks (gomp_barrier_t *bar)
{
- bar->generation |= 2;
+ bar->generation |= BAR_WAITING_FOR_TASK;
}
static inline bool
gomp_team_barrier_waiting_for_tasks (gomp_barrier_t *bar)
{
- return (bar->generation & 2) != 0;
+ return (bar->generation & BAR_WAITING_FOR_TASK) != 0;
+}
+
+static inline bool
+gomp_team_barrier_cancelled (gomp_barrier_t *bar)
+{
+ return __builtin_expect ((bar->generation & BAR_CANCELLED) != 0, 0);
}
static inline void
gomp_team_barrier_done (gomp_barrier_t *bar, gomp_barrier_state_t state)
{
- bar->generation = (state & ~3) + 4;
+ bar->generation = (state & -BAR_INCR) + BAR_INCR;
}
#endif /* GOMP_BARRIER_H */
diff --git a/libgomp/env.c b/libgomp/env.c
index 65cbba83e6c..57997c5765c 100644
--- a/libgomp/env.c
+++ b/libgomp/env.c
@@ -29,6 +29,10 @@
#include "libgomp_f.h"
#include <ctype.h>
#include <stdlib.h>
+#include <stdio.h>
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h> /* For PRIu64. */
+#endif
#ifdef STRING_WITH_STRINGS
# include <string.h>
# include <strings.h>
@@ -50,23 +54,28 @@
struct gomp_task_icv gomp_global_icv = {
.nthreads_var = 1,
+ .thread_limit_var = UINT_MAX,
.run_sched_var = GFS_DYNAMIC,
.run_sched_modifier = 1,
+ .default_device_var = 0,
.dyn_var = false,
- .nest_var = false
+ .nest_var = false,
+ .bind_var = omp_proc_bind_false,
+ .target_data = NULL
};
-unsigned short *gomp_cpu_affinity;
-size_t gomp_cpu_affinity_len;
unsigned long gomp_max_active_levels_var = INT_MAX;
-unsigned long gomp_thread_limit_var = ULONG_MAX;
-unsigned long gomp_remaining_threads_count;
+bool gomp_cancel_var = false;
#ifndef HAVE_SYNC_BUILTINS
-gomp_mutex_t gomp_remaining_threads_lock;
+gomp_mutex_t gomp_managed_threads_lock;
#endif
unsigned long gomp_available_cpus = 1, gomp_managed_threads = 1;
unsigned long long gomp_spin_count_var, gomp_throttled_spin_count_var;
unsigned long *gomp_nthreads_var_list, gomp_nthreads_var_list_len;
+char *gomp_bind_var_list;
+unsigned long gomp_bind_var_list_len;
+void **gomp_places_list;
+unsigned long gomp_places_list_len;
/* Parse the OMP_SCHEDULE environment variable. */
@@ -184,6 +193,24 @@ parse_unsigned_long (const char *name, unsigned long *pvalue, bool allow_zero)
return false;
}
+/* Parse a positive int environment variable. Return true if one was
+ present and it was successfully parsed. */
+
+static bool
+parse_int (const char *name, int *pvalue, bool allow_zero)
+{
+ unsigned long value;
+ if (!parse_unsigned_long (name, &value, allow_zero))
+ return false;
+ if (value > INT_MAX)
+ {
+ gomp_error ("Invalid value for environment variable %s", name);
+ return false;
+ }
+ *pvalue = (int) value;
+ return true;
+}
+
/* Parse an unsigned long list environment variable. Return true if one was
present and it was successfully parsed. */
@@ -273,6 +300,412 @@ parse_unsigned_long_list (const char *name, unsigned long *p1stvalue,
return false;
}
+/* Parse environment variable set to a boolean or list of omp_proc_bind_t
+ enum values. Return true if one was present and it was successfully
+ parsed. */
+
+static bool
+parse_bind_var (const char *name, char *p1stvalue,
+ char **pvalues, unsigned long *pnvalues)
+{
+ char *env;
+ char value, *values = NULL;
+ int i;
+ static struct proc_bind_kinds
+ {
+ const char name[7];
+ const char len;
+ omp_proc_bind_t kind;
+ } kinds[] =
+ {
+ { "false", 5, omp_proc_bind_false },
+ { "true", 4, omp_proc_bind_true },
+ { "master", 6, omp_proc_bind_master },
+ { "close", 5, omp_proc_bind_close },
+ { "spread", 6, omp_proc_bind_spread }
+ };
+
+ env = getenv (name);
+ if (env == NULL)
+ return false;
+
+ while (isspace ((unsigned char) *env))
+ ++env;
+ if (*env == '\0')
+ goto invalid;
+
+ for (i = 0; i < 5; i++)
+ if (strncasecmp (env, kinds[i].name, kinds[i].len) == 0)
+ {
+ value = kinds[i].kind;
+ env += kinds[i].len;
+ break;
+ }
+ if (i == 5)
+ goto invalid;
+
+ while (isspace ((unsigned char) *env))
+ ++env;
+ if (*env != '\0')
+ {
+ if (*env == ',')
+ {
+ unsigned long nvalues = 0, nalloced = 0;
+
+ if (value == omp_proc_bind_false
+ || value == omp_proc_bind_true)
+ goto invalid;
+
+ do
+ {
+ env++;
+ if (nvalues == nalloced)
+ {
+ char *n;
+ nalloced = nalloced ? nalloced * 2 : 16;
+ n = realloc (values, nalloced);
+ if (n == NULL)
+ {
+ free (values);
+ gomp_error ("Out of memory while trying to parse"
+ " environment variable %s", name);
+ return false;
+ }
+ values = n;
+ if (nvalues == 0)
+ values[nvalues++] = value;
+ }
+
+ while (isspace ((unsigned char) *env))
+ ++env;
+ if (*env == '\0')
+ goto invalid;
+
+ for (i = 2; i < 5; i++)
+ if (strncasecmp (env, kinds[i].name, kinds[i].len) == 0)
+ {
+ value = kinds[i].kind;
+ env += kinds[i].len;
+ break;
+ }
+ if (i == 5)
+ goto invalid;
+
+ values[nvalues++] = value;
+ while (isspace ((unsigned char) *env))
+ ++env;
+ if (*env == '\0')
+ break;
+ if (*env != ',')
+ goto invalid;
+ }
+ while (1);
+ *p1stvalue = values[0];
+ *pvalues = values;
+ *pnvalues = nvalues;
+ return true;
+ }
+ goto invalid;
+ }
+
+ *p1stvalue = value;
+ return true;
+
+ invalid:
+ free (values);
+ gomp_error ("Invalid value for environment variable %s", name);
+ return false;
+}
+
+static bool
+parse_one_place (char **envp, bool *negatep, unsigned long *lenp,
+ long *stridep)
+{
+ char *env = *envp, *start;
+ void *p = gomp_places_list ? gomp_places_list[gomp_places_list_len] : NULL;
+ unsigned long len = 1;
+ long stride = 1;
+ int pass;
+ bool any_negate = false;
+ *negatep = false;
+ while (isspace ((unsigned char) *env))
+ ++env;
+ if (*env == '!')
+ {
+ *negatep = true;
+ ++env;
+ while (isspace ((unsigned char) *env))
+ ++env;
+ }
+ if (*env != '{')
+ return false;
+ ++env;
+ while (isspace ((unsigned char) *env))
+ ++env;
+ start = env;
+ for (pass = 0; pass < (any_negate ? 2 : 1); pass++)
+ {
+ env = start;
+ do
+ {
+ unsigned long this_num, this_len = 1;
+ long this_stride = 1;
+ bool this_negate = (*env == '!');
+ if (this_negate)
+ {
+ if (gomp_places_list)
+ any_negate = true;
+ ++env;
+ while (isspace ((unsigned char) *env))
+ ++env;
+ }
+
+ errno = 0;
+ this_num = strtoul (env, &env, 10);
+ if (errno)
+ return false;
+ while (isspace ((unsigned char) *env))
+ ++env;
+ if (*env == ':')
+ {
+ ++env;
+ while (isspace ((unsigned char) *env))
+ ++env;
+ errno = 0;
+ this_len = strtoul (env, &env, 10);
+ if (errno || this_len == 0)
+ return false;
+ while (isspace ((unsigned char) *env))
+ ++env;
+ if (*env == ':')
+ {
+ ++env;
+ while (isspace ((unsigned char) *env))
+ ++env;
+ errno = 0;
+ this_stride = strtol (env, &env, 10);
+ if (errno)
+ return false;
+ while (isspace ((unsigned char) *env))
+ ++env;
+ }
+ }
+ if (this_negate && this_len != 1)
+ return false;
+ if (gomp_places_list && pass == this_negate)
+ {
+ if (this_negate)
+ {
+ if (!gomp_affinity_remove_cpu (p, this_num))
+ return false;
+ }
+ else if (!gomp_affinity_add_cpus (p, this_num, this_len,
+ this_stride, false))
+ return false;
+ }
+ if (*env == '}')
+ break;
+ if (*env != ',')
+ return false;
+ ++env;
+ }
+ while (1);
+ }
+
+ ++env;
+ while (isspace ((unsigned char) *env))
+ ++env;
+ if (*env == ':')
+ {
+ ++env;
+ while (isspace ((unsigned char) *env))
+ ++env;
+ errno = 0;
+ len = strtoul (env, &env, 10);
+ if (errno || len == 0 || len >= 65536)
+ return false;
+ while (isspace ((unsigned char) *env))
+ ++env;
+ if (*env == ':')
+ {
+ ++env;
+ while (isspace ((unsigned char) *env))
+ ++env;
+ errno = 0;
+ stride = strtol (env, &env, 10);
+ if (errno)
+ return false;
+ while (isspace ((unsigned char) *env))
+ ++env;
+ }
+ }
+ if (*negatep && len != 1)
+ return false;
+ *envp = env;
+ *lenp = len;
+ *stridep = stride;
+ return true;
+}
+
+static bool
+parse_places_var (const char *name)
+{
+ char *env = getenv (name), *end;
+ bool any_negate = false;
+ int level = 0;
+ unsigned long count = 0;
+ if (env == NULL)
+ return false;
+
+ while (isspace ((unsigned char) *env))
+ ++env;
+ if (*env == '\0')
+ goto invalid;
+
+ if (strncasecmp (env, "threads", 7) == 0)
+ {
+ env += 7;
+ level = 1;
+ }
+ else if (strncasecmp (env, "cores", 5) == 0)
+ {
+ env += 5;
+ level = 2;
+ }
+ else if (strncasecmp (env, "sockets", 7) == 0)
+ {
+ env += 7;
+ level = 3;
+ }
+ if (level)
+ {
+ count = ULONG_MAX;
+ while (isspace ((unsigned char) *env))
+ ++env;
+ if (*env != '\0')
+ {
+ if (*env++ != '(')
+ goto invalid;
+ while (isspace ((unsigned char) *env))
+ ++env;
+
+ errno = 0;
+ count = strtoul (env, &end, 10);
+ if (errno)
+ goto invalid;
+ env = end;
+ while (isspace ((unsigned char) *env))
+ ++env;
+ if (*env != ')')
+ goto invalid;
+ ++env;
+ while (isspace ((unsigned char) *env))
+ ++env;
+ if (*env != '\0')
+ goto invalid;
+ }
+ return gomp_affinity_init_level (level, count, false);
+ }
+
+ count = 0;
+ end = env;
+ do
+ {
+ bool negate;
+ unsigned long len;
+ long stride;
+ if (!parse_one_place (&end, &negate, &len, &stride))
+ goto invalid;
+ if (negate)
+ {
+ if (!any_negate)
+ count++;
+ any_negate = true;
+ }
+ else
+ count += len;
+ if (count > 65536)
+ goto invalid;
+ if (*end == '\0')
+ break;
+ if (*end != ',')
+ goto invalid;
+ end++;
+ }
+ while (1);
+
+ if (gomp_global_icv.bind_var == omp_proc_bind_false)
+ return false;
+
+ gomp_places_list_len = 0;
+ gomp_places_list = gomp_affinity_alloc (count, false);
+ if (gomp_places_list == NULL)
+ return false;
+
+ do
+ {
+ bool negate;
+ unsigned long len;
+ long stride;
+ gomp_affinity_init_place (gomp_places_list[gomp_places_list_len]);
+ if (!parse_one_place (&env, &negate, &len, &stride))
+ goto invalid;
+ if (negate)
+ {
+ void *p;
+ for (count = 0; count < gomp_places_list_len; count++)
+ if (gomp_affinity_same_place
+ (gomp_places_list[count],
+ gomp_places_list[gomp_places_list_len]))
+ break;
+ if (count == gomp_places_list_len)
+ {
+ gomp_error ("Trying to remove a non-existing place from list "
+ "of places");
+ goto invalid;
+ }
+ p = gomp_places_list[count];
+ memmove (&gomp_places_list[count],
+ &gomp_places_list[count + 1],
+ (gomp_places_list_len - count - 1) * sizeof (void *));
+ --gomp_places_list_len;
+ gomp_places_list[gomp_places_list_len] = p;
+ }
+ else if (len == 1)
+ ++gomp_places_list_len;
+ else
+ {
+ for (count = 0; count < len - 1; count++)
+ if (!gomp_affinity_copy_place
+ (gomp_places_list[gomp_places_list_len + count + 1],
+ gomp_places_list[gomp_places_list_len + count],
+ stride))
+ goto invalid;
+ gomp_places_list_len += len;
+ }
+ if (*env == '\0')
+ break;
+ env++;
+ }
+ while (1);
+
+ if (gomp_places_list_len == 0)
+ {
+ gomp_error ("All places have been removed");
+ goto invalid;
+ }
+ if (!gomp_affinity_finalize_place_list (false))
+ goto invalid;
+ return true;
+
+ invalid:
+ free (gomp_places_list);
+ gomp_places_list = NULL;
+ gomp_places_list_len = 0;
+ gomp_error ("Invalid value for environment variable %s", name);
+ return false;
+}
+
/* Parse the OMP_STACKSIZE environment varible. Return true if one was
present and it was successfully parsed. */
@@ -480,84 +913,89 @@ parse_wait_policy (void)
static bool
parse_affinity (void)
{
- char *env, *end;
+ char *env, *end, *start;
+ int pass;
unsigned long cpu_beg, cpu_end, cpu_stride;
- unsigned short *cpus = NULL;
- size_t allocated = 0, used = 0, needed;
+ size_t count = 0, needed;
env = getenv ("GOMP_CPU_AFFINITY");
if (env == NULL)
return false;
- do
+ start = env;
+ for (pass = 0; pass < 2; pass++)
{
- while (*env == ' ' || *env == '\t')
- env++;
-
- cpu_beg = strtoul (env, &end, 0);
- cpu_end = cpu_beg;
- cpu_stride = 1;
- if (env == end || cpu_beg >= 65536)
- goto invalid;
-
- env = end;
- if (*env == '-')
+ env = start;
+ if (pass == 1)
{
- cpu_end = strtoul (++env, &end, 0);
- if (env == end || cpu_end >= 65536 || cpu_end < cpu_beg)
+ gomp_places_list_len = 0;
+ gomp_places_list = gomp_affinity_alloc (count, true);
+ if (gomp_places_list == NULL)
+ return false;
+ }
+ do
+ {
+ while (isspace ((unsigned char) *env))
+ ++env;
+
+ errno = 0;
+ cpu_beg = strtoul (env, &end, 0);
+ if (errno || cpu_beg >= 65536)
goto invalid;
+ cpu_end = cpu_beg;
+ cpu_stride = 1;
env = end;
- if (*env == ':')
+ if (*env == '-')
{
- cpu_stride = strtoul (++env, &end, 0);
- if (env == end || cpu_stride == 0 || cpu_stride >= 65536)
+ errno = 0;
+ cpu_end = strtoul (++env, &end, 0);
+ if (errno || cpu_end >= 65536 || cpu_end < cpu_beg)
goto invalid;
env = end;
- }
- }
+ if (*env == ':')
+ {
+ errno = 0;
+ cpu_stride = strtoul (++env, &end, 0);
+ if (errno || cpu_stride == 0 || cpu_stride >= 65536)
+ goto invalid;
- needed = (cpu_end - cpu_beg) / cpu_stride + 1;
- if (used + needed >= allocated)
- {
- unsigned short *new_cpus;
+ env = end;
+ }
+ }
- if (allocated < 64)
- allocated = 64;
- if (allocated > needed)
- allocated <<= 1;
+ needed = (cpu_end - cpu_beg) / cpu_stride + 1;
+ if (pass == 0)
+ count += needed;
else
- allocated += 2 * needed;
- new_cpus = realloc (cpus, allocated * sizeof (unsigned short));
- if (new_cpus == NULL)
{
- free (cpus);
- gomp_error ("not enough memory to store GOMP_CPU_AFFINITY list");
- return false;
+ while (needed--)
+ {
+ void *p = gomp_places_list[gomp_places_list_len];
+ gomp_affinity_init_place (p);
+ if (gomp_affinity_add_cpus (p, cpu_beg, 1, 0, true))
+ ++gomp_places_list_len;
+ cpu_beg += cpu_stride;
+ }
}
- cpus = new_cpus;
- }
+ while (isspace ((unsigned char) *env))
+ ++env;
- while (needed--)
- {
- cpus[used++] = cpu_beg;
- cpu_beg += cpu_stride;
+ if (*env == ',')
+ env++;
+ else if (*env == '\0')
+ break;
}
-
- while (*env == ' ' || *env == '\t')
- env++;
-
- if (*env == ',')
- env++;
- else if (*env == '\0')
- break;
+ while (1);
}
- while (1);
- gomp_cpu_affinity = cpus;
- gomp_cpu_affinity_len = used;
+ if (gomp_places_list_len == 0)
+ {
+ free (gomp_places_list);
+ gomp_places_list = NULL;
+ }
return true;
invalid:
@@ -565,12 +1003,160 @@ parse_affinity (void)
return false;
}
+
+static void
+handle_omp_display_env (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)
+ {
+ display = true;
+ 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 = '201307'\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);
+
+ fputs (" OMP_PROC_BIND = '", stderr);
+ switch (gomp_global_icv.bind_var)
+ {
+ case omp_proc_bind_false:
+ fputs ("FALSE", stderr);
+ break;
+ case omp_proc_bind_true:
+ fputs ("TRUE", stderr);
+ break;
+ case omp_proc_bind_master:
+ fputs ("MASTER", stderr);
+ break;
+ case omp_proc_bind_close:
+ fputs ("CLOSE", stderr);
+ break;
+ case omp_proc_bind_spread:
+ fputs ("SPREAD", stderr);
+ break;
+ }
+ for (i = 1; i < gomp_bind_var_list_len; i++)
+ switch (gomp_bind_var_list[i])
+ {
+ case omp_proc_bind_master:
+ fputs (",MASTER", stderr);
+ break;
+ case omp_proc_bind_close:
+ fputs (",CLOSE", stderr);
+ break;
+ case omp_proc_bind_spread:
+ fputs (",SPREAD", stderr);
+ break;
+ }
+ fputs ("'\n", stderr);
+ fputs (" OMP_PLACES = '", stderr);
+ for (i = 0; i < gomp_places_list_len; i++)
+ {
+ fputs ("{", stderr);
+ gomp_affinity_print_place (gomp_places_list[i]);
+ fputs (i + 1 == gomp_places_list_len ? "}" : "},", stderr);
+ }
+ fputs ("'\n", stderr);
+
+ 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 = '%u'\n",
+ gomp_global_icv.thread_limit_var);
+ fprintf (stderr, " OMP_MAX_ACTIVE_LEVELS = '%lu'\n",
+ gomp_max_active_levels_var);
+
+ fprintf (stderr, " OMP_CANCELLATION = '%s'\n",
+ gomp_cancel_var ? "TRUE" : "FALSE");
+ fprintf (stderr, " OMP_DEFAULT_DEVICE = '%d'\n",
+ gomp_global_icv.default_device_var);
+
+ if (verbose)
+ {
+ fputs (" GOMP_CPU_AFFINITY = ''\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)
{
- unsigned long stacksize;
+ unsigned long thread_limit_var, stacksize;
int wait_policy;
- bool bind_var = false;
/* Do a compile time check that mkomp_h.pl did good job. */
omp_check_defines ();
@@ -578,14 +1164,17 @@ initialize_env (void)
parse_schedule ();
parse_boolean ("OMP_DYNAMIC", &gomp_global_icv.dyn_var);
parse_boolean ("OMP_NESTED", &gomp_global_icv.nest_var);
- parse_boolean ("OMP_PROC_BIND", &bind_var);
+ parse_boolean ("OMP_CANCELLATION", &gomp_cancel_var);
+ parse_int ("OMP_DEFAULT_DEVICE", &gomp_global_icv.default_device_var, true);
parse_unsigned_long ("OMP_MAX_ACTIVE_LEVELS", &gomp_max_active_levels_var,
true);
- parse_unsigned_long ("OMP_THREAD_LIMIT", &gomp_thread_limit_var, false);
- if (gomp_thread_limit_var != ULONG_MAX)
- gomp_remaining_threads_count = gomp_thread_limit_var - 1;
+ if (parse_unsigned_long ("OMP_THREAD_LIMIT", &thread_limit_var, false))
+ {
+ gomp_global_icv.thread_limit_var
+ = thread_limit_var > INT_MAX ? UINT_MAX : thread_limit_var;
+ }
#ifndef HAVE_SYNC_BUILTINS
- gomp_mutex_init (&gomp_remaining_threads_lock);
+ gomp_mutex_init (&gomp_managed_threads_lock);
#endif
gomp_init_num_threads ();
gomp_available_cpus = gomp_global_icv.nthreads_var;
@@ -594,7 +1183,14 @@ initialize_env (void)
&gomp_nthreads_var_list,
&gomp_nthreads_var_list_len))
gomp_global_icv.nthreads_var = gomp_available_cpus;
- if (parse_affinity () || bind_var)
+ if (!parse_bind_var ("OMP_PROC_BIND",
+ &gomp_global_icv.bind_var,
+ &gomp_bind_var_list,
+ &gomp_bind_var_list_len))
+ gomp_global_icv.bind_var = omp_proc_bind_false;
+ if (parse_places_var ("OMP_PLACES")
+ || parse_affinity ()
+ || gomp_global_icv.bind_var)
gomp_init_affinity ();
wait_policy = parse_wait_policy ();
if (!parse_spincount ("GOMP_SPINCOUNT", &gomp_spin_count_var))
@@ -645,6 +1241,8 @@ initialize_env (void)
if (err != 0)
gomp_error ("Stack size change failed: %s", strerror (err));
}
+
+ handle_omp_display_env (stacksize, wait_policy);
}
@@ -728,7 +1326,8 @@ omp_get_max_threads (void)
int
omp_get_thread_limit (void)
{
- return gomp_thread_limit_var > INT_MAX ? INT_MAX : gomp_thread_limit_var;
+ struct gomp_task_icv *icv = gomp_icv (false);
+ return icv->thread_limit_var > INT_MAX ? INT_MAX : icv->thread_limit_var;
}
void
@@ -744,6 +1343,60 @@ omp_get_max_active_levels (void)
return gomp_max_active_levels_var;
}
+int
+omp_get_cancellation (void)
+{
+ return gomp_cancel_var;
+}
+
+omp_proc_bind_t
+omp_get_proc_bind (void)
+{
+ struct gomp_task_icv *icv = gomp_icv (false);
+ return icv->bind_var;
+}
+
+void
+omp_set_default_device (int device_num)
+{
+ struct gomp_task_icv *icv = gomp_icv (true);
+ icv->default_device_var = device_num >= 0 ? device_num : 0;
+}
+
+int
+omp_get_default_device (void)
+{
+ struct gomp_task_icv *icv = gomp_icv (false);
+ return icv->default_device_var;
+}
+
+int
+omp_get_num_devices (void)
+{
+ return gomp_get_num_devices ();
+}
+
+int
+omp_get_num_teams (void)
+{
+ /* Hardcoded to 1 on host, MIC, HSAIL? Maybe variable on PTX. */
+ return 1;
+}
+
+int
+omp_get_team_num (void)
+{
+ /* Hardcoded to 0 on host, MIC, HSAIL? Maybe variable on PTX. */
+ return 0;
+}
+
+int
+omp_is_initial_device (void)
+{
+ /* Hardcoded to 1 on host, should be 0 on MIC, HSAIL, PTX. */
+ return 1;
+}
+
ialias (omp_set_dynamic)
ialias (omp_set_nested)
ialias (omp_set_num_threads)
@@ -755,3 +1408,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 3a4a42a4c61..38b968a8d39 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/hashtab.h b/libgomp/hashtab.h
new file mode 100644
index 00000000000..7f1dad69524
--- /dev/null
+++ b/libgomp/hashtab.h
@@ -0,0 +1,443 @@
+/* An expandable hash tables datatype.
+ Copyright (C) 1999-2013
+ Free Software Foundation, Inc.
+ Contributed by Vladimir Makarov <vmakarov@cygnus.com>.
+
+This program 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 2 of the License, or
+(at your option) any later version.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* The hash table code copied from include/hashtab.[hc] and adjusted,
+ so that the hash table entries are in the flexible array at the end
+ of the control structure, no callbacks are used and the elements in the
+ table are of the hash_entry_type type.
+ Before including this file, define hash_entry_type type and
+ htab_alloc and htab_free functions. After including it, define
+ htab_hash and htab_eq inline functions. */
+
+/* This package implements basic hash table functionality. It is possible
+ to search for an entry, create an entry and destroy an entry.
+
+ Elements in the table are generic pointers.
+
+ The size of the table is not fixed; if the occupancy of the table
+ grows too high the hash table will be expanded.
+
+ The abstract data implementation is based on generalized Algorithm D
+ from Knuth's book "The art of computer programming". Hash table is
+ expanded by creation of new hash table and transferring elements from
+ the old table to the new table. */
+
+/* The type for a hash code. */
+typedef unsigned int hashval_t;
+
+static inline hashval_t htab_hash (hash_entry_type);
+static inline bool htab_eq (hash_entry_type, hash_entry_type);
+
+/* This macro defines reserved value for empty table entry. */
+
+#define HTAB_EMPTY_ENTRY ((hash_entry_type) 0)
+
+/* This macro defines reserved value for table entry which contained
+ a deleted element. */
+
+#define HTAB_DELETED_ENTRY ((hash_entry_type) 1)
+
+/* Hash tables are of the following type. The structure
+ (implementation) of this type is not needed for using the hash
+ tables. All work with hash table should be executed only through
+ functions mentioned below. The size of this structure is subject to
+ change. */
+
+struct htab {
+ /* Current size (in entries) of the hash table. */
+ size_t size;
+
+ /* Current number of elements including also deleted elements. */
+ size_t n_elements;
+
+ /* Current number of deleted elements in the table. */
+ size_t n_deleted;
+
+ /* Current size (in entries) of the hash table, as an index into the
+ table of primes. */
+ unsigned int size_prime_index;
+
+ /* Table itself. */
+ hash_entry_type entries[];
+};
+
+typedef struct htab *htab_t;
+
+/* An enum saying whether we insert into the hash table or not. */
+enum insert_option {NO_INSERT, INSERT};
+
+/* Table of primes and multiplicative inverses.
+
+ Note that these are not minimally reduced inverses. Unlike when generating
+ code to divide by a constant, we want to be able to use the same algorithm
+ all the time. All of these inverses (are implied to) have bit 32 set.
+
+ For the record, the function that computed the table is in
+ libiberty/hashtab.c. */
+
+struct prime_ent
+{
+ hashval_t prime;
+ hashval_t inv;
+ hashval_t inv_m2; /* inverse of prime-2 */
+ hashval_t shift;
+};
+
+static struct prime_ent const prime_tab[] = {
+ { 7, 0x24924925, 0x9999999b, 2 },
+ { 13, 0x3b13b13c, 0x745d1747, 3 },
+ { 31, 0x08421085, 0x1a7b9612, 4 },
+ { 61, 0x0c9714fc, 0x15b1e5f8, 5 },
+ { 127, 0x02040811, 0x0624dd30, 6 },
+ { 251, 0x05197f7e, 0x073260a5, 7 },
+ { 509, 0x01824366, 0x02864fc8, 8 },
+ { 1021, 0x00c0906d, 0x014191f7, 9 },
+ { 2039, 0x0121456f, 0x0161e69e, 10 },
+ { 4093, 0x00300902, 0x00501908, 11 },
+ { 8191, 0x00080041, 0x00180241, 12 },
+ { 16381, 0x000c0091, 0x00140191, 13 },
+ { 32749, 0x002605a5, 0x002a06e6, 14 },
+ { 65521, 0x000f00e2, 0x00110122, 15 },
+ { 131071, 0x00008001, 0x00018003, 16 },
+ { 262139, 0x00014002, 0x0001c004, 17 },
+ { 524287, 0x00002001, 0x00006001, 18 },
+ { 1048573, 0x00003001, 0x00005001, 19 },
+ { 2097143, 0x00004801, 0x00005801, 20 },
+ { 4194301, 0x00000c01, 0x00001401, 21 },
+ { 8388593, 0x00001e01, 0x00002201, 22 },
+ { 16777213, 0x00000301, 0x00000501, 23 },
+ { 33554393, 0x00001381, 0x00001481, 24 },
+ { 67108859, 0x00000141, 0x000001c1, 25 },
+ { 134217689, 0x000004e1, 0x00000521, 26 },
+ { 268435399, 0x00000391, 0x000003b1, 27 },
+ { 536870909, 0x00000019, 0x00000029, 28 },
+ { 1073741789, 0x0000008d, 0x00000095, 29 },
+ { 2147483647, 0x00000003, 0x00000007, 30 },
+ /* Avoid "decimal constant so large it is unsigned" for 4294967291. */
+ { 0xfffffffb, 0x00000006, 0x00000008, 31 }
+};
+
+/* The following function returns an index into the above table of the
+ nearest prime number which is greater than N, and near a power of two. */
+
+static unsigned int
+higher_prime_index (unsigned long n)
+{
+ unsigned int low = 0;
+ unsigned int high = sizeof(prime_tab) / sizeof(prime_tab[0]);
+
+ while (low != high)
+ {
+ unsigned int mid = low + (high - low) / 2;
+ if (n > prime_tab[mid].prime)
+ low = mid + 1;
+ else
+ high = mid;
+ }
+
+ /* If we've run out of primes, abort. */
+ if (n > prime_tab[low].prime)
+ abort ();
+
+ return low;
+}
+
+/* Return the current size of given hash table. */
+
+static inline size_t
+htab_size (htab_t htab)
+{
+ return htab->size;
+}
+
+/* Return the current number of elements in given hash table. */
+
+static inline size_t
+htab_elements (htab_t htab)
+{
+ return htab->n_elements - htab->n_deleted;
+}
+
+/* Return X % Y. */
+
+static inline hashval_t
+htab_mod_1 (hashval_t x, hashval_t y, hashval_t inv, int shift)
+{
+ /* The multiplicative inverses computed above are for 32-bit types, and
+ requires that we be able to compute a highpart multiply. */
+ if (sizeof (hashval_t) * __CHAR_BIT__ <= 32)
+ {
+ hashval_t t1, t2, t3, t4, q, r;
+
+ t1 = ((unsigned long long)x * inv) >> 32;
+ t2 = x - t1;
+ t3 = t2 >> 1;
+ t4 = t1 + t3;
+ q = t4 >> shift;
+ r = x - (q * y);
+
+ return r;
+ }
+
+ /* Otherwise just use the native division routines. */
+ return x % y;
+}
+
+/* Compute the primary hash for HASH given HTAB's current size. */
+
+static inline hashval_t
+htab_mod (hashval_t hash, htab_t htab)
+{
+ const struct prime_ent *p = &prime_tab[htab->size_prime_index];
+ return htab_mod_1 (hash, p->prime, p->inv, p->shift);
+}
+
+/* Compute the secondary hash for HASH given HTAB's current size. */
+
+static inline hashval_t
+htab_mod_m2 (hashval_t hash, htab_t htab)
+{
+ const struct prime_ent *p = &prime_tab[htab->size_prime_index];
+ return 1 + htab_mod_1 (hash, p->prime - 2, p->inv_m2, p->shift);
+}
+
+/* Create hash table of size SIZE. */
+
+static htab_t
+htab_create (size_t size)
+{
+ htab_t result;
+ unsigned int size_prime_index;
+
+ size_prime_index = higher_prime_index (size);
+ size = prime_tab[size_prime_index].prime;
+
+ result = (htab_t) htab_alloc (sizeof (struct htab)
+ + size * sizeof (hash_entry_type));
+ result->size = size;
+ result->n_elements = 0;
+ result->n_deleted = 0;
+ result->size_prime_index = size_prime_index;
+ memset (result->entries, 0, size * sizeof (hash_entry_type));
+ return result;
+}
+
+/* Similar to htab_find_slot, but without several unwanted side effects:
+ - Does not call htab_eq when it finds an existing entry.
+ - Does not change the count of elements in the hash table.
+ This function also assumes there are no deleted entries in the table.
+ HASH is the hash value for the element to be inserted. */
+
+static hash_entry_type *
+find_empty_slot_for_expand (htab_t htab, hashval_t hash)
+{
+ hashval_t index = htab_mod (hash, htab);
+ size_t size = htab_size (htab);
+ hash_entry_type *slot = htab->entries + index;
+ hashval_t hash2;
+
+ if (*slot == HTAB_EMPTY_ENTRY)
+ return slot;
+ else if (*slot == HTAB_DELETED_ENTRY)
+ abort ();
+
+ hash2 = htab_mod_m2 (hash, htab);
+ for (;;)
+ {
+ index += hash2;
+ if (index >= size)
+ index -= size;
+
+ slot = htab->entries + index;
+ if (*slot == HTAB_EMPTY_ENTRY)
+ return slot;
+ else if (*slot == HTAB_DELETED_ENTRY)
+ abort ();
+ }
+}
+
+/* The following function changes size of memory allocated for the
+ entries and repeatedly inserts the table elements. The occupancy
+ of the table after the call will be about 50%. Naturally the hash
+ table must already exist. Remember also that the place of the
+ table entries is changed. */
+
+static htab_t
+htab_expand (htab_t htab)
+{
+ htab_t nhtab;
+ hash_entry_type *olimit;
+ hash_entry_type *p;
+ size_t osize, elts;
+
+ osize = htab->size;
+ olimit = htab->entries + osize;
+ elts = htab_elements (htab);
+
+ /* Resize only when table after removal of unused elements is either
+ too full or too empty. */
+ if (elts * 2 > osize || (elts * 8 < osize && osize > 32))
+ nhtab = htab_create (elts * 2);
+ else
+ nhtab = htab_create (osize - 1);
+ nhtab->n_elements = htab->n_elements - htab->n_deleted;
+
+ p = htab->entries;
+ do
+ {
+ hash_entry_type x = *p;
+
+ if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY)
+ *find_empty_slot_for_expand (nhtab, htab_hash (x)) = x;
+
+ p++;
+ }
+ while (p < olimit);
+
+ htab_free (htab);
+ return nhtab;
+}
+
+/* This function searches for a hash table entry equal to the given
+ element. It cannot be used to insert or delete an element. */
+
+static hash_entry_type
+htab_find (htab_t htab, const hash_entry_type element)
+{
+ hashval_t index, hash2, hash = htab_hash (element);
+ size_t size;
+ hash_entry_type entry;
+
+ size = htab_size (htab);
+ index = htab_mod (hash, htab);
+
+ entry = htab->entries[index];
+ if (entry == HTAB_EMPTY_ENTRY
+ || (entry != HTAB_DELETED_ENTRY && htab_eq (entry, element)))
+ return entry;
+
+ hash2 = htab_mod_m2 (hash, htab);
+ for (;;)
+ {
+ index += hash2;
+ if (index >= size)
+ index -= size;
+
+ entry = htab->entries[index];
+ if (entry == HTAB_EMPTY_ENTRY
+ || (entry != HTAB_DELETED_ENTRY && htab_eq (entry, element)))
+ return entry;
+ }
+}
+
+/* This function searches for a hash table slot containing an entry
+ equal to the given element. To delete an entry, call this with
+ insert=NO_INSERT, then call htab_clear_slot on the slot returned
+ (possibly after doing some checks). To insert an entry, call this
+ with insert=INSERT, then write the value you want into the returned
+ slot. */
+
+static hash_entry_type *
+htab_find_slot (htab_t *htabp, const hash_entry_type element,
+ enum insert_option insert)
+{
+ hash_entry_type *first_deleted_slot;
+ hashval_t index, hash2, hash = htab_hash (element);
+ size_t size;
+ hash_entry_type entry;
+ htab_t htab = *htabp;
+
+ size = htab_size (htab);
+ if (insert == INSERT && size * 3 <= htab->n_elements * 4)
+ {
+ htab = *htabp = htab_expand (htab);
+ size = htab_size (htab);
+ }
+
+ index = htab_mod (hash, htab);
+
+ first_deleted_slot = NULL;
+
+ entry = htab->entries[index];
+ if (entry == HTAB_EMPTY_ENTRY)
+ goto empty_entry;
+ else if (entry == HTAB_DELETED_ENTRY)
+ first_deleted_slot = &htab->entries[index];
+ else if (htab_eq (entry, element))
+ return &htab->entries[index];
+
+ hash2 = htab_mod_m2 (hash, htab);
+ for (;;)
+ {
+ index += hash2;
+ if (index >= size)
+ index -= size;
+
+ entry = htab->entries[index];
+ if (entry == HTAB_EMPTY_ENTRY)
+ goto empty_entry;
+ else if (entry == HTAB_DELETED_ENTRY)
+ {
+ if (!first_deleted_slot)
+ first_deleted_slot = &htab->entries[index];
+ }
+ else if (htab_eq (entry, element))
+ return &htab->entries[index];
+ }
+
+ empty_entry:
+ if (insert == NO_INSERT)
+ return NULL;
+
+ if (first_deleted_slot)
+ {
+ htab->n_deleted--;
+ *first_deleted_slot = HTAB_EMPTY_ENTRY;
+ return first_deleted_slot;
+ }
+
+ htab->n_elements++;
+ return &htab->entries[index];
+}
+
+/* This function clears a specified slot in a hash table. It is
+ useful when you've already done the lookup and don't want to do it
+ again. */
+
+static inline void
+htab_clear_slot (htab_t htab, hash_entry_type *slot)
+{
+ if (slot < htab->entries || slot >= htab->entries + htab_size (htab)
+ || *slot == HTAB_EMPTY_ENTRY || *slot == HTAB_DELETED_ENTRY)
+ abort ();
+
+ *slot = HTAB_DELETED_ENTRY;
+ htab->n_deleted++;
+}
+
+/* Returns a hash code for pointer P. Simplified version of evahash */
+
+static inline hashval_t
+hash_pointer (const void *p)
+{
+ uintptr_t v = (uintptr_t) p;
+ if (sizeof (v) > sizeof (hashval_t))
+ v ^= v >> (sizeof (uintptr_t) / 2 * __CHAR_BIT__);
+ return v;
+}
diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h
index 322a43520ee..bdc0486ad12 100644
--- a/libgomp/libgomp.h
+++ b/libgomp/libgomp.h
@@ -39,6 +39,7 @@
#include <pthread.h>
#include <stdbool.h>
+#include <stdlib.h>
#ifdef HAVE_ATTRIBUTE_VISIBILITY
# pragma GCC visibility push(hidden)
@@ -201,6 +202,10 @@ struct gomp_team_state
/* Active nesting level. Only active parallel regions are counted. */
unsigned active_level;
+ /* Place-partition-var, offset and length into gomp_places_list array. */
+ unsigned place_partition_off;
+ unsigned place_partition_len;
+
#ifdef HAVE_SYNC_BUILTINS
/* Number of single stmts encountered. */
unsigned long single_count;
@@ -214,30 +219,40 @@ struct gomp_team_state
unsigned long static_trip;
};
-/* These are the OpenMP 3.0 Internal Control Variables described in
+struct target_mem_desc;
+
+/* These are the OpenMP 4.0 Internal Control Variables described in
section 2.3.1. Those described as having one copy per task are
stored within the structure; those described as having one copy
for the whole program are (naturally) global variables. */
-
+
struct gomp_task_icv
{
unsigned long nthreads_var;
enum gomp_schedule_type run_sched_var;
int run_sched_modifier;
+ int default_device_var;
+ unsigned int thread_limit_var;
bool dyn_var;
bool nest_var;
+ char bind_var;
+ /* Internal ICV. */
+ struct target_mem_desc *target_data;
};
extern struct gomp_task_icv gomp_global_icv;
-extern unsigned long gomp_thread_limit_var;
-extern unsigned long gomp_remaining_threads_count;
#ifndef HAVE_SYNC_BUILTINS
-extern gomp_mutex_t gomp_remaining_threads_lock;
+extern gomp_mutex_t gomp_managed_threads_lock;
#endif
extern unsigned long gomp_max_active_levels_var;
+extern bool gomp_cancel_var;
extern unsigned long long gomp_spin_count_var, gomp_throttled_spin_count_var;
extern unsigned long gomp_available_cpus, gomp_managed_threads;
extern unsigned long *gomp_nthreads_var_list, gomp_nthreads_var_list_len;
+extern char *gomp_bind_var_list;
+extern unsigned long gomp_bind_var_list_len;
+extern void **gomp_places_list;
+extern unsigned long gomp_places_list_len;
enum gomp_task_kind
{
@@ -247,6 +262,27 @@ enum gomp_task_kind
GOMP_TASK_TIED
};
+struct gomp_task;
+struct gomp_taskgroup;
+struct htab;
+
+struct gomp_task_depend_entry
+{
+ void *addr;
+ struct gomp_task_depend_entry *next;
+ struct gomp_task_depend_entry *prev;
+ struct gomp_task *task;
+ bool is_in;
+ bool redundant;
+};
+
+struct gomp_dependers_vec
+{
+ size_t n_elem;
+ size_t allocated;
+ struct gomp_task *elem[];
+};
+
/* This structure describes a "task" to be run by a thread. */
struct gomp_task
@@ -257,6 +293,13 @@ struct gomp_task
struct gomp_task *prev_child;
struct gomp_task *next_queue;
struct gomp_task *prev_queue;
+ struct gomp_task *next_taskgroup;
+ struct gomp_task *prev_taskgroup;
+ struct gomp_taskgroup *taskgroup;
+ struct gomp_dependers_vec *dependers;
+ struct htab *depend_hash;
+ size_t depend_count;
+ size_t num_dependees;
struct gomp_task_icv icv;
void (*fn) (void *);
void *fn_data;
@@ -264,7 +307,19 @@ struct gomp_task
bool in_taskwait;
bool in_tied_task;
bool final_task;
+ bool copy_ctors_done;
gomp_sem_t taskwait_sem;
+ struct gomp_task_depend_entry depend[];
+};
+
+struct gomp_taskgroup
+{
+ struct gomp_taskgroup *prev;
+ struct gomp_task *children;
+ bool in_taskgroup_wait;
+ bool cancelled;
+ gomp_sem_t taskgroup_sem;
+ size_t num_children;
};
/* This structure describes a "team" of threads. These are the threads
@@ -293,6 +348,12 @@ struct gomp_team
of the threads in the team. */
gomp_sem_t **ordered_release;
+ /* List of work shares on which gomp_fini_work_share hasn't been
+ called yet. If the team hasn't been cancelled, this should be
+ equal to each thr->ts.work_share, but otherwise it can be a possibly
+ long list of workshares. */
+ struct gomp_work_share *work_shares_to_free;
+
/* List of gomp_work_share structs chained through next_free fields.
This is populated and taken off only by the first thread in the
team encountering a new work sharing construct, in a critical
@@ -324,8 +385,20 @@ struct gomp_team
gomp_mutex_t task_lock;
struct gomp_task *task_queue;
- int task_count;
- int task_running_count;
+ /* Number of all GOMP_TASK_{WAITING,TIED} tasks in the team. */
+ unsigned int task_count;
+ /* Number of GOMP_TASK_WAITING tasks currently waiting to be scheduled. */
+ unsigned int task_queued_count;
+ /* Number of GOMP_TASK_{WAITING,TIED} tasks currently running
+ directly in gomp_barrier_handle_tasks; tasks spawned
+ from e.g. GOMP_taskwait or GOMP_taskgroup_end don't count, even when
+ that is called from a task run from gomp_barrier_handle_tasks.
+ task_running_count should be always <= team->nthreads,
+ and if current task isn't in_tied_task, then it will be
+ even < team->nthreads. */
+ unsigned int task_running_count;
+ int work_share_cancelled;
+ int team_cancelled;
/* This array contains structures for implicit tasks. */
struct gomp_task implicit_task[];
@@ -350,7 +423,11 @@ struct gomp_thread
/* This semaphore is used for ordered loops. */
gomp_sem_t release;
- /* user pthread thread pool */
+ /* Place this thread is bound to plus one, or zero if not bound
+ to any place. */
+ unsigned int place;
+
+ /* User pthread thread pool */
struct gomp_thread_pool *thread_pool;
};
@@ -363,11 +440,23 @@ struct gomp_thread_pool
unsigned threads_size;
unsigned threads_used;
struct gomp_team *last_team;
+ /* Number of threads running in this contention group. */
+ unsigned long threads_busy;
/* This barrier holds and releases threads waiting in threads. */
gomp_barrier_t threads_dock;
};
+enum gomp_cancel_kind
+{
+ GOMP_CANCEL_PARALLEL = 1,
+ GOMP_CANCEL_LOOP = 2,
+ GOMP_CANCEL_FOR = GOMP_CANCEL_LOOP,
+ GOMP_CANCEL_DO = GOMP_CANCEL_LOOP,
+ GOMP_CANCEL_SECTIONS = 4,
+ GOMP_CANCEL_TASKGROUP = 8
+};
+
/* ... and here is that TLS data. */
#ifdef HAVE_TLS
@@ -402,17 +491,22 @@ static inline struct gomp_task_icv *gomp_icv (bool write)
/* The attributes to be used during thread creation. */
extern pthread_attr_t gomp_thread_attr;
-/* Other variables. */
-
-extern unsigned short *gomp_cpu_affinity;
-extern size_t gomp_cpu_affinity_len;
-
/* Function prototypes. */
/* affinity.c */
extern void gomp_init_affinity (void);
-extern void gomp_init_thread_affinity (pthread_attr_t *);
+extern void gomp_init_thread_affinity (pthread_attr_t *, unsigned int);
+extern void **gomp_affinity_alloc (unsigned long, bool);
+extern void gomp_affinity_init_place (void *);
+extern bool gomp_affinity_add_cpus (void *, unsigned long, unsigned long,
+ long, bool);
+extern bool gomp_affinity_remove_cpu (void *, unsigned long);
+extern bool gomp_affinity_copy_place (void *, void *, long);
+extern bool gomp_affinity_same_place (void *, void *);
+extern bool gomp_affinity_finalize_place_list (bool);
+extern bool gomp_affinity_init_level (int, unsigned long, bool);
+extern void gomp_affinity_print_place (void *);
/* alloc.c */
@@ -486,6 +580,8 @@ extern void gomp_barrier_handle_tasks (gomp_barrier_state_t);
static void inline
gomp_finish_task (struct gomp_task *task)
{
+ if (__builtin_expect (task->depend_hash != NULL, 0))
+ free (task->depend_hash);
gomp_sem_destroy (&task->taskwait_sem);
}
@@ -493,8 +589,13 @@ gomp_finish_task (struct gomp_task *task)
extern struct gomp_team *gomp_new_team (unsigned);
extern void gomp_team_start (void (*) (void *), void *, unsigned,
- struct gomp_team *);
+ unsigned, struct gomp_team *);
extern void gomp_team_end (void);
+extern void gomp_free_thread (void *);
+
+/* target.c */
+
+extern int gomp_get_num_devices (void);
/* work.c */
@@ -502,6 +603,7 @@ extern void gomp_init_work_share (struct gomp_work_share *, bool, unsigned);
extern void gomp_fini_work_share (struct gomp_work_share *);
extern bool gomp_work_share_start (bool);
extern void gomp_work_share_end (void);
+extern bool gomp_work_share_end_cancel (void);
extern void gomp_work_share_end_nowait (void);
static inline void
@@ -580,11 +682,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 7b051f96aab..b102fd88357 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,25 @@ GOMP_3.0 {
global:
GOMP_taskyield;
} GOMP_2.0;
+
+GOMP_4.0 {
+ global:
+ GOMP_barrier_cancel;
+ GOMP_cancel;
+ GOMP_cancellation_point;
+ GOMP_loop_end_cancel;
+ GOMP_parallel_loop_dynamic;
+ GOMP_parallel_loop_guided;
+ GOMP_parallel_loop_runtime;
+ GOMP_parallel_loop_static;
+ GOMP_parallel_sections;
+ GOMP_parallel;
+ GOMP_sections_end_cancel;
+ GOMP_taskgroup_start;
+ GOMP_taskgroup_end;
+ GOMP_target;
+ GOMP_target_data;
+ GOMP_target_end_data;
+ GOMP_target_update;
+ GOMP_teams;
+} GOMP_3.0;
diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi
index 2985128f8ac..a6930cc318b 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 a31e3458c1b..32c4cf61421 100644
--- a/libgomp/libgomp_g.h
+++ b/libgomp/libgomp_g.h
@@ -33,6 +33,7 @@
/* barrier.c */
extern void GOMP_barrier (void);
+extern bool GOMP_barrier_cancel (void);
/* critical.c */
@@ -76,9 +77,22 @@ 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);
+extern bool GOMP_loop_end_cancel (void);
/* loop_ull.c */
@@ -157,13 +171,18 @@ 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 bool GOMP_cancel (int, bool);
+extern bool GOMP_cancellation_point (int);
/* task.c */
extern void GOMP_task (void (*) (void *), void *, void (*) (void *, void *),
- long, long, bool, unsigned);
+ long, long, bool, unsigned, void **);
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,8 +190,11 @@ 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);
+extern bool GOMP_sections_end_cancel (void);
/* single.c */
@@ -180,4 +202,15 @@ extern bool GOMP_single_start (void);
extern void *GOMP_single_copy_start (void);
extern void GOMP_single_copy_end (void *);
+/* target.c */
+
+extern void GOMP_target (int, void (*) (void *), const void *,
+ size_t, void **, size_t *, unsigned char *);
+extern void GOMP_target_data (int, const void *,
+ size_t, void **, size_t *, unsigned char *);
+extern void GOMP_target_end_data (void);
+extern void GOMP_target_update (int, const void *,
+ size_t, void **, size_t *, unsigned char *);
+extern void GOMP_teams (unsigned int, unsigned int);
+
#endif /* LIBGOMP_G_H */
diff --git a/libgomp/loop.c b/libgomp/loop.c
index 12c818b0110..f5b33a06658 100644
--- a/libgomp/loop.c
+++ b/libgomp/loop.c
@@ -439,14 +439,14 @@ static void
gomp_parallel_loop_start (void (*fn) (void *), void *data,
unsigned num_threads, long start, long end,
long incr, enum gomp_schedule_type sched,
- long chunk_size)
+ long chunk_size, unsigned int flags)
{
struct gomp_team *team;
num_threads = gomp_resolve_num_threads (num_threads, 0);
team = gomp_new_team (num_threads);
gomp_loop_init (&team->work_shares[0], start, end, incr, sched, chunk_size);
- gomp_team_start (fn, data, num_threads, team);
+ gomp_team_start (fn, data, num_threads, flags, team);
}
void
@@ -455,7 +455,7 @@ GOMP_parallel_loop_static_start (void (*fn) (void *), void *data,
long incr, long chunk_size)
{
gomp_parallel_loop_start (fn, data, num_threads, start, end, incr,
- GFS_STATIC, chunk_size);
+ GFS_STATIC, chunk_size, 0);
}
void
@@ -464,7 +464,7 @@ GOMP_parallel_loop_dynamic_start (void (*fn) (void *), void *data,
long incr, long chunk_size)
{
gomp_parallel_loop_start (fn, data, num_threads, start, end, incr,
- GFS_DYNAMIC, chunk_size);
+ GFS_DYNAMIC, chunk_size, 0);
}
void
@@ -473,7 +473,7 @@ GOMP_parallel_loop_guided_start (void (*fn) (void *), void *data,
long incr, long chunk_size)
{
gomp_parallel_loop_start (fn, data, num_threads, start, end, incr,
- GFS_GUIDED, chunk_size);
+ GFS_GUIDED, chunk_size, 0);
}
void
@@ -483,11 +483,59 @@ GOMP_parallel_loop_runtime_start (void (*fn) (void *), void *data,
{
struct gomp_task_icv *icv = gomp_icv (false);
gomp_parallel_loop_start (fn, data, num_threads, start, end, incr,
- icv->run_sched_var, icv->run_sched_modifier);
+ icv->run_sched_var, icv->run_sched_modifier, 0);
+}
+
+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)
+{
+ gomp_parallel_loop_start (fn, data, num_threads, start, end, incr,
+ GFS_STATIC, chunk_size, flags);
+ 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)
+{
+ gomp_parallel_loop_start (fn, data, num_threads, start, end, incr,
+ GFS_DYNAMIC, chunk_size, flags);
+ 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)
+{
+ gomp_parallel_loop_start (fn, data, num_threads, start, end, incr,
+ GFS_GUIDED, chunk_size, flags);
+ 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)
+{
+ 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,
+ flags);
+ 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 loop iterations are complete. The first two versions synchronize
all threads; the nowait version does not. */
void
@@ -496,6 +544,12 @@ GOMP_loop_end (void)
gomp_work_share_end ();
}
+bool
+GOMP_loop_end_cancel (void)
+{
+ return gomp_work_share_end_cancel ();
+}
+
void
GOMP_loop_end_nowait (void)
{
diff --git a/libgomp/omp.h.in b/libgomp/omp.h.in
index 5db440785db..4fc123669ec 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 c9bc5fd003a..3c6deb6bbd5 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 f188edcf661..804636df82f 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 45735119025..ccc0b6a6973 100644
--- a/libgomp/parallel.c
+++ b/libgomp/parallel.c
@@ -37,18 +37,19 @@
unsigned
gomp_resolve_num_threads (unsigned specified, unsigned count)
{
- struct gomp_thread *thread = gomp_thread();
+ struct gomp_thread *thr = gomp_thread ();
struct gomp_task_icv *icv;
unsigned threads_requested, max_num_threads, num_threads;
- unsigned long remaining;
+ unsigned long busy;
+ struct gomp_thread_pool *pool;
icv = gomp_icv (false);
if (specified == 1)
return 1;
- else if (thread->ts.active_level >= 1 && !icv->nest_var)
+ else if (thr->ts.active_level >= 1 && !icv->nest_var)
return 1;
- else if (thread->ts.active_level >= gomp_max_active_levels_var)
+ else if (thr->ts.active_level >= gomp_max_active_levels_var)
return 1;
/* If NUM_THREADS not specified, use nthreads_var. */
@@ -72,30 +73,46 @@ gomp_resolve_num_threads (unsigned specified, unsigned count)
max_num_threads = count;
}
- /* ULONG_MAX stands for infinity. */
- if (__builtin_expect (gomp_thread_limit_var == ULONG_MAX, 1)
+ /* UINT_MAX stands for infinity. */
+ if (__builtin_expect (icv->thread_limit_var == UINT_MAX, 1)
|| max_num_threads == 1)
return max_num_threads;
+ /* The threads_busy counter lives in thread_pool, if there
+ isn't a thread_pool yet, there must be just one thread
+ in the contention group. If thr->team is NULL, this isn't
+ nested parallel, so there is just one thread in the
+ contention group as well, no need to handle it atomically. */
+ pool = thr->thread_pool;
+ if (thr->ts.team == NULL)
+ {
+ num_threads = max_num_threads;
+ if (num_threads > icv->thread_limit_var)
+ num_threads = icv->thread_limit_var;
+ if (pool)
+ pool->threads_busy = num_threads;
+ return num_threads;
+ }
+
#ifdef HAVE_SYNC_BUILTINS
do
{
- remaining = gomp_remaining_threads_count;
+ busy = pool->threads_busy;
num_threads = max_num_threads;
- if (num_threads > remaining)
- num_threads = remaining + 1;
+ if (icv->thread_limit_var - busy + 1 < num_threads)
+ num_threads = icv->thread_limit_var - busy + 1;
}
- while (__sync_val_compare_and_swap (&gomp_remaining_threads_count,
- remaining, remaining - num_threads + 1)
- != remaining);
+ while (__sync_val_compare_and_swap (&pool->threads_busy,
+ busy, busy + num_threads - 1)
+ != busy);
#else
- gomp_mutex_lock (&gomp_remaining_threads_lock);
+ gomp_mutex_lock (&gomp_managed_threads_lock);
num_threads = max_num_threads;
- remaining = gomp_remaining_threads_count;
- if (num_threads > remaining)
- num_threads = remaining + 1;
- gomp_remaining_threads_count -= num_threads - 1;
- gomp_mutex_unlock (&gomp_remaining_threads_lock);
+ busy = pool->threads_busy;
+ if (icv->thread_limit_var - busy + 1 < num_threads)
+ num_threads = icv->thread_limit_var - busy + 1;
+ pool->threads_busy += num_threads - 1;
+ gomp_mutex_unlock (&gomp_managed_threads_lock);
#endif
return num_threads;
@@ -105,31 +122,113 @@ void
GOMP_parallel_start (void (*fn) (void *), void *data, unsigned num_threads)
{
num_threads = gomp_resolve_num_threads (num_threads, 0);
- gomp_team_start (fn, data, num_threads, gomp_new_team (num_threads));
+ gomp_team_start (fn, data, num_threads, 0, gomp_new_team (num_threads));
}
void
GOMP_parallel_end (void)
{
- if (__builtin_expect (gomp_thread_limit_var != ULONG_MAX, 0))
+ struct gomp_task_icv *icv = gomp_icv (false);
+ if (__builtin_expect (icv->thread_limit_var != UINT_MAX, 0))
{
struct gomp_thread *thr = gomp_thread ();
struct gomp_team *team = thr->ts.team;
- if (team && team->nthreads > 1)
+ unsigned int nthreads = team ? team->nthreads : 1;
+ gomp_team_end ();
+ if (nthreads > 1)
{
+ /* If not nested, there is just one thread in the
+ contention group left, no need for atomicity. */
+ if (thr->ts.team == NULL)
+ thr->thread_pool->threads_busy = 1;
+ else
+ {
#ifdef HAVE_SYNC_BUILTINS
- __sync_fetch_and_add (&gomp_remaining_threads_count,
- 1UL - team->nthreads);
+ __sync_fetch_and_add (&thr->thread_pool->threads_busy,
+ 1UL - nthreads);
#else
- gomp_mutex_lock (&gomp_remaining_threads_lock);
- gomp_remaining_threads_count -= team->nthreads - 1;
- gomp_mutex_unlock (&gomp_remaining_threads_lock);
+ gomp_mutex_lock (&gomp_managed_threads_lock);
+ thr->thread_pool->threads_busy -= nthreads - 1;
+ gomp_mutex_unlock (&gomp_managed_threads_lock);
#endif
+ }
}
}
- gomp_team_end ();
+ else
+ gomp_team_end ();
+}
+ialias (GOMP_parallel_end)
+
+void
+GOMP_parallel (void (*fn) (void *), void *data, unsigned num_threads, unsigned int flags)
+{
+ num_threads = gomp_resolve_num_threads (num_threads, 0);
+ gomp_team_start (fn, data, num_threads, flags, gomp_new_team (num_threads));
+ fn (data);
+ ialias_call (GOMP_parallel_end) ();
+}
+
+bool
+GOMP_cancellation_point (int which)
+{
+ if (!gomp_cancel_var)
+ return false;
+
+ struct gomp_thread *thr = gomp_thread ();
+ struct gomp_team *team = thr->ts.team;
+ if (which & (GOMP_CANCEL_LOOP | GOMP_CANCEL_SECTIONS))
+ {
+ if (team == NULL)
+ return false;
+ return team->work_share_cancelled != 0;
+ }
+ else if (which & GOMP_CANCEL_TASKGROUP)
+ {
+ if (thr->task->taskgroup && thr->task->taskgroup->cancelled)
+ return true;
+ /* FALLTHRU into the GOMP_CANCEL_PARALLEL case,
+ as #pragma omp cancel parallel also cancels all explicit
+ tasks. */
+ }
+ if (team)
+ return gomp_team_barrier_cancelled (&team->barrier);
+ return false;
}
+ialias (GOMP_cancellation_point)
+
+bool
+GOMP_cancel (int which, bool do_cancel)
+{
+ if (!gomp_cancel_var)
+ return false;
+
+ if (!do_cancel)
+ return ialias_call (GOMP_cancellation_point) (which);
+ struct gomp_thread *thr = gomp_thread ();
+ struct gomp_team *team = thr->ts.team;
+ if (which & (GOMP_CANCEL_LOOP | GOMP_CANCEL_SECTIONS))
+ {
+ /* In orphaned worksharing region, all we want to cancel
+ is current thread. */
+ if (team != NULL)
+ team->work_share_cancelled = 1;
+ return true;
+ }
+ else if (which & GOMP_CANCEL_TASKGROUP)
+ {
+ if (thr->task->taskgroup && !thr->task->taskgroup->cancelled)
+ {
+ gomp_mutex_lock (&team->task_lock);
+ thr->task->taskgroup->cancelled = true;
+ gomp_mutex_unlock (&team->task_lock);
+ }
+ return true;
+ }
+ team->team_cancelled = 1;
+ gomp_team_barrier_cancel (team);
+ return true;
+}
/* The public OpenMP API for thread and team related inquiries. */
diff --git a/libgomp/sections.c b/libgomp/sections.c
index 369f7a4426f..6fb117de0b1 100644
--- a/libgomp/sections.c
+++ b/libgomp/sections.c
@@ -139,11 +139,27 @@ GOMP_parallel_sections_start (void (*fn) (void *), void *data,
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);
+ gomp_team_start (fn, data, num_threads, 0, 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;
+
+ 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, flags, 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
+ that all sections are complete. The first two versions synchronize
all threads; the nowait version does not. */
void
@@ -152,6 +168,12 @@ GOMP_sections_end (void)
gomp_work_share_end ();
}
+bool
+GOMP_sections_end_cancel (void)
+{
+ return gomp_work_share_end_cancel ();
+}
+
void
GOMP_sections_end_nowait (void)
{
diff --git a/libgomp/target.c b/libgomp/target.c
new file mode 100644
index 00000000000..2e9865f2ae3
--- /dev/null
+++ b/libgomp/target.c
@@ -0,0 +1,96 @@
+/* Copyright (C) 2013 Free Software Foundation, Inc.
+ Contributed by Jakub Jelinek <jakub@redhat.com>.
+
+ This file is part of the GNU OpenMP Library (libgomp).
+
+ Libgomp is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This file handles the maintainence of threads in response to team
+ creation and termination. */
+
+#include "libgomp.h"
+#include <limits.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+attribute_hidden int
+gomp_get_num_devices (void)
+{
+ return 0;
+}
+
+/* Called when encountering a target directive. If DEVICE
+ is -1, it means use device-var ICV. If it is -2 (or any other value
+ larger than last available hw device, use host fallback.
+ FN is address of host code, OPENMP_TARGET contains value of the
+ __OPENMP_TARGET__ symbol in the shared library or binary that invokes
+ GOMP_target. HOSTADDRS, SIZES and KINDS are arrays
+ with MAPNUM entries, with addresses of the host objects,
+ sizes of the host objects (resp. for pointer kind pointer bias
+ and assumed sizeof (void *) size) and kinds. */
+
+void
+GOMP_target (int device, void (*fn) (void *), const void *openmp_target,
+ size_t mapnum, void **hostaddrs, size_t *sizes,
+ unsigned char *kinds)
+{
+ /* Host fallback. */
+ struct gomp_thread old_thr, *thr = gomp_thread ();
+ old_thr = *thr;
+ memset (thr, '\0', sizeof (*thr));
+ if (gomp_places_list)
+ {
+ thr->place = old_thr.place;
+ thr->ts.place_partition_len = gomp_places_list_len;
+ }
+ fn (hostaddrs);
+ gomp_free_thread (thr);
+ *thr = old_thr;
+}
+
+void
+GOMP_target_data (int device, const void *openmp_target, size_t mapnum,
+ void **hostaddrs, size_t *sizes, unsigned char *kinds)
+{
+}
+
+void
+GOMP_target_end_data (void)
+{
+}
+
+void
+GOMP_target_update (int device, const void *openmp_target, size_t mapnum,
+ void **hostaddrs, size_t *sizes, unsigned char *kinds)
+{
+}
+
+void
+GOMP_teams (unsigned int num_teams, unsigned int thread_limit)
+{
+ if (thread_limit)
+ {
+ struct gomp_task_icv *icv = gomp_icv (true);
+ icv->thread_limit_var
+ = thread_limit > INT_MAX ? UINT_MAX : thread_limit;
+ }
+ (void) num_teams;
+}
diff --git a/libgomp/task.c b/libgomp/task.c
index 7de650a43f1..a3d343fe126 100644
--- a/libgomp/task.c
+++ b/libgomp/task.c
@@ -29,6 +29,33 @@
#include <stdlib.h>
#include <string.h>
+typedef struct gomp_task_depend_entry *hash_entry_type;
+
+static inline void *
+htab_alloc (size_t size)
+{
+ return gomp_malloc (size);
+}
+
+static inline void
+htab_free (void *ptr)
+{
+ free (ptr);
+}
+
+#include "hashtab.h"
+
+static inline hashval_t
+htab_hash (hash_entry_type element)
+{
+ return hash_pointer (element->addr);
+}
+
+static inline bool
+htab_eq (hash_entry_type x, hash_entry_type y)
+{
+ return x->addr == y->addr;
+}
/* Create a new task data structure. */
@@ -42,7 +69,12 @@ gomp_init_task (struct gomp_task *task, struct gomp_task *parent_task,
task->in_taskwait = false;
task->in_tied_task = false;
task->final_task = false;
+ task->copy_ctors_done = false;
task->children = NULL;
+ task->taskgroup = NULL;
+ task->dependers = NULL;
+ task->depend_hash = NULL;
+ task->depend_count = 0;
gomp_sem_init (&task->taskwait_sem, 0);
}
@@ -78,7 +110,8 @@ gomp_clear_parent (struct gomp_task *children)
void
GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *),
- long arg_size, long arg_align, bool if_clause, unsigned flags)
+ long arg_size, long arg_align, bool if_clause, unsigned flags,
+ void **depend)
{
struct gomp_thread *thr = gomp_thread ();
struct gomp_team *team = thr->ts.team;
@@ -94,17 +127,58 @@ GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *),
flags &= ~1;
#endif
+ /* If parallel or taskgroup has been cancelled, don't start new tasks. */
+ if (team
+ && (gomp_team_barrier_cancelled (&team->barrier)
+ || (thr->task->taskgroup && thr->task->taskgroup->cancelled)))
+ return;
+
if (!if_clause || team == NULL
|| (thr->task && thr->task->final_task)
|| team->task_count > 64 * team->nthreads)
{
struct gomp_task task;
+ /* If there are depend clauses and earlier deferred sibling tasks
+ with depend clauses, check if there isn't a dependency. If there
+ is, fall through to the deferred task handling, as we can't
+ schedule such tasks right away. There is no need to handle
+ depend clauses for non-deferred tasks other than this, because
+ the parent task is suspended until the child task finishes and thus
+ it can't start further child tasks. */
+ if ((flags & 8) && thr->task && thr->task->depend_hash)
+ {
+ struct gomp_task *parent = thr->task;
+ struct gomp_task_depend_entry elem, *ent = NULL;
+ size_t ndepend = (uintptr_t) depend[0];
+ size_t nout = (uintptr_t) depend[1];
+ size_t i;
+ gomp_mutex_lock (&team->task_lock);
+ for (i = 0; i < ndepend; i++)
+ {
+ elem.addr = depend[i + 2];
+ ent = htab_find (parent->depend_hash, &elem);
+ for (; ent; ent = ent->next)
+ if (i >= nout && ent->is_in)
+ continue;
+ else
+ break;
+ if (ent)
+ break;
+ }
+ gomp_mutex_unlock (&team->task_lock);
+ if (ent)
+ goto defer;
+ }
+
gomp_init_task (&task, thr->task, gomp_icv (false));
task.kind = GOMP_TASK_IFFALSE;
task.final_task = (thr->task && thr->task->final_task) || (flags & 2);
if (thr->task)
- task.in_tied_task = thr->task->in_tied_task;
+ {
+ task.in_tied_task = thr->task->in_tied_task;
+ task.taskgroup = thr->task->taskgroup;
+ }
thr->task = &task;
if (__builtin_expect (cpyfn != NULL, 0))
{
@@ -135,29 +209,161 @@ GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *),
}
else
{
+ defer:;
struct gomp_task *task;
struct gomp_task *parent = thr->task;
+ struct gomp_taskgroup *taskgroup = parent->taskgroup;
char *arg;
bool do_wake;
-
- task = gomp_malloc (sizeof (*task) + arg_size + arg_align - 1);
- arg = (char *) (((uintptr_t) (task + 1) + arg_align - 1)
+ size_t depend_size = 0;
+
+ if (flags & 8)
+ depend_size = ((uintptr_t) depend[0]
+ * sizeof (struct gomp_task_depend_entry));
+ task = gomp_malloc (sizeof (*task) + depend_size
+ + arg_size + arg_align - 1);
+ arg = (char *) (((uintptr_t) (task + 1) + depend_size + arg_align - 1)
& ~(uintptr_t) (arg_align - 1));
gomp_init_task (task, parent, gomp_icv (false));
task->kind = GOMP_TASK_IFFALSE;
task->in_tied_task = parent->in_tied_task;
+ task->taskgroup = taskgroup;
thr->task = task;
if (cpyfn)
- cpyfn (arg, data);
+ {
+ cpyfn (arg, data);
+ task->copy_ctors_done = true;
+ }
else
memcpy (arg, data, arg_size);
thr->task = parent;
task->kind = GOMP_TASK_WAITING;
task->fn = fn;
task->fn_data = arg;
- task->in_tied_task = true;
task->final_task = (flags & 2) >> 1;
gomp_mutex_lock (&team->task_lock);
+ /* If parallel or taskgroup has been cancelled, don't start new
+ tasks. */
+ if (__builtin_expect ((gomp_team_barrier_cancelled (&team->barrier)
+ || (taskgroup && taskgroup->cancelled))
+ && !task->copy_ctors_done, 0))
+ {
+ gomp_mutex_unlock (&team->task_lock);
+ gomp_finish_task (task);
+ free (task);
+ return;
+ }
+ if (taskgroup)
+ taskgroup->num_children++;
+ if (depend_size)
+ {
+ size_t ndepend = (uintptr_t) depend[0];
+ size_t nout = (uintptr_t) depend[1];
+ size_t i;
+ hash_entry_type ent;
+
+ task->depend_count = ndepend;
+ task->num_dependees = 0;
+ if (parent->depend_hash == NULL)
+ parent->depend_hash
+ = htab_create (2 * ndepend > 12 ? 2 * ndepend : 12);
+ for (i = 0; i < ndepend; i++)
+ {
+ task->depend[i].addr = depend[2 + i];
+ task->depend[i].next = NULL;
+ task->depend[i].prev = NULL;
+ task->depend[i].task = task;
+ task->depend[i].is_in = i >= nout;
+ task->depend[i].redundant = false;
+
+ hash_entry_type *slot
+ = htab_find_slot (&parent->depend_hash, &task->depend[i],
+ INSERT);
+ hash_entry_type out = NULL;
+ if (*slot)
+ {
+ /* If multiple depends on the same task are the
+ same, all but the first one are redundant.
+ As inout/out come first, if any of them is
+ inout/out, it will win, which is the right
+ semantics. */
+ if ((*slot)->task == task)
+ {
+ task->depend[i].redundant = true;
+ continue;
+ }
+ for (ent = *slot; ent; ent = ent->next)
+ {
+ /* depend(in:...) doesn't depend on earlier
+ depend(in:...). */
+ if (i >= nout && ent->is_in)
+ continue;
+
+ if (!ent->is_in)
+ out = ent;
+
+ struct gomp_task *tsk = ent->task;
+ if (tsk->dependers == NULL)
+ {
+ tsk->dependers
+ = gomp_malloc (sizeof (struct gomp_dependers_vec)
+ + 6 * sizeof (struct gomp_task *));
+ tsk->dependers->n_elem = 1;
+ tsk->dependers->allocated = 6;
+ tsk->dependers->elem[0] = task;
+ task->num_dependees++;
+ continue;
+ }
+ /* We already have some other dependency on tsk
+ from earlier depend clause. */
+ else if (tsk->dependers->n_elem
+ && (tsk->dependers->elem[tsk->dependers->n_elem
+ - 1]
+ == task))
+ continue;
+ else if (tsk->dependers->n_elem
+ == tsk->dependers->allocated)
+ {
+ tsk->dependers->allocated
+ = tsk->dependers->allocated * 2 + 2;
+ tsk->dependers
+ = gomp_realloc (tsk->dependers,
+ sizeof (struct gomp_dependers_vec)
+ + (tsk->dependers->allocated
+ * sizeof (struct gomp_task *)));
+ }
+ tsk->dependers->elem[tsk->dependers->n_elem++] = task;
+ task->num_dependees++;
+ }
+ task->depend[i].next = *slot;
+ (*slot)->prev = &task->depend[i];
+ }
+ *slot = &task->depend[i];
+
+ /* There is no need to store more than one depend({,in}out:)
+ task per address in the hash table chain, because each out
+ depends on all earlier outs, thus it is enough to record
+ just the last depend({,in}out:). For depend(in:), we need
+ to keep all of the previous ones not terminated yet, because
+ a later depend({,in}out:) might need to depend on all of
+ them. So, if the new task's clause is depend({,in}out:),
+ we know there is at most one other depend({,in}out:) clause
+ in the list (out) and to maintain the invariant we now
+ need to remove it from the list. */
+ if (!task->depend[i].is_in && out)
+ {
+ if (out->next)
+ out->next->prev = out->prev;
+ out->prev->next = out->next;
+ out->redundant = true;
+ }
+ }
+ if (task->num_dependees)
+ {
+ gomp_mutex_unlock (&team->task_lock);
+ return;
+ }
+ }
if (parent->children)
{
task->next_child = parent->children;
@@ -171,6 +377,22 @@ GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *),
task->prev_child = task;
}
parent->children = task;
+ if (taskgroup)
+ {
+ if (taskgroup->children)
+ {
+ task->next_taskgroup = taskgroup->children;
+ task->prev_taskgroup = taskgroup->children->prev_taskgroup;
+ task->next_taskgroup->prev_taskgroup = task;
+ task->prev_taskgroup->next_taskgroup = task;
+ }
+ else
+ {
+ task->next_taskgroup = task;
+ task->prev_taskgroup = task;
+ }
+ taskgroup->children = task;
+ }
if (team->task_queue)
{
task->next_queue = team->task_queue;
@@ -185,6 +407,7 @@ GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *),
team->task_queue = task;
}
++team->task_count;
+ ++team->task_queued_count;
gomp_team_barrier_set_task_pending (&team->barrier);
do_wake = team->task_running_count + !parent->in_tied_task
< team->nthreads;
@@ -194,6 +417,220 @@ GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *),
}
}
+static inline bool
+gomp_task_run_pre (struct gomp_task *child_task, struct gomp_task *parent,
+ struct gomp_taskgroup *taskgroup, struct gomp_team *team)
+{
+ if (parent && parent->children == child_task)
+ parent->children = child_task->next_child;
+ if (taskgroup && taskgroup->children == child_task)
+ taskgroup->children = child_task->next_taskgroup;
+ child_task->prev_queue->next_queue = child_task->next_queue;
+ child_task->next_queue->prev_queue = child_task->prev_queue;
+ if (team->task_queue == child_task)
+ {
+ if (child_task->next_queue != child_task)
+ team->task_queue = child_task->next_queue;
+ else
+ team->task_queue = NULL;
+ }
+ child_task->kind = GOMP_TASK_TIED;
+ if (--team->task_queued_count == 0)
+ gomp_team_barrier_clear_task_pending (&team->barrier);
+ if ((gomp_team_barrier_cancelled (&team->barrier)
+ || (taskgroup && taskgroup->cancelled))
+ && !child_task->copy_ctors_done)
+ return true;
+ return false;
+}
+
+static void
+gomp_task_run_post_handle_depend_hash (struct gomp_task *child_task)
+{
+ struct gomp_task *parent = child_task->parent;
+ size_t i;
+
+ for (i = 0; i < child_task->depend_count; i++)
+ if (!child_task->depend[i].redundant)
+ {
+ if (child_task->depend[i].next)
+ child_task->depend[i].next->prev = child_task->depend[i].prev;
+ if (child_task->depend[i].prev)
+ child_task->depend[i].prev->next = child_task->depend[i].next;
+ else
+ {
+ hash_entry_type *slot
+ = htab_find_slot (&parent->depend_hash, &child_task->depend[i],
+ NO_INSERT);
+ if (*slot != &child_task->depend[i])
+ abort ();
+ if (child_task->depend[i].next)
+ *slot = child_task->depend[i].next;
+ else
+ htab_clear_slot (parent->depend_hash, slot);
+ }
+ }
+}
+
+static size_t
+gomp_task_run_post_handle_dependers (struct gomp_task *child_task,
+ struct gomp_team *team)
+{
+ struct gomp_task *parent = child_task->parent;
+ size_t i, count = child_task->dependers->n_elem, ret = 0;
+ for (i = 0; i < count; i++)
+ {
+ struct gomp_task *task = child_task->dependers->elem[i];
+ if (--task->num_dependees != 0)
+ continue;
+
+ struct gomp_taskgroup *taskgroup = task->taskgroup;
+ if (parent)
+ {
+ if (parent->children)
+ {
+ task->next_child = parent->children;
+ task->prev_child = parent->children->prev_child;
+ task->next_child->prev_child = task;
+ task->prev_child->next_child = task;
+ }
+ else
+ {
+ task->next_child = task;
+ task->prev_child = task;
+ }
+ parent->children = task;
+ if (parent->in_taskwait)
+ {
+ parent->in_taskwait = false;
+ gomp_sem_post (&parent->taskwait_sem);
+ }
+ }
+ if (taskgroup)
+ {
+ if (taskgroup->children)
+ {
+ task->next_taskgroup = taskgroup->children;
+ task->prev_taskgroup = taskgroup->children->prev_taskgroup;
+ task->next_taskgroup->prev_taskgroup = task;
+ task->prev_taskgroup->next_taskgroup = task;
+ }
+ else
+ {
+ task->next_taskgroup = task;
+ task->prev_taskgroup = task;
+ }
+ taskgroup->children = task;
+ if (taskgroup->in_taskgroup_wait)
+ {
+ taskgroup->in_taskgroup_wait = false;
+ gomp_sem_post (&taskgroup->taskgroup_sem);
+ }
+ }
+ if (team->task_queue)
+ {
+ task->next_queue = team->task_queue;
+ task->prev_queue = team->task_queue->prev_queue;
+ task->next_queue->prev_queue = task;
+ task->prev_queue->next_queue = task;
+ }
+ else
+ {
+ task->next_queue = task;
+ task->prev_queue = task;
+ team->task_queue = task;
+ }
+ ++team->task_count;
+ ++team->task_queued_count;
+ ++ret;
+ }
+ free (child_task->dependers);
+ child_task->dependers = NULL;
+ if (ret > 1)
+ gomp_team_barrier_set_task_pending (&team->barrier);
+ return ret;
+}
+
+static inline size_t
+gomp_task_run_post_handle_depend (struct gomp_task *child_task,
+ struct gomp_team *team)
+{
+ if (child_task->depend_count == 0)
+ return 0;
+
+ /* If parent is gone already, the hash table is freed and nothing
+ will use the hash table anymore, no need to remove anything from it. */
+ if (child_task->parent != NULL)
+ gomp_task_run_post_handle_depend_hash (child_task);
+
+ if (child_task->dependers == NULL)
+ return 0;
+
+ return gomp_task_run_post_handle_dependers (child_task, team);
+}
+
+static inline void
+gomp_task_run_post_remove_parent (struct gomp_task *child_task)
+{
+ struct gomp_task *parent = child_task->parent;
+ if (parent == NULL)
+ return;
+ child_task->prev_child->next_child = child_task->next_child;
+ child_task->next_child->prev_child = child_task->prev_child;
+ if (parent->children != child_task)
+ return;
+ if (child_task->next_child != child_task)
+ parent->children = child_task->next_child;
+ else
+ {
+ /* We access task->children in GOMP_taskwait
+ outside of the task lock mutex region, so
+ need a release barrier here to ensure memory
+ written by child_task->fn above is flushed
+ before the NULL is written. */
+ __atomic_store_n (&parent->children, NULL, MEMMODEL_RELEASE);
+ if (parent->in_taskwait)
+ {
+ parent->in_taskwait = false;
+ gomp_sem_post (&parent->taskwait_sem);
+ }
+ }
+}
+
+static inline void
+gomp_task_run_post_remove_taskgroup (struct gomp_task *child_task)
+{
+ struct gomp_taskgroup *taskgroup = child_task->taskgroup;
+ if (taskgroup == NULL)
+ return;
+ child_task->prev_taskgroup->next_taskgroup = child_task->next_taskgroup;
+ child_task->next_taskgroup->prev_taskgroup = child_task->prev_taskgroup;
+ if (taskgroup->num_children > 1)
+ --taskgroup->num_children;
+ else
+ {
+ /* We access taskgroup->num_children in GOMP_taskgroup_end
+ outside of the task lock mutex region, so
+ need a release barrier here to ensure memory
+ written by child_task->fn above is flushed
+ before the NULL is written. */
+ __atomic_store_n (&taskgroup->num_children, 0, MEMMODEL_RELEASE);
+ }
+ if (taskgroup->children != child_task)
+ return;
+ if (child_task->next_taskgroup != child_task)
+ taskgroup->children = child_task->next_taskgroup;
+ else
+ {
+ taskgroup->children = NULL;
+ if (taskgroup->in_taskgroup_wait)
+ {
+ taskgroup->in_taskgroup_wait = false;
+ gomp_sem_post (&taskgroup->taskgroup_sem);
+ }
+ }
+}
+
void
gomp_barrier_handle_tasks (gomp_barrier_state_t state)
{
@@ -202,6 +639,7 @@ gomp_barrier_handle_tasks (gomp_barrier_state_t state)
struct gomp_task *task = thr->task;
struct gomp_task *child_task = NULL;
struct gomp_task *to_free = NULL;
+ int do_wake = 0;
gomp_mutex_lock (&team->task_lock);
if (gomp_barrier_last_thread (state))
@@ -218,26 +656,31 @@ gomp_barrier_handle_tasks (gomp_barrier_state_t state)
while (1)
{
+ bool cancelled = false;
if (team->task_queue != NULL)
{
- struct gomp_task *parent;
-
child_task = team->task_queue;
- parent = child_task->parent;
- if (parent && parent->children == child_task)
- parent->children = child_task->next_child;
- child_task->prev_queue->next_queue = child_task->next_queue;
- child_task->next_queue->prev_queue = child_task->prev_queue;
- if (child_task->next_queue != child_task)
- team->task_queue = child_task->next_queue;
- else
- team->task_queue = NULL;
- child_task->kind = GOMP_TASK_TIED;
+ cancelled = gomp_task_run_pre (child_task, child_task->parent,
+ child_task->taskgroup, team);
+ if (__builtin_expect (cancelled, 0))
+ {
+ if (to_free)
+ {
+ gomp_finish_task (to_free);
+ free (to_free);
+ to_free = NULL;
+ }
+ goto finish_cancelled;
+ }
team->task_running_count++;
- if (team->task_count == team->task_running_count)
- gomp_team_barrier_clear_task_pending (&team->barrier);
+ child_task->in_tied_task = true;
}
gomp_mutex_unlock (&team->task_lock);
+ if (do_wake)
+ {
+ gomp_team_barrier_wake (&team->barrier, do_wake);
+ do_wake = 0;
+ }
if (to_free)
{
gomp_finish_task (to_free);
@@ -255,33 +698,22 @@ gomp_barrier_handle_tasks (gomp_barrier_state_t state)
gomp_mutex_lock (&team->task_lock);
if (child_task)
{
- struct gomp_task *parent = child_task->parent;
- if (parent)
- {
- child_task->prev_child->next_child = child_task->next_child;
- child_task->next_child->prev_child = child_task->prev_child;
- if (parent->children == child_task)
- {
- if (child_task->next_child != child_task)
- parent->children = child_task->next_child;
- else
- {
- /* We access task->children in GOMP_taskwait
- outside of the task lock mutex region, so
- need a release barrier here to ensure memory
- written by child_task->fn above is flushed
- before the NULL is written. */
- __atomic_store_n (&parent->children, NULL,
- MEMMODEL_RELEASE);
- if (parent->in_taskwait)
- gomp_sem_post (&parent->taskwait_sem);
- }
- }
- }
+ finish_cancelled:;
+ size_t new_tasks
+ = gomp_task_run_post_handle_depend (child_task, team);
+ gomp_task_run_post_remove_parent (child_task);
gomp_clear_parent (child_task->children);
+ gomp_task_run_post_remove_taskgroup (child_task);
to_free = child_task;
child_task = NULL;
- team->task_running_count--;
+ if (!cancelled)
+ team->task_running_count--;
+ if (new_tasks > 1)
+ {
+ do_wake = team->nthreads - team->task_running_count;
+ if (do_wake > new_tasks)
+ do_wake = new_tasks;
+ }
if (--team->task_count == 0
&& gomp_team_barrier_waiting_for_tasks (&team->barrier))
{
@@ -304,9 +736,10 @@ GOMP_taskwait (void)
struct gomp_task *task = thr->task;
struct gomp_task *child_task = NULL;
struct gomp_task *to_free = NULL;
+ int do_wake = 0;
/* The acquire barrier on load of task->children here synchronizes
- with the write of a NULL in gomp_barrier_handle_tasks. It is
+ with the write of a NULL in gomp_task_run_post_remove_parent. It is
not necessary that we synchronize with other non-NULL writes at
this point, but we must ensure that all writes to memory by a
child thread task work function are seen before we exit from
@@ -318,6 +751,7 @@ GOMP_taskwait (void)
gomp_mutex_lock (&team->task_lock);
while (1)
{
+ bool cancelled = false;
if (task->children == NULL)
{
gomp_mutex_unlock (&team->task_lock);
@@ -331,26 +765,30 @@ GOMP_taskwait (void)
if (task->children->kind == GOMP_TASK_WAITING)
{
child_task = task->children;
- task->children = child_task->next_child;
- child_task->prev_queue->next_queue = child_task->next_queue;
- child_task->next_queue->prev_queue = child_task->prev_queue;
- if (team->task_queue == child_task)
+ cancelled
+ = gomp_task_run_pre (child_task, task, child_task->taskgroup,
+ team);
+ if (__builtin_expect (cancelled, 0))
{
- if (child_task->next_queue != child_task)
- team->task_queue = child_task->next_queue;
- else
- team->task_queue = NULL;
+ if (to_free)
+ {
+ gomp_finish_task (to_free);
+ free (to_free);
+ to_free = NULL;
+ }
+ goto finish_cancelled;
}
- child_task->kind = GOMP_TASK_TIED;
- team->task_running_count++;
- if (team->task_count == team->task_running_count)
- gomp_team_barrier_clear_task_pending (&team->barrier);
}
else
/* All tasks we are waiting for are already running
in other threads. Wait for them. */
task->in_taskwait = true;
gomp_mutex_unlock (&team->task_lock);
+ if (do_wake)
+ {
+ gomp_team_barrier_wake (&team->barrier, do_wake);
+ do_wake = 0;
+ }
if (to_free)
{
gomp_finish_task (to_free);
@@ -364,14 +802,13 @@ GOMP_taskwait (void)
thr->task = task;
}
else
- {
- gomp_sem_wait (&task->taskwait_sem);
- task->in_taskwait = false;
- return;
- }
+ gomp_sem_wait (&task->taskwait_sem);
gomp_mutex_lock (&team->task_lock);
if (child_task)
{
+ finish_cancelled:;
+ size_t new_tasks
+ = gomp_task_run_post_handle_depend (child_task, team);
child_task->prev_child->next_child = child_task->next_child;
child_task->next_child->prev_child = child_task->prev_child;
if (task->children == child_task)
@@ -382,10 +819,17 @@ GOMP_taskwait (void)
task->children = NULL;
}
gomp_clear_parent (child_task->children);
+ gomp_task_run_post_remove_taskgroup (child_task);
to_free = child_task;
child_task = NULL;
team->task_count--;
- team->task_running_count--;
+ if (new_tasks > 1)
+ {
+ do_wake = team->nthreads - team->task_running_count
+ - !task->in_tied_task;
+ if (do_wake > new_tasks)
+ do_wake = new_tasks;
+ }
}
}
}
@@ -398,6 +842,153 @@ GOMP_taskyield (void)
/* Nothing at the moment. */
}
+void
+GOMP_taskgroup_start (void)
+{
+ struct gomp_thread *thr = gomp_thread ();
+ struct gomp_team *team = thr->ts.team;
+ struct gomp_task *task = thr->task;
+ struct gomp_taskgroup *taskgroup;
+
+ /* If team is NULL, all tasks are executed as
+ GOMP_TASK_IFFALSE tasks and thus all children tasks of
+ taskgroup and their descendant tasks will be finished
+ by the time GOMP_taskgroup_end is called. */
+ if (team == NULL)
+ return;
+ taskgroup = gomp_malloc (sizeof (struct gomp_taskgroup));
+ taskgroup->prev = task->taskgroup;
+ taskgroup->children = NULL;
+ taskgroup->in_taskgroup_wait = false;
+ taskgroup->cancelled = false;
+ taskgroup->num_children = 0;
+ gomp_sem_init (&taskgroup->taskgroup_sem, 0);
+ task->taskgroup = taskgroup;
+}
+
+void
+GOMP_taskgroup_end (void)
+{
+ struct gomp_thread *thr = gomp_thread ();
+ struct gomp_team *team = thr->ts.team;
+ struct gomp_task *task = thr->task;
+ struct gomp_taskgroup *taskgroup;
+ struct gomp_task *child_task = NULL;
+ struct gomp_task *to_free = NULL;
+ int do_wake = 0;
+
+ if (team == NULL)
+ return;
+ taskgroup = task->taskgroup;
+
+ /* The acquire barrier on load of taskgroup->num_children here
+ synchronizes with the write of 0 in gomp_task_run_post_remove_taskgroup.
+ It is not necessary that we synchronize with other non-0 writes at
+ this point, but we must ensure that all writes to memory by a
+ child thread task work function are seen before we exit from
+ GOMP_taskgroup_end. */
+ if (__atomic_load_n (&taskgroup->num_children, MEMMODEL_ACQUIRE) == 0)
+ goto finish;
+
+ gomp_mutex_lock (&team->task_lock);
+ while (1)
+ {
+ bool cancelled = false;
+ if (taskgroup->children == NULL)
+ {
+ if (taskgroup->num_children)
+ goto do_wait;
+ gomp_mutex_unlock (&team->task_lock);
+ if (to_free)
+ {
+ gomp_finish_task (to_free);
+ free (to_free);
+ }
+ goto finish;
+ }
+ if (taskgroup->children->kind == GOMP_TASK_WAITING)
+ {
+ child_task = taskgroup->children;
+ cancelled
+ = gomp_task_run_pre (child_task, child_task->parent, taskgroup,
+ team);
+ if (__builtin_expect (cancelled, 0))
+ {
+ if (to_free)
+ {
+ gomp_finish_task (to_free);
+ free (to_free);
+ to_free = NULL;
+ }
+ goto finish_cancelled;
+ }
+ }
+ else
+ {
+ do_wait:
+ /* All tasks we are waiting for are already running
+ in other threads. Wait for them. */
+ taskgroup->in_taskgroup_wait = true;
+ }
+ gomp_mutex_unlock (&team->task_lock);
+ if (do_wake)
+ {
+ gomp_team_barrier_wake (&team->barrier, do_wake);
+ do_wake = 0;
+ }
+ if (to_free)
+ {
+ gomp_finish_task (to_free);
+ free (to_free);
+ to_free = NULL;
+ }
+ if (child_task)
+ {
+ thr->task = child_task;
+ child_task->fn (child_task->fn_data);
+ thr->task = task;
+ }
+ else
+ gomp_sem_wait (&taskgroup->taskgroup_sem);
+ gomp_mutex_lock (&team->task_lock);
+ if (child_task)
+ {
+ finish_cancelled:;
+ size_t new_tasks
+ = gomp_task_run_post_handle_depend (child_task, team);
+ child_task->prev_taskgroup->next_taskgroup
+ = child_task->next_taskgroup;
+ child_task->next_taskgroup->prev_taskgroup
+ = child_task->prev_taskgroup;
+ --taskgroup->num_children;
+ if (taskgroup->children == child_task)
+ {
+ if (child_task->next_taskgroup != child_task)
+ taskgroup->children = child_task->next_taskgroup;
+ else
+ taskgroup->children = NULL;
+ }
+ gomp_task_run_post_remove_parent (child_task);
+ gomp_clear_parent (child_task->children);
+ to_free = child_task;
+ child_task = NULL;
+ team->task_count--;
+ if (new_tasks > 1)
+ {
+ do_wake = team->nthreads - team->task_running_count
+ - !task->in_tied_task;
+ if (do_wake > new_tasks)
+ do_wake = new_tasks;
+ }
+ }
+ }
+
+ finish:
+ task->taskgroup = taskgroup->prev;
+ gomp_sem_destroy (&taskgroup->taskgroup_sem);
+ free (taskgroup);
+}
+
int
omp_in_final (void)
{
diff --git a/libgomp/team.c b/libgomp/team.c
index 243aa9aa954..f4c47f7cba8 100644
--- a/libgomp/team.c
+++ b/libgomp/team.c
@@ -53,6 +53,7 @@ struct gomp_thread_start_data
struct gomp_team_state ts;
struct gomp_task *task;
struct gomp_thread_pool *thread_pool;
+ unsigned int place;
bool nested;
};
@@ -84,6 +85,7 @@ gomp_thread_start (void *xdata)
thr->thread_pool = data->thread_pool;
thr->ts = data->ts;
thr->task = data->task;
+ thr->place = data->place;
thr->ts.team->ordered_release[thr->ts.team_id] = &thr->release;
@@ -98,7 +100,7 @@ gomp_thread_start (void *xdata)
gomp_barrier_wait (&team->barrier);
local_fn (local_data);
- gomp_team_barrier_wait (&team->barrier);
+ gomp_team_barrier_wait_final (&team->barrier);
gomp_finish_task (task);
gomp_barrier_wait_last (&team->barrier);
}
@@ -113,7 +115,7 @@ gomp_thread_start (void *xdata)
struct gomp_task *task = thr->task;
local_fn (local_data);
- gomp_team_barrier_wait (&team->barrier);
+ gomp_team_barrier_wait_final (&team->barrier);
gomp_finish_task (task);
gomp_barrier_wait (&pool->threads_dock);
@@ -126,6 +128,8 @@ gomp_thread_start (void *xdata)
}
gomp_sem_destroy (&thr->release);
+ thr->thread_pool = NULL;
+ thr->task = NULL;
return NULL;
}
@@ -149,6 +153,7 @@ gomp_new_team (unsigned nthreads)
#else
gomp_mutex_init (&team->work_share_list_free_lock);
#endif
+ team->work_shares_to_free = &team->work_shares[0];
gomp_init_work_share (&team->work_shares[0], false, nthreads);
team->work_shares[0].next_alloc = NULL;
team->work_share_list_free = NULL;
@@ -167,7 +172,10 @@ gomp_new_team (unsigned nthreads)
gomp_mutex_init (&team->task_lock);
team->task_queue = NULL;
team->task_count = 0;
+ team->task_queued_count = 0;
team->task_running_count = 0;
+ team->work_share_cancelled = 0;
+ team->team_cancelled = 0;
return team;
}
@@ -199,16 +207,19 @@ static struct gomp_thread_pool *gomp_new_thread_pool (void)
static void
gomp_free_pool_helper (void *thread_pool)
{
+ struct gomp_thread *thr = gomp_thread ();
struct gomp_thread_pool *pool
= (struct gomp_thread_pool *) thread_pool;
gomp_barrier_wait_last (&pool->threads_dock);
- gomp_sem_destroy (&gomp_thread ()->release);
+ gomp_sem_destroy (&thr->release);
+ thr->thread_pool = NULL;
+ thr->task = NULL;
pthread_exit (NULL);
}
/* Free a thread pool and release its threads. */
-static void
+void
gomp_free_thread (void *arg __attribute__((unused)))
{
struct gomp_thread *thr = gomp_thread ();
@@ -236,9 +247,9 @@ gomp_free_thread (void *arg __attribute__((unused)))
__sync_fetch_and_add (&gomp_managed_threads,
1L - pool->threads_used);
#else
- gomp_mutex_lock (&gomp_remaining_threads_lock);
+ gomp_mutex_lock (&gomp_managed_threads_lock);
gomp_managed_threads -= pool->threads_used - 1L;
- gomp_mutex_unlock (&gomp_remaining_threads_lock);
+ gomp_mutex_unlock (&gomp_managed_threads_lock);
#endif
}
free (pool->threads);
@@ -259,7 +270,7 @@ gomp_free_thread (void *arg __attribute__((unused)))
void
gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
- struct gomp_team *team)
+ unsigned flags, struct gomp_team *team)
{
struct gomp_thread_start_data *start_data;
struct gomp_thread *thr, *nthr;
@@ -270,17 +281,24 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
unsigned i, n, old_threads_used = 0;
pthread_attr_t thread_attr, *attr;
unsigned long nthreads_var;
+ char bind, bind_var;
+ unsigned int s = 0, rest = 0, p = 0, k = 0;
+ unsigned int affinity_count = 0;
+ struct gomp_thread **affinity_thr = NULL;
thr = gomp_thread ();
nested = thr->ts.team != NULL;
if (__builtin_expect (thr->thread_pool == NULL, 0))
{
thr->thread_pool = gomp_new_thread_pool ();
+ thr->thread_pool->threads_busy = nthreads;
pthread_setspecific (gomp_thread_destructor, thr);
}
pool = thr->thread_pool;
task = thr->task;
icv = task ? &task->icv : &gomp_global_icv;
+ if (__builtin_expect (gomp_places_list != NULL, 0) && thr->place == 0)
+ gomp_init_affinity ();
/* Always save the previous state, even if this isn't a nested team.
In particular, we should save any work share state from an outer
@@ -303,14 +321,95 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
if (__builtin_expect (gomp_nthreads_var_list != NULL, 0)
&& thr->ts.level < gomp_nthreads_var_list_len)
nthreads_var = gomp_nthreads_var_list[thr->ts.level];
+ bind_var = icv->bind_var;
+ if (bind_var != omp_proc_bind_false && (flags & 7) != omp_proc_bind_false)
+ bind_var = flags & 7;
+ bind = bind_var;
+ if (__builtin_expect (gomp_bind_var_list != NULL, 0)
+ && thr->ts.level < gomp_bind_var_list_len)
+ bind_var = gomp_bind_var_list[thr->ts.level];
gomp_init_task (thr->task, task, icv);
team->implicit_task[0].icv.nthreads_var = nthreads_var;
+ team->implicit_task[0].icv.bind_var = bind_var;
if (nthreads == 1)
return;
i = 1;
+ if (__builtin_expect (gomp_places_list != NULL, 0))
+ {
+ if (bind == omp_proc_bind_false)
+ bind = omp_proc_bind_true;
+ /* Depending on chosen proc_bind model, set subpartition
+ for the master thread and initialize helper variables
+ P and optionally S, K and/or REST used by later place
+ computation for each additional thread. */
+ p = thr->place - 1;
+ switch (bind)
+ {
+ case omp_proc_bind_false:
+ bind = omp_proc_bind_true;
+ /* FALLTHRU */
+ case omp_proc_bind_true:
+ case omp_proc_bind_close:
+ if (nthreads > thr->ts.place_partition_len)
+ {
+ /* T > P. S threads will be placed in each place,
+ and the final REM threads placed one by one
+ into the already occupied places. */
+ s = nthreads / thr->ts.place_partition_len;
+ rest = nthreads % thr->ts.place_partition_len;
+ }
+ else
+ s = 1;
+ k = 1;
+ break;
+ case omp_proc_bind_master:
+ /* Each thread will be bound to master's place. */
+ break;
+ case omp_proc_bind_spread:
+ if (nthreads <= thr->ts.place_partition_len)
+ {
+ /* T <= P. Each subpartition will have in between s
+ and s+1 places (subpartitions starting at or
+ after rest will have s places, earlier s+1 places),
+ each thread will be bound to the first place in
+ its subpartition (except for the master thread
+ that can be bound to another place in its
+ subpartition). */
+ s = thr->ts.place_partition_len / nthreads;
+ rest = thr->ts.place_partition_len % nthreads;
+ rest = (s + 1) * rest + thr->ts.place_partition_off;
+ if (p < rest)
+ {
+ p -= (p - thr->ts.place_partition_off) % (s + 1);
+ thr->ts.place_partition_len = s + 1;
+ }
+ else
+ {
+ p -= (p - rest) % s;
+ thr->ts.place_partition_len = s;
+ }
+ thr->ts.place_partition_off = p;
+ }
+ else
+ {
+ /* T > P. Each subpartition will have just a single
+ place and we'll place between s and s+1
+ threads into each subpartition. */
+ s = nthreads / thr->ts.place_partition_len;
+ rest = nthreads % thr->ts.place_partition_len;
+ thr->ts.place_partition_off = p;
+ thr->ts.place_partition_len = 1;
+ k = 1;
+ }
+ break;
+ }
+ }
+ else
+ bind = omp_proc_bind_false;
+
/* We only allow the reuse of idle threads for non-nested PARALLEL
regions. This appears to be implied by the semantics of
threadprivate variables, but perhaps that's reading too much into
@@ -341,47 +440,244 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
team will exit. */
pool->threads_used = nthreads;
+ /* If necessary, expand the size of the gomp_threads array. It is
+ expected that changes in the number of threads are rare, thus we
+ make no effort to expand gomp_threads_size geometrically. */
+ if (nthreads >= pool->threads_size)
+ {
+ pool->threads_size = nthreads + 1;
+ pool->threads
+ = gomp_realloc (pool->threads,
+ pool->threads_size
+ * sizeof (struct gomp_thread_data *));
+ }
+
/* Release existing idle threads. */
for (; i < n; ++i)
{
- nthr = pool->threads[i];
+ unsigned int place_partition_off = thr->ts.place_partition_off;
+ unsigned int place_partition_len = thr->ts.place_partition_len;
+ unsigned int place = 0;
+ if (__builtin_expect (gomp_places_list != NULL, 0))
+ {
+ switch (bind)
+ {
+ case omp_proc_bind_true:
+ case omp_proc_bind_close:
+ if (k == s)
+ {
+ ++p;
+ if (p == (team->prev_ts.place_partition_off
+ + team->prev_ts.place_partition_len))
+ p = team->prev_ts.place_partition_off;
+ k = 1;
+ if (i == nthreads - rest)
+ s = 1;
+ }
+ else
+ ++k;
+ break;
+ case omp_proc_bind_master:
+ break;
+ case omp_proc_bind_spread:
+ if (k == 0)
+ {
+ /* T <= P. */
+ if (p < rest)
+ p += s + 1;
+ else
+ p += s;
+ if (p == (team->prev_ts.place_partition_off
+ + team->prev_ts.place_partition_len))
+ p = team->prev_ts.place_partition_off;
+ place_partition_off = p;
+ if (p < rest)
+ place_partition_len = s + 1;
+ else
+ place_partition_len = s;
+ }
+ else
+ {
+ /* T > P. */
+ if (k == s)
+ {
+ ++p;
+ if (p == (team->prev_ts.place_partition_off
+ + team->prev_ts.place_partition_len))
+ p = team->prev_ts.place_partition_off;
+ k = 1;
+ if (i == nthreads - rest)
+ s = 1;
+ }
+ else
+ ++k;
+ place_partition_off = p;
+ place_partition_len = 1;
+ }
+ break;
+ }
+ if (affinity_thr != NULL
+ || (bind != omp_proc_bind_true
+ && pool->threads[i]->place != p + 1)
+ || pool->threads[i]->place <= place_partition_off
+ || pool->threads[i]->place > (place_partition_off
+ + place_partition_len))
+ {
+ unsigned int l;
+ if (affinity_thr == NULL)
+ {
+ unsigned int j;
+
+ if (team->prev_ts.place_partition_len > 64)
+ affinity_thr
+ = gomp_malloc (team->prev_ts.place_partition_len
+ * sizeof (struct gomp_thread *));
+ else
+ affinity_thr
+ = gomp_alloca (team->prev_ts.place_partition_len
+ * sizeof (struct gomp_thread *));
+ memset (affinity_thr, '\0',
+ team->prev_ts.place_partition_len
+ * sizeof (struct gomp_thread *));
+ for (j = i; j < old_threads_used; j++)
+ {
+ if (pool->threads[j]->place
+ > team->prev_ts.place_partition_off
+ && (pool->threads[j]->place
+ <= (team->prev_ts.place_partition_off
+ + team->prev_ts.place_partition_len)))
+ {
+ l = pool->threads[j]->place - 1
+ - team->prev_ts.place_partition_off;
+ pool->threads[j]->data = affinity_thr[l];
+ affinity_thr[l] = pool->threads[j];
+ }
+ pool->threads[j] = NULL;
+ }
+ if (nthreads > old_threads_used)
+ memset (&pool->threads[old_threads_used],
+ '\0', ((nthreads - old_threads_used)
+ * sizeof (struct gomp_thread *)));
+ n = nthreads;
+ affinity_count = old_threads_used - i;
+ }
+ if (affinity_count == 0)
+ break;
+ l = p;
+ if (affinity_thr[l - team->prev_ts.place_partition_off]
+ == NULL)
+ {
+ if (bind != omp_proc_bind_true)
+ continue;
+ for (l = place_partition_off;
+ l < place_partition_off + place_partition_len;
+ l++)
+ if (affinity_thr[l - team->prev_ts.place_partition_off]
+ != NULL)
+ break;
+ if (l == place_partition_off + place_partition_len)
+ continue;
+ }
+ nthr = affinity_thr[l - team->prev_ts.place_partition_off];
+ affinity_thr[l - team->prev_ts.place_partition_off]
+ = (struct gomp_thread *) nthr->data;
+ affinity_count--;
+ pool->threads[i] = nthr;
+ }
+ else
+ nthr = pool->threads[i];
+ place = p + 1;
+ }
+ else
+ nthr = pool->threads[i];
nthr->ts.team = team;
nthr->ts.work_share = &team->work_shares[0];
nthr->ts.last_work_share = NULL;
nthr->ts.team_id = i;
nthr->ts.level = team->prev_ts.level + 1;
nthr->ts.active_level = thr->ts.active_level;
+ nthr->ts.place_partition_off = place_partition_off;
+ nthr->ts.place_partition_len = place_partition_len;
#ifdef HAVE_SYNC_BUILTINS
nthr->ts.single_count = 0;
#endif
nthr->ts.static_trip = 0;
nthr->task = &team->implicit_task[i];
+ nthr->place = place;
gomp_init_task (nthr->task, task, icv);
team->implicit_task[i].icv.nthreads_var = nthreads_var;
+ team->implicit_task[i].icv.bind_var = bind_var;
nthr->fn = fn;
nthr->data = data;
team->ordered_release[i] = &nthr->release;
}
+ if (__builtin_expect (affinity_thr != NULL, 0))
+ {
+ /* If AFFINITY_THR is non-NULL just because we had to
+ permute some threads in the pool, but we've managed
+ to find exactly as many old threads as we'd find
+ without affinity, we don't need to handle this
+ specially anymore. */
+ if (nthreads <= old_threads_used
+ ? (affinity_count == old_threads_used - nthreads)
+ : (i == old_threads_used))
+ {
+ if (team->prev_ts.place_partition_len > 64)
+ free (affinity_thr);
+ affinity_thr = NULL;
+ affinity_count = 0;
+ }
+ else
+ {
+ i = 1;
+ /* We are going to compute the places/subpartitions
+ again from the beginning. So, we need to reinitialize
+ vars modified by the switch (bind) above inside
+ of the loop, to the state they had after the initial
+ switch (bind). */
+ switch (bind)
+ {
+ case omp_proc_bind_true:
+ case omp_proc_bind_close:
+ if (nthreads > thr->ts.place_partition_len)
+ /* T > P. S has been changed, so needs
+ to be recomputed. */
+ s = nthreads / thr->ts.place_partition_len;
+ k = 1;
+ p = thr->place - 1;
+ break;
+ case omp_proc_bind_master:
+ /* No vars have been changed. */
+ break;
+ case omp_proc_bind_spread:
+ p = thr->ts.place_partition_off;
+ if (k != 0)
+ {
+ /* T > P. */
+ s = nthreads / team->prev_ts.place_partition_len;
+ k = 1;
+ }
+ break;
+ }
+
+ /* Increase the barrier threshold to make sure all new
+ threads and all the threads we're going to let die
+ arrive before the team is released. */
+ if (affinity_count)
+ gomp_barrier_reinit (&pool->threads_dock,
+ nthreads + affinity_count);
+ }
+ }
+
if (i == nthreads)
goto do_release;
- /* If necessary, expand the size of the gomp_threads array. It is
- expected that changes in the number of threads are rare, thus we
- make no effort to expand gomp_threads_size geometrically. */
- if (nthreads >= pool->threads_size)
- {
- pool->threads_size = nthreads + 1;
- pool->threads
- = gomp_realloc (pool->threads,
- pool->threads_size
- * sizeof (struct gomp_thread_data *));
- }
}
- if (__builtin_expect (nthreads > old_threads_used, 0))
+ if (__builtin_expect (nthreads + affinity_count > old_threads_used, 0))
{
- long diff = (long) nthreads - (long) old_threads_used;
+ long diff = (long) (nthreads + affinity_count) - (long) old_threads_used;
if (old_threads_used == 0)
--diff;
@@ -389,14 +685,14 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
#ifdef HAVE_SYNC_BUILTINS
__sync_fetch_and_add (&gomp_managed_threads, diff);
#else
- gomp_mutex_lock (&gomp_remaining_threads_lock);
+ gomp_mutex_lock (&gomp_managed_threads_lock);
gomp_managed_threads += diff;
- gomp_mutex_unlock (&gomp_remaining_threads_lock);
+ gomp_mutex_unlock (&gomp_managed_threads_lock);
#endif
}
attr = &gomp_thread_attr;
- if (__builtin_expect (gomp_cpu_affinity != NULL, 0))
+ if (__builtin_expect (gomp_places_list != NULL, 0))
{
size_t stacksize;
pthread_attr_init (&thread_attr);
@@ -410,11 +706,78 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
* (nthreads-i));
/* Launch new threads. */
- for (; i < nthreads; ++i, ++start_data)
+ for (; i < nthreads; ++i)
{
pthread_t pt;
int err;
+ start_data->ts.place_partition_off = thr->ts.place_partition_off;
+ start_data->ts.place_partition_len = thr->ts.place_partition_len;
+ start_data->place = 0;
+ if (__builtin_expect (gomp_places_list != NULL, 0))
+ {
+ switch (bind)
+ {
+ case omp_proc_bind_true:
+ case omp_proc_bind_close:
+ if (k == s)
+ {
+ ++p;
+ if (p == (team->prev_ts.place_partition_off
+ + team->prev_ts.place_partition_len))
+ p = team->prev_ts.place_partition_off;
+ k = 1;
+ if (i == nthreads - rest)
+ s = 1;
+ }
+ else
+ ++k;
+ break;
+ case omp_proc_bind_master:
+ break;
+ case omp_proc_bind_spread:
+ if (k == 0)
+ {
+ /* T <= P. */
+ if (p < rest)
+ p += s + 1;
+ else
+ p += s;
+ if (p == (team->prev_ts.place_partition_off
+ + team->prev_ts.place_partition_len))
+ p = team->prev_ts.place_partition_off;
+ start_data->ts.place_partition_off = p;
+ if (p < rest)
+ start_data->ts.place_partition_len = s + 1;
+ else
+ start_data->ts.place_partition_len = s;
+ }
+ else
+ {
+ /* T > P. */
+ if (k == s)
+ {
+ ++p;
+ if (p == (team->prev_ts.place_partition_off
+ + team->prev_ts.place_partition_len))
+ p = team->prev_ts.place_partition_off;
+ k = 1;
+ if (i == nthreads - rest)
+ s = 1;
+ }
+ else
+ ++k;
+ start_data->ts.place_partition_off = p;
+ start_data->ts.place_partition_len = 1;
+ }
+ break;
+ }
+ start_data->place = p + 1;
+ if (affinity_thr != NULL && pool->threads[i] != NULL)
+ continue;
+ gomp_init_thread_affinity (attr, p);
+ }
+
start_data->fn = fn;
start_data->fn_data = data;
start_data->ts.team = team;
@@ -430,18 +793,16 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
start_data->task = &team->implicit_task[i];
gomp_init_task (start_data->task, task, icv);
team->implicit_task[i].icv.nthreads_var = nthreads_var;
+ team->implicit_task[i].icv.bind_var = bind_var;
start_data->thread_pool = pool;
start_data->nested = nested;
- if (gomp_cpu_affinity != NULL)
- gomp_init_thread_affinity (attr);
-
- err = pthread_create (&pt, attr, gomp_thread_start, start_data);
+ err = pthread_create (&pt, attr, gomp_thread_start, start_data++);
if (err != 0)
gomp_fatal ("Thread creation failed: %s", strerror (err));
}
- if (__builtin_expect (gomp_cpu_affinity != NULL, 0))
+ if (__builtin_expect (gomp_places_list != NULL, 0))
pthread_attr_destroy (&thread_attr);
do_release:
@@ -450,21 +811,32 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
/* Decrease the barrier threshold to match the number of threads
that should arrive back at the end of this team. The extra
threads should be exiting. Note that we arrange for this test
- to never be true for nested teams. */
- if (__builtin_expect (nthreads < old_threads_used, 0))
+ to never be true for nested teams. If AFFINITY_COUNT is non-zero,
+ the barrier as well as gomp_managed_threads was temporarily
+ set to NTHREADS + AFFINITY_COUNT. For NTHREADS < OLD_THREADS_COUNT,
+ AFFINITY_COUNT if non-zero will be always at least
+ OLD_THREADS_COUNT - NTHREADS. */
+ if (__builtin_expect (nthreads < old_threads_used, 0)
+ || __builtin_expect (affinity_count, 0))
{
long diff = (long) nthreads - (long) old_threads_used;
+ if (affinity_count)
+ diff = -affinity_count;
+
gomp_barrier_reinit (&pool->threads_dock, nthreads);
#ifdef HAVE_SYNC_BUILTINS
__sync_fetch_and_add (&gomp_managed_threads, diff);
#else
- gomp_mutex_lock (&gomp_remaining_threads_lock);
+ gomp_mutex_lock (&gomp_managed_threads_lock);
gomp_managed_threads += diff;
- gomp_mutex_unlock (&gomp_remaining_threads_lock);
+ gomp_mutex_unlock (&gomp_managed_threads_lock);
#endif
}
+ if (__builtin_expect (affinity_thr != NULL, 0)
+ && team->prev_ts.place_partition_len > 64)
+ free (affinity_thr);
}
@@ -477,9 +849,26 @@ gomp_team_end (void)
struct gomp_thread *thr = gomp_thread ();
struct gomp_team *team = thr->ts.team;
- /* This barrier handles all pending explicit threads. */
- gomp_team_barrier_wait (&team->barrier);
- gomp_fini_work_share (thr->ts.work_share);
+ /* This barrier handles all pending explicit threads.
+ As #pragma omp cancel parallel might get awaited count in
+ team->barrier in a inconsistent state, we need to use a different
+ counter here. */
+ gomp_team_barrier_wait_final (&team->barrier);
+ if (__builtin_expect (team->team_cancelled, 0))
+ {
+ struct gomp_work_share *ws = team->work_shares_to_free;
+ do
+ {
+ struct gomp_work_share *next_ws = gomp_ptrlock_get (&ws->next_ws);
+ if (next_ws == NULL)
+ gomp_ptrlock_set (&ws->next_ws, ws);
+ gomp_fini_work_share (ws);
+ ws = next_ws;
+ }
+ while (ws != NULL);
+ }
+ else
+ gomp_fini_work_share (thr->ts.work_share);
gomp_end_task ();
thr->ts = team->prev_ts;
@@ -489,9 +878,9 @@ gomp_team_end (void)
#ifdef HAVE_SYNC_BUILTINS
__sync_fetch_and_add (&gomp_managed_threads, 1L - team->nthreads);
#else
- gomp_mutex_lock (&gomp_remaining_threads_lock);
+ gomp_mutex_lock (&gomp_managed_threads_lock);
gomp_managed_threads -= team->nthreads - 1L;
- gomp_mutex_unlock (&gomp_remaining_threads_lock);
+ gomp_mutex_unlock (&gomp_managed_threads_lock);
#endif
/* This barrier has gomp_barrier_wait_last counterparts
and ensures the team can be safely destroyed. */
@@ -532,8 +921,6 @@ gomp_team_end (void)
static void __attribute__((constructor))
initialize_team (void)
{
- struct gomp_thread *thr;
-
#ifndef HAVE_TLS
static struct gomp_thread initial_thread_tls_data;
@@ -543,13 +930,6 @@ initialize_team (void)
if (pthread_key_create (&gomp_thread_destructor, gomp_free_thread) != 0)
gomp_fatal ("could not create thread pool destructor.");
-
-#ifdef HAVE_TLS
- thr = &gomp_tls_data;
-#else
- thr = &initial_thread_tls_data;
-#endif
- gomp_sem_init (&thr->release, 0);
}
static void __attribute__((destructor))
diff --git a/libgomp/testsuite/libgomp.c++/affinity-1.C b/libgomp/testsuite/libgomp.c++/affinity-1.C
new file mode 100644
index 00000000000..d20b392baf6
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/affinity-1.C
@@ -0,0 +1,4 @@
+// { dg-do run }
+// { dg-set-target-env-var OMP_PROC_BIND "true" }
+
+#include "../libgomp.c/affinity-1.c"
diff --git a/libgomp/testsuite/libgomp.c++/atomic-10.C b/libgomp/testsuite/libgomp.c++/atomic-10.C
new file mode 100644
index 00000000000..2145f288233
--- /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 00000000000..c7101e01408
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/atomic-11.C
@@ -0,0 +1,108 @@
+// { dg-do run }
+
+extern "C" void abort (void);
+
+template <typename T>
+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 <int> ();
+ 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 00000000000..d1ae9d8c88c
--- /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 00000000000..0569d1c6deb
--- /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 <typename T>
+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 <int> ();
+ 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 00000000000..4cd9df812d3
--- /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 update seq_cst
+ x = 3 * 2 * 1 + x;
+ #pragma omp atomic read seq_cst
+ v = x;
+ if (v != 9)
+ abort ();
+ #pragma omp atomic capture seq_cst
+ 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 capture seq_cst
+ 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 read seq_cst
+ v = x;
+ if (v != 6)
+ abort ();
+ #pragma omp atomic capture seq_cst
+ { v = x; x = 3 + x; }
+ if (v != 6)
+ abort ();
+ #pragma omp atomic capture seq_cst
+ { 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 capture seq_cst
+ { 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 read seq_cst
+ 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 capture seq_cst
+ { 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 00000000000..1eabce7dbd3
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/atomic-15.C
@@ -0,0 +1,108 @@
+// { dg-do run }
+
+extern "C" void abort (void);
+
+template <typename T>
+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 update seq_cst
+ x = 3 * 2 * 1 + x;
+ #pragma omp atomic read seq_cst
+ v = x;
+ if (v != 9)
+ abort ();
+ #pragma omp atomic capture seq_cst
+ 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 capture seq_cst
+ 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 read seq_cst
+ v = x;
+ if (v != 6)
+ abort ();
+ #pragma omp atomic capture seq_cst
+ { v = x; x = 3 + x; }
+ if (v != 6)
+ abort ();
+ #pragma omp atomic capture seq_cst
+ { 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 capture seq_cst
+ { 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 read seq_cst
+ 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 capture seq_cst
+ { 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 <int> ();
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c++/cancel-for-1.C b/libgomp/testsuite/libgomp.c++/cancel-for-1.C
new file mode 100644
index 00000000000..8183a2d06a1
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/cancel-for-1.C
@@ -0,0 +1,29 @@
+// { dg-do run }
+// { dg-set-target-env-var OMP_CANCELLATION "true" }
+
+#include <omp.h>
+#include "cancel-test.h"
+
+int
+main ()
+{
+ {
+ S c;
+ #pragma omp parallel num_threads (32)
+ {
+ S a, b;
+ int i;
+ #pragma omp for private (b) firstprivate (c)
+ for (i = 0; i < 1000; ++i)
+ {
+ S d;
+ #pragma omp cancel for
+ if (omp_get_cancellation ())
+ abort ();
+ b.bump ();
+ c.bump ();
+ }
+ }
+ }
+ S::verify ();
+}
diff --git a/libgomp/testsuite/libgomp.c++/cancel-for-2.C b/libgomp/testsuite/libgomp.c++/cancel-for-2.C
new file mode 100644
index 00000000000..1595a239cd0
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/cancel-for-2.C
@@ -0,0 +1,126 @@
+// { dg-do run }
+// { dg-set-target-env-var OMP_CANCELLATION "true" }
+
+#include <omp.h>
+#include "cancel-test.h"
+
+__attribute__((noinline, noclone)) int
+foo (int *x)
+{
+ S a, b, c, d, e;
+ int v = 0, w = 0;
+ #pragma omp parallel num_threads (32) shared (v, w) private (c, d) firstprivate (e)
+ {
+ S g;
+ int i;
+ c.bump ();
+ e.bump ();
+ #pragma omp for private (d, g) firstprivate (b)
+ for (i = 0; i < 1000; ++i)
+ {
+ b.bump ();
+ d.bump ();
+ g.bump ();
+ #pragma omp cancel for if (x[0])
+ abort ();
+ }
+ #pragma omp for private (d, g) firstprivate (b)
+ for (i = 0; i < 1000; ++i)
+ {
+ b.bump ();
+ d.bump ();
+ g.bump ();
+ #pragma omp cancel for if (x[1])
+ #pragma omp atomic
+ v++;
+ }
+ #pragma omp for private (d, g) firstprivate (b)
+ for (i = 0; i < 1000; ++i)
+ {
+ b.bump ();
+ d.bump ();
+ g.bump ();
+ #pragma omp cancel for if (x[2])
+ #pragma omp atomic
+ w += 8;
+ }
+ #pragma omp for private (d, g) firstprivate (b)
+ for (i = 0; i < 1000; ++i)
+ {
+ b.bump ();
+ d.bump ();
+ g.bump ();
+ #pragma omp cancel for if (x[3])
+ #pragma omp atomic
+ v += 2;
+ }
+ }
+ if (v != 3000 || w != 0)
+ abort ();
+ #pragma omp parallel num_threads (32) shared (v, w) private (c, d) firstprivate (e)
+ {
+ S g, h;
+ int i;
+ c.bump ();
+ e.bump ();
+ /* None of these cancel directives should actually cancel anything,
+ but the compiler shouldn't know that and thus should use cancellable
+ barriers at the end of all the workshares. */
+ #pragma omp cancel parallel if (omp_get_thread_num () == 1 && x[4])
+ #pragma omp for private (d, g) firstprivate (b)
+ for (i = 0; i < 1000; ++i)
+ {
+ b.bump ();
+ d.bump ();
+ g.bump ();
+ #pragma omp cancel for if (x[0])
+ abort ();
+ }
+ #pragma omp cancel parallel if (omp_get_thread_num () == 2 && x[4])
+ #pragma omp for private (d, g) firstprivate (b)
+ for (i = 0; i < 1000; ++i)
+ {
+ b.bump ();
+ d.bump ();
+ g.bump ();
+ #pragma omp cancel for if (x[1])
+ #pragma omp atomic
+ v++;
+ }
+ #pragma omp cancel parallel if (omp_get_thread_num () == 3 && x[4])
+ #pragma omp for private (d, g) firstprivate (b)
+ for (i = 0; i < 1000; ++i)
+ {
+ b.bump ();
+ d.bump ();
+ g.bump ();
+ #pragma omp cancel for if (x[2])
+ #pragma omp atomic
+ w += 8;
+ }
+ #pragma omp cancel parallel if (omp_get_thread_num () == 4 && x[4])
+ #pragma omp for private (d, g) firstprivate (b)
+ for (i = 0; i < 1000; ++i)
+ {
+ b.bump ();
+ d.bump ();
+ g.bump ();
+ #pragma omp cancel for if (x[3])
+ #pragma omp atomic
+ v += 2;
+ }
+ #pragma omp cancel parallel if (omp_get_thread_num () == 5 && x[4])
+ }
+ if (v != 6000 || w != 0)
+ abort ();
+ return 0;
+}
+
+int
+main ()
+{
+ int x[] = { 1, 0, 1, 0, 0 };
+ if (omp_get_cancellation ())
+ foo (x);
+ S::verify ();
+}
diff --git a/libgomp/testsuite/libgomp.c++/cancel-parallel-1.C b/libgomp/testsuite/libgomp.c++/cancel-parallel-1.C
new file mode 100644
index 00000000000..033d676b3b2
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/cancel-parallel-1.C
@@ -0,0 +1,18 @@
+// { dg-do run }
+// { dg-set-target-env-var OMP_CANCELLATION "true" }
+
+#include <omp.h>
+#include "cancel-test.h"
+
+int
+main ()
+{
+ #pragma omp parallel num_threads (32)
+ {
+ S a;
+ #pragma omp cancel parallel
+ if (omp_get_cancellation ())
+ abort ();
+ }
+ S::verify ();
+}
diff --git a/libgomp/testsuite/libgomp.c++/cancel-parallel-2.C b/libgomp/testsuite/libgomp.c++/cancel-parallel-2.C
new file mode 100644
index 00000000000..340423b5586
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/cancel-parallel-2.C
@@ -0,0 +1,57 @@
+// { dg-do run }
+// { dg-set-target-env-var OMP_CANCELLATION "true" }
+
+#include <unistd.h>
+#include <omp.h>
+#include "cancel-test.h"
+
+static void
+foo (int *x)
+{
+ S a, b, c;
+ #pragma omp parallel firstprivate(x, c) num_threads (32) private (b)
+ {
+ S d;
+ b.bump ();
+ c.bump ();
+ int thr = omp_get_thread_num ();
+ switch (x[thr])
+ {
+ case 4:
+ #pragma omp cancel parallel
+ break;
+ case 3:
+ #pragma omp task
+ usleep (1000);
+ #pragma omp task
+ usleep (2000);
+ #pragma omp task
+ usleep (4000);
+ break;
+ case 2:
+ usleep (1000);
+ /* FALLTHRU */
+ case 1:
+ #pragma omp cancellation point parallel
+ break;
+ }
+ #pragma omp barrier
+ if (omp_get_cancellation ())
+ abort ();
+ }
+}
+
+int
+main ()
+{
+ int i, j, x[32] = { 0, 1, 2, 4, 2, 2, 1, 0 };
+ foo (x);
+ for (i = 0; i < 32; i++)
+ {
+ for (j = 0; j < 32; j++)
+ x[j] = rand () & 3;
+ x[rand () & 31] = 4;
+ foo (x);
+ }
+ S::verify ();
+}
diff --git a/libgomp/testsuite/libgomp.c++/cancel-parallel-3.C b/libgomp/testsuite/libgomp.c++/cancel-parallel-3.C
new file mode 100644
index 00000000000..9db7a4f7b3e
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/cancel-parallel-3.C
@@ -0,0 +1,50 @@
+// { dg-do run }
+// { dg-set-target-env-var OMP_CANCELLATION "true" }
+
+#include <omp.h>
+#include <unistd.h>
+#include "cancel-test.h"
+
+static inline void
+do_some_work (void)
+{
+ asm volatile ("" : : : "memory");
+}
+
+void
+foo ()
+{
+ S a, b, c;
+ omp_set_dynamic (0);
+ omp_set_schedule (omp_sched_static, 1);
+ #pragma omp parallel num_threads (16) private (b) firstprivate (c)
+ {
+ S d;
+ int i, j;
+ b.bump ();
+ c.bump ();
+ do_some_work ();
+ #pragma omp barrier
+ if (omp_get_thread_num () == 1)
+ {
+ sleep (2);
+ #pragma omp cancellation point parallel
+ }
+ for (j = 3; j <= 16; j++)
+ #pragma omp for schedule (runtime) nowait
+ for (i = 0; i < j; i++)
+ do_some_work ();
+ if (omp_get_thread_num () == 0)
+ {
+ sleep (1);
+ #pragma omp cancel parallel
+ }
+ }
+}
+
+int
+main ()
+{
+ foo ();
+ S::verify ();
+}
diff --git a/libgomp/testsuite/libgomp.c++/cancel-sections-1.C b/libgomp/testsuite/libgomp.c++/cancel-sections-1.C
new file mode 100644
index 00000000000..81a9c352018
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/cancel-sections-1.C
@@ -0,0 +1,43 @@
+// { dg-do run }
+// { dg-set-target-env-var OMP_CANCELLATION "true" }
+
+#include <omp.h>
+#include "cancel-test.h"
+
+int
+main ()
+{
+ if (!omp_get_cancellation ())
+ return 0;
+ #pragma omp parallel num_threads (32)
+ {
+ S a;
+ #pragma omp sections
+ {
+ {
+ S b;
+ #pragma omp cancel sections
+ abort ();
+ }
+ #pragma omp section
+ {
+ S c;
+ #pragma omp cancel sections
+ abort ();
+ }
+ #pragma omp section
+ {
+ S d;
+ #pragma omp cancel sections
+ abort ();
+ }
+ #pragma omp section
+ {
+ S e;
+ #pragma omp cancel sections
+ abort ();
+ }
+ }
+ }
+ S::verify ();
+}
diff --git a/libgomp/testsuite/libgomp.c++/cancel-taskgroup-1.C b/libgomp/testsuite/libgomp.c++/cancel-taskgroup-1.C
new file mode 100644
index 00000000000..4f66859d171
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/cancel-taskgroup-1.C
@@ -0,0 +1,4 @@
+// { dg-do run }
+// { dg-set-target-env-var OMP_CANCELLATION "true" }
+
+#include "../libgomp.c/cancel-taskgroup-1.c"
diff --git a/libgomp/testsuite/libgomp.c++/cancel-taskgroup-2.C b/libgomp/testsuite/libgomp.c++/cancel-taskgroup-2.C
new file mode 100644
index 00000000000..d4a02e91140
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/cancel-taskgroup-2.C
@@ -0,0 +1,4 @@
+// { dg-do run }
+// { dg-set-target-env-var OMP_CANCELLATION "true" }
+
+#include "../libgomp.c/cancel-taskgroup-2.c"
diff --git a/libgomp/testsuite/libgomp.c++/cancel-taskgroup-3.C b/libgomp/testsuite/libgomp.c++/cancel-taskgroup-3.C
new file mode 100644
index 00000000000..c897265ef8b
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/cancel-taskgroup-3.C
@@ -0,0 +1,58 @@
+// { dg-do run }
+// { dg-set-target-env-var OMP_CANCELLATION "true" }
+
+#include <unistd.h>
+#include <omp.h>
+#include "cancel-test.h"
+
+void
+foo ()
+{
+ S a, b, c, d, e, f;
+ #pragma omp parallel private (c, d) firstprivate (e, f)
+ #pragma omp taskgroup
+ {
+ c.bump ();
+ e.bump ();
+ #pragma omp task firstprivate (b, f) private (d)
+ {
+ S h;
+ b.bump ();
+ d.bump ();
+ f.bump ();
+ #pragma omp cancel taskgroup
+ if (omp_get_cancellation ())
+ abort ();
+ }
+ }
+ #pragma omp parallel private (c, d) firstprivate (e, f)
+ {
+ #pragma omp barrier
+ #pragma omp single
+ #pragma omp taskgroup
+ {
+ int i;
+ c.bump ();
+ e.bump ();
+ for (i = 0; i < 50; i++)
+ #pragma omp task firstprivate (b, f) private (d)
+ {
+ S h;
+ b.bump ();
+ d.bump ();
+ f.bump ();
+ #pragma omp cancellation point taskgroup
+ usleep (30);
+ #pragma omp cancel taskgroup if (i > 5)
+ }
+ }
+ usleep (10);
+ }
+}
+
+int
+main ()
+{
+ foo ();
+ S::verify ();
+}
diff --git a/libgomp/testsuite/libgomp.c++/cancel-test.h b/libgomp/testsuite/libgomp.c++/cancel-test.h
new file mode 100644
index 00000000000..776d6ee6321
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/cancel-test.h
@@ -0,0 +1,47 @@
+#include <stdlib.h>
+#include <omp.h>
+
+struct S
+{
+ static int s;
+ int v;
+ S ()
+ {
+ #pragma omp atomic
+ s++;
+ }
+
+ S (int x)
+ {
+ #pragma omp atomic
+ s++;
+ v = x;
+ }
+
+ ~S ()
+ {
+ #pragma omp atomic
+ s--;
+ }
+
+ S (const S &x)
+ {
+ #pragma omp atomic
+ s++;
+ v = x.v;
+ }
+
+ static void
+ verify ()
+ {
+ if (s) abort ();
+ }
+
+ void
+ bump ()
+ {
+ v++;
+ }
+};
+
+int S::s = 0;
diff --git a/libgomp/testsuite/libgomp.c++/for-10.C b/libgomp/testsuite/libgomp.c++/for-10.C
new file mode 100644
index 00000000000..fb1a3e952b1
--- /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 00000000000..0244e4de112
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/for-11.C
@@ -0,0 +1,108 @@
+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;
+ #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 00000000000..86b9d9318cb
--- /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 00000000000..16ef159b827
--- /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 00000000000..6b12415bdce
--- /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 00000000000..1c6d8e01af9
--- /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++/simd-4.C b/libgomp/testsuite/libgomp.c++/simd-4.C
new file mode 100644
index 00000000000..bdfacc65264
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/simd-4.C
@@ -0,0 +1,45 @@
+// { 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 };
+struct S
+{
+ int s;
+ S () : s (0) {}
+ ~S () {}
+};
+#pragma omp declare reduction (+:S:omp_out.s += omp_in.s)
+#pragma omp declare reduction (foo:S:omp_out.s += omp_in.s)
+#pragma omp declare reduction (foo:int:omp_out += omp_in)
+
+__attribute__((noinline, noclone)) int
+foo ()
+{
+ int i, u = 0;
+ S s, t;
+ #pragma omp simd aligned(a : 32) reduction(+:s) reduction(foo:t, u)
+ for (i = 0; i < 1024; i++)
+ {
+ int x = a[i];
+ s.s += x;
+ t.s += x;
+ u += x;
+ }
+ if (t.s != s.s || u != s.s)
+ abort ();
+ return s.s;
+}
+
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 1024; i++)
+ a[i] = (i & 31) + (i / 128);
+ int s = foo ();
+ if (s != 19456)
+ abort ();
+}
diff --git a/libgomp/testsuite/libgomp.c++/simd-5.C b/libgomp/testsuite/libgomp.c++/simd-5.C
new file mode 100644
index 00000000000..6c4627e210a
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/simd-5.C
@@ -0,0 +1,47 @@
+// { 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 };
+struct S
+{
+ int s;
+ S () : s (0) {}
+ ~S () {}
+};
+#pragma omp declare reduction (+:S:omp_out.s += omp_in.s)
+#pragma omp declare reduction (foo:S:omp_out.s += omp_in.s)
+#pragma omp declare reduction (foo:int:omp_out += omp_in)
+
+__attribute__((noinline, noclone)) int
+foo ()
+{
+ int i, u = 0, q = 0;
+ S s, t;
+ #pragma omp simd aligned(a : 32) reduction(+:s, q) reduction(foo:t, u) \
+ safelen(1)
+ for (i = 0; i < 1024; i++)
+ {
+ int x = a[i];
+ s.s += x;
+ t.s += x;
+ u += x;
+ q++;
+ }
+ if (t.s != s.s || u != s.s || q != 1024)
+ abort ();
+ return s.s;
+}
+
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 1024; i++)
+ a[i] = (i & 31) + (i / 128);
+ int s = foo ();
+ if (s != 19456)
+ abort ();
+}
diff --git a/libgomp/testsuite/libgomp.c++/simd-6.C b/libgomp/testsuite/libgomp.c++/simd-6.C
new file mode 100644
index 00000000000..cfc13d0a0f9
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/simd-6.C
@@ -0,0 +1,70 @@
+// { 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 };
+struct S
+{
+ int s;
+ S () : s (0) {}
+ S (int x) : s (x) {}
+ ~S () {}
+};
+#pragma omp declare reduction (+:S:omp_out.s += omp_in.s) \
+ initializer (omp_priv (0))
+#pragma omp declare reduction (foo:S:omp_out.s += omp_in.s) \
+ initializer (omp_priv (0))
+#pragma omp declare reduction (foo:int:omp_out += omp_in) \
+ initializer (omp_priv = 0)
+
+__attribute__((noinline, noclone)) S
+foo (S s)
+{
+ int i, v = 0, &u = v;
+ S t;
+ #pragma omp simd aligned(a : 32) reduction(+:s) reduction(foo:t, u)
+ for (i = 0; i < 1024; i++)
+ {
+ int x = a[i];
+ s.s += x;
+ t.s += x;
+ u += x;
+ }
+ if (t.s != s.s || u != s.s)
+ abort ();
+ return t;
+}
+
+__attribute__((noinline, noclone)) int
+bar (S &s, S &t)
+{
+ int i, v = 0, &u = v;
+ #pragma omp simd aligned(a : 32) reduction(+:s) reduction(foo:t, u)
+ for (i = 0; i < 1024; i++)
+ {
+ int x = a[i];
+ s.s += x;
+ t.s += x;
+ u += x;
+ }
+ if (t.s != s.s || u != s.s)
+ abort ();
+ return s.s;
+}
+
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 1024; i++)
+ a[i] = (i & 31) + (i / 128);
+ S q;
+ int s = foo (q).s;
+ if (s != 19456)
+ abort ();
+ S r, v;
+ if (bar (r, v) != s)
+ abort ();
+}
diff --git a/libgomp/testsuite/libgomp.c++/simd-7.C b/libgomp/testsuite/libgomp.c++/simd-7.C
new file mode 100644
index 00000000000..5a6f4cef7c1
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/simd-7.C
@@ -0,0 +1,72 @@
+// { 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 };
+struct S
+{
+ int s;
+ S () : s (0) {}
+ S (int x) : s (x) {}
+ ~S () {}
+};
+#pragma omp declare reduction (+:S:omp_out.s += omp_in.s) \
+ initializer (omp_priv (0))
+#pragma omp declare reduction (foo:S:omp_out.s += omp_in.s) \
+ initializer (omp_priv (0))
+#pragma omp declare reduction (foo:int:omp_out += omp_in) \
+ initializer (omp_priv = 0)
+
+__attribute__((noinline, noclone)) S
+foo (S s)
+{
+ int i, v = 0, &u = v;
+ S t;
+ #pragma omp simd aligned(a : 32) reduction(+:s) reduction(foo:t, u) \
+ safelen(1)
+ for (i = 0; i < 1024; i++)
+ {
+ int x = a[i];
+ s.s += x;
+ t.s += x;
+ u += x;
+ }
+ if (t.s != s.s || u != s.s)
+ abort ();
+ return t;
+}
+
+__attribute__((noinline, noclone)) int
+bar (S &s, S &t)
+{
+ int i, v = 0, &u = v;
+ #pragma omp simd aligned(a : 32) reduction(+:s) reduction(foo:t, u) \
+ safelen(1)
+ for (i = 0; i < 1024; i++)
+ {
+ int x = a[i];
+ s.s += x;
+ t.s += x;
+ u += x;
+ }
+ if (t.s != s.s || u != s.s)
+ abort ();
+ return s.s;
+}
+
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 1024; i++)
+ a[i] = (i & 31) + (i / 128);
+ S q;
+ int s = foo (q).s;
+ if (s != 19456)
+ abort ();
+ S r, v;
+ if (bar (r, v) != s)
+ abort ();
+}
diff --git a/libgomp/testsuite/libgomp.c++/simd-8.C b/libgomp/testsuite/libgomp.c++/simd-8.C
new file mode 100644
index 00000000000..7c758328529
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/simd-8.C
@@ -0,0 +1,47 @@
+// PR libgomp/58482
+// { 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 };
+struct S
+{
+ int s;
+ S () : s (0) {}
+ ~S () {}
+};
+#pragma omp declare reduction (+:S:omp_out.s += omp_in.s)
+#pragma omp declare reduction (foo:S:omp_out.s += omp_in.s)
+#pragma omp declare reduction (foo:int:omp_out += omp_in)
+
+__attribute__((noinline, noclone)) int
+foo ()
+{
+ int i, u = 0;
+ S s, t;
+ #pragma omp parallel for simd aligned(a : 32) reduction(+:s) \
+ reduction(foo:t, u)
+ for (i = 0; i < 1024; i++)
+ {
+ int x = a[i];
+ s.s += x;
+ t.s += x;
+ u += x;
+ }
+ if (t.s != s.s || u != s.s)
+ abort ();
+ return s.s;
+}
+
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 1024; i++)
+ a[i] = (i & 31) + (i / 128);
+ int s = foo ();
+ if (s != 19456)
+ abort ();
+}
diff --git a/libgomp/testsuite/libgomp.c++/target-1.C b/libgomp/testsuite/libgomp.c++/target-1.C
new file mode 100644
index 00000000000..3cf01d9975d
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/target-1.C
@@ -0,0 +1 @@
+#include "../libgomp.c/target-1.c"
diff --git a/libgomp/testsuite/libgomp.c++/target-2-aux.cc b/libgomp/testsuite/libgomp.c++/target-2-aux.cc
new file mode 100644
index 00000000000..b405404e6dc
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/target-2-aux.cc
@@ -0,0 +1,5 @@
+double f[1024];
+double (&fr) [1024] = f;
+double gbuf[1024];
+double *g = gbuf;
+double *&gr = g;
diff --git a/libgomp/testsuite/libgomp.c++/target-2.C b/libgomp/testsuite/libgomp.c++/target-2.C
new file mode 100644
index 00000000000..83207cd51cd
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/target-2.C
@@ -0,0 +1,58 @@
+// { dg-options "-O2 -fopenmp" }
+// { dg-additional-sources "target-2-aux.cc" }
+
+extern "C" void abort (void);
+
+void
+fn1 (double *x, double *y, int z)
+{
+ int i;
+ for (i = 0; i < z; i++)
+ {
+ x[i] = i & 31;
+ y[i] = (i & 63) - 30;
+ }
+}
+
+double b[1024];
+double (&br) [1024] = b;
+double cbuf[1024];
+double *c = cbuf;
+double *&cr = c;
+extern double (&fr) [1024];
+extern double *&gr;
+
+double
+fn2 (int x, double (&dr) [1024], double *&er)
+{
+ double s = 0;
+ double h[1024];
+ double (&hr) [1024] = h;
+ double ibuf[1024];
+ double *i = ibuf;
+ double *&ir = i;
+ int j;
+ fn1 (hr + 2 * x, ir + 2 * x, x);
+ #pragma omp target map(to: br[:x], cr[0:x], dr[x:x], er[x:x]) \
+ map(to: fr[0:x], gr[0:x], hr[2 * x:x], ir[2 * x:x])
+ #pragma omp parallel for reduction(+:s)
+ for (j = 0; j < x; j++)
+ s += br[j] * cr[j] + dr[x + j] + er[x + j]
+ + fr[j] + gr[j] + hr[2 * x + j] + ir[2 * x + j];
+ return s;
+}
+
+int
+main ()
+{
+ double d[1024];
+ double ebuf[1024];
+ double *e = ebuf;
+ fn1 (br, cr, 128);
+ fn1 (d + 128, e + 128, 128);
+ fn1 (fr, gr, 128);
+ double h = fn2 (128, d, e);
+ if (h != 20416.0)
+ abort ();
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c++/target-3.C b/libgomp/testsuite/libgomp.c++/target-3.C
new file mode 100644
index 00000000000..2e4586feca0
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/target-3.C
@@ -0,0 +1 @@
+#include "../libgomp.c/target-2.c"
diff --git a/libgomp/testsuite/libgomp.c++/taskgroup-1.C b/libgomp/testsuite/libgomp.c++/taskgroup-1.C
new file mode 100644
index 00000000000..5129896613d
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/taskgroup-1.C
@@ -0,0 +1 @@
+#include "../libgomp.c/taskgroup-1.c"
diff --git a/libgomp/testsuite/libgomp.c++/udr-1.C b/libgomp/testsuite/libgomp.c++/udr-1.C
new file mode 100644
index 00000000000..c3ddd859ea4
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/udr-1.C
@@ -0,0 +1,82 @@
+// { dg-do run }
+
+extern "C" void abort ();
+
+struct S
+{
+ int s;
+ void foo (S &x) { s += x.s; }
+ void foo (S &x, bool y) { s += x.s; if (y) abort (); }
+ S (const S &x) { s = x.s + 1; }
+ S (const S &x, bool y) { s = x.s + 2; if (y) abort (); }
+ S () { s = 6; }
+ ~S ();
+};
+
+S::~S ()
+{
+ if (s < 6) abort ();
+ s = -1;
+ /* Ensure the above store is not DSEd. */
+ asm volatile ("" : : "r" (&s) : "memory");
+}
+
+void
+bar (S &x)
+{
+ if (x.s != 6) abort ();
+ x.s = 15;
+}
+
+#pragma omp declare reduction (foo: S: omp_out.foo (omp_in)) \
+ initializer (omp_priv (omp_orig, false))
+#pragma omp declare reduction (foo: char, int, short: omp_out += omp_in - 4) \
+ initializer (omp_priv (4))
+#pragma omp declare reduction (+: S: omp_out.foo (omp_in, false)) \
+ initializer (omp_priv (omp_orig))
+
+namespace N
+{
+ #pragma omp declare reduction (foo: S: omp_out.foo (omp_in)) \
+ initializer (::bar (omp_priv))
+ namespace M {}
+}
+
+int
+main ()
+{
+ S a, b, c, s, t, u;
+ if (a.s != 6 || b.s != 6 || c.s != 6
+ || s.s != 6 || t.s != 6 || u.s != 6) abort ();
+ s.s = 9; t.s = 10; u.s = 11;
+ int d = 0, e = 0, f = 0, g = 0, h = 30, v = 2, q = 0;
+ #pragma omp declare reduction (foo: S: omp_out.foo (omp_in, true)) \
+ initializer (omp_priv = omp_orig)
+ {
+ #pragma omp declare reduction (foo: S: omp_out.foo (omp_in, false)) \
+ initializer (omp_priv = omp_orig)
+ #pragma omp parallel num_threads (4) reduction (N::operator +: q) \
+ reduction (operator +: a, d) reduction (::operator +: b, e) \
+ reduction (+: c, f) reduction (::N::M::operator +: g) \
+ reduction (::N::min: h) reduction (foo: s) reduction (N::foo: t) \
+ reduction (::foo: u) reduction (::foo: v)
+ {
+ if (a.s != 7 || b.s != 7 || c.s != 7
+ || s.s != 10 || t.s != 15 || u.s != 13
+ || v != 4 || d || e || f || g || h != __INT_MAX__) abort ();
+ asm volatile ("" : "+m" (a.s), "+m" (b.s));
+ asm volatile ("" : "+m" (c.s), "+r" (d));
+ asm volatile ("" : "+r" (e), "+r" (f));
+ asm volatile ("" : "+r" (g), "+r" (h));
+ asm volatile ("" : "+m" (s.s), "+m" (t.s));
+ asm volatile ("" : "+m" (u.s), "+r" (v));
+ a.s++; b.s++; c.s++; d++; e++; f++; g++; h = t.s;
+ s.s++; t.s++; u.s++; v++; q++;
+ }
+ }
+ if (a.s != 6 + q * 8 || b.s != 6 + q * 8 || c.s != 6 + q * 8
+ || d != q || e != q || f != q || g != q || h != 15
+ || s.s != 9 + q * 11 || t.s != 10 + q * 16 || u.s != 11 + q * 14
+ || v != 2 + q)
+ abort ();
+}
diff --git a/libgomp/testsuite/libgomp.c++/udr-2.C b/libgomp/testsuite/libgomp.c++/udr-2.C
new file mode 100644
index 00000000000..5408be146bd
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/udr-2.C
@@ -0,0 +1,88 @@
+// { dg-do run }
+
+extern "C" void abort ();
+
+namespace NS
+{
+ struct U
+ {
+ void foo (U &, bool);
+ U ();
+ };
+ struct S
+ {
+ int s;
+ #pragma omp declare reduction (foo : U, S : omp_out.foo (omp_in, false))
+ #pragma omp declare reduction (foo : int : omp_out += omp_in) \
+ initializer (omp_priv = int ())
+ void baz (int v)
+ {
+ S s;
+ int q = 0;
+ if (s.s != 6 || v != 0) abort ();
+ s.s = 20;
+ #pragma omp parallel num_threads (4) reduction (foo : s, v) \
+ reduction (::NS::U::operator + : q)
+ {
+ if (s.s != 6 || q != 0 || v != 0) abort ();
+ asm volatile ("" : "+m" (s.s), "+r" (q), "+r" (v));
+ s.s++; q++; v++;
+ }
+ if (s.s != 20 + q * 7 || q != v) abort ();
+ }
+ void foo (S &x) { s += x.s; }
+ void foo (S &x, bool y) { s += x.s; if (y) abort (); }
+ S (const S &x) { s = x.s + 1; }
+ S (const S &x, bool y) { s = x.s + 2; if (y) abort (); }
+ S () { s = 6; }
+ S (int x) { s = x; }
+ ~S ();
+ };
+ #pragma omp declare reduction (bar : S : omp_out.foo (omp_in)) \
+ initializer (omp_priv (8))
+}
+
+NS::S::~S ()
+{
+ if (s < 6) abort ();
+ s = -1;
+ /* Ensure the above store is not DSEd. */
+ asm volatile ("" : : "r" (&s) : "memory");
+}
+
+struct T : public NS::S
+{
+ void baz ()
+ {
+ S s;
+ int q = 0;
+ if (s.s != 6) abort ();
+ #pragma omp parallel num_threads (4) reduction (foo:s) \
+ reduction (+: q)
+ {
+ if (s.s != 6 || q != 0) abort ();
+ asm volatile ("" : "+m" (s.s), "+r" (q));
+ s.s += 2; q++;
+ }
+ if (s.s != 6 + q * 8) abort ();
+ }
+};
+
+int
+main ()
+{
+ NS::S s;
+ s.baz (0);
+ T t;
+ t.baz ();
+ int q = 0;
+ if (s.s != 6) abort ();
+ // Test ADL
+ #pragma omp parallel num_threads (4) reduction (bar:s) reduction (+:q)
+ {
+ if (s.s != 8 || q != 0) abort ();
+ asm volatile ("" : "+m" (s.s), "+r" (q));
+ s.s += 4; q++;
+ }
+ if (s.s != 6 + q * 12) abort ();
+}
diff --git a/libgomp/testsuite/libgomp.c++/udr-3.C b/libgomp/testsuite/libgomp.c++/udr-3.C
new file mode 100644
index 00000000000..74a01389c7b
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/udr-3.C
@@ -0,0 +1,149 @@
+// { dg-do run }
+
+extern "C" void abort ();
+
+void
+dblinit (double *p)
+{
+ *p = 2.0;
+}
+
+namespace NS
+{
+ template <int N>
+ struct U
+ {
+ void foo (U &, bool);
+ U ();
+ };
+ template <int N>
+ struct S
+ {
+ int s;
+ #pragma omp declare reduction (foo : U<0>, S : omp_out.foo (omp_in, false))
+ #pragma omp declare reduction (foo : int : omp_out += omp_in) \
+ initializer (omp_priv = N + 2)
+ #pragma omp declare reduction (foo : double : omp_out += omp_in) \
+ initializer (dblinit (&omp_priv))
+ void baz (int v)
+ {
+ S s;
+ int q = 0;
+ if (s.s != 6 || v != 0) abort ();
+ s.s = 20;
+ double d = 4.0;
+ #pragma omp parallel num_threads (4) reduction (foo : s, v, d) \
+ reduction (::NS::U<N>::operator + : q)
+ {
+ if (s.s != 6 || q != 0 || v != N + 2 || d != 2.0) abort ();
+ asm volatile ("" : "+m" (s.s), "+r" (q), "+r" (v));
+ s.s++; q++; v++;
+ }
+ if (s.s != 20 + q * 7 || (N + 3) * q != v || d != 4.0 + 2.0 * q)
+ abort ();
+ }
+ void foo (S &x) { s += x.s; }
+ void foo (S &x, bool y) { s += x.s; if (y) abort (); }
+ S (const S &x) { s = x.s + 1; }
+ S (const S &x, bool y) { s = x.s + 2; if (y) abort (); }
+ S () { s = 6; }
+ S (int x) { s = x; }
+ ~S ();
+ };
+ #pragma omp declare reduction (bar : S<1> : omp_out.foo (omp_in)) \
+ initializer (omp_priv (8))
+}
+
+template <int N>
+NS::S<N>::~S ()
+{
+ if (s < 6) abort ();
+ s = -1;
+ /* Ensure the above store is not DSEd. */
+ asm volatile ("" : : "r" (&s) : "memory");
+}
+
+template <int N>
+struct T : public NS::S<N>
+{
+ void baz ()
+ {
+ NS::S<N> s;
+ int q = 0;
+ if (s.s != 6) abort ();
+ #pragma omp parallel num_threads (4) reduction (foo:s) \
+ reduction (+: q)
+ {
+ if (s.s != 6 || q != 0) abort ();
+ asm volatile ("" : "+m" (s.s), "+r" (q));
+ s.s += 2; q++;
+ }
+ if (s.s != 6 + q * 8) abort ();
+ }
+};
+
+struct W
+{
+ int v;
+ W () : v (6) {}
+ ~W () {}
+};
+
+template <typename T, typename D>
+struct V
+{
+ #pragma omp declare reduction (baz: T: omp_out.s += omp_in.s) \
+ initializer (omp_priv (11))
+ #pragma omp declare reduction (baz: D: omp_out += omp_in) \
+ initializer (dblinit (&omp_priv))
+ static void dblinit (D *x) { *x = 3.0; }
+ void baz ()
+ {
+ T t;
+ V v;
+ int q = 0;
+ D d = 4.0;
+ if (t.s != 6 || v.v != 4) abort ();
+ #pragma omp declare reduction (+ : V, W : omp_out.v -= omp_in.v) \
+ initializer (omp_priv (12))
+ {
+ #pragma omp declare reduction (+ : W, V : omp_out.v += omp_in.v) \
+ initializer (omp_priv (9))
+ #pragma omp parallel num_threads (4) reduction (+: v, q) \
+ reduction (baz: t, d)
+ {
+ if (t.s != 11 || v.v != 9 || q != 0 || d != 3.0) abort ();
+ asm volatile ("" : "+m" (t.s), "+m" (v.v), "+r" (q));
+ t.s += 2; v.v += 3; q++;
+ }
+ if (t.s != 6 + 13 * q || v.v != 4 + 12 * q || d != 4.0 + 3.0 * q)
+ abort ();
+ }
+ }
+ int v;
+ V () : v (4) {}
+ V (int x) : v (x) {}
+ ~V () {}
+};
+
+int
+main ()
+{
+ NS::S<0> u;
+ u.baz (0);
+ T<2> t;
+ t.baz ();
+ NS::S<1> s;
+ int q = 0;
+ if (s.s != 6) abort ();
+ // Test ADL
+ #pragma omp parallel num_threads (4) reduction (bar:s) reduction (+:q)
+ {
+ if (s.s != 8 || q != 0) abort ();
+ asm volatile ("" : "+m" (s.s), "+r" (q));
+ s.s += 4; q++;
+ }
+ if (s.s != 6 + q * 12) abort ();
+ V <NS::S <0>, double> v;
+ v.baz ();
+}
diff --git a/libgomp/testsuite/libgomp.c++/udr-4.C b/libgomp/testsuite/libgomp.c++/udr-4.C
new file mode 100644
index 00000000000..3e717467a0e
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/udr-4.C
@@ -0,0 +1,32 @@
+// { dg-do run }
+
+extern "C" void abort ();
+
+struct S
+{
+ int s;
+ S () : s (0) {}
+ ~S () {}
+};
+
+#pragma omp declare reduction (+:S:omp_out.s += omp_in.s)
+#pragma omp declare reduction (foo:S:omp_out.s += omp_in.s)
+#pragma omp declare reduction (foo:int:omp_out += omp_in)
+
+int
+main ()
+{
+ int i, u = 0, q = 0;
+ S s, t;
+ if (s.s != 0 || t.s != 0) abort ();
+ #pragma omp parallel reduction(+:s, q) reduction(foo:t, u)
+ {
+ if (s.s != 0 || t.s != 0 || u != 0 || q != 0) abort ();
+ s.s = 6;
+ t.s = 8;
+ u = 9;
+ q++;
+ }
+ if (s.s != 6 * q || t.s != 8 * q || u != 9 * q) abort ();
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c++/udr-5.C b/libgomp/testsuite/libgomp.c++/udr-5.C
new file mode 100644
index 00000000000..91ae2f697c3
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/udr-5.C
@@ -0,0 +1,49 @@
+// { dg-do run }
+
+extern "C" void abort ();
+
+struct S
+{
+ void foo ()
+ {
+ S s;
+ int j = 0;
+ #pragma omp declare reduction (bar : int : omp_out += omp_in)
+ #pragma omp parallel reduction (bar : s) reduction(S::operator+ : j)
+ s.a = 4, j = 1;
+ if (s.a != 4 * j) abort ();
+ }
+ #pragma omp declare reduction (bar : S : baz (omp_out, omp_in))
+ static void baz (S &x, S &y) { x.a += y.a; }
+ S () : a (0) {}
+ int a;
+};
+
+template <int N>
+struct T
+{
+ void foo ()
+ {
+ S s;
+ T t;
+ int j = 0;
+ #pragma omp declare reduction (bar : int : omp_out += omp_in)
+ #pragma omp parallel reduction (bar : t) reduction (S::bar : s) \
+ reduction(T<N>::operator+ : j)
+ s.a = 4, t.a = 5, j = 1;
+ if (s.a != 4 * j || t.a != 5 * j) abort ();
+ }
+ #pragma omp declare reduction (bar : T<N> : baz (omp_out, omp_in))
+ static void baz (T &x, T &y) { x.a += y.a; }
+ T () : a (N) {}
+ int a;
+};
+
+int
+main ()
+{
+ S s;
+ s.foo ();
+ T<0> t;
+ t.foo ();
+}
diff --git a/libgomp/testsuite/libgomp.c++/udr-6.C b/libgomp/testsuite/libgomp.c++/udr-6.C
new file mode 100644
index 00000000000..4be821ed0db
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/udr-6.C
@@ -0,0 +1,68 @@
+// { dg-do run }
+
+extern "C" void abort ();
+
+struct A { int a; A () : a (6) {} };
+struct B { int b; B () : b (5) {} };
+struct C { int c; C () : c (4) {} };
+struct D { int d; D () : d (3) {} };
+struct E : A, B {};
+struct F : C, D {};
+struct G : E, F {};
+void foo (B &);
+void foo (F &);
+#pragma omp declare reduction (+:B:omp_out.b += omp_in.b) \
+ initializer(foo (omp_priv))
+
+void
+foo (B &x)
+{
+ if (x.b != 5)
+ abort ();
+ x.b = 9;
+}
+
+template <typename T>
+void bar (T &x, T &y, int z)
+{
+ if (z)
+ abort ();
+ x.a += y.a;
+}
+
+namespace N1
+{
+ struct A { int a; A () : a (0) {} };
+ #pragma omp declare reduction (+:A:bar (omp_out, omp_in, 0))
+};
+namespace N2
+{
+ struct B : N1::A { };
+ #pragma omp declare reduction (+:N1::A:bar (omp_out, omp_in, 1))
+};
+
+int
+main ()
+{
+ G g;
+ int i = 0;
+ #pragma omp parallel reduction(+:g, i)
+ {
+ if (g.a != 6 || g.b != 9 || g.c != 4 || g.d != 3)
+ abort ();
+ g.a = 1, g.b = 2, g.c = 3, g.d = 4, i = 1;
+ }
+ if (g.a != 6 || g.b != 5 + 2 * i || g.c != 4 || g.d != 3)
+ abort ();
+ N2::B b;
+ i = 0;
+ #pragma omp parallel reduction (+:b, i)
+ {
+ if (b.a != 0)
+ abort ();
+ b.a = 4;
+ i = 1;
+ }
+ if (b.a != 4 * i)
+ abort ();
+}
diff --git a/libgomp/testsuite/libgomp.c++/udr-7.C b/libgomp/testsuite/libgomp.c++/udr-7.C
new file mode 100644
index 00000000000..6f661895a37
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/udr-7.C
@@ -0,0 +1,72 @@
+// { dg-do run }
+
+extern "C" void abort ();
+
+struct S
+{
+ int s;
+ void foo (S &x) { s += x.s; }
+ S (const S &x) { s = x.s + 1; }
+ S () { s = 6; }
+ ~S () {}
+};
+
+void
+bar (S &x, S &y)
+{
+ if (x.s != 6 || y.s != 6)
+ abort ();
+ x.s = 8;
+}
+
+#pragma omp declare reduction (foo: S: omp_out.foo (omp_in)) \
+ initializer (omp_priv (omp_orig))
+#pragma omp declare reduction (bar : S: omp_out.foo (omp_in)) \
+ initializer (bar (omp_priv, omp_orig))
+
+S
+baz (S x)
+{
+ S r;
+ int i = 0;
+ if (x.s != 7 || r.s != 6)
+ abort ();
+ #pragma omp parallel reduction (foo: x) reduction (bar: r) \
+ reduction (+: i)
+ {
+ if (x.s != 8 || r.s != 8)
+ abort ();
+ x.s = 12;
+ r.s = 14;
+ i = 1;
+ }
+ if (x.s != 7 + 12 * i || r.s != 6 + 14 * i)
+ abort ();
+ return r;
+}
+
+void
+baz (S &x, S &y)
+{
+ int i = 0, &j = i;
+ #pragma omp parallel reduction (foo: x) reduction (bar: y) \
+ reduction (+: i)
+ {
+ if (x.s != 7 || y.s != 8)
+ abort ();
+ x.s = 12;
+ y.s = 14;
+ i = 1;
+ }
+ if (x.s != 6 + 12 * j || y.s != 6 + 14 * j)
+ abort ();
+}
+
+int
+main ()
+{
+ S s;
+ baz (s);
+ S t, u;
+ baz (t, u);
+}
diff --git a/libgomp/testsuite/libgomp.c++/udr-8.C b/libgomp/testsuite/libgomp.c++/udr-8.C
new file mode 100644
index 00000000000..81c4beb8b6e
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/udr-8.C
@@ -0,0 +1,39 @@
+// { dg-do run }
+
+extern "C" void abort ();
+
+struct S;
+void foo (S *, S *);
+void bar (S &, S &);
+#pragma omp declare reduction (+:S:foo (&omp_out, &omp_in))
+#pragma omp declare reduction (*:S:bar (omp_out, omp_in))
+struct S { int s; S () : s (0) {} };
+
+void
+foo (S *x, S *y)
+{
+ x->s += y->s;
+}
+
+void
+bar (S &x, S &y)
+{
+ x.s += y.s;
+}
+
+int
+main ()
+{
+ S s, t;
+ int i = 0;
+ #pragma omp parallel reduction (+:s, i) reduction (*:t)
+ {
+ if (s.s != 0 || t.s != 0)
+ abort ();
+ s.s = 2;
+ t.s = 3;
+ i = 1;
+ }
+ if (s.s != 2 * i || t.s != 3 * i)
+ abort ();
+}
diff --git a/libgomp/testsuite/libgomp.c++/udr-9.C b/libgomp/testsuite/libgomp.c++/udr-9.C
new file mode 100644
index 00000000000..58fea18a4ce
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/udr-9.C
@@ -0,0 +1,3 @@
+// { dg-do run }
+
+#include "../libgomp.c/udr-1.c"
diff --git a/libgomp/testsuite/libgomp.c/affinity-1.c b/libgomp/testsuite/libgomp.c/affinity-1.c
new file mode 100644
index 00000000000..5d3e45d1df9
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/affinity-1.c
@@ -0,0 +1,1146 @@
+/* Affinity tests.
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ 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
+ <http://www.gnu.org/licenses/>. */
+
+/* { dg-do run } */
+/* { dg-set-target-env-var OMP_PROC_BIND "false" } */
+/* { dg-additional-options "-DINTERPOSE_GETAFFINITY -DDO_FORK -ldl" { target *-*-linux* } } */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include "config.h"
+#include <alloca.h>
+#include <omp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef DO_FORK
+#include <signal.h>
+#endif
+#ifdef HAVE_PTHREAD_AFFINITY_NP
+#include <sched.h>
+#include <pthread.h>
+#ifdef INTERPOSE_GETAFFINITY
+#include <dlfcn.h>
+#endif
+#endif
+
+struct place
+{
+ int start, len;
+};
+struct places
+{
+ char name[40];
+ int count;
+ struct place places[8];
+} places_array[] = {
+ { "", 1, { { -1, -1 } } },
+ { "{0}:8", 8,
+ { { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1 },
+ { 4, 1 }, { 5, 1 }, { 6, 1 }, { 7, 1 } } },
+ { "{7,6}:2:-3", 2, { { 6, 2 }, { 3, 2 } } },
+ { "{6,7}:4:-2,!{2,3}", 3, { { 6, 2 }, { 4, 2 }, { 0, 2 } } },
+ { "{1}:7:1", 7,
+ { { 1, 1 }, { 2, 1 }, { 3, 1 },
+ { 4, 1 }, { 5, 1 }, { 6, 1 }, { 7, 1 } } },
+ { "{0,1},{3,2,4},{6,5,!6},{6},{7:2:-1,!6}", 5,
+ { { 0, 2 }, { 2, 3 }, { 5, 1 }, { 6, 1 }, { 7, 1 } } }
+};
+
+unsigned long contig_cpucount;
+unsigned long min_cpusetsize;
+
+#if defined (HAVE_PTHREAD_AFFINITY_NP) && defined (_SC_NPROCESSORS_CONF) \
+ && defined (CPU_ALLOC_SIZE)
+
+#if defined (RTLD_NEXT) && defined (INTERPOSE_GETAFFINITY)
+int (*orig_getaffinity_np) (pthread_t, size_t, cpu_set_t *);
+
+int
+pthread_getaffinity_np (pthread_t thread, size_t cpusetsize, cpu_set_t *cpuset)
+{
+ int ret;
+ unsigned long i, max;
+ if (orig_getaffinity_np == NULL)
+ {
+ orig_getaffinity_np = (int (*) (pthread_t, size_t, cpu_set_t *))
+ dlsym (RTLD_NEXT, "pthread_getaffinity_np");
+ if (orig_getaffinity_np == NULL)
+ exit (0);
+ }
+ ret = orig_getaffinity_np (thread, cpusetsize, cpuset);
+ if (ret != 0)
+ return ret;
+ if (contig_cpucount == 0)
+ {
+ max = 8 * cpusetsize;
+ for (i = 0; i < max; i++)
+ if (!CPU_ISSET_S (i, cpusetsize, cpuset))
+ break;
+ contig_cpucount = i;
+ min_cpusetsize = cpusetsize;
+ }
+ return ret;
+}
+#endif
+
+void
+print_affinity (struct place p)
+{
+ static unsigned long size;
+ if (size == 0)
+ {
+ if (min_cpusetsize)
+ size = min_cpusetsize;
+ else
+ {
+ size = sysconf (_SC_NPROCESSORS_CONF);
+ size = CPU_ALLOC_SIZE (size);
+ if (size < sizeof (cpu_set_t))
+ size = sizeof (cpu_set_t);
+ }
+ }
+ cpu_set_t *cpusetp = (cpu_set_t *) alloca (size);
+ if (pthread_getaffinity_np (pthread_self (), size, cpusetp) == 0)
+ {
+ unsigned long i, len, max = 8 * size;
+ int notfirst = 0, unexpected = 1;
+
+ printf (" bound to {");
+ for (i = 0, len = 0; i < max; i++)
+ if (CPU_ISSET_S (i, size, cpusetp))
+ {
+ if (len == 0)
+ {
+ if (notfirst)
+ {
+ unexpected = 1;
+ printf (",");
+ }
+ else if (i == (unsigned long) p.start)
+ unexpected = 0;
+ notfirst = 1;
+ printf ("%lu", i);
+ }
+ ++len;
+ }
+ else
+ {
+ if (len && len != (unsigned long) p.len)
+ unexpected = 1;
+ if (len > 1)
+ printf (":%lu", len);
+ len = 0;
+ }
+ if (len && len != (unsigned long) p.len)
+ unexpected = 1;
+ if (len > 1)
+ printf (":%lu", len);
+ printf ("}");
+ if (p.start != -1 && unexpected)
+ {
+ printf (", expected {%d", p.start);
+ if (p.len != 1)
+ printf (":%d", p.len);
+ printf ("} instead");
+ }
+ else if (p.start != -1)
+ printf (", verified");
+ }
+}
+#else
+void
+print_affinity (struct place p)
+{
+ (void) p.start;
+ (void) p.len;
+}
+#endif
+
+
+int
+main ()
+{
+ char *env_proc_bind = getenv ("OMP_PROC_BIND");
+ int test_false = env_proc_bind && strcmp (env_proc_bind, "false") == 0;
+ int test_true = env_proc_bind && strcmp (env_proc_bind, "true") == 0;
+ int test_spread_master_close
+ = env_proc_bind && strcmp (env_proc_bind, "spread,master,close") == 0;
+ char *env_places = getenv ("OMP_PLACES");
+ int test_places = 0;
+
+#ifdef DO_FORK
+ if (env_places == NULL && contig_cpucount >= 8 && test_false
+ && getenv ("GOMP_AFFINITY") == NULL)
+ {
+ int i, j, status;
+ pid_t pid;
+ for (j = 0; j < 2; j++)
+ {
+ if (setenv ("OMP_PROC_BIND", j ? "spread,master,close" : "true", 1)
+ < 0)
+ break;
+ for (i = sizeof (places_array) / sizeof (places_array[0]) - 1;
+ i; --i)
+ {
+ if (setenv ("OMP_PLACES", places_array[i].name, 1) < 0)
+ break;
+ pid = fork ();
+ if (pid == -1)
+ break;
+ if (pid == 0)
+ {
+ execl ("/proc/self/exe", "affinity-1.exe", NULL);
+ _exit (1);
+ }
+ if (waitpid (pid, &status, 0) < 0)
+ break;
+ if (WIFSIGNALED (status) && WTERMSIG (status) == SIGABRT)
+ abort ();
+ else if (!WIFEXITED (status) || WEXITSTATUS (status) != 0)
+ break;
+ }
+ if (i)
+ break;
+ }
+ }
+#endif
+
+ int first = 1;
+ if (env_proc_bind)
+ {
+ printf ("OMP_PROC_BIND='%s'", env_proc_bind);
+ first = 0;
+ }
+ if (env_places)
+ printf ("%sOMP_PLACES='%s'", first ? "" : " ", env_places);
+ printf ("\n");
+
+ if (env_places && contig_cpucount >= 8
+ && (test_true || test_spread_master_close))
+ {
+ for (test_places = sizeof (places_array) / sizeof (places_array[0]) - 1;
+ test_places; --test_places)
+ if (strcmp (env_places, places_array[test_places].name) == 0)
+ break;
+ }
+
+#define verify(if_true, if_s_m_c) \
+ if (test_false && omp_get_proc_bind () != omp_proc_bind_false) \
+ abort (); \
+ if (test_true && omp_get_proc_bind () != if_true) \
+ abort (); \
+ if (test_spread_master_close && omp_get_proc_bind () != if_s_m_c) \
+ abort ();
+
+ verify (omp_proc_bind_true, omp_proc_bind_spread);
+
+ printf ("Initial thread");
+ print_affinity (places_array[test_places].places[0]);
+ printf ("\n");
+ omp_set_nested (1);
+ omp_set_dynamic (0);
+
+ #pragma omp parallel if (0)
+ {
+ verify (omp_proc_bind_true, omp_proc_bind_master);
+ #pragma omp parallel if (0)
+ {
+ verify (omp_proc_bind_true, omp_proc_bind_close);
+ #pragma omp parallel if (0)
+ {
+ verify (omp_proc_bind_true, omp_proc_bind_close);
+ }
+ #pragma omp parallel if (0) proc_bind (spread)
+ {
+ verify (omp_proc_bind_spread, omp_proc_bind_spread);
+ }
+ }
+ #pragma omp parallel if (0) proc_bind (master)
+ {
+ verify (omp_proc_bind_master, omp_proc_bind_close);
+ #pragma omp parallel if (0)
+ {
+ verify (omp_proc_bind_master, omp_proc_bind_close);
+ }
+ #pragma omp parallel if (0) proc_bind (spread)
+ {
+ verify (omp_proc_bind_spread, omp_proc_bind_spread);
+ }
+ }
+ }
+
+ /* True/spread */
+ #pragma omp parallel num_threads (4)
+ {
+ verify (omp_proc_bind_true, omp_proc_bind_master);
+ #pragma omp critical
+ {
+ struct place p = places_array[0].places[0];
+ int thr = omp_get_thread_num ();
+ printf ("#1 thread %d", thr);
+ if (omp_get_num_threads () == 4 && test_spread_master_close)
+ switch (places_array[test_places].count)
+ {
+ case 8:
+ /* T = 4, P = 8, each subpartition has 2 places. */
+ case 7:
+ /* T = 4, P = 7, each subpartition has 2 places, but
+ last partition, which has just one place. */
+ p = places_array[test_places].places[2 * thr];
+ break;
+ case 5:
+ /* T = 4, P = 5, first subpartition has 2 places, the
+ rest just one. */
+ p = places_array[test_places].places[thr ? 1 + thr : 0];
+ break;
+ case 3:
+ /* T = 4, P = 3, unit sized subpartitions, first gets
+ thr0 and thr3, second thr1, third thr2. */
+ p = places_array[test_places].places[thr == 3 ? 0 : thr];
+ break;
+ case 2:
+ /* T = 4, P = 2, unit sized subpartitions, each with
+ 2 threads. */
+ p = places_array[test_places].places[thr / 2];
+ break;
+ }
+ print_affinity (p);
+ printf ("\n");
+ }
+ #pragma omp barrier
+ if (omp_get_thread_num () == 3)
+ {
+ /* True/spread, true/master. */
+ #pragma omp parallel num_threads (3)
+ {
+ verify (omp_proc_bind_true, omp_proc_bind_close);
+ #pragma omp critical
+ {
+ struct place p = places_array[0].places[0];
+ int thr = omp_get_thread_num ();
+ printf ("#1,#1 thread 3,%d", thr);
+ if (omp_get_num_threads () == 3 && test_spread_master_close)
+ /* Outer is spread, inner master, so just bind to the
+ place or the master thread, which is thr 3 above. */
+ switch (places_array[test_places].count)
+ {
+ case 8:
+ case 7:
+ p = places_array[test_places].places[6];
+ break;
+ case 5:
+ p = places_array[test_places].places[4];
+ break;
+ case 3:
+ p = places_array[test_places].places[0];
+ break;
+ case 2:
+ p = places_array[test_places].places[1];
+ break;
+ }
+ print_affinity (p);
+ printf ("\n");
+ }
+ }
+ /* True/spread, spread. */
+ #pragma omp parallel num_threads (5) proc_bind (spread)
+ {
+ verify (omp_proc_bind_spread, omp_proc_bind_close);
+ #pragma omp critical
+ {
+ struct place p = places_array[0].places[0];
+ int thr = omp_get_thread_num ();
+ printf ("#1,#2 thread 3,%d", thr);
+ if (omp_get_num_threads () == 5 && test_spread_master_close)
+ /* Outer is spread, inner spread. */
+ switch (places_array[test_places].count)
+ {
+ case 8:
+ /* T = 5, P = 2, unit sized subpartitions. */
+ p = places_array[test_places].places[thr == 4 ? 6
+ : 6 + thr / 2];
+ break;
+ /* The rest are T = 5, P = 1. */
+ case 7:
+ p = places_array[test_places].places[6];
+ break;
+ case 5:
+ p = places_array[test_places].places[4];
+ break;
+ case 3:
+ p = places_array[test_places].places[0];
+ break;
+ case 2:
+ p = places_array[test_places].places[1];
+ break;
+ }
+ print_affinity (p);
+ printf ("\n");
+ }
+ #pragma omp barrier
+ if (omp_get_thread_num () == 3)
+ {
+ /* True/spread, spread, close. */
+ #pragma omp parallel num_threads (5) proc_bind (close)
+ {
+ verify (omp_proc_bind_close, omp_proc_bind_close);
+ #pragma omp critical
+ {
+ struct place p = places_array[0].places[0];
+ int thr = omp_get_thread_num ();
+ printf ("#1,#2,#1 thread 3,3,%d", thr);
+ if (omp_get_num_threads () == 5 && test_spread_master_close)
+ /* Outer is spread, inner spread, innermost close. */
+ switch (places_array[test_places].count)
+ {
+ /* All are T = 5, P = 1. */
+ case 8:
+ p = places_array[test_places].places[7];
+ break;
+ case 7:
+ p = places_array[test_places].places[6];
+ break;
+ case 5:
+ p = places_array[test_places].places[4];
+ break;
+ case 3:
+ p = places_array[test_places].places[0];
+ break;
+ case 2:
+ p = places_array[test_places].places[1];
+ break;
+ }
+ print_affinity (p);
+ printf ("\n");
+ }
+ }
+ }
+ }
+ /* True/spread, master. */
+ #pragma omp parallel num_threads (4) proc_bind(master)
+ {
+ verify (omp_proc_bind_master, omp_proc_bind_close);
+ #pragma omp critical
+ {
+ struct place p = places_array[0].places[0];
+ int thr = omp_get_thread_num ();
+ printf ("#1,#3 thread 3,%d", thr);
+ if (omp_get_num_threads () == 4 && test_spread_master_close)
+ /* Outer is spread, inner master, so just bind to the
+ place or the master thread, which is thr 3 above. */
+ switch (places_array[test_places].count)
+ {
+ case 8:
+ case 7:
+ p = places_array[test_places].places[6];
+ break;
+ case 5:
+ p = places_array[test_places].places[4];
+ break;
+ case 3:
+ p = places_array[test_places].places[0];
+ break;
+ case 2:
+ p = places_array[test_places].places[1];
+ break;
+ }
+ print_affinity (p);
+ printf ("\n");
+ }
+ }
+ /* True/spread, close. */
+ #pragma omp parallel num_threads (6) proc_bind (close)
+ {
+ verify (omp_proc_bind_close, omp_proc_bind_close);
+ #pragma omp critical
+ {
+ struct place p = places_array[0].places[0];
+ int thr = omp_get_thread_num ();
+ printf ("#1,#4 thread 3,%d", thr);
+ if (omp_get_num_threads () == 6 && test_spread_master_close)
+ /* Outer is spread, inner close. */
+ switch (places_array[test_places].count)
+ {
+ case 8:
+ /* T = 6, P = 2, unit sized subpartitions. */
+ p = places_array[test_places].places[6 + thr / 3];
+ break;
+ /* The rest are T = 6, P = 1. */
+ case 7:
+ p = places_array[test_places].places[6];
+ break;
+ case 5:
+ p = places_array[test_places].places[4];
+ break;
+ case 3:
+ p = places_array[test_places].places[0];
+ break;
+ case 2:
+ p = places_array[test_places].places[1];
+ break;
+ }
+ print_affinity (p);
+ printf ("\n");
+ }
+ }
+ }
+ }
+
+ /* Spread. */
+ #pragma omp parallel num_threads (5) proc_bind(spread)
+ {
+ verify (omp_proc_bind_spread, omp_proc_bind_master);
+ #pragma omp critical
+ {
+ struct place p = places_array[0].places[0];
+ int thr = omp_get_thread_num ();
+ printf ("#2 thread %d", thr);
+ if (omp_get_num_threads () == 5
+ && (test_spread_master_close || test_true))
+ switch (places_array[test_places].count)
+ {
+ case 8:
+ /* T = 5, P = 8, first 3 subpartitions have 2 places, last
+ 2 one place. */
+ p = places_array[test_places].places[thr < 3 ? 2 * thr : 3 + thr];
+ break;
+ case 7:
+ /* T = 5, P = 7, first 2 subpartitions have 2 places, last
+ 3 one place. */
+ p = places_array[test_places].places[thr < 2 ? 2 * thr : 2 + thr];
+ break;
+ case 5:
+ /* T = 5, P = 5, unit sized subpartitions, each one with one
+ thread. */
+ p = places_array[test_places].places[thr];
+ break;
+ case 3:
+ /* T = 5, P = 3, unit sized subpartitions, first gets
+ thr0 and thr3, second thr1 and thr4, third thr2. */
+ p = places_array[test_places].places[thr >= 3 ? thr - 3 : thr];
+ break;
+ case 2:
+ /* T = 5, P = 2, unit sized subpartitions, first with
+ thr{0,1,4} and second with thr{2,3}. */
+ p = places_array[test_places].places[thr == 4 ? 0 : thr / 2];
+ break;
+ }
+ print_affinity (p);
+ printf ("\n");
+ }
+ #pragma omp barrier
+ if (omp_get_thread_num () == 3)
+ {
+ int pp = 0;
+ switch (places_array[test_places].count)
+ {
+ case 8: pp = 6; break;
+ case 7: pp = 5; break;
+ case 5: pp = 3; break;
+ case 2: pp = 1; break;
+ }
+ /* Spread, spread/master. */
+ #pragma omp parallel num_threads (3) firstprivate (pp)
+ {
+ verify (omp_proc_bind_spread, omp_proc_bind_close);
+ #pragma omp critical
+ {
+ struct place p = places_array[0].places[0];
+ int thr = omp_get_thread_num ();
+ printf ("#2,#1 thread 3,%d", thr);
+ if (test_spread_master_close || test_true)
+ /* Outer is spread, inner spread resp. master, bit we have
+ just unit sized partitions. */
+ p = places_array[test_places].places[pp];
+ print_affinity (p);
+ printf ("\n");
+ }
+ }
+ /* Spread, spread. */
+ #pragma omp parallel num_threads (5) proc_bind (spread) \
+ firstprivate (pp)
+ {
+ verify (omp_proc_bind_spread, omp_proc_bind_close);
+ #pragma omp critical
+ {
+ struct place p = places_array[0].places[0];
+ int thr = omp_get_thread_num ();
+ printf ("#2,#2 thread 3,%d", thr);
+ if (test_spread_master_close || test_true)
+ /* Outer is spread, inner spread, bit we have
+ just unit sized partitions. */
+ p = places_array[test_places].places[pp];
+ print_affinity (p);
+ printf ("\n");
+ }
+ }
+ /* Spread, master. */
+ #pragma omp parallel num_threads (4) proc_bind(master) \
+ firstprivate(pp)
+ {
+ verify (omp_proc_bind_master, omp_proc_bind_close);
+ #pragma omp critical
+ {
+ struct place p = places_array[0].places[0];
+ int thr = omp_get_thread_num ();
+ printf ("#2,#3 thread 3,%d", thr);
+ if (test_spread_master_close || test_true)
+ /* Outer is spread, inner master, bit we have
+ just unit sized partitions. */
+ p = places_array[test_places].places[pp];
+ print_affinity (p);
+ printf ("\n");
+ }
+ }
+ /* Spread, close. */
+ #pragma omp parallel num_threads (6) proc_bind (close) \
+ firstprivate (pp)
+ {
+ verify (omp_proc_bind_close, omp_proc_bind_close);
+ #pragma omp critical
+ {
+ struct place p = places_array[0].places[0];
+ int thr = omp_get_thread_num ();
+ printf ("#2,#4 thread 3,%d", thr);
+ if (test_spread_master_close || test_true)
+ /* Outer is spread, inner close, bit we have
+ just unit sized partitions. */
+ p = places_array[test_places].places[pp];
+ print_affinity (p);
+ printf ("\n");
+ }
+ }
+ }
+ }
+
+ /* Master. */
+ #pragma omp parallel num_threads (3) proc_bind(master)
+ {
+ verify (omp_proc_bind_master, omp_proc_bind_master);
+ #pragma omp critical
+ {
+ struct place p = places_array[0].places[0];
+ int thr = omp_get_thread_num ();
+ printf ("#3 thread %d", thr);
+ if (test_spread_master_close || test_true)
+ p = places_array[test_places].places[0];
+ print_affinity (p);
+ printf ("\n");
+ }
+ #pragma omp barrier
+ if (omp_get_thread_num () == 2)
+ {
+ /* Master, master. */
+ #pragma omp parallel num_threads (4)
+ {
+ verify (omp_proc_bind_master, omp_proc_bind_close);
+ #pragma omp critical
+ {
+ struct place p = places_array[0].places[0];
+ int thr = omp_get_thread_num ();
+ printf ("#3,#1 thread 2,%d", thr);
+ if (test_spread_master_close || test_true)
+ /* Outer is master, inner is master. */
+ p = places_array[test_places].places[0];
+ print_affinity (p);
+ printf ("\n");
+ }
+ }
+ /* Master, spread. */
+ #pragma omp parallel num_threads (4) proc_bind (spread)
+ {
+ verify (omp_proc_bind_spread, omp_proc_bind_close);
+ #pragma omp critical
+ {
+ struct place p = places_array[0].places[0];
+ int thr = omp_get_thread_num ();
+ printf ("#3,#2 thread 2,%d", thr);
+ if (omp_get_num_threads () == 4
+ && (test_spread_master_close || test_true))
+ /* Outer is master, inner is spread. */
+ switch (places_array[test_places].count)
+ {
+ case 8:
+ /* T = 4, P = 8, each subpartition has 2 places. */
+ case 7:
+ /* T = 4, P = 7, each subpartition has 2 places, but
+ last partition, which has just one place. */
+ p = places_array[test_places].places[2 * thr];
+ break;
+ case 5:
+ /* T = 4, P = 5, first subpartition has 2 places, the
+ rest just one. */
+ p = places_array[test_places].places[thr ? 1 + thr : 0];
+ break;
+ case 3:
+ /* T = 4, P = 3, unit sized subpartitions, first gets
+ thr0 and thr3, second thr1, third thr2. */
+ p = places_array[test_places].places[thr == 3 ? 0 : thr];
+ break;
+ case 2:
+ /* T = 4, P = 2, unit sized subpartitions, each with
+ 2 threads. */
+ p = places_array[test_places].places[thr / 2];
+ break;
+ }
+ print_affinity (p);
+ printf ("\n");
+ }
+ #pragma omp barrier
+ if (omp_get_thread_num () == 0)
+ {
+ /* Master, spread, close. */
+ #pragma omp parallel num_threads (5) proc_bind (close)
+ {
+ verify (omp_proc_bind_close, omp_proc_bind_close);
+ #pragma omp critical
+ {
+ struct place p = places_array[0].places[0];
+ int thr = omp_get_thread_num ();
+ printf ("#3,#2,#1 thread 2,0,%d", thr);
+ if (omp_get_num_threads () == 5
+ && (test_spread_master_close || test_true))
+ /* Outer is master, inner spread, innermost close. */
+ switch (places_array[test_places].count)
+ {
+ /* First 3 are T = 5, P = 2. */
+ case 8:
+ case 7:
+ case 5:
+ p = places_array[test_places].places[(thr & 2) / 2];
+ break;
+ /* All the rest are T = 5, P = 1. */
+ case 3:
+ case 2:
+ p = places_array[test_places].places[0];
+ break;
+ }
+ print_affinity (p);
+ printf ("\n");
+ }
+ }
+ }
+ #pragma omp barrier
+ if (omp_get_thread_num () == 3)
+ {
+ /* Master, spread, close. */
+ #pragma omp parallel num_threads (5) proc_bind (close)
+ {
+ verify (omp_proc_bind_close, omp_proc_bind_close);
+ #pragma omp critical
+ {
+ struct place p = places_array[0].places[0];
+ int thr = omp_get_thread_num ();
+ printf ("#3,#2,#2 thread 2,3,%d", thr);
+ if (omp_get_num_threads () == 5
+ && (test_spread_master_close || test_true))
+ /* Outer is master, inner spread, innermost close. */
+ switch (places_array[test_places].count)
+ {
+ case 8:
+ /* T = 5, P = 2. */
+ p = places_array[test_places].places[6
+ + (thr & 2) / 2];
+ break;
+ /* All the rest are T = 5, P = 1. */
+ case 7:
+ p = places_array[test_places].places[6];
+ break;
+ case 5:
+ p = places_array[test_places].places[4];
+ break;
+ case 3:
+ p = places_array[test_places].places[0];
+ break;
+ case 2:
+ p = places_array[test_places].places[1];
+ break;
+ }
+ print_affinity (p);
+ printf ("\n");
+ }
+ }
+ }
+ }
+ /* Master, master. */
+ #pragma omp parallel num_threads (4) proc_bind(master)
+ {
+ verify (omp_proc_bind_master, omp_proc_bind_close);
+ #pragma omp critical
+ {
+ struct place p = places_array[0].places[0];
+ int thr = omp_get_thread_num ();
+ printf ("#3,#3 thread 2,%d", thr);
+ if (test_spread_master_close || test_true)
+ /* Outer is master, inner master. */
+ p = places_array[test_places].places[0];
+ print_affinity (p);
+ printf ("\n");
+ }
+ }
+ /* Master, close. */
+ #pragma omp parallel num_threads (6) proc_bind (close)
+ {
+ verify (omp_proc_bind_close, omp_proc_bind_close);
+ #pragma omp critical
+ {
+ struct place p = places_array[0].places[0];
+ int thr = omp_get_thread_num ();
+ printf ("#3,#4 thread 2,%d", thr);
+ if (omp_get_num_threads () == 6
+ && (test_spread_master_close || test_true))
+ switch (places_array[test_places].count)
+ {
+ case 8:
+ /* T = 6, P = 8. */
+ case 7:
+ /* T = 6, P = 7. */
+ p = places_array[test_places].places[thr];
+ break;
+ case 5:
+ /* T = 6, P = 5. thr{0,5} go into the first place. */
+ p = places_array[test_places].places[thr == 5 ? 0 : thr];
+ break;
+ case 3:
+ /* T = 6, P = 3, two threads into each place. */
+ p = places_array[test_places].places[thr / 2];
+ break;
+ case 2:
+ /* T = 6, P = 2, 3 threads into each place. */
+ p = places_array[test_places].places[thr / 3];
+ break;
+ }
+ print_affinity (p);
+ printf ("\n");
+ }
+ }
+ }
+ }
+
+ #pragma omp parallel num_threads (5) proc_bind(close)
+ {
+ verify (omp_proc_bind_close, omp_proc_bind_master);
+ #pragma omp critical
+ {
+ struct place p = places_array[0].places[0];
+ int thr = omp_get_thread_num ();
+ printf ("#4 thread %d", thr);
+ if (omp_get_num_threads () == 5
+ && (test_spread_master_close || test_true))
+ switch (places_array[test_places].count)
+ {
+ case 8:
+ /* T = 5, P = 8. */
+ case 7:
+ /* T = 5, P = 7. */
+ case 5:
+ /* T = 5, P = 5. */
+ p = places_array[test_places].places[thr];
+ break;
+ case 3:
+ /* T = 5, P = 3, thr{0,3} in first place, thr{1,4} in second,
+ thr2 in third. */
+ p = places_array[test_places].places[thr >= 3 ? thr - 3 : thr];
+ break;
+ case 2:
+ /* T = 5, P = 2, thr{0,1,4} in first place, thr{2,3} in second. */
+ p = places_array[test_places].places[thr == 4 ? 0 : thr / 2];
+ break;
+ }
+ print_affinity (p);
+ printf ("\n");
+ }
+ #pragma omp barrier
+ if (omp_get_thread_num () == 2)
+ {
+ int pp = 0;
+ switch (places_array[test_places].count)
+ {
+ case 8:
+ case 7:
+ case 5:
+ case 3:
+ pp = 2;
+ break;
+ case 2:
+ pp = 1;
+ break;
+ }
+ /* Close, close/master. */
+ #pragma omp parallel num_threads (4) firstprivate (pp)
+ {
+ verify (omp_proc_bind_close, omp_proc_bind_close);
+ #pragma omp critical
+ {
+ struct place p = places_array[0].places[0];
+ int thr = omp_get_thread_num ();
+ printf ("#4,#1 thread 2,%d", thr);
+ if (test_spread_master_close)
+ /* Outer is close, inner is master. */
+ p = places_array[test_places].places[pp];
+ else if (omp_get_num_threads () == 4 && test_true)
+ /* Outer is close, inner is close. */
+ switch (places_array[test_places].count)
+ {
+ case 8:
+ /* T = 4, P = 8. */
+ case 7:
+ /* T = 4, P = 7. */
+ p = places_array[test_places].places[2 + thr];
+ break;
+ case 5:
+ /* T = 4, P = 5. There is wrap-around for thr3. */
+ p = places_array[test_places].places[thr == 3 ? 0 : 2 + thr];
+ break;
+ case 3:
+ /* T = 4, P = 3, thr{0,3} go into p2, thr1 into p0, thr2
+ into p1. */
+ p = places_array[test_places].places[(2 + thr) % 3];
+ break;
+ case 2:
+ /* T = 4, P = 2, 2 threads into each place. */
+ p = places_array[test_places].places[1 - thr / 2];
+ break;
+ }
+
+ print_affinity (p);
+ printf ("\n");
+ }
+ }
+ /* Close, spread. */
+ #pragma omp parallel num_threads (4) proc_bind (spread)
+ {
+ verify (omp_proc_bind_spread, omp_proc_bind_close);
+ #pragma omp critical
+ {
+ struct place p = places_array[0].places[0];
+ int thr = omp_get_thread_num ();
+ printf ("#4,#2 thread 2,%d", thr);
+ if (omp_get_num_threads () == 4
+ && (test_spread_master_close || test_true))
+ /* Outer is close, inner is spread. */
+ switch (places_array[test_places].count)
+ {
+ case 8:
+ /* T = 4, P = 8, each subpartition has 2 places. */
+ case 7:
+ /* T = 4, P = 7, each subpartition has 2 places, but
+ last partition, which has just one place. */
+ p = places_array[test_places].places[thr == 3 ? 0
+ : 2 + 2 * thr];
+ break;
+ case 5:
+ /* T = 4, P = 5, first subpartition has 2 places, the
+ rest just one. */
+ p = places_array[test_places].places[thr == 3 ? 0
+ : 2 + thr];
+ break;
+ case 3:
+ /* T = 4, P = 3, unit sized subpartitions, third gets
+ thr0 and thr3, first thr1, second thr2. */
+ p = places_array[test_places].places[thr == 0 ? 2 : thr - 1];
+ break;
+ case 2:
+ /* T = 4, P = 2, unit sized subpartitions, each with
+ 2 threads. */
+ p = places_array[test_places].places[1 - thr / 2];
+ break;
+ }
+ print_affinity (p);
+ printf ("\n");
+ }
+ #pragma omp barrier
+ if (omp_get_thread_num () == 0)
+ {
+ /* Close, spread, close. */
+ #pragma omp parallel num_threads (5) proc_bind (close)
+ {
+ verify (omp_proc_bind_close, omp_proc_bind_close);
+ #pragma omp critical
+ {
+ struct place p = places_array[0].places[0];
+ int thr = omp_get_thread_num ();
+ printf ("#4,#2,#1 thread 2,0,%d", thr);
+ if (omp_get_num_threads () == 5
+ && (test_spread_master_close || test_true))
+ /* Outer is close, inner spread, innermost close. */
+ switch (places_array[test_places].count)
+ {
+ case 8:
+ case 7:
+ /* T = 5, P = 2. */
+ p = places_array[test_places].places[2
+ + (thr & 2) / 2];
+ break;
+ /* All the rest are T = 5, P = 1. */
+ case 5:
+ case 3:
+ p = places_array[test_places].places[2];
+ break;
+ case 2:
+ p = places_array[test_places].places[1];
+ break;
+ }
+ print_affinity (p);
+ printf ("\n");
+ }
+ }
+ }
+ #pragma omp barrier
+ if (omp_get_thread_num () == 2)
+ {
+ /* Close, spread, close. */
+ #pragma omp parallel num_threads (5) proc_bind (close)
+ {
+ verify (omp_proc_bind_close, omp_proc_bind_close);
+ #pragma omp critical
+ {
+ struct place p = places_array[0].places[0];
+ int thr = omp_get_thread_num ();
+ printf ("#4,#2,#2 thread 2,2,%d", thr);
+ if (omp_get_num_threads () == 5
+ && (test_spread_master_close || test_true))
+ /* Outer is close, inner spread, innermost close. */
+ switch (places_array[test_places].count)
+ {
+ case 8:
+ /* T = 5, P = 2. */
+ p = places_array[test_places].places[6
+ + (thr & 2) / 2];
+ break;
+ /* All the rest are T = 5, P = 1. */
+ case 7:
+ p = places_array[test_places].places[6];
+ break;
+ case 5:
+ p = places_array[test_places].places[4];
+ break;
+ case 3:
+ p = places_array[test_places].places[1];
+ break;
+ case 2:
+ p = places_array[test_places].places[0];
+ break;
+ }
+ print_affinity (p);
+ printf ("\n");
+ }
+ }
+ }
+ #pragma omp barrier
+ if (omp_get_thread_num () == 3)
+ {
+ /* Close, spread, close. */
+ #pragma omp parallel num_threads (5) proc_bind (close)
+ {
+ verify (omp_proc_bind_close, omp_proc_bind_close);
+ #pragma omp critical
+ {
+ struct place p = places_array[0].places[0];
+ int thr = omp_get_thread_num ();
+ printf ("#4,#2,#3 thread 2,3,%d", thr);
+ if (omp_get_num_threads () == 5
+ && (test_spread_master_close || test_true))
+ /* Outer is close, inner spread, innermost close. */
+ switch (places_array[test_places].count)
+ {
+ case 8:
+ case 7:
+ case 5:
+ /* T = 5, P = 2. */
+ p = places_array[test_places].places[(thr & 2) / 2];
+ break;
+ /* All the rest are T = 5, P = 1. */
+ case 3:
+ p = places_array[test_places].places[2];
+ break;
+ case 2:
+ p = places_array[test_places].places[0];
+ break;
+ }
+ print_affinity (p);
+ printf ("\n");
+ }
+ }
+ }
+ }
+ /* Close, master. */
+ #pragma omp parallel num_threads (4) proc_bind(master) \
+ firstprivate (pp)
+ {
+ verify (omp_proc_bind_master, omp_proc_bind_close);
+ #pragma omp critical
+ {
+ struct place p = places_array[0].places[0];
+ int thr = omp_get_thread_num ();
+ printf ("#4,#3 thread 2,%d", thr);
+ if (test_spread_master_close || test_true)
+ /* Outer is close, inner master. */
+ p = places_array[test_places].places[pp];
+ print_affinity (p);
+ printf ("\n");
+ }
+ }
+ /* Close, close. */
+ #pragma omp parallel num_threads (6) proc_bind (close)
+ {
+ verify (omp_proc_bind_close, omp_proc_bind_close);
+ #pragma omp critical
+ {
+ struct place p = places_array[0].places[0];
+ int thr = omp_get_thread_num ();
+ printf ("#4,#4 thread 2,%d", thr);
+ if (omp_get_num_threads () == 6
+ && (test_spread_master_close || test_true))
+ switch (places_array[test_places].count)
+ {
+ case 8:
+ /* T = 6, P = 8. */
+ p = places_array[test_places].places[2 + thr];
+ break;
+ case 7:
+ /* T = 6, P = 7. */
+ p = places_array[test_places].places[thr == 5 ? 0 : 2 + thr];
+ break;
+ case 5:
+ /* T = 6, P = 5. thr{0,5} go into the third place. */
+ p = places_array[test_places].places[thr >= 3 ? thr - 3
+ : 2 + thr];
+ break;
+ case 3:
+ /* T = 6, P = 3, two threads into each place. */
+ p = places_array[test_places].places[thr < 2 ? 2
+ : thr / 2 - 1];
+ break;
+ case 2:
+ /* T = 6, P = 2, 3 threads into each place. */
+ p = places_array[test_places].places[1 - thr / 3];
+ break;
+ }
+ print_affinity (p);
+ printf ("\n");
+ }
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/atomic-14.c b/libgomp/testsuite/libgomp.c/atomic-14.c
index 593665046c5..9046d80220d 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 00000000000..58331f4a90b
--- /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 00000000000..d33f670ec1f
--- /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 00000000000..2bd0e9b44dc
--- /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 update seq_cst
+ x = 3 * 2 * 1 + x;
+ #pragma omp atomic read seq_cst
+ v = x;
+ if (v != 9)
+ abort ();
+ #pragma omp atomic capture seq_cst
+ 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 capture seq_cst
+ 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 read seq_cst
+ v = x;
+ if (v != 6)
+ abort ();
+ #pragma omp atomic capture seq_cst
+ { v = x; x = 3 + x; }
+ if (v != 6)
+ abort ();
+ #pragma omp atomic capture seq_cst
+ { 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 capture seq_cst
+ { 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 read seq_cst
+ 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 capture seq_cst
+ { 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/cancel-for-1.c b/libgomp/testsuite/libgomp.c/cancel-for-1.c
new file mode 100644
index 00000000000..f805f13642f
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/cancel-for-1.c
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-set-target-env-var OMP_CANCELLATION "true" } */
+
+#include <stdlib.h>
+#include <omp.h>
+
+int
+main ()
+{
+ #pragma omp parallel num_threads (32)
+ {
+ int i;
+ #pragma omp for
+ for (i = 0; i < 1000; ++i)
+ {
+ #pragma omp cancel for
+ if (omp_get_cancellation ())
+ abort ();
+ }
+ }
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/cancel-for-2.c b/libgomp/testsuite/libgomp.c/cancel-for-2.c
new file mode 100644
index 00000000000..30cfbb1c502
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/cancel-for-2.c
@@ -0,0 +1,95 @@
+/* { dg-do run } */
+/* { dg-set-target-env-var OMP_CANCELLATION "true" } */
+
+#include <stdlib.h>
+#include <omp.h>
+
+__attribute__((noinline, noclone)) int
+foo (int *x)
+{
+ int v = 0, w = 0;
+ #pragma omp parallel num_threads (32) shared (v, w)
+ {
+ int i;
+ #pragma omp for
+ for (i = 0; i < 1000; ++i)
+ {
+ #pragma omp cancel for if (x[0])
+ abort ();
+ }
+ #pragma omp for
+ for (i = 0; i < 1000; ++i)
+ {
+ #pragma omp cancel for if (x[1])
+ #pragma omp atomic
+ v++;
+ }
+ #pragma omp for
+ for (i = 0; i < 1000; ++i)
+ {
+ #pragma omp cancel for if (x[2])
+ #pragma omp atomic
+ w += 8;
+ }
+ #pragma omp for
+ for (i = 0; i < 1000; ++i)
+ {
+ #pragma omp cancel for if (x[3])
+ #pragma omp atomic
+ v += 2;
+ }
+ }
+ if (v != 3000 || w != 0)
+ abort ();
+ #pragma omp parallel num_threads (32) shared (v, w)
+ {
+ int i;
+ /* None of these cancel directives should actually cancel anything,
+ but the compiler shouldn't know that and thus should use cancellable
+ barriers at the end of all the workshares. */
+ #pragma omp cancel parallel if (omp_get_thread_num () == 1 && x[4])
+ #pragma omp for
+ for (i = 0; i < 1000; ++i)
+ {
+ #pragma omp cancel for if (x[0])
+ abort ();
+ }
+ #pragma omp cancel parallel if (omp_get_thread_num () == 2 && x[4])
+ #pragma omp for
+ for (i = 0; i < 1000; ++i)
+ {
+ #pragma omp cancel for if (x[1])
+ #pragma omp atomic
+ v++;
+ }
+ #pragma omp cancel parallel if (omp_get_thread_num () == 3 && x[4])
+ #pragma omp for
+ for (i = 0; i < 1000; ++i)
+ {
+ #pragma omp cancel for if (x[2])
+ #pragma omp atomic
+ w += 8;
+ }
+ #pragma omp cancel parallel if (omp_get_thread_num () == 4 && x[4])
+ #pragma omp for
+ for (i = 0; i < 1000; ++i)
+ {
+ #pragma omp cancel for if (x[3])
+ #pragma omp atomic
+ v += 2;
+ }
+ #pragma omp cancel parallel if (omp_get_thread_num () == 5 && x[4])
+ }
+ if (v != 6000 || w != 0)
+ abort ();
+ return 0;
+}
+
+int
+main ()
+{
+ int x[] = { 1, 0, 1, 0, 0 };
+ if (omp_get_cancellation ())
+ foo (x);
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/cancel-parallel-1.c b/libgomp/testsuite/libgomp.c/cancel-parallel-1.c
new file mode 100644
index 00000000000..614eb50f0d6
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/cancel-parallel-1.c
@@ -0,0 +1,17 @@
+/* { dg-do run } */
+/* { dg-set-target-env-var OMP_CANCELLATION "true" } */
+
+#include <stdlib.h>
+#include <omp.h>
+
+int
+main ()
+{
+ #pragma omp parallel num_threads (32)
+ {
+ #pragma omp cancel parallel
+ if (omp_get_cancellation ())
+ abort ();
+ }
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/cancel-parallel-2.c b/libgomp/testsuite/libgomp.c/cancel-parallel-2.c
new file mode 100644
index 00000000000..cae0aa45c0f
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/cancel-parallel-2.c
@@ -0,0 +1,53 @@
+/* { dg-do run } */
+/* { dg-set-target-env-var OMP_CANCELLATION "true" } */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <omp.h>
+
+static void
+foo (int *x)
+{
+ #pragma omp parallel firstprivate(x) num_threads (32)
+ {
+ int thr = omp_get_thread_num ();
+ switch (x[thr])
+ {
+ case 4:
+ #pragma omp cancel parallel
+ break;
+ case 3:
+ #pragma omp task
+ usleep (1000);
+ #pragma omp task
+ usleep (2000);
+ #pragma omp task
+ usleep (4000);
+ break;
+ case 2:
+ usleep (1000);
+ /* FALLTHRU */
+ case 1:
+ #pragma omp cancellation point parallel
+ break;
+ }
+ #pragma omp barrier
+ if (omp_get_cancellation ())
+ abort ();
+ }
+}
+
+int
+main ()
+{
+ int i, j, x[32] = { 0, 1, 2, 4, 2, 2, 1, 0 };
+ foo (x);
+ for (i = 0; i < 32; i++)
+ {
+ for (j = 0; j < 32; j++)
+ x[j] = rand () & 3;
+ x[rand () & 31] = 4;
+ foo (x);
+ }
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/cancel-parallel-3.c b/libgomp/testsuite/libgomp.c/cancel-parallel-3.c
new file mode 100644
index 00000000000..7ceaed18467
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/cancel-parallel-3.c
@@ -0,0 +1,39 @@
+/* { dg-do run } */
+/* { dg-set-target-env-var OMP_CANCELLATION "true" } */
+
+#include <omp.h>
+#include <unistd.h>
+
+static inline void
+do_some_work (void)
+{
+ asm volatile ("" : : : "memory");
+}
+
+int
+main ()
+{
+ omp_set_dynamic (0);
+ omp_set_schedule (omp_sched_static, 1);
+ #pragma omp parallel num_threads (16)
+ {
+ int i, j;
+ do_some_work ();
+ #pragma omp barrier
+ if (omp_get_thread_num () == 1)
+ {
+ sleep (2);
+ #pragma omp cancellation point parallel
+ }
+ for (j = 3; j <= 16; j++)
+ #pragma omp for schedule (runtime) nowait
+ for (i = 0; i < j; i++)
+ do_some_work ();
+ if (omp_get_thread_num () == 0)
+ {
+ sleep (1);
+ #pragma omp cancel parallel
+ }
+ }
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/cancel-sections-1.c b/libgomp/testsuite/libgomp.c/cancel-sections-1.c
new file mode 100644
index 00000000000..e0cef0b6ea7
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/cancel-sections-1.c
@@ -0,0 +1,38 @@
+/* { dg-do run } */
+/* { dg-set-target-env-var OMP_CANCELLATION "true" } */
+
+#include <stdlib.h>
+#include <omp.h>
+
+int
+main ()
+{
+ if (!omp_get_cancellation ())
+ return 0;
+ #pragma omp parallel num_threads (32)
+ {
+ #pragma omp sections
+ {
+ {
+ #pragma omp cancel sections
+ abort ();
+ }
+ #pragma omp section
+ {
+ #pragma omp cancel sections
+ abort ();
+ }
+ #pragma omp section
+ {
+ #pragma omp cancel sections
+ abort ();
+ }
+ #pragma omp section
+ {
+ #pragma omp cancel sections
+ abort ();
+ }
+ }
+ }
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/cancel-taskgroup-1.c b/libgomp/testsuite/libgomp.c/cancel-taskgroup-1.c
new file mode 100644
index 00000000000..5a808113fb0
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/cancel-taskgroup-1.c
@@ -0,0 +1,70 @@
+/* { dg-do run } */
+/* { dg-set-target-env-var OMP_CANCELLATION "true" } */
+
+#include <stdlib.h>
+#include <omp.h>
+
+struct T { struct T *children[2]; int val; };
+
+struct T *
+search (struct T *tree, int val, int lvl)
+{
+ if (tree == NULL || tree->val == val)
+ return tree;
+ struct T *ret = NULL;
+ int i;
+ for (i = 0; i < 2; i++)
+ #pragma omp task shared(ret) if(lvl < 10)
+ {
+ struct T *r = search (tree->children[i], val, lvl + 1);
+ if (r)
+ {
+ #pragma omp atomic write
+ ret = r;
+ #pragma omp cancel taskgroup
+ }
+ }
+ #pragma omp taskwait
+ return ret;
+}
+
+struct T *
+searchp (struct T *tree, int val)
+{
+ struct T *ret;
+ #pragma omp parallel shared(ret) firstprivate (tree, val)
+ #pragma omp single
+ #pragma omp taskgroup
+ ret = search (tree, val, 0);
+ return ret;
+}
+
+int
+main ()
+{
+ /* Must be power of two minus 1. */
+ int size = 0x7ffff;
+ struct T *trees = (struct T *) malloc (size * sizeof (struct T));
+ if (trees == NULL)
+ return 0;
+ int i, l = 1, b = 0;
+ for (i = 0; i < size; i++)
+ {
+ if (i == l)
+ {
+ b = l;
+ l = l * 2 + 1;
+ }
+ trees[i].val = i;
+ trees[i].children[0] = l == size ? NULL : &trees[l + (i - b) * 2];
+ trees[i].children[1] = l == size ? NULL : &trees[l + (i - b) * 2 + 1];
+ }
+ for (i = 0; i < 50; i++)
+ {
+ int v = random () & size;
+ if (searchp (&trees[0], v) != &trees[v])
+ abort ();
+ }
+ free (trees);
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/cancel-taskgroup-2.c b/libgomp/testsuite/libgomp.c/cancel-taskgroup-2.c
new file mode 100644
index 00000000000..c7b8bf75623
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/cancel-taskgroup-2.c
@@ -0,0 +1,37 @@
+/* { dg-do run } */
+/* { dg-set-target-env-var OMP_CANCELLATION "true" } */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <omp.h>
+
+int
+main ()
+{
+ #pragma omp parallel
+ #pragma omp taskgroup
+ #pragma omp task
+ {
+ #pragma omp cancel taskgroup
+ if (omp_get_cancellation ())
+ abort ();
+ }
+ #pragma omp parallel
+ {
+ #pragma omp barrier
+ #pragma omp single
+ #pragma omp taskgroup
+ {
+ int i;
+ for (i = 0; i < 50; i++)
+ #pragma omp task
+ {
+ #pragma omp cancellation point taskgroup
+ usleep (30);
+ #pragma omp cancel taskgroup if (i > 5)
+ }
+ }
+ usleep (10);
+ }
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/depend-1.c b/libgomp/testsuite/libgomp.c/depend-1.c
new file mode 100644
index 00000000000..2db1205c12a
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/depend-1.c
@@ -0,0 +1,215 @@
+#include <stdlib.h>
+
+void
+dep (void)
+{
+ int x = 1;
+ #pragma omp parallel
+ #pragma omp single
+ {
+ #pragma omp task shared (x) depend(out: x)
+ x = 2;
+ #pragma omp task shared (x) depend(in: x)
+ if (x != 2)
+ abort ();
+ }
+}
+
+void
+dep2 (void)
+{
+ #pragma omp parallel
+ #pragma omp single
+ {
+ int x = 1;
+ #pragma omp task shared (x) depend(out: x)
+ x = 2;
+ #pragma omp task shared (x) depend(in: x)
+ if (x != 2)
+ abort ();
+ #pragma omp taskwait
+ }
+}
+
+void
+dep3 (void)
+{
+ #pragma omp parallel
+ {
+ int x = 1;
+ #pragma omp single
+ {
+ #pragma omp task shared (x) depend(out: x)
+ x = 2;
+ #pragma omp task shared (x) depend(in: x)
+ if (x != 2)
+ abort ();
+ }
+ }
+}
+
+void
+firstpriv (void)
+{
+ #pragma omp parallel
+ #pragma omp single
+ {
+ int x = 1;
+ #pragma omp task depend(out: x)
+ x = 2;
+ #pragma omp task depend(in: x)
+ if (x != 1)
+ abort ();
+ }
+}
+
+void
+antidep (void)
+{
+ int x = 1;
+ #pragma omp parallel
+ #pragma omp single
+ {
+ #pragma omp task shared(x) depend(in: x)
+ if (x != 1)
+ abort ();
+ #pragma omp task shared(x) depend(out: x)
+ x = 2;
+ }
+}
+
+void
+antidep2 (void)
+{
+ #pragma omp parallel
+ #pragma omp single
+ {
+ int x = 1;
+ #pragma omp taskgroup
+ {
+ #pragma omp task shared(x) depend(in: x)
+ if (x != 1)
+ abort ();
+ #pragma omp task shared(x) depend(out: x)
+ x = 2;
+ }
+ }
+}
+
+void
+antidep3 (void)
+{
+ #pragma omp parallel
+ {
+ int x = 1;
+ #pragma omp single
+ {
+ #pragma omp task shared(x) depend(in: x)
+ if (x != 1)
+ abort ();
+ #pragma omp task shared(x) depend(out: x)
+ x = 2;
+ }
+ }
+}
+
+
+void
+outdep (void)
+{
+ #pragma omp parallel
+ #pragma omp single
+ {
+ int x = 0;
+ #pragma omp task shared(x) depend(out: x)
+ x = 1;
+ #pragma omp task shared(x) depend(out: x)
+ x = 2;
+ #pragma omp taskwait
+ if (x != 2)
+ abort ();
+ }
+}
+
+void
+concurrent (void)
+{
+ int x = 1;
+ #pragma omp parallel
+ #pragma omp single
+ {
+ #pragma omp task shared (x) depend(out: x)
+ x = 2;
+ #pragma omp task shared (x) depend(in: x)
+ if (x != 2)
+ abort ();
+ #pragma omp task shared (x) depend(in: x)
+ if (x != 2)
+ abort ();
+ #pragma omp task shared (x) depend(in: x)
+ if (x != 2)
+ abort ();
+ }
+}
+
+void
+concurrent2 (void)
+{
+ #pragma omp parallel
+ #pragma omp single
+ {
+ int x = 1;
+ #pragma omp task shared (x) depend(out: x)
+ x = 2;
+ #pragma omp task shared (x) depend(in: x)
+ if (x != 2)
+ abort ();
+ #pragma omp task shared (x) depend(in: x)
+ if (x != 2)
+ abort ();
+ #pragma omp task shared (x) depend(in: x)
+ if (x != 2)
+ abort ();
+ #pragma omp taskwait
+ }
+}
+
+void
+concurrent3 (void)
+{
+ #pragma omp parallel
+ {
+ int x = 1;
+ #pragma omp single
+ {
+ #pragma omp task shared (x) depend(out: x)
+ x = 2;
+ #pragma omp task shared (x) depend(in: x)
+ if (x != 2)
+ abort ();
+ #pragma omp task shared (x) depend(in: x)
+ if (x != 2)
+ abort ();
+ #pragma omp task shared (x) depend(in: x)
+ if (x != 2)
+ abort ();
+ }
+ }
+}
+
+int
+main ()
+{
+ dep ();
+ dep2 ();
+ dep3 ();
+ firstpriv ();
+ antidep ();
+ antidep2 ();
+ antidep3 ();
+ outdep ();
+ concurrent ();
+ concurrent2 ();
+ concurrent3 ();
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/depend-2.c b/libgomp/testsuite/libgomp.c/depend-2.c
new file mode 100644
index 00000000000..2772309e4b8
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/depend-2.c
@@ -0,0 +1,71 @@
+#include <stdlib.h>
+#include <unistd.h>
+
+void
+foo (int do_sleep)
+{
+ int a[64], i, *p = a + 4, x = 0;
+ asm volatile ("" : "+r" (p));
+ for (i = 0; i < 64; i++)
+ a[i] = i + 8;
+ #pragma omp parallel private (i)
+ {
+ #pragma omp single nowait
+ {
+ for (i = 0; i < 8; i++)
+ {
+ #pragma omp task depend(out: a[i * 8 : 4])
+ a[i * 8] += (i + 2) * 9;
+ #pragma omp task depend(out: p[i * 8 : 2])
+ p[i * 8] += (i + 3) * 10;
+ #pragma omp task depend(out: x)
+ x = 1;
+ }
+ for (i = 0; i < 8; i++)
+ #pragma omp task depend(in: a[i * 8 : 4]) \
+ depend(inout: a[i * 8 + 4 : 2]) \
+ depend(in: a[0 : 4]) depend(in: x)
+ {
+ if (a[0] != 8 + 2 * 9 || x != 1)
+ abort ();
+ if (a[i * 8] != i * 8 + 8 + (i + 2) * 9)
+ abort ();
+ if (a[4 + i * 8] != 4 + i * 8 + 8 + (i + 3) * 10)
+ abort ();
+ p[i * 8] += a[i * 8];
+ }
+ for (i = 0; i < 8; i++)
+ #pragma omp task depend(inout: a[i * 8 : 4]) \
+ depend(in: p[i * 8 : 2]) \
+ depend(in: p[0 : 2], x)
+ {
+ if (p[0] != 4 + 8 + 3 * 10 + 0 + 8 + 2 * 9 || x != 1)
+ abort ();
+ if (a[i * 8] != i * 8 + 8 + (i + 2) * 9)
+ abort ();
+ if (a[4 + i * 8] != (4 + i * 8 + 8 + (i + 3) * 10
+ + i * 8 + 8 + (i + 2) * 9))
+ abort ();
+ a[i * 8] += 2;
+ }
+ for (i = 0; i < 4; i++)
+ #pragma omp task depend(in: a[i * 16 : 4], a[i * 16 + 8 : 4], x)
+ {
+ if (a[i * 16] != i * 16 + 8 + (2 * i + 2) * 9 + 2 || x != 1)
+ abort ();
+ if (p[i * 16 + 4] != i * 16 + 8 + 8 + (2 * i + 1 + 2) * 9 + 2)
+ abort ();
+ }
+ }
+ if (do_sleep)
+ sleep (1);
+ }
+}
+
+int
+main ()
+{
+ foo (1);
+ foo (0);
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/depend-3.c b/libgomp/testsuite/libgomp.c/depend-3.c
new file mode 100644
index 00000000000..d565d6e4619
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/depend-3.c
@@ -0,0 +1,51 @@
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+main ()
+{
+ #pragma omp parallel
+ #pragma omp single
+ {
+ int x = 1, y = 2;
+ #pragma omp taskgroup
+ {
+ #pragma omp task shared (x) depend(in: x)
+ {
+ usleep (10000);
+ if (x != 1)
+ abort ();
+ }
+ #pragma omp taskgroup
+ {
+ #pragma omp task shared (x) depend(in: x)
+ {
+ usleep (15000);
+ if (x != 1)
+ abort ();
+ }
+ #pragma omp task shared (y) depend(inout: y)
+ {
+ if (y != 2)
+ abort ();
+ y = 3;
+ }
+ #pragma omp taskgroup
+ {
+ #pragma omp task shared (x) depend(in: x)
+ {
+ usleep (13000);
+ if (x != 1)
+ abort ();
+ }
+ #pragma omp taskgroup
+ {
+ #pragma omp task shared (x) depend(out: x)
+ x = 2;
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/depend-4.c b/libgomp/testsuite/libgomp.c/depend-4.c
new file mode 100644
index 00000000000..a4395ea6fc0
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/depend-4.c
@@ -0,0 +1,56 @@
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+main ()
+{
+ #pragma omp parallel
+ #pragma omp single
+ {
+ int x = 1, y = 2, z = 3;
+ #pragma omp taskgroup
+ {
+ #pragma omp task shared (x, y, z) depend(inout: x, y) \
+ depend (in: z) if (x > 10)
+ {
+ if (x != 1 || y != 2 || z != 3)
+ abort ();
+ x = 4;
+ y = 5;
+ }
+ /* The above task has depend clauses, but no dependencies
+ on earlier tasks, and is if (0), so must be scheduled
+ immediately. */
+ if (x != 4 || y != 5)
+ abort ();
+ }
+ #pragma omp taskgroup
+ {
+ #pragma omp task shared (x, y) depend(in: x, y)
+ {
+ usleep (10000);
+ if (x != 4 || y != 5 || z != 3)
+ abort ();
+ }
+ #pragma omp task shared (x, y) depend(in: x, y)
+ {
+ usleep (10000);
+ if (x != 4 || y != 5 || z != 3)
+ abort ();
+ }
+ #pragma omp task shared (x, y, z) depend(inout: x, y) \
+ depend (in: z) if (x > 10)
+ {
+ if (x != 4 || y != 5 || z != 3)
+ abort ();
+ x = 6;
+ y = 7;
+ }
+ /* The above task has depend clauses, and may have dependencies
+ on earlier tasks, while it is if (0), it can be deferred. */
+ }
+ if (x != 6 || y != 7)
+ 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 00000000000..e702453fb1a
--- /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 00000000000..fa82c5b20d7
--- /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 00000000000..f5a01ab05ec
--- /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 00000000000..57c385ec876
--- /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;
+}
diff --git a/libgomp/testsuite/libgomp.c/for-3.c b/libgomp/testsuite/libgomp.c/for-3.c
new file mode 100644
index 00000000000..06cbf4f9de1
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/for-3.c
@@ -0,0 +1,110 @@
+/* { dg-options "-std=gnu99 -fopenmp" } */
+
+extern void abort ();
+
+#define M(x, y, z) O(x, y, z)
+#define O(x, y, z) x ## _ ## y ## _ ## z
+
+#pragma omp declare target
+
+#define F distribute
+#define G d
+#define S
+#define N(x) M(x, G, normal)
+#include "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 "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 "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 "for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#define F distribute parallel for
+#define G dpf
+#include "for-1.h"
+#undef F
+#undef G
+
+#define F distribute parallel for dist_schedule(static, 128)
+#define G dpf_ds128
+#include "for-1.h"
+#undef F
+#undef G
+
+#define F distribute parallel for simd
+#define G dpfs
+#include "for-1.h"
+#undef F
+#undef G
+
+#define F distribute parallel for simd dist_schedule(static, 128)
+#define G dpfs_ds128
+#include "for-1.h"
+#undef F
+#undef G
+
+#pragma omp end declare target
+
+int
+main ()
+{
+ int err = 0;
+ #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/pr58392.c b/libgomp/testsuite/libgomp.c/pr58392.c
new file mode 100644
index 00000000000..6ca97adc2d3
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/pr58392.c
@@ -0,0 +1,58 @@
+/* PR tree-optimization/58392 */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+/* { dg-additional-options "-msse2" { target sse2_runtime } } */
+/* { dg-additional-options "-mavx" { target avx_runtime } } */
+
+extern void abort (void);
+int d[32 * 32];
+
+__attribute__((noinline, noclone)) int
+foo (int a, int b)
+{
+ int j, c = 0;
+ #pragma omp parallel for reduction(+: c)
+ for (j = 0; j < a; j += 32)
+ {
+ int l;
+ #pragma omp simd reduction(+: c)
+ for (l = 0; l < b; ++l)
+ c += d[j + l];
+ }
+ return c;
+}
+
+__attribute__((noinline, noclone)) int
+bar (int a)
+{
+ int j, c = 0;
+ #pragma omp parallel for simd reduction(+: c)
+ for (j = 0; j < a; ++j)
+ c += d[j];
+ return c;
+}
+
+__attribute__((noinline)) static int
+baz (int a)
+{
+ int j, c = 0;
+ #pragma omp simd reduction(+: c)
+ for (j = 0; j < a; ++j)
+ c += d[j];
+ return c;
+}
+
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 32 * 32; i++)
+ d[i] = (i & 31);
+ if (foo (32 * 32, 32) != (31 * 32 / 2) * 32)
+ abort ();
+ if (bar (32 * 32) != (31 * 32 / 2) * 32)
+ abort ();
+ if (baz (32 * 32) != (31 * 32 / 2) * 32)
+ 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 00000000000..352b3b7ddd4
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/simd-1.c
@@ -0,0 +1,57 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+/* { dg-additional-options "-msse2" { target sse2_runtime } } */
+/* { dg-additional-options "-mavx" { target avx_runtime } } */
+
+extern void abort ();
+int a[1024] __attribute__((aligned (32))) = { 1 };
+int b[1024] __attribute__((aligned (32))) = { 1 };
+int k, m;
+struct U { int u; };
+struct V { int v; };
+
+__attribute__((noinline, noclone)) int
+foo (int *p)
+{
+ int i, s = 0;
+ struct U u;
+ struct 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)
+ 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 00000000000..b485fcb6f6f
--- /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 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 00000000000..34a38830143
--- /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 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/simd-4.c b/libgomp/testsuite/libgomp.c/simd-4.c
new file mode 100644
index 00000000000..fd87c7e1fa7
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/simd-4.c
@@ -0,0 +1,42 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+/* { dg-additional-options "-msse2" { target sse2_runtime } } */
+/* { dg-additional-options "-mavx" { target avx_runtime } } */
+
+extern void abort ();
+int a[1024] __attribute__((aligned (32))) = { 1 };
+struct S { int s; };
+#pragma omp declare reduction (+:struct S:omp_out.s += omp_in.s)
+#pragma omp declare reduction (foo:struct S:omp_out.s += omp_in.s)
+#pragma omp declare reduction (foo:int:omp_out += omp_in)
+
+__attribute__((noinline, noclone)) int
+foo (void)
+{
+ int i, u = 0;
+ struct S s, t;
+ s.s = 0; t.s = 0;
+ #pragma omp simd aligned(a : 32) reduction(+:s) reduction(foo:t, u)
+ for (i = 0; i < 1024; i++)
+ {
+ int x = a[i];
+ s.s += x;
+ t.s += x;
+ u += x;
+ }
+ if (t.s != s.s || u != s.s)
+ abort ();
+ return s.s;
+}
+
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 1024; i++)
+ a[i] = (i & 31) + (i / 128);
+ int s = foo ();
+ if (s != 19456)
+ abort ();
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/simd-5.c b/libgomp/testsuite/libgomp.c/simd-5.c
new file mode 100644
index 00000000000..0b6d41e6356
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/simd-5.c
@@ -0,0 +1,44 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+/* { dg-additional-options "-msse2" { target sse2_runtime } } */
+/* { dg-additional-options "-mavx" { target avx_runtime } } */
+
+extern void abort ();
+int a[1024] __attribute__((aligned (32))) = { 1 };
+struct S { int s; };
+#pragma omp declare reduction (+:struct S:omp_out.s += omp_in.s)
+#pragma omp declare reduction (foo:struct S:omp_out.s += omp_in.s)
+#pragma omp declare reduction (foo:int:omp_out += omp_in)
+
+__attribute__((noinline, noclone)) int
+foo (void)
+{
+ int i, u = 0, q = 0;
+ struct S s, t;
+ s.s = 0; t.s = 0;
+ #pragma omp simd aligned(a : 32) reduction(+:s, q) reduction(foo:t, u) \
+ safelen(1)
+ for (i = 0; i < 1024; i++)
+ {
+ int x = a[i];
+ s.s += x;
+ t.s += x;
+ u += x;
+ q++;
+ }
+ if (t.s != s.s || u != s.s || q != 1024)
+ abort ();
+ return s.s;
+}
+
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 1024; i++)
+ a[i] = (i & 31) + (i / 128);
+ int s = foo ();
+ if (s != 19456)
+ abort ();
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/simd-6.c b/libgomp/testsuite/libgomp.c/simd-6.c
new file mode 100644
index 00000000000..896f34784f2
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/simd-6.c
@@ -0,0 +1,44 @@
+/* PR libgomp/58482 */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+/* { dg-additional-options "-msse2" { target sse2_runtime } } */
+/* { dg-additional-options "-mavx" { target avx_runtime } } */
+
+extern void abort ();
+int a[1024] __attribute__((aligned (32))) = { 1 };
+struct S { int s; };
+#pragma omp declare reduction (+:struct S:omp_out.s += omp_in.s)
+#pragma omp declare reduction (foo:struct S:omp_out.s += omp_in.s)
+#pragma omp declare reduction (foo:int:omp_out += omp_in)
+
+__attribute__((noinline, noclone)) int
+foo (void)
+{
+ int i, u = 0;
+ struct S s, t;
+ s.s = 0; t.s = 0;
+ #pragma omp parallel for simd aligned(a : 32) reduction(+:s) \
+ reduction(foo:t, u)
+ for (i = 0; i < 1024; i++)
+ {
+ int x = a[i];
+ s.s += x;
+ t.s += x;
+ u += x;
+ }
+ if (t.s != s.s || u != s.s)
+ abort ();
+ return s.s;
+}
+
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 1024; i++)
+ a[i] = (i & 31) + (i / 128);
+ int s = foo ();
+ if (s != 19456)
+ abort ();
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/target-1.c b/libgomp/testsuite/libgomp.c/target-1.c
new file mode 100644
index 00000000000..f734d3c279d
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/target-1.c
@@ -0,0 +1,90 @@
+extern
+#ifdef __cplusplus
+"C"
+#endif
+void abort (void);
+
+void
+fn1 (double *x, double *y, int z)
+{
+ int i;
+ for (i = 0; i < z; i++)
+ {
+ x[i] = i & 31;
+ y[i] = (i & 63) - 30;
+ }
+}
+
+#pragma omp declare target
+int tgtv = 6;
+int
+tgt (void)
+{
+ #pragma omp atomic update
+ tgtv++;
+ return 0;
+}
+#pragma omp end declare target
+
+double
+fn2 (int x, int y, int z)
+{
+ double b[1024], c[1024], s = 0;
+ int i, j;
+ fn1 (b, c, x);
+ #pragma omp target data map(to: b)
+ {
+ #pragma omp target map(tofrom: c)
+ #pragma omp teams num_teams(y) thread_limit(z) reduction(+:s) firstprivate(x)
+ #pragma omp distribute dist_schedule(static, 4) collapse(1)
+ for (j=0; j < x; j += y)
+ #pragma omp parallel for reduction(+:s)
+ for (i = j; i < j + y; i++)
+ tgt (), s += b[i] * c[i];
+ #pragma omp target update from(b, tgtv)
+ }
+ return s;
+}
+
+double
+fn3 (int x)
+{
+ double b[1024], c[1024], s = 0;
+ int i;
+ fn1 (b, c, x);
+ #pragma omp target map(to: b, c)
+ #pragma omp parallel for reduction(+:s)
+ for (i = 0; i < x; i++)
+ tgt (), s += b[i] * c[i];
+ return s;
+}
+
+double
+fn4 (int x, double *p)
+{
+ double b[1024], c[1024], d[1024], s = 0;
+ int i;
+ fn1 (b, c, x);
+ fn1 (d + x, p + x, x);
+ #pragma omp target map(to: b, c[0:x], d[x:x]) map(to:p[x:64 + (x & 31)])
+ #pragma omp parallel for reduction(+:s)
+ for (i = 0; i < x; i++)
+ s += b[i] * c[i] + d[x + i] + p[x + i];
+ return s;
+}
+
+int
+main ()
+{
+ double a = fn2 (128, 4, 6);
+ int b = tgtv;
+ double c = fn3 (61);
+ #pragma omp target update from(tgtv)
+ int d = tgtv;
+ double e[1024];
+ double f = fn4 (64, e);
+ if (a != 13888.0 || b != 6 + 128 || c != 4062.0 || d != 6 + 128 + 61
+ || f != 8032.0)
+ abort ();
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/target-2.c b/libgomp/testsuite/libgomp.c/target-2.c
new file mode 100644
index 00000000000..ada8dad81ad
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/target-2.c
@@ -0,0 +1,88 @@
+extern
+#ifdef __cplusplus
+"C"
+#endif
+void abort (void);
+
+void
+fn1 (double *x, double *y, int z)
+{
+ int i;
+ for (i = 0; i < z; i++)
+ {
+ x[i] = i & 31;
+ y[i] = (i & 63) - 30;
+ }
+}
+
+double
+fn2 (int x)
+{
+ double s = 0;
+ double b[3 * x], c[3 * x], d[3 * x], e[3 * x];
+ int i;
+ fn1 (b, c, x);
+ fn1 (e, d + x, x);
+ #pragma omp target map(to: b, c[:x], d[x:x], e)
+ #pragma omp parallel for reduction(+:s)
+ for (i = 0; i < x; i++)
+ s += b[i] * c[i] + d[x + i] + sizeof (b) - sizeof (c);
+ return s;
+}
+
+double
+fn3 (int x)
+{
+ double s = 0;
+ double b[3 * x], c[3 * x], d[3 * x], e[3 * x];
+ int i;
+ fn1 (b, c, x);
+ fn1 (e, d, x);
+ #pragma omp target
+ #pragma omp parallel for reduction(+:s)
+ for (i = 0; i < x; i++)
+ s += b[i] * c[i] + d[i];
+ return s;
+}
+
+double
+fn4 (int x)
+{
+ double s = 0;
+ double b[3 * x], c[3 * x], d[3 * x], e[3 * x];
+ int i;
+ fn1 (b, c, x);
+ fn1 (e, d + x, x);
+ #pragma omp target data map(from: b, c[:x], d[x:x], e)
+ {
+ #pragma omp target update to(b, c[:x], d[x:x], e)
+ #pragma omp target map(c[:x], d[x:x])
+ #pragma omp parallel for reduction(+:s)
+ for (i = 0; i < x; i++)
+ {
+ s += b[i] * c[i] + d[x + i] + sizeof (b) - sizeof (c);
+ b[i] = i + 0.5;
+ c[i] = 0.5 - i;
+ d[x + i] = 0.5 * i;
+ }
+ }
+ for (i = 0; i < x; i++)
+ if (b[i] != i + 0.5 || c[i] != 0.5 - i || d[x + i] != 0.5 * i)
+ abort ();
+ return s;
+}
+
+int
+main ()
+{
+ double a = fn2 (128);
+ if (a != 14080.0)
+ abort ();
+ double b = fn3 (128);
+ if (a != b)
+ abort ();
+ double c = fn4 (256);
+ if (c != 28160.0)
+ abort ();
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/target-3.c b/libgomp/testsuite/libgomp.c/target-3.c
new file mode 100644
index 00000000000..7002cf287f9
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/target-3.c
@@ -0,0 +1,17 @@
+#include <omp.h>
+#include <stdlib.h>
+
+int
+main ()
+{
+ if (omp_get_level ())
+ abort ();
+ #pragma omp target if (0)
+ if (omp_get_level ())
+ abort ();
+ #pragma omp target if (0)
+ #pragma omp teams
+ if (omp_get_level ())
+ abort ();
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/target-4.c b/libgomp/testsuite/libgomp.c/target-4.c
new file mode 100644
index 00000000000..26e935b3673
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/target-4.c
@@ -0,0 +1,14 @@
+#include <omp.h>
+#include <stdlib.h>
+
+int
+main ()
+{
+ omp_set_dynamic (0);
+ #pragma omp parallel num_threads (4)
+ #pragma omp target if (0)
+ #pragma omp single
+ if (omp_get_num_threads () != 1)
+ abort ();
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/target-5.c b/libgomp/testsuite/libgomp.c/target-5.c
new file mode 100644
index 00000000000..436744359ca
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/target-5.c
@@ -0,0 +1,83 @@
+#include <omp.h>
+#include <stdlib.h>
+
+int
+main ()
+{
+ int d_o = omp_get_dynamic ();
+ int n_o = omp_get_nested ();
+ omp_sched_t s_o;
+ int c_o;
+ omp_get_schedule (&s_o, &c_o);
+ int m_o = omp_get_max_threads ();
+ omp_set_dynamic (1);
+ omp_set_nested (1);
+ omp_set_schedule (omp_sched_static, 2);
+ omp_set_num_threads (4);
+ int d = omp_get_dynamic ();
+ int n = omp_get_nested ();
+ omp_sched_t s;
+ int c;
+ omp_get_schedule (&s, &c);
+ int m = omp_get_max_threads ();
+ if (!omp_is_initial_device ())
+ abort ();
+ #pragma omp target if (0)
+ {
+ omp_sched_t s_c;
+ int c_c;
+ omp_get_schedule (&s_c, &c_c);
+ if (d_o != omp_get_dynamic ()
+ || n_o != omp_get_nested ()
+ || s_o != s_c
+ || c_o != c_c
+ || m_o != omp_get_max_threads ())
+ abort ();
+ omp_set_dynamic (0);
+ omp_set_nested (0);
+ omp_set_schedule (omp_sched_dynamic, 4);
+ omp_set_num_threads (2);
+ if (!omp_is_initial_device ())
+ abort ();
+ }
+ if (!omp_is_initial_device ())
+ abort ();
+ omp_sched_t s_c;
+ int c_c;
+ omp_get_schedule (&s_c, &c_c);
+ if (d != omp_get_dynamic ()
+ || n != omp_get_nested ()
+ || s != s_c
+ || c != c_c
+ || m != omp_get_max_threads ())
+ abort ();
+ #pragma omp target if (0)
+ #pragma omp teams
+ {
+ omp_sched_t s_c;
+ int c_c;
+ omp_get_schedule (&s_c, &c_c);
+ if (d_o != omp_get_dynamic ()
+ || n_o != omp_get_nested ()
+ || s_o != s_c
+ || c_o != c_c
+ || m_o != omp_get_max_threads ())
+ abort ();
+ omp_set_dynamic (0);
+ omp_set_nested (0);
+ omp_set_schedule (omp_sched_dynamic, 4);
+ omp_set_num_threads (2);
+ if (!omp_is_initial_device ())
+ abort ();
+ }
+ if (!omp_is_initial_device ())
+ abort ();
+ omp_get_schedule (&s_c, &c_c);
+ if (d != omp_get_dynamic ()
+ || n != omp_get_nested ()
+ || s != s_c
+ || c != c_c
+ || m != omp_get_max_threads ())
+ abort ();
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/target-6.c b/libgomp/testsuite/libgomp.c/target-6.c
new file mode 100644
index 00000000000..ea35aa465f5
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/target-6.c
@@ -0,0 +1,68 @@
+#include <omp.h>
+#include <stdlib.h>
+
+int
+main ()
+{
+ omp_set_dynamic (0);
+ omp_set_nested (1);
+ if (omp_in_parallel ())
+ abort ();
+ #pragma omp parallel num_threads (3)
+ if (omp_get_thread_num () == 2)
+ {
+ if (!omp_in_parallel ())
+ abort ();
+ #pragma omp parallel num_threads (3)
+ if (omp_get_thread_num () == 1)
+ {
+ if (!omp_in_parallel ()
+ || omp_get_level () != 2
+ || omp_get_ancestor_thread_num (0) != 0
+ || omp_get_ancestor_thread_num (1) != 2
+ || omp_get_ancestor_thread_num (2) != 1
+ || omp_get_ancestor_thread_num (3) != -1)
+ abort ();
+ #pragma omp target if (0)
+ {
+ if (omp_in_parallel ()
+ || omp_get_level () != 0
+ || omp_get_ancestor_thread_num (0) != 0
+ || omp_get_ancestor_thread_num (1) != -1)
+ abort ();
+ #pragma omp parallel num_threads (2)
+ {
+ if (!omp_in_parallel ()
+ || omp_get_level () != 1
+ || omp_get_ancestor_thread_num (0) != 0
+ || omp_get_ancestor_thread_num (1)
+ != omp_get_thread_num ()
+ || omp_get_ancestor_thread_num (2) != -1)
+ abort ();
+ }
+ }
+ #pragma omp target if (0)
+ {
+ #pragma omp teams thread_limit (2)
+ {
+ if (omp_in_parallel ()
+ || omp_get_level () != 0
+ || omp_get_ancestor_thread_num (0) != 0
+ || omp_get_ancestor_thread_num (1) != -1)
+ abort ();
+ #pragma omp parallel num_threads (2)
+ {
+ if (!omp_in_parallel ()
+ || omp_get_level () != 1
+ || omp_get_ancestor_thread_num (0) != 0
+ || omp_get_ancestor_thread_num (1)
+ != omp_get_thread_num ()
+ || omp_get_ancestor_thread_num (2) != -1)
+ abort ();
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/target-7.c b/libgomp/testsuite/libgomp.c/target-7.c
new file mode 100644
index 00000000000..90de6c52311
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/target-7.c
@@ -0,0 +1,111 @@
+#include <omp.h>
+#include <stdlib.h>
+
+volatile int v;
+
+void
+foo (int f)
+{
+ int d = f ? omp_get_num_devices () : omp_get_default_device ();
+ int h = 5;
+ #pragma omp target device (d)
+ if (omp_get_level () != 0)
+ abort ();
+ #pragma omp target if (v > 1)
+ if (omp_get_level () != 0 || !omp_is_initial_device ())
+ abort ();
+ #pragma omp target device (d) if (v > 1)
+ if (omp_get_level () != 0 || !omp_is_initial_device ())
+ abort ();
+ #pragma omp target if (v <= 1)
+ if (omp_get_level () != 0 || (f && !omp_is_initial_device ()))
+ abort ();
+ #pragma omp target device (d) if (v <= 1)
+ if (omp_get_level () != 0 || (f && !omp_is_initial_device ()))
+ abort ();
+ #pragma omp target if (0)
+ if (omp_get_level () != 0 || !omp_is_initial_device ())
+ abort ();
+ #pragma omp target device (d) if (0)
+ if (omp_get_level () != 0 || !omp_is_initial_device ())
+ abort ();
+ #pragma omp target if (1)
+ if (omp_get_level () != 0 || (f && !omp_is_initial_device ()))
+ abort ();
+ #pragma omp target device (d) if (1)
+ if (omp_get_level () != 0 || (f && !omp_is_initial_device ()))
+ abort ();
+ #pragma omp target data device (d) map (to: h)
+ {
+ #pragma omp target device (d)
+ if (omp_get_level () != 0 || (f && !omp_is_initial_device ()) || h++ != 5)
+ abort ();
+ #pragma omp target update device (d) from (h)
+ }
+ #pragma omp target data if (v > 1) map (to: h)
+ {
+ #pragma omp target if (v > 1)
+ if (omp_get_level () != 0 || !omp_is_initial_device () || h++ != 6)
+ abort ();
+ #pragma omp target update if (v > 1) from (h)
+ }
+ #pragma omp target data device (d) if (v > 1) map (to: h)
+ {
+ #pragma omp target device (d) if (v > 1)
+ if (omp_get_level () != 0 || !omp_is_initial_device () || h++ != 7)
+ abort ();
+ #pragma omp target update device (d) if (v > 1) from (h)
+ }
+ #pragma omp target data if (v <= 1) map (to: h)
+ {
+ #pragma omp target if (v <= 1)
+ if (omp_get_level () != 0 || (f && !omp_is_initial_device ()) || h++ != 8)
+ abort ();
+ #pragma omp target update if (v <= 1) from (h)
+ }
+ #pragma omp target data device (d) if (v <= 1) map (to: h)
+ {
+ #pragma omp target device (d) if (v <= 1)
+ if (omp_get_level () != 0 || (f && !omp_is_initial_device ()) || h++ != 9)
+ abort ();
+ #pragma omp target update device (d) if (v <= 1) from (h)
+ }
+ #pragma omp target data if (0) map (to: h)
+ {
+ #pragma omp target if (0)
+ if (omp_get_level () != 0 || !omp_is_initial_device () || h++ != 10)
+ abort ();
+ #pragma omp target update if (0) from (h)
+ }
+ #pragma omp target data device (d) if (0) map (to: h)
+ {
+ #pragma omp target device (d) if (0)
+ if (omp_get_level () != 0 || !omp_is_initial_device () || h++ != 11)
+ abort ();
+ #pragma omp target update device (d) if (0) from (h)
+ }
+ #pragma omp target data if (1) map (to: h)
+ {
+ #pragma omp target if (1)
+ if (omp_get_level () != 0 || (f && !omp_is_initial_device ()) || h++ != 12)
+ abort ();
+ #pragma omp target update if (1) from (h)
+ }
+ #pragma omp target data device (d) if (1) map (to: h)
+ {
+ #pragma omp target device (d) if (1)
+ if (omp_get_level () != 0 || (f && !omp_is_initial_device ()) || h++ != 13)
+ abort ();
+ #pragma omp target update device (d) if (1) from (h)
+ }
+ if (h != 14)
+ abort ();
+}
+
+int
+main ()
+{
+ foo (0);
+ foo (1);
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/taskgroup-1.c b/libgomp/testsuite/libgomp.c/taskgroup-1.c
new file mode 100644
index 00000000000..641a3bc0f2c
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/taskgroup-1.c
@@ -0,0 +1,83 @@
+extern
+#ifdef __cplusplus
+"C"
+#endif
+void abort (void);
+int v[16] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
+
+int
+main ()
+{
+ #pragma omp parallel num_threads (4)
+ #pragma omp single
+ {
+ int i;
+ #pragma omp taskgroup
+ {
+ for (i = 0; i < 16; i += 2)
+ #pragma omp task
+ {
+ #pragma omp task
+ v[i]++;
+ #pragma omp task
+ v[i + 1]++;
+ }
+ }
+ for (i = 0; i < 16; i++)
+ if (v[i] != i + 2)
+ abort ();
+ #pragma omp taskgroup
+ {
+ for (i = 0; i < 16; i += 2)
+ #pragma omp task
+ {
+ #pragma omp task
+ v[i]++;
+ #pragma omp task
+ v[i + 1]++;
+ #pragma omp taskwait
+ }
+ }
+ for (i = 0; i < 16; i++)
+ if (v[i] != i + 3)
+ abort ();
+ #pragma omp taskgroup
+ {
+ for (i = 0; i < 16; i += 2)
+ #pragma omp task
+ {
+ #pragma omp task
+ v[i]++;
+ v[i + 1]++;
+ }
+ #pragma omp taskwait
+ for (i = 0; i < 16; i += 2)
+ #pragma omp task
+ v[i + 1]++;
+ }
+ for (i = 0; i < 16; i++)
+ if (v[i] != i + 4 + (i & 1))
+ abort ();
+ #pragma omp taskgroup
+ {
+ for (i = 0; i < 16; i += 2)
+ {
+ #pragma omp taskgroup
+ {
+ #pragma omp task
+ v[i]++;
+ #pragma omp task
+ v[i + 1]++;
+ }
+ if (v[i] != i + 5 || v[i + 1] != i + 7)
+ abort ();
+ #pragma omp task
+ v[i]++;
+ }
+ }
+ for (i = 0; i < 16; i++)
+ if (v[i] != i + 6)
+ abort ();
+ }
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/thread-limit-1.c b/libgomp/testsuite/libgomp.c/thread-limit-1.c
new file mode 100644
index 00000000000..6cc716bee89
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/thread-limit-1.c
@@ -0,0 +1,41 @@
+/* { dg-do run } */
+/* { dg-set-target-env-var OMP_THREAD_LIMIT "6" } */
+
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+main ()
+{
+ if (omp_get_thread_limit () != 6)
+ return 0;
+ omp_set_dynamic (0);
+ omp_set_nested (1);
+ #pragma omp parallel num_threads (3)
+ if (omp_get_num_threads () != 3)
+ abort ();
+ #pragma omp parallel num_threads (3)
+ if (omp_get_num_threads () != 3)
+ abort ();
+ #pragma omp parallel num_threads (8)
+ if (omp_get_num_threads () > 6)
+ abort ();
+ #pragma omp parallel num_threads (6)
+ if (omp_get_num_threads () != 6)
+ abort ();
+ int cnt = 0;
+ #pragma omp parallel num_threads (5)
+ #pragma omp parallel num_threads (5)
+ #pragma omp parallel num_threads (2)
+ {
+ int v;
+ #pragma omp atomic capture
+ v = ++cnt;
+ if (v > 6)
+ abort ();
+ usleep (10000);
+ #pragma omp atomic
+ --cnt;
+ }
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/thread-limit-2.c b/libgomp/testsuite/libgomp.c/thread-limit-2.c
new file mode 100644
index 00000000000..0fc9dae0fd1
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/thread-limit-2.c
@@ -0,0 +1,57 @@
+/* { dg-do run } */
+/* { dg-set-target-env-var OMP_THREAD_LIMIT "9" } */
+
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+main ()
+{
+ if (omp_get_thread_limit () != 9)
+ return 0;
+ omp_set_dynamic (0);
+ #pragma omp parallel num_threads (8)
+ if (omp_get_num_threads () != 8)
+ abort ();
+ #pragma omp parallel num_threads (16)
+ if (omp_get_num_threads () > 9)
+ abort ();
+ #pragma omp target if (0)
+ #pragma omp teams thread_limit (6)
+ {
+ if (omp_get_thread_limit () > 6)
+ abort ();
+ if (omp_get_thread_limit () == 6)
+ {
+ omp_set_dynamic (0);
+ omp_set_nested (1);
+ #pragma omp parallel num_threads (3)
+ if (omp_get_num_threads () != 3)
+ abort ();
+ #pragma omp parallel num_threads (3)
+ if (omp_get_num_threads () != 3)
+ abort ();
+ #pragma omp parallel num_threads (8)
+ if (omp_get_num_threads () > 6)
+ abort ();
+ #pragma omp parallel num_threads (6)
+ if (omp_get_num_threads () != 6)
+ abort ();
+ int cnt = 0;
+ #pragma omp parallel num_threads (5)
+ #pragma omp parallel num_threads (5)
+ #pragma omp parallel num_threads (2)
+ {
+ int v;
+ #pragma omp atomic capture
+ v = ++cnt;
+ if (v > 6)
+ abort ();
+ usleep (10000);
+ #pragma omp atomic
+ --cnt;
+ }
+ }
+ }
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/thread-limit-3.c b/libgomp/testsuite/libgomp.c/thread-limit-3.c
new file mode 100644
index 00000000000..af9bd7887ab
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/thread-limit-3.c
@@ -0,0 +1,12 @@
+#include <stdlib.h>
+#include <omp.h>
+
+int
+main ()
+{
+ #pragma omp target if (0)
+ #pragma omp teams thread_limit (1)
+ if (omp_get_thread_limit () != 1)
+ abort ();
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/udr-1.c b/libgomp/testsuite/libgomp.c/udr-1.c
new file mode 100644
index 00000000000..ea9da72526e
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/udr-1.c
@@ -0,0 +1,81 @@
+/* { dg-do run } */
+
+extern
+#ifdef __cplusplus
+"C"
+#endif
+void abort ();
+
+struct S { int s; struct S *t; };
+
+void
+foo (struct S *out, struct S *in)
+{
+ out->s += in->s;
+}
+
+void
+bar (struct S *x)
+{
+ if (x->s != 6) abort ();
+ x->s = 15;
+}
+
+void
+baz (struct S *x, struct S *y)
+{
+ x->s = 6;
+ x->t = x;
+ (void) y;
+}
+
+#pragma omp declare reduction (foo: struct S: foo (&omp_out, &omp_in)) \
+ initializer (omp_priv = { 8, &omp_priv })
+#pragma omp declare reduction (foo: char, int, short: omp_out += omp_in - 4) \
+ initializer (omp_priv = 4)
+#pragma omp declare reduction (+: struct S: foo (&omp_out, &omp_in)) \
+ initializer (baz (&omp_priv, &omp_orig))
+
+void
+test (struct S s, struct S t)
+{
+ int q = 0;
+ #pragma omp parallel num_threads (4) reduction (+: s, q) reduction (foo: t)
+ {
+ if (s.s != 6 || s.t != &s || t.s != 8 || t.t != &t)
+ abort ();
+ s.s = 2;
+ t.s = 3;
+ q = 1;
+ }
+ if (s.s != 12 + 2 * q || t.s != 14 + 3 * q)
+ abort ();
+}
+
+int
+main ()
+{
+ struct S s, t;
+ s.s = 9; t.s = 10;
+ int h = 30, v = 2, q = 0;
+ #pragma omp declare reduction (foo: struct S: omp_out.s *= omp_in.s) \
+ initializer (omp_priv = omp_orig)
+ {
+ #pragma omp declare reduction (foo: struct S: omp_out.s += omp_in.s) \
+ initializer (omp_priv = omp_orig)
+ #pragma omp parallel num_threads (4) reduction (+: t, q) \
+ reduction (min: h) reduction (foo: s, v)
+ {
+ if (s.s != 9 || t.s != 6 || v != 4 || h != __INT_MAX__) abort ();
+ asm volatile ("" : "+m" (s.s), "+m" (t.s));
+ asm volatile ("" : "+r" (h), "+r" (v));
+ h = t.s; s.s++; t.s++; v++; q++;
+ }
+ }
+ if (h != 6 || s.s != 9 + q * 10 || t.s != 10 + q * 7 || v != 2 + q)
+ abort ();
+ s.s = 12;
+ t.s = 14;
+ test (s, t);
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/udr-2.c b/libgomp/testsuite/libgomp.c/udr-2.c
new file mode 100644
index 00000000000..b58b5c781ab
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/udr-2.c
@@ -0,0 +1,27 @@
+/* { dg-do run } */
+
+extern void abort ();
+
+struct S { int s; };
+
+#pragma omp declare reduction (+:struct S:omp_out.s += omp_in.s)
+#pragma omp declare reduction (foo:struct S:omp_out.s += omp_in.s)
+#pragma omp declare reduction (foo:int:omp_out += omp_in)
+
+int
+main ()
+{
+ int u = 0, q = 0;
+ struct S s, t;
+ s.s = 0; t.s = 0;
+ #pragma omp parallel reduction(+:s, q) reduction(foo:t, u)
+ {
+ if (s.s != 0 || t.s != 0 || u != 0 || q != 0) abort ();
+ s.s = 6;
+ t.s = 8;
+ u = 9;
+ q++;
+ }
+ if (s.s != 6 * q || t.s != 8 * q || u != 9 * q) abort ();
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/udr-3.c b/libgomp/testsuite/libgomp.c/udr-3.c
new file mode 100644
index 00000000000..e0a5b8764df
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/udr-3.c
@@ -0,0 +1,32 @@
+/* { dg-do run } */
+
+extern void abort ();
+
+struct S;
+void foo (struct S *, struct S *);
+#pragma omp declare reduction (+:struct S:foo (&omp_out, &omp_in))
+struct S { int s; };
+
+void
+foo (struct S *x, struct S *y)
+{
+ x->s += y->s;
+}
+
+int
+main ()
+{
+ struct S s;
+ int i = 0;
+ s.s = 0;
+ #pragma omp parallel reduction (+:s, i)
+ {
+ if (s.s != 0)
+ abort ();
+ s.s = 2;
+ i = 1;
+ }
+ if (s.s != 2 * i)
+ abort ();
+ return 0;
+}
diff --git a/libgomp/work.c b/libgomp/work.c
index 591242740af..9c5a327263b 100644
--- a/libgomp/work.c
+++ b/libgomp/work.c
@@ -221,7 +221,10 @@ gomp_work_share_end (void)
if (gomp_barrier_last_thread (bstate))
{
if (__builtin_expect (thr->ts.last_work_share != NULL, 1))
- free_work_share (team, thr->ts.last_work_share);
+ {
+ team->work_shares_to_free = thr->ts.work_share;
+ free_work_share (team, thr->ts.last_work_share);
+ }
}
gomp_team_barrier_wait_end (&team->barrier, bstate);
@@ -229,6 +232,32 @@ gomp_work_share_end (void)
}
/* The current thread is done with its current work sharing construct.
+ This version implies a cancellable barrier at the end of the work-share. */
+
+bool
+gomp_work_share_end_cancel (void)
+{
+ struct gomp_thread *thr = gomp_thread ();
+ struct gomp_team *team = thr->ts.team;
+ gomp_barrier_state_t bstate;
+
+ /* Cancellable work sharing constructs cannot be orphaned. */
+ bstate = gomp_barrier_wait_cancel_start (&team->barrier);
+
+ if (gomp_barrier_last_thread (bstate))
+ {
+ if (__builtin_expect (thr->ts.last_work_share != NULL, 1))
+ {
+ team->work_shares_to_free = thr->ts.work_share;
+ free_work_share (team, thr->ts.last_work_share);
+ }
+ }
+ thr->ts.last_work_share = NULL;
+
+ return gomp_team_barrier_wait_cancel_end (&team->barrier, bstate);
+}
+
+/* The current thread is done with its current work sharing construct.
This version does NOT imply a barrier at the end of the work-share. */
void
@@ -259,6 +288,9 @@ gomp_work_share_end_nowait (void)
#endif
if (completed == team->nthreads)
- free_work_share (team, thr->ts.last_work_share);
+ {
+ team->work_shares_to_free = thr->ts.work_share;
+ free_work_share (team, thr->ts.last_work_share);
+ }
thr->ts.last_work_share = NULL;
}