On Fri, Dec 10, 2021 at 05:33:25PM +0000, Kwok Cheung Yeung wrote:
> 2021-12-10 Kwok Cheung Yeung <kcy@codesourcery.com>
>
> gcc/
> * gimple-low.c (lower_omp_metadirective): New.
> (lower_stmt): Handle GIMPLE_OMP_METADIRECTIVE.
> * gimple-pretty-print.c (dump_gimple_omp_metadirective): New.
> (pp_gimple_stmt_1): Handle GIMPLE_OMP_METADIRECTIVE.
> * gimple-walk.c (walk_gimple_op): Handle GIMPLE_OMP_METADIRECTIVE.
> (walk_gimple_stmt): Likewise.
> * gimple.c (gimple_alloc_omp_metadirective): New.
> (gimple_build_omp_metadirective): New.
> (gimple_build_omp_metadirective_variant): New.
> * gimple.def (GIMPLE_OMP_METADIRECTIVE): New.
> (GIMPLE_OMP_METADIRECTIVE_VARIANT): New.
> * gimple.h (gomp_metadirective_variant): New.
> (gomp_metadirective): New.
> (is_a_helper <gomp_metadirective *>::test): New.
> (is_a_helper <gomp_metadirective_variant *>::test): New.
> (is_a_helper <const gomp_metadirective *>::test): New.
> (is_a_helper <const gomp_metadirective_variant *>::test): New.
> (gimple_alloc_omp_metadirective): New prototype.
> (gimple_build_omp_metadirective): New prototype.
> (gimple_build_omp_metadirective_variant): New prototype.
> (gimple_has_substatements): Add GIMPLE_OMP_METADIRECTIVE case.
> (gimple_has_ops): Add GIMPLE_OMP_METADIRECTIVE.
> (gimple_omp_metadirective_label): New.
> (gimple_omp_metadirective_set_label): New.
> (gimple_omp_metadirective_variants): New.
> (gimple_omp_metadirective_set_variants): New.
> (CASE_GIMPLE_OMP): Add GIMPLE_OMP_METADIRECTIVE.
> * gimplify.c (is_gimple_stmt): Add OMP_METADIRECTIVE.
> (expand_omp_metadirective): New.
> (gimplify_omp_metadirective): New.
> (gimplify_expr): Add case for OMP_METADIRECTIVE.
> * gsstruct.def (GSS_OMP_METADIRECTIVE): New.
> (GSS_OMP_METADIRECTIVE_VARIANT): New.
> * omp-expand.c (build_omp_regions_1): Handle GIMPLE_OMP_METADIRECTIVE.
> (omp_make_gimple_edges): Likewise.
> * omp-low.c (struct omp_context): Add next_clone field.
> (new_omp_context): Initialize next_clone field.
> (clone_omp_context): New.
> (delete_omp_context): Delete clone contexts.
> (scan_omp_metadirective): New.
> (scan_omp_1_stmt): Handle GIMPLE_OMP_METADIRECTIVE.
> (lower_omp_metadirective): New.
> (lower_omp_1): Handle GIMPLE_OMP_METADIRECTIVE.
> * tree-cfg.c (cleanup_dead_labels): Handle GIMPLE_OMP_METADIRECTIVE.
> (gimple_redirect_edge_and_branch): Likewise.
> * tree-inline.c (remap_gimple_stmt): Handle GIMPLE_OMP_METADIRECTIVE.
> (estimate_num_insns): Likewise.
> * tree-pretty-print.c (dump_generic_node): Handle OMP_METADIRECTIVE.
> * tree-ssa-operands.c (parse_ssa_operands): Handle
> GIMPLE_OMP_METADIRECTIVE.
> --- a/gcc/gimple-pretty-print.c
> +++ b/gcc/gimple-pretty-print.c
> @@ -2051,6 +2051,63 @@ dump_gimple_omp_return (pretty_printer *buffer, const gimple *gs, int spc,
> }
> }
>
> +/* Dump a GIMPLE_OMP_METADIRECTIVE tuple on the pretty_printer BUFFER. */
> +
> +static void
> +dump_gimple_omp_metadirective (pretty_printer *buffer, const gimple *gs,
> + int spc, dump_flags_t flags)
> +{
> + if (flags & TDF_RAW)
> + {
> + dump_gimple_fmt (buffer, spc, flags, "%G <%+BODY <%S> >", gs,
> + gimple_omp_body (gs));
> + }
No need for {}s around a single statement.
> + else
> + {
> + pp_string (buffer, "#pragma omp metadirective");
> + newline_and_indent (buffer, spc + 2);
> +
> + gimple *variant = gimple_omp_metadirective_variants (gs);
> +
> + for (unsigned i = 0; i < gimple_num_ops (gs); i++)
> + {
> + tree selector = gimple_op (gs, i);
> +
> + if (selector == NULL_TREE)
> + pp_string (buffer, "default:");
> + else
> + {
> + pp_string (buffer, "when (");
> + dump_generic_node (buffer, selector, spc, flags, false);
> + pp_string (buffer, "):");
> + }
> +
> + if (variant != NULL)
> + {
> + newline_and_indent (buffer, spc + 4);
> + pp_left_brace (buffer);
> + pp_newline (buffer);
> + dump_gimple_seq (buffer, gimple_omp_body (variant), spc + 6,
> + flags);
> + newline_and_indent (buffer, spc + 4);
> + pp_right_brace (buffer);
> +
> + variant = variant->next;
> + }
> + else
> + {
> + tree label = gimple_omp_metadirective_label (gs, i);
> +
> + pp_string (buffer, " ");
> + dump_generic_node (buffer, label, spc, flags, false);
> + }
> +
> + if (i != gimple_num_ops (gs) - 1)
> + newline_and_indent (buffer, spc + 2);
I think better would be to use a gimple_stmt_iterator to walk the variants,
so no variant->next etc., but gimple_omp_metadirective_variants returning
a gimple_seq instead of gimple * (it is the same thing under the hood),
then
gimple_seq variant_seq = gimple_omp_metadirective_variants (gs);
gimple_stmt_iterator gsi = gsi_start (variant_seq);
and in the loop
gimple *variant = gsi_stmt (gsi);
and gsi_next (&gsi); at the end. Similarly for all other spots that walk
gimple_omp_metadirective_variants.
> + case GIMPLE_OMP_METADIRECTIVE:
> + {
> + gimple *variant = gimple_omp_metadirective_variants (stmt);
> +
> + while (variant)
> + {
> + ret = walk_gimple_op (gimple_omp_body (variant), callback_op, wi);
> + if (ret)
> + return ret;
> +
> + variant = variant->next;
> + }
So here too...
> + }
> + break;
> +
> case GIMPLE_TRANSACTION:
> {
> gtransaction *txn = as_a <gtransaction *> (stmt);
> @@ -700,6 +715,22 @@ walk_gimple_stmt (gimple_stmt_iterator *gsi, walk_stmt_fn callback_stmt,
> return wi->callback_result;
> break;
>
> + case GIMPLE_OMP_METADIRECTIVE:
> + {
> + gimple *variant = gimple_omp_metadirective_variants (stmt);
> +
> + while (variant)
> + {
> + ret = walk_gimple_seq_mod (gimple_omp_body_ptr (variant),
> + callback_stmt, callback_op, wi);
> + if (ret)
> + return wi->callback_result;
> +
> + variant = variant->next;
> + }
and here etc.
> --- a/gcc/omp-expand.c
> +++ b/gcc/omp-expand.c
> @@ -10418,6 +10418,10 @@ build_omp_regions_1 (basic_block bb, struct omp_region *parent,
> /* GIMPLE_OMP_SECTIONS_SWITCH is part of
> GIMPLE_OMP_SECTIONS, and we do nothing for it. */
> }
> + else if (code == GIMPLE_OMP_METADIRECTIVE)
> + {
> + /* Do nothing for metadirectives. */
> + }
No {}s around the comment, just /* ... */;
> --- a/gcc/tree-cfg.c
> +++ b/gcc/tree-cfg.c
> @@ -1670,6 +1670,18 @@ cleanup_dead_labels (void)
> }
> break;
>
> + case GIMPLE_OMP_METADIRECTIVE:
> + {
> + for (unsigned i = 0; i < gimple_num_ops (stmt); i++)
> + {
> + label = gimple_omp_metadirective_label (stmt, i);
> + new_label = main_block_label (label, label_for_bb);
> + if (new_label != label)
> + gimple_omp_metadirective_set_label (stmt, i, new_label);
> + }
> + }
> + break;
Why the {} around the for?
> @@ -6147,6 +6159,18 @@ gimple_redirect_edge_and_branch (edge e, basic_block dest)
> gimple_block_label (dest));
> break;
>
> + case GIMPLE_OMP_METADIRECTIVE:
> + {
> + for (unsigned i = 0; i < gimple_num_ops (stmt); i++)
> + {
> + tree label = gimple_omp_metadirective_label (stmt, i);
> + if (label_to_block (cfun, label) == e->dest)
> + gimple_omp_metadirective_set_label (stmt, i,
> + gimple_block_label (dest));
> + }
> + }
> + break;
Likewise.
> --- a/gcc/tree-ssa-operands.c
> +++ b/gcc/tree-ssa-operands.c
> @@ -973,6 +973,33 @@ operands_scanner::parse_ssa_operands ()
> append_vuse (gimple_vop (fn));
> goto do_default;
>
> + case GIMPLE_OMP_METADIRECTIVE:
> + n = gimple_num_ops (stmt);
> + for (i = start; i < n; i++)
> + {
Why the {}s around the inner for?
> + for (tree selector = gimple_op (stmt, i);
> + selector != NULL;
> + selector = TREE_CHAIN (selector))
> + {
Why the {}s around the if ?
> + if (TREE_PURPOSE (selector) == get_identifier ("user"))
> + {
> + for (tree property = TREE_VALUE (selector);
> + property != NULL;
> + property = TREE_CHAIN (property))
> + if (TREE_PURPOSE (property)
> + == get_identifier ("condition"))
> + {
> + for (tree condition = TREE_VALUE (property);
> + condition != NULL;
> + condition = TREE_CHAIN (condition))
> + get_expr_operands (&TREE_VALUE (condition),
> + opf_use);
> + }
> + }
> + }
> + }
> + break;
> +
Also, I wonder how does LTO saving/restoring handle the
GIMPLE_OMP_METADIRECTIVE statements.
Otherwise LGTM.
Jakub
@@ -234,6 +234,34 @@ lower_omp_directive (gimple_stmt_iterator *gsi, struct lower_data *data)
gsi_next (gsi);
}
+/* Lower the OpenMP metadirective statement pointed by GSI. */
+
+static void
+lower_omp_metadirective (gimple_stmt_iterator *gsi, struct lower_data *data)
+{
+ gimple *stmt = gsi_stmt (*gsi);
+ gimple *variant = gimple_omp_metadirective_variants (stmt);
+ unsigned i;
+
+ /* The variants are not used after lowering. */
+ gimple_omp_metadirective_set_variants (stmt, NULL);
+
+ for (i = 0; i < gimple_num_ops (stmt); i++)
+ {
+ tree label = create_artificial_label (UNKNOWN_LOCATION);
+ gimple_omp_metadirective_set_label (stmt, i, label);
+ gsi_insert_after (gsi, gimple_build_label (label), GSI_CONTINUE_LINKING);
+
+ gimple_seq *directive_ptr = gimple_omp_body_ptr (variant);
+ lower_sequence (directive_ptr, data);
+ gsi_insert_seq_after (gsi, *directive_ptr, GSI_CONTINUE_LINKING);
+
+ variant = variant->next;
+ }
+
+ gsi_next (gsi);
+}
+
/* Lower statement GSI. DATA is passed through the recursion. We try to
track the fallthruness of statements and get rid of unreachable return
@@ -400,6 +428,12 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
data->cannot_fallthru = false;
return;
+ case GIMPLE_OMP_METADIRECTIVE:
+ data->cannot_fallthru = false;
+ lower_omp_metadirective (gsi, data);
+ data->cannot_fallthru = false;
+ return;
+
case GIMPLE_TRANSACTION:
lower_sequence (gimple_transaction_body_ptr (
as_a <gtransaction *> (stmt)),
@@ -2051,6 +2051,63 @@ dump_gimple_omp_return (pretty_printer *buffer, const gimple *gs, int spc,
}
}
+/* Dump a GIMPLE_OMP_METADIRECTIVE tuple on the pretty_printer BUFFER. */
+
+static void
+dump_gimple_omp_metadirective (pretty_printer *buffer, const gimple *gs,
+ int spc, dump_flags_t flags)
+{
+ if (flags & TDF_RAW)
+ {
+ dump_gimple_fmt (buffer, spc, flags, "%G <%+BODY <%S> >", gs,
+ gimple_omp_body (gs));
+ }
+ else
+ {
+ pp_string (buffer, "#pragma omp metadirective");
+ newline_and_indent (buffer, spc + 2);
+
+ gimple *variant = gimple_omp_metadirective_variants (gs);
+
+ for (unsigned i = 0; i < gimple_num_ops (gs); i++)
+ {
+ tree selector = gimple_op (gs, i);
+
+ if (selector == NULL_TREE)
+ pp_string (buffer, "default:");
+ else
+ {
+ pp_string (buffer, "when (");
+ dump_generic_node (buffer, selector, spc, flags, false);
+ pp_string (buffer, "):");
+ }
+
+ if (variant != NULL)
+ {
+ newline_and_indent (buffer, spc + 4);
+ pp_left_brace (buffer);
+ pp_newline (buffer);
+ dump_gimple_seq (buffer, gimple_omp_body (variant), spc + 6,
+ flags);
+ newline_and_indent (buffer, spc + 4);
+ pp_right_brace (buffer);
+
+ variant = variant->next;
+ }
+ else
+ {
+ tree label = gimple_omp_metadirective_label (gs, i);
+
+ pp_string (buffer, " ");
+ dump_generic_node (buffer, label, spc, flags, false);
+ }
+
+ if (i != gimple_num_ops (gs) - 1)
+ newline_and_indent (buffer, spc + 2);
+ }
+ }
+}
+
/* Dump a GIMPLE_TRANSACTION tuple on the pretty_printer BUFFER. */
static void
@@ -2823,6 +2880,12 @@ pp_gimple_stmt_1 (pretty_printer *buffer, const gimple *gs, int spc,
flags);
break;
+ case GIMPLE_OMP_METADIRECTIVE:
+ dump_gimple_omp_metadirective (buffer,
+ as_a <const gomp_metadirective *> (gs),
+ spc, flags);
+ break;
+
case GIMPLE_CATCH:
dump_gimple_catch (buffer, as_a <const gcatch *> (gs), spc, flags);
break;
@@ -485,6 +485,21 @@ walk_gimple_op (gimple *stmt, walk_tree_fn callback_op,
}
break;
+ case GIMPLE_OMP_METADIRECTIVE:
+ {
+ gimple *variant = gimple_omp_metadirective_variants (stmt);
+
+ while (variant)
+ {
+ ret = walk_gimple_op (gimple_omp_body (variant), callback_op, wi);
+ if (ret)
+ return ret;
+
+ variant = variant->next;
+ }
+ }
+ break;
+
case GIMPLE_TRANSACTION:
{
gtransaction *txn = as_a <gtransaction *> (stmt);
@@ -700,6 +715,22 @@ walk_gimple_stmt (gimple_stmt_iterator *gsi, walk_stmt_fn callback_stmt,
return wi->callback_result;
break;
+ case GIMPLE_OMP_METADIRECTIVE:
+ {
+ gimple *variant = gimple_omp_metadirective_variants (stmt);
+
+ while (variant)
+ {
+ ret = walk_gimple_seq_mod (gimple_omp_body_ptr (variant),
+ callback_stmt, callback_op, wi);
+ if (ret)
+ return wi->callback_result;
+
+ variant = variant->next;
+ }
+ }
+ break;
+
case GIMPLE_WITH_CLEANUP_EXPR:
ret = walk_gimple_seq_mod (gimple_wce_cleanup_ptr (stmt), callback_stmt,
callback_op, wi);
@@ -1267,6 +1267,41 @@ gimple_build_omp_atomic_store (tree val, enum omp_memory_order mo)
return p;
}
+/* Allocate extra memory for a GIMPLE_OMP_METADIRECTIVE statement. */
+
+void
+gimple_alloc_omp_metadirective (gimple *g)
+{
+ gomp_metadirective *p = as_a <gomp_metadirective *> (g);
+
+ p->labels = ggc_cleared_vec_alloc<tree> (gimple_num_ops (p));
+}
+
+/* Build a GIMPLE_OMP_METADIRECTIVE statement. */
+
+gomp_metadirective *
+gimple_build_omp_metadirective (int num_variants)
+{
+ gomp_metadirective *p
+ = as_a <gomp_metadirective *> (gimple_alloc (GIMPLE_OMP_METADIRECTIVE,
+ num_variants));
+ gimple_alloc_omp_metadirective (p);
+ gimple_omp_metadirective_set_variants (p, NULL);
+
+ return p;
+}
+
+/* Build a GIMPLE_OMP_METADIRECTIVE_VARIANT statement. */
+
+gomp_metadirective_variant *
+gimple_build_omp_metadirective_variant (gimple_seq body)
+{
+ gomp_metadirective_variant *variant = as_a <gomp_metadirective_variant *>
+ (gimple_alloc (GIMPLE_OMP_METADIRECTIVE_VARIANT, 0));
+ gimple_omp_set_body (variant, body);
+ return variant;
+}
+
/* Build a GIMPLE_TRANSACTION statement. */
gtransaction *
@@ -393,6 +393,13 @@ DEFGSCODE(GIMPLE_OMP_TEAMS, "gimple_omp_teams", GSS_OMP_PARALLEL_LAYOUT)
CLAUSES is an OMP_CLAUSE chain holding the associated clauses. */
DEFGSCODE(GIMPLE_OMP_ORDERED, "gimple_omp_ordered", GSS_OMP_SINGLE_LAYOUT)
+/* GIMPLE_OMP_METADIRECTIVE represents #pragma omp metadirective. */
+DEFGSCODE(GIMPLE_OMP_METADIRECTIVE, "gimple_omp_metadirective",
+ GSS_OMP_METADIRECTIVE)
+
+DEFGSCODE(GIMPLE_OMP_METADIRECTIVE_VARIANT,
+ "gimple_omp_metadirective_variant", GSS_OMP_METADIRECTIVE_VARIANT)
+
/* GIMPLE_PREDICT <PREDICT, OUTCOME> specifies a hint for branch prediction.
PREDICT is one of the predictors from predict.def.
@@ -824,6 +824,30 @@ struct GTY((tag("GSS_OMP_ATOMIC_STORE_LAYOUT")))
stmt->code == GIMPLE_OMP_RETURN. */
};
+struct GTY((tag("GSS_OMP_METADIRECTIVE_VARIANT")))
+ gomp_metadirective_variant : public gimple_statement_omp
+{
+ /* The body in the base class contains the directive for this variant. */
+
+ /* No extra fields; adds invariant:
+ stmt->code == GIMPLE_OMP_METADIRECTIVE_VARIANT. */};
+
+struct GTY((tag("GSS_OMP_METADIRECTIVE")))
+ gomp_metadirective : public gimple_statement_with_ops_base
+{
+ /* [ WORD 1-7 ] : base class */
+
+ /* [ WORD 8 ] : a list of bodies associated with the directive variants. */
+ gomp_metadirective_variant *variants;
+
+ /* [ WORD 9 ] : label vector. */
+ tree * GTY((length ("%h.num_ops"))) labels;
+
+ /* [ WORD 10 ] : operand vector. Used to hold the selectors for the
+ directive variants. */
+ tree GTY((length ("%h.num_ops"))) op[1];
+};
+
/* GIMPLE_TRANSACTION. */
/* Bits to be stored in the GIMPLE_TRANSACTION subcode. */
@@ -1235,6 +1259,22 @@ is_a_helper <gomp_task *>::test (gimple *gs)
return gs->code == GIMPLE_OMP_TASK;
}
+template <>
+template <>
+inline bool
+is_a_helper <gomp_metadirective *>::test (gimple *gs)
+{
+ return gs->code == GIMPLE_OMP_METADIRECTIVE;
+}
+
+template <>
+template <>
+inline bool
+is_a_helper <gomp_metadirective_variant *>::test (gimple *gs)
+{
+ return gs->code == GIMPLE_OMP_METADIRECTIVE_VARIANT;
+}
+
template <>
template <>
inline bool
@@ -1477,6 +1517,22 @@ is_a_helper <const gomp_task *>::test (const gimple *gs)
return gs->code == GIMPLE_OMP_TASK;
}
+template <>
+template <>
+inline bool
+is_a_helper <const gomp_metadirective *>::test (const gimple *gs)
+{
+ return gs->code == GIMPLE_OMP_METADIRECTIVE;
+}
+
+template <>
+template <>
+inline bool
+is_a_helper <const gomp_metadirective_variant *>::test (const gimple *gs)
+{
+ return gs->code == GIMPLE_OMP_METADIRECTIVE_VARIANT;
+}
+
template <>
template <>
inline bool
@@ -1576,6 +1632,9 @@ gomp_teams *gimple_build_omp_teams (gimple_seq, tree);
gomp_atomic_load *gimple_build_omp_atomic_load (tree, tree,
enum omp_memory_order);
gomp_atomic_store *gimple_build_omp_atomic_store (tree, enum omp_memory_order);
+void gimple_alloc_omp_metadirective (gimple *g);
+gomp_metadirective *gimple_build_omp_metadirective (int num_variants);
+gomp_metadirective_variant *gimple_build_omp_metadirective_variant (gimple_seq body);
gtransaction *gimple_build_transaction (gimple_seq);
extern void gimple_seq_add_stmt (gimple_seq *, gimple *);
extern void gimple_seq_add_stmt_without_update (gimple_seq *, gimple *);
@@ -1853,6 +1912,7 @@ gimple_has_substatements (gimple *g)
case GIMPLE_OMP_TARGET:
case GIMPLE_OMP_TEAMS:
case GIMPLE_OMP_CRITICAL:
+ case GIMPLE_OMP_METADIRECTIVE:
case GIMPLE_WITH_CLEANUP_EXPR:
case GIMPLE_TRANSACTION:
return true;
@@ -2110,7 +2170,8 @@ gimple_init_singleton (gimple *g)
static inline bool
gimple_has_ops (const gimple *g)
{
- return gimple_code (g) >= GIMPLE_COND && gimple_code (g) <= GIMPLE_RETURN;
+ return (gimple_code (g) >= GIMPLE_COND && gimple_code (g) <= GIMPLE_RETURN)
+ || gimple_code (g) == GIMPLE_OMP_METADIRECTIVE;
}
template <>
@@ -6488,6 +6549,42 @@ gimple_omp_continue_set_control_use (gomp_continue *cont_stmt, tree use)
cont_stmt->control_use = use;
}
+
+static inline tree
+gimple_omp_metadirective_label (const gimple *g, unsigned i)
+{
+ const gomp_metadirective *omp_metadirective
+ = as_a <const gomp_metadirective *> (g);
+ return omp_metadirective->labels[i];
+}
+
+
+static inline void
+gimple_omp_metadirective_set_label (gimple *g, unsigned i, tree label)
+{
+ gomp_metadirective *omp_metadirective = as_a <gomp_metadirective *> (g);
+ omp_metadirective->labels[i] = label;
+}
+
+
+static inline gomp_metadirective_variant *
+gimple_omp_metadirective_variants (const gimple *g)
+{
+ const gomp_metadirective *omp_metadirective
+ = as_a <const gomp_metadirective *> (g);
+ return omp_metadirective->variants;
+}
+
+
+static inline void
+gimple_omp_metadirective_set_variants (gimple *g, gimple *variants)
+{
+ gomp_metadirective *omp_metadirective = as_a <gomp_metadirective *> (g);
+ omp_metadirective->variants
+ = variants ? as_a <gomp_metadirective_variant *> (variants) : NULL;
+}
+
+
/* Return a pointer to the body for the GIMPLE_TRANSACTION statement
TRANSACTION_STMT. */
@@ -6638,6 +6735,7 @@ gimple_return_set_retval (greturn *gs, tree retval)
case GIMPLE_OMP_RETURN: \
case GIMPLE_OMP_ATOMIC_LOAD: \
case GIMPLE_OMP_ATOMIC_STORE: \
+ case GIMPLE_OMP_METADIRECTIVE: \
case GIMPLE_OMP_CONTINUE
static inline bool
@@ -5787,6 +5787,7 @@ is_gimple_stmt (tree t)
case OMP_TASKGROUP:
case OMP_ORDERED:
case OMP_CRITICAL:
+ case OMP_METADIRECTIVE:
case OMP_TASK:
case OMP_TARGET:
case OMP_TARGET_DATA:
@@ -14680,6 +14681,94 @@ gimplify_omp_ordered (tree expr, gimple_seq body)
return gimple_build_omp_ordered (body, OMP_ORDERED_CLAUSES (expr));
}
+/* Replace a metadirective with the candidate directive variants in
+ CANDIDATES. */
+
+static enum gimplify_status
+expand_omp_metadirective (vec<struct omp_metadirective_variant> &,
+ gimple_seq *)
+{
+ return GS_ERROR;
+}
+
+/* Gimplify an OMP_METADIRECTIVE construct. EXPR is the tree version.
+ The metadirective will be resolved at this point if possible. */
+
+static enum gimplify_status
+gimplify_omp_metadirective (tree *expr_p, gimple_seq *pre_p, gimple_seq *,
+ bool (*) (tree), fallback_t)
+{
+ auto_vec<tree> selectors;
+
+ /* Try to resolve the metadirective. */
+ vec<struct omp_metadirective_variant> candidates
+ = omp_resolve_metadirective (*expr_p);
+ if (!candidates.is_empty ())
+ return expand_omp_metadirective (candidates, pre_p);
+
+ /* The metadirective cannot be resolved yet. */
+
+ gomp_metadirective_variant *first_variant = NULL;
+ gomp_metadirective_variant *prev_variant = NULL;
+ gimple_seq standalone_body = NULL;
+ tree body_label = NULL;
+ tree end_label = create_artificial_label (UNKNOWN_LOCATION);
+
+ for (tree clause = OMP_METADIRECTIVE_CLAUSES (*expr_p); clause != NULL_TREE;
+ clause = TREE_CHAIN (clause))
+ {
+ tree selector = TREE_PURPOSE (clause);
+ tree directive = TREE_PURPOSE (TREE_VALUE (clause));
+ tree body = TREE_VALUE (TREE_VALUE (clause));
+
+ selectors.safe_push (selector);
+ gomp_metadirective_variant *variant
+ = gimple_build_omp_metadirective_variant (NULL);
+ gimple_seq *directive_p = gimple_omp_body_ptr (variant);
+
+ gimplify_stmt (&directive, directive_p);
+ if (body != NULL_TREE)
+ {
+ if (standalone_body == NULL)
+ {
+ gimplify_stmt (&body, &standalone_body);
+ body_label = create_artificial_label (UNKNOWN_LOCATION);
+ }
+ gimplify_seq_add_stmt (directive_p, gimple_build_goto (body_label));
+ }
+ else
+ gimplify_seq_add_stmt (directive_p, gimple_build_goto (end_label));
+
+ if (!first_variant)
+ first_variant = variant;
+ if (prev_variant)
+ {
+ prev_variant->next = variant;
+ variant->prev = prev_variant;
+ }
+ prev_variant = variant;
+ }
+
+ gomp_metadirective *stmt
+ = gimple_build_omp_metadirective (selectors.length ());
+ gimple_omp_metadirective_set_variants (stmt, first_variant);
+
+ tree selector;
+ unsigned int i;
+ FOR_EACH_VEC_ELT (selectors, i, selector)
+ gimple_set_op (stmt, i, selector);
+
+ gimplify_seq_add_stmt (pre_p, stmt);
+ if (standalone_body)
+ {
+ gimplify_seq_add_stmt (pre_p, gimple_build_label (body_label));
+ gimplify_seq_add_stmt (pre_p, standalone_body);
+ }
+ gimplify_seq_add_stmt (pre_p, gimple_build_label (end_label));
+
+ return GS_ALL_DONE;
+}
+
/* Convert the GENERIC expression tree *EXPR_P to GIMPLE. If the
expression produces a value to be used as an operand inside a GIMPLE
statement, the value will be stored back in *EXPR_P. This value will
@@ -15586,6 +15675,11 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
ret = gimplify_omp_atomic (expr_p, pre_p);
break;
+ case OMP_METADIRECTIVE:
+ ret = gimplify_omp_metadirective (expr_p, pre_p, post_p,
+ gimple_test_f, fallback);
+ break;
+
case TRANSACTION_EXPR:
ret = gimplify_transaction (expr_p, pre_p);
break;
@@ -50,4 +50,6 @@ DEFGSSTRUCT(GSS_OMP_SINGLE_LAYOUT, gimple_statement_omp_single_layout, false)
DEFGSSTRUCT(GSS_OMP_CONTINUE, gomp_continue, false)
DEFGSSTRUCT(GSS_OMP_ATOMIC_LOAD, gomp_atomic_load, false)
DEFGSSTRUCT(GSS_OMP_ATOMIC_STORE_LAYOUT, gomp_atomic_store, false)
+DEFGSSTRUCT(GSS_OMP_METADIRECTIVE, gomp_metadirective, true)
+DEFGSSTRUCT(GSS_OMP_METADIRECTIVE_VARIANT, gomp_metadirective_variant, false)
DEFGSSTRUCT(GSS_TRANSACTION, gtransaction, false)
@@ -10418,6 +10418,10 @@ build_omp_regions_1 (basic_block bb, struct omp_region *parent,
/* GIMPLE_OMP_SECTIONS_SWITCH is part of
GIMPLE_OMP_SECTIONS, and we do nothing for it. */
}
+ else if (code == GIMPLE_OMP_METADIRECTIVE)
+ {
+ /* Do nothing for metadirectives. */
+ }
else
{
region = new_omp_region (bb, code, parent);
@@ -10791,6 +10795,30 @@ omp_make_gimple_edges (basic_block bb, struct omp_region **region,
}
break;
+ case GIMPLE_OMP_METADIRECTIVE:
+ /* Create an edge to the beginning of the body of each candidate
+ directive. */
+ {
+ gimple *stmt = last_stmt (bb);
+ unsigned i;
+ bool seen_default = false;
+
+ for (i = 0; i < gimple_num_ops (stmt); i++)
+ {
+ tree dest = gimple_omp_metadirective_label (stmt, i);
+ basic_block dest_bb = label_to_block (cfun, dest);
+ make_edge (bb, dest_bb, 0);
+
+ if (gimple_op (stmt, i) == NULL_TREE)
+ seen_default = true;
+ }
+
+ gcc_assert (seen_default);
+
+ fallthru = false;
+ }
+ break;
+
default:
gcc_unreachable ();
}
@@ -183,6 +183,10 @@ struct omp_context
/* Candidates for adjusting OpenACC privatization level. */
vec<tree> oacc_privatization_candidates;
+
+ /* Only used for omp metadirectives. Links to the next shallow
+ clone of this context. */
+ struct omp_context *next_clone;
};
static splay_tree all_contexts;
@@ -985,6 +989,7 @@ new_omp_context (gimple *stmt, omp_context *outer_ctx)
splay_tree_insert (all_contexts, (splay_tree_key) stmt,
(splay_tree_value) ctx);
ctx->stmt = stmt;
+ ctx->next_clone = NULL;
if (outer_ctx)
{
@@ -1014,6 +1019,18 @@ new_omp_context (gimple *stmt, omp_context *outer_ctx)
return ctx;
}
+static omp_context *
+clone_omp_context (omp_context *ctx)
+{
+ omp_context *clone_ctx = XCNEW (omp_context);
+
+ memcpy (clone_ctx, ctx, sizeof (omp_context));
+ ctx->next_clone = clone_ctx;
+ clone_ctx->next_clone = NULL;
+
+ return clone_ctx;
+}
+
static gimple_seq maybe_catch_exception (gimple_seq);
/* Finalize task copyfn. */
@@ -1060,6 +1077,15 @@ delete_omp_context (splay_tree_value value)
{
omp_context *ctx = (omp_context *) value;
+ /* Delete clones. */
+ omp_context *clone = ctx->next_clone;
+ while (clone)
+ {
+ omp_context *next_clone = clone->next_clone;
+ XDELETE (clone);
+ clone = next_clone;
+ }
+
delete ctx->cb.decl_map;
if (ctx->field_map)
@@ -3091,6 +3117,24 @@ scan_omp_teams (gomp_teams *stmt, omp_context *outer_ctx)
ctx->record_type = ctx->receiver_decl = NULL;
}
+/* Scan an OpenMP metadirective. */
+
+static void
+scan_omp_metadirective (gomp_metadirective *stmt, omp_context *outer_ctx)
+{
+ gomp_metadirective_variant *variant
+ = gimple_omp_metadirective_variants (stmt);
+
+ while (variant)
+ {
+ gimple_seq *directive_p = gimple_omp_body_ptr (variant);
+ omp_context *ctx = outer_ctx ? clone_omp_context (outer_ctx) : NULL;
+
+ scan_omp (directive_p, ctx);
+ variant = (gomp_metadirective_variant *) variant->next;
+ }
+}
+
/* Check nesting restrictions. */
static bool
check_omp_nesting_restrictions (gimple *stmt, omp_context *ctx)
@@ -4235,6 +4279,10 @@ scan_omp_1_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
scan_omp_teams (as_a <gomp_teams *> (stmt), ctx);
break;
+ case GIMPLE_OMP_METADIRECTIVE:
+ scan_omp_metadirective (as_a <gomp_metadirective *> (stmt), ctx);
+ break;
+
case GIMPLE_BIND:
{
tree var;
@@ -10654,6 +10702,21 @@ oacc_privatization_scan_decl_chain (omp_context *ctx, tree decls)
}
}
+static void
+lower_omp_metadirective (gimple_stmt_iterator *gsi_p, omp_context *ctx)
+{
+ gimple *stmt = gsi_stmt (*gsi_p);
+ gomp_metadirective_variant *variant
+ = gimple_omp_metadirective_variants (stmt);
+ while (variant)
+ {
+ gimple_seq *directive_p = gimple_omp_body_ptr (variant);
+ lower_omp (directive_p, ctx);
+
+ variant = (gomp_metadirective_variant *) (variant->next);
+ }
+}
+
/* Callback for walk_gimple_seq. Find #pragma omp scan statement. */
static tree
@@ -14230,6 +14293,9 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p, omp_context *ctx)
else
lower_omp_teams (gsi_p, ctx);
break;
+ case GIMPLE_OMP_METADIRECTIVE:
+ lower_omp_metadirective (gsi_p, ctx);
+ break;
case GIMPLE_CALL:
tree fndecl;
call_stmt = as_a <gcall *> (stmt);
@@ -1670,6 +1670,18 @@ cleanup_dead_labels (void)
}
break;
+ case GIMPLE_OMP_METADIRECTIVE:
+ {
+ for (unsigned i = 0; i < gimple_num_ops (stmt); i++)
+ {
+ label = gimple_omp_metadirective_label (stmt, i);
+ new_label = main_block_label (label, label_for_bb);
+ if (new_label != label)
+ gimple_omp_metadirective_set_label (stmt, i, new_label);
+ }
+ }
+ break;
+
default:
break;
}
@@ -6147,6 +6159,18 @@ gimple_redirect_edge_and_branch (edge e, basic_block dest)
gimple_block_label (dest));
break;
+ case GIMPLE_OMP_METADIRECTIVE:
+ {
+ for (unsigned i = 0; i < gimple_num_ops (stmt); i++)
+ {
+ tree label = gimple_omp_metadirective_label (stmt, i);
+ if (label_to_block (cfun, label) == e->dest)
+ gimple_omp_metadirective_set_label (stmt, i,
+ gimple_block_label (dest));
+ }
+ }
+ break;
+
default:
/* Otherwise it must be a fallthru edge, and we don't need to
do anything besides redirecting it. */
@@ -1674,6 +1674,35 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
(s1, gimple_omp_masked_clauses (stmt));
break;
+ case GIMPLE_OMP_METADIRECTIVE:
+ copy = gimple_build_omp_metadirective (gimple_num_ops (stmt));
+ {
+ gimple *first_variant = NULL;
+ gimple **prev_next = &first_variant;
+ for (gimple *variant = gimple_omp_metadirective_variants (stmt);
+ variant; variant = variant->next)
+ {
+ s1 = remap_gimple_seq (gimple_omp_body (variant), id);
+ gimple *new_variant
+ = gimple_build_omp_metadirective_variant (s1);
+
+ *prev_next = new_variant;
+ prev_next = &new_variant->next;
+ }
+ gimple_omp_metadirective_set_variants (copy, first_variant);
+ }
+
+ memset (&wi, 0, sizeof (wi));
+ wi.info = id;
+ for (unsigned i = 0; i < gimple_num_ops (stmt); i++)
+ {
+ tree label = gimple_omp_metadirective_label (stmt, i);
+ walk_tree (&label, remap_gimple_op_r, &wi, NULL);
+ gimple_omp_metadirective_set_label (copy, i, label);
+ gimple_set_op (copy, i, gimple_op (stmt, i));
+ }
+ break;
+
case GIMPLE_OMP_SCOPE:
s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
copy = gimple_build_omp_scope
@@ -4590,6 +4619,13 @@ estimate_num_insns (gimple *stmt, eni_weights *weights)
return (weights->omp_cost
+ estimate_num_insns_seq (gimple_omp_body (stmt), weights));
+ case GIMPLE_OMP_METADIRECTIVE:
+ /* The actual instruction will disappear eventually, so metadirective
+ statements have zero additional cost (if only static selectors
+ are used). */
+ /* TODO: Estimate the cost of evaluating dynamic selectors */
+ return 0;
+
case GIMPLE_TRANSACTION:
return (weights->tm_cost
+ estimate_num_insns_seq (gimple_transaction_body (
@@ -3751,6 +3751,40 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags,
is_expr = false;
break;
+ case OMP_METADIRECTIVE:
+ {
+ pp_string (pp, "#pragma omp metadirective");
+ newline_and_indent (pp, spc + 2);
+ pp_left_brace (pp);
+
+ tree clause = OMP_METADIRECTIVE_CLAUSES (node);
+ while (clause != NULL_TREE)
+ {
+ newline_and_indent (pp, spc + 4);
+ if (TREE_PURPOSE (clause) == NULL_TREE)
+ pp_string (pp, "default:");
+ else
+ {
+ pp_string (pp, "when (");
+ dump_generic_node (pp, TREE_PURPOSE (clause), spc + 4, flags,
+ false);
+ pp_string (pp, "):");
+ }
+ newline_and_indent (pp, spc + 6);
+
+ tree variant = TREE_VALUE (clause);
+ dump_generic_node (pp, TREE_PURPOSE (variant), spc + 6, flags,
+ false);
+ newline_and_indent (pp, spc + 6);
+ dump_generic_node (pp, TREE_VALUE (variant), spc + 6, flags,
+ false);
+ clause = TREE_CHAIN (clause);
+ }
+ newline_and_indent (pp, spc + 2);
+ pp_right_brace (pp);
+ }
+ break;
+
case TRANSACTION_EXPR:
if (TRANSACTION_EXPR_OUTER (node))
pp_string (pp, "__transaction_atomic [[outer]]");
@@ -973,6 +973,33 @@ operands_scanner::parse_ssa_operands ()
append_vuse (gimple_vop (fn));
goto do_default;
+ case GIMPLE_OMP_METADIRECTIVE:
+ n = gimple_num_ops (stmt);
+ for (i = start; i < n; i++)
+ {
+ for (tree selector = gimple_op (stmt, i);
+ selector != NULL;
+ selector = TREE_CHAIN (selector))
+ {
+ if (TREE_PURPOSE (selector) == get_identifier ("user"))
+ {
+ for (tree property = TREE_VALUE (selector);
+ property != NULL;
+ property = TREE_CHAIN (property))
+ if (TREE_PURPOSE (property)
+ == get_identifier ("condition"))
+ {
+ for (tree condition = TREE_VALUE (property);
+ condition != NULL;
+ condition = TREE_CHAIN (condition))
+ get_expr_operands (&TREE_VALUE (condition),
+ opf_use);
+ }
+ }
+ }
+ }
+ break;
+
case GIMPLE_CALL:
/* Add call-clobbered operands, if needed. */
maybe_add_call_vops (as_a <gcall *> (stmt));