public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/omp/gcc-12] openmp: Add middle-end support for metadirectives
@ 2022-06-29 14:43 Kwok Yeung
  0 siblings, 0 replies; only message in thread
From: Kwok Yeung @ 2022-06-29 14:43 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:30e0547b8deb41aa3ae3d4fbdd7c657871d0790d

commit 30e0547b8deb41aa3ae3d4fbdd7c657871d0790d
Author: Kwok Cheung Yeung <kcy@codesourcery.com>
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  <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.

Diff:
---
 gcc/ChangeLog.omp          |  53 ++++++++++++++++++++++++
 gcc/gimple-low.cc          |  34 +++++++++++++++
 gcc/gimple-pretty-print.cc |  63 ++++++++++++++++++++++++++++
 gcc/gimple-walk.cc         |  31 ++++++++++++++
 gcc/gimple.cc              |  35 ++++++++++++++++
 gcc/gimple.def             |   7 ++++
 gcc/gimple.h               | 100 ++++++++++++++++++++++++++++++++++++++++++++-
 gcc/gimplify.cc            |  94 ++++++++++++++++++++++++++++++++++++++++++
 gcc/gsstruct.def           |   2 +
 gcc/omp-expand.cc          |  28 +++++++++++++
 gcc/omp-low.cc             |  66 ++++++++++++++++++++++++++++++
 gcc/tree-cfg.cc            |  24 +++++++++++
 gcc/tree-inline.cc         |  36 ++++++++++++++++
 gcc/tree-pretty-print.cc   |  34 +++++++++++++++
 gcc/tree-ssa-operands.cc   |  27 ++++++++++++
 15 files changed, 633 insertions(+), 1 deletion(-)

diff --git a/gcc/ChangeLog.omp b/gcc/ChangeLog.omp
index b9629fcbb02..7ca90838b5a 100644
--- a/gcc/ChangeLog.omp
+++ b/gcc/ChangeLog.omp
@@ -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.
diff --git a/gcc/gimple-low.cc b/gcc/gimple-low.cc
index 2ec19d5657d..a1c2d67bdbd 100644
--- a/gcc/gimple-low.cc
+++ b/gcc/gimple-low.cc
@@ -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)),
diff --git a/gcc/gimple-pretty-print.cc b/gcc/gimple-pretty-print.cc
index 10b47e62a21..1d3c48968d4 100644
--- a/gcc/gimple-pretty-print.cc
+++ b/gcc/gimple-pretty-print.cc
@@ -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;
diff --git a/gcc/gimple-walk.cc b/gcc/gimple-walk.cc
index f91ff3c68cf..c5f3822f9c0 100644
--- a/gcc/gimple-walk.cc
+++ b/gcc/gimple-walk.cc
@@ -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);
diff --git a/gcc/gimple.cc b/gcc/gimple.cc
index 9e62da4265b..f6dc694d3d1 100644
--- a/gcc/gimple.cc
+++ b/gcc/gimple.cc
@@ -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 *
diff --git a/gcc/gimple.def b/gcc/gimple.def
index 296c73c2d52..b987eb4e37e 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 <PREDICT, OUTCOME> 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 77c7f81ba08..b35ae25eea6 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -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
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index 5111decad01..f94707d78d8 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -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;
diff --git a/gcc/gsstruct.def b/gcc/gsstruct.def
index 19e1088b718..c9ee6dc2e9a 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.cc b/gcc/omp-expand.cc
index 88c2da3def3..acd17b08f3a 100644
--- a/gcc/omp-expand.cc
+++ b/gcc/omp-expand.cc
@@ -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 ();
     }
diff --git a/gcc/omp-low.cc b/gcc/omp-low.cc
index a40af51ec15..c9e9dec8559 100644
--- a/gcc/omp-low.cc
+++ b/gcc/omp-low.cc
@@ -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);
diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc
index e321d929fd0..344d671f940 100644
--- a/gcc/tree-cfg.cc
+++ b/gcc/tree-cfg.cc
@@ -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.  */
diff --git a/gcc/tree-inline.cc b/gcc/tree-inline.cc
index ca66a8266b1..192786ae875 100644
--- a/gcc/tree-inline.cc
+++ b/gcc/tree-inline.cc
@@ -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 (
diff --git a/gcc/tree-pretty-print.cc b/gcc/tree-pretty-print.cc
index 9e85b53493e..3dbfec9a7e8 100644
--- a/gcc/tree-pretty-print.cc
+++ b/gcc/tree-pretty-print.cc
@@ -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]]");
diff --git a/gcc/tree-ssa-operands.cc b/gcc/tree-ssa-operands.cc
index 4915622e163..29b7d0377ff 100644
--- a/gcc/tree-ssa-operands.cc
+++ b/gcc/tree-ssa-operands.cc
@@ -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));


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-06-29 14:43 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-29 14:43 [gcc/devel/omp/gcc-12] openmp: Add middle-end support for metadirectives Kwok Yeung

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).