+ 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) = gimple_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_lp_nr = 0;
+ 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;
+
+ push_cfun (child_cfun);
+
+ 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 = gimple_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_loc (loc, sarg);
+ src = build3 (COMPONENT_REF, TREE_TYPE (sf), src, sf, NULL);
+ t = build2 (MODIFY_EXPR, TREE_TYPE (*p), *p, src);
+ append_to_statement_list (t, &list);
+ }
+
+ /* Second pass: copy shared var pointers and copy construct non-VLA
+ firstprivate vars. */
+ for (c = gimple_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_loc (loc, sarg);
+ src = build3 (COMPONENT_REF, TREE_TYPE (sf), src, sf, NULL);
+ dst = build_fold_indirect_ref_loc (loc, arg);
+ dst = build3 (COMPONENT_REF, TREE_TYPE (f), dst, f, NULL);
+ t = build2 (MODIFY_EXPR, TREE_TYPE (dst), 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_loc (loc, 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_loc (loc, src);
+ }
+ else
+ src = decl;
+ dst = build_fold_indirect_ref_loc (loc, 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_loc (loc, sarg);
+ src = build3 (COMPONENT_REF, TREE_TYPE (sf), src, sf, NULL);
+ if (use_pointer_for_field (decl, NULL))
+ src = build_fold_indirect_ref_loc (loc, src);
+ }
+ else
+ src = decl;
+ dst = build_fold_indirect_ref_loc (loc, arg);
+ dst = build3 (COMPONENT_REF, TREE_TYPE (f), dst, f, NULL);
+ t = build2 (MODIFY_EXPR, TREE_TYPE (dst), dst, src);
+ append_to_statement_list (t, &list);
+ break;
+ default:
+ break;
+ }
+
+ /* Last pass: handle VLA firstprivates. */
+ if (tcctx.cb.decl_map)
+ for (c = gimple_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_loc (loc, sarg);
+ src = build3 (COMPONENT_REF, TREE_TYPE (sf), src, sf, NULL);
+ src = build_fold_indirect_ref_loc (loc, src);
+ dst = build_fold_indirect_ref_loc (loc, 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_loc (loc, arg);
+ ptr = build3 (COMPONENT_REF, TREE_TYPE (df), ptr, df, NULL);
+ t = build2 (MODIFY_EXPR, TREE_TYPE (ptr), ptr,
+ build_fold_addr_expr_loc (loc, 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 the current statement
+ in GSI_P. CTX holds context information for the directive. */
+
+static void
+lower_omp_taskreg (gimple_stmt_iterator *gsi_p, omp_context *ctx)
+{
+ tree clauses;
+ tree child_fn, t;
+ gimple stmt = gsi_stmt (*gsi_p);
+ gimple par_bind, bind;
+ gimple_seq par_body, olist, ilist, par_olist, par_ilist, new_body;
+ struct gimplify_ctx gctx;
+ location_t loc = gimple_location (stmt);
+
+ clauses = gimple_omp_taskreg_clauses (stmt);
+ par_bind = gimple_seq_first_stmt (gimple_omp_body (stmt));
+ par_body = gimple_bind_body (par_bind);