diff options
author | Jakub Jelinek <jakub@redhat.com> | 2008-05-14 09:11:10 +0000 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2008-05-14 09:11:10 +0000 |
commit | f641074bd10324db19d24c5c7d7450767d64d78b (patch) | |
tree | ca4d50265af4b01417b3aa1bd3ee30590d72202f | |
parent | b353658eebe13efc87271da9539ffcd8d6df1f1a (diff) |
* tree.def (OMP_TASK): Add 3 new arguments.
* tree.h (OMP_TASK_EXPLICIT_START): Removed.
(OMP_TASK_COPYFN, OMP_TASK_ARG_SIZE, OMP_TASK_ARG_ALIGN): Define.
* builtin-types.def (BT_PTR_FN_VOID_PTR_PTR,
BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT): New.
(BT_FN_VOID_OMPFN_PTR_BOOL_UINT): Removed.
* omp-builtins.def (BUILT_IN_GOMP_TASK_START): Removed.
(BUILT_IN_GOMP_TASK): Change type.
* omp-low.c (omp_context): Add sfield_map and srecord_type fields.
(is_task_ctx, lookup_sfield): New functions.
(use_pointer_for_field): Use is_task_ctx helper.
(build_sender_ref): Call lookup_sfield instead of lookup_field.
(install_var_field): Add mask argument. Populate both record_type
and srecord_type if needed.
(delete_omp_context): Destroy sfield_map, clear DECL_ABSTRACT_ORIGIN
in srecord_type.
(fixup_child_record_type): Also remap FIELD_DECL's DECL_SIZE{,_UNIT}
and DECL_FIELD_OFFSET.
(scan_sharing_clauses): Adjust install_var_field callers. For
firstprivate clauses on explicit tasks allocate the var by value in
record_type unconditionally, rather than by reference.
(create_omp_child_function_name): Add task_copy argument, use
*_omp_cpyfn* names if it is true.
(create_omp_child_function): Add task_copy argument, if true create
*_omp_cpyfn* helper function.
(scan_omp_parallel): Adjust create_omp_child_function callers.
(scan_omp_task): Likewise. If srecord_type has been created, create
*_omp_cpyfn* helper function too. Set OMP_TASK_ARG_SIZE
and OMP_TASK_ARG_ALIGN.
(lower_rec_input_clauses): Don't run constructors for firstprivate
explicit task vars which are initialized by *_omp_cpyfn*. Kill
OMP_TASK_EXPLICIT_START. Adjust OMP_CLAUSE_PRIVATE_OUTER_REF
handling. Don't add GOMP_task_start call.
(lower_send_clauses): Clear DECL_ABSTRACT_ORIGIN if in task to
avoid duplicate setting of fields.
(lower_send_shared_vars): Use srecord_type if non-NULL.
(expand_task_copyfn): New function.
(expand_task_call): Call expand_task_copyfn. Kill
OMP_TASK_EXPLICIT_START. Pass OMP_TASK_CPYFN, OMP_TASK_ARG_SIZE
and OMP_TASK_ARG_ALIGN as extra arguments to GOMP_task.
(struct omp_taskcopy_context): New type.
(task_copyfn_copy_decl, task_copyfn_remap_type, create_task_copyfn):
New functions.
(lower_omp_taskreg): Call create_task_copyfn if srecord_type is
needed. Adjust sender_decl type.
* tree-pretty-print.c (dump_generic_node) <case OMP_TASK>: Print
OMP_TASK_COPYFN.
* bitmap.c (bitmap_default_obstack_depth): New variable.
(bitmap_obstack_initialize, bitmap_obstack_release): Do nothing
if argument is NULL and bitmap_default_obstack is already initialized.
* ipa-struct-reorg.c (do_reorg_1): Call bitmap_obstack_release
at the end.
* matrix-reorg.c (matrix_reorg): Likewise.
fortran/
* trans-openmp.c (gfc_trans_omp_task): Create OMP_TASK using make_node.
* types.def (BT_FN_VOID_PTR_PTR, BT_PTR_FN_VOID_PTR_PTR,
BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT): New.
(BT_FN_VOID_OMPFN_PTR_BOOL_UINT): Removed.
libgomp/
* task.c: Include string.h.
(GOMP_task): Add cpyfn, arg_size and arg_align arguments.
Allocate argument buffer and either call cpyfn to populate it,
or memcpy it from the argument struct.
(GOMP_task_start): Removed.
* libgomp.map: Remove GOMP_task_start@@GOMP_2.0.
* libgomp_g.h (GOMP_task_flag_untied,
GOMP_task_flag_explicit_start): Removed.
(GOMP_task): Adjust prototype.
(GOMP_task_start): Removed.
* testsuite/libgomp.fortran/task2.f90: New test.
* testsuite/libgomp.fortran/allocatable4.f90: New test.
* testsuite/libgomp.c/task-4.c: New test.
* testsuite/libgomp.c++/task-4.C: New test.
* testsuite/libgomp.c++/task-3.C: New test.
git-svn-id: https://gcc.gnu.org/svn/gcc/branches/gomp-3_0-branch@135285 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/ChangeLog.gomp | 57 | ||||
-rw-r--r-- | gcc/bitmap.c | 16 | ||||
-rw-r--r-- | gcc/builtin-types.def | 8 | ||||
-rw-r--r-- | gcc/fortran/ChangeLog.gomp | 7 | ||||
-rw-r--r-- | gcc/fortran/trans-openmp.c | 9 | ||||
-rw-r--r-- | gcc/fortran/types.def | 9 | ||||
-rw-r--r-- | gcc/ipa-struct-reorg.c | 1 | ||||
-rw-r--r-- | gcc/matrix-reorg.c | 4 | ||||
-rw-r--r-- | gcc/omp-builtins.def | 5 | ||||
-rw-r--r-- | gcc/omp-low.c | 632 | ||||
-rw-r--r-- | gcc/tree-pretty-print.c | 9 | ||||
-rw-r--r-- | gcc/tree.def | 11 | ||||
-rw-r--r-- | gcc/tree.h | 10 | ||||
-rw-r--r-- | libgomp/ChangeLog.gomp | 18 | ||||
-rw-r--r-- | libgomp/libgomp.map | 1 | ||||
-rw-r--r-- | libgomp/libgomp_g.h | 6 | ||||
-rw-r--r-- | libgomp/task.c | 30 | ||||
-rw-r--r-- | libgomp/testsuite/libgomp.c++/task-3.C | 90 | ||||
-rw-r--r-- | libgomp/testsuite/libgomp.c++/task-4.C | 37 | ||||
-rw-r--r-- | libgomp/testsuite/libgomp.c/task-4.c | 40 | ||||
-rw-r--r-- | libgomp/testsuite/libgomp.fortran/allocatable4.f90 | 47 | ||||
-rw-r--r-- | libgomp/testsuite/libgomp.fortran/task2.f90 | 142 |
22 files changed, 1074 insertions, 115 deletions
diff --git a/gcc/ChangeLog.gomp b/gcc/ChangeLog.gomp index 4a22611531c..38b67b9656e 100644 --- a/gcc/ChangeLog.gomp +++ b/gcc/ChangeLog.gomp @@ -1,3 +1,60 @@ +2008-05-14 Jakub Jelinek <jakub@redhat.com> + + * tree.def (OMP_TASK): Add 3 new arguments. + * tree.h (OMP_TASK_EXPLICIT_START): Removed. + (OMP_TASK_COPYFN, OMP_TASK_ARG_SIZE, OMP_TASK_ARG_ALIGN): Define. + * builtin-types.def (BT_PTR_FN_VOID_PTR_PTR, + BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT): New. + (BT_FN_VOID_OMPFN_PTR_BOOL_UINT): Removed. + * omp-builtins.def (BUILT_IN_GOMP_TASK_START): Removed. + (BUILT_IN_GOMP_TASK): Change type. + * omp-low.c (omp_context): Add sfield_map and srecord_type fields. + (is_task_ctx, lookup_sfield): New functions. + (use_pointer_for_field): Use is_task_ctx helper. + (build_sender_ref): Call lookup_sfield instead of lookup_field. + (install_var_field): Add mask argument. Populate both record_type + and srecord_type if needed. + (delete_omp_context): Destroy sfield_map, clear DECL_ABSTRACT_ORIGIN + in srecord_type. + (fixup_child_record_type): Also remap FIELD_DECL's DECL_SIZE{,_UNIT} + and DECL_FIELD_OFFSET. + (scan_sharing_clauses): Adjust install_var_field callers. For + firstprivate clauses on explicit tasks allocate the var by value in + record_type unconditionally, rather than by reference. + (create_omp_child_function_name): Add task_copy argument, use + *_omp_cpyfn* names if it is true. + (create_omp_child_function): Add task_copy argument, if true create + *_omp_cpyfn* helper function. + (scan_omp_parallel): Adjust create_omp_child_function callers. + (scan_omp_task): Likewise. If srecord_type has been created, create + *_omp_cpyfn* helper function too. Set OMP_TASK_ARG_SIZE + and OMP_TASK_ARG_ALIGN. + (lower_rec_input_clauses): Don't run constructors for firstprivate + explicit task vars which are initialized by *_omp_cpyfn*. Kill + OMP_TASK_EXPLICIT_START. Adjust OMP_CLAUSE_PRIVATE_OUTER_REF + handling. Don't add GOMP_task_start call. + (lower_send_clauses): Clear DECL_ABSTRACT_ORIGIN if in task to + avoid duplicate setting of fields. + (lower_send_shared_vars): Use srecord_type if non-NULL. + (expand_task_copyfn): New function. + (expand_task_call): Call expand_task_copyfn. Kill + OMP_TASK_EXPLICIT_START. Pass OMP_TASK_CPYFN, OMP_TASK_ARG_SIZE + and OMP_TASK_ARG_ALIGN as extra arguments to GOMP_task. + (struct omp_taskcopy_context): New type. + (task_copyfn_copy_decl, task_copyfn_remap_type, create_task_copyfn): + New functions. + (lower_omp_taskreg): Call create_task_copyfn if srecord_type is + needed. Adjust sender_decl type. + * tree-pretty-print.c (dump_generic_node) <case OMP_TASK>: Print + OMP_TASK_COPYFN. + + * bitmap.c (bitmap_default_obstack_depth): New variable. + (bitmap_obstack_initialize, bitmap_obstack_release): Do nothing + if argument is NULL and bitmap_default_obstack is already initialized. + * ipa-struct-reorg.c (do_reorg_1): Call bitmap_obstack_release + at the end. + * matrix-reorg.c (matrix_reorg): Likewise. + 2008-04-01 Jakub Jelinek <jakub@redhat.com> * c-parser.c (c_parser_omp_for_loop): Fix parsing of collapsed diff --git a/gcc/bitmap.c b/gcc/bitmap.c index c2a66f96a73..97e60de6b3c 100644 --- a/gcc/bitmap.c +++ b/gcc/bitmap.c @@ -119,6 +119,7 @@ register_overhead (bitmap b, int amount) /* Global data */ bitmap_element bitmap_zero_bits; /* An element of all zero bits. */ bitmap_obstack bitmap_default_obstack; /* The default bitmap obstack. */ +static int bitmap_default_obstack_depth; static GTY((deletable)) bitmap_element *bitmap_ggc_free; /* Freelist of GC'd elements. */ @@ -302,7 +303,11 @@ void bitmap_obstack_initialize (bitmap_obstack *bit_obstack) { if (!bit_obstack) - bit_obstack = &bitmap_default_obstack; + { + if (bitmap_default_obstack_depth++) + return; + bit_obstack = &bitmap_default_obstack; + } #if !defined(__GNUC__) || (__GNUC__ < 2) #define __alignof__(type) 0 @@ -323,7 +328,14 @@ void bitmap_obstack_release (bitmap_obstack *bit_obstack) { if (!bit_obstack) - bit_obstack = &bitmap_default_obstack; + { + if (--bitmap_default_obstack_depth) + { + gcc_assert (bitmap_default_obstack_depth > 0); + return; + } + bit_obstack = &bitmap_default_obstack; + } bit_obstack->elements = NULL; bit_obstack->heads = NULL; diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def index 65e0b759947..5047889880b 100644 --- a/gcc/builtin-types.def +++ b/gcc/builtin-types.def @@ -309,6 +309,8 @@ DEF_FUNCTION_TYPE_2 (BT_FN_I16_VPTR_I16, BT_I16, BT_VOLATILE_PTR, BT_I16) DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_LONGPTR_LONGPTR, BT_BOOL, BT_PTR_LONG, BT_PTR_LONG) +DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR) + DEF_FUNCTION_TYPE_3 (BT_FN_STRING_STRING_CONST_STRING_SIZE, BT_STRING, BT_STRING, BT_CONST_STRING, BT_SIZE) DEF_FUNCTION_TYPE_3 (BT_FN_INT_CONST_STRING_CONST_STRING_SIZE, @@ -393,8 +395,6 @@ DEF_FUNCTION_TYPE_4 (BT_FN_VOID_OMPFN_PTR_UINT_UINT, BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, BT_UINT) DEF_FUNCTION_TYPE_4 (BT_FN_VOID_PTR_WORD_WORD_PTR, BT_VOID, BT_PTR, BT_WORD, BT_WORD, BT_PTR) -DEF_FUNCTION_TYPE_4 (BT_FN_VOID_OMPFN_PTR_BOOL_UINT, BT_VOID, BT_PTR_FN_VOID_PTR, - BT_PTR, BT_BOOL, BT_UINT) DEF_FUNCTION_TYPE_5 (BT_FN_INT_STRING_INT_SIZE_CONST_STRING_VALIST_ARG, BT_INT, BT_STRING, BT_INT, BT_SIZE, BT_CONST_STRING, @@ -416,6 +416,10 @@ DEF_FUNCTION_TYPE_6 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG, DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG, 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) 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/fortran/ChangeLog.gomp b/gcc/fortran/ChangeLog.gomp index 26a5271a16d..c97396e3e10 100644 --- a/gcc/fortran/ChangeLog.gomp +++ b/gcc/fortran/ChangeLog.gomp @@ -1,3 +1,10 @@ +2008-05-14 Jakub Jelinek <jakub@redhat.com> + + * trans-openmp.c (gfc_trans_omp_task): Create OMP_TASK using make_node. + * types.def (BT_FN_VOID_PTR_PTR, BT_PTR_FN_VOID_PTR_PTR, + BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT): New. + (BT_FN_VOID_OMPFN_PTR_BOOL_UINT): Removed. + 2008-03-12 Jakub Jelinek <jakub@redhat.com> * types.def (BT_FN_VOID_OMPFN_PTR_BOOL_BOOL): Remove. diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c index 23f8d03396b..48789dde720 100644 --- a/gcc/fortran/trans-openmp.c +++ b/gcc/fortran/trans-openmp.c @@ -1521,13 +1521,16 @@ static tree gfc_trans_omp_task (gfc_code *code) { stmtblock_t block; - tree stmt, omp_clauses; + tree stmt, body_stmt, omp_clauses; gfc_start_block (&block); omp_clauses = gfc_trans_omp_clauses (&block, code->ext.omp_clauses, code->loc); - stmt = gfc_trans_omp_code (code->block->next, true); - stmt = build4_v (OMP_TASK, stmt, omp_clauses, NULL, NULL); + body_stmt = gfc_trans_omp_code (code->block->next, true); + stmt = make_node (OMP_TASK); + TREE_TYPE (stmt) = void_type_node; + OMP_TASK_CLAUSES (stmt) = omp_clauses; + OMP_TASK_BODY (stmt) = body_stmt; gfc_add_expr_to_block (&block, stmt); return gfc_finish_block (&block); } diff --git a/gcc/fortran/types.def b/gcc/fortran/types.def index 0086f6f3f88..8eebee5bda6 100644 --- a/gcc/fortran/types.def +++ b/gcc/fortran/types.def @@ -93,6 +93,9 @@ DEF_FUNCTION_TYPE_2 (BT_FN_I2_VPTR_I2, BT_I2, BT_VOLATILE_PTR, BT_I2) DEF_FUNCTION_TYPE_2 (BT_FN_I4_VPTR_I4, BT_I4, BT_VOLATILE_PTR, BT_I4) DEF_FUNCTION_TYPE_2 (BT_FN_I8_VPTR_I8, BT_I8, BT_VOLATILE_PTR, BT_I8) DEF_FUNCTION_TYPE_2 (BT_FN_I16_VPTR_I16, BT_I16, BT_VOLATILE_PTR, BT_I16) +DEF_FUNCTION_TYPE_2 (BT_FN_VOID_PTR_PTR, BT_VOID, BT_PTR, BT_PTR) + +DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR) DEF_FUNCTION_TYPE_3 (BT_FN_BOOL_VPTR_I1_I1, BT_BOOL, BT_VOLATILE_PTR, BT_I1, BT_I1) @@ -117,8 +120,6 @@ DEF_FUNCTION_TYPE_4 (BT_FN_VOID_OMPFN_PTR_UINT_UINT, BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, BT_UINT) DEF_FUNCTION_TYPE_4 (BT_FN_VOID_PTR_WORD_WORD_PTR, BT_VOID, BT_PTR, BT_WORD, BT_WORD, BT_PTR) -DEF_FUNCTION_TYPE_4 (BT_FN_VOID_OMPFN_PTR_BOOL_UINT, BT_VOID, - BT_PTR_FN_VOID_PTR, BT_PTR, BT_BOOL, BT_UINT) DEF_FUNCTION_TYPE_5 (BT_FN_BOOL_LONG_LONG_LONG_LONGPTR_LONGPTR, BT_BOOL, BT_LONG, BT_LONG, BT_LONG, @@ -134,5 +135,9 @@ DEF_FUNCTION_TYPE_6 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG, DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG, 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) DEF_FUNCTION_TYPE_VAR_0 (BT_FN_VOID_VAR, BT_VOID) diff --git a/gcc/ipa-struct-reorg.c b/gcc/ipa-struct-reorg.c index 514b9a22898..e10bc93deeb 100644 --- a/gcc/ipa-struct-reorg.c +++ b/gcc/ipa-struct-reorg.c @@ -3727,6 +3727,7 @@ do_reorg_1 (void) } set_cfun (NULL); + bitmap_obstack_release (NULL); } /* This function creates new global struct variables. diff --git a/gcc/matrix-reorg.c b/gcc/matrix-reorg.c index 38b0d5e146b..28badb66390 100644 --- a/gcc/matrix-reorg.c +++ b/gcc/matrix-reorg.c @@ -2236,6 +2236,7 @@ matrix_reorg (void) free_dominance_info (CDI_POST_DOMINATORS); pop_cfun (); current_function_decl = temp_fn; + bitmap_obstack_release (NULL); return 0; } @@ -2250,6 +2251,7 @@ matrix_reorg (void) free_dominance_info (CDI_POST_DOMINATORS); pop_cfun (); current_function_decl = temp_fn; + bitmap_obstack_release (NULL); return 0; } @@ -2280,6 +2282,7 @@ matrix_reorg (void) free_dominance_info (CDI_POST_DOMINATORS); pop_cfun (); current_function_decl = temp_fn; + bitmap_obstack_release (NULL); } htab_traverse (matrices_to_reorg, transform_allocation_sites, NULL); /* Now transform the accesses. */ @@ -2300,6 +2303,7 @@ matrix_reorg (void) free_dominance_info (CDI_POST_DOMINATORS); pop_cfun (); current_function_decl = temp_fn; + bitmap_obstack_release (NULL); } htab_traverse (matrices_to_reorg, dump_matrix_reorg_analysis, NULL); diff --git a/gcc/omp-builtins.def b/gcc/omp-builtins.def index 12e310b1c35..d23d563fc3d 100644 --- a/gcc/omp-builtins.def +++ b/gcc/omp-builtins.def @@ -37,8 +37,6 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_BARRIER, "GOMP_barrier", BT_FN_VOID, ATTR_NOTHROW_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKWAIT, "GOMP_taskwait", BT_FN_VOID, ATTR_NOTHROW_LIST) -DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASK_START, "GOMP_task_start", - BT_FN_VOID, ATTR_NOTHROW_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_CRITICAL_START, "GOMP_critical_start", BT_FN_VOID, ATTR_NOTHROW_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_CRITICAL_END, "GOMP_critical_end", @@ -153,7 +151,8 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_START, "GOMP_parallel_start", DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_END, "GOMP_parallel_end", BT_FN_VOID, ATTR_NOTHROW_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASK, "GOMP_task", - BT_FN_VOID_OMPFN_PTR_BOOL_UINT, ATTR_NOTHROW_LIST) + BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT, + ATTR_NOTHROW_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SECTIONS_START, "GOMP_sections_start", BT_FN_UINT_UINT, ATTR_NOTHROW_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SECTIONS_NEXT, "GOMP_sections_next", diff --git a/gcc/omp-low.c b/gcc/omp-low.c index a640e3222ff..a1d7c994142 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -77,6 +77,14 @@ typedef struct omp_context tree sender_decl; tree receiver_decl; + /* These are used just by task contexts, if task firstprivate fn is + needed. srecord_type is used to communicate from the thread + that encountered the task construct to task firstprivate fn, + record_type is allocated by GOMP_task, initialized by task firstprivate + fn and passed to the task body fn. */ + splay_tree sfield_map; + tree srecord_type; + /* A chain of variables to add to the top-level block surrounding the construct. In the case of a parallel, this is in the child function. */ tree block_vars; @@ -146,6 +154,15 @@ is_parallel_ctx (omp_context *ctx) } +/* Return true if CTX is for an omp task. */ + +static inline bool +is_task_ctx (omp_context *ctx) +{ + return TREE_CODE (ctx->stmt) == OMP_TASK; +} + + /* Return true if CTX is for an omp parallel or omp task. */ static inline bool @@ -576,6 +593,16 @@ lookup_field (tree var, omp_context *ctx) } static inline tree +lookup_sfield (tree var, omp_context *ctx) +{ + splay_tree_node n; + n = splay_tree_lookup (ctx->sfield_map + ? ctx->sfield_map : ctx->field_map, + (splay_tree_key) var); + return (tree) n->value; +} + +static inline tree maybe_lookup_field (tree var, omp_context *ctx) { splay_tree_node n; @@ -647,8 +674,7 @@ use_pointer_for_field (tree decl, omp_context *shared_ctx) (in which case just copy-in is used). As tasks can be deferred or executed in different thread, when GOMP_task returns, the task hasn't necessarily terminated. */ - if (!TREE_READONLY (decl) - && TREE_CODE (shared_ctx->stmt) == OMP_TASK) + if (!TREE_READONLY (decl) && is_task_ctx (shared_ctx)) { tree outer = maybe_lookup_decl_in_outer_ctx (decl, shared_ctx); if (is_gimple_reg (outer)) @@ -772,7 +798,7 @@ build_outer_var_ref (tree var, omp_context *ctx) static tree build_sender_ref (tree var, omp_context *ctx) { - tree field = lookup_field (var, ctx); + tree field = lookup_sfield (var, ctx); return build3 (COMPONENT_REF, TREE_TYPE (field), ctx->sender_decl, field, NULL); } @@ -780,15 +806,20 @@ build_sender_ref (tree var, omp_context *ctx) /* Add a new field for VAR inside the structure CTX->SENDER_DECL. */ static void -install_var_field (tree var, bool by_ref, omp_context *ctx) +install_var_field (tree var, bool by_ref, int mask, omp_context *ctx) { - tree field, type; + tree field, type, sfield = NULL_TREE; - gcc_assert (!splay_tree_lookup (ctx->field_map, (splay_tree_key) var)); + gcc_assert ((mask & 1) == 0 + || !splay_tree_lookup (ctx->field_map, (splay_tree_key) var)); + gcc_assert ((mask & 2) == 0 || !ctx->sfield_map + || !splay_tree_lookup (ctx->sfield_map, (splay_tree_key) var)); type = TREE_TYPE (var); if (by_ref) type = build_pointer_type (type); + else if ((mask & 3) == 1 && is_reference (var)) + type = TREE_TYPE (type); field = build_decl (FIELD_DECL, DECL_NAME (var), type); @@ -796,11 +827,57 @@ install_var_field (tree var, bool by_ref, omp_context *ctx) side effect of making dwarf2out ignore this member, so for helpful debugging we clear it later in delete_omp_context. */ DECL_ABSTRACT_ORIGIN (field) = var; + if (type == TREE_TYPE (var)) + { + DECL_ALIGN (field) = DECL_ALIGN (var); + DECL_USER_ALIGN (field) = DECL_USER_ALIGN (var); + TREE_THIS_VOLATILE (field) = TREE_THIS_VOLATILE (var); + } + else + DECL_ALIGN (field) = TYPE_ALIGN (type); + + if ((mask & 3) == 3) + { + insert_field_into_struct (ctx->record_type, field); + if (ctx->srecord_type) + { + sfield = build_decl (FIELD_DECL, DECL_NAME (var), type); + DECL_ABSTRACT_ORIGIN (sfield) = var; + DECL_ALIGN (sfield) = DECL_ALIGN (field); + DECL_USER_ALIGN (sfield) = DECL_USER_ALIGN (field); + TREE_THIS_VOLATILE (sfield) = TREE_THIS_VOLATILE (field); + insert_field_into_struct (ctx->srecord_type, sfield); + } + } + else + { + if (ctx->srecord_type == NULL_TREE) + { + tree t; - insert_field_into_struct (ctx->record_type, field); + ctx->srecord_type = lang_hooks.types.make_type (RECORD_TYPE); + ctx->sfield_map = splay_tree_new (splay_tree_compare_pointers, 0, 0); + for (t = TYPE_FIELDS (ctx->record_type); t ; t = TREE_CHAIN (t)) + { + sfield = build_decl (FIELD_DECL, DECL_NAME (t), TREE_TYPE (t)); + DECL_ABSTRACT_ORIGIN (sfield) = DECL_ABSTRACT_ORIGIN (t); + insert_field_into_struct (ctx->srecord_type, sfield); + splay_tree_insert (ctx->sfield_map, + (splay_tree_key) DECL_ABSTRACT_ORIGIN (t), + (splay_tree_value) sfield); + } + } + sfield = field; + insert_field_into_struct ((mask & 1) ? ctx->record_type + : ctx->srecord_type, field); + } - splay_tree_insert (ctx->field_map, (splay_tree_key) var, - (splay_tree_value) field); + if (mask & 1) + splay_tree_insert (ctx->field_map, (splay_tree_key) var, + (splay_tree_value) field); + if ((mask & 2) && ctx->sfield_map) + splay_tree_insert (ctx->sfield_map, (splay_tree_key) var, + (splay_tree_value) sfield); } static tree @@ -1037,6 +1114,8 @@ delete_omp_context (splay_tree_value value) if (ctx->field_map) splay_tree_delete (ctx->field_map); + if (ctx->sfield_map) + splay_tree_delete (ctx->sfield_map); /* We hijacked DECL_ABSTRACT_ORIGIN earlier. We need to clear it before it produces corrupt debug information. */ @@ -1046,6 +1125,12 @@ delete_omp_context (splay_tree_value value) for (t = TYPE_FIELDS (ctx->record_type); t ; t = TREE_CHAIN (t)) DECL_ABSTRACT_ORIGIN (t) = NULL; } + if (ctx->srecord_type) + { + tree t; + for (t = TYPE_FIELDS (ctx->srecord_type); t ; t = TREE_CHAIN (t)) + DECL_ABSTRACT_ORIGIN (t) = NULL; + } XDELETE (ctx); } @@ -1080,6 +1165,9 @@ fixup_child_record_type (omp_context *ctx) DECL_CONTEXT (new_f) = type; TREE_TYPE (new_f) = remap_type (TREE_TYPE (f), &ctx->cb); TREE_CHAIN (new_f) = new_fields; + walk_tree (&DECL_SIZE (new_f), copy_body_r, &ctx->cb, NULL); + walk_tree (&DECL_SIZE_UNIT (new_f), copy_body_r, &ctx->cb, NULL); + walk_tree (&DECL_FIELD_OFFSET (new_f), copy_body_r, &ctx->cb, NULL); new_fields = new_f; /* Arrange to be able to look up the receiver field @@ -1131,7 +1219,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) || by_ref || is_reference (decl)) { - install_var_field (decl, by_ref, ctx); + install_var_field (decl, by_ref, 3, ctx); install_var_local (decl, ctx); break; } @@ -1151,13 +1239,26 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) decl = OMP_CLAUSE_DECL (c); do_private: if (is_variable_sized (decl)) - break; - else if (is_taskreg_ctx (ctx) - && ! is_global_var (maybe_lookup_decl_in_outer_ctx (decl, - ctx))) { + if (is_task_ctx (ctx)) + install_var_field (decl, false, 1, ctx); + break; + } + else if (is_taskreg_ctx (ctx)) + { + bool global + = is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx)); by_ref = use_pointer_for_field (decl, NULL); - install_var_field (decl, by_ref, ctx); + + if (is_task_ctx (ctx) + && (global || by_ref || is_reference (decl))) + { + install_var_field (decl, false, 1, ctx); + if (!global) + install_var_field (decl, by_ref, 2, ctx); + } + else if (!global) + install_var_field (decl, by_ref, 3, ctx); } install_var_local (decl, ctx); break; @@ -1170,7 +1271,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_COPYIN: decl = OMP_CLAUSE_DECL (c); by_ref = use_pointer_for_field (decl, NULL); - install_var_field (decl, by_ref, ctx); + install_var_field (decl, by_ref, 3, ctx); break; case OMP_CLAUSE_DEFAULT: @@ -1263,15 +1364,17 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) static GTY(()) unsigned int tmp_ompfn_id_num; static tree -create_omp_child_function_name (void) +create_omp_child_function_name (bool task_copy) { tree name = DECL_ASSEMBLER_NAME (current_function_decl); size_t len = IDENTIFIER_LENGTH (name); char *tmp_name, *prefix; + const char *suffix; - prefix = alloca (len + sizeof ("_omp_fn")); + suffix = task_copy ? "_omp_cpyfn" : "_omp_fn"; + prefix = alloca (len + strlen (suffix) + 1); memcpy (prefix, IDENTIFIER_POINTER (name), len); - strcpy (prefix + len, "_omp_fn"); + strcpy (prefix + len, suffix); #ifndef NO_DOT_IN_LABEL prefix[len] = '.'; #elif !defined NO_DOLLAR_IN_LABEL @@ -1285,17 +1388,24 @@ create_omp_child_function_name (void) yet, just the bare decl. */ static void -create_omp_child_function (omp_context *ctx) +create_omp_child_function (omp_context *ctx, bool task_copy) { tree decl, type, name, t; - name = create_omp_child_function_name (); - type = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE); + name = create_omp_child_function_name (task_copy); + if (task_copy) + type = build_function_type_list (void_type_node, ptr_type_node, + ptr_type_node, NULL_TREE); + else + type = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE); decl = build_decl (FUNCTION_DECL, name, type); decl = lang_hooks.decls.pushdecl (decl); - ctx->cb.dst_fn = decl; + if (!task_copy) + ctx->cb.dst_fn = decl; + else + OMP_TASK_COPYFN (ctx->stmt) = decl; TREE_STATIC (decl) = 1; TREE_USED (decl) = 1; @@ -1318,7 +1428,19 @@ create_omp_child_function (omp_context *ctx) DECL_CONTEXT (t) = current_function_decl; TREE_USED (t) = 1; DECL_ARGUMENTS (decl) = t; - ctx->receiver_decl = t; + if (!task_copy) + ctx->receiver_decl = t; + else + { + t = build_decl (PARM_DECL, get_identifier (".omp_data_o"), + ptr_type_node); + DECL_ARTIFICIAL (t) = 1; + DECL_ARG_TYPE (t) = ptr_type_node; + DECL_CONTEXT (t) = current_function_decl; + TREE_USED (t) = 1; + TREE_CHAIN (t) = DECL_ARGUMENTS (decl); + DECL_ARGUMENTS (decl) = t; + } /* Allocate memory for the function structure. The call to allocate_struct_function clobbers CFUN, so we need to restore @@ -1357,7 +1479,7 @@ scan_omp_parallel (tree *stmt_p, omp_context *outer_ctx) name = create_tmp_var_name (".omp_data_s"); name = build_decl (TYPE_DECL, name, ctx->record_type); TYPE_NAME (ctx->record_type) = name; - create_omp_child_function (ctx); + create_omp_child_function (ctx, false); OMP_PARALLEL_FN (*stmt_p) = ctx->cb.dst_fn; scan_sharing_clauses (OMP_PARALLEL_CLAUSES (*stmt_p), ctx); @@ -1397,18 +1519,56 @@ scan_omp_task (tree *stmt_p, omp_context *outer_ctx) name = create_tmp_var_name (".omp_data_s"); name = build_decl (TYPE_DECL, name, ctx->record_type); TYPE_NAME (ctx->record_type) = name; - create_omp_child_function (ctx); + create_omp_child_function (ctx, false); OMP_TASK_FN (*stmt_p) = ctx->cb.dst_fn; scan_sharing_clauses (OMP_TASK_CLAUSES (*stmt_p), ctx); + + if (ctx->srecord_type) + { + name = create_tmp_var_name (".omp_data_a"); + name = build_decl (TYPE_DECL, name, ctx->srecord_type); + TYPE_NAME (ctx->srecord_type) = name; + create_omp_child_function (ctx, true); + } + scan_omp (&OMP_TASK_BODY (*stmt_p), ctx); if (TYPE_FIELDS (ctx->record_type) == NULL) - ctx->record_type = ctx->receiver_decl = NULL; + { + ctx->record_type = ctx->receiver_decl = NULL; + OMP_TASK_ARG_SIZE (*stmt_p) + = build_int_cst (long_integer_type_node, 0); + OMP_TASK_ARG_ALIGN (*stmt_p) + = build_int_cst (long_integer_type_node, 1); + } else { + tree *p, vla_fields = NULL_TREE, *q = &vla_fields; + /* Move VLA fields to the end. */ + p = &TYPE_FIELDS (ctx->record_type); + while (*p) + if (!TYPE_SIZE_UNIT (TREE_TYPE (*p)) + || ! TREE_CONSTANT (TYPE_SIZE_UNIT (TREE_TYPE (*p)))) + { + *q = *p; + *p = TREE_CHAIN (*p); + TREE_CHAIN (*q) = NULL_TREE; + q = &TREE_CHAIN (*q); + } + else + p = &TREE_CHAIN (*p); + *p = vla_fields; layout_type (ctx->record_type); fixup_child_record_type (ctx); + if (ctx->srecord_type) + layout_type (ctx->srecord_type); + OMP_TASK_ARG_SIZE (*stmt_p) + = fold_convert (long_integer_type_node, + TYPE_SIZE_UNIT (ctx->record_type)); + OMP_TASK_ARG_ALIGN (*stmt_p) + = build_int_cst (long_integer_type_node, + TYPE_ALIGN_UNIT (ctx->record_type)); } } @@ -1922,16 +2082,18 @@ lower_rec_input_clauses (tree clauses, tree *ilist, tree *dlist, if (pass == 0) continue; - ptr = DECL_VALUE_EXPR (new_var); - gcc_assert (TREE_CODE (ptr) == INDIRECT_REF); - ptr = TREE_OPERAND (ptr, 0); - gcc_assert (DECL_P (ptr)); - - x = TYPE_SIZE_UNIT (TREE_TYPE (new_var)); - x = build_call_expr (built_in_decls[BUILT_IN_ALLOCA], 1, x); - x = fold_convert (TREE_TYPE (ptr), x); - x = build_gimple_modify_stmt (ptr, x); - gimplify_and_add (x, ilist); + if (c_kind != OMP_CLAUSE_FIRSTPRIVATE || !is_task_ctx (ctx)) + { + ptr = DECL_VALUE_EXPR (new_var); + gcc_assert (TREE_CODE (ptr) == INDIRECT_REF); + ptr = TREE_OPERAND (ptr, 0); + gcc_assert (DECL_P (ptr)); + x = TYPE_SIZE_UNIT (TREE_TYPE (new_var)); + x = build_call_expr (built_in_decls[BUILT_IN_ALLOCA], 1, x); + x = fold_convert (TREE_TYPE (ptr), x); + x = build_gimple_modify_stmt (ptr, x); + gimplify_and_add (x, ilist); + } } else if (is_reference (var)) { @@ -1947,7 +2109,12 @@ lower_rec_input_clauses (tree clauses, tree *ilist, tree *dlist, continue; x = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (new_var))); - if (TREE_CONSTANT (x)) + if (c_kind == OMP_CLAUSE_FIRSTPRIVATE && is_task_ctx (ctx)) + { + x = build_receiver_ref (var, false, ctx); + x = build_fold_addr_expr (x); + } + else if (TREE_CONSTANT (x)) { const char *name = NULL; if (DECL_NAME (var)) @@ -2007,13 +2174,14 @@ lower_rec_input_clauses (tree clauses, tree *ilist, tree *dlist, /* FALLTHRU */ case OMP_CLAUSE_PRIVATE: - if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_PRIVATE - || OMP_CLAUSE_PRIVATE_OUTER_REF (c)) + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_PRIVATE) + x = build_outer_var_ref (var, ctx); + else if (OMP_CLAUSE_PRIVATE_OUTER_REF (c)) { - x = build_outer_var_ref (var, ctx); - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE - && TREE_CODE (ctx->stmt) == OMP_TASK) - OMP_TASK_EXPLICIT_START (ctx->stmt) = 1; + if (is_task_ctx (ctx)) + x = build_receiver_ref (var, false, ctx); + else + x = build_outer_var_ref (var, ctx); } else x = NULL; @@ -2033,17 +2201,23 @@ lower_rec_input_clauses (tree clauses, tree *ilist, tree *dlist, break; case OMP_CLAUSE_FIRSTPRIVATE: + if (is_task_ctx (ctx)) + { + if (is_reference (var) || is_variable_sized (var)) + goto do_dtor; + else if (is_global_var (maybe_lookup_decl_in_outer_ctx (var, + ctx)) + || use_pointer_for_field (var, NULL)) + { + x = build_receiver_ref (var, false, ctx); + SET_DECL_VALUE_EXPR (new_var, x); + DECL_HAS_VALUE_EXPR_P (new_var) = 1; + goto do_dtor; + } + } x = build_outer_var_ref (var, ctx); x = lang_hooks.decls.omp_clause_copy_ctor (c, new_var, x); gimplify_and_add (x, ilist); - if (TREE_CODE (ctx->stmt) == OMP_TASK) - { - if (is_global_var (maybe_lookup_decl_in_outer_ctx (var, - ctx)) - || is_variable_sized (var) - || use_pointer_for_field (var, NULL)) - OMP_TASK_EXPLICIT_START (ctx->stmt) = 1; - } goto do_dtor; break; @@ -2103,14 +2277,6 @@ lower_rec_input_clauses (tree clauses, tree *ilist, tree *dlist, happens after firstprivate copying in all threads. */ if (copyin_by_ref || lastprivate_firstprivate) gimplify_and_add (build_omp_barrier (), ilist); - - if (TREE_CODE (ctx->stmt) == OMP_TASK - && OMP_TASK_EXPLICIT_START (ctx->stmt)) - { - x = built_in_decls[BUILT_IN_GOMP_TASK_START]; - x = build_call_expr (x, 0); - gimplify_and_add (x, ilist); - } } @@ -2396,6 +2562,8 @@ lower_send_clauses (tree clauses, tree *ilist, tree *olist, omp_context *ctx) x = by_ref ? build_fold_addr_expr (var) : var; x = build_gimple_modify_stmt (ref, x); gimplify_and_add (x, ilist); + if (is_task_ctx (ctx)) + DECL_ABSTRACT_ORIGIN (TREE_OPERAND (ref, 1)) = NULL; } if (do_out) @@ -2414,12 +2582,13 @@ lower_send_clauses (tree clauses, tree *ilist, tree *olist, omp_context *ctx) static void lower_send_shared_vars (tree *ilist, tree *olist, omp_context *ctx) { - tree var, ovar, nvar, f, x; + tree var, ovar, nvar, f, x, record_type; if (ctx->record_type == NULL) return; - for (f = TYPE_FIELDS (ctx->record_type); f ; f = TREE_CHAIN (f)) + record_type = ctx->srecord_type ? ctx->srecord_type : ctx->record_type; + for (f = TYPE_FIELDS (record_type); f ; f = TREE_CHAIN (f)) { ovar = DECL_ABSTRACT_ORIGIN (f); nvar = maybe_lookup_decl (ovar, ctx); @@ -2623,17 +2792,50 @@ expand_parallel_call (struct omp_region *region, basic_block bb, } +static void maybe_catch_exception (tree *stmt_p); + + +/* Finalize task copyfn. */ + +static void +expand_task_copyfn (tree task_stmt) +{ + struct function *child_cfun; + tree child_fn, old_fn; + + child_fn = OMP_TASK_COPYFN (task_stmt); + child_cfun = DECL_STRUCT_FUNCTION (child_fn); + + /* Inform the callgraph about the new function. */ + DECL_STRUCT_FUNCTION (child_fn)->curr_properties + = cfun->curr_properties; + + old_fn = current_function_decl; + push_cfun (child_cfun); + current_function_decl = child_fn; + gimplify_body (&DECL_SAVED_TREE (child_fn), child_fn, false); + maybe_catch_exception (&BIND_EXPR_BODY (DECL_SAVED_TREE (child_fn))); + child_cfun->gimplified = true; + pop_cfun (); + current_function_decl = old_fn; + + cgraph_add_new_function (child_fn, false); +} + /* Build the function call to GOMP_task to actually generate the task operation. BB is the block where to insert the code. */ static void expand_task_call (basic_block bb, tree entry_stmt) { - tree t, t1, t2, flags, cond, c, clauses; + tree t, t1, t2, t3, flags, cond, c, clauses; block_stmt_iterator si; clauses = OMP_TASK_CLAUSES (entry_stmt); + if (OMP_TASK_COPYFN (entry_stmt)) + expand_task_copyfn (entry_stmt); + c = find_omp_clause (clauses, OMP_CLAUSE_IF); if (c) cond = gimple_boolify (OMP_CLAUSE_IF_EXPR (c)); @@ -2641,20 +2843,24 @@ expand_task_call (basic_block bb, tree entry_stmt) cond = boolean_true_node; c = find_omp_clause (clauses, OMP_CLAUSE_UNTIED); - flags = build_int_cst (unsigned_type_node, - (c ? 1 : 0) - | (OMP_TASK_EXPLICIT_START (entry_stmt) ? 2 : 0)); + flags = build_int_cst (unsigned_type_node, (c ? 1 : 0)); si = bsi_last (bb); t = OMP_TASK_DATA_ARG (entry_stmt); if (t == NULL) - t1 = null_pointer_node; + t2 = null_pointer_node; else - t1 = build_fold_addr_expr (t); - t2 = build_fold_addr_expr (OMP_TASK_FN (entry_stmt)); + t2 = build_fold_addr_expr (t); + t1 = build_fold_addr_expr (OMP_TASK_FN (entry_stmt)); + t = OMP_TASK_COPYFN (entry_stmt); + if (t == NULL) + t3 = null_pointer_node; + else + t3 = build_fold_addr_expr (t); - t = build_call_expr (built_in_decls[BUILT_IN_GOMP_TASK], 4, t2, t1, - cond, flags); + t = build_call_expr (built_in_decls[BUILT_IN_GOMP_TASK], 7, t1, t2, t3, + OMP_TASK_ARG_SIZE (entry_stmt), + OMP_TASK_ARG_ALIGN (entry_stmt), cond, flags); force_gimple_operand_bsi (&si, t, true, NULL_TREE, false, BSI_CONTINUE_LINKING); @@ -5332,6 +5538,284 @@ check_combined_parallel (tree *tp, int *walk_subtrees, void *data) return NULL; } +struct omp_taskcopy_context +{ + /* This field must be at the beginning, as we do "inheritance": Some + callback functions for tree-inline.c (e.g., omp_copy_decl) + receive a copy_body_data pointer that is up-casted to an + omp_context pointer. */ + copy_body_data cb; + omp_context *ctx; +}; + +static tree +task_copyfn_copy_decl (tree var, copy_body_data *cb) +{ + struct omp_taskcopy_context *tcctx = (struct omp_taskcopy_context *) cb; + + if (splay_tree_lookup (tcctx->ctx->sfield_map, (splay_tree_key) var)) + return create_tmp_var (TREE_TYPE (var), NULL); + + return var; +} + +static tree +task_copyfn_remap_type (struct omp_taskcopy_context *tcctx, tree orig_type) +{ + tree name, new_fields = NULL, type, f; + + type = lang_hooks.types.make_type (RECORD_TYPE); + name = DECL_NAME (TYPE_NAME (orig_type)); + name = build_decl (TYPE_DECL, name, type); + TYPE_NAME (type) = name; + + for (f = TYPE_FIELDS (orig_type); f ; f = TREE_CHAIN (f)) + { + tree new_f = copy_node (f); + DECL_CONTEXT (new_f) = type; + TREE_TYPE (new_f) = remap_type (TREE_TYPE (f), &tcctx->cb); + TREE_CHAIN (new_f) = new_fields; + walk_tree (&DECL_SIZE (new_f), copy_body_r, &tcctx->cb, NULL); + walk_tree (&DECL_SIZE_UNIT (new_f), copy_body_r, &tcctx->cb, NULL); + walk_tree (&DECL_FIELD_OFFSET (new_f), copy_body_r, &tcctx->cb, NULL); + new_fields = new_f; + *pointer_map_insert (tcctx->cb.decl_map, f) = new_f; + } + TYPE_FIELDS (type) = nreverse (new_fields); + layout_type (type); + return type; +} + +/* Create task copyfn. */ + +static void +create_task_copyfn (tree task_stmt, omp_context *ctx) +{ + struct function *child_cfun; + tree child_fn, t, c, src, dst, f, sf, arg, sarg, decl; + tree record_type, srecord_type, bind, list; + bool record_needs_remap = false, srecord_needs_remap = false; + splay_tree_node n; + struct omp_taskcopy_context tcctx; + + child_fn = OMP_TASK_COPYFN (task_stmt); + child_cfun = DECL_STRUCT_FUNCTION (child_fn); + gcc_assert (child_cfun->cfg == NULL); + child_cfun->x_dont_save_pending_sizes_p = 1; + DECL_SAVED_TREE (child_fn) = alloc_stmt_list (); + + /* Reset DECL_CONTEXT on function arguments. */ + for (t = DECL_ARGUMENTS (child_fn); t; t = TREE_CHAIN (t)) + DECL_CONTEXT (t) = child_fn; + + /* Populate the function. */ + push_cfun (child_cfun); + push_gimplify_context (); + current_function_decl = child_fn; + + bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL); + TREE_SIDE_EFFECTS (bind) = 1; + list = NULL; + DECL_SAVED_TREE (child_fn) = bind; + DECL_SOURCE_LOCATION (child_fn) = EXPR_LOCATION (task_stmt); + + /* Remap src and dst argument types if needed. */ + record_type = ctx->record_type; + srecord_type = ctx->srecord_type; + for (f = TYPE_FIELDS (record_type); f ; f = TREE_CHAIN (f)) + if (variably_modified_type_p (TREE_TYPE (f), ctx->cb.src_fn)) + { + record_needs_remap = true; + break; + } + for (f = TYPE_FIELDS (srecord_type); f ; f = TREE_CHAIN (f)) + if (variably_modified_type_p (TREE_TYPE (f), ctx->cb.src_fn)) + { + srecord_needs_remap = true; + break; + } + + if (record_needs_remap || srecord_needs_remap) + { + memset (&tcctx, '\0', sizeof (tcctx)); + tcctx.cb.src_fn = ctx->cb.src_fn; + tcctx.cb.dst_fn = child_fn; + tcctx.cb.src_node = cgraph_node (tcctx.cb.src_fn); + tcctx.cb.dst_node = tcctx.cb.src_node; + tcctx.cb.src_cfun = ctx->cb.src_cfun; + tcctx.cb.copy_decl = task_copyfn_copy_decl; + tcctx.cb.eh_region = -1; + tcctx.cb.transform_call_graph_edges = CB_CGE_MOVE; + tcctx.cb.decl_map = pointer_map_create (); + tcctx.ctx = ctx; + + if (record_needs_remap) + record_type = task_copyfn_remap_type (&tcctx, record_type); + if (srecord_needs_remap) + srecord_type = task_copyfn_remap_type (&tcctx, srecord_type); + } + else + tcctx.cb.decl_map = NULL; + + arg = DECL_ARGUMENTS (child_fn); + TREE_TYPE (arg) = build_pointer_type (record_type); + sarg = TREE_CHAIN (arg); + TREE_TYPE (sarg) = build_pointer_type (srecord_type); + + /* First pass: initialize temporaries used in record_type and srecord_type + sizes and field offsets. */ + if (tcctx.cb.decl_map) + for (c = OMP_TASK_CLAUSES (task_stmt); c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE) + { + tree *p; + + decl = OMP_CLAUSE_DECL (c); + p = (tree *) pointer_map_contains (tcctx.cb.decl_map, decl); + if (p == NULL) + continue; + n = splay_tree_lookup (ctx->sfield_map, (splay_tree_key) decl); + sf = (tree) n->value; + sf = *(tree *) pointer_map_contains (tcctx.cb.decl_map, sf); + src = build_fold_indirect_ref (sarg); + src = build3 (COMPONENT_REF, TREE_TYPE (sf), src, sf, NULL); + t = build_gimple_modify_stmt (*p, src); + append_to_statement_list (t, &list); + } + + /* Second pass: copy shared var pointers and copy construct non-VLA + firstprivate vars. */ + for (c = OMP_TASK_CLAUSES (task_stmt); c; c = OMP_CLAUSE_CHAIN (c)) + switch (OMP_CLAUSE_CODE (c)) + { + case OMP_CLAUSE_SHARED: + decl = OMP_CLAUSE_DECL (c); + n = splay_tree_lookup (ctx->field_map, (splay_tree_key) decl); + if (n == NULL) + break; + f = (tree) n->value; + if (tcctx.cb.decl_map) + f = *(tree *) pointer_map_contains (tcctx.cb.decl_map, f); + n = splay_tree_lookup (ctx->sfield_map, (splay_tree_key) decl); + sf = (tree) n->value; + if (tcctx.cb.decl_map) + sf = *(tree *) pointer_map_contains (tcctx.cb.decl_map, sf); + src = build_fold_indirect_ref (sarg); + src = build3 (COMPONENT_REF, TREE_TYPE (sf), src, sf, NULL); + dst = build_fold_indirect_ref (arg); + dst = build3 (COMPONENT_REF, TREE_TYPE (f), dst, f, NULL); + t = build_gimple_modify_stmt (dst, src); + append_to_statement_list (t, &list); + break; + case OMP_CLAUSE_FIRSTPRIVATE: + decl = OMP_CLAUSE_DECL (c); + if (is_variable_sized (decl)) + break; + n = splay_tree_lookup (ctx->field_map, (splay_tree_key) decl); + if (n == NULL) + break; + f = (tree) n->value; + if (tcctx.cb.decl_map) + f = *(tree *) pointer_map_contains (tcctx.cb.decl_map, f); + n = splay_tree_lookup (ctx->sfield_map, (splay_tree_key) decl); + if (n != NULL) + { + sf = (tree) n->value; + if (tcctx.cb.decl_map) + sf = *(tree *) pointer_map_contains (tcctx.cb.decl_map, sf); + src = build_fold_indirect_ref (sarg); + src = build3 (COMPONENT_REF, TREE_TYPE (sf), src, sf, NULL); + if (use_pointer_for_field (decl, NULL) || is_reference (decl)) + src = build_fold_indirect_ref (src); + } + else + src = decl; + dst = build_fold_indirect_ref (arg); + dst = build3 (COMPONENT_REF, TREE_TYPE (f), dst, f, NULL); + t = lang_hooks.decls.omp_clause_copy_ctor (c, dst, src); + append_to_statement_list (t, &list); + break; + case OMP_CLAUSE_PRIVATE: + if (! OMP_CLAUSE_PRIVATE_OUTER_REF (c)) + break; + decl = OMP_CLAUSE_DECL (c); + n = splay_tree_lookup (ctx->field_map, (splay_tree_key) decl); + f = (tree) n->value; + if (tcctx.cb.decl_map) + f = *(tree *) pointer_map_contains (tcctx.cb.decl_map, f); + n = splay_tree_lookup (ctx->sfield_map, (splay_tree_key) decl); + if (n != NULL) + { + sf = (tree) n->value; + if (tcctx.cb.decl_map) + sf = *(tree *) pointer_map_contains (tcctx.cb.decl_map, sf); + src = build_fold_indirect_ref (sarg); + src = build3 (COMPONENT_REF, TREE_TYPE (sf), src, sf, NULL); + if (use_pointer_for_field (decl, NULL)) + src = build_fold_indirect_ref (src); + } + else + src = decl; + dst = build_fold_indirect_ref (arg); + dst = build3 (COMPONENT_REF, TREE_TYPE (f), dst, f, NULL); + t = build_gimple_modify_stmt (dst, src); + append_to_statement_list (t, &list); + break; + default: + break; + } + + /* Last pass: handle VLA firstprivates. */ + if (tcctx.cb.decl_map) + for (c = OMP_TASK_CLAUSES (task_stmt); c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE) + { + tree ind, ptr, df; + + decl = OMP_CLAUSE_DECL (c); + if (!is_variable_sized (decl)) + continue; + n = splay_tree_lookup (ctx->field_map, (splay_tree_key) decl); + if (n == NULL) + continue; + f = (tree) n->value; + f = *(tree *) pointer_map_contains (tcctx.cb.decl_map, f); + gcc_assert (DECL_HAS_VALUE_EXPR_P (decl)); + ind = DECL_VALUE_EXPR (decl); + gcc_assert (TREE_CODE (ind) == INDIRECT_REF); + gcc_assert (DECL_P (TREE_OPERAND (ind, 0))); + n = splay_tree_lookup (ctx->sfield_map, + (splay_tree_key) TREE_OPERAND (ind, 0)); + sf = (tree) n->value; + sf = *(tree *) pointer_map_contains (tcctx.cb.decl_map, sf); + src = build_fold_indirect_ref (sarg); + src = build3 (COMPONENT_REF, TREE_TYPE (sf), src, sf, NULL); + src = build_fold_indirect_ref (src); + dst = build_fold_indirect_ref (arg); + dst = build3 (COMPONENT_REF, TREE_TYPE (f), dst, f, NULL); + t = lang_hooks.decls.omp_clause_copy_ctor (c, dst, src); + append_to_statement_list (t, &list); + n = splay_tree_lookup (ctx->field_map, + (splay_tree_key) TREE_OPERAND (ind, 0)); + df = (tree) n->value; + df = *(tree *) pointer_map_contains (tcctx.cb.decl_map, df); + ptr = build_fold_indirect_ref (arg); + ptr = build3 (COMPONENT_REF, TREE_TYPE (df), ptr, df, NULL); + t = build_gimple_modify_stmt (ptr, build_fold_addr_expr (dst)); + append_to_statement_list (t, &list); + } + + t = build1 (RETURN_EXPR, void_type_node, NULL); + append_to_statement_list (t, &list); + + if (tcctx.cb.decl_map) + pointer_map_destroy (tcctx.cb.decl_map); + pop_gimplify_context (NULL); + BIND_EXPR_BODY (bind) = list; + pop_cfun (); + current_function_decl = ctx->cb.src_fn; +} + /* Lower the OpenMP parallel or task directive in *STMT_P. CTX holds context information for the directive. */ @@ -5361,6 +5845,8 @@ lower_omp_taskreg (tree *stmt_p, omp_context *ctx) if (ws_num == 1) OMP_PARALLEL_COMBINED (stmt) = 1; } + if (ctx->srecord_type) + create_task_copyfn (stmt, ctx); push_gimplify_context (); @@ -5378,7 +5864,9 @@ lower_omp_taskreg (tree *stmt_p, omp_context *ctx) if (ctx->record_type) { - ctx->sender_decl = create_tmp_var (ctx->record_type, ".omp_data_o"); + ctx->sender_decl + = create_tmp_var (ctx->srecord_type ? ctx->srecord_type + : ctx->record_type, ".omp_data_o"); OMP_TASKREG_DATA_ARG (stmt) = ctx->sender_decl; } diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index bfce19b1c0b..6eb6426154e 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -1887,7 +1887,14 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, else pp_string (buffer, "???"); - pp_string (buffer, ")]"); + pp_character (buffer, ')'); + if (OMP_TASK_COPYFN (node)) + { + pp_string (buffer, ", copy fn: "); + dump_generic_node (buffer, OMP_TASK_COPYFN (node), spc, + flags, false); + } + pp_character (buffer, ']'); } goto dump_omp_body; diff --git a/gcc/tree.def b/gcc/tree.def index a0b54d53e07..e7b09a28953 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -1002,9 +1002,14 @@ DEFTREECODE (OMP_PARALLEL, "omp_parallel", tcc_statement, 4) pass_lower_omp. Operand 3: OMP_TASK_DATA_ARG: Local variable in the parent function containing data to be shared with the child - function. */ - -DEFTREECODE (OMP_TASK, "omp_task", tcc_statement, 4) + function. + Operand 4: OMP_TASK_COPYFN: FUNCTION_DECL used for constructing + firstprivate variables. + Operand 5: OMP_TASK_ARG_SIZE: Length of the task argument block. + Operand 6: OMP_TASK_ARG_ALIGN: Required alignment of the task + argument block. */ + +DEFTREECODE (OMP_TASK, "omp_task", tcc_statement, 7) /* OpenMP - #pragma omp for [clause1 ... clauseN] Operand 0: OMP_FOR_BODY: Loop body. diff --git a/gcc/tree.h b/gcc/tree.h index b139aed5e52..aa7e4862281 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -501,8 +501,6 @@ struct gimple_stmt GTY(()) OMP_SECTION OMP_PARALLEL_COMBINED in OMP_PARALLEL - OMP_TASK_EXPLICIT_START in - OMP_TASK OMP_CLAUSE_PRIVATE_OUTER_REF in OMP_CLAUSE_PRIVATE @@ -1752,6 +1750,9 @@ struct tree_constructor GTY(()) #define OMP_TASK_CLAUSES(NODE) TREE_OPERAND (OMP_TASK_CHECK (NODE), 1) #define OMP_TASK_FN(NODE) TREE_OPERAND (OMP_TASK_CHECK (NODE), 2) #define OMP_TASK_DATA_ARG(NODE) TREE_OPERAND (OMP_TASK_CHECK (NODE), 3) +#define OMP_TASK_COPYFN(NODE) TREE_OPERAND (OMP_TASK_CHECK (NODE), 4) +#define OMP_TASK_ARG_SIZE(NODE) TREE_OPERAND (OMP_TASK_CHECK (NODE), 5) +#define OMP_TASK_ARG_ALIGN(NODE) TREE_OPERAND (OMP_TASK_CHECK (NODE), 6) #define OMP_TASKREG_CHECK(NODE) TREE_RANGE_CHECK (NODE, OMP_PARALLEL, OMP_TASK) #define OMP_TASKREG_BODY(NODE) TREE_OPERAND (OMP_TASKREG_CHECK (NODE), 0) @@ -1805,11 +1806,6 @@ struct tree_constructor GTY(()) #define OMP_PARALLEL_COMBINED(NODE) \ TREE_PRIVATE (OMP_PARALLEL_CHECK (NODE)) -/* True on an OMP_TASK statement if explicit GOMP_task_start call - is needed after privatized variable initialization. */ -#define OMP_TASK_EXPLICIT_START(NODE) \ - TREE_PRIVATE (OMP_TASK_CHECK (NODE)) - /* 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. */ diff --git a/libgomp/ChangeLog.gomp b/libgomp/ChangeLog.gomp index 0ca809b666c..2913495e98f 100644 --- a/libgomp/ChangeLog.gomp +++ b/libgomp/ChangeLog.gomp @@ -1,3 +1,21 @@ +2008-05-14 Jakub Jelinek <jakub@redhat.com> + + * task.c: Include string.h. + (GOMP_task): Add cpyfn, arg_size and arg_align arguments. + Allocate argument buffer and either call cpyfn to populate it, + or memcpy it from the argument struct. + (GOMP_task_start): Removed. + * libgomp.map: Remove GOMP_task_start@@GOMP_2.0. + * libgomp_g.h (GOMP_task_flag_untied, + GOMP_task_flag_explicit_start): Removed. + (GOMP_task): Adjust prototype. + (GOMP_task_start): Removed. + * testsuite/libgomp.fortran/task2.f90: New test. + * testsuite/libgomp.fortran/allocatable4.f90: New test. + * testsuite/libgomp.c/task-4.c: New test. + * testsuite/libgomp.c++/task-4.C: New test. + * testsuite/libgomp.c++/task-3.C: New test. + 2008-05-07 Jakub Jelinek <jakub@redhat.com> * libgomp.h (gomp_new_icv): New prototype. diff --git a/libgomp/libgomp.map b/libgomp/libgomp.map index 0eecb0a5d2c..6e9ba92bf6e 100644 --- a/libgomp/libgomp.map +++ b/libgomp/libgomp.map @@ -154,6 +154,5 @@ GOMP_1.0 { GOMP_2.0 { global: GOMP_task; - GOMP_task_start; GOMP_taskwait; } GOMP_1.0; diff --git a/libgomp/libgomp_g.h b/libgomp/libgomp_g.h index 3d70df0ab2b..658b89d70e4 100644 --- a/libgomp/libgomp_g.h +++ b/libgomp/libgomp_g.h @@ -95,10 +95,8 @@ extern void GOMP_parallel_end (void); /* team.c */ -#define GOMP_task_flag_untied 1 /* UNTIED clause present. */ -#define GOMP_task_flag_explicit_start 2 /* Explicit GOMP_task_start needed. */ -extern void GOMP_task (void (*) (void *), void *, bool, unsigned); -extern void GOMP_task_start (void); +extern void GOMP_task (void (*) (void *), void *, void (*) (void *, void *), + long, long, bool, unsigned); extern void GOMP_taskwait (void); /* sections.c */ diff --git a/libgomp/task.c b/libgomp/task.c index 22da7342b12..36596d5234b 100644 --- a/libgomp/task.c +++ b/libgomp/task.c @@ -30,6 +30,7 @@ #include "libgomp.h" #include <stdlib.h> +#include <string.h> /* Create a new task data structure. */ @@ -58,7 +59,8 @@ gomp_end_task (void) then the task may be executed by any member of the team. */ void -GOMP_task (void (*fn) (void *), void *data, +GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *), + long arg_size, long arg_align, bool if_clause __attribute__((unused)), unsigned flags __attribute__((unused))) { @@ -67,24 +69,22 @@ GOMP_task (void (*fn) (void *), void *data, gomp_init_task (&task, thr->task, gomp_icv (false)); thr->task = &task; - /* We only implement synchronous tasks at the moment, which means that - we cannot defer or untie the task. Which means we execute it now. */ - fn (data); + { + /* We only implement synchronous tasks at the moment, which means that + we cannot defer or untie the task. Which means we execute it now. */ + char buf[arg_size + arg_align - 1]; + char *arg = (char *) (((uintptr_t) buf + arg_align - 1) + & ~(uintptr_t) (arg_align - 1)); + if (cpyfn) + cpyfn (arg, data); + else + memcpy (arg, data, arg_size); + fn (arg); + } gomp_end_task (); } -/* Called after a task has been initialized. Only should be called if - GOMP_task was called with GOMP_task_flag_explicit_start bit set, - after all firstprivate etc. copying is done. The copying will - happen immediately, in the thread that created the task, afterwards - it can be suspended and/or moved to another thread, even if not untied. */ - -void -GOMP_task_start (void) -{ -} - /* Called when encountering a taskwait directive. */ void diff --git a/libgomp/testsuite/libgomp.c++/task-3.C b/libgomp/testsuite/libgomp.c++/task-3.C new file mode 100644 index 00000000000..e1ecb49654a --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/task-3.C @@ -0,0 +1,90 @@ +// { dg-do run } + +extern "C" void abort (); + +struct A +{ + A (); + ~A (); + A (const A &); + unsigned long l; +}; + +int e; + +A::A () +{ + l = 17; +} + +A::~A () +{ + if (l > 30) + #pragma omp atomic + e++; +} + +A::A (const A &r) +{ + l = r.l; +} + +void +check (int i, A &a, int j, A &b) +{ + if (i != 6 || a.l != 21 || j != 0 || b.l != 23) + #pragma omp atomic + e++; +} + +A b; +int j; + +void +foo (int i) +{ + A a; + a.l = 21; + #pragma omp task firstprivate (i, a, j, b) + check (i, a, j, b); +} + +void +bar (int i, A a) +{ + a.l = 21; + #pragma omp task firstprivate (i, a, j, b) + check (i, a, j, b); +} + +A +baz () +{ + A a, c; + a.l = 21; + c.l = 23; + #pragma omp task firstprivate (a, c) + check (6, a, 0, c); + return a; +} + +int +main () +{ + b.l = 23; + foo (6); + bar (6, A ()); + baz (); + #pragma omp parallel num_threads (4) + { + #pragma omp single + for (int i = 0; i < 64; i++) + { + foo (6); + bar (6, A ()); + baz (); + } + } + if (e) + abort (); +} diff --git a/libgomp/testsuite/libgomp.c++/task-4.C b/libgomp/testsuite/libgomp.c++/task-4.C new file mode 100644 index 00000000000..f2e786a2fdd --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/task-4.C @@ -0,0 +1,37 @@ +#include <omp.h> +extern "C" void *memset (void *, int, __SIZE_TYPE__); +extern "C" void abort (void); + +int e; + +void +baz (int i, int *p, int j, int *q) +{ + if (p[0] != 1 || p[i] != 3 || q[0] != 2 || q[j] != 4) + #pragma omp atomic + e++; +} + +void +foo (int i, int j) +{ + int p[i + 1]; + int q[j + 1]; + memset (p, 0, sizeof (p)); + memset (q, 0, sizeof (q)); + p[0] = 1; + p[i] = 3; + q[0] = 2; + q[j] = 4; + #pragma omp task firstprivate (p, q) + baz (i, p, j, q); +} + +int +main () +{ + #pragma omp parallel num_threads (4) + foo (5 + omp_get_thread_num (), 7 + omp_get_thread_num ()); + if (e) + abort (); +} diff --git a/libgomp/testsuite/libgomp.c/task-4.c b/libgomp/testsuite/libgomp.c/task-4.c new file mode 100644 index 00000000000..18435930019 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/task-4.c @@ -0,0 +1,40 @@ +/* { dg-do run } */ + +#include <omp.h> +#include <stdlib.h> +#include <string.h> + +int e; + +void __attribute__((noinline)) +baz (int i, int *p, int j, int *q) +{ + if (p[0] != 1 || p[i] != 3 || q[0] != 2 || q[j] != 4) + #pragma omp atomic + e++; +} + +void __attribute__((noinline)) +foo (int i, int j) +{ + int p[i + 1]; + int q[j + 1]; + memset (p, 0, sizeof (p)); + memset (q, 0, sizeof (q)); + p[0] = 1; + p[i] = 3; + q[0] = 2; + q[j] = 4; + #pragma omp task firstprivate (p, q) + baz (i, p, j, q); +} + +int +main (void) +{ + #pragma omp parallel num_threads (4) + foo (5 + omp_get_thread_num (), 7 + omp_get_thread_num ()); + if (e) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.fortran/allocatable4.f90 b/libgomp/testsuite/libgomp.fortran/allocatable4.f90 new file mode 100644 index 00000000000..996578c94fa --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/allocatable4.f90 @@ -0,0 +1,47 @@ +! { dg-do run } + + integer, allocatable :: a(:, :) + integer :: b(6, 3) + integer :: i, j + logical :: k, l + b(:, :) = 16 + l = .false. + if (allocated (a)) call abort +!$omp task private (a, b) shared (l) + l = l.or.allocated (a) + allocate (a(3, 6)) + l = l.or..not.allocated (a) + l = l.or.size(a).ne.18.or.size(a,1).ne.3.or.size(a,2).ne.6 + a(3, 2) = 1 + b(3, 2) = 1 + deallocate (a) + l = l.or.allocated (a) +!$omp end task +!$omp taskwait + if (allocated (a).or.l) call abort + allocate (a(6, 3)) + a(:, :) = 3 + if (.not.allocated (a)) call abort + l = l.or.size(a).ne.18.or.size(a,1).ne.6.or.size(a,2).ne.3 + if (l) call abort +!$omp task private (a, b) shared (l) + l = l.or..not.allocated (a) + a(3, 2) = 1 + b(3, 2) = 1 +!$omp end task +!$omp taskwait + if (l.or..not.allocated (a)) call abort +!$omp task firstprivate (a, b) shared (l) + l = l.or..not.allocated (a) + l = l.or.size(a).ne.18.or.size(a,1).ne.6.or.size(a,2).ne.3 + do i = 1, 6 + l = l.or.(a(i, 1).ne.3).or.(a(i, 2).ne.3) + l = l.or.(a(i, 3).ne.3).or.(b(i, 1).ne.16) + l = l.or.(b(i, 2).ne.16).or.(b(i, 3).ne.16) + end do + a(:, :) = 7 + b(:, :) = 8 +!$omp end task +!$omp taskwait + if (any (a.ne.3).or.any (b.ne.16).or.l) call abort +end diff --git a/libgomp/testsuite/libgomp.fortran/task2.f90 b/libgomp/testsuite/libgomp.fortran/task2.f90 new file mode 100644 index 00000000000..24ffee53ac8 --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/task2.f90 @@ -0,0 +1,142 @@ + integer :: err + err = 0 +!$omp parallel num_threads (4) default (none) shared (err) +!$omp single + call test +!$omp end single +!$omp end parallel + if (err.ne.0) call abort +contains + subroutine check (x, y, l) + integer :: x, y + logical :: l + l = l .or. x .ne. y + end subroutine check + + subroutine foo (c, d, e, f, g, h, i, j, k, n) + use omp_lib + integer :: n + character (len = *) :: c + character (len = n) :: d + integer, dimension (2, 3:5, n) :: e + integer, dimension (2, 3:n, n) :: f + character (len = *), dimension (5, 3:n) :: g + character (len = n), dimension (5, 3:n) :: h + real, dimension (:, :, :) :: i + double precision, dimension (3:, 5:, 7:) :: j + integer, dimension (:, :, :) :: k + logical :: l + integer :: p, q, r + character (len = n) :: s + integer, dimension (2, 3:5, n) :: t + integer, dimension (2, 3:n, n) :: u + character (len = n), dimension (5, 3:n) :: v + character (len = 2 * n + 24) :: w + integer :: x, z + character (len = 1) :: y + s = 'PQRSTUV' + forall (p = 1:2, q = 3:5, r = 1:7) t(p, q, r) = -10 + p - q + 2 * r + forall (p = 1:2, q = 3:7, r = 1:7) u(p, q, r) = 30 - p + q - 2 * r + forall (p = 1:5, q = 3:7, p + q .le. 8) v(p, q) = '_+|/Oo_' + forall (p = 1:5, q = 3:7, p + q .gt. 8) v(p, q) = '///|||!' +!$omp task default (none) firstprivate (c, d, e, f, g, h, i, j, k) & +!$omp & firstprivate (s, t, u, v) private (l, p, q, r, w, x, y) shared (err) + l = .false. + l = l .or. c .ne. 'abcdefghijkl' + l = l .or. d .ne. 'ABCDEFG' + l = l .or. s .ne. 'PQRSTUV' + do 100, p = 1, 2 + do 100, q = 3, 7 + do 100, r = 1, 7 + if (q .lt. 6) l = l .or. e(p, q, r) .ne. 5 + p + q + 2 * r + l = l .or. f(p, q, r) .ne. 25 + p + q + 2 * r + if (r .lt. 6 .and. q + r .le. 8) l = l .or. g(r, q) .ne. '0123456789AB' + if (r .lt. 6 .and. q + r .gt. 8) l = l .or. g(r, q) .ne. '9876543210ZY' + if (r .lt. 6 .and. q + r .le. 8) l = l .or. h(r, q) .ne. '0123456' + if (r .lt. 6 .and. q + r .gt. 8) l = l .or. h(r, q) .ne. '9876543' + if (q .lt. 6) l = l .or. t(p, q, r) .ne. -10 + p - q + 2 * r + l = l .or. u(p, q, r) .ne. 30 - p + q - 2 * r + if (r .lt. 6 .and. q + r .le. 8) l = l .or. v(r, q) .ne. '_+|/Oo_' + if (r .lt. 6 .and. q + r .gt. 8) l = l .or. v(r, q) .ne. '///|||!' +100 continue + do 101, p = 3, 5 + do 101, q = 2, 6 + do 101, r = 1, 7 + l = l .or. i(p - 2, q - 1, r) .ne. 7.5 * p * q * r + l = l .or. j(p, q + 3, r + 6) .ne. 9.5 * p * q * r +101 continue + do 102, p = 1, 5 + do 102, q = 4, 6 + l = l .or. k(p, 1, q - 3) .ne. 19 + p + 7 + 3 * q +102 continue + call check (size (e, 1), 2, l) + call check (size (e, 2), 3, l) + call check (size (e, 3), 7, l) + call check (size (e), 42, l) + call check (size (f, 1), 2, l) + call check (size (f, 2), 5, l) + call check (size (f, 3), 7, l) + call check (size (f), 70, l) + call check (size (g, 1), 5, l) + call check (size (g, 2), 5, l) + call check (size (g), 25, l) + call check (size (h, 1), 5, l) + call check (size (h, 2), 5, l) + call check (size (h), 25, l) + call check (size (i, 1), 3, l) + call check (size (i, 2), 5, l) + call check (size (i, 3), 7, l) + call check (size (i), 105, l) + call check (size (j, 1), 4, l) + call check (size (j, 2), 5, l) + call check (size (j, 3), 7, l) + call check (size (j), 140, l) + call check (size (k, 1), 5, l) + call check (size (k, 2), 1, l) + call check (size (k, 3), 3, l) + call check (size (k), 15, l) + if (l) then +!$omp atomic + err = err + 1 + end if +!$omp end task + c = '' + d = '' + e(:, :, :) = 199 + f(:, :, :) = 198 + g(:, :) = '' + h(:, :) = '' + i(:, :, :) = 7.0 + j(:, :, :) = 8.0 + k(:, :, :) = 9 + s = '' + t(:, :, :) = 10 + u(:, :, :) = 11 + v(:, :) = '' + end subroutine foo + + subroutine test + character (len = 12) :: c + character (len = 7) :: d + integer, dimension (2, 3:5, 7) :: e + integer, dimension (2, 3:7, 7) :: f + character (len = 12), dimension (5, 3:7) :: g + character (len = 7), dimension (5, 3:7) :: h + real, dimension (3:5, 2:6, 1:7) :: i + double precision, dimension (3:6, 2:6, 1:7) :: j + integer, dimension (1:5, 7:7, 4:6) :: k + integer :: p, q, r + c = 'abcdefghijkl' + d = 'ABCDEFG' + forall (p = 1:2, q = 3:5, r = 1:7) e(p, q, r) = 5 + p + q + 2 * r + forall (p = 1:2, q = 3:7, r = 1:7) f(p, q, r) = 25 + p + q + 2 * r + forall (p = 1:5, q = 3:7, p + q .le. 8) g(p, q) = '0123456789AB' + forall (p = 1:5, q = 3:7, p + q .gt. 8) g(p, q) = '9876543210ZY' + forall (p = 1:5, q = 3:7, p + q .le. 8) h(p, q) = '0123456' + forall (p = 1:5, q = 3:7, p + q .gt. 8) h(p, q) = '9876543' + forall (p = 3:5, q = 2:6, r = 1:7) i(p, q, r) = 7.5 * p * q * r + forall (p = 3:6, q = 2:6, r = 1:7) j(p, q, r) = 9.5 * p * q * r + forall (p = 1:5, q = 7:7, r = 4:6) k(p, q, r) = 19 + p + q + 3 * r + call foo (c, d, e, f, g, h, i, j, k, 7) + end subroutine test +end |