enum omp_region_type
{
ORT_WORKSHARE = 0,
- ORT_TASK = 1,
ORT_PARALLEL = 2,
- ORT_COMBINED_PARALLEL = 3
+ ORT_COMBINED_PARALLEL = 3,
+ ORT_TASK = 4,
+ ORT_UNTIED_TASK = 5
};
struct gimplify_omp_ctx
During gimplification, we need to manipulate statement sequences
before the def/use vectors have been constructed. */
-static void
+void
gimplify_seq_add_stmt (gimple_seq *seq_p, gimple gs)
{
gimple_stmt_iterator si;
c->privatized_types = pointer_set_create ();
c->location = input_location;
c->region_type = region_type;
- if (region_type != ORT_TASK)
+ if ((region_type & ORT_TASK) == 0)
c->default_kind = OMP_CLAUSE_DEFAULT_SHARED;
else
c->default_kind = OMP_CLAUSE_DEFAULT_UNSPECIFIED;
static void omp_add_variable (struct gimplify_omp_ctx *, tree, unsigned int);
static bool omp_notice_variable (struct gimplify_omp_ctx *, tree, bool);
-/* A subroutine of append_to_statement_list{,_force}. T is not NULL. */
-
-static void
-append_to_statement_list_1 (tree t, tree *list_p)
-{
- tree list = *list_p;
- tree_stmt_iterator i;
-
- if (!list)
- {
- if (t && TREE_CODE (t) == STATEMENT_LIST)
- {
- *list_p = t;
- return;
- }
- *list_p = list = alloc_stmt_list ();
- }
-
- i = tsi_last (list);
- tsi_link_after (&i, t, TSI_CONTINUE_LINKING);
-}
-
-/* Add T to the end of the list container pointed to by LIST_P.
- If T is an expression with no effects, it is ignored. */
-
-void
-append_to_statement_list (tree t, tree *list_p)
-{
- if (t && TREE_SIDE_EFFECTS (t))
- append_to_statement_list_1 (t, list_p);
-}
-
-/* Similar, but the statement is always added, regardless of side effects. */
-
-void
-append_to_statement_list_force (tree t, tree *list_p)
-{
- if (t != NULL_TREE)
- append_to_statement_list_1 (t, list_p);
-}
-
/* Both gimplify the statement T and append it to *SEQ_P. This function
behaves exactly as gimplify_stmt, but you don't have to pass T as a
reference. */
}
}
- default:
- break;
+ ret = GS_UNHANDLED;
+ break;
+
+ case WITH_SIZE_EXPR:
+ /* Likewise for calls that return an aggregate of non-constant size,
+ since we would not be able to generate a temporary at all. */
+ if (TREE_CODE (TREE_OPERAND (*from_p, 0)) == CALL_EXPR)
+ {
+ *from_p = TREE_OPERAND (*from_p, 0);
+ ret = GS_OK;
+ }
+ else
+ ret = GS_UNHANDLED;
+ break;
+
+ /* If we're initializing from a container, push the initialization
+ inside it. */
+ case CLEANUP_POINT_EXPR:
+ case BIND_EXPR:
+ case STATEMENT_LIST:
+ {
+ tree wrap = *from_p;
+ tree t;
+
+ ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_min_lval,
+ fb_lvalue);
+ if (ret != GS_ERROR)
+ ret = GS_OK;
+
+ t = voidify_wrapper_expr (wrap, *expr_p);
+ gcc_assert (t == *expr_p);
+
+ if (want_value)
+ {
+ gimplify_and_add (wrap, pre_p);
+ *expr_p = unshare_expr (*to_p);
+ }
+ else
+ *expr_p = wrap;
+ return GS_OK;
+ }
+
+ case COMPOUND_LITERAL_EXPR:
+ {
+ tree complit = TREE_OPERAND (*expr_p, 1);
+ tree decl_s = COMPOUND_LITERAL_EXPR_DECL_EXPR (complit);
+ tree decl = DECL_EXPR_DECL (decl_s);
+ tree init = DECL_INITIAL (decl);
+
+ /* struct T x = (struct T) { 0, 1, 2 } can be optimized
+ into struct T x = { 0, 1, 2 } if the address of the
+ compound literal has never been taken. */
+ if (!TREE_ADDRESSABLE (complit)
+ && !TREE_ADDRESSABLE (decl)
+ && init)
+ {
+ *expr_p = copy_node (*expr_p);
+ TREE_OPERAND (*expr_p, 1) = init;
+ return GS_OK;
+ }
}
}
while (changed);
splay_tree_insert (ctx->variables, (splay_tree_key)decl, flags);
}
+/* Notice a threadprivate variable DECL used in OpenMP context CTX.
+ This just prints out diagnostics about threadprivate variable uses
+ in untied tasks. If DECL2 is non-NULL, prevent this warning
+ on that variable. */
+
+static bool
+omp_notice_threadprivate_variable (struct gimplify_omp_ctx *ctx, tree decl,
+ tree decl2)
+{
+ splay_tree_node n;
+
+ if (ctx->region_type != ORT_UNTIED_TASK)
+ return false;
+ n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl);
+ if (n == NULL)
+ {
+ error ("threadprivate variable %qE used in untied task", DECL_NAME (decl));
+ error_at (ctx->location, "enclosing task");
+ splay_tree_insert (ctx->variables, (splay_tree_key)decl, 0);
+ }
+ if (decl2)
+ splay_tree_insert (ctx->variables, (splay_tree_key)decl2, 0);
+ return false;
+}
+
/* Record the fact that DECL was used within the OpenMP context CTX.
IN_CODE is true when real code uses DECL, and false when we should
merely emit default(none) errors. Return true if DECL is going to
if (is_global_var (decl))
{
if (DECL_THREAD_LOCAL_P (decl))
- return false;
+ return omp_notice_threadprivate_variable (ctx, decl, NULL_TREE);
if (DECL_HAS_VALUE_EXPR_P (decl))
{
tree value = get_base_address (DECL_VALUE_EXPR (decl));
if (value && DECL_P (value) && DECL_THREAD_LOCAL_P (value))
- return false;
+ return omp_notice_threadprivate_variable (ctx, decl, value);
}
}
case OMP_CLAUSE_DEFAULT_NONE:
error ("%qE not specified in enclosing parallel",
DECL_NAME (decl));
- error_at (ctx->location, "enclosing parallel");
+ if ((ctx->region_type & ORT_TASK) != 0)
+ error_at (ctx->location, "enclosing task");
+ else
+ error_at (ctx->location, "enclosing parallel");
/* FALLTHRU */
case OMP_CLAUSE_DEFAULT_SHARED:
flags |= GOVD_SHARED;
break;
case OMP_CLAUSE_DEFAULT_UNSPECIFIED:
/* decl will be either GOVD_FIRSTPRIVATE or GOVD_SHARED. */
- gcc_assert (ctx->region_type == ORT_TASK);
+ gcc_assert ((ctx->region_type & ORT_TASK) != 0);
if (ctx->outer_context)
omp_notice_variable (ctx->outer_context, decl, in_code);
for (octx = ctx->outer_context; octx; octx = octx->outer_context)
gimple_seq body = NULL;
struct gimplify_ctx gctx;
- gimplify_scan_omp_clauses (&OMP_TASK_CLAUSES (expr), pre_p, ORT_TASK);
+ gimplify_scan_omp_clauses (&OMP_TASK_CLAUSES (expr), pre_p,
+ find_omp_clause (OMP_TASK_CLAUSES (expr),
+ OMP_CLAUSE_UNTIED)
+ ? ORT_UNTIED_TASK : ORT_TASK);
push_gimplify_context (&gctx);