diff mbox series

OpenMP: Handle 'all' as category in defaultmap

Message ID 8b546fa4-2925-3d35-21f5-bca3ad567e71@codesourcery.com
State New
Headers show
Series OpenMP: Handle 'all' as category in defaultmap | expand

Commit Message

Tobias Burnus Aug. 22, 2023, 9:54 a.m. UTC
I stumbled over this when compiling the defaultmap files of the OpenMP example document
(upcoming version). Seemingly, an 'all' was sneaked in when the syntax representation was
changed (as alias for not specifying a category). I wonder which intended or nonintended
changes are still hiding and, hence, still need to be implemented and/or fixed in the spec.

Comments, suggestions, remarks to the attached patch?

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
diff mbox series

Patch

OpenMP: Handle 'all' as category in defaultmap

Both, specifying no category and specifying 'all', implies
that the implicit-behavior applies to all categories.

gcc/c/ChangeLog:

	* c-parser.cc (c_parser_omp_clause_defaultmap): Parse
	'all' as category.

gcc/cp/ChangeLog:

	* parser.cc (cp_parser_omp_clause_defaultmap): Parse
	'all' as category.

gcc/fortran/ChangeLog:

	* gfortran.h (enum gfc_omp_defaultmap_category):
	Add OMP_DEFAULTMAP_CAT_ALL.
	* openmp.cc (gfc_match_omp_clauses): Parse
	'all' as category.
	* trans-openmp.cc (gfc_trans_omp_clauses): Handle it.

gcc/ChangeLog:

	* tree-core.h (enum omp_clause_defaultmap_kind): Add
	OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL.
	* gimplify.cc (gimplify_scan_omp_clauses): Handle it.
	* tree-pretty-print.cc (dump_omp_clause): Likewise.

libgomp/ChangeLog:

	* libgomp.texi (OpenMP 5.2 status): Add depobj with
	destroy-var argument as 'N'. Mark defaultmap with
	'all' category as 'Y'.

gcc/testsuite/ChangeLog:

	* gfortran.dg/gomp/defaultmap-1.f90: Update dg-error.
	* c-c++-common/gomp/defaultmap-5.c: New test.
	* c-c++-common/gomp/defaultmap-6.c: New test.
	* gfortran.dg/gomp/defaultmap-10.f90: New test.
	* gfortran.dg/gomp/defaultmap-9.f90: New test.

 gcc/c/c-parser.cc                                |  19 +++-
 gcc/cp/parser.cc                                 |  19 +++-
 gcc/fortran/gfortran.h                           |   1 +
 gcc/fortran/openmp.cc                            |  12 ++-
 gcc/fortran/trans-openmp.cc                      |   3 +
 gcc/gimplify.cc                                  |   1 +
 gcc/testsuite/c-c++-common/gomp/defaultmap-5.c   |  47 +++++++++
 gcc/testsuite/c-c++-common/gomp/defaultmap-6.c   |  48 ++++++++++
 gcc/testsuite/gfortran.dg/gomp/defaultmap-1.f90  |   2 +-
 gcc/testsuite/gfortran.dg/gomp/defaultmap-10.f90 | 116 +++++++++++++++++++++++
 gcc/testsuite/gfortran.dg/gomp/defaultmap-9.f90  |  71 ++++++++++++++
 gcc/tree-core.h                                  |   1 +
 gcc/tree-pretty-print.cc                         |   3 +
 libgomp/libgomp.texi                             |   4 +-
 14 files changed, 334 insertions(+), 13 deletions(-)

diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 33fe7b115ff..4a4820d792c 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -15067,8 +15067,8 @@  c_parser_omp_clause_defaultmap (c_parser *parser, tree list)
       if (!c_parser_next_token_is (parser, CPP_NAME))
 	{
 	invalid_category:
-	  c_parser_error (parser, "expected %<scalar%>, %<aggregate%> or "
-				  "%<pointer%>");
+	  c_parser_error (parser, "expected %<scalar%>, %<aggregate%>, "
+				  "%<pointer%> or %<all%>");
 	  goto out_err;
 	}
       p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
@@ -15077,6 +15077,8 @@  c_parser_omp_clause_defaultmap (c_parser *parser, tree list)
 	case 'a':
 	  if (strcmp ("aggregate", p) == 0)
 	    category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE;
