Patchwork [gomp4] #pragma omp declare target and some nesting checking

login
register
mail settings
Submitter Jakub Jelinek
Date May 28, 2013, 12:39 p.m.
Message ID <20130528123907.GN1377@tucnak.redhat.com>
Download mbox | patch
Permalink /patch/246859/
State New
Headers show

Comments

Jakub Jelinek - May 28, 2013, 12:39 p.m.
Hi!

This patch handles
#pragma omp declare target
...
#pragma omp end declare target
and adds some accelerator related nesting restrictions.

I haven't done much checking that both the opening and closing
directive appear in the same scope, perhaps that can be done later on.
Plus I guess further checking should be done during intantiation
(something cplus_declare_attributes doesn't verify if
processing_template_decl), and we'll need extra diagnostics that all
vars/functions used in target regions actually have "omp declare target"
attribute, but that will be probably best done during omplow when we clone
the bodies.

All the VAR_DECLs/FUNCTION_DECLs seen in the declare target directive
get "omp declare target" attribute on them.

Does this look reasonable?

2013-05-28  Jakub Jelinek  <jakub@redhat.com>

	* omp-low.c (check_omp_nesting_restrictions): Add some
	accelerator related nesting restrictions.
	(scan_omp_1_stmt): Call check_omp_nesting_restrictions
	even for GOMP_taskgroup_{start,end}.
	* gimplify.c (omp_notice_threadprivate_variable): Fix a typo.
	(gimplify_body): For functions with "omp declare target" attribute
	add ORT_TARGET region around the body.
cp/
	* parser.c (cp_parser_omp_declare_target,
	cp_parser_omp_end_declare_target): New functions.
	(cp_parser_omp_declare): For target keyword call
	cp_parser_omp_declare_target.
	(cp_parser_pragma): Handle PRAGMA_OMP_END_DECLARE_TARGET.
	* cp-tree.h (current_omp_declare_target_attribute): Declare.
	* decl2.c (current_omp_declare_target_attribute): New variable.
	(cp_omp_mappable_type): New function.
	(cplus_decl_attributes): Handle addition of "omp declare target"
	attribute for decls in #pragma omp declare target region.  Complain
	for invalid uses.
c-family/
	* c-common.c (c_common_attribute_table): Add "omp declare target"
	attribute.
	(handle_omp_declare_target_attribute): New function.


	Jakub

Patch

--- gcc/omp-low.c.jj	2013-05-27 09:22:21.000000000 +0200
+++ gcc/omp-low.c	2013-05-27 19:14:16.156240922 +0200
@@ -1864,20 +1864,54 @@  scan_omp_single (gimple stmt, omp_contex
 static bool
 check_omp_nesting_restrictions (gimple stmt, omp_context *ctx)
 {
-  if (ctx != NULL
-      && gimple_code (ctx->stmt) == GIMPLE_OMP_FOR
-      && (gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD
-	  || gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_FOR_SIMD))
+  if (ctx != NULL)
     {
-      error_at (gimple_location (stmt),
-		"OpenMP constructs may not be nested inside simd region");
-      return false;
+      if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR
+	  && (gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD
+	      || gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_FOR_SIMD))
+	{
+	  error_at (gimple_location (stmt),
+		    "OpenMP constructs may not be nested inside simd region");
+	  return false;
+	}
+      else if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS)
+	{
+	  if ((gimple_code (stmt) != GIMPLE_OMP_FOR
+	       || gimple_omp_for_kind (ctx->stmt) != GF_OMP_FOR_KIND_DISTRIBUTE)
+	      && gimple_code (stmt) != GIMPLE_OMP_PARALLEL)
+	    {
+	      error_at (gimple_location (stmt),
+			"only distribute or parallel constructs are allowed to "
+			"be closely nested inside teams construct");
+	      return false;
+	    }
+	}
+      else if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR
+	       && gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_DISTRIBUTE
+	       && gimple_code (stmt) != GIMPLE_OMP_PARALLEL)
+	{
+	  error_at (gimple_location (stmt),
+		    "only parallel constructs are allowed to "
+		    "be closely nested inside distribute construct");
+	  return false;
+	}
     }
   switch (gimple_code (stmt))
     {
     case GIMPLE_OMP_FOR:
       if (gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_SIMD)
 	return true;
+      if (gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_DISTRIBUTE)
+	{
+	  if (ctx == NULL || gimple_code (ctx->stmt) != GIMPLE_OMP_TEAMS)
+	    {
+	      error_at (gimple_location (stmt),
+			"distribute construct must be closely nested inside "
+			"teams construct");
+	      return false;
+	    }
+	  return true;
+	}
       /* FALLTHRU */
     case GIMPLE_OMP_SECTIONS:
     case GIMPLE_OMP_SINGLE:
@@ -1973,6 +2007,17 @@  check_omp_nesting_restrictions (gimple s
 	    return false;
 	  }
       break;
+    case GIMPLE_OMP_TEAMS:
+      if (ctx == NULL
+	  || gimple_code (ctx->stmt) != GIMPLE_OMP_TARGET
+	  || gimple_omp_target_kind (ctx->stmt) != GF_OMP_TARGET_KIND_REGION)
+	{
+	  error_at (gimple_location (stmt),
+		    "teams construct not closely nested inside of target "
+		    "region");
+	  return false;
+	}
+      break;
     default:
       break;
     }
