This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[gomp3] GOMP_task API changes


Hi!

The following patch changes GOMP_task API in a way that allows
{make,set,swap,get}context free tasking for tied tasks.

The problem is, we need to run firstprivate (and allocatable private)
constructors at the time the explicit task construct is encountered,
rather than at the time the task is to be scheduled in some thread,
because the original variables that were supposed to be copied
might have changed or might go out of scope by the time it is to be
scheduled.  For integral/pointer firstprivate vars this doesn't
mean big changes, GOMP_task is simply told the size and alignment
of the argument block structure, and it together with allocating
task control structure will also allocate buffer for the argument
block structure and copy the caller's argument block structure
in there and when scheduled pass pointer to that as argument to the task
body function, rather than pointer to the original argument block
structure (which might be long time gone).

For variables which are firstprivatized by reference, references,
variables sized vars or allocatable privates I've originally planned
to allocate stack for the task, makecontext and run the constructors
and then reschedule the task afterwards, using GOMP_task_start.
But, with many tasks queued that might be horribly expensive.
So this patch creates a helper function, which is run after
the new task structure is allocated and task context temporarily switched
to the new task (to do ICVs and locks right in the ctors).
This helper function then initializes fields in the argument
block, using the pointers etc. from the original argument block.
So at task creation time we only need to allocate memory for the
firstprivate variables and pointers to shared vars, no stack
needs to be created in advance and at the time it is scheduled
it can use the stack of the implicit task currently in barrier
(explicit or implicit), GOMP_taskwait or GOMP_task (if it is if(0)).
A new tied task can be scheduled only if it is descendant of all
the tasks in the current thread that aren't waiting on barrier
(only implicit tasks can do that).

The libgomp side has been just adjusted for the new API, but tasks
are still stubbed there (i.e. all tasks are ATM if (0) tasks).
That's work for further patch.

2008-05-13  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.
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.
	* 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.

