aboutsummaryrefslogtreecommitdiff
path: root/gcc/omp-low.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/omp-low.c')
-rw-r--r--gcc/omp-low.c1937
1 files changed, 1617 insertions, 320 deletions
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index c608ae4..e9223b2 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;
@@ -95,21 +103,30 @@ typedef struct omp_context
} omp_context;
+struct omp_for_data_loop
+{
+ tree v, n1, n2, step;
+ enum tree_code cond_code;
+};
+
/* A structure describing the main elements of a parallel loop. */
struct omp_for_data
{
- tree v, n1, n2, step, chunk_size, for_stmt;
- enum tree_code cond_code;
- tree pre;
+ struct omp_for_data_loop loop;
+ tree chunk_size, for_stmt;
+ tree pre, iter_type;
+ int collapse;
bool have_nowait, have_ordered;
enum omp_clause_schedule_kind sched_kind;
+ struct omp_for_data_loop *loops;
};
static splay_tree all_contexts;
-static int parallel_nesting_level;
+static int taskreg_nesting_level;
struct omp_region *root_omp_region;
+static bitmap task_shared_vars;
static void scan_omp (tree *, omp_context *);
static void lower_omp (tree *, omp_context *);
@@ -137,6 +154,25 @@ 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
+is_taskreg_ctx (omp_context *ctx)
+{
+ return TREE_CODE (ctx->stmt) == OMP_PARALLEL
+ || TREE_CODE (ctx->stmt) == OMP_TASK;
+}
+
+
/* Return true if REGION is a combined parallel+workshare region. */
static inline bool
@@ -150,65 +186,28 @@ is_combined_parallel (struct omp_region *region)
them into *FD. */
static void
-extract_omp_for_data (tree for_stmt, struct omp_for_data *fd)
+extract_omp_for_data (tree for_stmt, struct omp_for_data *fd,
+ struct omp_for_data_loop *loops)
{
- tree t, var;
+ tree t, var, *collapse_iter, *collapse_count;
+ tree count = NULL_TREE, iter_type = long_integer_type_node;
+ struct omp_for_data_loop *loop;
+ int i;
+ struct omp_for_data_loop dummy_loop;
fd->for_stmt = for_stmt;
fd->pre = NULL;
-
- t = OMP_FOR_INIT (for_stmt);
- gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
- fd->v = GIMPLE_STMT_OPERAND (t, 0);
- gcc_assert (SSA_VAR_P (fd->v));
- gcc_assert (TREE_CODE (TREE_TYPE (fd->v)) == INTEGER_TYPE);
- var = TREE_CODE (fd->v) == SSA_NAME ? SSA_NAME_VAR (fd->v) : fd->v;
- fd->n1 = GIMPLE_STMT_OPERAND (t, 1);
-
- t = OMP_FOR_COND (for_stmt);
- fd->cond_code = TREE_CODE (t);
- gcc_assert (TREE_OPERAND (t, 0) == var);
- fd->n2 = TREE_OPERAND (t, 1);
- switch (fd->cond_code)
- {
- case LT_EXPR:
- case GT_EXPR:
- break;
- case LE_EXPR:
- fd->n2 = fold_build2 (PLUS_EXPR, TREE_TYPE (fd->n2), fd->n2,
- build_int_cst (TREE_TYPE (fd->n2), 1));
- fd->cond_code = LT_EXPR;
- break;
- case GE_EXPR:
- fd->n2 = fold_build2 (MINUS_EXPR, TREE_TYPE (fd->n2), fd->n2,
- build_int_cst (TREE_TYPE (fd->n2), 1));
- fd->cond_code = GT_EXPR;
- break;
- default:
- gcc_unreachable ();
- }
-
- t = OMP_FOR_INCR (fd->for_stmt);
- gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
- gcc_assert (GIMPLE_STMT_OPERAND (t, 0) == var);
- t = GIMPLE_STMT_OPERAND (t, 1);
- gcc_assert (TREE_OPERAND (t, 0) == var);
- switch (TREE_CODE (t))
- {
- case PLUS_EXPR:
- fd->step = TREE_OPERAND (t, 1);
- break;
- case MINUS_EXPR:
- fd->step = TREE_OPERAND (t, 1);
- fd->step = fold_build1 (NEGATE_EXPR, TREE_TYPE (fd->step), fd->step);
- break;
- default:
- gcc_unreachable ();
- }
+ fd->collapse = TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt));
+ if (fd->collapse > 1)
+ fd->loops = loops;
+ else
+ fd->loops = &fd->loop;
fd->have_nowait = fd->have_ordered = false;
fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC;
fd->chunk_size = NULL_TREE;
+ collapse_iter = NULL;
+ collapse_count = NULL;
for (t = OMP_FOR_CLAUSES (for_stmt); t ; t = OMP_CLAUSE_CHAIN (t))
switch (OMP_CLAUSE_CODE (t))
@@ -223,20 +222,223 @@ extract_omp_for_data (tree for_stmt, struct omp_for_data *fd)
fd->sched_kind = OMP_CLAUSE_SCHEDULE_KIND (t);
fd->chunk_size = OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (t);
break;
+ case OMP_CLAUSE_COLLAPSE:
+ if (fd->collapse > 1)
+ {
+ collapse_iter = &OMP_CLAUSE_COLLAPSE_ITERVAR (t);
+ collapse_count = &OMP_CLAUSE_COLLAPSE_COUNT (t);
+ }
default:
break;
}
+ /* FIXME: for now map schedule(auto) to schedule(static).
+ There should be analysis to determine whether all iterations
+ are approximately the same amount of work (then schedule(static)
+ is best) or if it varries (then schedule(dynamic,N) is better). */
+ if (fd->sched_kind == OMP_CLAUSE_SCHEDULE_AUTO)
+ {
+ fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC;
+ gcc_assert (fd->chunk_size == NULL);
+ }
+ gcc_assert (fd->collapse == 1 || collapse_iter != NULL);
if (fd->sched_kind == OMP_CLAUSE_SCHEDULE_RUNTIME)
gcc_assert (fd->chunk_size == NULL);
else if (fd->chunk_size == NULL)
{
/* We only need to compute a default chunk size for ordered
static loops and dynamic loops. */
- if (fd->sched_kind != OMP_CLAUSE_SCHEDULE_STATIC || fd->have_ordered)
+ if (fd->sched_kind != OMP_CLAUSE_SCHEDULE_STATIC
+ || fd->have_ordered
+ || fd->collapse > 1)
fd->chunk_size = (fd->sched_kind == OMP_CLAUSE_SCHEDULE_STATIC)
? integer_zero_node : integer_one_node;
}
+
+ for (i = 0; i < fd->collapse; i++)
+ {
+ if (fd->collapse == 1)
+ loop = &fd->loop;
+ else if (loops != NULL)
+ loop = loops + i;
+ else
+ loop = &dummy_loop;
+
+ t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i);
+ gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
+ loop->v = GIMPLE_STMT_OPERAND (t, 0);
+ gcc_assert (SSA_VAR_P (loop->v));
+ gcc_assert (TREE_CODE (TREE_TYPE (loop->v)) == INTEGER_TYPE
+ || TREE_CODE (TREE_TYPE (loop->v)) == POINTER_TYPE);
+ var = TREE_CODE (loop->v) == SSA_NAME ? SSA_NAME_VAR (loop->v) : loop->v;
+ loop->n1 = GIMPLE_STMT_OPERAND (t, 1);
+
+ t = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), i);
+ loop->cond_code = TREE_CODE (t);
+ gcc_assert (TREE_OPERAND (t, 0) == var);
+ loop->n2 = TREE_OPERAND (t, 1);
+ switch (loop->cond_code)
+ {
+ case LT_EXPR:
+ case GT_EXPR:
+ break;
+ case LE_EXPR:
+ if (POINTER_TYPE_P (TREE_TYPE (loop->n2)))
+ loop->n2 = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (loop->n2),
+ loop->n2, size_one_node);
+ else
+ loop->n2 = fold_build2 (PLUS_EXPR, TREE_TYPE (loop->n2), loop->n2,
+ build_int_cst (TREE_TYPE (loop->n2), 1));
+ loop->cond_code = LT_EXPR;
+ break;
+ case GE_EXPR:
+ if (POINTER_TYPE_P (TREE_TYPE (loop->n2)))
+ loop->n2 = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (loop->n2),
+ loop->n2, size_int (-1));
+ else
+ loop->n2 = fold_build2 (MINUS_EXPR, TREE_TYPE (loop->n2), loop->n2,
+ build_int_cst (TREE_TYPE (loop->n2), 1));
+ loop->cond_code = GT_EXPR;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i);
+ gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
+ gcc_assert (GIMPLE_STMT_OPERAND (t, 0) == var);
+ t = GIMPLE_STMT_OPERAND (t, 1);
+ gcc_assert (TREE_OPERAND (t, 0) == var);
+ switch (TREE_CODE (t))
+ {
+ case PLUS_EXPR:
+ case POINTER_PLUS_EXPR:
+ loop->step = TREE_OPERAND (t, 1);
+ break;
+ case MINUS_EXPR:
+ loop->step = TREE_OPERAND (t, 1);
+ loop->step = fold_build1 (NEGATE_EXPR, TREE_TYPE (loop->step),
+ loop->step);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ if (iter_type != long_long_unsigned_type_node)
+ {
+ if (POINTER_TYPE_P (TREE_TYPE (loop->v)))
+ iter_type = long_long_unsigned_type_node;
+ else if (TYPE_UNSIGNED (TREE_TYPE (loop->v))
+ && TYPE_PRECISION (TREE_TYPE (loop->v))
+ >= TYPE_PRECISION (iter_type))
+ {
+ tree n;
+
+ if (loop->cond_code == LT_EXPR)
+ n = fold_build2 (PLUS_EXPR, TREE_TYPE (loop->v),
+ loop->n2, loop->step);
+ else
+ n = loop->n1;
+ if (TREE_CODE (n) != INTEGER_CST
+ || tree_int_cst_lt (TYPE_MAX_VALUE (iter_type), n))
+ iter_type = long_long_unsigned_type_node;
+ }
+ else if (TYPE_PRECISION (TREE_TYPE (loop->v))
+ > TYPE_PRECISION (iter_type))
+ {
+ tree n1, n2;
+
+ if (loop->cond_code == LT_EXPR)
+ {
+ n1 = loop->n1;
+ n2 = fold_build2 (PLUS_EXPR, TREE_TYPE (loop->v),
+ loop->n2, loop->step);
+ }
+ else
+ {
+ n1 = fold_build2 (MINUS_EXPR, TREE_TYPE (loop->v),
+ loop->n2, loop->step);
+ n2 = loop->n1;
+ }
+ if (TREE_CODE (n1) != INTEGER_CST
+ || TREE_CODE (n2) != INTEGER_CST
+ || !tree_int_cst_lt (TYPE_MIN_VALUE (iter_type), n1)
+ || !tree_int_cst_lt (n2, TYPE_MAX_VALUE (iter_type)))
+ iter_type = long_long_unsigned_type_node;
+ }
+ }
+
+ if (collapse_count && *collapse_count == NULL)
+ {
+ if ((i == 0 || count != NULL_TREE)
+ && TREE_CODE (TREE_TYPE (loop->v)) == INTEGER_TYPE
+ && TREE_CONSTANT (loop->n1)
+ && TREE_CONSTANT (loop->n2)
+ && TREE_CODE (loop->step) == INTEGER_CST)
+ {
+ tree itype = TREE_TYPE (loop->v);
+
+ if (POINTER_TYPE_P (itype))
+ itype
+ = lang_hooks.types.type_for_size (TYPE_PRECISION (itype), 0);
+ t = build_int_cst (itype, (loop->cond_code == LT_EXPR ? -1 : 1));
+ t = fold_build2 (PLUS_EXPR, itype,
+ fold_convert (itype, loop->step), t);
+ t = fold_build2 (PLUS_EXPR, itype, t,
+ fold_convert (itype, loop->n2));
+ t = fold_build2 (MINUS_EXPR, itype, t,
+ fold_convert (itype, loop->n1));
+ if (TYPE_UNSIGNED (itype) && loop->cond_code == GT_EXPR)
+ t = fold_build2 (TRUNC_DIV_EXPR, itype,
+ fold_build1 (NEGATE_EXPR, itype, t),
+ fold_build1 (NEGATE_EXPR, itype,
+ fold_convert (itype,
+ loop->step)));
+ else
+ t = fold_build2 (TRUNC_DIV_EXPR, itype, t,
+ fold_convert (itype, loop->step));
+ t = fold_convert (long_long_unsigned_type_node, t);
+ if (count != NULL_TREE)
+ count = fold_build2 (MULT_EXPR, long_long_unsigned_type_node,
+ count, t);
+ else
+ count = t;
+ if (TREE_CODE (count) != INTEGER_CST)
+ count = NULL_TREE;
+ }
+ else
+ count = NULL_TREE;
+ }
+ }
+
+ if (count)
+ {
+ if (!tree_int_cst_lt (count, TYPE_MAX_VALUE (long_integer_type_node)))
+ iter_type = long_long_unsigned_type_node;
+ else
+ iter_type = long_integer_type_node;
+ }
+ else if (collapse_iter && *collapse_iter != NULL)
+ iter_type = TREE_TYPE (*collapse_iter);
+ fd->iter_type = iter_type;
+ if (collapse_iter && *collapse_iter == NULL)
+ *collapse_iter = create_tmp_var (iter_type, ".iter");
+ if (collapse_count && *collapse_count == NULL)
+ {
+ if (count)
+ *collapse_count = fold_convert (iter_type, count);
+ else
+ *collapse_count = create_tmp_var (iter_type, ".count");
+ }
+
+ if (fd->collapse > 1)
+ {
+ fd->loop.v = *collapse_iter;
+ fd->loop.n1 = build_int_cst (TREE_TYPE (fd->loop.v), 0);
+ fd->loop.n2 = *collapse_count;
+ fd->loop.step = build_int_cst (TREE_TYPE (fd->loop.v), 1);
+ fd->loop.cond_code = LT_EXPR;
+ }
}
@@ -296,16 +498,21 @@ workshare_safe_to_combine_p (basic_block par_entry_bb, basic_block ws_entry_bb)
gcc_assert (TREE_CODE (ws_stmt) == OMP_FOR);
- extract_omp_for_data (ws_stmt, &fd);
+ extract_omp_for_data (ws_stmt, &fd, NULL);
+
+ if (fd.collapse > 1 && TREE_CODE (fd.loop.n2) != INTEGER_CST)
+ return false;
+ if (fd.iter_type != long_integer_type_node)
+ return false;
/* FIXME. We give up too easily here. If any of these arguments
are not constants, they will likely involve variables that have
been mapped into fields of .omp_data_s for sharing with the child
function. With appropriate data flow, it would be possible to
see through this. */
- if (!is_gimple_min_invariant (fd.n1)
- || !is_gimple_min_invariant (fd.n2)
- || !is_gimple_min_invariant (fd.step)
+ if (!is_gimple_min_invariant (fd.loop.n1)
+ || !is_gimple_min_invariant (fd.loop.n2)
+ || !is_gimple_min_invariant (fd.loop.step)
|| (fd.chunk_size && !is_gimple_min_invariant (fd.chunk_size)))
return false;
@@ -327,7 +534,7 @@ get_ws_args_for (tree ws_stmt)
struct omp_for_data fd;
tree ws_args;
- extract_omp_for_data (ws_stmt, &fd);
+ extract_omp_for_data (ws_stmt, &fd, NULL);
ws_args = NULL_TREE;
if (fd.chunk_size)
@@ -336,13 +543,13 @@ get_ws_args_for (tree ws_stmt)
ws_args = tree_cons (NULL, t, ws_args);
}
- t = fold_convert (long_integer_type_node, fd.step);
+ t = fold_convert (long_integer_type_node, fd.loop.step);
ws_args = tree_cons (NULL, t, ws_args);
- t = fold_convert (long_integer_type_node, fd.n2);
+ t = fold_convert (long_integer_type_node, fd.loop.n2);
ws_args = tree_cons (NULL, t, ws_args);
- t = fold_convert (long_integer_type_node, fd.n1);
+ t = fold_convert (long_integer_type_node, fd.loop.n1);
ws_args = tree_cons (NULL, t, ws_args);
return ws_args;
@@ -472,6 +679,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;
@@ -483,7 +700,7 @@ maybe_lookup_field (tree var, omp_context *ctx)
the parallel context if DECL is to be shared. */
static bool
-use_pointer_for_field (const_tree decl, omp_context *shared_ctx)
+use_pointer_for_field (tree decl, omp_context *shared_ctx)
{
if (AGGREGATE_TYPE_P (TREE_TYPE (decl)))
return true;
@@ -524,11 +741,11 @@ use_pointer_for_field (const_tree decl, omp_context *shared_ctx)
if (maybe_lookup_decl (decl, up))
break;
- if (up && is_parallel_ctx (up))
+ if (up && is_taskreg_ctx (up))
{
tree c;
- for (c = OMP_PARALLEL_CLAUSES (up->stmt);
+ for (c = OMP_TASKREG_CLAUSES (up->stmt);
c; c = OMP_CLAUSE_CHAIN (c))
if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED
&& OMP_CLAUSE_DECL (c) == decl)
@@ -538,6 +755,26 @@ use_pointer_for_field (const_tree decl, omp_context *shared_ctx)
return true;
}
}
+
+ /* For tasks avoid using copy-in/out, unless they are readonly
+ (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) && is_task_ctx (shared_ctx))
+ {
+ tree outer = maybe_lookup_decl_in_outer_ctx (decl, shared_ctx);
+ if (is_gimple_reg (outer))
+ {
+ /* Taking address of OUTER in lower_send_shared_vars
+ might need regimplification of everything that uses the
+ variable. */
+ if (!task_shared_vars)
+ task_shared_vars = BITMAP_ALLOC (NULL);
+ bitmap_set_bit (task_shared_vars, DECL_UID (outer));
+ TREE_ADDRESSABLE (outer) = 1;
+ }
+ return true;
+ }
}
return false;
@@ -622,7 +859,7 @@ build_outer_var_ref (tree var, omp_context *ctx)
x = build_outer_var_ref (x, ctx);
x = build_fold_indirect_ref (x);
}
- else if (is_parallel_ctx (ctx))
+ else if (is_taskreg_ctx (ctx))
{
bool by_ref = use_pointer_for_field (var, NULL);
x = build_receiver_ref (var, by_ref, ctx);
@@ -647,7 +884,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);
}
@@ -655,15 +892,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);
@@ -671,11 +913,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);
- insert_field_into_struct (ctx->record_type, field);
+ 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;
+
+ 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
@@ -740,7 +1028,7 @@ omp_copy_decl (tree var, copy_body_data *cb)
return new_var;
}
- while (!is_parallel_ctx (ctx))
+ while (!is_taskreg_ctx (ctx))
{
ctx = ctx->outer;
if (ctx == NULL)
@@ -912,6 +1200,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. */
@@ -921,6 +1211,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);
}
@@ -955,6 +1251,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
@@ -986,26 +1285,28 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
{
case OMP_CLAUSE_PRIVATE:
decl = OMP_CLAUSE_DECL (c);
- if (!is_variable_sized (decl))
+ if (OMP_CLAUSE_PRIVATE_OUTER_REF (c))
+ goto do_private;
+ else if (!is_variable_sized (decl))
install_var_local (decl, ctx);
break;
case OMP_CLAUSE_SHARED:
- gcc_assert (is_parallel_ctx (ctx));
+ gcc_assert (is_taskreg_ctx (ctx));
decl = OMP_CLAUSE_DECL (c);
gcc_assert (!COMPLETE_TYPE_P (TREE_TYPE (decl))
|| !is_variable_sized (decl));
- by_ref = use_pointer_for_field (decl, ctx);
/* Global variables don't need to be copied,
the receiver side will use them directly. */
if (is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx)))
break;
+ by_ref = use_pointer_for_field (decl, ctx);
if (! TREE_READONLY (decl)
|| TREE_ADDRESSABLE (decl)
|| 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;
}
@@ -1025,13 +1326,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_parallel_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;
@@ -1044,7 +1358,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:
@@ -1060,6 +1374,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
case OMP_CLAUSE_NOWAIT:
case OMP_CLAUSE_ORDERED:
+ case OMP_CLAUSE_COLLAPSE:
+ case OMP_CLAUSE_UNTIED:
break;
default:
@@ -1074,6 +1390,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
case OMP_CLAUSE_LASTPRIVATE:
/* Let the corresponding firstprivate clause create
the variable. */
+ if (OMP_CLAUSE_LASTPRIVATE_STMT (c))
+ scan_array_reductions = true;
if (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c))
break;
/* FALLTHRU */
@@ -1106,6 +1424,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
case OMP_CLAUSE_SCHEDULE:
case OMP_CLAUSE_NOWAIT:
case OMP_CLAUSE_ORDERED:
+ case OMP_CLAUSE_COLLAPSE:
+ case OMP_CLAUSE_UNTIED:
break;
default:
@@ -1121,6 +1441,9 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
scan_omp (&OMP_CLAUSE_REDUCTION_INIT (c), ctx);
scan_omp (&OMP_CLAUSE_REDUCTION_MERGE (c), ctx);
}
+ else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
+ && OMP_CLAUSE_LASTPRIVATE_STMT (c))
+ scan_omp (&OMP_CLAUSE_LASTPRIVATE_STMT (c), ctx);
}
/* Create a new name for omp child function. Returns an identifier. */
@@ -1128,15 +1451,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
@@ -1150,17 +1475,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;
@@ -1183,7 +1515,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
@@ -1214,7 +1558,7 @@ scan_omp_parallel (tree *stmt_p, omp_context *outer_ctx)
}
ctx = new_omp_context (*stmt_p, outer_ctx);
- if (parallel_nesting_level > 1)
+ if (taskreg_nesting_level > 1)
ctx->is_nested = true;
ctx->field_map = splay_tree_new (splay_tree_compare_pointers, 0, 0);
ctx->default_kind = OMP_CLAUSE_DEFAULT_SHARED;
@@ -1222,7 +1566,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);
@@ -1237,6 +1581,84 @@ scan_omp_parallel (tree *stmt_p, omp_context *outer_ctx)
}
}
+/* Scan an OpenMP task directive. */
+
+static void
+scan_omp_task (tree *stmt_p, omp_context *outer_ctx)
+{
+ omp_context *ctx;
+ tree name;
+
+ /* Ignore task directives with empty bodies. */
+ if (optimize > 0
+ && empty_body_p (OMP_TASK_BODY (*stmt_p)))
+ {
+ *stmt_p = build_empty_stmt ();
+ return;
+ }
+
+ ctx = new_omp_context (*stmt_p, outer_ctx);
+ if (taskreg_nesting_level > 1)
+ ctx->is_nested = true;
+ ctx->field_map = splay_tree_new (splay_tree_compare_pointers, 0, 0);
+ ctx->default_kind = OMP_CLAUSE_DEFAULT_SHARED;
+ ctx->record_type = lang_hooks.types.make_type (RECORD_TYPE);
+ name = create_tmp_var_name (".omp_data_s");
+ name = build_decl (TYPE_DECL, name, ctx->record_type);
+ TYPE_NAME (ctx->record_type) = name;
+ 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;
+ 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));
+ }
+}
+
/* Scan an OpenMP loop directive. */
@@ -1245,6 +1667,7 @@ scan_omp_for (tree *stmt_p, omp_context *outer_ctx)
{
omp_context *ctx;
tree stmt;
+ int i;
stmt = *stmt_p;
ctx = new_omp_context (stmt, outer_ctx);
@@ -1252,9 +1675,12 @@ scan_omp_for (tree *stmt_p, omp_context *outer_ctx)
scan_sharing_clauses (OMP_FOR_CLAUSES (stmt), ctx);
scan_omp (&OMP_FOR_PRE_BODY (stmt), ctx);
- scan_omp (&OMP_FOR_INIT (stmt), ctx);
- scan_omp (&OMP_FOR_COND (stmt), ctx);
- scan_omp (&OMP_FOR_INCR (stmt), ctx);
+ for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (stmt)); i++)
+ {
+ scan_omp (&TREE_VEC_ELT (OMP_FOR_INIT (stmt), i), ctx);
+ scan_omp (&TREE_VEC_ELT (OMP_FOR_COND (stmt), i), ctx);
+ scan_omp (&TREE_VEC_ELT (OMP_FOR_INCR (stmt), i), ctx);
+ }
scan_omp (&OMP_FOR_BODY (stmt), ctx);
}
@@ -1307,6 +1733,7 @@ check_omp_nesting_restrictions (tree t, omp_context *ctx)
case OMP_FOR:
case OMP_SECTIONS:
case OMP_SINGLE:
+ case CALL_EXPR:
for (; ctx != NULL; ctx = ctx->outer)
switch (TREE_CODE (ctx->stmt))
{
@@ -1315,8 +1742,17 @@ check_omp_nesting_restrictions (tree t, omp_context *ctx)
case OMP_SINGLE:
case OMP_ORDERED:
case OMP_MASTER:
+ case OMP_TASK:
+ if (TREE_CODE (t) == CALL_EXPR)
+ {
+ warning (0, "barrier region may not be closely nested inside "
+ "of work-sharing, critical, ordered, master or "
+ "explicit task region");
+ return;
+ }
warning (0, "work-sharing region may not be closely nested inside "
- "of work-sharing, critical, ordered or master region");
+ "of work-sharing, critical, ordered, master or explicit "
+ "task region");
return;
case OMP_PARALLEL:
return;
@@ -1331,8 +1767,9 @@ check_omp_nesting_restrictions (tree t, omp_context *ctx)
case OMP_FOR:
case OMP_SECTIONS:
case OMP_SINGLE:
+ case OMP_TASK:
warning (0, "master region may not be closely nested inside "
- "of work-sharing region");
+ "of work-sharing or explicit task region");
return;
case OMP_PARALLEL:
return;
@@ -1345,8 +1782,9 @@ check_omp_nesting_restrictions (tree t, omp_context *ctx)
switch (TREE_CODE (ctx->stmt))
{
case OMP_CRITICAL:
+ case OMP_TASK:
warning (0, "ordered region may not be closely nested inside "
- "of critical region");
+ "of critical or explicit task region");
return;
case OMP_FOR:
if (find_omp_clause (OMP_CLAUSES (ctx->stmt),
@@ -1389,16 +1827,32 @@ scan_omp_1 (tree *tp, int *walk_subtrees, void *data)
input_location = EXPR_LOCATION (t);
/* Check the OpenMP nesting restrictions. */
- if (OMP_DIRECTIVE_P (t) && ctx != NULL)
- check_omp_nesting_restrictions (t, ctx);
+ if (ctx != NULL)
+ {
+ if (OMP_DIRECTIVE_P (t))
+ check_omp_nesting_restrictions (t, ctx);
+ else if (TREE_CODE (t) == CALL_EXPR)
+ {
+ tree fndecl = get_callee_fndecl (t);
+ if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+ && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_GOMP_BARRIER)
+ check_omp_nesting_restrictions (t, ctx);
+ }
+ }
*walk_subtrees = 0;
switch (TREE_CODE (t))
{
case OMP_PARALLEL:
- parallel_nesting_level++;
+ taskreg_nesting_level++;
scan_omp_parallel (tp, ctx);
- parallel_nesting_level--;
+ taskreg_nesting_level--;
+ break;
+
+ case OMP_TASK:
+ taskreg_nesting_level++;
+ scan_omp_task (tp, ctx);
+ taskreg_nesting_level--;
break;
case OMP_FOR:
@@ -1715,16 +2169,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))
{
@@ -1740,7 +2196,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))
@@ -1800,7 +2261,18 @@ lower_rec_input_clauses (tree clauses, tree *ilist, tree *dlist,
/* FALLTHRU */
case OMP_CLAUSE_PRIVATE:
- x = lang_hooks.decls.omp_clause_default_ctor (c, new_var);
+ if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_PRIVATE)
+ x = build_outer_var_ref (var, ctx);
+ else if (OMP_CLAUSE_PRIVATE_OUTER_REF (c))
+ {
+ if (is_task_ctx (ctx))
+ x = build_receiver_ref (var, false, ctx);
+ else
+ x = build_outer_var_ref (var, ctx);
+ }
+ else
+ x = NULL;
+ x = lang_hooks.decls.omp_clause_default_ctor (c, new_var, x);
if (x)
gimplify_and_add (x, ilist);
/* FALLTHRU */
@@ -1816,6 +2288,20 @@ 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);
@@ -1833,8 +2319,16 @@ lower_rec_input_clauses (tree clauses, tree *ilist, tree *dlist,
case OMP_CLAUSE_REDUCTION:
if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
{
+ tree placeholder = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c);
+ x = build_outer_var_ref (var, ctx);
+
+ if (is_reference (var))
+ x = build_fold_addr_expr (x);
+ SET_DECL_VALUE_EXPR (placeholder, x);
+ DECL_HAS_VALUE_EXPR_P (placeholder) = 1;
gimplify_and_add (OMP_CLAUSE_REDUCTION_INIT (c), ilist);
OMP_CLAUSE_REDUCTION_INIT (c) = NULL;
+ DECL_HAS_VALUE_EXPR_P (placeholder) = 0;
}
else
{
@@ -1879,9 +2373,10 @@ lower_rec_input_clauses (tree clauses, tree *ilist, tree *dlist,
static void
lower_lastprivate_clauses (tree clauses, tree predicate, tree *stmt_list,
- omp_context *ctx)
+ omp_context *ctx)
{
tree sub_list, x, c;
+ bool par_clauses = false;
/* Early exit if there are no lastprivate clauses. */
clauses = find_omp_clause (clauses, OMP_CLAUSE_LASTPRIVATE);
@@ -1901,25 +2396,47 @@ lower_lastprivate_clauses (tree clauses, tree predicate, tree *stmt_list,
OMP_CLAUSE_LASTPRIVATE);
if (clauses == NULL)
return;
+ par_clauses = true;
}
sub_list = alloc_stmt_list ();
- for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+ for (c = clauses; c ;)
{
tree var, new_var;
- if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_LASTPRIVATE)
- continue;
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE)
+ {
+ var = OMP_CLAUSE_DECL (c);
+ new_var = lookup_decl (var, ctx);
- var = OMP_CLAUSE_DECL (c);
- new_var = lookup_decl (var, ctx);
+ if (OMP_CLAUSE_LASTPRIVATE_STMT (c))
+ gimplify_and_add (OMP_CLAUSE_LASTPRIVATE_STMT (c), &sub_list);
+ OMP_CLAUSE_LASTPRIVATE_STMT (c) = NULL;
- x = build_outer_var_ref (var, ctx);
- if (is_reference (var))
- new_var = build_fold_indirect_ref (new_var);
- x = lang_hooks.decls.omp_clause_assign_op (c, x, new_var);
- append_to_statement_list (x, &sub_list);
+ x = build_outer_var_ref (var, ctx);
+ if (is_reference (var))
+ new_var = build_fold_indirect_ref (new_var);
+ x = lang_hooks.decls.omp_clause_assign_op (c, x, new_var);
+ append_to_statement_list (x, &sub_list);
+ }
+ c = OMP_CLAUSE_CHAIN (c);
+ if (c == NULL && !par_clauses)
+ {
+ /* If this was a workshare clause, see if it had been combined
+ with its parallel. In that case, continue looking for the
+ clauses also on the parallel statement itself. */
+ if (is_parallel_ctx (ctx))
+ break;
+
+ ctx = ctx->outer;
+ if (ctx == NULL || !is_parallel_ctx (ctx))
+ break;
+
+ c = find_omp_clause (OMP_PARALLEL_CLAUSES (ctx->stmt),
+ OMP_CLAUSE_LASTPRIVATE);
+ par_clauses = true;
+ }
}
if (predicate)
@@ -2071,6 +2588,10 @@ lower_send_clauses (tree clauses, tree *ilist, tree *olist, omp_context *ctx)
switch (OMP_CLAUSE_CODE (c))
{
+ case OMP_CLAUSE_PRIVATE:
+ if (OMP_CLAUSE_PRIVATE_OUTER_REF (c))
+ break;
+ continue;
case OMP_CLAUSE_FIRSTPRIVATE:
case OMP_CLAUSE_COPYIN:
case OMP_CLAUSE_LASTPRIVATE:
@@ -2092,6 +2613,7 @@ lower_send_clauses (tree clauses, tree *ilist, tree *olist, omp_context *ctx)
switch (OMP_CLAUSE_CODE (c))
{
+ case OMP_CLAUSE_PRIVATE:
case OMP_CLAUSE_FIRSTPRIVATE:
case OMP_CLAUSE_COPYIN:
do_in = true;
@@ -2105,7 +2627,11 @@ lower_send_clauses (tree clauses, tree *ilist, tree *olist, omp_context *ctx)
do_in = true;
}
else
- do_out = true;
+ {
+ do_out = true;
+ if (lang_hooks.decls.omp_private_outer_ref (val))
+ do_in = true;
+ }
break;
case OMP_CLAUSE_REDUCTION:
@@ -2123,6 +2649,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)
@@ -2141,12 +2669,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);
@@ -2171,9 +2700,12 @@ lower_send_shared_vars (tree *ilist, tree *olist, omp_context *ctx)
x = build_gimple_modify_stmt (x, var);
gimplify_and_add (x, ilist);
- x = build_sender_ref (ovar, ctx);
- x = build_gimple_modify_stmt (var, x);
- gimplify_and_add (x, olist);
+ if (!TREE_READONLY (var))
+ {
+ x = build_sender_ref (ovar, ctx);
+ x = build_gimple_modify_stmt (var, x);
+ gimplify_and_add (x, olist);
+ }
}
}
}
@@ -2203,8 +2735,11 @@ expand_parallel_call (struct omp_region *region, basic_block bb,
switch (region->inner->type)
{
case OMP_FOR:
+ gcc_assert (region->inner->sched_kind != OMP_CLAUSE_SCHEDULE_AUTO);
start_ix = BUILT_IN_GOMP_PARALLEL_LOOP_STATIC_START
- + region->inner->sched_kind;
+ + (region->inner->sched_kind
+ == OMP_CLAUSE_SCHEDULE_RUNTIME
+ ? 3 : region->inner->sched_kind);
break;
case OMP_SECTIONS:
start_ix = BUILT_IN_GOMP_PARALLEL_SECTIONS_START;
@@ -2347,6 +2882,80 @@ 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)));
+ 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, 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));
+ else
+ cond = boolean_true_node;
+
+ c = find_omp_clause (clauses, OMP_CLAUSE_UNTIED);
+ flags = build_int_cst (unsigned_type_node, (c ? 1 : 0));
+
+ si = bsi_last (bb);
+ t = OMP_TASK_DATA_ARG (entry_stmt);
+ if (t == NULL)
+ t2 = null_pointer_node;
+ else
+ 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], 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);
+}
+
+
/* If exceptions are enabled, wrap *STMT_P in a MUST_NOT_THROW catch
handler. This prevents programs from violating the structured
block semantics with throws. */
@@ -2460,10 +3069,12 @@ remove_exit_barriers (struct omp_region *region)
calls. These can't be declared as const functions, but
within one parallel body they are constant, so they can be
transformed there into __builtin_omp_get_{thread_num,num_threads} ()
- which are declared const. */
+ which are declared const. Similarly for task body, except
+ that in untied task omp_get_thread_num () can change at any task
+ scheduling point. */
static void
-optimize_omp_library_calls (void)
+optimize_omp_library_calls (tree entry_stmt)
{
basic_block bb;
block_stmt_iterator bsi;
@@ -2471,6 +3082,9 @@ optimize_omp_library_calls (void)
= DECL_ASSEMBLER_NAME (built_in_decls [BUILT_IN_OMP_GET_THREAD_NUM]);
tree num_thr_id
= DECL_ASSEMBLER_NAME (built_in_decls [BUILT_IN_OMP_GET_NUM_THREADS]);
+ bool untied_task = (TREE_CODE (entry_stmt) == OMP_TASK
+ && find_omp_clause (OMP_TASK_CLAUSES (entry_stmt),
+ OMP_CLAUSE_UNTIED) != NULL);
FOR_EACH_BB (bb)
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
@@ -2488,7 +3102,13 @@ optimize_omp_library_calls (void)
tree built_in;
if (DECL_NAME (decl) == thr_num_id)
- built_in = built_in_decls [BUILT_IN_OMP_GET_THREAD_NUM];
+ {
+ /* In #pragma omp task untied omp_get_thread_num () can change
+ during the execution of the task region. */
+ if (untied_task)
+ continue;
+ built_in = built_in_decls [BUILT_IN_OMP_GET_THREAD_NUM];
+ }
else if (DECL_NAME (decl) == num_thr_id)
built_in = built_in_decls [BUILT_IN_OMP_GET_NUM_THREADS];
else
@@ -2511,10 +3131,10 @@ optimize_omp_library_calls (void)
}
}
-/* Expand the OpenMP parallel directive starting at REGION. */
+/* Expand the OpenMP parallel or task directive starting at REGION. */
static void
-expand_omp_parallel (struct omp_region *region)
+expand_omp_taskreg (struct omp_region *region)
{
basic_block entry_bb, exit_bb, new_bb;
struct function *child_cfun;
@@ -2524,7 +3144,7 @@ expand_omp_parallel (struct omp_region *region)
edge e;
entry_stmt = last_stmt (region->entry);
- child_fn = OMP_PARALLEL_FN (entry_stmt);
+ child_fn = OMP_TASKREG_FN (entry_stmt);
child_cfun = DECL_STRUCT_FUNCTION (child_fn);
/* If this function has been already instrumented, make sure
the child function isn't instrumented again. */
@@ -2549,7 +3169,8 @@ expand_omp_parallel (struct omp_region *region)
entry_succ_e = single_succ_edge (entry_bb);
si = bsi_last (entry_bb);
- gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_PARALLEL);
+ gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_PARALLEL
+ || TREE_CODE (bsi_stmt (si)) == OMP_TASK);
bsi_remove (&si, true);
new_bb = entry_bb;
@@ -2575,7 +3196,7 @@ expand_omp_parallel (struct omp_region *region)
a function call that has been inlined, the original PARM_DECL
.OMP_DATA_I may have been converted into a different local
variable. In which case, we need to keep the assignment. */
- if (OMP_PARALLEL_DATA_ARG (entry_stmt))
+ if (OMP_TASKREG_DATA_ARG (entry_stmt))
{
basic_block entry_succ_bb = single_succ (entry_bb);
block_stmt_iterator si;
@@ -2594,7 +3215,7 @@ expand_omp_parallel (struct omp_region *region)
STRIP_NOPS (arg);
if (TREE_CODE (arg) == ADDR_EXPR
&& TREE_OPERAND (arg, 0)
- == OMP_PARALLEL_DATA_ARG (entry_stmt))
+ == OMP_TASKREG_DATA_ARG (entry_stmt))
{
parcopy_stmt = stmt;
break;
@@ -2633,11 +3254,12 @@ expand_omp_parallel (struct omp_region *region)
for (t = DECL_ARGUMENTS (child_fn); t; t = TREE_CHAIN (t))
DECL_CONTEXT (t) = child_fn;
- /* Split ENTRY_BB at OMP_PARALLEL so that it can be moved to the
- child function. */
+ /* Split ENTRY_BB at OMP_PARALLEL or OMP_TASK, so that it can be
+ moved to the child function. */
si = bsi_last (entry_bb);
t = bsi_stmt (si);
- gcc_assert (t && TREE_CODE (t) == OMP_PARALLEL);
+ gcc_assert (t && (TREE_CODE (t) == OMP_PARALLEL
+ || TREE_CODE (t) == OMP_TASK));
bsi_remove (&si, true);
e = split_block (entry_bb, t);
entry_bb = e->dest;
@@ -2677,7 +3299,7 @@ expand_omp_parallel (struct omp_region *region)
fixed in a following pass. */
push_cfun (child_cfun);
if (optimize)
- optimize_omp_library_calls ();
+ optimize_omp_library_calls (entry_stmt);
rebuild_cgraph_edges ();
/* Some EH regions might become dead, see PR34608. If
@@ -2701,7 +3323,10 @@ expand_omp_parallel (struct omp_region *region)
}
/* Emit a library call to launch the children threads. */
- expand_parallel_call (region, new_bb, entry_stmt, ws_args);
+ if (TREE_CODE (entry_stmt) == OMP_PARALLEL)
+ expand_parallel_call (region, new_bb, entry_stmt, ws_args);
+ else
+ expand_task_call (new_bb, entry_stmt);
update_ssa (TODO_update_ssa_only_virtuals);
}
@@ -2727,7 +3352,64 @@ expand_omp_parallel (struct omp_region *region)
L3:
If this is a combined omp parallel loop, instead of the call to
- GOMP_loop_foo_start, we call GOMP_loop_foo_next. */
+ GOMP_loop_foo_start, we call GOMP_loop_foo_next.
+
+ For collapsed loops, given parameters:
+ collapse(3)
+ for (V1 = N11; V1 cond1 N12; V1 += STEP1)
+ for (V2 = N21; V2 cond2 N22; V2 += STEP2)
+ for (V3 = N31; V3 cond3 N32; V3 += STEP3)
+ BODY;
+
+ we generate pseudocode
+
+ if (cond3 is <)
+ adj = STEP3 - 1;
+ else
+ adj = STEP3 + 1;
+ count3 = (adj + N32 - N31) / STEP3;
+ if (cond2 is <)
+ adj = STEP2 - 1;
+ else
+ adj = STEP2 + 1;
+ count2 = (adj + N22 - N21) / STEP2;
+ if (cond1 is <)
+ adj = STEP1 - 1;
+ else
+ adj = STEP1 + 1;
+ count1 = (adj + N12 - N11) / STEP1;
+ count = count1 * count2 * count3;
+ more = GOMP_loop_foo_start (0, count, 1, CHUNK, &istart0, &iend0);
+ if (more) goto L0; else goto L3;
+ L0:
+ V = istart0;
+ T = V;
+ V3 = N31 + (T % count3) * STEP3;
+ T = T / count3;
+ V2 = N21 + (T % count2) * STEP2;
+ T = T / count2;
+ V1 = N11 + T * STEP1;
+ iend = iend0;
+ L1:
+ BODY;
+ V += 1;
+ if (V < iend) goto L10; else goto L2;
+ L10:
+ V3 += STEP3;
+ if (V3 cond3 N32) goto L1; else goto L11;
+ L11:
+ V3 = N31;
+ V2 += STEP2;
+ if (V2 cond2 N22) goto L1; else goto L12;
+ L12:
+ V2 = N21;
+ V1 += STEP1;
+ goto L1;
+ L2:
+ if (GOMP_loop_foo_next (&istart0, &iend0)) goto L0; else goto L3;
+ L3:
+
+ */
static void
expand_omp_for_generic (struct omp_region *region,
@@ -2736,20 +3418,23 @@ expand_omp_for_generic (struct omp_region *region,
enum built_in_function next_fn)
{
tree type, istart0, iend0, iend, phi;
- tree t, vmain, vback;
- basic_block entry_bb, cont_bb, exit_bb, l0_bb, l1_bb;
+ tree t, vmain, vback, bias = NULL_TREE;
+ basic_block entry_bb, cont_bb, exit_bb, l0_bb, l1_bb, collapse_bb;
basic_block l2_bb = NULL, l3_bb = NULL;
block_stmt_iterator si;
bool in_combined_parallel = is_combined_parallel (region);
bool broken_loop = region->cont == NULL;
edge e, ne;
+ tree *counts = NULL;
+ int i;
gcc_assert (!broken_loop || !in_combined_parallel);
+ gcc_assert (fd->iter_type == long_integer_type_node
+ || !in_combined_parallel);
- type = TREE_TYPE (fd->v);
-
- istart0 = create_tmp_var (long_integer_type_node, ".istart0");
- iend0 = create_tmp_var (long_integer_type_node, ".iend0");
+ type = TREE_TYPE (fd->loop.v);
+ istart0 = create_tmp_var (fd->iter_type, ".istart0");
+ iend0 = create_tmp_var (fd->iter_type, ".iend0");
TREE_ADDRESSABLE (istart0) = 1;
TREE_ADDRESSABLE (iend0) = 1;
if (gimple_in_ssa_p (cfun))
@@ -2758,8 +3443,32 @@ expand_omp_for_generic (struct omp_region *region,
add_referenced_var (iend0);
}
+ /* See if we need to bias by LLONG_MIN. */
+ if (fd->iter_type == long_long_unsigned_type_node
+ && TREE_CODE (type) == INTEGER_TYPE
+ && !TYPE_UNSIGNED (type))
+ {
+ tree n1, n2;
+
+ if (fd->loop.cond_code == LT_EXPR)
+ {
+ n1 = fd->loop.n1;
+ n2 = fold_build2 (PLUS_EXPR, type, fd->loop.n2, fd->loop.step);
+ }
+ else
+ {
+ n1 = fold_build2 (MINUS_EXPR, type, fd->loop.n2, fd->loop.step);
+ n2 = fd->loop.n1;
+ }
+ if (TREE_CODE (n1) != INTEGER_CST
+ || TREE_CODE (n2) != INTEGER_CST
+ || ((tree_int_cst_sgn (n1) < 0) ^ (tree_int_cst_sgn (n2) < 0)))
+ bias = fold_convert (fd->iter_type, TYPE_MIN_VALUE (type));
+ }
+
entry_bb = region->entry;
cont_bb = region->cont;
+ collapse_bb = NULL;
gcc_assert (EDGE_COUNT (entry_bb->succs) == 2);
gcc_assert (broken_loop
|| BRANCH_EDGE (entry_bb)->dest == FALLTHRU_EDGE (cont_bb)->dest);
@@ -2777,7 +3486,60 @@ expand_omp_for_generic (struct omp_region *region,
exit_bb = region->exit;
si = bsi_last (entry_bb);
+
gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_FOR);
+ if (fd->collapse > 1)
+ {
+ /* collapsed loops need work for expansion in SSA form. */
+ gcc_assert (!gimple_in_ssa_p (cfun));
+ counts = (tree *) alloca (fd->collapse * sizeof (tree));
+ for (i = 0; i < fd->collapse; i++)
+ {
+ tree itype = TREE_TYPE (fd->loops[i].v);
+
+ if (POINTER_TYPE_P (itype))
+ itype = lang_hooks.types.type_for_size (TYPE_PRECISION (itype), 0);
+ t = build_int_cst (itype, (fd->loops[i].cond_code == LT_EXPR
+ ? -1 : 1));
+ t = fold_build2 (PLUS_EXPR, itype,
+ fold_convert (itype, fd->loops[i].step), t);
+ t = fold_build2 (PLUS_EXPR, itype, t,
+ fold_convert (itype, fd->loops[i].n2));
+ t = fold_build2 (MINUS_EXPR, itype, t,
+ fold_convert (itype, fd->loops[i].n1));
+ if (TYPE_UNSIGNED (itype) && fd->loops[i].cond_code == GT_EXPR)
+ t = fold_build2 (TRUNC_DIV_EXPR, itype,
+ fold_build1 (NEGATE_EXPR, itype, t),
+ fold_build1 (NEGATE_EXPR, itype,
+ fold_convert (itype,
+ fd->loops[i].step)));
+ else
+ t = fold_build2 (TRUNC_DIV_EXPR, itype, t,
+ fold_convert (itype, fd->loops[i].step));
+ t = fold_convert (type, t);
+ if (TREE_CODE (t) == INTEGER_CST)
+ counts[i] = t;
+ else
+ {
+ counts[i] = create_tmp_var (type, ".count");
+ t = build_gimple_modify_stmt (counts[i], t);
+ force_gimple_operand_bsi (&si, t, true, NULL_TREE,
+ true, BSI_SAME_STMT);
+ }
+ if (SSA_VAR_P (fd->loop.n2))
+ {
+ if (i == 0)
+ t = build_gimple_modify_stmt (fd->loop.n2, counts[0]);
+ else
+ {
+ t = fold_build2 (MULT_EXPR, type, fd->loop.n2, counts[i]);
+ t = build_gimple_modify_stmt (fd->loop.n2, t);
+ }
+ force_gimple_operand_bsi (&si, t, true, NULL_TREE,
+ true, BSI_SAME_STMT);
+ }
+ }
+ }
if (in_combined_parallel)
{
/* In a combined parallel loop, emit a call to
@@ -2793,19 +3555,52 @@ expand_omp_for_generic (struct omp_region *region,
GOMP_loop_foo_start in ENTRY_BB. */
t4 = build_fold_addr_expr (iend0);
t3 = build_fold_addr_expr (istart0);
- t2 = fold_convert (long_integer_type_node, fd->step);
- t1 = fold_convert (long_integer_type_node, fd->n2);
- t0 = fold_convert (long_integer_type_node, fd->n1);
- if (fd->chunk_size)
+ t2 = fold_convert (fd->iter_type, fd->loop.step);
+ t1 = fold_convert (fd->iter_type, fd->loop.n2);
+ t0 = fold_convert (fd->iter_type, fd->loop.n1);
+ if (bias)
{
- t = fold_convert (long_integer_type_node, fd->chunk_size);
- t = build_call_expr (built_in_decls[start_fn], 6,
- t0, t1, t2, t, t3, t4);
+ t1 = fold_build2 (PLUS_EXPR, fd->iter_type, t1, bias);
+ t0 = fold_build2 (PLUS_EXPR, fd->iter_type, t0, bias);
+ }
+ if (fd->iter_type == long_integer_type_node)
+ {
+ if (fd->chunk_size)
+ {
+ t = fold_convert (fd->iter_type, fd->chunk_size);
+ t = build_call_expr (built_in_decls[start_fn], 6,
+ t0, t1, t2, t, t3, t4);
+ }
+ else
+ t = build_call_expr (built_in_decls[start_fn], 5,
+ t0, t1, t2, t3, t4);
}
else
- t = build_call_expr (built_in_decls[start_fn], 5,
- t0, t1, t2, t3, t4);
+ {
+ tree t5;
+ tree c_bool_type;
+
+ /* The GOMP_loop_ull_*start functions have additional boolean
+ argument, true for < loops and false for > loops.
+ In Fortran, the C bool type can be different from
+ boolean_type_node. */
+ c_bool_type = TREE_TYPE (TREE_TYPE (built_in_decls[start_fn]));
+ t5 = build_int_cst (c_bool_type,
+ fd->loop.cond_code == LT_EXPR ? 1 : 0);
+ if (fd->chunk_size)
+ {
+ t = fold_convert (fd->iter_type, fd->chunk_size);
+ t = build_call_expr (built_in_decls[start_fn], 7,
+ t5, t0, t1, t2, t, t3, t4);
+ }
+ else
+ t = build_call_expr (built_in_decls[start_fn], 6,
+ t5, t0, t1, t2, t3, t4);
+ }
}
+ if (TREE_TYPE (t) != boolean_type_node)
+ t = fold_build2 (NE_EXPR, boolean_type_node,
+ t, build_int_cst (TREE_TYPE (t), 0));
t = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
true, BSI_SAME_STMT);
t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
@@ -2816,17 +3611,57 @@ expand_omp_for_generic (struct omp_region *region,
/* Iteration setup for sequential loop goes in L0_BB. */
si = bsi_start (l0_bb);
- t = fold_convert (type, istart0);
+ if (bias)
+ t = fold_convert (type, fold_build2 (MINUS_EXPR, fd->iter_type,
+ istart0, bias));
+ else
+ t = fold_convert (type, istart0);
t = force_gimple_operand_bsi (&si, t, false, NULL_TREE,
false, BSI_CONTINUE_LINKING);
- t = build_gimple_modify_stmt (fd->v, t);
+ t = build_gimple_modify_stmt (fd->loop.v, t);
bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
if (gimple_in_ssa_p (cfun))
- SSA_NAME_DEF_STMT (fd->v) = t;
+ SSA_NAME_DEF_STMT (fd->loop.v) = t;
- t = fold_convert (type, iend0);
+ if (bias)
+ t = fold_convert (type, fold_build2 (MINUS_EXPR, fd->iter_type,
+ iend0, bias));
+ else
+ t = fold_convert (type, iend0);
iend = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
false, BSI_CONTINUE_LINKING);
+ if (fd->collapse > 1)
+ {
+ tree tem = create_tmp_var (type, ".tem");
+
+ t = build_gimple_modify_stmt (tem, fd->loop.v);
+ bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
+ for (i = fd->collapse - 1; i >= 0; i--)
+ {
+ tree vtype = TREE_TYPE (fd->loops[i].v), itype;
+ itype = vtype;
+ if (POINTER_TYPE_P (vtype))
+ itype = lang_hooks.types.type_for_size (TYPE_PRECISION (vtype), 0);
+ t = fold_build2 (TRUNC_MOD_EXPR, type, tem, counts[i]);
+ t = fold_convert (itype, t);
+ t = fold_build2 (MULT_EXPR, itype, t, fd->loops[i].step);
+ if (POINTER_TYPE_P (vtype))
+ t = fold_build2 (POINTER_PLUS_EXPR, vtype,
+ fd->loops[i].n1, fold_convert (sizetype, t));
+ else
+ t = fold_build2 (PLUS_EXPR, itype, fd->loops[i].n1, t);
+ t = build_gimple_modify_stmt (fd->loops[i].v, t);
+ force_gimple_operand_bsi (&si, t, true, NULL_TREE,
+ false, BSI_CONTINUE_LINKING);
+ if (i != 0)
+ {
+ t = fold_build2 (TRUNC_DIV_EXPR, type, tem, counts[i]);
+ t = build_gimple_modify_stmt (tem, t);
+ force_gimple_operand_bsi (&si, t, true, NULL_TREE,
+ false, BSI_CONTINUE_LINKING);
+ }
+ }
+ }
if (!broken_loop)
{
@@ -2838,7 +3673,11 @@ expand_omp_for_generic (struct omp_region *region,
vmain = TREE_OPERAND (t, 1);
vback = TREE_OPERAND (t, 0);
- t = fold_build2 (PLUS_EXPR, type, vmain, fd->step);
+ if (POINTER_TYPE_P (type))
+ t = fold_build2 (POINTER_PLUS_EXPR, type, vmain,
+ fold_convert (sizetype, fd->loop.step));
+ else
+ t = fold_build2 (PLUS_EXPR, type, vmain, fd->loop.step);
t = force_gimple_operand_bsi (&si, t, false, NULL_TREE,
true, BSI_SAME_STMT);
t = build_gimple_modify_stmt (vback, t);
@@ -2846,19 +3685,78 @@ expand_omp_for_generic (struct omp_region *region,
if (gimple_in_ssa_p (cfun))
SSA_NAME_DEF_STMT (vback) = t;
- t = build2 (fd->cond_code, boolean_type_node, vback, iend);
+ t = build2 (fd->loop.cond_code, boolean_type_node, vback, iend);
t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
bsi_insert_before (&si, t, BSI_SAME_STMT);
/* Remove OMP_CONTINUE. */
bsi_remove (&si, true);
+ if (fd->collapse > 1)
+ {
+ basic_block last_bb, bb;
+
+ last_bb = cont_bb;
+ for (i = fd->collapse - 1; i >= 0; i--)
+ {
+ tree vtype = TREE_TYPE (fd->loops[i].v);
+
+ bb = create_empty_bb (last_bb);
+ si = bsi_start (bb);
+
+ if (i < fd->collapse - 1)
+ {
+ e = make_edge (last_bb, bb, EDGE_FALSE_VALUE);
+ e->probability = REG_BR_PROB_BASE / 8;
+
+ t = build_gimple_modify_stmt (fd->loops[i + 1].v,
+ fd->loops[i + 1].n1);
+ force_gimple_operand_bsi (&si, t, true, NULL_TREE,
+ false, BSI_CONTINUE_LINKING);
+ }
+ else
+ collapse_bb = bb;
+
+ set_immediate_dominator (CDI_DOMINATORS, bb, last_bb);
+
+ if (POINTER_TYPE_P (vtype))
+ t = fold_build2 (POINTER_PLUS_EXPR, vtype,
+ fd->loops[i].v,
+ fold_convert (sizetype, fd->loops[i].step));
+ else
+ t = fold_build2 (PLUS_EXPR, vtype, fd->loops[i].v,
+ fd->loops[i].step);
+ t = build_gimple_modify_stmt (fd->loops[i].v, t);
+ force_gimple_operand_bsi (&si, t, true, NULL_TREE,
+ false, BSI_CONTINUE_LINKING);
+
+ if (i > 0)
+ {
+ t = fold_build2 (fd->loops[i].cond_code, boolean_type_node,
+ fd->loops[i].v, fd->loops[i].n2);
+ t = force_gimple_operand_bsi (&si, t, false, NULL_TREE,
+ false, BSI_CONTINUE_LINKING);
+ t = build3 (COND_EXPR, void_type_node, t,
+ NULL_TREE, NULL_TREE);
+ bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
+ e = make_edge (bb, l1_bb, EDGE_TRUE_VALUE);
+ e->probability = REG_BR_PROB_BASE * 7 / 8;
+ }
+ else
+ make_edge (bb, l1_bb, EDGE_FALLTHRU);
+ last_bb = bb;
+ }
+ }
+
/* Emit code to get the next parallel iteration in L2_BB. */
si = bsi_start (l2_bb);
t = build_call_expr (built_in_decls[next_fn], 2,
build_fold_addr_expr (istart0),
build_fold_addr_expr (iend0));
+ if (TREE_TYPE (t) != boolean_type_node)
+ t = fold_build2 (NE_EXPR, boolean_type_node,
+ t, build_int_cst (TREE_TYPE (t), 0));
t = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
false, BSI_CONTINUE_LINKING);
t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
@@ -2889,8 +3787,20 @@ expand_omp_for_generic (struct omp_region *region,
PHI_ARG_DEF_FROM_EDGE (phi, e));
remove_edge (e);
- find_edge (cont_bb, l1_bb)->flags = EDGE_TRUE_VALUE;
make_edge (cont_bb, l2_bb, EDGE_FALSE_VALUE);
+ if (fd->collapse > 1)
+ {
+ e = find_edge (cont_bb, l1_bb);
+ remove_edge (e);
+ e = make_edge (cont_bb, collapse_bb, EDGE_TRUE_VALUE);
+ }
+ else
+ {
+ e = find_edge (cont_bb, l1_bb);
+ e->flags = EDGE_TRUE_VALUE;
+ }
+ e->probability = REG_BR_PROB_BASE * 7 / 8;
+ find_edge (cont_bb, l2_bb)->probability = REG_BR_PROB_BASE / 8;
make_edge (l2_bb, l0_bb, EDGE_TRUE_VALUE);
set_immediate_dominator (CDI_DOMINATORS, l2_bb,
@@ -2917,7 +3827,10 @@ expand_omp_for_generic (struct omp_region *region,
adj = STEP - 1;
else
adj = STEP + 1;
- n = (adj + N2 - N1) / STEP;
+ if ((__typeof (V)) -1 > 0 && cond is >)
+ n = -(adj + N2 - N1) / -STEP;
+ else
+ n = (adj + N2 - N1) / STEP;
q = n / nthreads;
q += (q * nthreads != n);
s0 = q * threadid;
@@ -2938,12 +3851,14 @@ expand_omp_for_static_nochunk (struct omp_region *region,
struct omp_for_data *fd)
{
tree n, q, s0, e0, e, t, nthreads, threadid;
- tree type, vmain, vback;
+ tree type, itype, vmain, vback;
basic_block entry_bb, exit_bb, seq_start_bb, body_bb, cont_bb;
basic_block fin_bb;
block_stmt_iterator si;
- type = TREE_TYPE (fd->v);
+ itype = type = TREE_TYPE (fd->loop.v);
+ if (POINTER_TYPE_P (type))
+ itype = lang_hooks.types.type_for_size (TYPE_PRECISION (type), 0);
entry_bb = region->entry;
cont_bb = region->cont;
@@ -2961,51 +3876,51 @@ expand_omp_for_static_nochunk (struct omp_region *region,
gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_FOR);
t = build_call_expr (built_in_decls[BUILT_IN_OMP_GET_NUM_THREADS], 0);
- t = fold_convert (type, t);
+ t = fold_convert (itype, t);
nthreads = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
true, BSI_SAME_STMT);
t = build_call_expr (built_in_decls[BUILT_IN_OMP_GET_THREAD_NUM], 0);
- t = fold_convert (type, t);
+ t = fold_convert (itype, t);
threadid = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
true, BSI_SAME_STMT);
- fd->n1 = force_gimple_operand_bsi (&si,
- fold_convert (type, fd->n1),
- true, NULL_TREE,
- true, BSI_SAME_STMT);
-
- fd->n2 = force_gimple_operand_bsi (&si,
- fold_convert (type, fd->n2),
- true, NULL_TREE,
- true, BSI_SAME_STMT);
-
- fd->step = force_gimple_operand_bsi (&si,
- fold_convert (type, fd->step),
- true, NULL_TREE,
- true, BSI_SAME_STMT);
-
- t = build_int_cst (type, (fd->cond_code == LT_EXPR ? -1 : 1));
- t = fold_build2 (PLUS_EXPR, type, fd->step, t);
- t = fold_build2 (PLUS_EXPR, type, t, fd->n2);
- t = fold_build2 (MINUS_EXPR, type, t, fd->n1);
- t = fold_build2 (TRUNC_DIV_EXPR, type, t, fd->step);
- t = fold_convert (type, t);
+ fd->loop.n1
+ = force_gimple_operand_bsi (&si, fold_convert (type, fd->loop.n1),
+ true, NULL_TREE, true, BSI_SAME_STMT);
+ fd->loop.n2
+ = force_gimple_operand_bsi (&si, fold_convert (itype, fd->loop.n2),
+ true, NULL_TREE, true, BSI_SAME_STMT);
+ fd->loop.step
+ = force_gimple_operand_bsi (&si, fold_convert (itype, fd->loop.step),
+ true, NULL_TREE, true, BSI_SAME_STMT);
+
+ t = build_int_cst (itype, (fd->loop.cond_code == LT_EXPR ? -1 : 1));
+ t = fold_build2 (PLUS_EXPR, itype, fd->loop.step, t);
+ t = fold_build2 (PLUS_EXPR, itype, t, fd->loop.n2);
+ t = fold_build2 (MINUS_EXPR, itype, t, fold_convert (itype, fd->loop.n1));
+ if (TYPE_UNSIGNED (itype) && fd->loop.cond_code == GT_EXPR)
+ t = fold_build2 (TRUNC_DIV_EXPR, itype,
+ fold_build1 (NEGATE_EXPR, itype, t),
+ fold_build1 (NEGATE_EXPR, itype, fd->loop.step));
+ else
+ t = fold_build2 (TRUNC_DIV_EXPR, itype, t, fd->loop.step);
+ t = fold_convert (itype, t);
n = force_gimple_operand_bsi (&si, t, true, NULL_TREE, true, BSI_SAME_STMT);
- t = fold_build2 (TRUNC_DIV_EXPR, type, n, nthreads);
+ t = fold_build2 (TRUNC_DIV_EXPR, itype, n, nthreads);
q = force_gimple_operand_bsi (&si, t, true, NULL_TREE, true, BSI_SAME_STMT);
- t = fold_build2 (MULT_EXPR, type, q, nthreads);
- t = fold_build2 (NE_EXPR, type, t, n);
- t = fold_build2 (PLUS_EXPR, type, q, t);
+ t = fold_build2 (MULT_EXPR, itype, q, nthreads);
+ t = fold_build2 (NE_EXPR, itype, t, n);
+ t = fold_build2 (PLUS_EXPR, itype, q, t);
q = force_gimple_operand_bsi (&si, t, true, NULL_TREE, true, BSI_SAME_STMT);
- t = build2 (MULT_EXPR, type, q, threadid);
+ t = build2 (MULT_EXPR, itype, q, threadid);
s0 = force_gimple_operand_bsi (&si, t, true, NULL_TREE, true, BSI_SAME_STMT);
- t = fold_build2 (PLUS_EXPR, type, s0, q);
- t = fold_build2 (MIN_EXPR, type, t, n);
+ t = fold_build2 (PLUS_EXPR, itype, s0, q);
+ t = fold_build2 (MIN_EXPR, itype, t, n);
e0 = force_gimple_operand_bsi (&si, t, true, NULL_TREE, true, BSI_SAME_STMT);
t = build2 (GE_EXPR, boolean_type_node, s0, e0);
@@ -3018,19 +3933,27 @@ expand_omp_for_static_nochunk (struct omp_region *region,
/* Setup code for sequential iteration goes in SEQ_START_BB. */
si = bsi_start (seq_start_bb);
- t = fold_convert (type, s0);
- t = fold_build2 (MULT_EXPR, type, t, fd->step);
- t = fold_build2 (PLUS_EXPR, type, t, fd->n1);
+ t = fold_convert (itype, s0);
+ t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step);
+ if (POINTER_TYPE_P (type))
+ t = fold_build2 (POINTER_PLUS_EXPR, type, fd->loop.n1,
+ fold_convert (sizetype, t));
+ else
+ t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1);
t = force_gimple_operand_bsi (&si, t, false, NULL_TREE,
false, BSI_CONTINUE_LINKING);
- t = build_gimple_modify_stmt (fd->v, t);
+ t = build_gimple_modify_stmt (fd->loop.v, t);
bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
if (gimple_in_ssa_p (cfun))
- SSA_NAME_DEF_STMT (fd->v) = t;
+ SSA_NAME_DEF_STMT (fd->loop.v) = t;
- t = fold_convert (type, e0);
- t = fold_build2 (MULT_EXPR, type, t, fd->step);
- t = fold_build2 (PLUS_EXPR, type, t, fd->n1);
+ t = fold_convert (itype, e0);
+ t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step);
+ if (POINTER_TYPE_P (type))
+ t = fold_build2 (POINTER_PLUS_EXPR, type, fd->loop.n1,
+ fold_convert (sizetype, t));
+ else
+ t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1);
e = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
false, BSI_CONTINUE_LINKING);
@@ -3041,7 +3964,11 @@ expand_omp_for_static_nochunk (struct omp_region *region,
vmain = TREE_OPERAND (t, 1);
vback = TREE_OPERAND (t, 0);
- t = fold_build2 (PLUS_EXPR, type, vmain, fd->step);
+ if (POINTER_TYPE_P (type))
+ t = fold_build2 (POINTER_PLUS_EXPR, type, vmain,
+ fold_convert (sizetype, fd->loop.step));
+ else
+ t = fold_build2 (PLUS_EXPR, type, vmain, fd->loop.step);
t = force_gimple_operand_bsi (&si, t, false, NULL_TREE,
true, BSI_SAME_STMT);
t = build_gimple_modify_stmt (vback, t);
@@ -3049,7 +3976,7 @@ expand_omp_for_static_nochunk (struct omp_region *region,
if (gimple_in_ssa_p (cfun))
SSA_NAME_DEF_STMT (vback) = t;
- t = build2 (fd->cond_code, boolean_type_node, vback, e);
+ t = build2 (fd->loop.cond_code, boolean_type_node, vback, e);
t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
bsi_insert_before (&si, t, BSI_SAME_STMT);
@@ -3090,7 +4017,10 @@ expand_omp_for_static_nochunk (struct omp_region *region,
adj = STEP - 1;
else
adj = STEP + 1;
- n = (adj + N2 - N1) / STEP;
+ if ((__typeof (V)) -1 > 0 && cond is >)
+ n = -(adj + N2 - N1) / -STEP;
+ else
+ n = (adj + N2 - N1) / STEP;
trip = 0;
V = threadid * CHUNK * STEP + N1; -- this extra definition of V is
here so that V is defined
@@ -3113,17 +4043,20 @@ expand_omp_for_static_nochunk (struct omp_region *region,
*/
static void
-expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd)
+expand_omp_for_static_chunk (struct omp_region *region,
+ struct omp_for_data *fd)
{
tree n, s0, e0, e, t, phi, nphi, args;
tree trip_var, trip_init, trip_main, trip_back, nthreads, threadid;
- tree type, cont, v_main, v_back, v_extra;
+ tree type, itype, cont, v_main, v_back, v_extra;
basic_block entry_bb, exit_bb, body_bb, seq_start_bb, iter_part_bb;
basic_block trip_update_bb, cont_bb, fin_bb;
block_stmt_iterator si;
edge se, re, ene;
- type = TREE_TYPE (fd->v);
+ itype = type = TREE_TYPE (fd->loop.v);
+ if (POINTER_TYPE_P (type))
+ itype = lang_hooks.types.type_for_size (TYPE_PRECISION (type), 0);
entry_bb = region->entry;
se = split_block (entry_bb, last_stmt (entry_bb));
@@ -3146,40 +4079,43 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd)
gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_FOR);
t = build_call_expr (built_in_decls[BUILT_IN_OMP_GET_NUM_THREADS], 0);
- t = fold_convert (type, t);
+ t = fold_convert (itype, t);
nthreads = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
true, BSI_SAME_STMT);
t = build_call_expr (built_in_decls[BUILT_IN_OMP_GET_THREAD_NUM], 0);
- t = fold_convert (type, t);
+ t = fold_convert (itype, t);
threadid = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
true, BSI_SAME_STMT);
- fd->n1 = force_gimple_operand_bsi (&si, fold_convert (type, fd->n1),
- true, NULL_TREE,
- true, BSI_SAME_STMT);
- fd->n2 = force_gimple_operand_bsi (&si, fold_convert (type, fd->n2),
- true, NULL_TREE,
- true, BSI_SAME_STMT);
- fd->step = force_gimple_operand_bsi (&si, fold_convert (type, fd->step),
- true, NULL_TREE,
- true, BSI_SAME_STMT);
+ fd->loop.n1
+ = force_gimple_operand_bsi (&si, fold_convert (type, fd->loop.n1),
+ true, NULL_TREE, true, BSI_SAME_STMT);
+ fd->loop.n2
+ = force_gimple_operand_bsi (&si, fold_convert (itype, fd->loop.n2),
+ true, NULL_TREE, true, BSI_SAME_STMT);
+ fd->loop.step
+ = force_gimple_operand_bsi (&si, fold_convert (itype, fd->loop.step),
+ true, NULL_TREE, true, BSI_SAME_STMT);
fd->chunk_size
- = force_gimple_operand_bsi (&si, fold_convert (type,
- fd->chunk_size),
- true, NULL_TREE,
- true, BSI_SAME_STMT);
-
- t = build_int_cst (type, (fd->cond_code == LT_EXPR ? -1 : 1));
- t = fold_build2 (PLUS_EXPR, type, fd->step, t);
- t = fold_build2 (PLUS_EXPR, type, t, fd->n2);
- t = fold_build2 (MINUS_EXPR, type, t, fd->n1);
- t = fold_build2 (TRUNC_DIV_EXPR, type, t, fd->step);
- t = fold_convert (type, t);
+ = force_gimple_operand_bsi (&si, fold_convert (itype, fd->chunk_size),
+ true, NULL_TREE, true, BSI_SAME_STMT);
+
+ t = build_int_cst (itype, (fd->loop.cond_code == LT_EXPR ? -1 : 1));
+ t = fold_build2 (PLUS_EXPR, itype, fd->loop.step, t);
+ t = fold_build2 (PLUS_EXPR, itype, t, fd->loop.n2);
+ t = fold_build2 (MINUS_EXPR, itype, t, fold_convert (itype, fd->loop.n1));
+ if (TYPE_UNSIGNED (itype) && fd->loop.cond_code == GT_EXPR)
+ t = fold_build2 (TRUNC_DIV_EXPR, itype,
+ fold_build1 (NEGATE_EXPR, itype, t),
+ fold_build1 (NEGATE_EXPR, itype, fd->loop.step));
+ else
+ t = fold_build2 (TRUNC_DIV_EXPR, itype, t, fd->loop.step);
+ t = fold_convert (itype, t);
n = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
true, BSI_SAME_STMT);
- trip_var = create_tmp_var (type, ".trip");
+ trip_var = create_tmp_var (itype, ".trip");
if (gimple_in_ssa_p (cfun))
{
add_referenced_var (trip_var);
@@ -3194,14 +4130,18 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd)
trip_back = trip_var;
}
- t = build_gimple_modify_stmt (trip_init, build_int_cst (type, 0));
+ t = build_gimple_modify_stmt (trip_init, build_int_cst (itype, 0));
bsi_insert_before (&si, t, BSI_SAME_STMT);
if (gimple_in_ssa_p (cfun))
SSA_NAME_DEF_STMT (trip_init) = t;
- t = fold_build2 (MULT_EXPR, type, threadid, fd->chunk_size);
- t = fold_build2 (MULT_EXPR, type, t, fd->step);
- t = fold_build2 (PLUS_EXPR, type, t, fd->n1);
+ t = fold_build2 (MULT_EXPR, itype, threadid, fd->chunk_size);
+ t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step);
+ if (POINTER_TYPE_P (type))
+ t = fold_build2 (POINTER_PLUS_EXPR, type, fd->loop.n1,
+ fold_convert (sizetype, t));
+ else
+ t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1);
v_extra = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
true, BSI_SAME_STMT);
@@ -3211,14 +4151,14 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd)
/* Iteration space partitioning goes in ITER_PART_BB. */
si = bsi_last (iter_part_bb);
- t = fold_build2 (MULT_EXPR, type, trip_main, nthreads);
- t = fold_build2 (PLUS_EXPR, type, t, threadid);
- t = fold_build2 (MULT_EXPR, type, t, fd->chunk_size);
+ t = fold_build2 (MULT_EXPR, itype, trip_main, nthreads);
+ t = fold_build2 (PLUS_EXPR, itype, t, threadid);
+ t = fold_build2 (MULT_EXPR, itype, t, fd->chunk_size);
s0 = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
false, BSI_CONTINUE_LINKING);
- t = fold_build2 (PLUS_EXPR, type, s0, fd->chunk_size);
- t = fold_build2 (MIN_EXPR, type, t, n);
+ t = fold_build2 (PLUS_EXPR, itype, s0, fd->chunk_size);
+ t = fold_build2 (MIN_EXPR, itype, t, n);
e0 = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
false, BSI_CONTINUE_LINKING);
@@ -3229,19 +4169,27 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd)
/* Setup code for sequential iteration goes in SEQ_START_BB. */
si = bsi_start (seq_start_bb);
- t = fold_convert (type, s0);
- t = fold_build2 (MULT_EXPR, type, t, fd->step);
- t = fold_build2 (PLUS_EXPR, type, t, fd->n1);
+ t = fold_convert (itype, s0);
+ t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step);
+ if (POINTER_TYPE_P (type))
+ t = fold_build2 (POINTER_PLUS_EXPR, type, fd->loop.n1,
+ fold_convert (sizetype, t));
+ else
+ t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1);
t = force_gimple_operand_bsi (&si, t, false, NULL_TREE,
false, BSI_CONTINUE_LINKING);
- t = build_gimple_modify_stmt (fd->v, t);
+ t = build_gimple_modify_stmt (fd->loop.v, t);
bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
if (gimple_in_ssa_p (cfun))
- SSA_NAME_DEF_STMT (fd->v) = t;
+ SSA_NAME_DEF_STMT (fd->loop.v) = t;
- t = fold_convert (type, e0);
- t = fold_build2 (MULT_EXPR, type, t, fd->step);
- t = fold_build2 (PLUS_EXPR, type, t, fd->n1);
+ t = fold_convert (itype, e0);
+ t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step);
+ if (POINTER_TYPE_P (type))
+ t = fold_build2 (POINTER_PLUS_EXPR, type, fd->loop.n1,
+ fold_convert (sizetype, t));
+ else
+ t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1);
e = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
false, BSI_CONTINUE_LINKING);
@@ -3253,13 +4201,17 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd)
v_main = TREE_OPERAND (cont, 1);
v_back = TREE_OPERAND (cont, 0);
- t = build2 (PLUS_EXPR, type, v_main, fd->step);
+ if (POINTER_TYPE_P (type))
+ t = fold_build2 (POINTER_PLUS_EXPR, type, v_main,
+ fold_convert (sizetype, fd->loop.step));
+ else
+ t = build2 (PLUS_EXPR, type, v_main, fd->loop.step);
t = build_gimple_modify_stmt (v_back, t);
bsi_insert_before (&si, t, BSI_SAME_STMT);
if (gimple_in_ssa_p (cfun))
SSA_NAME_DEF_STMT (v_back) = t;
- t = build2 (fd->cond_code, boolean_type_node, v_back, e);
+ t = build2 (fd->loop.cond_code, boolean_type_node, v_back, e);
t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
bsi_insert_before (&si, t, BSI_SAME_STMT);
@@ -3269,8 +4221,8 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd)
/* Trip update code goes into TRIP_UPDATE_BB. */
si = bsi_start (trip_update_bb);
- t = build_int_cst (type, 1);
- t = build2 (PLUS_EXPR, type, trip_main, t);
+ t = build_int_cst (itype, 1);
+ t = build2 (PLUS_EXPR, itype, trip_main, t);
t = build_gimple_modify_stmt (trip_back, t);
bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
if (gimple_in_ssa_p (cfun))
@@ -3313,9 +4265,9 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd)
SSA_NAME_DEF_STMT (t) = nphi;
t = PHI_ARG_DEF_FROM_EDGE (phi, se);
- /* A special case -- fd->v is not yet computed in iter_part_bb, we
- need to use v_extra instead. */
- if (t == fd->v)
+ /* A special case -- fd->loop.v is not yet computed in
+ iter_part_bb, we need to use v_extra instead. */
+ if (t == fd->loop.v)
t = v_extra;
add_phi_arg (nphi, t, ene);
add_phi_arg (nphi, TREE_VALUE (args), re);
@@ -3349,8 +4301,14 @@ static void
expand_omp_for (struct omp_region *region)
{
struct omp_for_data fd;
+ struct omp_for_data_loop *loops;
- extract_omp_for_data (last_stmt (region->entry), &fd);
+ loops
+ = (struct omp_for_data_loop *)
+ alloca (TREE_VEC_LENGTH (OMP_FOR_INIT (last_stmt (region->entry)))
+ * sizeof (struct omp_for_data_loop));
+
+ extract_omp_for_data (last_stmt (region->entry), &fd, loops);
region->sched_kind = fd.sched_kind;
gcc_assert (EDGE_COUNT (region->entry->succs) == 2);
@@ -3365,6 +4323,7 @@ expand_omp_for (struct omp_region *region)
if (fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC
&& !fd.have_ordered
+ && fd.collapse == 1
&& region->cont != NULL)
{
if (fd.chunk_size == NULL)
@@ -3374,9 +4333,21 @@ expand_omp_for (struct omp_region *region)
}
else
{
- int fn_index = fd.sched_kind + fd.have_ordered * 4;
- int start_ix = BUILT_IN_GOMP_LOOP_STATIC_START + fn_index;
- int next_ix = BUILT_IN_GOMP_LOOP_STATIC_NEXT + fn_index;
+ int fn_index, start_ix, next_ix;
+
+ gcc_assert (fd.sched_kind != OMP_CLAUSE_SCHEDULE_AUTO);
+ fn_index = (fd.sched_kind == OMP_CLAUSE_SCHEDULE_RUNTIME)
+ ? 3 : fd.sched_kind;
+ fn_index += fd.have_ordered * 4;
+ start_ix = BUILT_IN_GOMP_LOOP_STATIC_START + fn_index;
+ next_ix = BUILT_IN_GOMP_LOOP_STATIC_NEXT + fn_index;
+ if (fd.iter_type == long_long_unsigned_type_node)
+ {
+ start_ix += BUILT_IN_GOMP_LOOP_ULL_STATIC_START
+ - BUILT_IN_GOMP_LOOP_STATIC_START;
+ next_ix += BUILT_IN_GOMP_LOOP_ULL_STATIC_NEXT
+ - BUILT_IN_GOMP_LOOP_STATIC_NEXT;
+ }
expand_omp_for_generic (region, &fd, start_ix, next_ix);
}
@@ -4037,7 +5008,11 @@ expand_omp (struct omp_region *region)
switch (region->type)
{
case OMP_PARALLEL:
- expand_omp_parallel (region);
+ expand_omp_taskreg (region);
+ break;
+
+ case OMP_TASK:
+ expand_omp_taskreg (region);
break;
case OMP_FOR:
@@ -4355,6 +5330,9 @@ lower_omp_single_simple (tree single_stmt, tree *pre_p)
tree t;
t = build_call_expr (built_in_decls[BUILT_IN_GOMP_SINGLE_START], 0);
+ if (TREE_TYPE (t) != boolean_type_node)
+ t = fold_build2 (NE_EXPR, boolean_type_node,
+ t, build_int_cst (TREE_TYPE (t), 0));
t = build3 (COND_EXPR, void_type_node, t,
OMP_SINGLE_BODY (single_stmt), NULL);
gimplify_and_add (t, pre_p);
@@ -4661,37 +5639,38 @@ lower_omp_for_lastprivate (struct omp_for_data *fd, tree *body_p,
tree clauses, cond, stmts, vinit, t;
enum tree_code cond_code;
- cond_code = fd->cond_code;
+ cond_code = fd->loop.cond_code;
cond_code = cond_code == LT_EXPR ? GE_EXPR : LE_EXPR;
/* When possible, use a strict equality expression. This can let VRP
type optimizations deduce the value and remove a copy. */
- if (host_integerp (fd->step, 0))
+ if (host_integerp (fd->loop.step, 0))
{
- HOST_WIDE_INT step = TREE_INT_CST_LOW (fd->step);
+ HOST_WIDE_INT step = TREE_INT_CST_LOW (fd->loop.step);
if (step == 1 || step == -1)
cond_code = EQ_EXPR;
}
- cond = build2 (cond_code, boolean_type_node, fd->v, fd->n2);
+ cond = build2 (cond_code, boolean_type_node, fd->loop.v, fd->loop.n2);
clauses = OMP_FOR_CLAUSES (fd->for_stmt);
stmts = NULL;
lower_lastprivate_clauses (clauses, cond, &stmts, ctx);
if (stmts != NULL)
{
- append_to_statement_list (stmts, dlist);
+ append_to_statement_list (*dlist, &stmts);
+ *dlist = stmts;
/* Optimize: v = 0; is usually cheaper than v = some_other_constant. */
- vinit = fd->n1;
+ vinit = fd->loop.n1;
if (cond_code == EQ_EXPR
- && host_integerp (fd->n2, 0)
- && ! integer_zerop (fd->n2))
- vinit = build_int_cst (TREE_TYPE (fd->v), 0);
+ && host_integerp (fd->loop.n2, 0)
+ && ! integer_zerop (fd->loop.n2))
+ vinit = build_int_cst (TREE_TYPE (fd->loop.v), 0);
/* Initialize the iterator variable, so that threads that don't execute
any iterations don't execute the lastprivate clauses by accident. */
- t = build_gimple_modify_stmt (fd->v, vinit);
+ t = build_gimple_modify_stmt (fd->loop.v, vinit);
gimplify_and_add (t, body_p);
}
}
@@ -4704,6 +5683,7 @@ lower_omp_for (tree *stmt_p, omp_context *ctx)
{
tree t, stmt, ilist, dlist, new_stmt, *body_p, *rhs_p;
struct omp_for_data fd;
+ int i;
stmt = *stmt_p;
@@ -4724,8 +5704,8 @@ lower_omp_for (tree *stmt_p, omp_context *ctx)
/* The pre-body and input clauses go before the lowered OMP_FOR. */
ilist = NULL;
dlist = NULL;
- append_to_statement_list (OMP_FOR_PRE_BODY (stmt), body_p);
lower_rec_input_clauses (OMP_FOR_CLAUSES (stmt), body_p, &dlist, ctx);
+ append_to_statement_list (OMP_FOR_PRE_BODY (stmt), body_p);
/* Lower the header expressions. At this point, we can assume that
the header is of the form:
@@ -4734,20 +5714,24 @@ lower_omp_for (tree *stmt_p, omp_context *ctx)
We just need to make sure that VAL1, VAL2 and VAL3 are lowered
using the .omp_data_s mapping, if needed. */
- rhs_p = &GIMPLE_STMT_OPERAND (OMP_FOR_INIT (stmt), 1);
- if (!is_gimple_min_invariant (*rhs_p))
- *rhs_p = get_formal_tmp_var (*rhs_p, body_p);
-
- rhs_p = &TREE_OPERAND (OMP_FOR_COND (stmt), 1);
- if (!is_gimple_min_invariant (*rhs_p))
- *rhs_p = get_formal_tmp_var (*rhs_p, body_p);
-
- rhs_p = &TREE_OPERAND (GIMPLE_STMT_OPERAND (OMP_FOR_INCR (stmt), 1), 1);
- if (!is_gimple_min_invariant (*rhs_p))
- *rhs_p = get_formal_tmp_var (*rhs_p, body_p);
+ for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (stmt)); i++)
+ {
+ rhs_p = &GIMPLE_STMT_OPERAND (TREE_VEC_ELT (OMP_FOR_INIT (stmt), i), 1);
+ if (!is_gimple_min_invariant (*rhs_p))
+ *rhs_p = get_formal_tmp_var (*rhs_p, body_p);
+
+ rhs_p = &TREE_OPERAND (TREE_VEC_ELT (OMP_FOR_COND (stmt), i), 1);
+ if (!is_gimple_min_invariant (*rhs_p))
+ *rhs_p = get_formal_tmp_var (*rhs_p, body_p);
+
+ rhs_p = &TREE_OPERAND (GIMPLE_STMT_OPERAND
+ (TREE_VEC_ELT (OMP_FOR_INCR (stmt), i), 1), 1);
+ if (!is_gimple_min_invariant (*rhs_p))
+ *rhs_p = get_formal_tmp_var (*rhs_p, body_p);
+ }
/* Once lowered, extract the bounds and clauses. */
- extract_omp_for_data (stmt, &fd);
+ extract_omp_for_data (stmt, &fd, NULL);
lower_omp_for_lastprivate (&fd, body_p, &dlist, ctx);
@@ -4755,7 +5739,7 @@ lower_omp_for (tree *stmt_p, omp_context *ctx)
append_to_statement_list (OMP_FOR_BODY (stmt), body_p);
- t = build2 (OMP_CONTINUE, void_type_node, fd.v, fd.v);
+ t = build2 (OMP_CONTINUE, void_type_node, fd.loop.v, fd.loop.v);
append_to_statement_list (t, body_p);
/* After the loop, add exit clauses. */
@@ -4800,11 +5784,290 @@ check_combined_parallel (tree *tp, int *walk_subtrees, void *data)
return NULL;
}
-/* Lower the OpenMP parallel directive in *STMT_P. CTX holds context
+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->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_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;
+
+ 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 = 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. */
static void
-lower_omp_parallel (tree *stmt_p, omp_context *ctx)
+lower_omp_taskreg (tree *stmt_p, omp_context *ctx)
{
tree clauses, par_bind, par_body, new_body, bind;
tree olist, ilist, par_olist, par_ilist;
@@ -4812,11 +6075,11 @@ lower_omp_parallel (tree *stmt_p, omp_context *ctx)
stmt = *stmt_p;
- clauses = OMP_PARALLEL_CLAUSES (stmt);
- par_bind = OMP_PARALLEL_BODY (stmt);
+ clauses = OMP_TASKREG_CLAUSES (stmt);
+ par_bind = OMP_TASKREG_BODY (stmt);
par_body = BIND_EXPR_BODY (par_bind);
child_fn = ctx->cb.dst_fn;
- if (!OMP_PARALLEL_COMBINED (stmt))
+ if (TREE_CODE (stmt) == OMP_PARALLEL && !OMP_PARALLEL_COMBINED (stmt))
{
struct walk_stmt_info wi;
int ws_num = 0;
@@ -4829,6 +6092,8 @@ lower_omp_parallel (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 ();
@@ -4836,7 +6101,8 @@ lower_omp_parallel (tree *stmt_p, omp_context *ctx)
par_ilist = NULL_TREE;
lower_rec_input_clauses (clauses, &par_ilist, &par_olist, ctx);
lower_omp (&par_body, ctx);
- lower_reduction_clauses (clauses, &par_olist, ctx);
+ if (TREE_CODE (stmt) == OMP_PARALLEL)
+ lower_reduction_clauses (clauses, &par_olist, ctx);
/* Declare all the variables created by mapping and the variables
declared in the scope of the parallel body. */
@@ -4845,8 +6111,10 @@ lower_omp_parallel (tree *stmt_p, omp_context *ctx)
if (ctx->record_type)
{
- ctx->sender_decl = create_tmp_var (ctx->record_type, ".omp_data_o");
- OMP_PARALLEL_DATA_ARG (stmt) = ctx->sender_decl;
+ 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;
}
olist = NULL_TREE;
@@ -4855,7 +6123,7 @@ lower_omp_parallel (tree *stmt_p, omp_context *ctx)
lower_send_shared_vars (&ilist, &olist, ctx);
/* Once all the expansions are done, sequence all the different
- fragments inside OMP_PARALLEL_BODY. */
+ fragments inside OMP_TASKREG_BODY. */
bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL);
append_to_statement_list (ilist, &BIND_EXPR_BODY (bind));
@@ -4876,7 +6144,7 @@ lower_omp_parallel (tree *stmt_p, omp_context *ctx)
maybe_catch_exception (&new_body);
t = make_node (OMP_RETURN);
append_to_statement_list (t, &new_body);
- OMP_PARALLEL_BODY (stmt) = new_body;
+ OMP_TASKREG_BODY (stmt) = new_body;
append_to_statement_list (stmt, &BIND_EXPR_BODY (bind));
append_to_statement_list (olist, &BIND_EXPR_BODY (bind));
@@ -4890,17 +6158,21 @@ lower_omp_parallel (tree *stmt_p, omp_context *ctx)
regimplified. */
static tree
-lower_omp_2 (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
+lower_omp_2 (tree *tp, int *walk_subtrees, void *data)
{
tree t = *tp;
+ omp_context *ctx = data;
/* Any variable with DECL_VALUE_EXPR needs to be regimplified. */
- if (TREE_CODE (t) == VAR_DECL && DECL_HAS_VALUE_EXPR_P (t))
+ if (TREE_CODE (t) == VAR_DECL
+ && ((ctx && DECL_HAS_VALUE_EXPR_P (t))
+ || (task_shared_vars
+ && bitmap_bit_p (task_shared_vars, DECL_UID (t)))))
return t;
/* If a global variable has been privatized, TREE_CONSTANT on
ADDR_EXPR might be wrong. */
- if (TREE_CODE (t) == ADDR_EXPR)
+ if (ctx && TREE_CODE (t) == ADDR_EXPR)
recompute_tree_invariant_for_addr_expr (t);
*walk_subtrees = !TYPE_P (t) && !DECL_P (t);
@@ -4940,7 +6212,7 @@ lower_omp_1 (tree *tp, omp_context *ctx, tree_stmt_iterator *tsi)
case COND_EXPR:
lower_omp_1 (&COND_EXPR_THEN (t), ctx, NULL);
lower_omp_1 (&COND_EXPR_ELSE (t), ctx, NULL);
- if (ctx
+ if ((ctx || task_shared_vars)
&& walk_tree (&COND_EXPR_COND (t), lower_omp_2, ctx, NULL))
{
tree pre = NULL;
@@ -4977,8 +6249,9 @@ lower_omp_1 (tree *tp, omp_context *ctx, tree_stmt_iterator *tsi)
break;
case OMP_PARALLEL:
+ case OMP_TASK:
ctx = maybe_lookup_ctx (t);
- lower_omp_parallel (tp, ctx);
+ lower_omp_taskreg (tp, ctx);
break;
case OMP_FOR:
ctx = maybe_lookup_ctx (t);
@@ -5012,7 +6285,8 @@ lower_omp_1 (tree *tp, omp_context *ctx, tree_stmt_iterator *tsi)
break;
default:
- if (ctx && walk_tree (tp, lower_omp_2, ctx, NULL))
+ if ((ctx || task_shared_vars)
+ && walk_tree (tp, lower_omp_2, ctx, NULL))
{
/* The gimplifier doesn't gimplify CALL_EXPR_STATIC_CHAIN.
Handle that here. */
@@ -5068,16 +6342,23 @@ execute_lower_omp (void)
delete_omp_context);
scan_omp (&DECL_SAVED_TREE (current_function_decl), NULL);
- gcc_assert (parallel_nesting_level == 0);
+ gcc_assert (taskreg_nesting_level == 0);
if (all_contexts->root)
- lower_omp (&DECL_SAVED_TREE (current_function_decl), NULL);
+ {
+ if (task_shared_vars)
+ push_gimplify_context ();
+ lower_omp (&DECL_SAVED_TREE (current_function_decl), NULL);
+ if (task_shared_vars)
+ pop_gimplify_context (NULL);
+ }
if (all_contexts)
{
splay_tree_delete (all_contexts);
all_contexts = NULL;
}
+ BITMAP_FREE (task_shared_vars);
return 0;
}
@@ -5160,11 +6441,13 @@ diagnose_sb_1 (tree *tp, int *walk_subtrees, void *data)
tree context = (tree) wi->info;
tree inner_context;
tree t = *tp;
+ int i;
*walk_subtrees = 0;
switch (TREE_CODE (t))
{
case OMP_PARALLEL:
+ case OMP_TASK:
case OMP_SECTIONS:
case OMP_SINGLE:
walk_tree (&OMP_CLAUSES (t), diagnose_sb_1, wi, NULL);
@@ -5184,9 +6467,15 @@ diagnose_sb_1 (tree *tp, int *walk_subtrees, void *data)
walk_tree (&OMP_FOR_CLAUSES (t), diagnose_sb_1, wi, NULL);
inner_context = tree_cons (NULL, t, context);
wi->info = inner_context;
- walk_tree (&OMP_FOR_INIT (t), diagnose_sb_1, wi, NULL);
- walk_tree (&OMP_FOR_COND (t), diagnose_sb_1, wi, NULL);
- walk_tree (&OMP_FOR_INCR (t), diagnose_sb_1, wi, NULL);
+ for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (t)); i++)
+ {
+ walk_tree (&TREE_VEC_ELT (OMP_FOR_INIT (t), i), diagnose_sb_1,
+ wi, NULL);
+ walk_tree (&TREE_VEC_ELT (OMP_FOR_COND (t), i), diagnose_sb_1,
+ wi, NULL);
+ walk_tree (&TREE_VEC_ELT (OMP_FOR_INCR (t), i), diagnose_sb_1,
+ wi, NULL);
+ }
walk_stmts (wi, &OMP_FOR_PRE_BODY (t));
walk_stmts (wi, &OMP_FOR_BODY (t));
wi->info = context;
@@ -5214,11 +6503,13 @@ diagnose_sb_2 (tree *tp, int *walk_subtrees, void *data)
tree context = (tree) wi->info;
splay_tree_node n;
tree t = *tp;
+ int i;
*walk_subtrees = 0;
switch (TREE_CODE (t))
{
case OMP_PARALLEL:
+ case OMP_TASK:
case OMP_SECTIONS:
case OMP_SINGLE:
walk_tree (&OMP_CLAUSES (t), diagnose_sb_2, wi, NULL);
@@ -5235,9 +6526,15 @@ diagnose_sb_2 (tree *tp, int *walk_subtrees, void *data)
case OMP_FOR:
walk_tree (&OMP_FOR_CLAUSES (t), diagnose_sb_2, wi, NULL);
wi->info = t;
- walk_tree (&OMP_FOR_INIT (t), diagnose_sb_2, wi, NULL);
- walk_tree (&OMP_FOR_COND (t), diagnose_sb_2, wi, NULL);
- walk_tree (&OMP_FOR_INCR (t), diagnose_sb_2, wi, NULL);
+ for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (t)); i++)
+ {
+ walk_tree (&TREE_VEC_ELT (OMP_FOR_INIT (t), i), diagnose_sb_2,
+ wi, NULL);
+ walk_tree (&TREE_VEC_ELT (OMP_FOR_COND (t), i), diagnose_sb_2,
+ wi, NULL);
+ walk_tree (&TREE_VEC_ELT (OMP_FOR_INCR (t), i), diagnose_sb_2,
+ wi, NULL);
+ }
walk_stmts (wi, &OMP_FOR_PRE_BODY (t));
walk_stmts (wi, &OMP_FOR_BODY (t));
wi->info = context;