aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2008-05-14 09:11:10 +0000
committerJakub Jelinek <jakub@redhat.com>2008-05-14 09:11:10 +0000
commitf641074bd10324db19d24c5c7d7450767d64d78b (patch)
treeca4d50265af4b01417b3aa1bd3ee30590d72202f
parentb353658eebe13efc87271da9539ffcd8d6df1f1a (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.gomp57
-rw-r--r--gcc/bitmap.c16
-rw-r--r--gcc/builtin-types.def8
-rw-r--r--gcc/fortran/ChangeLog.gomp7
-rw-r--r--gcc/fortran/trans-openmp.c9
-rw-r--r--gcc/fortran/types.def9
-rw-r--r--gcc/ipa-struct-reorg.c1
-rw-r--r--gcc/matrix-reorg.c4
-rw-r--r--gcc/omp-builtins.def5
-rw-r--r--gcc/omp-low.c632
-rw-r--r--gcc/tree-pretty-print.c9
-rw-r--r--gcc/tree.def11
-rw-r--r--gcc/tree.h10
-rw-r--r--libgomp/ChangeLog.gomp18
-rw-r--r--libgomp/libgomp.map1
-rw-r--r--libgomp/libgomp_g.h6
-rw-r--r--libgomp/task.c30
-rw-r--r--libgomp/testsuite/libgomp.c++/task-3.C90
-rw-r--r--libgomp/testsuite/libgomp.c++/task-4.C37
-rw-r--r--libgomp/testsuite/libgomp.c/task-4.c40
-rw-r--r--libgomp/testsuite/libgomp.fortran/allocatable4.f9047
-rw-r--r--libgomp/testsuite/libgomp.fortran/task2.f90142
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