]> 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, 28 Jun 2022 20:53:28 +0000 (13:53 -0700)
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.cc (lower_omp_metadirective): New.
(lower_stmt): Handle GIMPLE_OMP_METADIRECTIVE.
* gimple-pretty-print.cc (dump_gimple_omp_metadirective): New.
(pp_gimple_stmt_1): Handle GIMPLE_OMP_METADIRECTIVE.
* gimple-walk.cc (walk_gimple_op): Handle GIMPLE_OMP_METADIRECTIVE.
(walk_gimple_stmt): Likewise.
* gimple.cc (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.cc (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.cc (build_omp_regions_1): Handle GIMPLE_OMP_METADIRECTIVE.
(omp_make_gimple_edges): Likewise.
* omp-low.cc (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.cc (cleanup_dead_labels): Handle GIMPLE_OMP_METADIRECTIVE.
(gimple_redirect_edge_and_branch): Likewise.
* tree-inline.cc (remap_gimple_stmt): Handle GIMPLE_OMP_METADIRECTIVE.
(estimate_num_insns): Likewise.
* tree-pretty-print.cc (dump_generic_node): Handle OMP_METADIRECTIVE.
* tree-ssa-operands.cc (parse_ssa_operands): Handle
GIMPLE_OMP_METADIRECTIVE.

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

index b9629fcbb0248c2873d02a00a4ce488381babfe5..7ca90838b5a16cade5350a113217e4944210e381 100644 (file)
@@ -1,3 +1,56 @@
+2022-01-25  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+       * gimple-low.cc (lower_omp_metadirective): New.
+       (lower_stmt): Handle GIMPLE_OMP_METADIRECTIVE.
+       * gimple-pretty-print.cc (dump_gimple_omp_metadirective): New.
+       (pp_gimple_stmt_1): Handle GIMPLE_OMP_METADIRECTIVE.
+       * gimple-walk.cc (walk_gimple_op): Handle GIMPLE_OMP_METADIRECTIVE.
+       (walk_gimple_stmt): Likewise.
+       * gimple.cc (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.cc (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.cc (build_omp_regions_1): Handle GIMPLE_OMP_METADIRECTIVE.
+       (omp_make_gimple_edges): Likewise.
+       * omp-low.cc (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.cc (cleanup_dead_labels): Handle GIMPLE_OMP_METADIRECTIVE.
+       (gimple_redirect_edge_and_branch): Likewise.
+       * tree-inline.cc (remap_gimple_stmt): Handle GIMPLE_OMP_METADIRECTIVE.
+       (estimate_num_insns): Likewise.
+       * tree-pretty-print.cc (dump_generic_node): Handle OMP_METADIRECTIVE.
+       * tree-ssa-operands.cc (parse_ssa_operands): Handle
+       GIMPLE_OMP_METADIRECTIVE.
+
 2022-01-25  Kwok Cheung Yeung  <kcy@codesourcery.com>
 
        * omp-general.cc (omp_context_selector_matches): Add extra argument.
index 2ec19d5657d2a207c2691d194b8bb1ac11ca41eb..a1c2d67bdbddfb500945c49b96a11d497ae21821 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 10b47e62a21c604a3e71c67de1492755a9d727c3..1d3c48968d43fb6458e881413bc5fb2c51788a5d 100644 (file)
@@ -2054,6 +2054,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
@@ -2826,6 +2883,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 f91ff3c68cf84bf3910684594e6313ceb3cf8715..c5f3822f9c02292faa58fadd1110b7f1a5c539a0 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 9e62da4265b2a8a02121d574ddfad2095d8048ad..f6dc694d3d1af456530da968cf530b5b0c91b683 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 296c73c2d5233ca0ce0ed65b8dca3580d51b8e44..b987eb4e37edec3b7b0f7d033088ae5fa28cc8d7 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 77c7f81ba0875934626b77dc156850ee85491415..b35ae25eea64f91cc4b7baf46b7f6df2cf5e9728 100644 (file)
@@ -827,6 +827,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.  */
@@ -1238,6 +1262,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
@@ -1480,6 +1520,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
@@ -1579,6 +1635,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 *);
@@ -1856,6 +1915,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;
@@ -2113,7 +2173,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 <>
@@ -6500,6 +6561,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.  */
 
@@ -6650,6 +6747,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 5111decad01ca61dcf3b8d3118c1eb1ff5da1fa6..f94707d78d80f2361a65b7a4484595704c523b3c 100644 (file)
@@ -5937,6 +5937,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:
@@ -15543,6 +15544,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
@@ -16460,6 +16549,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 19e1088b718be1085efdabb362767f5866865a71..c9ee6dc2e9a7044f08150f6de474d8ff5732436c 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 88c2da3def36ba56005f070191a89a26780a8922..acd17b08f3a5cf24ed46ae68c5d13c9017d8df0a 100644 (file)
@@ -10539,6 +10539,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);
@@ -10917,6 +10921,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 a40af51ec151811e4adce6bb6d29a822ec52022c..c9e9dec85595b130f88776c9203595f3f65129d9 100644 (file)
@@ -189,6 +189,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;
@@ -1140,6 +1144,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)
     {
@@ -1172,6 +1177,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.  */
@@ -1218,6 +1235,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)
@@ -3535,6 +3561,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)
@@ -4687,6 +4731,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;
@@ -11196,6 +11244,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
@@ -15094,6 +15157,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 e321d929fd0cd3dfe81b079674ece6d98f9c5af1..344d671f940aebce70eb4960969f96d7d98ed6b2 100644 (file)
@@ -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;
       }
@@ -6130,6 +6142,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 ca66a8266b14de42c8c10917b06239aaf93a9758..192786ae8755ddcd4b3cbd7ab27ffa0a8444381d 100644 (file)
@@ -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 (
index 9e85b53493ed121199ac38cf8990e50cc8909bd9..3dbfec9a7e86bb53362cb89a9c19711c8e1ea740 100644 (file)
@@ -3809,6 +3809,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 4915622e163d3d151b0b6e335e45338a3d67f7e7..29b7d0377ff73a0458b7d353818fce6de4d0e196 100644 (file)
@@ -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));