]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
openmp: Add middle-end support for metadirectives
authorKwok Cheung Yeung <kcy@codesourcery.com>
Tue, 25 Jan 2022 18:36:59 +0000 (10:36 -0800)
committerKwok Cheung Yeung <kcy@codesourcery.com>
Tue, 25 Jan 2022 20:05:02 +0000 (12:05 -0800)
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  <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.

15 files changed:
gcc/ChangeLog.omp
gcc/gimple-low.c
gcc/gimple-pretty-print.c
gcc/gimple-walk.c
gcc/gimple.c
gcc/gimple.def
gcc/gimple.h
gcc/gimplify.c
gcc/gsstruct.def
gcc/omp-expand.c
gcc/omp-low.c
gcc/tree-cfg.c
gcc/tree-inline.c
gcc/tree-pretty-print.c
gcc/tree-ssa-operands.c

index 0615ddf515f5a9cbc2912c58f6e388f3aec9a617..c3842cc10adbe0a956e6cf589bf460dbc968faa7 100644 (file)
@@ -1,3 +1,56 @@
+2022-01-25  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+       * 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.
+
 2022-01-25  Kwok Cheung Yeung  <kcy@codesourcery.com>
 
        * omp-general.c (omp_context_selector_matches): Add extra argument.
index 7e39c22df4411db5cb2dfb9d54b8f57f9960b595..723c8b1d51648298976fb0cd47133269fe185fef 100644 (file)
@@ -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)),
index 03d9010e044a133301645af5265a5d5ae86d83aa..f302c7e7a76e5bd5fbd2ba69730725792aad6629 100644 (file)
@@ -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 <const gomp_metadirective *> (gs),
+                                    spc, flags);
+      break;
+
     case GIMPLE_CATCH:
       dump_gimple_catch (buffer, as_a <const gcatch *> (gs), spc, flags);
       break;
index 66fd491844d7b02c906d89e79107256133412e09..c0bbde8d08fa26ae479df8def4a5b0fc59eda64b 100644 (file)
@@ -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 <gtransaction *> (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);
index 1e71b319f9b744a5a86caeb70b62c60341f2a03b..e62a6fe6f00e95b7795e3081803e2810e2e5fb25 100644 (file)
@@ -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 *
index 193b2506523dff716cfca5e297064e3e5d729b53..55ff9883193c2d0b18649f35418ea679c1cbd2ca 100644 (file)
@@ -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.
index 988956242820ad1237715191b40264726bcc02fc..f98fdfac4bf24f1a8ebfc98e22655cf991bb18b3 100644 (file)
@@ -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 <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
@@ -1479,6 +1519,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
@@ -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 <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.  */
 
@@ -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
index d4abfa59fd7c1651843cd3af06678769aa433cae..3f3739fff208e2e69abce5a461831d571f04819c 100644 (file)
@@ -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<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
@@ -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;
index 8f777e2bb95bac5148db2a1d5dd9060956ec8f3d..ff10605baecc66bd8b8b998ad4ae42112e7bb30e 100644 (file)
@@ -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)
index 182868501fe7cbfa2e36e01674304c85a0cc50db..2f9f4cd1d4853d487fc36ad119c6330de5c00ee5 100644 (file)
@@ -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 ();
     }
index d64db62cc35aa90e379eb092cc353e83b447a453..9445a6b18ddbb0be650f4c72928d5f62f54060cf 100644 (file)
@@ -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 <gomp_teams *> (stmt), ctx);
       break;
 
+    case GIMPLE_OMP_METADIRECTIVE:
+      scan_omp_metadirective (as_a <gomp_metadirective *> (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 <gcall *> (stmt);
index 4f63aa69ba88dfe3d6ecc2c65727f079902cb2cd..82ca96a746c3991144b361c2ed08b9e7e2b34dc4 100644 (file)
@@ -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.  */
index 8c9c600767a7ae05a7319ced9c7b906546a089f5..051077598a4d1a3eb28661437f3eb81bf0f506a2 100644 (file)
@@ -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 (
index 2e0255176c766554ef5a5c9d500bbba4b8ab1532..6eedca4f91f121eda1d73f7d0ef6d92ca541a40e 100644 (file)
@@ -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]]");
index 9e620883d44bf47e51597c263947a681c3a67232..f1850ce3de428507b1573b6d22e5c2dbfd570e72 100644 (file)
@@ -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 <gcall *> (stmt));