+	  else if (strcmp ("all", p) == 0)
+	    category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL;
 	  else
 	    goto invalid_category;
 	  break;
@@ -15106,13 +15108,19 @@  c_parser_omp_clause_defaultmap (c_parser *parser, tree list)
   for (c = list; c ; c = OMP_CLAUSE_CHAIN (c))
     if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEFAULTMAP
 	&& (category == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED
+	    || category == OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL
 	    || OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) == category
 	    || (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c)
-		== OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED)))
+		== OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED)
+	    || (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c)
+		== OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL)))
       {
 	enum omp_clause_defaultmap_kind cat = category;
 	location_t loc = OMP_CLAUSE_LOCATION (c);
-	if (cat == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED)
+	if (cat == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED
+	    || (cat == OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL
+		&& (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c)
+		    != OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED)))
 	  cat = OMP_CLAUSE_DEFAULTMAP_CATEGORY (c);
 	p = NULL;
 	switch (cat)
@@ -15120,6 +15128,9 @@  c_parser_omp_clause_defaultmap (c_parser *parser, tree list)
 	  case OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED:
 	    p = NULL;
 	    break;
+	  case OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL:
+	    p = "all";
+	    break;
 	  case OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE:
 	    p = "aggregate";
 	    break;
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 774706ac607..eeb22e44fb4 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -38810,8 +38810,8 @@  cp_parser_omp_clause_defaultmap (cp_parser *parser, tree list,
       if (!cp_lexer_next_token_is (parser->lexer, CPP_NAME))
 	{
 	invalid_category:
-	  cp_parser_error (parser, "expected %<scalar%>, %<aggregate%> or "
-				   "%<pointer%>");
+	  cp_parser_error (parser, "expected %<scalar%>, %<aggregate%>, "
+				   "%<all%>");
 	  goto out_err;
 	}
       id = cp_lexer_peek_token (parser->lexer)->u.value;
@@ -38822,6 +38822,8 @@  cp_parser_omp_clause_defaultmap (cp_parser *parser, tree list,
 	case 'a':
 	  if (strcmp ("aggregate", p) == 0)
 	    category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE;
+	  else if (strcmp ("all", p) == 0)
+	    category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL;
 	  else
 	    goto invalid_category;
 	  break;
@@ -38852,13 +38854,19 @@  cp_parser_omp_clause_defaultmap (cp_parser *parser, tree list,
   for (c = list; c ; c = OMP_CLAUSE_CHAIN (c))
     if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEFAULTMAP
 	&& (category == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED
+	    || category == OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL
 	    || OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) == category
 	    || (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c)
-		== OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED)))
+		== OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED)
+	    || (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c)
+		== OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL)))
       {
 	enum omp_clause_defaultmap_kind cat = category;
 	location_t loc = OMP_CLAUSE_LOCATION (c);
-	if (cat == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED)
+	if (cat == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED
+	    || (cat == OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL
+		&& (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c)
+		    != OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED)))
 	  cat = OMP_CLAUSE_DEFAULTMAP_CATEGORY (c);
 	p = NULL;
 	switch (cat)