@@ -2062,6 +2107,8 @@  scan_omp_1_stmt (gimple_stmt_iterator *g
 	      case BUILT_IN_GOMP_CANCELLATION_POINT:
 	      case BUILT_IN_GOMP_TASKYIELD:
 	      case BUILT_IN_GOMP_TASKWAIT:
+	      case BUILT_IN_GOMP_TASKGROUP_START:
+	      case BUILT_IN_GOMP_TASKGROUP_END:
 		remove = !check_omp_nesting_restrictions (stmt, ctx);
 		break;
 	      default:
--- gcc/cp/parser.c.jj	2013-05-27 09:22:21.000000000 +0200
+++ gcc/cp/parser.c	2013-05-27 17:07:36.697516807 +0200
@@ -29240,6 +29240,30 @@  cp_parser_omp_declare_simd (cp_parser *p
     }
 }
 
+/* OpenMP 4.0:
+   # pragma omp declare target new-line
+   declarations and definitions
+   # pragma omp end declare target new-line  */
+
+static void
+cp_parser_omp_declare_target (cp_parser *parser, cp_token *pragma_tok)
+{
+  cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+  current_omp_declare_target_attribute++;
+}
+
+static void
+cp_parser_omp_end_declare_target (cp_parser *parser, cp_token *pragma_tok)
+{
+  cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+  if (!current_omp_declare_target_attribute)
+    error_at (pragma_tok->location,
+	      "%<#pragma omp end declare target%> without corresponding "
+	      "%<#pragma omp declare target%>");
+  else
+    current_omp_declare_target_attribute--;
+}
+
 /* OpenMP 4.0
    #pragma omp declare simd declare-simd-clauses[optseq] new-line
    #pragma omp declare reduction (reduction-id : typename-list : expression) \
@@ -29269,6 +29293,12 @@  cp_parser_omp_declare (cp_parser *parser
 					   context);
 	  return;
 	}  */
+      if (strcmp (p, "target") == 0)
+	{
+	  cp_lexer_consume_token (parser->lexer);
+	  cp_parser_omp_declare_target (parser, pragma_tok);
+	  return;
+	}
     }
   cp_parser_error (parser, "expected %<simd%> or %<reduction%>");
   cp_parser_require_pragma_eol (parser, pragma_tok);
