public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [Patch] OpenMP (C only): omp allocate - handle stack vars, improve diagnostic
@ 2023-08-29 16:12 Tobias Burnus
  2023-08-29 16:28 ` Jakub Jelinek
  0 siblings, 1 reply; 15+ messages in thread
From: Tobias Burnus @ 2023-08-29 16:12 UTC (permalink / raw)
  To: gcc-patches, Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 1190 bytes --]

This adds support for
   #pragma omp allocate(var-list) [allocator(..) align(..)]

While the spec permits stack and static variables, this patch only
adds support for stack variables - keeping the 'sorry' for static
variables.
It is also only C as I wanted to get this out before updating C++
parsing. However, if disable the 'sorry' + add the attribute, it
will also work for C++.

For Fortran, there is no expression associated with the declaration
such that it will not work with the gimplify.cc patch (it cannot
find the place to add it); however, I have a mostly working version
for FE generated support for stack _and_ static variables.

The main RFC question for this patch is whether to generate the
GOMP_alloc/free calls also for !TREE_USED() or not. This patch avoids
this to aid removal of such stack variables, but one could also argue
otherwise.

Thoughts, comments, remarks?

Tobias
-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955

[-- Attachment #2: omp-allocate-c.diff --]
[-- Type: text/x-patch, Size: 30713 bytes --]

OpenMP (C only): omp allocate - handle stack vars, improve diagnostic

The 'allocate' directive can be used for both stack and static variables.
While the parser in C and C++ was pre-existing, it missed several
diagnostics, which this commit adds - for now only for C.
Additionally, it stopped with a sorry after parsing.

For C only, the sorry is now restricted to static variables, the stack
variable declarations are now tagged by the 'omp allocate' attribute and
in gimplify_bind_expr the GOMP_alloc/GOMP_free allocation will now be
added.

Follow up: Add the same parser additions for C++ and update the testcases.
And add Fortran support, where also parsing support exists, where also
diagnostic updates are required.

gcc/c/ChangeLog:

	* c-parser.cc (c_parser_omp_construct): Move call to
	c_parser_omp_allocate to ...
	(c_parser_pragma): ... here.
	(c_parser_omp_allocate): Avoid ICE is allocator could not
	be parsed; set 'omp allocate' attribute for stack variables
	and only reject stack variables; add several additional
	restriction checks.

gcc/ChangeLog:

	* gimplify.cc (gimplify_bind_expr): Convert 'omp allocate'
	var-decl attribute to GOMP_alloc/GOMP_free calls.

libgomp/ChangeLog:

	* libgomp.texi (Impl.Status): Mark allocate directive as 'P'.
	(OMP_ALLOCATOR): Fix name of ICV variable.
	* testsuite/libgomp.c-c++-common/allocate-4.c: New test.

gcc/testsuite/ChangeLog:

	* c-c++-common/gomp/allocate-5.c: Fix testcase; make some
	dg-messages for 'sorry' as c++, only.
	* c-c++-common/gomp/directive-1.c: Make a 'sorry' c++ only.
	* c-c++-common/gomp/allocate-10.c: New test.
	* c-c++-common/gomp/allocate-9.c: New test.

 gcc/c/c-parser.cc                                  | 73 ++++++++++++++---
 gcc/gimplify.cc                                    | 82 +++++++++++++++----
 gcc/testsuite/c-c++-common/gomp/allocate-10.c      | 46 +++++++++++
 gcc/testsuite/c-c++-common/gomp/allocate-5.c       | 58 ++++++-------
 gcc/testsuite/c-c++-common/gomp/allocate-9.c       | 94 ++++++++++++++++++++++
 gcc/testsuite/c-c++-common/gomp/directive-1.c      |  2 +-
 libgomp/libgomp.texi                               |  7 +-
 .../testsuite/libgomp.c-c++-common/allocate-4.c    | 75 +++++++++++++++++
 8 files changed, 377 insertions(+), 60 deletions(-)

diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index cae10ba9c80..a04fd474a28 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -1679,6 +1679,7 @@ static bool c_parser_omp_declare (c_parser *, enum pragma_context);
 static void c_parser_omp_requires (c_parser *);
 static bool c_parser_omp_error (c_parser *, enum pragma_context);
 static void c_parser_omp_assumption_clauses (c_parser *, bool);
+static void c_parser_omp_allocate (c_parser *);
 static void c_parser_omp_assumes (c_parser *);
 static bool c_parser_omp_ordered (c_parser *, enum pragma_context, bool *);
 static void c_parser_oacc_routine (c_parser *, enum pragma_context);
@@ -13620,6 +13621,10 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p)
       c_parser_omp_requires (parser);
       return false;
 
+    case PRAGMA_OMP_ALLOCATE:
+      c_parser_omp_allocate (parser);
+      return false;
+
     case PRAGMA_OMP_ASSUMES:
       if (context != pragma_external)
 	{
@@ -19316,10 +19321,13 @@ c_parser_oacc_wait (location_t loc, c_parser *parser, char *p_name)
    align (constant-expression)]  */
 
 static void
-c_parser_omp_allocate (location_t loc, c_parser *parser)
+c_parser_omp_allocate (c_parser *parser)
 {
   tree alignment = NULL_TREE;
   tree allocator = NULL_TREE;
+  c_parser_consume_pragma (parser);
+  location_t loc = c_parser_peek_token (parser)->location;
+  location_t allocator_loc = UNKNOWN_LOCATION;
   tree nl = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ALLOCATE, NULL_TREE);
   do
     {
@@ -19344,7 +19352,9 @@ c_parser_omp_allocate (location_t loc, c_parser *parser)
       c_expr expr = c_parser_expr_no_commas (parser, NULL);
       expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
       expr_loc = c_parser_peek_token (parser)->location;
-      if (p[2] == 'i' && alignment)
+      if (expr.value == error_mark_node)
+	;
+      else if (p[2] == 'i' && alignment)
 	{
 	  error_at (expr_loc, "too many %qs clauses", "align");
 	  break;
@@ -19371,6 +19381,7 @@ c_parser_omp_allocate (location_t loc, c_parser *parser)
       else
 	{
 	  allocator = c_fully_fold (expr.value, false, NULL);
+	  allocator_loc = expr_loc;
 	  tree orig_type
 	    = expr.original_type ? expr.original_type : TREE_TYPE (allocator);
 	  orig_type = TYPE_MAIN_VARIANT (orig_type);
@@ -19390,14 +19401,53 @@ c_parser_omp_allocate (location_t loc, c_parser *parser)
     } while (true);
   c_parser_skip_to_pragma_eol (parser);
 
-  if (allocator || alignment)
-    for (tree c = nl; c != NULL_TREE; c = OMP_CLAUSE_CHAIN (c))
-      {
-	OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) = allocator;
-	OMP_CLAUSE_ALLOCATE_ALIGN (c) = alignment;
-      }
-
-  sorry_at (loc, "%<#pragma omp allocate%> not yet supported");
+  for (tree c = nl; c != NULL_TREE; c = OMP_CLAUSE_CHAIN (c))
+    {
+      tree var = OMP_CLAUSE_DECL (c);
+      if (TREE_CODE (var) == PARM_DECL)
+	{
+	  error_at (OMP_CLAUSE_LOCATION (nl),
+		    "function parameter %qD may not appear as list item in an "
+		    "%<allocate%> directive", var);
+	  continue;
+	}
+      if (!c_check_in_current_scope (var))
+	{
+	  error_at (OMP_CLAUSE_LOCATION (nl),
+		    "%<allocate%> directive must be in the same scope as %qD",
+		    var);
+	  inform (DECL_SOURCE_LOCATION (var), "declared here");
+	  continue;
+	}
+      if (lookup_attribute ("omp allocate", DECL_ATTRIBUTES (var)))
+	{
+	  error_at (OMP_CLAUSE_LOCATION (nl),
+		    "%qD already appeared as list item in an "
+		    "%<allocate%> directive", var);
+	  continue;
+	}
+      if (TREE_STATIC (var))
+	{
+	  if (allocator == NULL_TREE && allocator_loc == UNKNOWN_LOCATION)
+	    error_at (loc, "%<allocator%> clause required for "
+			   "static variable %qD", var);
+	  else if (allocator
+		   && (tree_int_cst_sgn (allocator) != 1
+		       || tree_to_shwi (allocator) > 8))
+	    /* 8 = largest predefined memory allocator. */
+	    error_at (allocator_loc,
+		      "%<allocator%> clause requires a predefined allocator as "
+		      "%qD is static", var);
+	  else
+	    sorry_at (OMP_CLAUSE_LOCATION (nl),
+		      "%<#pragma omp allocate%> for static variables like "
+		      "%qD not yet supported", var);
+	  continue;
+	}
+      DECL_ATTRIBUTES (var) = tree_cons (get_identifier ("omp allocate"),
+					 build_tree_list (allocator, alignment),
+					 DECL_ATTRIBUTES (var));
+    }
 }
 
 /* OpenMP 2.5:
@@ -24894,9 +24944,6 @@ c_parser_omp_construct (c_parser *parser, bool *if_p)
       strcpy (p_name, "#pragma wait");
       stmt = c_parser_oacc_wait (loc, parser, p_name);
       break;
-    case PRAGMA_OMP_ALLOCATE:
-      c_parser_omp_allocate (loc, parser);
-      return;
     case PRAGMA_OMP_ATOMIC:
       c_parser_omp_atomic (loc, parser, false);
       return;
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index a49b50bc857..e48eb404bcb 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -1364,6 +1364,44 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)
 	{
 	  struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp;
 
+	  tree attr;
+	  if (flag_openmp
+	      && !is_global_var (t)
+	      && DECL_CONTEXT (t) == current_function_decl
+	      && TREE_USED (t)
+	      && (attr = lookup_attribute ("omp allocate", DECL_ATTRIBUTES (t)))
+		 != NULL_TREE)
+	    {
+	      tree v = create_tmp_var_raw (build_pointer_type (TREE_TYPE (t)));
+	      DECL_IGNORED_P (v) = 0;
+	      tree tmp = build_fold_indirect_ref (v);
+	      TREE_THIS_NOTRAP (tmp) = 1;
+	      SET_DECL_VALUE_EXPR (t, tmp);
+	      DECL_HAS_VALUE_EXPR_P (t) = 1;
+	      attr = TREE_VALUE (attr);
+	      tree sz = TYPE_SIZE_UNIT (TREE_TYPE (t));
+	      tree alloc = (TREE_PURPOSE (attr)
+			    ? TREE_PURPOSE (attr)
+			    : build_zero_cst (ptr_type_node));
+	      tree align = (TREE_VALUE (attr)
+			    ? TREE_VALUE (attr) : build_zero_cst (size_type_node));
+	      tmp = builtin_decl_explicit (BUILT_IN_GOMP_ALLOC);
+	      tmp = build_call_expr_loc (DECL_SOURCE_LOCATION (t), tmp, 3, align, sz, alloc);
+	      tmp = fold_build2_loc (DECL_SOURCE_LOCATION (t), MODIFY_EXPR, TREE_TYPE (v), v,
+				     fold_convert (TREE_TYPE (v), tmp));
+	      gcc_assert (BIND_EXPR_BODY (bind_expr) != NULL_TREE
+			  && TREE_CODE (BIND_EXPR_BODY (bind_expr)) == STATEMENT_LIST);
+	      tree_stmt_iterator e = tsi_start (BIND_EXPR_BODY (bind_expr));
+	      while (!tsi_end_p (e))
+		{
+		  if (EXPR_LOCATION (*e) == DECL_SOURCE_LOCATION (t))
+		    break;
+		  ++e;
+		}
+	      gcc_assert (!tsi_end_p (e));
+	      tsi_link_before (&e, tmp, TSI_SAME_STMT);
+	    }
+
 	  /* Mark variable as local.  */
 	  if (ctx && ctx->region_type != ORT_NONE && !DECL_EXTERNAL (t))
 	    {
@@ -1446,22 +1484,6 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)
   cleanup = NULL;
   stack_save = NULL;
 
-  /* If the code both contains VLAs and calls alloca, then we cannot reclaim
-     the stack space allocated to the VLAs.  */
-  if (gimplify_ctxp->save_stack && !gimplify_ctxp->keep_stack)
-    {
-      gcall *stack_restore;
-
-      /* Save stack on entry and restore it on exit.  Add a try_finally
-	 block to achieve this.  */
-      build_stack_save_restore (&stack_save, &stack_restore);
-
-      gimple_set_location (stack_save, start_locus);
-      gimple_set_location (stack_restore, end_locus);
-
-      gimplify_seq_add_stmt (&cleanup, stack_restore);
-    }
-
   /* Add clobbers for all variables that go out of scope.  */
   for (t = BIND_EXPR_VARS (bind_expr); t ; t = DECL_CHAIN (t))
     {
@@ -1469,6 +1491,17 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)
 	  && !is_global_var (t)
 	  && DECL_CONTEXT (t) == current_function_decl)
 	{
+	  if (flag_openmp
+	      && DECL_HAS_VALUE_EXPR_P (t)
+	      && TREE_USED (t)
+	      && lookup_attribute ("omp allocate", DECL_ATTRIBUTES (t)))
+	    {
+	      tree tmp = builtin_decl_explicit (BUILT_IN_GOMP_FREE);
+	      tmp = build_call_expr_loc (end_locus, tmp, 2,
+					 TREE_OPERAND (DECL_VALUE_EXPR (t), 0),
+					 build_zero_cst (ptr_type_node));
+	      gimplify_and_add (tmp, &cleanup);
+	    }
 	  if (!DECL_HARD_REGISTER (t)
 	      && !TREE_THIS_VOLATILE (t)
 	      && !DECL_HAS_VALUE_EXPR_P (t)
@@ -1525,6 +1558,23 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)
 	gimplify_ctxp->live_switch_vars->remove (t);
     }
 
+  /* If the code both contains VLAs and calls alloca, then we cannot reclaim
+     the stack space allocated to the VLAs.  */
+  if (gimplify_ctxp->save_stack && !gimplify_ctxp->keep_stack)
+    {
+      gcall *stack_restore;
+
+      /* Save stack on entry and restore it on exit.  Add a try_finally
+	 block to achieve this.  */
+      build_stack_save_restore (&stack_save, &stack_restore);
+
+      gimple_set_location (stack_save, start_locus);
+      gimple_set_location (stack_restore, end_locus);
+
+      gimplify_seq_add_stmt (&cleanup, stack_restore);
+    }
+
+
   if (ret_clauses)
     {
       gomp_target *stmt;
diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-10.c b/gcc/testsuite/c-c++-common/gomp/allocate-10.c
new file mode 100644
index 00000000000..6fe16b1eb03
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/allocate-10.c
@@ -0,0 +1,46 @@
+/* TODO: enable for C++ once implemented. */
+/* { dg-do compile { target c } } */
+/* { dg-additional-options "-Wall -fdump-tree-gimple" } */
+
+typedef enum omp_allocator_handle_t
+{
+  omp_default_mem_alloc = 1,
+  __omp_allocator_handle_t_max__ = __UINTPTR_MAX__
+} omp_allocator_handle_t;
+
+void
+f()
+{
+  int n;
+  int A[n]; /* { dg-warning "'n' is used uninitialized" } */
+  /* { dg-warning "unused variable 'A'" "" { target *-*-* } .-1 } */
+}
+
+void
+h1()
+{
+  omp_allocator_handle_t my_handle;
+  int B1[3]; /* { dg-warning "'my_handle' is used uninitialized" } */
+  /* { dg-warning "variable 'B1' set but not used" "" { target *-*-* } .-1 } */
+  #pragma omp allocate(B1) allocator(my_handle)
+  B1[0] = 5;
+  /* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc" 1 "gimple" } } */
+  /* { dg-final { scan-tree-dump-times "D.\[0-9\]+ = __builtin_GOMP_alloc \\(0, 12, my_handle\\);" 1 "gimple" } } */
+  /* { dg-final { scan-tree-dump-times "__builtin_GOMP_free \\(D.\[0-9\]+, 0B\\);" 1 "gimple" } } */
+}
+
+void
+h2()
+{
+  omp_allocator_handle_t my_handle;
+  int B2[3];  /* { dg-warning "unused variable 'B2'" } */
+  #pragma omp allocate(B2) allocator(my_handle) /* No warning as 'B2' is unused */
+}
+
+void
+h3()
+{
+  omp_allocator_handle_t my_handle;
+  int B3[3] = {1,2,3};  /* { dg-warning "unused variable 'B3'" } */
+  #pragma omp allocate(B3) allocator(my_handle) /* No warning as 'B3' is unused */
+}
diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-5.c b/gcc/testsuite/c-c++-common/gomp/allocate-5.c
index 8a9181205f7..de1efc6832d 100644
--- a/gcc/testsuite/c-c++-common/gomp/allocate-5.c
+++ b/gcc/testsuite/c-c++-common/gomp/allocate-5.c
@@ -19,59 +19,63 @@ void
 foo ()
 {
   int a, b;
+  static int c;
   omp_allocator_handle_t my_allocator;
-#pragma omp allocate (a)  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" } */
-#pragma omp allocate (b) allocator(my_allocator)  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" } */
+#pragma omp allocate (a)  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } } */
+#pragma omp allocate (b) allocator(my_allocator)  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } } */
+#pragma omp allocate(c) align(32)
+  /* { dg-message "'allocator' clause required for static variable 'c'" "" { target c } .-1 } */
+  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-2 } */
 }
 
 void
 bar ()
 {
-  int a, b;
+  int a, a2, b;
   omp_allocator_handle_t my_allocator;
 #pragma omp allocate  /* { dg-error "expected '\\(' before end of line" } */
-  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target *-*-* } .-1 } */
+  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
 #pragma omp allocate allocator(my_allocator)  /* { dg-error "expected '\\(' before 'allocator'" } */
-  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target *-*-* } .-1 } */
+  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
 #pragma omp allocate(a) foo(my_allocator) /* { dg-error "expected 'allocator'" } */
   /* { dg-error "expected end of line before '\\(' token" "" { target *-*-* } .-1 } */
-  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target *-*-* } .-2 } */
-#pragma omp allocate(a) allocator(b)  /* { dg-error "'allocator' clause allocator expression has type 'int' rather than 'omp_allocator_handle_t'" "todo: cp/semantics.c" { xfail c++ } } */
-  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target *-*-* } .-1 } */
+  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-2 } */
+#pragma omp allocate(a2) allocator(b)  /* { dg-error "'allocator' clause allocator expression has type 'int' rather than 'omp_allocator_handle_t'" "todo: cp/semantics.c" { xfail c++ } } */
+  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
 }
 
 
 void
 align_test ()
 {
-  int i;
-  #pragma omp allocate(i) allocator(omp_default_mem_alloc), align(32)
-  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target *-*-* } .-1 } */
-  #pragma omp allocate(i) align ( 32 ),allocator(omp_default_mem_alloc)
-  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target *-*-* } .-1 } */
-  #pragma omp allocate(i),allocator(omp_default_mem_alloc) align(32)
-  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target *-*-* } .-1 } */
-  #pragma omp allocate(i) align ( 32 ) allocator(omp_default_mem_alloc)
-  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target *-*-* } .-1 } */
+  int i1,i2,i3,i4,i5,i6;
+  #pragma omp allocate(i1) allocator(omp_default_mem_alloc), align(32)
+  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
+  #pragma omp allocate(i2) align ( 32 ),allocator(omp_default_mem_alloc)
+  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
+  #pragma omp allocate(i3),allocator(omp_default_mem_alloc) align(32)
+  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
+  #pragma omp allocate(i4) align ( 32 ) allocator(omp_default_mem_alloc)
+  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
 
-  #pragma omp allocate(i) allocator ( omp_high_bw_mem_alloc ), align ( 32 ) allocator(omp_default_mem_alloc)
+  #pragma omp allocate(i5) allocator ( omp_high_bw_mem_alloc ), align ( 32 ) allocator(omp_default_mem_alloc)
   /* { dg-error "too many 'allocator' clauses" "" { target *-*-* } .-1 } */
   /* { dg-error "expected end of line before '\\)' token" "" { target *-*-* } .-2 } */
-  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target *-*-* } .-3 } */
-  #pragma omp allocate(i) align ( 32 ), align(32) allocator(omp_default_mem_alloc)
+  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-3 } */
+  #pragma omp allocate(i6) align ( 32 ), align(32) allocator(omp_default_mem_alloc)
   /* { dg-error "too many 'align' clauses" "" { target *-*-* } .-1 } */
   /* { dg-error "expected end of line before '\\)' token" "" { target *-*-* } .-2 } */
-  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target *-*-* } .-3 } */
+  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-3 } */
 }
 
 void
 align_test2 ()
 {
-  int i;
+  int i, i2,i3;
   #pragma omp allocate(i) align (32.0)  /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" } */
-  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target *-*-* } .-1 } */
-  #pragma omp allocate(i) align ( 31 )  /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" } */
-  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target *-*-* } .-1 } */
-  #pragma omp allocate(i) align ( -32 )  /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" } */
-  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target *-*-* } .-1 } */
+  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
+  #pragma omp allocate(i2) align ( 31 )  /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" } */
+  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
+  #pragma omp allocate(i3) align ( -32 )  /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" } */
+  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
 }
diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-9.c b/gcc/testsuite/c-c++-common/gomp/allocate-9.c
new file mode 100644
index 00000000000..e782b48bdf4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/allocate-9.c
@@ -0,0 +1,94 @@
+typedef enum omp_allocator_handle_t
+{
+  omp_null_allocator = 0,
+  omp_default_mem_alloc = 1,
+  omp_large_cap_mem_alloc = 2,
+  omp_const_mem_alloc = 3,
+  omp_high_bw_mem_alloc = 4,
+  omp_low_lat_mem_alloc = 5,
+  omp_cgroup_mem_alloc = 6,
+  omp_pteam_mem_alloc = 7,
+  omp_thread_mem_alloc = 8,
+  __ompx_last_mem_alloc = omp_thread_mem_alloc,
+  __omp_allocator_handle_t_max__ = __UINTPTR_MAX__
+} omp_allocator_handle_t;
+
+
+static int A[5] = {1,2,3,4,5};
+int B, C, D;
+
+/* If the following fails bacause of added predefined allocators, please update
+   - c/c-parser.c's c_parser_omp_allocate
+   - fortran/openmp.cc's is_predefined_allocator
+   - libgomp/env.c's parse_allocator
+   - libgomp/libgomp.texi (document the new values - multiple locations)
+   + ensure that the memory-spaces are also up to date. */
+
+#pragma omp allocate(A) align(32) allocator((omp_allocator_handle_t) 9) /* { dg-error "'allocator' clause requires a predefined allocator as 'A' is static" "" { xfail c++ } } */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
+
+
+// typo in allocator name:
+#pragma omp allocate(A) allocator(omp_low_latency_mem_alloc)
+/* { dg-error "'omp_low_latency_mem_alloc' undeclared here \\(not in a function\\); did you mean 'omp_low_lat_mem_alloc'\\?" "" { target c } .-1 } */
+/* { dg-error "'omp_low_latency_mem_alloc' was not declared in this scope; did you mean 'omp_low_lat_mem_alloc'\\?" "" { target c++ } .-2 } */
+/* { dg-error "'allocator' clause required for static variable 'A'" "" { target c } .-3 } */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-4 } */
+
+/* align be const multiple of 2 */
+#pragma omp allocate(A) align(31) allocator(omp_default_mem_alloc) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" } */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' for static variables like 'A' not yet supported" "" { target c } .-1 } */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-2 } */
+
+/* allocator missing (required as A is static) */
+#pragma omp allocate(A) align(32) /* { dg-error "'allocator' clause required for static variable 'A'" "" { xfail c++ } } */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
+
+/* "expression in the clause must be a constant expression that evaluates to one of the
+   predefined memory allocator values -> omp_low_lat_mem_alloc"  */
+#pragma omp allocate(B) allocator((omp_allocator_handle_t) (omp_high_bw_mem_alloc+1)) align(32) /* OK: omp_low_lat_mem_alloc */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' for static variables like 'B' not yet supported" "" { target c } .-1 } */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-2 } */
+
+#pragma omp allocate(C) allocator((omp_allocator_handle_t) 2) /* OK: omp_large_cap_mem_alloc */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' for static variables like 'C' not yet supported" "" { target c } .-1 } */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-2 } */
+
+#pragma omp allocate(A) align(32) allocator(omp_null_allocator) /* { dg-error "'allocator' clause requires a predefined allocator as 'A' is static" "" { xfail c++ } } */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
+
+#pragma omp allocate(C) align(32) allocator(omp_large_cap_mem_alloc)  /* { dg-error "'C' already appeared as list item in an 'allocate' directive" "" { xfail *-*-* } } */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' for static variables like 'C' not yet supported" "" { target c } .-1 } */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-2 } */
+
+// allocate directive in same TU
+int f()
+{
+  #pragma omp allocate(D) align(32) allocator(omp_large_cap_mem_alloc) /* { dg-error "'allocate' directive must be in the same scope as 'D'" "" { xfail c++ } } */
+/* { dg-note "declared here" "" { target c } 18 } */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-2 } */
+  return A[0];
+}
+
+int g()
+{
+  int a2=1, b2=2;
+  #pragma omp allocate(a2)
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
+  #pragma omp allocate(a2)  /* { dg-error "'a2' already appeared as list item in an 'allocate' directive" "" { xfail c++ } } */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
+  {
+    int c2=3;
+    #pragma omp allocate(c2, b2) /* { dg-error "'allocate' directive must be in the same scope as 'b2'" "" { xfail c++ } } */
+/* { dg-note "declared here" "" { target c } .-8 } */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-2 } */
+    return c2+a2+b2;
+  }
+}
+
+int h(int q)
+{
+  #pragma omp allocate(q)  /* { dg-error "function parameter 'q' may not appear as list item in an 'allocate' directive" "" { xfail c++ } } */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
+  return q;
+}
diff --git a/gcc/testsuite/c-c++-common/gomp/directive-1.c b/gcc/testsuite/c-c++-common/gomp/directive-1.c
index fc441538778..21ca319b9f9 100644
--- a/gcc/testsuite/c-c++-common/gomp/directive-1.c
+++ b/gcc/testsuite/c-c++-common/gomp/directive-1.c
@@ -19,7 +19,7 @@ foo (void)
   int i, k = 0, l = 0;
   #pragma omp allocate, (i)			/* { dg-error "expected '\\\(' before ',' token" } */
 						/* { dg-error "expected end of line before ',' token" "" { target c++ } .-1 } */
-						/* { dg-message "not yet supported" "" { target *-*-* } .-2 } */
+						/* { dg-message "not yet supported" "" { target c++ } .-2 } */
   #pragma omp critical, (bar)			/* { dg-error "expected an OpenMP clause before '\\\(' token" } */
   ;
   #pragma omp flush, (k, l)			/* { dg-error "expected '\\\(' or end of line before ',' token" "" { target c } } */
diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi
index 4aad8cc52f4..6dab873337e 100644
--- a/libgomp/libgomp.texi
+++ b/libgomp/libgomp.texi
@@ -225,7 +225,7 @@ The OpenMP 4.5 specification is fully supported.
 @item Predefined memory spaces, memory allocators, allocator traits
       @tab Y @tab See also @ref{Memory allocation}
 @item Memory management routines @tab Y @tab
-@item @code{allocate} directive @tab N @tab
+@item @code{allocate} directive @tab P @tab Only C, only stack variables
 @item @code{allocate} clause @tab P @tab Initial support
 @item @code{use_device_addr} clause on @code{target data} @tab Y @tab
 @item @code{ancestor} modifier on @code{device} clause @tab Y @tab
@@ -296,7 +296,8 @@ The OpenMP 4.5 specification is fully supported.
 @item Loop transformation constructs @tab N @tab
 @item @code{strict} modifier in the @code{grainsize} and @code{num_tasks}
       clauses of the @code{taskloop} construct @tab Y @tab
-@item @code{align} clause in @code{allocate} directive @tab N @tab
+@item @code{align} clause in @code{allocate} directive @tab P
+      @tab Only C (and only stack variables)
 @item @code{align} modifier in @code{allocate} clause @tab Y @tab
 @item @code{thread_limit} clause to @code{target} construct @tab Y @tab
 @item @code{has_device_addr} clause to @code{target} construct @tab Y @tab
@@ -2204,7 +2205,7 @@ variable is not set.
 @section @env{OMP_ALLOCATOR} -- Set the default allocator
 @cindex Environment Variable
 @table @asis
-@item @emph{ICV:} @var{available-devices-var}
+@item @emph{ICV:} @var{def-allocator-var}
 @item @emph{Scope:} data environment
 @item @emph{Description}:
 Sets the default allocator that is used when no allocator has been specified
diff --git a/libgomp/testsuite/libgomp.c-c++-common/allocate-4.c b/libgomp/testsuite/libgomp.c-c++-common/allocate-4.c
new file mode 100644
index 00000000000..ebfdc78a56b
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/allocate-4.c
@@ -0,0 +1,75 @@
+/* TODO: enable for C++ once implemented. */
+/* { dg-do run { target c } } */
+/* { dg-additional-options "-fdump-tree-gimple" } */
+
+#include <omp.h>
+#include <stdint.h>
+
+/* { dg-final { scan-tree-dump-times "__builtin_GOMP_free \\(D.\[0-9\]+, 0B\\);" 5 "gimple" } } */
+
+int one ()
+{
+  int sum = 0;
+  #pragma omp allocate(sum)
+  /* { dg-final { scan-tree-dump-times "D.\[0-9\]+ = __builtin_GOMP_alloc \\(0, 4, 0B\\);" 1 "gimple" } } */
+
+  /* NOTE: Initializer cannot be omp_init_allocator - as 'A' is
+     in the same scope and the auto-omp_free comes later than
+     any omp_destroy_allocator.  */
+  omp_allocator_handle_t my_allocator = omp_low_lat_mem_alloc;
+  int n = 25;
+  int A[n];
+  #pragma omp allocate(A) align(128) allocator(my_allocator)
+  /* { dg-final { scan-tree-dump-times "D.\[0-9\]+ = __builtin_GOMP_alloc \\(128, _\[0-9\]+, my_allocator\\);" 1 "gimple" } } */
+
+  if (((intptr_t)A) % 128 != 0)
+    __builtin_abort ();
+  for (int i = 0; i < n; ++i)
+    A[i] = i;
+
+  omp_alloctrait_t traits[1] = { { omp_atk_alignment, 64 } };
+  my_allocator = omp_init_allocator(omp_low_lat_mem_space,1,traits);
+  {
+    int B[n] = { };
+    int C[5] = {1,2,3,4,5};
+    #pragma omp allocate(B,C) allocator(my_allocator)
+    /* { dg-final { scan-tree-dump-times "D.\[0-9\]+ = __builtin_GOMP_alloc \\(0, _\[0-9\]+, my_allocator\\);" 1 "gimple" } } */
+    /* { dg-final { scan-tree-dump-times "D.\[0-9\]+ = __builtin_GOMP_alloc \\(0, 20, my_allocator\\);" 1 "gimple" } } */
+
+    int D[5] = {11,22,33,44,55};
+    #pragma omp allocate(D) align(256)
+    /* { dg-final { scan-tree-dump-times "D.\[0-9\]+ = __builtin_GOMP_alloc \\(256, 20, 0B\\);" 1 "gimple" } } */
+
+    if (((intptr_t) B) % 64 != 0)
+      __builtin_abort ();
+    if (((intptr_t) C) % 64 != 0)
+      __builtin_abort ();
+    if (((intptr_t) D) % 64 != 0)
+      __builtin_abort ();
+
+    for (int i = 0; i < 5; ++i)
+      {
+	if (C[i] != i+1)
+	  __builtin_abort ();
+	if (D[i] != i+1 + 10*(i+1))
+	  __builtin_abort ();
+      }
+
+    for (int i = 0; i < n; ++i)
+      {
+	if (B[i] != 0)
+	  __builtin_abort ();
+	sum += A[i]+B[i]+C[i%5]+D[i%5];
+      }
+  }
+  omp_destroy_allocator (my_allocator);
+  return sum;
+}
+
+int
+main ()
+{
+  if (one () != 1200)
+    __builtin_abort ();
+  return 0;
+}

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2023-09-12  8:55 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-29 16:12 [Patch] OpenMP (C only): omp allocate - handle stack vars, improve diagnostic Tobias Burnus
2023-08-29 16:28 ` Jakub Jelinek
2023-08-29 16:56   ` Tobias Burnus
2023-08-29 17:14     ` Jakub Jelinek
2023-08-30 10:47       ` Tobias Burnus
2023-08-30 11:13         ` Jakub Jelinek
2023-08-30 12:43         ` Tobias Burnus
2023-09-11 11:44           ` [Patch] OpenMP (C only): omp allocate - extend parsing support, improve diagnostic (was: [Patch] OpenMP (C only): omp allocate - handle stack vars, improve diagnostic) Tobias Burnus
2023-09-11 11:54             ` Jakub Jelinek
2023-09-11 13:07               ` David Malcolm
2023-09-11 13:21               ` Tobias Burnus
2023-09-11 13:34                 ` Jakub Jelinek
2023-09-12  7:04                   ` [Patch] OpenMP (C only): omp allocate - extend parsing support, improve diagnostic Tobias Burnus
2023-09-12  7:15                     ` Jakub Jelinek
2023-09-12  8:55                     ` Tobias Burnus

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).