@@ -38866,6 +38874,9 @@  cp_parser_omp_clause_defaultmap (cp_parser *parser, tree list,
 	  case OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED:
 	    p = NULL;
 	    break;
+	  case OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL:
+	    p = "all";
+	    break;
 	  case OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE:
 	    p = "aggregate";
 	    break;
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index fd47000a88e..cce9688ee6a 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -1334,6 +1334,7 @@  enum gfc_omp_defaultmap
 enum gfc_omp_defaultmap_category
 {
   OMP_DEFAULTMAP_CAT_UNCATEGORIZED,
+  OMP_DEFAULTMAP_CAT_ALL,
   OMP_DEFAULTMAP_CAT_SCALAR,
   OMP_DEFAULTMAP_CAT_AGGREGATE,
   OMP_DEFAULTMAP_CAT_ALLOCATABLE,
diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc
index bee3015e484..2ffbf6f5ef9 100644
--- a/gcc/fortran/openmp.cc
+++ b/gcc/fortran/openmp.cc
@@ -2250,17 +2250,22 @@  gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 		    category = OMP_DEFAULTMAP_CAT_ALLOCATABLE;
 		  else if (gfc_match ("pointer ") == MATCH_YES)
 		    category = OMP_DEFAULTMAP_CAT_POINTER;
+		  else if (gfc_match ("all ") == MATCH_YES)
+		    category = OMP_DEFAULTMAP_CAT_ALL;
 		  else
 		    {
-		      gfc_error ("Expected SCALAR, AGGREGATE, ALLOCATABLE or "
-				 "POINTER at %C");
+		      gfc_error ("Expected SCALAR, AGGREGATE, ALLOCATABLE, "
+				 "POINTER or ALL at %C");
 		      break;
 		    }
 		}
 	      for (int i = 0; i < OMP_DEFAULTMAP_CAT_NUM; ++i)
 		{
 		  if (i != category
-		      && category != OMP_DEFAULTMAP_CAT_UNCATEGORIZED)
+		      && category != OMP_DEFAULTMAP_CAT_UNCATEGORIZED
+		      && category != OMP_DEFAULTMAP_CAT_ALL
+		      && i != OMP_DEFAULTMAP_CAT_UNCATEGORIZED
+		      && i != OMP_DEFAULTMAP_CAT_ALL)
 		    continue;
 		  if (c->defaultmap[i] != OMP_DEFAULTMAP_UNSET)
 		    {
@@ -2268,6 +2273,7 @@  gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 		      switch (i)
 			{
 			case OMP_DEFAULTMAP_CAT_UNCATEGORIZED: break;
+			case OMP_DEFAULTMAP_CAT_ALL: pcategory = "ALL"; break;
 			case OMP_DEFAULTMAP_CAT_SCALAR: pcategory = "SCALAR"; break;
 			case OMP_DEFAULTMAP_CAT_AGGREGATE:
 			  pcategory = "AGGREGATE";
diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
index cf741cebf91..2f116fd6738 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -4443,6 +4443,9 @@  gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 	case OMP_DEFAULTMAP_CAT_UNCATEGORIZED:
 	  category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED;
 	  break;
+	case OMP_DEFAULTMAP_CAT_ALL:
+	  category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL;
+	  break;
 	case OMP_DEFAULTMAP_CAT_SCALAR:
 	  category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR;
 	  break;
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index 7549436944c..9a9919e2f2f 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -12037,6 +12037,7 @@  gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
 	  switch (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c))
 	    {
 	    case OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED:
+	    case OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL:
 	      gdmkmin = GDMK_SCALAR;
 	      gdmkmax = GDMK_POINTER;
 	      break;
diff --git a/gcc/testsuite/c-c++-common/gomp/defaultmap-5.c b/gcc/testsuite/c-c++-common/gomp/defaultmap-5.c
new file mode 100644
index 00000000000..cc1a77fadb3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/defaultmap-5.c
@@ -0,0 +1,47 @@ 
+/* { dg-additional-options "-fdump-tree-original -fdump-tree-gimple" } */
+
+void f()
+{
+  struct s {
+    int i;
+  };
+  int scalar1 = 5;
+  int array1[5] = {1,2,3,4,5};
+  int *ptr1 = &scalar1;
+  struct s mystruct1 = {.i = 5};
+
+  /* firstprivate + unspecified modifer. */
+  #pragma omp target defaultmap(firstprivate)
+   {
+     scalar1 = 1;
+     array1[0] = 2;
+     if (ptr1 == 0L)
+       mystruct1.i = 3;
+   }
+
+  /* equivalent: firstprivate + ALL modifer. */
+  #pragma omp target defaultmap(firstprivate : all)
+   {
+     scalar1 = 1;
+     array1[0] = 2;
+     if (ptr1 == 0L)
+       mystruct1.i = 3;
+   }
+
+  /* tofrom + ALL modifer. */
+  #pragma omp target defaultmap(tofrom : all)
+   {
+     scalar1 = 1;
+     array1[0] = 2;
+     if (ptr1 == 0L)
+       mystruct1.i = 3;
+   }
+}
+
+/* { dg-final { scan-tree-dump-times "#pragma omp target defaultmap\\(firstprivate\\)" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "#pragma omp target defaultmap\\(firstprivate:all\\)" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "#pragma omp target defaultmap\\(tofrom:all\\)" 1 "original" } } */
+
+/* { dg-final { scan-tree-dump-times "#pragma omp target.* defaultmap\\(firstprivate\\) firstprivate\\(mystruct1\\) firstprivate\\(ptr1\\) firstprivate\\(array1\\) firstprivate\\(scalar1\\)" 1 "gimple" } } */
+/* { dg-final { scan-tree-dump-times "#pragma omp target.* defaultmap\\(firstprivate:all\\) firstprivate\\(mystruct1\\) firstprivate\\(ptr1\\) firstprivate\\(array1\\) firstprivate\\(scalar1\\)" 1 "gimple" } } */
+/* { dg-final { scan-tree-dump-times "#pragma omp target.* defaultmap\\(tofrom:all\\) map\\(tofrom:mystruct1 \\\[len: .\\\]\\\[implicit\\\]\\) map\\(tofrom:ptr1 \\\[len: .\\\]\\\[implicit\\\]\\) map\\(tofrom:array1 \\\[len: ..\\\]\\\[implicit\\\]\\) map\\(tofrom:scalar1 \\\[len: .\\\]\\\[implicit\\\]\\)" 1 "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/gomp/defaultmap-6.c b/gcc/testsuite/c-c++-common/gomp/defaultmap-6.c
new file mode 100644
index 00000000000..45fce8b66e9
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/defaultmap-6.c
@@ -0,0 +1,48 @@ 
+void f()
+{
+  struct s {
+    int i;
+  };
+  int scalar1 = 5;
+  int array1[5] = {1,2,3,4,5};
+  int *ptr1 = &scalar1;
+  struct s mystruct1 = {.i = 5};
+
+  #pragma omp target defaultmap(firstprivate ) defaultmap(firstprivate : aggregate)  /* { dg-error "too many 'defaultmap' clauses with 'aggregate' category" }  */
+   {
+     scalar1 = 1; array1[0] = 2; if (ptr1 == 0L) mystruct1.i = 3;
+   }
+
+  #pragma omp target defaultmap(firstprivate : all ) defaultmap(alloc : pointer) /* { dg-error "too many 'defaultmap' clauses with 'pointer' category" }  */
+   {
+     scalar1 = 1; array1[0] = 2; if (ptr1 == 0L) mystruct1.i = 3;
+   }
+
+
+  #pragma omp target defaultmap(firstprivate : aggregate)  defaultmap(firstprivate ) /* { dg-error "too many 'defaultmap' clauses with 'aggregate' category" }  */
+   {
+     scalar1 = 1; array1[0] = 2; if (ptr1 == 0L) mystruct1.i = 3;
+   }
+
+  #pragma omp target defaultmap(alloc : pointer) defaultmap(firstprivate : all )  /* { dg-error "too many 'defaultmap' clauses with 'pointer' category" }  */
+   {
+     scalar1 = 1; array1[0] = 2; if (ptr1 == 0L) mystruct1.i = 3;
+   }
+
+  #pragma omp target defaultmap(firstprivate :all ) defaultmap(firstprivate : all) /* { dg-error "too many 'defaultmap' clauses with 'all' category" }  */
+   {
+     scalar1 = 1; array1[0] = 2; if (ptr1 == 0L) mystruct1.i = 3;
+   }
+  #pragma omp target defaultmap(firstprivate ) defaultmap(firstprivate) /* { dg-error "too many 'defaultmap' clauses with unspecified category" }  */
+   {
+     scalar1 = 1; array1[0] = 2; if (ptr1 == 0L) mystruct1.i = 3;
+   }
+  #pragma omp target defaultmap(firstprivate ) defaultmap(firstprivate : all) /* { dg-error "too many 'defaultmap' clauses with 'all' category" }  */
+   {
+     scalar1 = 1; array1[0] = 2; if (ptr1 == 0L) mystruct1.i = 3;
+   }
+  #pragma omp target defaultmap(firstprivate : all) defaultmap(firstprivate) /* { dg-error "too many 'defaultmap' clauses with 'all' category" }  */
+   {
+     scalar1 = 1; array1[0] = 2; if (ptr1 == 0L) mystruct1.i = 3;
+   }
+}
diff --git a/gcc/testsuite/gfortran.dg/gomp/defaultmap-1.f90 b/gcc/testsuite/gfortran.dg/gomp/defaultmap-1.f90
index 1f1b8528aef..5123e078e98 100644
--- a/gcc/testsuite/gfortran.dg/gomp/defaultmap-1.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/defaultmap-1.f90
@@ -4,7 +4,7 @@  implicit none
 
 !$omp target defaultmap(bar)  ! { dg-error "25: Expected ALLOC, TO, FROM, TOFROM, FIRSTPRIVATE, PRESENT, NONE or DEFAULT" }
 
-!$omp target defaultmap ( alloc: foo)  ! { dg-error "34: Expected SCALAR, AGGREGATE, ALLOCATABLE or POINTER" }
+!$omp target defaultmap ( alloc: foo)  ! { dg-error "34: Expected SCALAR, AGGREGATE, ALLOCATABLE, POINTER or ALL" }
 
 !$omp target defaultmap(alloc:scalar) defaultmap(none:Scalar)  ! { dg-error "DEFAULTMAP at .1. but prior DEFAULTMAP for category SCALAR" }
 
diff --git a/gcc/testsuite/gfortran.dg/gomp/defaultmap-10.f90 b/gcc/testsuite/gfortran.dg/gomp/defaultmap-10.f90
new file mode 100644
index 00000000000..7e230d886f0
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/defaultmap-10.f90
@@ -0,0 +1,116 @@ 
+subroutine f
+  implicit none
+  type t
+    integer :: i
+  end type t
+  integer, target :: scalar
+  integer, target :: array(5)
+  integer, pointer :: ptr1, ptr2(:)
+  integer, allocatable :: alloc1, alloc2(:)
+  type(t) :: agg1, agg2(2)
+
+  scalar = 1
+  array = [1,2,3,4,5]
+  ptr1 => scalar
+  ptr2 => array
+  alloc1 = 5
+  alloc2 = [1,2]
+  agg1%i = 1
+  agg2(:)%i = [1,2]
+
+  !$omp target defaultmap(firstprivate ) defaultmap(firstprivate : aggregate)  ! { dg-error "DEFAULTMAP at .1. but prior DEFAULTMAP with unspecified category" }
+  block
+   scalar = 1;
+   array(1) = 2;
+   if (associated(ptr1)) &
+     agg1%i = 3;
+   if (associated(ptr2)) &
+     agg2(1)%i = 3;
+   if (allocated(alloc1)) &
+     alloc2(1) = 0
+  end block
+
+  !$omp target defaultmap(firstprivate : all ) defaultmap(alloc : pointer)  ! { dg-error "DEFAULTMAP at .1. but prior DEFAULTMAP for category ALL" }
+  block
+   scalar = 1;
+   array(1) = 2;
+   if (associated(ptr1)) &
+     agg1%i = 3;
+   if (associated(ptr2)) &
+     agg2(1)%i = 3;
+   if (allocated(alloc1)) &
+     alloc2(1) = 0
+  end block
+
+  !$omp target defaultmap(firstprivate : aggregate)  defaultmap(firstprivate )  ! { dg-error "DEFAULTMAP at .1. but prior DEFAULTMAP for category AGGREGATE" }
+  block
+   scalar = 1;
+   array(1) = 2;
+   if (associated(ptr1)) &
+     agg1%i = 3;
+   if (associated(ptr2)) &
+     agg2(1)%i = 3;
+   if (allocated(alloc1)) &
+     alloc2(1) = 0
+  end block
+
+  !$omp target defaultmap(alloc : pointer) defaultmap(firstprivate : all )   ! { dg-error "DEFAULTMAP at .1. but prior DEFAULTMAP for category POINTER" }
+  block
+   scalar = 1;
+   array(1) = 2;
+   if (associated(ptr1)) &
+     agg1%i = 3;
+   if (associated(ptr2)) &
+     agg2(1)%i = 3;
+   if (allocated(alloc1)) &
+     alloc2(1) = 0
+  end block
+
+  !$omp target defaultmap(firstprivate :all ) defaultmap(firstprivate : all)  ! { dg-error "DEFAULTMAP at .1. but prior DEFAULTMAP for category ALL" }
+  block
+   scalar = 1;
+   array(1) = 2;
+   if (associated(ptr1)) &
+     agg1%i = 3;
+   if (associated(ptr2)) &
+     agg2(1)%i = 3;
+   if (allocated(alloc1)) &
+     alloc2(1) = 0
+  end block
+
+  !$omp target defaultmap(firstprivate ) defaultmap(firstprivate)  ! { dg-error "DEFAULTMAP at .1. but prior DEFAULTMAP with unspecified category" }
+  block
+   scalar = 1;
+   array(1) = 2;
+   if (associated(ptr1)) &
+     agg1%i = 3;
+   if (associated(ptr2)) &
+     agg2(1)%i = 3;
+   if (allocated(alloc1)) &
+     alloc2(1) = 0
+  end block
+
+  !$omp target defaultmap(firstprivate ) defaultmap(firstprivate : all)  ! { dg-error "DEFAULTMAP at .1. but prior DEFAULTMAP with unspecified category" }
+  block
+   scalar = 1;
+   array(1) = 2;
+   if (associated(ptr1)) &
+     agg1%i = 3;
+   if (associated(ptr2)) &
+     agg2(1)%i = 3;
+   if (allocated(alloc1)) &
+     alloc2(1) = 0
+  end block
+
+  !$omp target defaultmap(firstprivate : all) defaultmap(firstprivate)  ! { dg-error "DEFAULTMAP at .1. but prior DEFAULTMAP for category ALL" }
+  block
+   scalar = 1;
+   array(1) = 2;
+   if (associated(ptr1)) &
+     agg1%i = 3;
+   if (associated(ptr2)) &
+     agg2(1)%i = 3;
+   if (allocated(alloc1)) &
+     alloc2(1) = 0
+  end block
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/defaultmap-9.f90 b/gcc/testsuite/gfortran.dg/gomp/defaultmap-9.f90
new file mode 100644
index 00000000000..b24fc95fc74
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/defaultmap-9.f90
@@ -0,0 +1,71 @@ 
+! { dg-additional-options "-fdump-tree-original -fdump-tree-gimple" }
+
+subroutine f
+  implicit none
+  type t
+    integer :: i
+  end type t
+  integer, target :: scalar
+  integer, target :: array(5)
+  integer, pointer :: ptr1, ptr2(:)
+  integer, allocatable :: alloc1, alloc2(:)
+  type(t) :: agg1, agg2(2)
+
+  scalar = 1
+  array = [1,2,3,4,5]
+  ptr1 => scalar
+  ptr2 => array
+  alloc1 = 5
+  alloc2 = [1,2]
+  agg1%i = 1
+  agg2(:)%i = [1,2]
+
+  ! firstprivate + unspecified modifer.
+  !$omp target defaultmap(firstprivate)
+  block
+   scalar = 1;
+   array(1) = 2;
+   if (associated(ptr1)) &
+     agg1%i = 3;
+   if (associated(ptr2)) &
+     agg2(1)%i = 3;
+   if (allocated(alloc1)) &
+     alloc2(1) = 0
+  end block
+
+  ! equivalent: firstprivate + ALL modifer.
+  !$omp target defaultmap(firstprivate : all)
+  block
+   scalar = 1;
+   array(1) = 2;
+   if (associated(ptr1)) &
+     agg1%i = 3;
+   if (associated(ptr2)) &
+     agg2(1)%i = 3;
+   if (allocated(alloc1)) &
+     alloc2(1) = 0
+  end block
+
+  ! tofrom + ALL modifer.
+  !$omp target defaultmap(tofrom : all)
+  block
+   scalar = 1;
+   array(1) = 2;
+   if (associated(ptr1)) &
+     agg1%i = 3;
+   if (associated(ptr2)) &
+     agg2(1)%i = 3;
+   if (allocated(alloc1)) &
+     alloc2(1) = 0
+  end block
+end subroutine
+
+! { dg-final { scan-tree-dump-times "#pragma omp target defaultmap\\(firstprivate\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target defaultmap\\(firstprivate:all\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target defaultmap\\(tofrom:all\\)" 1 "original" } }
+
+! { dg-final { scan-tree-dump-times "#pragma omp target.* defaultmap\\(firstprivate\\) firstprivate\\(scalar\\) firstprivate\\(ptr2\\) firstprivate\\(ptr1\\) firstprivate\\(array\\) firstprivate\\(alloc2\\) firstprivate\\(alloc1\\) firstprivate\\(agg2\\) firstprivate\\(agg1\\)" 1 "gimple" } }
+
+! { dg-final { scan-tree-dump-times "#pragma omp target.* defaultmap\\(firstprivate:all\\) firstprivate\\(scalar\\) firstprivate\\(ptr2\\) firstprivate\\(ptr1\\) firstprivate\\(array\\) firstprivate\\(alloc2\\) firstprivate\\(alloc1\\) firstprivate\\(agg2\\) firstprivate\\(agg1\\)" 1 "gimple" } }
+
+! { dg-final { scan-tree-dump-times "#pragma omp target.* defaultmap\\(tofrom:all\\) map\\(tofrom:scalar \\\[len: .\\\]\\\[implicit\\\]\\) map\\(tofrom:.*ptr2.data \\\[len: .*\\\]\\\[implicit\\\]\\) map\\(to:ptr2 \\\[pointer set, len: ..\\\]\\) map\\(always_pointer:.*ptr2.data \\\[pointer assign, bias: 0\\\]\\) map\\(tofrom:\\*ptr1 \\\[len: .\\\]\\\[implicit\\\]\\) map\\(alloc:ptr1 \\\[pointer assign, bias: 0\\\]\\) map\\(tofrom:array \\\[len: ..\\\]\\\[implicit\\\]\\) map\\(tofrom:.*alloc2.data \\\[len: .*\\\]\\\[implicit\\\]\\) map\\(to:alloc2 \\\[pointer set, len: ..\\\]\\) map\\(alloc:.*alloc2.data \\\[pointer assign, bias: 0\\\]\\) map\\(tofrom:\\*alloc1 \\\[len: .\\\]\\\[implicit\\\]\\) map\\(alloc:alloc1 \\\[pointer assign, bias: 0\\\]\\) map\\(tofrom:agg2 \\\[len: .\\\]\\\[implicit\\\]\\) map\\(tofrom:agg1 \\\[len: .\\\]\\\[implicit\\\]\\)" 1 "gimple" } }
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 668808a29d0..91551fde900 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -558,6 +558,7 @@  enum omp_clause_default_kind {
 
 enum omp_clause_defaultmap_kind {
   OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED,
+  OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL,
   OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR,
   OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE,
   OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALLOCATABLE,
diff --git a/gcc/tree-pretty-print.cc b/gcc/tree-pretty-print.cc
index 579037b32c2..e6fbf94793f 100644
--- a/gcc/tree-pretty-print.cc
+++ b/gcc/tree-pretty-print.cc
@@ -1248,6 +1248,9 @@  dump_omp_clause (pretty_printer *pp, tree clause, int spc, dump_flags_t flags)
 	{
 	case OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED:
 	  break;
+	case OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL:
+	  pp_string (pp, ":all");
+	  break;
 	case OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR:
 	  pp_string (pp, ":scalar");
 	  break;
diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi
index 073c181f627..5c91163893f 100644
--- a/libgomp/libgomp.texi
+++ b/libgomp/libgomp.texi
@@ -378,6 +378,8 @@  to address of matching mapped list item per 5.1, Sect. 2.21.7.2 @tab N @tab
       sentinel is warned for with with @code{-Wsurprising} (enabled by
       @code{-Wall}).  Unknown clauses are always rejected with an error.}
 @item Clauses on @code{end} directive can be on directive @tab Y @tab
+@item @code{destroy} clause with destroy-var argument on @code{depobj}
+      @tab N @tab
 @item Deprecation of no-argument @code{destroy} clause on @code{depobj}
       @tab N @tab
 @item @code{linear} clause syntax changes and @code{step} modifier @tab Y @tab
@@ -426,7 +428,7 @@  to address of matching mapped list item per 5.1, Sect. 2.21.7.2 @tab N @tab
       @code{omp_invalid_device} enum/PARAMETER @tab Y @tab
 @item Initial value of @var{default-device-var} ICV with
       @code{OMP_TARGET_OFFLOAD=mandatory} @tab Y @tab
-@item @code{all} as @emph{implicit-behavior} for @code{defaultmap} @tab N @tab
+@item @code{all} as @emph{implicit-behavior} for @code{defaultmap} @tab Y @tab
 @item @emph{interop_types} in any position of the modifier list for the @code{init} clause
       of the @code{interop} construct @tab N @tab
 @end multitable