public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/omp/gcc-12] openmp: Add support for resolving metadirectives during parsing and Gimplification
@ 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:d1e6d779001bdac5eab3080fd5d0fa7cfe85a6b4

commit d1e6d779001bdac5eab3080fd5d0fa7cfe85a6b4
Author: Kwok Cheung Yeung <kcy@codesourcery.com>
Date:   Tue Jan 25 10:42:50 2022 -0800

    openmp: Add support for resolving metadirectives during parsing and Gimplification
    
    This adds support for resolving metadirectives according to the OpenMP 5.1
    specification.  The variants are sorted by score, then gathered into a list
    of dynamic replacement candidates.  The metadirective is then expanded into
    a sequence of 'if..else' statements to test the dynamic selector and execute
    the variant if the selector is satisfied.
    
    If any of the selectors in the list are unresolvable, GCC will give up on
    resolving the metadirective and try again later.
    
    2022-01-25  Kwok Cheung Yeung  <kcy@codesourcery.com>
    
            gcc/
            * gimplify.cc (expand_omp_metadirective): New.
            * omp-general.cc: Include tree-pretty-print.h.
            (DELAY_METADIRECTIVES_AFTER_LTO): New macro.
            (omp_context_selector_matches): Delay resolution of selectors.  Allow
            non-constant expressions.
            (omp_dynamic_cond): New.
            (omp_dynamic_selector_p): New.
            (sort_variant): New.
            (omp_get_dynamic_candidates): New.
            (omp_resolve_metadirective): New.
            (omp_resolve_metadirective): New.
            * omp-general.h (struct omp_metadirective_variant): New.
            (omp_resolve_metadirective): New prototype.
    
            gcc/c-family/
            * c-omp.cc (c_omp_expand_metadirective_r): New.
            (c_omp_expand_metadirective): New.

Diff:
---
 gcc/ChangeLog.omp          |  16 ++++
 gcc/c-family/ChangeLog.omp |   5 +
 gcc/c-family/c-omp.cc      |  45 ++++++++-
 gcc/gimplify.cc            |  72 +++++++++++++-
 gcc/omp-general.cc         | 232 ++++++++++++++++++++++++++++++++++++++++++++-
 gcc/omp-general.h          |   7 ++
 6 files changed, 367 insertions(+), 10 deletions(-)

diff --git a/gcc/ChangeLog.omp b/gcc/ChangeLog.omp
index 7ca90838b5a..843aa6d922c 100644
--- a/gcc/ChangeLog.omp
+++ b/gcc/ChangeLog.omp
@@ -1,3 +1,19 @@
+2022-01-25  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+	* gimplify.cc (expand_omp_metadirective): New.
+	* omp-general.cc: Include tree-pretty-print.h.
+	(DELAY_METADIRECTIVES_AFTER_LTO): New macro.
+	(omp_context_selector_matches): Delay resolution of selectors.  Allow
+	non-constant expressions.
+	(omp_dynamic_cond): New.
+	(omp_dynamic_selector_p): New.
+	(sort_variant): New.
+	(omp_get_dynamic_candidates): New.
+	(omp_resolve_metadirective): New.
+	(omp_resolve_metadirective): New.
+	* omp-general.h (struct omp_metadirective_variant): New.
+	(omp_resolve_metadirective): New prototype.
+
 2022-01-25  Kwok Cheung Yeung  <kcy@codesourcery.com>
 
 	* gimple-low.cc (lower_omp_metadirective): New.
diff --git a/gcc/c-family/ChangeLog.omp b/gcc/c-family/ChangeLog.omp
index a783f4b56e1..49950946b81 100644
--- a/gcc/c-family/ChangeLog.omp
+++ b/gcc/c-family/ChangeLog.omp
@@ -1,3 +1,8 @@
+2022-01-25  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+	* c-omp.cc (c_omp_expand_metadirective_r): New.
+	(c_omp_expand_metadirective): New.
+
 2022-01-25  Kwok Cheung Yeung  <kcy@codesourcery.com>
 
 	* c-common.h (enum c_omp_directive_kind): Add C_OMP_DIR_META.
diff --git a/gcc/c-family/c-omp.cc b/gcc/c-family/c-omp.cc
index 82c2fb6844d..ca4f0766516 100644
--- a/gcc/c-family/c-omp.cc
+++ b/gcc/c-family/c-omp.cc
@@ -4033,8 +4033,49 @@ c_omp_categorize_directive (const char *first, const char *second,
   return NULL;
 }
 