@@ -29811,6 +29841,10 @@  cp_parser_pragma (cp_parser *parser, enu
     case PRAGMA_OMP_TARGET:
       return cp_parser_omp_target (parser, pragma_tok, context);
 
+    case PRAGMA_OMP_END_DECLARE_TARGET:
+      cp_parser_omp_end_declare_target (parser, pragma_tok);
+      return false;
+
     case PRAGMA_OMP_SECTION:
       error_at (pragma_tok->location, 
 		"%<#pragma omp section%> may only be used in "
--- gcc/cp/cp-tree.h.jj	2013-05-13 16:46:13.000000000 +0200
+++ gcc/cp/cp-tree.h	2013-05-28 10:49:49.848595138 +0200
@@ -4428,6 +4428,10 @@  extern GTY(()) vec<tree, va_gc> *local_c
 
 extern int at_eof;
 
+/* If non-zero, implicit "omp declare target" attribute is added into the
+   attribute lists.  */
+extern GTY(()) int current_omp_declare_target_attribute;
+
 /* A list of namespace-scope objects which have constructors or
    destructors which reside in the global scope.  The decl is stored
    in the TREE_VALUE slot and the initializer is stored in the
--- gcc/cp/decl2.c.jj	2013-05-13 16:46:02.000000000 +0200
+++ gcc/cp/decl2.c	2013-05-28 12:50:31.749223097 +0200
@@ -102,6 +102,9 @@  static GTY(()) vec<tree, va_gc> *no_link
 
 int at_eof;
 
+/* If non-zero, implicit "omp declare target" attribute is added into the
+   attribute lists.  */
+int current_omp_declare_target_attribute;
 
 
 /* Return a member function type (a METHOD_TYPE), given FNTYPE (a
@@ -1330,6 +1333,27 @@  cp_check_const_attributes (tree attribut
     }
 }
 
+/* Return true if TYPE is an OpenMP mappable type.  */
+static bool
+cp_omp_mappable_type (tree type)
+{
+  /* Mappable type has to be complete.  */
+  if (type == error_mark_node || !COMPLETE_TYPE_P (type))
+    return false;
+  /* A mappable type cannot contain virtual members.  */
+  if (CLASS_TYPE_P (type) && CLASSTYPE_VTABLES (type))
+    return false;
+  /* All data members must be non-static.  */
+  if (CLASS_TYPE_P (type))
+    {
+      tree field;
+      for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+	if (TREE_CODE (field) == VAR_DECL)
+	  return false;
+    }
+  return true;
+}
+
 /* Like decl_attributes, but handle C++ complexity.  */
 
 void
@@ -1339,6 +1363,30 @@  cplus_decl_attributes (tree *decl, tree
       || *decl == error_mark_node)
     return;
 
+  /* Add implicit "omp declare target" attribute if requested.  */
+  if (current_omp_declare_target_attribute
+      && (TREE_CODE (*decl) == VAR_DECL
+	  || TREE_CODE (*decl) == FUNCTION_DECL))
+    {
+      if (TREE_CODE (*decl) == VAR_DECL
+	  && RECORD_OR_UNION_CODE_P (TREE_CODE (CP_DECL_CONTEXT (*decl))))
+	error ("%q+D static data member inside of declare target directive",
+	       *decl);
+      else if (TREE_CODE (*decl) == VAR_DECL
+	       && (TREE_CODE (CP_DECL_CONTEXT (*decl)) == FUNCTION_DECL
+		   || (current_function_decl && !DECL_EXTERNAL (*decl))))
+	error ("%q+D in block scope inside of declare target directive",
+	       *decl);
+      else if (!processing_template_decl
+	       && TREE_CODE (*decl) == VAR_DECL
+	       && !cp_omp_mappable_type (TREE_TYPE (*decl)))
+	error ("%q+D in declare target directive does not have mappable type",
+	       *decl);
+      else
+	attributes = tree_cons (get_identifier ("omp declare target"),
+				NULL_TREE, attributes);
+    }
+
   if (processing_template_decl)
     {
       if (check_for_bare_parameter_packs (attributes))
--- gcc/gimplify.c.jj	2013-05-27 09:22:21.000000000 +0200
+++ gcc/gimplify.c	2013-05-27 18:11:15.113539762 +0200
@@ -5911,7 +5911,7 @@  omp_notice_threadprivate_variable (struc
   for (octx = ctx; octx; octx = octx->outer_context)
     if (octx->region_type == ORT_TARGET)
       {
-	n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl);
+	n = splay_tree_lookup (octx->variables, (splay_tree_key)decl);
 	if (n == NULL)
 	  {
 	    error ("threadprivate variable %qE used in target region",
@@ -8587,6 +8587,13 @@  gimplify_body (tree fndecl, bool do_parm
   gcc_assert (gimplify_ctxp == NULL);
   push_gimplify_context (&gctx);
 
+  if (flag_openmp)
+    {
+      gcc_assert (gimplify_omp_ctxp == NULL);
+      if (lookup_attribute ("omp declare target", DECL_ATTRIBUTES (fndecl)))
+	gimplify_omp_ctxp = new_omp_context (ORT_TARGET);
+    }
+
   /* Unshare most shared trees in the body and in that of any nested functions.
      It would seem we don't have to do this for nested functions because
      they are supposed to be output and then the outer function gimplified
@@ -8649,6 +8656,12 @@  gimplify_body (tree fndecl, bool do_parm
       nonlocal_vlas = NULL;
     }
 
+  if (flag_openmp && gimplify_omp_ctxp)
+    {
+      delete_omp_context (gimplify_omp_ctxp);
+      gimplify_omp_ctxp = NULL;
+    }
+
   pop_gimplify_context (outer_bind);
   gcc_assert (gimplify_ctxp == NULL);
 
--- gcc/c-family/c-common.c.jj	2013-05-20 13:18:25.000000000 +0200
+++ gcc/c-family/c-common.c	2013-05-27 16:58:37.870668360 +0200
@@ -370,6 +370,8 @@  static tree handle_no_split_stack_attrib
 static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *);
 static tree handle_omp_declare_simd_attribute (tree *, tree, tree, int,
 					       bool *);
+static tree handle_omp_declare_target_attribute (tree *, tree, tree, int,
+						 bool *);
 
 static void check_function_nonnull (tree, int, tree *);
 static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT);
@@ -742,6 +744,8 @@  const struct attribute_spec c_common_att
 			      handle_fnspec_attribute, false },
   { "omp declare simd",       0, -1, true,  false, false,
 			      handle_omp_declare_simd_attribute, false },
+  { "omp declare target",     0, 0, true, false, false,
+			      handle_omp_declare_target_attribute, false },
   { NULL,                     0, 0, false, false, false, NULL, false }
 };
 
@@ -7966,6 +7970,15 @@  handle_omp_declare_simd_attribute (tree
 {
   return NULL_TREE;
 }
+
+/* Handle an "omp declare target" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_omp_declare_target_attribute (tree *, tree, tree, int, bool *)
+{
+  return NULL_TREE;
+}
 
 /* Handle a "returns_twice" attribute; arguments as in
    struct attribute_spec.handler.  */