--- gcc/tree.def.jj	2008-03-12 11:24:29.000000000 +0100
+++ gcc/tree.def	2008-05-09 19:07:53.000000000 +0200
@@ -1002,9 +1002,14 @@ DEFTREECODE (OMP_PARALLEL, "omp_parallel
 	      pass_lower_omp.
    Operand 3: OMP_TASK_DATA_ARG: Local variable in the parent
 	      function containing data to be shared with the child
-	      function.  */
+	      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, 4)
+DEFTREECODE (OMP_TASK, "omp_task", tcc_statement, 7)
 
 /* OpenMP - #pragma omp for [clause1 ... clauseN]
    Operand 0: OMP_FOR_BODY: Loop body.
--- gcc/builtin-types.def.jj	2008-05-05 12:27:33.000000000 +0200
+++ gcc/builtin-types.def	2008-05-09 19:28:41.000000000 +0200
@@ -309,6 +309,8 @@ DEF_FUNCTION_TYPE_2 (BT_FN_I16_VPTR_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_PT
 		     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_PT
 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)
--- gcc/omp-builtins.def.jj	2008-05-05 12:27:34.000000000 +0200
+++ gcc/omp-builtins.def	2008-05-09 19:27:02.000000000 +0200
@@ -37,8 +37,6 @@ DEF_GOMP_BUILTIN (BUILT_IN_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
 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",
--- gcc/tree.h.jj	2008-03-12 12:13:40.000000000 +0100
+++ gcc/tree.h	2008-05-09 19:08:31.000000000 +0200
@@ -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.  */
--- gcc/bitmap.c.jj	2007-11-14 14:30:38.000000000 +0100
+++ gcc/bitmap.c	2008-05-13 10:31:25.000000000 +0200
@@ -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;
--- gcc/omp-low.c.jj	2008-05-05 12:27:33.000000000 +0200
+++ gcc/omp-low.c	2008-05-13 16:27:27.000000000 +0200
@@ -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_co
 	 (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_conte
 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 
 /* 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
      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 val
 
   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 val
       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 *ct
 	  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_
 	      || 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_
 	  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_
 	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_
 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 *
   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_con
   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
   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, t
 	      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, t
 		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, t
 	      /* 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, t
 	      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, t
      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 *
 	  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 *
 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 
 }
 
 
+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 e
     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 *
   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_con
       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_con
 
   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;
     }
 
--- gcc/tree-pretty-print.c.jj	2008-03-12 11:16:55.000000000 +0100
+++ gcc/tree-pretty-print.c	2008-05-07 15:19:50.000000000 +0200
@@ -1887,7 +1887,14 @@ dump_generic_node (pretty_printer *buffe
 	  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;
 
--- gcc/ipa-struct-reorg.c.jj	2008-02-20 18:25:38.000000000 +0100
+++ gcc/ipa-struct-reorg.c	2008-05-13 10:24:33.000000000 +0200
@@ -3727,6 +3727,7 @@ do_reorg_1 (void)
       }
 
   set_cfun (NULL);
+  bitmap_obstack_release (NULL);
 }
 
 /* This function creates new global struct variables.
--- gcc/matrix-reorg.c.jj	2007-11-14 12:47:19.000000000 +0100
+++ gcc/matrix-reorg.c	2008-05-13 10:24:13.000000000 +0200
@@ -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);
 
--- gcc/fortran/trans-openmp.c.jj	2008-03-12 12:01:14.000000000 +0100
+++ gcc/fortran/trans-openmp.c	2008-05-09 20:13:10.000000000 +0200
@@ -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);
 }
--- gcc/fortran/types.def.jj	2008-05-05 12:27:34.000000000 +0200
+++ gcc/fortran/types.def	2008-05-09 19:29:34.000000000 +0200
@@ -93,6 +93,9 @@ DEF_FUNCTION_TYPE_2 (BT_FN_I2_VPTR_I2, B
 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_PT
                      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_PT
 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)
--- libgomp/task.c.jj	2008-05-07 11:07:42.000000000 +0200
+++ libgomp/task.c	2008-05-09 19:40:35.000000000 +0200
@@ -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 *da
   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
--- libgomp/libgomp.map.jj	2008-03-25 12:19:37.000000000 +0100
+++ libgomp/libgomp.map	2008-05-09 19:31:06.000000000 +0200
@@ -154,6 +154,5 @@ GOMP_1.0 {
 GOMP_2.0 {
   global:
 	GOMP_task;
-	GOMP_task_start;
 	GOMP_taskwait;
 } GOMP_1.0;
--- libgomp/testsuite/libgomp.fortran/task2.f90.jj	2008-05-13 12:04:54.000000000 +0200
+++ libgomp/testsuite/libgomp.fortran/task2.f90	2008-05-13 13:00:33.000000000 +0200
@@ -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
--- libgomp/testsuite/libgomp.fortran/allocatable4.f90.jj	2008-05-13 15:01:19.000000000 +0200
+++ libgomp/testsuite/libgomp.fortran/allocatable4.f90	2008-05-13 13:47:09.000000000 +0200
@@ -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
--- libgomp/testsuite/libgomp.c/task-4.c.jj	2008-05-12 19:26:49.000000000 +0200
+++ libgomp/testsuite/libgomp.c/task-4.c	2008-05-12 19:27:45.000000000 +0200
@@ -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;
+}
--- libgomp/testsuite/libgomp.c++/task-4.C.jj	2008-05-13 11:42:06.000000000 +0200
+++ libgomp/testsuite/libgomp.c++/task-4.C	2008-05-13 11:43:35.000000000 +0200
@@ -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 ();
+}
--- libgomp/testsuite/libgomp.c++/task-3.C.jj	2008-05-13 09:33:39.000000000 +0200
+++ libgomp/testsuite/libgomp.c++/task-3.C	2008-05-13 11:49:00.000000000 +0200
@@ -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 ();
+}

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]