+static tree
+c_omp_expand_metadirective_r (vec<struct omp_metadirective_variant> &candidates,
+			      hash_map<tree, tree> &body_labels,
+			      unsigned index)
+{
+  struct omp_metadirective_variant &candidate = candidates[index];
+  tree if_block = push_stmt_list ();
+  if (candidate.directive != NULL_TREE)
+    add_stmt (candidate.directive);
+  if (candidate.body != NULL_TREE)
+    {
+      tree *label = body_labels.get (candidate.body);
+      if (label != NULL)
+	add_stmt (build1 (GOTO_EXPR, void_type_node, *label));
+      else
+	{
+	  tree body_label = create_artificial_label (UNKNOWN_LOCATION);
+	  add_stmt (build1 (LABEL_EXPR, void_type_node, body_label));
+	  add_stmt (candidate.body);
+	  body_labels.put (candidate.body, body_label);
+	}
+    }
+  if_block = pop_stmt_list (if_block);
+
+  if (index == candidates.length () - 1)
+    return if_block;
+
+  tree cond = candidate.selector;
+  gcc_assert (cond != NULL_TREE);
+
+  tree else_block = c_omp_expand_metadirective_r (candidates, body_labels,
+						  index + 1);
+  tree ret = push_stmt_list ();
+  tree stmt = build3 (COND_EXPR, void_type_node, cond, if_block, else_block);
+  add_stmt (stmt);
+  ret = pop_stmt_list (ret);
+
+  return ret;
+}
+
 tree
-c_omp_expand_metadirective (vec<struct omp_metadirective_variant> &)
+c_omp_expand_metadirective (vec<struct omp_metadirective_variant> &candidates)
 {
-  return NULL_TREE;
+  hash_map<tree, tree> body_labels;
+  return c_omp_expand_metadirective_r (candidates, body_labels, 0);
 }
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index f94707d78d8..fca7f4d6bf2 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -15548,10 +15548,76 @@ gimplify_omp_ordered (tree expr, gimple_seq body)
    CANDIDATES.  */
 
 static enum gimplify_status
-expand_omp_metadirective (vec<struct omp_metadirective_variant> &,
-			  gimple_seq *)
+expand_omp_metadirective (vec<struct omp_metadirective_variant> &candidates,
+			  gimple_seq *pre_p)
 {
-  return GS_ERROR;
+  auto_vec<tree> selectors;
+  auto_vec<tree> directive_labels;
+  auto_vec<gimple_seq> directive_bodies;
+  tree body_label = NULL_TREE;
+  tree end_label = create_artificial_label (UNKNOWN_LOCATION);
+
+  /* Construct bodies for each candidate.  */
+  for (unsigned i = 0; i < candidates.length(); i++)
+    {
+      struct omp_metadirective_variant &candidate = candidates[i];
+      gimple_seq body = NULL;
+
+      selectors.safe_push (candidate.selector);
+      directive_labels.safe_push (create_artificial_label (UNKNOWN_LOCATION));
+
+      gimplify_seq_add_stmt (&body,
+			     gimple_build_label (directive_labels.last ()));
+      if (candidate.directive != NULL_TREE)
+	gimplify_stmt (&candidate.directive, &body);
+      if (candidate.body != NULL_TREE)
+	{
+	  if (body_label != NULL_TREE)
+	    gimplify_seq_add_stmt (&body, gimple_build_goto (body_label));
+	  else
+	    {
+	      body_label = create_artificial_label (UNKNOWN_LOCATION);
+	      gimplify_seq_add_stmt (&body, gimple_build_label (body_label));
+	      gimplify_stmt (&candidate.body, &body);
+	    }
+	}
+
+      directive_bodies.safe_push (body);
+    }
+
+  auto_vec<tree> cond_labels;
+
+  cond_labels.safe_push (NULL_TREE);
+  for (unsigned i = 1; i < candidates.length () - 1; i++)
+    cond_labels.safe_push (create_artificial_label (UNKNOWN_LOCATION));
+  if (candidates.length () > 1)
+    cond_labels.safe_push (directive_labels.last ());
+
+  /* Generate conditionals to test each dynamic selector in turn, executing
+     the directive candidate if successful.  */
+  for (unsigned i = 0; i < candidates.length () - 1; i++)
+    {
+      if (i != 0)
+	gimplify_seq_add_stmt (pre_p, gimple_build_label (cond_labels [i]));
+
+      enum gimplify_status ret = gimplify_expr (&selectors[i], pre_p, NULL,
+						is_gimple_val, fb_rvalue);
+      if (ret == GS_ERROR || ret == GS_UNHANDLED)
+	return ret;
+
+      gcond *cond_stmt
+	= gimple_build_cond_from_tree (selectors[i], directive_labels[i],
+				       cond_labels[i + 1]);
+
+      gimplify_seq_add_stmt (pre_p, cond_stmt);
+      gimplify_seq_add_seq (pre_p, directive_bodies[i]);
+      gimplify_seq_add_stmt (pre_p, gimple_build_goto (end_label));
+    }
+
+  gimplify_seq_add_seq (pre_p, directive_bodies.last ());
+  gimplify_seq_add_stmt (pre_p, gimple_build_label (end_label));
+
+  return GS_ALL_DONE;
 }
 
 /* Gimplify an OMP_METADIRECTIVE construct.   EXPR is the tree version.
diff --git a/gcc/omp-general.cc b/gcc/omp-general.cc
index c50a4883e03..d7a962a643e 100644
--- a/gcc/omp-general.cc
+++ b/gcc/omp-general.cc
@@ -45,6 +45,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "data-streamer.h"
 #include "streamer-hooks.h"
 #include "opts.h"
+#include "tree-pretty-print.h"
 
 enum omp_requires omp_requires_mask;
 
@@ -1270,14 +1271,22 @@ omp_context_name_list_prop (tree prop)
     }
 }
 
+#define DELAY_METADIRECTIVES_AFTER_LTO { \
+  if (metadirective_p && !(cfun->curr_properties & PROP_gimple_lomp_dev))	\
+    return -1;	\
+}
+
 /* Return 1 if context selector matches the current OpenMP context, 0
    if it does not and -1 if it is unknown and need to be determined later.
    Some properties can be checked right away during parsing (this routine),
    others need to wait until the whole TU is parsed, others need to wait until
-   IPA, others until vectorization.  */
+   IPA, others until vectorization.
+
+   Dynamic properties (which are evaluated at run-time) should always
+   return 1.  */
 
 int
