From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1729) id 0DB1F385E009; Tue, 25 Jan 2022 20:36:22 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0DB1F385E009 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Kwok Yeung To: gcc-cvs@gcc.gnu.org Subject: [gcc/devel/omp/gcc-11] openmp: Add middle-end support for metadirectives X-Act-Checkin: gcc X-Git-Author: Kwok Cheung Yeung X-Git-Refname: refs/heads/devel/omp/gcc-11 X-Git-Oldrev: f464df13a44b9814341659be631f051377a2ce25 X-Git-Newrev: a238b6934b62ce3e8342047e41840c804d83b59d Message-Id: <20220125203622.0DB1F385E009@sourceware.org> Date: Tue, 25 Jan 2022 20:36:22 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 25 Jan 2022 20:36:22 -0000 https://gcc.gnu.org/g:a238b6934b62ce3e8342047e41840c804d83b59d commit a238b6934b62ce3e8342047e41840c804d83b59d Author: Kwok Cheung Yeung Date: Tue Jan 25 10:36:59 2022 -0800 openmp: Add middle-end support for metadirectives This adds a new Gimple statement type GIMPLE_OMP_METADIRECTIVE, which represents the metadirective in Gimple. In high Gimple, the statement contains the body of the directive variants, whereas in low Gimple, it only contains labels to the bodies. This patch adds support for converting metadirectives from tree to Gimple form, and handling of the Gimple form (Gimple lowering, OpenMP lowering and expansion, inlining, SSA handling etc). Metadirectives should be resolved before they reach the back-end, otherwise the compiler will crash as GCC does not know how to convert metadirective Gimple statements to RTX. 2022-01-25 Kwok Cheung Yeung 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 ::test): New. (is_a_helper ::test): New. (is_a_helper ::test): New. (is_a_helper ::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. Diff: --- gcc/ChangeLog.omp | 53 ++++++++++++++++++++++++ gcc/gimple-low.c | 34 ++++++++++++++++ gcc/gimple-pretty-print.c | 63 +++++++++++++++++++++++++++++ gcc/gimple-walk.c | 31 ++++++++++++++ gcc/gimple.c | 35 ++++++++++++++++ gcc/gimple.def | 7 ++++ gcc/gimple.h | 100 +++++++++++++++++++++++++++++++++++++++++++++- gcc/gimplify.c | 94 +++++++++++++++++++++++++++++++++++++++++++ gcc/gsstruct.def | 2 + gcc/omp-expand.c | 28 +++++++++++++ gcc/omp-low.c | 66 ++++++++++++++++++++++++++++++ gcc/tree-cfg.c | 24 +++++++++++ gcc/tree-inline.c | 36 +++++++++++++++++ gcc/tree-pretty-print.c | 34 ++++++++++++++++ gcc/tree-ssa-operands.c | 27 +++++++++++++ 15 files changed, 633 insertions(+), 1 deletion(-) diff --git a/gcc/ChangeLog.omp b/gcc/ChangeLog.omp index 0615ddf515f..c3842cc10ad 100644 --- a/gcc/ChangeLog.omp +++ b/gcc/ChangeLog.omp @@ -1,3 +1,56 @@ +2022-01-25 Kwok Cheung Yeung + + * 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 ::test): New. + (is_a_helper ::test): New. + (is_a_helper ::test): New. + (is_a_helper ::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. + 2022-01-25 Kwok Cheung Yeung * omp-general.c (omp_context_selector_matches): Add extra argument. diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c index 7e39c22df44..723c8b1d516 100644 --- a/gcc/gimple-low.c +++ b/gcc/gimple-low.c @@ -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 (stmt)), diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c index 03d9010e044..f302c7e7a76 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -2039,6 +2039,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 @@ -2802,6 +2859,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 (gs), + spc, flags); + break; + case GIMPLE_CATCH: dump_gimple_catch (buffer, as_a (gs), spc, flags); break; diff --git a/gcc/gimple-walk.c b/gcc/gimple-walk.c index 66fd491844d..c0bbde8d08f 100644 --- a/gcc/gimple-walk.c +++ b/gcc/gimple-walk.c @@ -494,6 +494,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 (stmt); @@ -709,6 +724,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); diff --git a/gcc/gimple.c b/gcc/gimple.c index 1e71b319f9b..e62a6fe6f00 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -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 (g); + + p->labels = ggc_cleared_vec_alloc (gimple_num_ops (p)); +} + +/* Build a GIMPLE_OMP_METADIRECTIVE statement. */ + +gomp_metadirective * +gimple_build_omp_metadirective (int num_variants) +{ + gomp_metadirective *p + = as_a (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 + (gimple_alloc (GIMPLE_OMP_METADIRECTIVE_VARIANT, 0)); + gimple_omp_set_body (variant, body); + return variant; +} + /* Build a GIMPLE_TRANSACTION statement. */ gtransaction * diff --git a/gcc/gimple.def b/gcc/gimple.def index 193b2506523..55ff9883193 100644 --- a/gcc/gimple.def +++ b/gcc/gimple.def @@ -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 specifies a hint for branch prediction. PREDICT is one of the predictors from predict.def. diff --git a/gcc/gimple.h b/gcc/gimple.h index 98895624282..f98fdfac4bf 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -826,6 +826,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. */ @@ -1237,6 +1261,22 @@ is_a_helper ::test (gimple *gs) return gs->code == GIMPLE_OMP_TASK; } +template <> +template <> +inline bool +is_a_helper ::test (gimple *gs) +{ + return gs->code == GIMPLE_OMP_METADIRECTIVE; +} + +template <> +template <> +inline bool +is_a_helper ::test (gimple *gs) +{ + return gs->code == GIMPLE_OMP_METADIRECTIVE_VARIANT; +} + template <> template <> inline bool @@ -1479,6 +1519,22 @@ is_a_helper ::test (const gimple *gs) return gs->code == GIMPLE_OMP_TASK; } +template <> +template <> +inline bool +is_a_helper ::test (const gimple *gs) +{ + return gs->code == GIMPLE_OMP_METADIRECTIVE; +} + +template <> +template <> +inline bool +is_a_helper ::test (const gimple *gs) +{ + return gs->code == GIMPLE_OMP_METADIRECTIVE_VARIANT; +} + template <> template <> inline bool @@ -1578,6 +1634,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 *); @@ -1835,6 +1894,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; @@ -2089,7 +2149,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 <> @@ -6429,6 +6490,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 (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 (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 (g); + return omp_metadirective->variants; +} + + +static inline void +gimple_omp_metadirective_set_variants (gimple *g, gimple *variants) +{ + gomp_metadirective *omp_metadirective = as_a (g); + omp_metadirective->variants + = variants ? as_a (variants) : NULL; +} + + /* Return a pointer to the body for the GIMPLE_TRANSACTION statement TRANSACTION_STMT. */ @@ -6579,6 +6676,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 diff --git a/gcc/gimplify.c b/gcc/gimplify.c index d4abfa59fd7..3f3739fff20 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -5678,6 +5678,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: @@ -15162,6 +15163,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 &, + 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 selectors; + + /* Try to resolve the metadirective. */ + vec 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 @@ -16068,6 +16157,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; diff --git a/gcc/gsstruct.def b/gcc/gsstruct.def index 8f777e2bb95..ff10605baec 100644 --- a/gcc/gsstruct.def +++ b/gcc/gsstruct.def @@ -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) diff --git a/gcc/omp-expand.c b/gcc/omp-expand.c index 182868501fe..2f9f4cd1d48 100644 --- a/gcc/omp-expand.c +++ b/gcc/omp-expand.c @@ -10552,6 +10552,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); @@ -10928,6 +10932,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 (); } diff --git a/gcc/omp-low.c b/gcc/omp-low.c index d64db62cc35..9445a6b18dd 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -189,6 +189,10 @@ struct omp_context /* Only used for omp target contexts. True if an OpenMP construct other than teams is strictly nested in it. */ bool nonteams_nested_p; + + /* Only used for omp metadirectives. Links to the next shallow + clone of this context. */ + struct omp_context *next_clone; }; static splay_tree all_contexts; @@ -1151,6 +1155,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) { @@ -1184,6 +1189,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. */ @@ -1230,6 +1247,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) @@ -3486,6 +3512,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) @@ -4620,6 +4664,10 @@ scan_omp_1_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, scan_omp_teams (as_a (stmt), ctx); break; + case GIMPLE_OMP_METADIRECTIVE: + scan_omp_metadirective (as_a (stmt), ctx); + break; + case GIMPLE_BIND: { tree var; @@ -10986,6 +11034,21 @@ lower_omp_for_lastprivate (struct omp_for_data *fd, gimple_seq *body_p, } } +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 @@ -14823,6 +14886,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 (stmt); diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 4f63aa69ba8..82ca96a746c 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -1668,6 +1668,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; } @@ -6085,6 +6097,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. */ diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 8c9c600767a..051077598a4 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -1683,6 +1683,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 @@ -4595,6 +4624,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 ( diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 2e0255176c7..6eedca4f91f 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -3783,6 +3783,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]]"); diff --git a/gcc/tree-ssa-operands.c b/gcc/tree-ssa-operands.c index 9e620883d44..f1850ce3de4 100644 --- a/gcc/tree-ssa-operands.c +++ b/gcc/tree-ssa-operands.c @@ -981,6 +981,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 (stmt));