-omp_context_selector_matches (tree ctx, bool)
+omp_context_selector_matches (tree ctx, bool metadirective_p)
 {
   int ret = 1;
   for (tree t1 = ctx; t1; t1 = TREE_CHAIN (t1))
@@ -1398,6 +1407,8 @@ omp_context_selector_matches (tree ctx, bool)
 		    const char *arch = omp_context_name_list_prop (t3);
 		    if (arch == NULL)
 		      return 0;
+		    DELAY_METADIRECTIVES_AFTER_LTO;
+
 		    int r = 0;
 		    if (targetm.omp.device_kind_arch_isa != NULL)
 		      r = targetm.omp.device_kind_arch_isa (omp_device_arch,
@@ -1522,6 +1533,8 @@ omp_context_selector_matches (tree ctx, bool)
 #endif
 			continue;
 		      }
+		    DELAY_METADIRECTIVES_AFTER_LTO;
+
 		    int r = 0;
 		    if (targetm.omp.device_kind_arch_isa != NULL)
 		      r = targetm.omp.device_kind_arch_isa (omp_device_kind,
@@ -1561,6 +1574,8 @@ omp_context_selector_matches (tree ctx, bool)
 		    const char *isa = omp_context_name_list_prop (t3);
 		    if (isa == NULL)
 		      return 0;
+		    DELAY_METADIRECTIVES_AFTER_LTO;
+
 		    int r = 0;
 		    if (targetm.omp.device_kind_arch_isa != NULL)
 		      r = targetm.omp.device_kind_arch_isa (omp_device_isa,
@@ -1612,6 +1627,12 @@ omp_context_selector_matches (tree ctx, bool)
 		for (tree t3 = TREE_VALUE (t2); t3; t3 = TREE_CHAIN (t3))
 		  if (TREE_PURPOSE (t3) == NULL_TREE)
 		    {
+		      /* OpenMP 5.1 allows non-constant conditions for
+			 metadirectives.  */
+		      if (metadirective_p
+			  && !tree_fits_shwi_p (TREE_VALUE (t3)))
+			break;
+
 		      if (integer_zerop (TREE_VALUE (t3)))
 			return 0;
 		      if (integer_nonzerop (TREE_VALUE (t3)))
@@ -1627,6 +1648,8 @@ omp_context_selector_matches (tree ctx, bool)
   return ret;
 }
 
+#undef DELAY_METADIRECTIVES_AFTER_LTO
+
 /* Compare construct={simd} CLAUSES1 with CLAUSES2, return 0/-1/1/2 as
    in omp_context_selector_set_compare.  */
 
@@ -1984,6 +2007,32 @@ omp_get_context_selector (tree ctx, const char *set, const char *sel)
   return NULL_TREE;
 }
 
+/* Return a tree expression representing the dynamic part of the context
+ * selector CTX.  */
+
+static tree
+omp_dynamic_cond (tree ctx)
+{
+  tree user = omp_get_context_selector (ctx, "user", "condition");
+  if (user)
+    {
+      tree expr_list = TREE_VALUE (user);
+
+      gcc_assert (TREE_PURPOSE (expr_list) == NULL_TREE);
+      return TREE_VALUE (expr_list);
+    }
+  return NULL_TREE;
+}
+
+/* Return true iff the context selector CTX contains a dynamic element
+   that cannot be resolved at compile-time.  */
+
+static bool
+omp_dynamic_selector_p (tree ctx)
+{
+  return omp_dynamic_cond (ctx) != NULL_TREE;
+}
+
 /* Compute *SCORE for context selector CTX.  Return true if the score
    would be different depending on whether it is a declare simd clone or
    not.  DECLARE_SIMD should be true for the case when it would be
@@ -2641,16 +2690,189 @@ omp_lto_input_declare_variant_alt (lto_input_block *ib, cgraph_node *node,
 						 INSERT) = entryp;
 }
 
+static int
+sort_variant (const void * a, const void *b, void *)
+{
+  widest_int score1 = ((const struct omp_metadirective_variant *) a)->score;
+  widest_int score2 = ((const struct omp_metadirective_variant *) b)->score;
+
+  if (score1 > score2)
+    return -1;
+  else if (score1 < score2)
+    return 1;
+  else
+    return 0;
+}
+
+/* Return a vector of dynamic replacement candidates for the directive
+   candidates in ALL_VARIANTS.  Return an empty vector if the metadirective
+   cannot be resolved.  */
+
+static vec<struct omp_metadirective_variant>
+omp_get_dynamic_candidates (vec <struct omp_metadirective_variant> &all_variants)
+{
+  auto_vec <struct omp_metadirective_variant> variants;
+  struct omp_metadirective_variant default_variant;
+  bool default_found = false;
+
+  for (unsigned int i = 0; i < all_variants.length (); i++)
+    {
+      struct omp_metadirective_variant variant = all_variants[i];
+
+      if (all_variants[i].selector == NULL_TREE)
+	{
+	  default_found = true;
+	  default_variant = all_variants[i];
+	  default_variant.score = 0;
+	  default_variant.resolvable_p = true;
+	  default_variant.dynamic_p = false;
+	  continue;
+	}
+
+      variant.resolvable_p = true;
+
+      if (dump_file)
+	{
+	  fprintf (dump_file, "Considering selector ");
+	  print_generic_expr (dump_file, variant.selector);
+	  fprintf (dump_file, " as candidate - ");
+	}
+
+      switch (omp_context_selector_matches (variant.selector, true))
+	{
+	case -1:
+	  variant.resolvable_p = false;
+	  if (dump_file)
+	    fprintf (dump_file, "unresolvable");
+	  /* FALLTHRU */
+	case 1:
+	  /* TODO: Handle SIMD score?.  */
+	  omp_context_compute_score (variant.selector, &variant.score, false);
+	  variant.dynamic_p = omp_dynamic_selector_p (variant.selector);
+	  variants.safe_push (variant);
+	  break;
+	case 0:
+	  if (dump_file)
+	    fprintf (dump_file, "no match");
+	  break;
+	}
+
+      if (dump_file)
+	fprintf (dump_file, "\n");
+    }
+
+  /* There must be one default variant.  */
+  gcc_assert (default_found);
+
+  /* A context selector that is a strict subset of another context selector
+     has a score of zero.  */
+  for (unsigned int i = 0; i < variants.length (); i++)
+    for (unsigned int j = i + 1; j < variants.length (); j++)
+      {
+	int r = omp_context_selector_compare (variants[i].selector,
+					      variants[j].selector);
+	if (r == -1)
+	  {
+	    /* variant1 is a strict subset of variant2.  */
+	    variants[i].score = 0;
+	    break;
+	  }
+	else if (r == 1)
+	  /* variant2 is a strict subset of variant1.  */
+	  variants[j].score = 0;
+      }
+
+  /* Sort the variants by decreasing score, preserving the original order
+     in case of a tie.  */
+  variants.stablesort (sort_variant, NULL);
+
+  /* Add the default as a final choice.  */
+  variants.safe_push (default_variant);
+
+  /* Build the dynamic candidate list.  */
+  for (unsigned i = 0; i < variants.length (); i++)
+    {
+      /* If one of the candidates is unresolvable, give up for now.  */
+      if (!variants[i].resolvable_p)
+	{
+	  variants.truncate (0);
+	  break;
+	}
+
+      /* Replace the original selector with just the dynamic part.  */
+      variants[i].selector = omp_dynamic_cond (variants[i].selector);
+
+      if (dump_file)
+	{
+	  fprintf (dump_file, "Adding directive variant with ");
+
+	  if (variants[i].selector)
+	    {
+	      fprintf (dump_file, "selector ");
+	      print_generic_expr (dump_file, variants[i].selector);
+	    }
+	  else
+	    fprintf (dump_file, "default selector");
+
+	  fprintf (dump_file, " as candidate.\n");
+	}
+
+      /* The last of the candidates is ended by a static selector.  */
+      if (!variants[i].dynamic_p)
+	{
+	  variants.truncate (i + 1);
+	  break;
+	}
+    }
+
+  return variants.copy ();
+}
+
 /* Return a vector of dynamic replacement candidates for the metadirective
    statement in METADIRECTIVE.  Return an empty vector if the metadirective
    cannot be resolved.  */
 
 vec<struct omp_metadirective_variant>
-omp_resolve_metadirective (tree)
+omp_resolve_metadirective (tree metadirective)
+{
+  auto_vec <struct omp_metadirective_variant> variants;
+  tree clause = OMP_METADIRECTIVE_CLAUSES (metadirective);
+
+  while (clause)
+    {
+      struct omp_metadirective_variant variant;
+
+      variant.selector = TREE_PURPOSE (clause);
+      variant.directive = TREE_PURPOSE (TREE_VALUE (clause));
+      variant.body = TREE_VALUE (TREE_VALUE (clause));
+
+      variants.safe_push (variant);
+      clause = TREE_CHAIN (clause);
+    }
+
+  return omp_get_dynamic_candidates (variants);
+}
+
+/* Return a vector of dynamic replacement candidates for the metadirective
+   Gimple statement in GS.  Return an empty vector if the metadirective
+   cannot be resolved.  */
+
+vec<struct omp_metadirective_variant>
+omp_resolve_metadirective (gimple *gs)
 {
-  vec<struct omp_metadirective_variant> variants = {};
+  auto_vec <struct omp_metadirective_variant> variants;
+
+  for (unsigned i = 0; i < gimple_num_ops (gs); i++)
+    {
+      struct omp_metadirective_variant variant;
+
+      variant.selector = gimple_op (gs, i);
+      variant.directive	= gimple_omp_metadirective_label (gs, i);
+
+      variants.safe_push (variant);
+    }
 
-  return variants;
+  return omp_get_dynamic_candidates (variants);
 }
 
 /* Encode an oacc launch argument.  This matches the GOMP_LAUNCH_PACK
diff --git a/gcc/omp-general.h b/gcc/omp-general.h
index 01701534205..65c1a60ad41 100644
--- a/gcc/omp-general.h
+++ b/gcc/omp-general.h
@@ -93,6 +93,12 @@ struct omp_for_data
 
 struct omp_metadirective_variant
 {
+  widest_int score;
+  tree selector;
+  tree directive;
+  tree body;
+  bool dynamic_p : 1;
+  bool resolvable_p : 1;
 };
 
 #define OACC_FN_ATTRIB "oacc function"
@@ -119,6 +125,7 @@ extern int omp_context_selector_set_compare (const char *, tree, tree);
 extern tree omp_get_context_selector (tree, const char *, const char *);
 extern tree omp_resolve_declare_variant (tree);
 extern vec<struct omp_metadirective_variant> omp_resolve_metadirective (tree);
+extern vec<struct omp_metadirective_variant> omp_resolve_metadirective (gimple *);
 extern tree oacc_launch_pack (unsigned code, tree device, unsigned op);
 extern tree oacc_replace_fn_attrib_attr (tree attribs, tree dims);
 extern void oacc_replace_fn_attrib (tree fn, tree dims);


^ 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 support for resolving metadirectives during parsing and Gimplification 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).