public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [gomp4 1/9] Add missing include.
  2013-11-06 19:44 Initial submission of OpenACC support integrated into OpenMP's lowering and expansion passes Thomas Schwinge
@ 2013-11-06 19:44 ` thomas
  2013-11-06 19:44   ` [gomp4 2/9] libgomp: Prepare for testcases without -fopenmp thomas
  2013-11-07  8:15   ` [gomp4 1/9] Add missing include Jakub Jelinek
  2013-11-07 18:14 ` Initial submission of OpenACC support integrated into OpenMP's lowering and expansion passes Evgeny Gavrin
  1 sibling, 2 replies; 44+ messages in thread
From: thomas @ 2013-11-06 19:44 UTC (permalink / raw)
  To: gcc-patches; +Cc: Thomas Schwinge

From: Thomas Schwinge <thomas@codesourcery.com>

	libgomp/
	* libgomp_g.h: Include <stddef.h> for size_t.
---
 libgomp/libgomp_g.h | 1 +
 1 file changed, 1 insertion(+)

diff --git libgomp/libgomp_g.h libgomp/libgomp_g.h
index 32c4cf6..577956a 100644
--- libgomp/libgomp_g.h
+++ libgomp/libgomp_g.h
@@ -29,6 +29,7 @@
 #define LIBGOMP_G_H 1
 
 #include <stdbool.h>
+#include <stddef.h>
 
 /* barrier.c */
 
-- 
1.8.1.1

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

* Initial submission of OpenACC support integrated into OpenMP's lowering and expansion passes
@ 2013-11-06 19:44 Thomas Schwinge
  2013-11-06 19:44 ` [gomp4 1/9] Add missing include thomas
  2013-11-07 18:14 ` Initial submission of OpenACC support integrated into OpenMP's lowering and expansion passes Evgeny Gavrin
  0 siblings, 2 replies; 44+ messages in thread
From: Thomas Schwinge @ 2013-11-06 19:44 UTC (permalink / raw)
  To: gcc-patches; +Cc: jakub, e.gavrin

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

Hi!

Here is our take of adding OpenACC support to GCC's front end and middle
end.  What I post here (that is, as replies to this email, to gcc-patches
only) is still very incomplete, but hopefully enough to outline the
general approach, and I'd like to commit these patches to gomp-4_0-branch
-- OK?  Also, may I additionally commit those patches to trunk that don't
have anything specific to OpenACC in them (such as the first two
preparation patches), which I assume will save some work when merging
between trunk and gomp-4_0-branch later on?

Due to the conceptual similarity compared to OpenMP, and that (later) it
is reasonable to expect to embed OpenACC directives into OpenMP ones, the
approach I've chosen is to directly embed OpenACC handling into the
existing OpenMP infrastructure/passes.  I had first begun implementing
separate OpenACC lowering and expansion passes, but then found myself
re-implementing/copying more and more of the existing OpenMP passes'
code, realized that makes no sense, and we shall instead handle these
directly together in one set of passes -- which also happens to
facilitate the interoperation requirement.

For the same reasons, OpenACC's runtime library shall be implemented in
libgomp next to OpenMP's.  Jakub's already approved this approach
generally.  This patch series doesn't contain any substantial rumtime
library work yet; the last patch adds GOACC_parallel, which so far simply
branches to GOMP_target.  There's more to come.

This is in contrast to Samsung's work, who are implementing OpenACC
separately from the existing OpenMP support.  Yet, I hope we'll be able
to share/re-use at least front end and some middle end code.

Our work builds on what has (briefly) been discussed before, for example
at the GNU Tools Cauldron's Accelerator BOF in this summer.  For the
moment, while still getting the concepts clear, I'm adding new
GENERIC/GIMPLE codes and their handling for OpenACC constructs (for the
implementation of OpenACC parallel "borrowing" from OpenMP target) -- the
long-term goal still is to evolve all these into general "acceleration"
abstractions, evolve the GCC OpenMP infrastructure and passes into
general "acceleration" passes.  As discussed, it makes sense to do this
generalization work later on, once we have a better understanding of what
we actually need.

We directly strive for OpenACC 2.0 support, skipping OpenACC 1.  We're
focussing on the C front end implementation first, following on with C++
and Fortran later on.

The patches I send here only contain a bare minimum of documentation
changes.  I already have further documentation changes prepared (source
code comments as well as Texinfo manual updates); will polish and send
these only once the approach we've chosen has generally been approved.

Comments on the approach and/or patches?


Grüße,
 Thomas

[-- Attachment #2: Type: application/pgp-signature, Size: 489 bytes --]

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

* [gomp4 2/9] libgomp: Prepare for testcases without -fopenmp.
  2013-11-06 19:44 ` [gomp4 1/9] Add missing include thomas
@ 2013-11-06 19:44   ` thomas
  2013-11-06 19:47     ` [gomp4 3/9] OpenACC: Recognize -fopenacc thomas
  2013-11-07  8:16     ` [gomp4 2/9] libgomp: Prepare for testcases without -fopenmp Jakub Jelinek
  2013-11-07  8:15   ` [gomp4 1/9] Add missing include Jakub Jelinek
  1 sibling, 2 replies; 44+ messages in thread
From: thomas @ 2013-11-06 19:44 UTC (permalink / raw)
  To: gcc-patches; +Cc: Thomas Schwinge

From: Thomas Schwinge <thomas@codesourcery.com>

	libgomp/
	* testsuite/lib/libgomp.exp (libgomp_init): Don't add -fopenmp to
	ALWAYS_CFLAGS.
	* testsuite/libgomp.c++/c++.exp (ALWAYS_CFLAGS): Add -fopenmp.
	* testsuite/libgomp.c/c.exp (ALWAYS_CFLAGS): Likewise.
	* testsuite/libgomp.fortran/fortran.exp (ALWAYS_CFLAGS): Likewise.
	* testsuite/libgomp.graphite/graphite.exp (ALWAYS_CFLAGS):
	Likewise.
---
 libgomp/testsuite/lib/libgomp.exp               | 3 ---
 libgomp/testsuite/libgomp.c++/c++.exp           | 3 +++
 libgomp/testsuite/libgomp.c/c.exp               | 3 +++
 libgomp/testsuite/libgomp.fortran/fortran.exp   | 3 +++
 libgomp/testsuite/libgomp.graphite/graphite.exp | 3 +++
 5 files changed, 12 insertions(+), 3 deletions(-)

diff --git libgomp/testsuite/lib/libgomp.exp libgomp/testsuite/lib/libgomp.exp
index d1d8bc8..c965147 100644
--- libgomp/testsuite/lib/libgomp.exp
+++ libgomp/testsuite/lib/libgomp.exp
@@ -169,9 +169,6 @@ proc libgomp_init { args } {
 
     # Disable color diagnostics
     lappend ALWAYS_CFLAGS "additional_flags=-fdiagnostics-color=never"
-
-    # And, gee, turn on OpenMP.
-    lappend ALWAYS_CFLAGS "additional_flags=-fopenmp"
 }
 
 #
diff --git libgomp/testsuite/libgomp.c++/c++.exp libgomp/testsuite/libgomp.c++/c++.exp
index b336306..88e017e 100644
--- libgomp/testsuite/libgomp.c++/c++.exp
+++ libgomp/testsuite/libgomp.c++/c++.exp
@@ -11,6 +11,9 @@ set lang_library_path "../libstdc++-v3/src/.libs"
 # Initialize dg.
 dg-init
 
+# Turn on OpenMP.
+lappend ALWAYS_CFLAGS "additional_flags=-fopenmp"
+
 set blddir [lookfor_file [get_multilibs] libgomp]
 
 
diff --git libgomp/testsuite/libgomp.c/c.exp libgomp/testsuite/libgomp.c/c.exp
index 7dfdf8b..8e902d4 100644
--- libgomp/testsuite/libgomp.c/c.exp
+++ libgomp/testsuite/libgomp.c/c.exp
@@ -17,6 +17,9 @@ if ![info exists DEFAULT_CFLAGS] then {
 # Initialize dg.
 dg-init
 
+# Turn on OpenMP.
+lappend ALWAYS_CFLAGS "additional_flags=-fopenmp"
+
 # Gather a list of all tests.
 set tests [lsort [find $srcdir/$subdir *.c]]
 
diff --git libgomp/testsuite/libgomp.fortran/fortran.exp libgomp/testsuite/libgomp.fortran/fortran.exp
index b7fef29..e0bffe3 100644
--- libgomp/testsuite/libgomp.fortran/fortran.exp
+++ libgomp/testsuite/libgomp.fortran/fortran.exp
@@ -15,6 +15,9 @@ set quadmath_library_path "../libquadmath/.libs"
 # Initialize dg.
 dg-init
 
+# Turn on OpenMP.
+lappend ALWAYS_CFLAGS "additional_flags=-fopenmp"
+
 if { $blddir != "" } {
     lappend ALWAYS_CFLAGS "additional_flags=-fintrinsic-modules-path=${blddir}"
     # Look for a static libgfortran first.
diff --git libgomp/testsuite/libgomp.graphite/graphite.exp libgomp/testsuite/libgomp.graphite/graphite.exp
index 08aa509..9129964 100644
--- libgomp/testsuite/libgomp.graphite/graphite.exp
+++ libgomp/testsuite/libgomp.graphite/graphite.exp
@@ -42,6 +42,9 @@ set PARALLEL_CFLAGS "-ansi -pedantic-errors -O2 \
 # Initialize `dg'.
 dg-init
 
+# Turn on OpenMP.
+lappend ALWAYS_CFLAGS "additional_flags=-fopenmp"
+
 # Gather a list of all tests.
 set tests [lsort [find $srcdir/$subdir *.c]]
 
-- 
1.8.1.1

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

* [gomp4 5/9] OpenACC: preprocessor definition, Fortran integer parameter.
  2013-11-06 20:39       ` [gomp4 4/9] OpenACC: The runtime library will be implemented in libgomp, too thomas
@ 2013-11-06 19:45         ` thomas
  2013-11-06 20:37           ` [gomp4 6/9] OpenACC: Infrastructure for builtins thomas
  2013-11-07  8:19           ` [gomp4 5/9] OpenACC: preprocessor definition, Fortran integer parameter Jakub Jelinek
  2013-11-07  8:18         ` [gomp4 4/9] OpenACC: The runtime library will be implemented in libgomp, too Jakub Jelinek
  1 sibling, 2 replies; 44+ messages in thread
From: thomas @ 2013-11-06 19:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: Thomas Schwinge

From: Thomas Schwinge <thomas@codesourcery.com>

	gcc/c-family/
	* c-cppbuiltin.c (c_cpp_builtins): Conditionally define _OPENACC.
	gcc/fortran/
	* cpp.c (cpp_define_builtins): Conditionally define _OPENACC.
	gcc/testsuite/
	* c-c++-common/cpp/openacc-define-1.c: Test _OPENACC.
	* c-c++-common/cpp/openacc-define-2.c: Likewise.
	* c-c++-common/cpp/openacc-define-3.c: Likewise.
	* gfortran.dg/openacc-define-1.f90: Likewise.
	* gfortran.dg/openacc-define-2.f90: Likewise.
	* gfortran.dg/openacc-define-3.f90: Likewise.
	libgomp/
	* openacc.f90 (openacc_version): New integer parameter.
	* openacc_lib.h (openacc_version): Likewise.
	* testsuite/libgomp.oacc-fortran/openacc_version-1.f: New file.
	* testsuite/libgomp.oacc-fortran/openacc_version-2.f90: Likewise.
---
 gcc/c-family/c-cppbuiltin.c                                  | 3 +++
 gcc/fortran/cpp.c                                            | 3 +++
 gcc/testsuite/c-c++-common/cpp/openacc-define-1.c            | 4 ++++
 gcc/testsuite/c-c++-common/cpp/openacc-define-2.c            | 4 ++++
 gcc/testsuite/c-c++-common/cpp/openacc-define-3.c            | 8 ++++++++
 gcc/testsuite/gfortran.dg/openacc-define-1.f90               | 4 ++++
 gcc/testsuite/gfortran.dg/openacc-define-2.f90               | 4 ++++
 gcc/testsuite/gfortran.dg/openacc-define-3.f90               | 8 ++++++++
 libgomp/openacc.f90                                          | 2 ++
 libgomp/openacc_lib.h                                        | 3 +++
 libgomp/testsuite/libgomp.oacc-fortran/openacc_version-1.f   | 9 +++++++++
 libgomp/testsuite/libgomp.oacc-fortran/openacc_version-2.f90 | 9 +++++++++
 12 files changed, 61 insertions(+)
 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/openacc_version-1.f
 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/openacc_version-2.f90

diff --git gcc/c-family/c-cppbuiltin.c gcc/c-family/c-cppbuiltin.c
index ed4c82c..d48d96f 100644
--- gcc/c-family/c-cppbuiltin.c
+++ gcc/c-family/c-cppbuiltin.c
@@ -895,6 +895,9 @@ c_cpp_builtins (cpp_reader *pfile)
   else if (flag_stack_protect == 1)
     cpp_define (pfile, "__SSP__=1");
 
+  if (flag_openacc)
+    cpp_define (pfile, "_OPENACC=201306");
+
   if (flag_openmp)
     cpp_define (pfile, "_OPENMP=201307");
 
diff --git gcc/fortran/cpp.c gcc/fortran/cpp.c
index ea53681..58f6cc9 100644
--- gcc/fortran/cpp.c
+++ gcc/fortran/cpp.c
@@ -169,6 +169,9 @@ cpp_define_builtins (cpp_reader *pfile)
   cpp_define (pfile, "__GFORTRAN__=1");
   cpp_define (pfile, "_LANGUAGE_FORTRAN=1");
 
+  if (gfc_option.gfc_flag_openacc)
+    cpp_define (pfile, "_OPENACC=201306");
+
   if (gfc_option.gfc_flag_openmp)
     cpp_define (pfile, "_OPENMP=201107");
 
diff --git gcc/testsuite/c-c++-common/cpp/openacc-define-1.c gcc/testsuite/c-c++-common/cpp/openacc-define-1.c
index feaf778..cd37548 100644
--- gcc/testsuite/c-c++-common/cpp/openacc-define-1.c
+++ gcc/testsuite/c-c++-common/cpp/openacc-define-1.c
@@ -1,2 +1,6 @@
 /* { dg-do preprocess } */
 /* { dg-require-effective-target fopenacc } */
+
+#ifdef _OPENACC
+# error _OPENACC defined
+#endif
diff --git gcc/testsuite/c-c++-common/cpp/openacc-define-2.c gcc/testsuite/c-c++-common/cpp/openacc-define-2.c
index a2f3e28..b007e32 100644
--- gcc/testsuite/c-c++-common/cpp/openacc-define-2.c
+++ gcc/testsuite/c-c++-common/cpp/openacc-define-2.c
@@ -1,3 +1,7 @@
 /* { dg-options "-fno-openacc" } */
 /* { dg-do preprocess } */
 /* { dg-require-effective-target fopenacc } */
+
+#ifdef _OPENACC
+# error _OPENACC defined
+#endif
diff --git gcc/testsuite/c-c++-common/cpp/openacc-define-3.c gcc/testsuite/c-c++-common/cpp/openacc-define-3.c
index ce270c3..ccedcd9 100644
--- gcc/testsuite/c-c++-common/cpp/openacc-define-3.c
+++ gcc/testsuite/c-c++-common/cpp/openacc-define-3.c
@@ -1,3 +1,11 @@
 /* { dg-options "-fopenacc" } */
 /* { dg-do preprocess } */
 /* { dg-require-effective-target fopenacc } */
+
+#ifndef _OPENACC
+# error _OPENACC not defined
+#endif
+
+#if _OPENACC != 201306
+# error _OPENACC defined to wrong value
+#endif
diff --git gcc/testsuite/gfortran.dg/openacc-define-1.f90 gcc/testsuite/gfortran.dg/openacc-define-1.f90
index b961468..42f4073 100644
--- gcc/testsuite/gfortran.dg/openacc-define-1.f90
+++ gcc/testsuite/gfortran.dg/openacc-define-1.f90
@@ -1,3 +1,7 @@
 ! { dg-options "-cpp" }
 ! { dg-do preprocess }
 ! { dg-require-effective-target fopenacc }
+
+#ifdef _OPENACC
+# error _OPENACC defined
+#endif
diff --git gcc/testsuite/gfortran.dg/openacc-define-2.f90 gcc/testsuite/gfortran.dg/openacc-define-2.f90
index 49b714d..8ad1bd5 100644
--- gcc/testsuite/gfortran.dg/openacc-define-2.f90
+++ gcc/testsuite/gfortran.dg/openacc-define-2.f90
@@ -1,3 +1,7 @@
 ! { dg-options "-cpp -fno-openacc" }
 ! { dg-do preprocess }
 ! { dg-require-effective-target fopenacc }
+
+#ifdef _OPENACC
+# error _OPENACC defined
+#endif
diff --git gcc/testsuite/gfortran.dg/openacc-define-3.f90 gcc/testsuite/gfortran.dg/openacc-define-3.f90
index 8018d5c..b6c296e 100644
--- gcc/testsuite/gfortran.dg/openacc-define-3.f90
+++ gcc/testsuite/gfortran.dg/openacc-define-3.f90
@@ -1,3 +1,11 @@
 ! { dg-options "-cpp -fopenacc" }
 ! { dg-do preprocess }
 ! { dg-require-effective-target fopenacc }
+
+#ifndef _OPENACC
+# error _OPENACC not defined
+#endif
+
+#if _OPENACC != 201306
+# error _OPENACC defined to wrong value
+#endif
diff --git libgomp/openacc.f90 libgomp/openacc.f90
index 55b79c2..b2a79f6 100644
--- libgomp/openacc.f90
+++ libgomp/openacc.f90
@@ -34,4 +34,6 @@ module openacc
   use openacc_kinds
   implicit none
 
+  integer, parameter :: openacc_version = 201306
+
 end module openacc
diff --git libgomp/openacc_lib.h libgomp/openacc_lib.h
index b2cb679..d19c95c 100644
--- libgomp/openacc_lib.h
+++ libgomp/openacc_lib.h
@@ -24,3 +24,6 @@
 !  a copy of the GCC Runtime Library Exception along with this program;
 !  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 !  <http://www.gnu.org/licenses/>.
+
+      integer openacc_version
+      parameter (openacc_version = 201306)
diff --git libgomp/testsuite/libgomp.oacc-fortran/openacc_version-1.f libgomp/testsuite/libgomp.oacc-fortran/openacc_version-1.f
new file mode 100644
index 0000000..db3c6b1
--- /dev/null
+++ libgomp/testsuite/libgomp.oacc-fortran/openacc_version-1.f
@@ -0,0 +1,9 @@
+! { dg-do run }
+
+      program main
+      implicit none
+      include "openacc_lib.h"
+
+      if (openacc_version .ne. 201306) call abort;
+
+      end program main
diff --git libgomp/testsuite/libgomp.oacc-fortran/openacc_version-2.f90 libgomp/testsuite/libgomp.oacc-fortran/openacc_version-2.f90
new file mode 100644
index 0000000..a14ecdd
--- /dev/null
+++ libgomp/testsuite/libgomp.oacc-fortran/openacc_version-2.f90
@@ -0,0 +1,9 @@
+! { dg-do run }
+
+program main
+  use openacc
+  implicit none
+
+  if (openacc_version .ne. 201306) call abort;
+
+end program main
-- 
1.8.1.1

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

* [gomp4 3/9] OpenACC: Recognize -fopenacc.
  2013-11-06 19:44   ` [gomp4 2/9] libgomp: Prepare for testcases without -fopenmp thomas
@ 2013-11-06 19:47     ` thomas
  2013-11-06 20:39       ` [gomp4 4/9] OpenACC: The runtime library will be implemented in libgomp, too thomas
  2013-11-07  8:17       ` [gomp4 3/9] OpenACC: Recognize -fopenacc Jakub Jelinek
  2013-11-07  8:16     ` [gomp4 2/9] libgomp: Prepare for testcases without -fopenmp Jakub Jelinek
  1 sibling, 2 replies; 44+ messages in thread
From: thomas @ 2013-11-06 19:47 UTC (permalink / raw)
  To: gcc-patches; +Cc: Thomas Schwinge

From: Thomas Schwinge <thomas@codesourcery.com>

	gcc/c-family/
	* c.opt (fopenacc): New option.
	gcc/fortran/
	* lang.opt (fopenacc): New option.
	* invoke.texi (-fopenacc): Document it.
	* gfortran.h (gfc_option_t): New member.
	* options.c (gfc_init_options, gfc_handle_option): Handle it.
	gcc/testsuite/
	* lib/target-supports.exp (check_effective_target_fopenacc): New
	procedure.
	gcc/
	* doc/invoke.texi (-fopenacc): Document it.
	* doc/sourcebuild.texi (fopenacc): Document it.
	gcc/testsuite/
	* c-c++-common/cpp/openacc-define-1.c: New file.
	* c-c++-common/cpp/openacc-define-2.c: Likewise.
	* c-c++-common/cpp/openacc-define-3.c: Likewise.
	* gfortran.dg/openacc-define-1.f90: Likewise.
	* gfortran.dg/openacc-define-2.f90: Likewise.
	* gfortran.dg/openacc-define-3.f90: Likewise.
---
 gcc/c-family/c.opt                                |  4 ++++
 gcc/doc/invoke.texi                               | 11 ++++++++++-
 gcc/doc/sourcebuild.texi                          |  3 +++
 gcc/fortran/gfortran.h                            |  1 +
 gcc/fortran/invoke.texi                           |  7 ++++++-
 gcc/fortran/lang.opt                              |  4 ++++
 gcc/fortran/options.c                             |  5 +++++
 gcc/testsuite/c-c++-common/cpp/openacc-define-1.c |  2 ++
 gcc/testsuite/c-c++-common/cpp/openacc-define-2.c |  3 +++
 gcc/testsuite/c-c++-common/cpp/openacc-define-3.c |  3 +++
 gcc/testsuite/gfortran.dg/openacc-define-1.f90    |  3 +++
 gcc/testsuite/gfortran.dg/openacc-define-2.f90    |  3 +++
 gcc/testsuite/gfortran.dg/openacc-define-3.f90    |  3 +++
 gcc/testsuite/lib/target-supports.exp             |  9 +++++++++
 14 files changed, 59 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/cpp/openacc-define-1.c
 create mode 100644 gcc/testsuite/c-c++-common/cpp/openacc-define-2.c
 create mode 100644 gcc/testsuite/c-c++-common/cpp/openacc-define-3.c
 create mode 100644 gcc/testsuite/gfortran.dg/openacc-define-1.f90
 create mode 100644 gcc/testsuite/gfortran.dg/openacc-define-2.f90
 create mode 100644 gcc/testsuite/gfortran.dg/openacc-define-3.f90

diff --git gcc/c-family/c.opt gcc/c-family/c.opt
index b862eb9..d86d79b 100644
--- gcc/c-family/c.opt
+++ gcc/c-family/c.opt
@@ -1065,6 +1065,10 @@ fobjc-std=objc1
 ObjC ObjC++ Var(flag_objc1_only)
 Conform to the Objective-C 1.0 language as implemented in GCC 4.0
 
+fopenacc
+C ObjC C++ ObjC++ Var(flag_openacc)
+Enable OpenACC
+
 fopenmp
 C ObjC C++ ObjC++ Var(flag_openmp)
 Enable OpenMP (implies -frecursive in Fortran)
diff --git gcc/doc/invoke.texi gcc/doc/invoke.texi
index e84bca3..e393139 100644
--- gcc/doc/invoke.texi
+++ gcc/doc/invoke.texi
@@ -168,7 +168,8 @@ in the following sections.
 @gccoptlist{-ansi  -std=@var{standard}  -fgnu89-inline @gol
 -aux-info @var{filename} -fallow-parameterless-variadic-functions @gol
 -fno-asm  -fno-builtin  -fno-builtin-@var{function} @gol
--fhosted  -ffreestanding -fopenmp -fms-extensions -fplan9-extensions @gol
+-fhosted  -ffreestanding -fopenacc -fopenmp -fms-extensions @gol
+-fplan9-extensions @gol
 -trigraphs  -traditional  -traditional-cpp @gol
 -fallow-single-precision  -fcond-mismatch -flax-vector-conversions @gol
 -fsigned-bitfields  -fsigned-char @gol
@@ -1831,6 +1832,14 @@ This is equivalent to @option{-fno-hosted}.
 @xref{Standards,,Language Standards Supported by GCC}, for details of
 freestanding and hosted environments.
 
+@item -fopenacc
+@opindex fopenacc
+@cindex OpenACC accelerator programming
+Enable handling of OpenACC.
+When @option{-fopenacc} is specified, the
+compiler generates accelerated code according to the OpenACC Application
+Programming Interface v2.0 @w{@uref{http://www.openacc.org/}}.
+
 @item -fopenmp
 @opindex fopenmp
 @cindex OpenMP parallel
diff --git gcc/doc/sourcebuild.texi gcc/doc/sourcebuild.texi
index 1a70916..8b0031c 100644
--- gcc/doc/sourcebuild.texi
+++ gcc/doc/sourcebuild.texi
@@ -1787,6 +1787,9 @@ Target supports Graphite optimizations.
 @item fixed_point
 Target supports fixed-point extension to C.
 
+@item fopenacc
+Target supports OpenACC via @option{-fopenacc}.
+
 @item fopenmp
 Target supports OpenMP via @option{-fopenmp}.
 
diff --git gcc/fortran/gfortran.h gcc/fortran/gfortran.h
index b28edd8..5089691 100644
--- gcc/fortran/gfortran.h
+++ gcc/fortran/gfortran.h
@@ -2285,6 +2285,7 @@ typedef struct
   int blas_matmul_limit;
   int flag_cray_pointer;
   int flag_d_lines;
+  int gfc_flag_openacc;
   int gfc_flag_openmp;
   int flag_sign_zero;
   int flag_stack_arrays;
diff --git gcc/fortran/invoke.texi gcc/fortran/invoke.texi
index eb678d1..46fca59 100644
--- gcc/fortran/invoke.texi
+++ gcc/fortran/invoke.texi
@@ -120,7 +120,7 @@ by type.  Explanations are in the following sections.
 -ffixed-line-length-none -ffree-form -ffree-line-length-@var{n} @gol
 -ffree-line-length-none -fimplicit-none -finteger-4-integer-8 @gol
 -fmax-identifier-length -fmodule-private -fno-fixed-form -fno-range-check @gol
--fopenmp -freal-4-real-10 -freal-4-real-16 -freal-4-real-8 @gol
+-fopenacc -fopenmp -freal-4-real-10 -freal-4-real-16 -freal-4-real-8 @gol
 -freal-8-real-10 -freal-8-real-16 -freal-8-real-4 -std=@var{std}
 }
 
@@ -336,6 +336,11 @@ representation of the translated Fortran code, produced by
 Enable the Cray pointer extension, which provides C-like pointer
 functionality.
 
+@item -fopenacc
+@opindex @code{fopenacc}
+@cindex OpenACC
+Enable the OpenACC extensions.
+
 @item -fopenmp
 @opindex @code{fopenmp}
 @cindex OpenMP
diff --git gcc/fortran/lang.opt gcc/fortran/lang.opt
index 4f79934..201159b 100644
--- gcc/fortran/lang.opt
+++ gcc/fortran/lang.opt
@@ -513,6 +513,10 @@ fmodule-private
 Fortran
 Set default accessibility of module entities to PRIVATE.
 
+fopenacc
+Fortran
+; Documented in C
+
 fopenmp
 Fortran
 ; Documented in C
diff --git gcc/fortran/options.c gcc/fortran/options.c
index 6e4e7c1..2298bba 100644
--- gcc/fortran/options.c
+++ gcc/fortran/options.c
@@ -146,6 +146,7 @@ gfc_init_options (unsigned int decoded_options_count,
   gfc_option.blas_matmul_limit = 30;
   gfc_option.flag_cray_pointer = 0;
   gfc_option.flag_d_lines = -1;
+  gfc_option.gfc_flag_openacc = 0;
   gfc_option.gfc_flag_openmp = 0;
   gfc_option.flag_sign_zero = 1;
   gfc_option.flag_recursive = 0;
@@ -832,6 +833,10 @@ gfc_handle_option (size_t scode, const char *arg, int value,
       gfc_option.source_form = FORM_FREE;
       break;
 
+    case OPT_fopenacc:
+      gfc_option.gfc_flag_openacc = value;
+      break;
+
     case OPT_fopenmp:
       gfc_option.gfc_flag_openmp = value;
       break;
diff --git gcc/testsuite/c-c++-common/cpp/openacc-define-1.c gcc/testsuite/c-c++-common/cpp/openacc-define-1.c
new file mode 100644
index 0000000..feaf778
--- /dev/null
+++ gcc/testsuite/c-c++-common/cpp/openacc-define-1.c
@@ -0,0 +1,2 @@
+/* { dg-do preprocess } */
+/* { dg-require-effective-target fopenacc } */
diff --git gcc/testsuite/c-c++-common/cpp/openacc-define-2.c gcc/testsuite/c-c++-common/cpp/openacc-define-2.c
new file mode 100644
index 0000000..a2f3e28
--- /dev/null
+++ gcc/testsuite/c-c++-common/cpp/openacc-define-2.c
@@ -0,0 +1,3 @@
+/* { dg-options "-fno-openacc" } */
+/* { dg-do preprocess } */
+/* { dg-require-effective-target fopenacc } */
diff --git gcc/testsuite/c-c++-common/cpp/openacc-define-3.c gcc/testsuite/c-c++-common/cpp/openacc-define-3.c
new file mode 100644
index 0000000..ce270c3
--- /dev/null
+++ gcc/testsuite/c-c++-common/cpp/openacc-define-3.c
@@ -0,0 +1,3 @@
+/* { dg-options "-fopenacc" } */
+/* { dg-do preprocess } */
+/* { dg-require-effective-target fopenacc } */
diff --git gcc/testsuite/gfortran.dg/openacc-define-1.f90 gcc/testsuite/gfortran.dg/openacc-define-1.f90
new file mode 100644
index 0000000..b961468
--- /dev/null
+++ gcc/testsuite/gfortran.dg/openacc-define-1.f90
@@ -0,0 +1,3 @@
+! { dg-options "-cpp" }
+! { dg-do preprocess }
+! { dg-require-effective-target fopenacc }
diff --git gcc/testsuite/gfortran.dg/openacc-define-2.f90 gcc/testsuite/gfortran.dg/openacc-define-2.f90
new file mode 100644
index 0000000..49b714d
--- /dev/null
+++ gcc/testsuite/gfortran.dg/openacc-define-2.f90
@@ -0,0 +1,3 @@
+! { dg-options "-cpp -fno-openacc" }
+! { dg-do preprocess }
+! { dg-require-effective-target fopenacc }
diff --git gcc/testsuite/gfortran.dg/openacc-define-3.f90 gcc/testsuite/gfortran.dg/openacc-define-3.f90
new file mode 100644
index 0000000..8018d5c
--- /dev/null
+++ gcc/testsuite/gfortran.dg/openacc-define-3.f90
@@ -0,0 +1,3 @@
+! { dg-options "-cpp -fopenacc" }
+! { dg-do preprocess }
+! { dg-require-effective-target fopenacc }
diff --git gcc/testsuite/lib/target-supports.exp gcc/testsuite/lib/target-supports.exp
index 5ca0b76..b611708 100644
--- gcc/testsuite/lib/target-supports.exp
+++ gcc/testsuite/lib/target-supports.exp
@@ -718,6 +718,15 @@ proc check_effective_target_fgraphite {} {
     } "-O1 -fgraphite"]
 }
 
+# Return 1 if compilation with -fopenacc is error-free for trivial
+# code, 0 otherwise.
+
+proc check_effective_target_fopenacc {} {
+    return [check_no_compiler_messages fopenacc object {
+	void foo (void) { }
+    } "-fopenacc"]
+}
+
 # Return 1 if compilation with -fopenmp is error-free for trivial
 # code, 0 otherwise.
 
-- 
1.8.1.1

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

* [gomp4 9/9] OpenACC: Basic support for #pragma acc parallel.
  2013-11-06 20:29               ` [gomp4 8/9] OpenACC: Basic support for #pragma acc in the C front end thomas
@ 2013-11-06 19:53                 ` thomas
  2013-11-06 20:01                   ` Thomas Schwinge
  2013-11-06 20:03                   ` [gomp4 9/9] OpenACC: Basic support for #pragma acc parallel Jakub Jelinek
  2013-11-07  8:41                 ` [gomp4 8/9] OpenACC: Basic support for #pragma acc in the C front end Jakub Jelinek
  1 sibling, 2 replies; 44+ messages in thread
From: thomas @ 2013-11-06 19:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: Thomas Schwinge

From: Thomas Schwinge <thomas@codesourcery.com>

	gcc/c-family/
	* c-pragma.h (pragma_kind): Add PRAGMA_OACC_PARALLEL.
	* c-pragma.c (oacc_pragmas): Add "parallel".
	gcc/c/
	* c-parser.c (c_parser_omp_structured_block): Update comment.
	(c_parser_oacc_parallel): New function.
	(c_parser_omp_construct): Handle PRAGMA_OACC_PARALLEL.

	gcc/
	* tree.def (OACC_PARALLEL): New code.
	* doc/generic.texi (OpenMP): Document it.
	* tree.h (OMP_BODY, OMP_CLAUSES): Include it.
	(OACC_PARALLEL_BODY, OACC_PARALLEL_CLAUSES): New macros.
	* tree-pretty-print.c (dump_generic_node): Handle OACC_PARALLEL.
	gcc/c/
	* c-tree.h (c_finish_oacc_parallel): New declaration.
	* c-typeck.c (c_finish_oacc_parallel): New function.
	gcc/c-family/
	* c-omp.c (c_omp_split_clauses): Catch OACC_PARALLEL.

	gcc/
	* gimple.def (GIMPLE_OACC_PARALLEL): New code.
	* doc/gimple.texi: Document it.
	* gimple.h (gimple_build_oacc_parallel): New declaration.
	(gimple_oacc_parallel_clauses, gimple_oacc_parallel_clauses_ptr)
	(gimple_oacc_parallel_set_clauses, gimple_oacc_parallel_child_fn)
	(gimple_oacc_parallel_child_fn_ptr)
	(gimple_oacc_parallel_set_child_fn, gimple_oacc_parallel_data_arg)
	(gimple_oacc_parallel_data_arg_ptr)
	(gimple_oacc_parallel_set_data_arg): New inline functions.
	(CASE_GIMPLE_OMP): Add GIMPLE_OACC_PARALLEL.
	* gimple.c (gimple_build_oacc_parallel): New function.
	(walk_gimple_op, walk_gimple_stmt, gimple_copy): Handle
	GIMPLE_OACC_PARALLEL.
	* gimplify.c (is_gimple_stmt): Handle GIMPLE_OACC_PARALLEL.
	(gimplify_oacc_parallel): New function.
	(gimplify_expr): Handle OACC_PARALLEL.
	* cgraphbuild.c (build_cgraph_edges): Handle GIMPLE_OACC_PARALLEL.
	* gimple-low.c (lower_stmt): Likewise.
	* gimple-pretty-print.c (pp_gimple_stmt_1): Likewise.
	(dump_gimple_oacc_parallel): New function.
	* oacc-builtins.def (BUILT_IN_GOACC_PARALLEL): New macro.
	* omp-low.c (scan_oacc_parallel, expand_oacc_parallel)
	(lower_oacc_parallel): New functions.
	(use_pointer_for_field, build_outer_var_ref, scan_sharing_clauses)
	(create_omp_child_function, check_omp_nesting_restrictions)
	(scan_omp_1_stmt, lower_rec_simd_input_clauses)
	(lower_lastprivate_clauses, lower_reduction_clauses)
	(lower_copyprivate_clauses, lower_send_clauses)
	(lower_send_shared_vars, expand_omp)
	(maybe_add_implicit_barrier_cancel, create_task_copyfn)
	(lower_omp_1, make_gimple_omp_edges): Handle GIMPLE_OACC_PARALLEL,
	or catch it.
	* tree-inline.c (remap_gimple_stmt): Likewise.
	* tree-nested.c (convert_nonlocal_reference_stmt)
	(convert_local_reference_stmt, convert_tramp_reference_stmt)
	(convert_gimple_call): Likewise.
	gcc/testsuite/
	* c-c++-common/goacc-gomp/nesting-fail-1.c: New file.
	* c-c++-common/goacc/nesting-fail-1.c: Likewise.
	* c-c++-common/goacc/parallel-1.c: Likewise.
	* c-c++-common/goacc/parallel-fail-1.c: Likewise.

	libgomp/
	* oacc-parallel.c: New file.
	* Makefile.am (libgomp_la_SOURCES): Add it.
	* Makefile.in: Regenerate.
	* libgomp.map (GOACC_2.0): Add GOACC_parallel.
	* libgomp_g.h (GOACC_parallel): New declaration.
	* testsuite/libgomp.oacc-c/goacc_parallel.c: New file.
	* testsuite/libgomp.oacc-c/parallel-1.c: New file.
---
 gcc/c-family/c-omp.c                               |    1 +
 gcc/c-family/c-pragma.c                            |    1 +
 gcc/c-family/c-pragma.h                            |    1 +
 gcc/c/c-parser.c                                   |   42 +-
 gcc/c/c-tree.h                                     |    1 +
 gcc/c/c-typeck.c                                   |   19 +
 gcc/cgraphbuild.c                                  |   12 +-
 gcc/doc/generic.texi                               |    5 +
 gcc/doc/gimple.texi                                |    8 +
 gcc/gimple-low.c                                   |    1 +
 gcc/gimple-pretty-print.c                          |   58 ++
 gcc/gimple.c                                       |   36 +
 gcc/gimple.def                                     |   10 +-
 gcc/gimple.h                                       |   89 ++
 gcc/gimplify.c                                     |   38 +
 gcc/oacc-builtins.def                              |    3 +
 gcc/omp-low.c                                      | 1047 ++++++++++++++++----
 .../c-c++-common/goacc-gomp/nesting-fail-1.c       |  121 +++
 gcc/testsuite/c-c++-common/goacc/nesting-fail-1.c  |   11 +
 gcc/testsuite/c-c++-common/goacc/parallel-1.c      |    6 +
 gcc/testsuite/c-c++-common/goacc/parallel-fail-1.c |    6 +
 gcc/tree-inline.c                                  |    4 +
 gcc/tree-nested.c                                  |   12 +
 gcc/tree-pretty-print.c                            |    5 +
 gcc/tree.def                                       |   11 +-
 gcc/tree.h                                         |    9 +-
 libgomp/Makefile.am                                |    2 +-
 libgomp/Makefile.in                                |    5 +-
 libgomp/libgomp.map                                |    2 +
 libgomp/libgomp_g.h                                |    5 +
 libgomp/oacc-parallel.c                            |   36 +
 libgomp/testsuite/libgomp.oacc-c/goacc_parallel.c  |   25 +
 libgomp/testsuite/libgomp.oacc-c/parallel-1.c      |   26 +
 33 files changed, 1450 insertions(+), 208 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/goacc-gomp/nesting-fail-1.c
 create mode 100644 gcc/testsuite/c-c++-common/goacc/nesting-fail-1.c
 create mode 100644 gcc/testsuite/c-c++-common/goacc/parallel-1.c
 create mode 100644 gcc/testsuite/c-c++-common/goacc/parallel-fail-1.c
 create mode 100644 libgomp/oacc-parallel.c
 create mode 100644 libgomp/testsuite/libgomp.oacc-c/goacc_parallel.c
 create mode 100644 libgomp/testsuite/libgomp.oacc-c/parallel-1.c

diff --git gcc/c-family/c-omp.c gcc/c-family/c-omp.c
index f001a75..f7d2bd9 100644
--- gcc/c-family/c-omp.c
+++ gcc/c-family/c-omp.c
@@ -627,6 +627,7 @@ c_omp_split_clauses (location_t loc, enum tree_code code,
   enum c_omp_clause_split s;
   int i;
 
+  gcc_assert (code != OACC_PARALLEL);
   for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++)
     cclauses[i] = NULL;
   /* Add implicit nowait clause on
diff --git gcc/c-family/c-pragma.c gcc/c-family/c-pragma.c
index 98f98d0..c329f8d 100644
--- gcc/c-family/c-pragma.c
+++ gcc/c-family/c-pragma.c
@@ -1165,6 +1165,7 @@ static vec<pragma_ns_name> registered_pp_pragmas;
 
 struct omp_pragma_def { const char *name; unsigned int id; };
 static const struct omp_pragma_def oacc_pragmas[] = {
+  { "parallel", PRAGMA_OACC_PARALLEL },
 };
 static const struct omp_pragma_def omp_pragmas[] = {
   { "atomic", PRAGMA_OMP_ATOMIC },
diff --git gcc/c-family/c-pragma.h gcc/c-family/c-pragma.h
index 705bcb4..5c58e32 100644
--- gcc/c-family/c-pragma.h
+++ gcc/c-family/c-pragma.h
@@ -27,6 +27,7 @@ along with GCC; see the file COPYING3.  If not see
 typedef enum pragma_kind {
   PRAGMA_NONE = 0,
 
+  PRAGMA_OACC_PARALLEL,
   PRAGMA_OMP_ATOMIC,
   PRAGMA_OMP_BARRIER,
   PRAGMA_OMP_CANCEL,
diff --git gcc/c/c-parser.c gcc/c/c-parser.c
index 8a1e988..297b6da7 100644
--- gcc/c/c-parser.c
+++ gcc/c/c-parser.c
@@ -4478,6 +4478,17 @@ c_parser_label (c_parser *parser)
      @throw expression ;
      @throw ;
 
+   OpenACC:
+
+   statement:
+     openacc-construct
+
+   openacc-construct:
+     parallel-construct
+
+   parallel-construct:
+     parallel-directive structured-block
+
    OpenMP:
 
    statement:
@@ -10754,7 +10765,7 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask,
   return clauses;
 }
 
-/* OpenMP 2.5:
+/* OpenACC 2.0, OpenMP 2.5:
    structured-block:
      statement
 
@@ -10770,6 +10781,32 @@ c_parser_omp_structured_block (c_parser *parser)
   return pop_stmt_list (stmt);
 }
 
+/* OpenACC 2.0:
+   # pragma acc parallel oacc-parallel-clause[optseq] new-line
+
+   LOC is the location of the #pragma token.
+*/
+
+#define OACC_PARALLEL_CLAUSE_MASK			\
+	PRAGMA_OMP_CLAUSE_NONE
+
+static tree
+c_parser_oacc_parallel (location_t loc, c_parser *parser)
+{
+  tree stmt, clauses, block;
+
+  clauses =  c_parser_omp_all_clauses (parser, OACC_PARALLEL_CLAUSE_MASK,
+				       "#pragma acc parallel");
+  gcc_assert (clauses == NULL);
+
+  block = c_begin_omp_parallel ();
+  add_stmt (c_parser_omp_structured_block (parser));
+
+  stmt = c_finish_oacc_parallel (loc, clauses, block);
+
+  return stmt;
+}
+
 /* OpenMP 2.5:
    # pragma omp atomic new-line
      expression-stmt
@@ -12948,6 +12985,9 @@ c_parser_omp_construct (c_parser *parser)
 
   switch (p_kind)
     {
+    case PRAGMA_OACC_PARALLEL:
+      stmt = c_parser_oacc_parallel (loc, parser);
+      break;
     case PRAGMA_OMP_ATOMIC:
       c_parser_omp_atomic (loc, parser);
       return;
diff --git gcc/c/c-tree.h gcc/c/c-tree.h
index 2565ccb..f524e31 100644
--- gcc/c/c-tree.h
+++ gcc/c/c-tree.h
@@ -635,6 +635,7 @@ extern tree c_finish_bc_stmt (location_t, tree *, bool);
 extern tree c_finish_goto_label (location_t, tree);
 extern tree c_finish_goto_ptr (location_t, tree);
 extern tree c_expr_to_decl (tree, bool *, bool *);
+extern tree c_finish_oacc_parallel (location_t, tree, tree);
 extern tree c_begin_omp_parallel (void);
 extern tree c_finish_omp_parallel (location_t, tree, tree);
 extern tree c_begin_omp_task (void);
diff --git gcc/c/c-typeck.c gcc/c/c-typeck.c
index 8f1d3a4..e7096e6 100644
--- gcc/c/c-typeck.c
+++ gcc/c/c-typeck.c
@@ -10644,6 +10644,25 @@ c_expr_to_decl (tree expr, bool *tc ATTRIBUTE_UNUSED, bool *se)
     return expr;
 }
 \f
+/* Generate OACC_PARALLEL, with CLAUSES and BLOCK as its compound
+   statement.  LOC is the location of the OACC_PARALLEL.  */
+
+tree
+c_finish_oacc_parallel (location_t loc, tree clauses, tree block)
+{
+  tree stmt;
+
+  block = c_end_compound_stmt (loc, block, true);
+
+  stmt = make_node (OACC_PARALLEL);
+  TREE_TYPE (stmt) = void_type_node;
+  OACC_PARALLEL_CLAUSES (stmt) = clauses;
+  OACC_PARALLEL_BODY (stmt) = block;
+  SET_EXPR_LOCATION (stmt, loc);
+
+  return add_stmt (stmt);
+}
+
 /* Like c_begin_compound_stmt, except force the retention of the BLOCK.  */
 
 tree
diff --git gcc/cgraphbuild.c gcc/cgraphbuild.c
index 87e06e3..efad3d9 100644
--- gcc/cgraphbuild.c
+++ gcc/cgraphbuild.c
@@ -333,7 +333,15 @@ build_cgraph_edges (void)
 					     bb->count, freq);
 	    }
 	  ipa_record_stmt_references (node, stmt);
-	  if (gimple_code (stmt) == GIMPLE_OMP_PARALLEL
+	  if (gimple_code (stmt) == GIMPLE_OACC_PARALLEL
+	      && gimple_oacc_parallel_child_fn (stmt))
+	    {
+	      tree fn = gimple_oacc_parallel_child_fn (stmt);
+	      ipa_record_reference (node,
+				    cgraph_get_create_real_symbol_node (fn),
+				    IPA_REF_ADDR, stmt);
+	    }
+	  else if (gimple_code (stmt) == GIMPLE_OMP_PARALLEL
 	      && gimple_omp_parallel_child_fn (stmt))
 	    {
 	      tree fn = gimple_omp_parallel_child_fn (stmt);
@@ -341,7 +349,7 @@ build_cgraph_edges (void)
 				    cgraph_get_create_real_symbol_node (fn),
 				    IPA_REF_ADDR, stmt);
 	    }
-	  if (gimple_code (stmt) == GIMPLE_OMP_TASK)
+	  else if (gimple_code (stmt) == GIMPLE_OMP_TASK)
 	    {
 	      tree fn = gimple_omp_task_child_fn (stmt);
 	      if (fn)
diff --git gcc/doc/generic.texi gcc/doc/generic.texi
index 73dd123..812f5a9 100644
--- gcc/doc/generic.texi
+++ gcc/doc/generic.texi
@@ -2049,6 +2049,7 @@ edge.  Rethrowing the exception is represented using @code{RESX_EXPR}.
 
 @node OpenMP
 @subsection OpenMP
+@tindex OACC_PARALLEL
 @tindex OMP_PARALLEL
 @tindex OMP_FOR
 @tindex OMP_SECTIONS
@@ -2066,6 +2067,10 @@ All the statements starting with @code{OMP_} represent directives and
 clauses used by the OpenMP API @w{@uref{http://www.openmp.org/}}.
 
 @table @code
+@item OACC_PARALLEL
+
+Represents @code{#pragma acc parallel [clause1 @dots{} clauseN]}.
+
 @item OMP_PARALLEL
 
 Represents @code{#pragma omp parallel [clause1 @dots{} clauseN]}. It
diff --git gcc/doc/gimple.texi gcc/doc/gimple.texi
index 7bd9fd5..0f1bbe6 100644
--- gcc/doc/gimple.texi
+++ gcc/doc/gimple.texi
@@ -338,6 +338,7 @@ The following table briefly describes the GIMPLE instruction set.
 @item @code{GIMPLE_GOTO}		@tab x			@tab x
 @item @code{GIMPLE_LABEL}		@tab x			@tab x
 @item @code{GIMPLE_NOP}			@tab x			@tab x
+@item @code{GIMPLE_OACC_PARALLEL}	@tab x			@tab x
 @item @code{GIMPLE_OMP_ATOMIC_LOAD}	@tab x			@tab x
 @item @code{GIMPLE_OMP_ATOMIC_STORE}	@tab x			@tab x
 @item @code{GIMPLE_OMP_CONTINUE}	@tab x			@tab x
@@ -905,6 +906,7 @@ Return a deep copy of statement @code{STMT}.
 * @code{GIMPLE_EH_FILTER}::
 * @code{GIMPLE_LABEL}::
 * @code{GIMPLE_NOP}::
+* @code{GIMPLE_OACC_PARALLEL}::
 * @code{GIMPLE_OMP_ATOMIC_LOAD}::
 * @code{GIMPLE_OMP_ATOMIC_STORE}::
 * @code{GIMPLE_OMP_CONTINUE}::
@@ -1554,6 +1556,12 @@ Build a @code{GIMPLE_NOP} statement.
 Returns @code{TRUE} if statement @code{G} is a @code{GIMPLE_NOP}.
 @end deftypefn
 
+
+@node @code{GIMPLE_OACC_PARALLEL}
+@subsection @code{GIMPLE_OACC_PARALLEL}
+@cindex @code{GIMPLE_OACC_PARALLEL}
+
+
 @node @code{GIMPLE_OMP_ATOMIC_LOAD}
 @subsection @code{GIMPLE_OMP_ATOMIC_LOAD}
 @cindex @code{GIMPLE_OMP_ATOMIC_LOAD}
diff --git gcc/gimple-low.c gcc/gimple-low.c
index d527d86..74c9925 100644
--- gcc/gimple-low.c
+++ gcc/gimple-low.c
@@ -368,6 +368,7 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
       }
       break;
 
+    case GIMPLE_OACC_PARALLEL:
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
     case GIMPLE_OMP_TARGET:
diff --git gcc/gimple-pretty-print.c gcc/gimple-pretty-print.c
index 6842213..59cb5bb 100644
--- gcc/gimple-pretty-print.c
+++ gcc/gimple-pretty-print.c
@@ -1823,6 +1823,60 @@ dump_gimple_phi (pretty_printer *buffer, gimple phi, int spc, bool comment,
 }
 
 
+/* Dump a GIMPLE_OACC_PARALLEL tuple on the pretty_printer BUFFER, SPC spaces
+   of indent.  FLAGS specifies details to show in the dump (see TDF_* in
+   dumpfile.h).  */
+
+static void
+dump_gimple_oacc_parallel (pretty_printer *buffer, gimple gs, int spc,
+                          int flags)
+{
+  if (flags & TDF_RAW)
+    {
+      dump_gimple_fmt (buffer, spc, flags, "%G <%+BODY <%S>%nCLAUSES <", gs,
+                       gimple_omp_body (gs));
+      dump_omp_clauses (buffer, gimple_oacc_parallel_clauses (gs), spc, flags);
+      dump_gimple_fmt (buffer, spc, flags, " >, %T, %T%n>",
+                       gimple_oacc_parallel_child_fn (gs),
+                       gimple_oacc_parallel_data_arg (gs));
+    }
+  else
+    {
+      gimple_seq body;
+      pp_string (buffer, "#pragma acc parallel");
+      dump_omp_clauses (buffer, gimple_oacc_parallel_clauses (gs), spc, flags);
+      if (gimple_oacc_parallel_child_fn (gs))
+	{
+	  pp_string (buffer, " [child fn: ");
+	  dump_generic_node (buffer, gimple_oacc_parallel_child_fn (gs),
+			     spc, flags, false);
+	  pp_string (buffer, " (");
+	  if (gimple_oacc_parallel_data_arg (gs))
+	    dump_generic_node (buffer, gimple_oacc_parallel_data_arg (gs),
+			       spc, flags, false);
+	  else
+	    pp_string (buffer, "???");
+	  pp_string (buffer, ")]");
+	}
+      body = gimple_omp_body (gs);
+      if (body && gimple_code (gimple_seq_first_stmt (body)) != GIMPLE_BIND)
+	{
+	  newline_and_indent (buffer, spc + 2);
+	  pp_left_brace (buffer);
+	  pp_newline (buffer);
+	  dump_gimple_seq (buffer, body, spc + 4, flags);
+	  newline_and_indent (buffer, spc + 2);
+	  pp_right_brace (buffer);
+	}
+      else if (body)
+	{
+	  pp_newline (buffer);
+	  dump_gimple_seq (buffer, body, spc + 2, flags);
+	}
+    }
+}
+
+
 /* Dump a GIMPLE_OMP_PARALLEL tuple on the pretty_printer BUFFER, SPC spaces
    of indent.  FLAGS specifies details to show in the dump (see TDF_* in
    dumpfile.h).  */
@@ -2123,6 +2177,10 @@ pp_gimple_stmt_1 (pretty_printer *buffer, gimple gs, int spc, int flags)
       dump_gimple_phi (buffer, gs, spc, false, flags);
       break;
 
+    case GIMPLE_OACC_PARALLEL:
+      dump_gimple_oacc_parallel (buffer, gs, spc, flags);
+      break;
+
     case GIMPLE_OMP_PARALLEL:
       dump_gimple_omp_parallel (buffer, gs, spc, flags);
       break;
diff --git gcc/gimple.c gcc/gimple.c
index 20f6010..ea96d26 100644
--- gcc/gimple.c
+++ gcc/gimple.c
@@ -898,6 +898,23 @@ gimple_build_debug_source_bind_stat (tree var, tree value,
 }
 
 
+/* Build a GIMPLE_OACC_PARALLEL statement.
+
+   BODY is sequence of statements which are executed in parallel.
+   CLAUSES are the OpenACC parallel construct's clauses.  */
+
+gimple
+gimple_build_oacc_parallel (gimple_seq body, tree clauses)
+{
+  gimple p = gimple_alloc (GIMPLE_OACC_PARALLEL, 0);
+  if (body)
+    gimple_omp_set_body (p, body);
+  gimple_oacc_parallel_set_clauses (p, clauses);
+
+  return p;
+}
+
+
 /* Build a GIMPLE_OMP_CRITICAL statement.
 
    BODY is the sequence of statements for which only one thread can execute.
@@ -1571,6 +1588,21 @@ walk_gimple_op (gimple stmt, walk_tree_fn callback_op,
 	return ret;
       break;
 
+    case GIMPLE_OACC_PARALLEL:
+      ret = walk_tree (gimple_oacc_parallel_clauses_ptr (stmt), callback_op,
+		       wi, pset);
+      if (ret)
+	return ret;
+      ret = walk_tree (gimple_oacc_parallel_child_fn_ptr (stmt), callback_op,
+		       wi, pset);
+      if (ret)
+	return ret;
+      ret = walk_tree (gimple_oacc_parallel_data_arg_ptr (stmt), callback_op,
+		       wi, pset);
+      if (ret)
+	return ret;
+      break;
+
     case GIMPLE_OMP_CONTINUE:
       ret = walk_tree (gimple_omp_continue_control_def_ptr (stmt),
 	  	       callback_op, wi, pset);
@@ -1866,6 +1898,7 @@ walk_gimple_stmt (gimple_stmt_iterator *gsi, walk_stmt_fn callback_stmt,
 	return wi->callback_result;
 
       /* FALL THROUGH.  */
+    case GIMPLE_OACC_PARALLEL:
     case GIMPLE_OMP_CRITICAL:
     case GIMPLE_OMP_MASTER:
     case GIMPLE_OMP_TASKGROUP:
@@ -2306,6 +2339,9 @@ gimple_copy (gimple stmt)
 	  gimple_try_set_cleanup (copy, new_seq);
 	  break;
 
+	case GIMPLE_OACC_PARALLEL:
+          abort ();
+
 	case GIMPLE_OMP_FOR:
 	  new_seq = gimple_seq_copy (gimple_omp_for_pre_body (stmt));
 	  gimple_omp_for_set_pre_body (copy, new_seq);
diff --git gcc/gimple.def gcc/gimple.def
index 07370ae..9ff9ab3 100644
--- gcc/gimple.def
+++ gcc/gimple.def
@@ -205,10 +205,16 @@ DEFGSCODE(GIMPLE_NOP, "gimple_nop", GSS_BASE)
 
 /* IMPORTANT.
 
-   Do not rearrange any of the GIMPLE_OMP_* codes.  This ordering is
-   exposed by the range check in gimple_omp_subcode().  */
+   Do not rearrange any of the GIMPLE_OACC_* and GIMPLE_OMP_* codes.  This
+   ordering is exposed by the range check in gimple_omp_subcode.  */
 
 
+/* GIMPLE_OACC_PARALLEL <BODY, CLAUSES, CHILD_FN, DATA_ARG> represents
+
+   #pragma acc parallel [CLAUSES]
+   BODY */
+DEFGSCODE(GIMPLE_OACC_PARALLEL, "gimple_oacc_parallel", GSS_OMP_PARALLEL)
+
 /* Tuples used for lowering of OMP_ATOMIC.  Although the form of the OMP_ATOMIC
    expression is very simple (just in form mem op= expr), various implicit
    conversions may cause the expression to become more complex, so that it does
diff --git gcc/gimple.h gcc/gimple.h
index b34424c..c9be1c9 100644
--- gcc/gimple.h
+++ gcc/gimple.h
@@ -786,6 +786,7 @@ gimple gimple_build_resx (int);
 gimple gimple_build_eh_dispatch (int);
 gimple gimple_build_switch_nlabels (unsigned, tree, tree);
 gimple gimple_build_switch (tree, tree, vec<tree> );
+gimple gimple_build_oacc_parallel (gimple_seq, tree);
 gimple gimple_build_omp_parallel (gimple_seq, tree, tree, tree);
 gimple gimple_build_omp_task (gimple_seq, tree, tree, tree, tree, tree, tree);
 gimple gimple_build_omp_for (gimple_seq, int, tree, size_t, gimple_seq);
@@ -1256,6 +1257,7 @@ gimple_has_substatements (gimple g)
     case GIMPLE_EH_FILTER:
     case GIMPLE_EH_ELSE:
     case GIMPLE_TRY:
+    case GIMPLE_OACC_PARALLEL:
     case GIMPLE_OMP_FOR:
     case GIMPLE_OMP_MASTER:
     case GIMPLE_OMP_TASKGROUP:
@@ -4061,6 +4063,92 @@ gimple_omp_set_body (gimple gs, gimple_seq body)
 }
 
 
+/* Return the clauses associated with OACC_PARALLEL statement GS.  */
+
+static inline tree
+gimple_oacc_parallel_clauses (const_gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OACC_PARALLEL);
+  return gs->gimple_omp_parallel.clauses;
+}
+
+/* Return a pointer to the clauses associated with OACC_PARALLEL statement
+   GS.  */
+
+static inline tree *
+gimple_oacc_parallel_clauses_ptr (gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OACC_PARALLEL);
+  return &gs->gimple_omp_parallel.clauses;
+}
+
+/* Set CLAUSES to be the list of clauses associated with OACC_PARALLEL
+   statement GS.  */
+
+static inline void
+gimple_oacc_parallel_set_clauses (gimple gs, tree clauses)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OACC_PARALLEL);
+  gs->gimple_omp_parallel.clauses = clauses;
+}
+
+/* Return the child function used to hold the body of OACC_PARALLEL statement
+   GS.  */
+
+static inline tree
+gimple_oacc_parallel_child_fn (const_gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OACC_PARALLEL);
+  return gs->gimple_omp_parallel.child_fn;
+}
+
+/* Return a pointer to the child function used to hold the body of
+   OACC_PARALLEL statement GS.  */
+
+static inline tree *
+gimple_oacc_parallel_child_fn_ptr (gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OACC_PARALLEL);
+  return &gs->gimple_omp_parallel.child_fn;
+}
+
+/* Set CHILD_FN to be the child function for OACC_PARALLEL statement GS.  */
+
+static inline void
+gimple_oacc_parallel_set_child_fn (gimple gs, tree child_fn)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OACC_PARALLEL);
+  gs->gimple_omp_parallel.child_fn = child_fn;
+}
+
+/* Return the data argument for OACC_PARALLEL statement GS.  */
+
+static inline tree
+gimple_oacc_parallel_data_arg (const_gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OACC_PARALLEL);
+  return gs->gimple_omp_parallel.data_arg;
+}
+
+/* Return a pointer to the data argument for OACC_PARALLEL statement GS.  */
+
+static inline tree *
+gimple_oacc_parallel_data_arg_ptr (gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OACC_PARALLEL);
+  return &gs->gimple_omp_parallel.data_arg;
+}
+
+/* Set DATA_ARG to be the data argument for OACC_PARALLEL statement GS.  */
+
+static inline void
+gimple_oacc_parallel_set_data_arg (gimple gs, tree data_arg)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OACC_PARALLEL);
+  gs->gimple_omp_parallel.data_arg = data_arg;
+}
+
+
 /* Return the name associated with OMP_CRITICAL statement GS.  */
 
 static inline tree
@@ -5269,6 +5357,7 @@ gimple_return_set_retbnd (gimple gs, tree retval)
 /* Returns true when the gimple statement STMT is any of the OpenMP types.  */
 
 #define CASE_GIMPLE_OMP				\
+    case GIMPLE_OACC_PARALLEL:			\
     case GIMPLE_OMP_PARALLEL:			\
     case GIMPLE_OMP_TASK:			\
     case GIMPLE_OMP_FOR:			\
diff --git gcc/gimplify.c gcc/gimplify.c
index 30c2b45..0c45729 100644
--- gcc/gimplify.c
+++ gcc/gimplify.c
@@ -4641,6 +4641,7 @@ is_gimple_stmt (tree t)
     case CATCH_EXPR:
     case ASM_EXPR:
     case STATEMENT_LIST:
+    case OACC_PARALLEL:
     case OMP_PARALLEL:
     case OMP_FOR:
     case OMP_SIMD:
@@ -6745,6 +6746,37 @@ gimplify_adjust_omp_clauses (tree *list_p)
   delete_omp_context (ctx);
 }
 
+/* Gimplify the contents of an OACC_PARALLEL statement.  This involves
+   gimplification of the body, as well as scanning the body for used
+   variables.  We need to do this scan now, because variable-sized
+   decls will be decomposed during gimplification.  */
+
+static void
+gimplify_oacc_parallel (tree *expr_p, gimple_seq *pre_p)
+{
+  tree expr = *expr_p;
+  gimple g;
+  gimple_seq body = NULL;
+  struct gimplify_ctx gctx;
+
+  gimplify_scan_omp_clauses (&OACC_PARALLEL_CLAUSES (expr), pre_p,
+			     ORT_TARGET);
+
+  push_gimplify_context (&gctx);
+
+  g = gimplify_and_return_first (OACC_PARALLEL_BODY (expr), &body);
+  if (gimple_code (g) == GIMPLE_BIND)
+    pop_gimplify_context (g);
+  else
+    pop_gimplify_context (NULL);
+
+  gimplify_adjust_omp_clauses (&OACC_PARALLEL_CLAUSES (expr));
+
+  g = gimple_build_oacc_parallel (body, OACC_PARALLEL_CLAUSES (expr));
+  gimplify_seq_add_stmt (pre_p, g);
+  *expr_p = NULL_TREE;
+}
+
 /* Gimplify the contents of an OMP_PARALLEL statement.  This involves
    gimplification of the body, as well as scanning the body for used
    variables.  We need to do this scan now, because variable-sized
@@ -8169,6 +8201,11 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
 	  ret = GS_ALL_DONE;
 	  break;
 
+	case OACC_PARALLEL:
+	  gimplify_oacc_parallel (expr_p, pre_p);
+	  ret = GS_ALL_DONE;
+	  break;
+
 	case OMP_PARALLEL:
 	  gimplify_omp_parallel (expr_p, pre_p);
 	  ret = GS_ALL_DONE;
@@ -8575,6 +8612,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
 		  && code != LOOP_EXPR
 		  && code != SWITCH_EXPR
 		  && code != TRY_FINALLY_EXPR
+		  && code != OACC_PARALLEL
 		  && code != OMP_CRITICAL
 		  && code != OMP_FOR
 		  && code != OMP_MASTER
diff --git gcc/oacc-builtins.def gcc/oacc-builtins.def
index fd630e0..a75e42d 100644
--- gcc/oacc-builtins.def
+++ gcc/oacc-builtins.def
@@ -26,3 +26,6 @@ along with GCC; see the file COPYING3.  If not see
      DEF_GOACC_BUILTIN (ENUM, NAME, TYPE, ATTRS)
 
    See builtins.def for details.  */
+
+DEF_GOACC_BUILTIN (BUILT_IN_GOACC_PARALLEL, "GOACC_parallel",
+		   BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR, ATTR_NOTHROW_LIST)
diff --git gcc/omp-low.c gcc/omp-low.c
index 99811d0..84fe466 100644
--- gcc/omp-low.c
+++ gcc/omp-low.c
@@ -844,6 +844,8 @@ use_pointer_for_field (tree decl, omp_context *shared_ctx)
      when we know the value is not accessible from an outer scope.  */
   if (shared_ctx)
     {
+      gcc_assert (gimple_code (shared_ctx->stmt) != GIMPLE_OACC_PARALLEL);
+
       /* ??? Trivially accessible from anywhere.  But why would we even
 	 be passing an address in this case?  Should we simply assert
 	 this to be false, or should we have a cleanup pass that removes
@@ -985,6 +987,8 @@ build_receiver_ref (tree var, bool by_ref, omp_context *ctx)
 static tree
 build_outer_var_ref (tree var, omp_context *ctx)
 {
+  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
+
   tree x;
 
   if (is_global_var (maybe_lookup_decl_in_outer_ctx (var, ctx)))
@@ -1484,6 +1488,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
       switch (OMP_CLAUSE_CODE (c))
 	{
 	case OMP_CLAUSE_PRIVATE:
+	  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	  decl = OMP_CLAUSE_DECL (c);
 	  if (OMP_CLAUSE_PRIVATE_OUTER_REF (c))
 	    goto do_private;
@@ -1492,6 +1497,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 	  break;
 
 	case OMP_CLAUSE_SHARED:
+	  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	  /* Ignore shared directives in teams construct.  */
 	  if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS)
 	    break;
@@ -1518,6 +1524,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 	  goto do_private;
 
 	case OMP_CLAUSE_LASTPRIVATE:
+	  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	  /* Let the corresponding firstprivate clause create
 	     the variable.  */
 	  if (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c))
@@ -1527,6 +1534,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 	case OMP_CLAUSE_FIRSTPRIVATE:
 	case OMP_CLAUSE_REDUCTION:
 	case OMP_CLAUSE_LINEAR:
+	  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	  decl = OMP_CLAUSE_DECL (c);
 	do_private:
 	  if (is_variable_sized (decl))
@@ -1555,6 +1563,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 	  break;
 
 	case OMP_CLAUSE__LOOPTEMP_:
+	  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	  gcc_assert (is_parallel_ctx (ctx));
 	  decl = OMP_CLAUSE_DECL (c);
 	  install_var_field (decl, false, 3, ctx);
@@ -1563,12 +1572,14 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 
 	case OMP_CLAUSE_COPYPRIVATE:
 	case OMP_CLAUSE_COPYIN:
+	  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	  decl = OMP_CLAUSE_DECL (c);
 	  by_ref = use_pointer_for_field (decl, NULL);
 	  install_var_field (decl, by_ref, 3, ctx);
 	  break;
 
 	case OMP_CLAUSE_DEFAULT:
+	  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	  ctx->default_kind = OMP_CLAUSE_DEFAULT_KIND (c);
 	  break;
 
@@ -1581,6 +1592,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 	case OMP_CLAUSE_SCHEDULE:
 	case OMP_CLAUSE_DIST_SCHEDULE:
 	case OMP_CLAUSE_DEPEND:
+	  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	  if (ctx->outer)
 	    scan_omp_op (&OMP_CLAUSE_OPERAND (c, 0), ctx->outer);
 	  break;
@@ -1599,10 +1611,14 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 	      && is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx))
 	      && lookup_attribute ("omp declare target",
 				   DECL_ATTRIBUTES (decl)))
+	    {
+	      gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	    break;
+	    }
 	  if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
 	      && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER)
 	    {
+	      gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	      /* Ignore OMP_CLAUSE_MAP_POINTER kind for arrays in
 		 #pragma omp target data, there is nothing to map for
 		 those.  */
@@ -1632,8 +1648,9 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 		    install_var_field (decl, true, 7, ctx);
 		  else
 		    install_var_field (decl, true, 3, ctx);
-		  if (gimple_omp_target_kind (ctx->stmt)
-		      == GF_OMP_TARGET_KIND_REGION)
+		  if (gimple_code (ctx->stmt) == GIMPLE_OACC_PARALLEL
+		      || (gimple_omp_target_kind (ctx->stmt)
+			  == GF_OMP_TARGET_KIND_REGION))
 		    install_var_local (decl, ctx);
 		}
 	    }
@@ -1673,9 +1690,11 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 	case OMP_CLAUSE_MERGEABLE:
 	case OMP_CLAUSE_PROC_BIND:
 	case OMP_CLAUSE_SAFELEN:
+	  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	  break;
 
 	case OMP_CLAUSE_ALIGNED:
+	  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	  decl = OMP_CLAUSE_DECL (c);
 	  if (is_global_var (decl)
 	      && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
@@ -1692,6 +1711,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
       switch (OMP_CLAUSE_CODE (c))
 	{
 	case OMP_CLAUSE_LASTPRIVATE:
+	  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	  /* Let the corresponding firstprivate clause create
 	     the variable.  */
 	  if (OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c))
@@ -1704,6 +1724,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 	case OMP_CLAUSE_FIRSTPRIVATE:
 	case OMP_CLAUSE_REDUCTION:
 	case OMP_CLAUSE_LINEAR:
+	  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	  decl = OMP_CLAUSE_DECL (c);
 	  if (is_variable_sized (decl))
 	    install_var_local (decl, ctx);
@@ -1716,6 +1737,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 	  break;
 
 	case OMP_CLAUSE_SHARED:
+	  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	  /* Ignore shared directives in teams construct.  */
 	  if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS)
 	    break;
@@ -1725,14 +1747,18 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 	  break;
 
 	case OMP_CLAUSE_MAP:
-	  if (gimple_omp_target_kind (ctx->stmt) == GF_OMP_TARGET_KIND_DATA)
+	  if (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL
+	      && gimple_omp_target_kind (ctx->stmt) == GF_OMP_TARGET_KIND_DATA)
 	    break;
 	  decl = OMP_CLAUSE_DECL (c);
 	  if (DECL_P (decl)
 	      && is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx))
 	      && lookup_attribute ("omp declare target",
 				   DECL_ATTRIBUTES (decl)))
+	    {
+	      gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	    break;
+	    }
 	  if (DECL_P (decl))
 	    {
 	      if (OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER
@@ -1781,6 +1807,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 	case OMP_CLAUSE__LOOPTEMP_:
 	case OMP_CLAUSE_TO:
 	case OMP_CLAUSE_FROM:
+	  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	  break;
 
 	default:
@@ -1789,6 +1816,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
     }
 
   if (scan_array_reductions)
+    {
+      gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
     for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
       if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
 	  && OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
@@ -1799,6 +1828,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
       else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
 	       && OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c))
 	scan_omp (&OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c), ctx);
+    }
 }
 
 /* Create a new name for omp child function.  Returns an identifier.  */
@@ -1830,6 +1860,8 @@ create_omp_child_function (omp_context *ctx, bool task_copy)
   decl = build_decl (gimple_location (ctx->stmt),
 		     FUNCTION_DECL, name, type);
 
+  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL
+	      || !task_copy);
   if (!task_copy)
     ctx->cb.dst_fn = decl;
   else
@@ -1861,6 +1893,8 @@ create_omp_child_function (omp_context *ctx, bool task_copy)
 	    break;
 	  }
     }
+  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL
+	      || !target_p);
   if (target_p)
     DECL_ATTRIBUTES (decl)
       = tree_cons (get_identifier ("omp declare target"),
@@ -1935,6 +1969,52 @@ find_combined_for (gimple_stmt_iterator *gsi_p,
   return NULL;
 }
 
+/* Scan an OpenACC parallel directive.  */
+
+static void
+scan_oacc_parallel (gimple stmt, omp_context *outer_ctx)
+{
+  omp_context *ctx;
+  tree name;
+
+  gcc_assert (taskreg_nesting_level == 0);
+  gcc_assert (target_nesting_level == 0);
+
+  ctx = new_omp_context (stmt, outer_ctx);
+  ctx->field_map = splay_tree_new (splay_tree_compare_pointers, 0, 0);
+  ctx->default_kind = OMP_CLAUSE_DEFAULT_SHARED;
+  ctx->record_type = lang_hooks.types.make_type (RECORD_TYPE);
+  name = create_tmp_var_name (".omp_data_t");
+  name = build_decl (gimple_location (stmt),
+		     TYPE_DECL, name, ctx->record_type);
+  DECL_ARTIFICIAL (name) = 1;
+  DECL_NAMELESS (name) = 1;
+  TYPE_NAME (ctx->record_type) = name;
+  create_omp_child_function (ctx, false);
+  gimple_oacc_parallel_set_child_fn (stmt, ctx->cb.dst_fn);
+
+  scan_sharing_clauses (gimple_oacc_parallel_clauses (stmt), ctx);
+  scan_omp (gimple_omp_body_ptr (stmt), ctx);
+
+  if (TYPE_FIELDS (ctx->record_type) == NULL)
+    ctx->record_type = ctx->receiver_decl = NULL;
+  else
+    {
+      TYPE_FIELDS (ctx->record_type)
+	= nreverse (TYPE_FIELDS (ctx->record_type));
+#ifdef ENABLE_CHECKING
+      tree field;
+      unsigned int align = DECL_ALIGN (TYPE_FIELDS (ctx->record_type));
+      for (field = TYPE_FIELDS (ctx->record_type);
+	   field;
+	   field = DECL_CHAIN (field))
+	gcc_assert (DECL_ALIGN (field) == align);
+#endif
+      layout_type (ctx->record_type);
+      fixup_child_record_type (ctx);
+    }
+}
+
 /* Scan an OpenMP parallel directive.  */
 
 static void
@@ -2225,6 +2305,38 @@ scan_omp_teams (gimple stmt, omp_context *outer_ctx)
 static bool
 check_omp_nesting_restrictions (gimple stmt, omp_context *ctx)
 {
+  omp_context *ctx_;
+
+  /* TODO: While the OpenACC specification does allow for certain kinds of
+     nesting, we don't support that yet.  */
+  /* No nesting of STMT (which is an OpenACC or OpenMP one, or a GOMP builtin)
+     inside any OpenACC CTX.  */
+  for (ctx_ = ctx; ctx_ != NULL; ctx_ = ctx_->outer)
+    switch (gimple_code (ctx_->stmt))
+      {
+      case GIMPLE_OACC_PARALLEL:
+	error_at (gimple_location (stmt),
+		  "may not be nested");
+	return false;
+      default:
+	break;
+      }
+  /* No nesting of OpenACC STMT inside any OpenACC or OpenMP CTX.  */
+  switch (gimple_code (stmt))
+    {
+    case GIMPLE_OACC_PARALLEL:
+      for (ctx_ = ctx; ctx_ != NULL; ctx_ = ctx_->outer)
+	if (is_gimple_omp (ctx_->stmt))
+	  {
+	    error_at (gimple_location (stmt),
+		      "may not be nested");
+	    return false;
+	  }
+      break;
+    default:
+      break;
+    }
+
   if (ctx != NULL)
     {
       if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR
@@ -2584,6 +2696,10 @@ scan_omp_1_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
 
   switch (gimple_code (stmt))
     {
+    case GIMPLE_OACC_PARALLEL:
+      scan_oacc_parallel (stmt, ctx);
+      break;
+
     case GIMPLE_OMP_PARALLEL:
       taskreg_nesting_level++;
       scan_omp_parallel (gsi, ctx);
@@ -2910,6 +3026,8 @@ static bool
 lower_rec_simd_input_clauses (tree new_var, omp_context *ctx, int &max_vf,
 			      tree &idx, tree &lane, tree &ivar, tree &lvar)
 {
+  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
+
   if (max_vf == 0)
     {
       max_vf = omp_max_vf ();
@@ -2959,6 +3077,8 @@ static void
 lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
 			 omp_context *ctx, struct omp_for_data *fd)
 {
+  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
+
   tree c, dtor, copyin_seq, x, ptr;
   bool copyin_by_ref = false;
   bool lastprivate_firstprivate = false;
@@ -3617,6 +3737,8 @@ static void
 lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *stmt_list,
 			   omp_context *ctx)
 {
+  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
+
   tree x, c, label = NULL, orig_clauses = clauses;
   bool par_clauses = false;
   tree simduid = NULL, lastlane = NULL;
@@ -3752,6 +3874,8 @@ lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *stmt_list,
 static void
 lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp, omp_context *ctx)
 {
+  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
+
   gimple_seq sub_seq = NULL;
   gimple stmt;
   tree x, c;
@@ -3853,6 +3977,8 @@ static void
 lower_copyprivate_clauses (tree clauses, gimple_seq *slist, gimple_seq *rlist,
 			    omp_context *ctx)
 {
+  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
+
   tree c;
 
   for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
@@ -3903,6 +4029,8 @@ static void
 lower_send_clauses (tree clauses, gimple_seq *ilist, gimple_seq *olist,
     		    omp_context *ctx)
 {
+  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
+
   tree c;
 
   for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
@@ -3994,6 +4122,8 @@ lower_send_clauses (tree clauses, gimple_seq *ilist, gimple_seq *olist,
 static void
 lower_send_shared_vars (gimple_seq *ilist, gimple_seq *olist, omp_context *ctx)
 {
+  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
+
   tree var, ovar, nvar, f, x, record_type;
 
   if (ctx->record_type == NULL)
@@ -4542,10 +4672,10 @@ expand_omp_build_assign (gimple_stmt_iterator *gsi_p, tree to, tree from)
     }
 }
 
-/* Expand the OpenMP parallel or task directive starting at REGION.  */
+/* Expand the OpenACC parallel directive starting at REGION.  */
 
 static void
-expand_omp_taskreg (struct omp_region *region)
+expand_oacc_parallel (struct omp_region *region)
 {
   basic_block entry_bb, exit_bb, new_bb;
   struct function *child_cfun;
@@ -4553,44 +4683,20 @@ expand_omp_taskreg (struct omp_region *region)
   gimple_stmt_iterator gsi;
   gimple entry_stmt, stmt;
   edge e;
-  vec<tree, va_gc> *ws_args;
 
   entry_stmt = last_stmt (region->entry);
-  child_fn = gimple_omp_taskreg_child_fn (entry_stmt);
+  child_fn = gimple_oacc_parallel_child_fn (entry_stmt);
   child_cfun = DECL_STRUCT_FUNCTION (child_fn);
 
+  /* Supported by expand_omp_taskreg, but not here.  */
+  gcc_assert (!child_cfun->cfg);
+  gcc_assert (!gimple_in_ssa_p (cfun));
+
   entry_bb = region->entry;
   exit_bb = region->exit;
 
-  if (is_combined_parallel (region))
-    ws_args = region->ws_args;
-  else
-    ws_args = NULL;
-
-  if (child_cfun->cfg)
-    {
-      /* Due to inlining, it may happen that we have already outlined
-	 the region, in which case all we need to do is make the
-	 sub-graph unreachable and emit the parallel call.  */
-      edge entry_succ_e, exit_succ_e;
-      gimple_stmt_iterator gsi;
-
-      entry_succ_e = single_succ_edge (entry_bb);
-
-      gsi = gsi_last_bb (entry_bb);
-      gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_PARALLEL
-		  || gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_TASK);
-      gsi_remove (&gsi, true);
-
-      new_bb = entry_bb;
-      if (exit_bb)
-	{
-	  exit_succ_e = single_succ_edge (exit_bb);
-	  make_edge (new_bb, exit_succ_e->dest, EDGE_FALLTHRU);
-	}
-      remove_edge_and_dominated_blocks (entry_succ_e);
-    }
-  else
+  /* Preserve indentation of expand_omp_target and expand_omp_taskreg.  */
+  if (1)
     {
       unsigned srcidx, dstidx, num;
 
@@ -4607,17 +4713,17 @@ expand_omp_taskreg (struct omp_region *region)
 	 a function call that has been inlined, the original PARM_DECL
 	 .OMP_DATA_I may have been converted into a different local
 	 variable.  In which case, we need to keep the assignment.  */
-      if (gimple_omp_taskreg_data_arg (entry_stmt))
+      if (gimple_oacc_parallel_data_arg (entry_stmt))
 	{
 	  basic_block entry_succ_bb = single_succ (entry_bb);
 	  gimple_stmt_iterator gsi;
-	  tree arg, narg;
+	  tree arg;
 	  gimple parcopy_stmt = NULL;
+	  tree sender
+	    = TREE_VEC_ELT (gimple_oacc_parallel_data_arg (entry_stmt), 0);
 
 	  for (gsi = gsi_start_bb (entry_succ_bb); ; gsi_next (&gsi))
 	    {
-	      gimple stmt;
-
 	      gcc_assert (!gsi_end_p (gsi));
 	      stmt = gsi_stmt (gsi);
 	      if (gimple_code (stmt) != GIMPLE_ASSIGN)
@@ -4631,8 +4737,7 @@ expand_omp_taskreg (struct omp_region *region)
 		     effectively doing a STRIP_NOPS.  */
 
 		  if (TREE_CODE (arg) == ADDR_EXPR
-		      && TREE_OPERAND (arg, 0)
-		        == gimple_omp_taskreg_data_arg (entry_stmt))
+		      && TREE_OPERAND (arg, 0) == sender)
 		    {
 		      parcopy_stmt = stmt;
 		      break;
@@ -4643,36 +4748,14 @@ expand_omp_taskreg (struct omp_region *region)
 	  gcc_assert (parcopy_stmt != NULL);
 	  arg = DECL_ARGUMENTS (child_fn);
 
-	  if (!gimple_in_ssa_p (cfun))
-	    {
-	      if (gimple_assign_lhs (parcopy_stmt) == arg)
-		gsi_remove (&gsi, true);
-	      else
-		{
-	          /* ?? Is setting the subcode really necessary ??  */
-		  gimple_omp_set_subcode (parcopy_stmt, TREE_CODE (arg));
-		  gimple_assign_set_rhs1 (parcopy_stmt, arg);
-		}
-	    }
-	  else
-	    {
-	      /* If we are in ssa form, we must load the value from the default
-		 definition of the argument.  That should not be defined now,
-		 since the argument is not used uninitialized.  */
-	      gcc_assert (ssa_default_def (cfun, arg) == NULL);
-	      narg = make_ssa_name (arg, gimple_build_nop ());
-	      set_ssa_default_def (cfun, arg, narg);
-	      /* ?? Is setting the subcode really necessary ??  */
-	      gimple_omp_set_subcode (parcopy_stmt, TREE_CODE (narg));
-	      gimple_assign_set_rhs1 (parcopy_stmt, narg);
-	      update_stmt (parcopy_stmt);
-	    }
+	  gcc_assert (gimple_assign_lhs (parcopy_stmt) == arg);
+	  gsi_remove (&gsi, true);
 	}
 
       /* Declare local variables needed in CHILD_CFUN.  */
       block = DECL_INITIAL (child_fn);
       BLOCK_VARS (block) = vec2chain (child_cfun->local_decls);
-      /* The gimplifier could record temporaries in parallel/task block
+      /* The gimplifier could record temporaries in the block
 	 rather than in containing function's local_decls chain,
 	 which would mean cgraph missed finalizing them.  Do it now.  */
       for (t = BLOCK_VARS (block); t; t = DECL_CHAIN (t))
@@ -4689,12 +4772,11 @@ expand_omp_taskreg (struct omp_region *region)
       for (t = DECL_ARGUMENTS (child_fn); t; t = DECL_CHAIN (t))
 	DECL_CONTEXT (t) = child_fn;
 
-      /* Split ENTRY_BB at GIMPLE_OMP_PARALLEL or GIMPLE_OMP_TASK,
+      /* Split ENTRY_BB at GIMPLE_OACC_PARALLEL,
 	 so that it can be moved to the child function.  */
       gsi = gsi_last_bb (entry_bb);
       stmt = gsi_stmt (gsi);
-      gcc_assert (stmt && (gimple_code (stmt) == GIMPLE_OMP_PARALLEL
-			   || gimple_code (stmt) == GIMPLE_OMP_TASK));
+      gcc_assert (stmt && (gimple_code (stmt) == GIMPLE_OACC_PARALLEL));
       gsi_remove (&gsi, true);
       e = split_block (entry_bb, stmt);
       entry_bb = e->dest;
@@ -4711,22 +4793,14 @@ expand_omp_taskreg (struct omp_region *region)
 	  gsi_remove (&gsi, true);
 	}
 
-      /* Move the parallel region into CHILD_CFUN.  */
+      /* Move the region into CHILD_CFUN.  */
 
-      if (gimple_in_ssa_p (cfun))
-	{
-	  init_tree_ssa (child_cfun);
-	  init_ssa_operands (child_cfun);
-	  child_cfun->gimple_df->in_ssa_p = true;
-	  block = NULL_TREE;
-	}
-      else
-	block = gimple_block (entry_stmt);
+      block = gimple_block (entry_stmt);
 
       new_bb = move_sese_region_to_fn (child_cfun, entry_bb, exit_bb, block);
       if (exit_bb)
 	single_succ_edge (new_bb)->flags = EDGE_FALLTHRU;
-      /* When the OMP expansion process cannot guarantee an up-to-date
+      /* When the expansion process cannot guarantee an up-to-date
          loop tree arrange for the child function to fixup loops.  */
       if (loops_state_satisfies_p (LOOPS_NEED_FIXUP))
 	child_cfun->x_current_loops->state |= LOOPS_NEED_FIXUP;
@@ -4752,8 +4826,6 @@ expand_omp_taskreg (struct omp_region *region)
       /* Fix the callgraph edges for child_cfun.  Those for cfun will be
 	 fixed in a following pass.  */
       push_cfun (child_cfun);
-      if (optimize)
-	optimize_omp_library_calls (entry_stmt);
       rebuild_cgraph_edges ();
 
       /* Some EH regions might become dead, see PR34608.  If
@@ -4770,73 +4842,359 @@ expand_omp_taskreg (struct omp_region *region)
 	  if (changed)
 	    cleanup_tree_cfg ();
 	}
-      if (gimple_in_ssa_p (cfun))
-	update_ssa (TODO_update_ssa);
       pop_cfun ();
     }
 
-  /* Emit a library call to launch the children threads.  */
-  if (gimple_code (entry_stmt) == GIMPLE_OMP_PARALLEL)
-    expand_parallel_call (region, new_bb, entry_stmt, ws_args);
-  else
-    expand_task_call (new_bb, entry_stmt);
-  if (gimple_in_ssa_p (cfun))
-    update_ssa (TODO_update_ssa_only_virtuals);
-}
+  /* Emit a library call to launch CHILD_FN.  */
+  tree t1, t2, t3, t4, device, c, clauses;
+  enum built_in_function start_ix;
+  location_t clause_loc;
 
+  clauses = gimple_oacc_parallel_clauses (entry_stmt);
 
-/* Helper function for expand_omp_{for_*,simd}.  If this is the outermost
-   of the combined collapse > 1 loop constructs, generate code like:
-	if (__builtin_expect (N32 cond3 N31, 0)) goto ZERO_ITER_BB;
-	if (cond3 is <)
-	  adj = STEP3 - 1;
-	else
-	  adj = STEP3 + 1;
-	count3 = (adj + N32 - N31) / STEP3;
-	if (__builtin_expect (N22 cond2 N21, 0)) goto ZERO_ITER_BB;
-	if (cond2 is <)
-	  adj = STEP2 - 1;
-	else
-	  adj = STEP2 + 1;
-	count2 = (adj + N22 - N21) / STEP2;
-	if (__builtin_expect (N12 cond1 N11, 0)) goto ZERO_ITER_BB;
-	if (cond1 is <)
-	  adj = STEP1 - 1;
-	else
-	  adj = STEP1 + 1;
-	count1 = (adj + N12 - N11) / STEP1;
-	count = count1 * count2 * count3;
-   Furthermore, if ZERO_ITER_BB is NULL, create a BB which does:
-	count = 0;
-   and set ZERO_ITER_BB to that bb.  If this isn't the outermost
-   of the combined loop constructs, just initialize COUNTS array
-   from the _looptemp_ clauses.  */
+  start_ix = BUILT_IN_GOACC_PARALLEL;
 
-/* NOTE: It *could* be better to moosh all of the BBs together,
-   creating one larger BB with all the computation and the unexpected
-   jump at the end.  I.e.
+  /* By default, the value of DEVICE is -1 (let runtime library choose).  */
+  device = build_int_cst (integer_type_node, -1);
 
-   bool zero3, zero2, zero1, zero;
+  c = find_omp_clause (clauses, OMP_CLAUSE_DEVICE);
+  gcc_assert (c == NULL);
+  if (c)
+    {
+      device = OMP_CLAUSE_DEVICE_ID (c);
+      clause_loc = OMP_CLAUSE_LOCATION (c);
+    }
+  else
+    clause_loc = gimple_location (entry_stmt);
 
-   zero3 = N32 c3 N31;
-   count3 = (N32 - N31) /[cl] STEP3;
-   zero2 = N22 c2 N21;
-   count2 = (N22 - N21) /[cl] STEP2;
-   zero1 = N12 c1 N11;
-   count1 = (N12 - N11) /[cl] STEP1;
-   zero = zero3 || zero2 || zero1;
-   count = count1 * count2 * count3;
-   if (__builtin_expect(zero, false)) goto zero_iter_bb;
+  /* Ensure 'device' is of the correct type.  */
+  device = fold_convert_loc (clause_loc, integer_type_node, device);
 
-   After all, we expect the zero=false, and thus we expect to have to
-   evaluate all of the comparison expressions, so short-circuiting
-   oughtn't be a win.  Since the condition isn't protecting a
-   denominator, we're not concerned about divide-by-zero, so we can
-   fully evaluate count even if a numerator turned out to be wrong.
+  gsi = gsi_last_bb (new_bb);
+  t = gimple_oacc_parallel_data_arg (entry_stmt);
+  if (t == NULL)
+    {
+      t1 = size_zero_node;
+      t2 = build_zero_cst (ptr_type_node);
+      t3 = t2;
+      t4 = t2;
+    }
+  else
+    {
+      t1 = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (TREE_VEC_ELT (t, 1))));
+      t1 = size_binop (PLUS_EXPR, t1, size_int (1));
+      t2 = build_fold_addr_expr (TREE_VEC_ELT (t, 0));
+      t3 = build_fold_addr_expr (TREE_VEC_ELT (t, 1));
+      t4 = build_fold_addr_expr (TREE_VEC_ELT (t, 2));
+    }
 
-   It seems like putting this all together would create much better
-   scheduling opportunities, and less pressure on the chip's branch
-   predictor.  */
+  gimple g;
+  /* FIXME: This will be address of
+     extern char __OPENMP_TARGET__[] __attribute__((visibility ("hidden")))
+     symbol, as soon as the linker plugin is able to create it for us.  */
+  tree openmp_target = build_zero_cst (ptr_type_node);
+  tree fnaddr = build_fold_addr_expr (child_fn);
+  g = gimple_build_call (builtin_decl_explicit (start_ix),
+			 7, device, fnaddr, openmp_target, t1, t2, t3, t4);
+  gimple_set_location (g, gimple_location (entry_stmt));
+  gsi_insert_before (&gsi, g, GSI_SAME_STMT);
+}
+
+/* Expand the OpenMP parallel or task directive starting at REGION.  */
+
+static void
+expand_omp_taskreg (struct omp_region *region)
+{
+  basic_block entry_bb, exit_bb, new_bb;
+  struct function *child_cfun;
+  tree child_fn, block, t;
+  gimple_stmt_iterator gsi;
+  gimple entry_stmt, stmt;
+  edge e;
+  vec<tree, va_gc> *ws_args;
+
+  entry_stmt = last_stmt (region->entry);
+  child_fn = gimple_omp_taskreg_child_fn (entry_stmt);
+  child_cfun = DECL_STRUCT_FUNCTION (child_fn);
+
+  entry_bb = region->entry;
+  exit_bb = region->exit;
+
+  if (is_combined_parallel (region))
+    ws_args = region->ws_args;
+  else
+    ws_args = NULL;
+
+  if (child_cfun->cfg)
+    {
+      /* Due to inlining, it may happen that we have already outlined
+	 the region, in which case all we need to do is make the
+	 sub-graph unreachable and emit the parallel call.  */
+      edge entry_succ_e, exit_succ_e;
+      gimple_stmt_iterator gsi;
+
+      entry_succ_e = single_succ_edge (entry_bb);
+
+      gsi = gsi_last_bb (entry_bb);
+      gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_PARALLEL
+		  || gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_TASK);
+      gsi_remove (&gsi, true);
+
+      new_bb = entry_bb;
+      if (exit_bb)
+	{
+	  exit_succ_e = single_succ_edge (exit_bb);
+	  make_edge (new_bb, exit_succ_e->dest, EDGE_FALLTHRU);
+	}
+      remove_edge_and_dominated_blocks (entry_succ_e);
+    }
+  else
+    {
+      unsigned srcidx, dstidx, num;
+
+      /* If the parallel region needs data sent from the parent
+	 function, then the very first statement (except possible
+	 tree profile counter updates) of the parallel body
+	 is a copy assignment .OMP_DATA_I = &.OMP_DATA_O.  Since
+	 &.OMP_DATA_O is passed as an argument to the child function,
+	 we need to replace it with the argument as seen by the child
+	 function.
+
+	 In most cases, this will end up being the identity assignment
+	 .OMP_DATA_I = .OMP_DATA_I.  However, if the parallel body had
+	 a function call that has been inlined, the original PARM_DECL
+	 .OMP_DATA_I may have been converted into a different local
+	 variable.  In which case, we need to keep the assignment.  */
+      if (gimple_omp_taskreg_data_arg (entry_stmt))
+	{
+	  basic_block entry_succ_bb = single_succ (entry_bb);
+	  gimple_stmt_iterator gsi;
+	  tree arg, narg;
+	  gimple parcopy_stmt = NULL;
+
+	  for (gsi = gsi_start_bb (entry_succ_bb); ; gsi_next (&gsi))
+	    {
+	      gimple stmt;
+
+	      gcc_assert (!gsi_end_p (gsi));
+	      stmt = gsi_stmt (gsi);
+	      if (gimple_code (stmt) != GIMPLE_ASSIGN)
+		continue;
+
+	      if (gimple_num_ops (stmt) == 2)
+		{
+		  tree arg = gimple_assign_rhs1 (stmt);
+
+		  /* We're ignore the subcode because we're
+		     effectively doing a STRIP_NOPS.  */
+
+		  if (TREE_CODE (arg) == ADDR_EXPR
+		      && TREE_OPERAND (arg, 0)
+		        == gimple_omp_taskreg_data_arg (entry_stmt))
+		    {
+		      parcopy_stmt = stmt;
+		      break;
+		    }
+		}
+	    }
+
+	  gcc_assert (parcopy_stmt != NULL);
+	  arg = DECL_ARGUMENTS (child_fn);
+
+	  if (!gimple_in_ssa_p (cfun))
+	    {
+	      if (gimple_assign_lhs (parcopy_stmt) == arg)
+		gsi_remove (&gsi, true);
+	      else
+		{
+	          /* ?? Is setting the subcode really necessary ??  */
+		  gimple_omp_set_subcode (parcopy_stmt, TREE_CODE (arg));
+		  gimple_assign_set_rhs1 (parcopy_stmt, arg);
+		}
+	    }
+	  else
+	    {
+	      /* If we are in ssa form, we must load the value from the default
+		 definition of the argument.  That should not be defined now,
+		 since the argument is not used uninitialized.  */
+	      gcc_assert (ssa_default_def (cfun, arg) == NULL);
+	      narg = make_ssa_name (arg, gimple_build_nop ());
+	      set_ssa_default_def (cfun, arg, narg);
+	      /* ?? Is setting the subcode really necessary ??  */
+	      gimple_omp_set_subcode (parcopy_stmt, TREE_CODE (narg));
+	      gimple_assign_set_rhs1 (parcopy_stmt, narg);
+	      update_stmt (parcopy_stmt);
+	    }
+	}
+
+      /* Declare local variables needed in CHILD_CFUN.  */
+      block = DECL_INITIAL (child_fn);
+      BLOCK_VARS (block) = vec2chain (child_cfun->local_decls);
+      /* The gimplifier could record temporaries in parallel/task block
+	 rather than in containing function's local_decls chain,
+	 which would mean cgraph missed finalizing them.  Do it now.  */
+      for (t = BLOCK_VARS (block); t; t = DECL_CHAIN (t))
+	if (TREE_CODE (t) == VAR_DECL
+	    && TREE_STATIC (t)
+	    && !DECL_EXTERNAL (t))
+	  varpool_finalize_decl (t);
+      DECL_SAVED_TREE (child_fn) = NULL;
+      /* We'll create a CFG for child_fn, so no gimple body is needed.  */
+      gimple_set_body (child_fn, NULL);
+      TREE_USED (block) = 1;
+
+      /* Reset DECL_CONTEXT on function arguments.  */
+      for (t = DECL_ARGUMENTS (child_fn); t; t = DECL_CHAIN (t))
+	DECL_CONTEXT (t) = child_fn;
+
+      /* Split ENTRY_BB at GIMPLE_OMP_PARALLEL or GIMPLE_OMP_TASK,
+	 so that it can be moved to the child function.  */
+      gsi = gsi_last_bb (entry_bb);
+      stmt = gsi_stmt (gsi);
+      gcc_assert (stmt && (gimple_code (stmt) == GIMPLE_OMP_PARALLEL
+			   || gimple_code (stmt) == GIMPLE_OMP_TASK));
+      gsi_remove (&gsi, true);
+      e = split_block (entry_bb, stmt);
+      entry_bb = e->dest;
+      single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
+
+      /* Convert GIMPLE_OMP_RETURN into a RETURN_EXPR.  */
+      if (exit_bb)
+	{
+	  gsi = gsi_last_bb (exit_bb);
+	  gcc_assert (!gsi_end_p (gsi)
+		      && gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
+	  stmt = gimple_build_return (NULL);
+	  gsi_insert_after (&gsi, stmt, GSI_SAME_STMT);
+	  gsi_remove (&gsi, true);
+	}
+
+      /* Move the parallel region into CHILD_CFUN.  */
+
+      if (gimple_in_ssa_p (cfun))
+	{
+	  init_tree_ssa (child_cfun);
+	  init_ssa_operands (child_cfun);
+	  child_cfun->gimple_df->in_ssa_p = true;
+	  block = NULL_TREE;
+	}
+      else
+	block = gimple_block (entry_stmt);
+
+      new_bb = move_sese_region_to_fn (child_cfun, entry_bb, exit_bb, block);
+      if (exit_bb)
+	single_succ_edge (new_bb)->flags = EDGE_FALLTHRU;
+      /* When the OMP expansion process cannot guarantee an up-to-date
+         loop tree arrange for the child function to fixup loops.  */
+      if (loops_state_satisfies_p (LOOPS_NEED_FIXUP))
+	child_cfun->x_current_loops->state |= LOOPS_NEED_FIXUP;
+
+      /* Remove non-local VAR_DECLs from child_cfun->local_decls list.  */
+      num = vec_safe_length (child_cfun->local_decls);
+      for (srcidx = 0, dstidx = 0; srcidx < num; srcidx++)
+	{
+	  t = (*child_cfun->local_decls)[srcidx];
+	  if (DECL_CONTEXT (t) == cfun->decl)
+	    continue;
+	  if (srcidx != dstidx)
+	    (*child_cfun->local_decls)[dstidx] = t;
+	  dstidx++;
+	}
+      if (dstidx != num)
+	vec_safe_truncate (child_cfun->local_decls, dstidx);
+
+      /* Inform the callgraph about the new function.  */
+      DECL_STRUCT_FUNCTION (child_fn)->curr_properties = cfun->curr_properties;
+      cgraph_add_new_function (child_fn, true);
+
+      /* Fix the callgraph edges for child_cfun.  Those for cfun will be
+	 fixed in a following pass.  */
+      push_cfun (child_cfun);
+      if (optimize)
+	optimize_omp_library_calls (entry_stmt);
+      rebuild_cgraph_edges ();
+
+      /* Some EH regions might become dead, see PR34608.  If
+	 pass_cleanup_cfg isn't the first pass to happen with the
+	 new child, these dead EH edges might cause problems.
+	 Clean them up now.  */
+      if (flag_exceptions)
+	{
+	  basic_block bb;
+	  bool changed = false;
+
+	  FOR_EACH_BB (bb)
+	    changed |= gimple_purge_dead_eh_edges (bb);
+	  if (changed)
+	    cleanup_tree_cfg ();
+	}
+      if (gimple_in_ssa_p (cfun))
+	update_ssa (TODO_update_ssa);
+      pop_cfun ();
+    }
+
+  /* Emit a library call to launch the children threads.  */
+  if (gimple_code (entry_stmt) == GIMPLE_OMP_PARALLEL)
+    expand_parallel_call (region, new_bb, entry_stmt, ws_args);
+  else
+    expand_task_call (new_bb, entry_stmt);
+  if (gimple_in_ssa_p (cfun))
+    update_ssa (TODO_update_ssa_only_virtuals);
+}
+
+
+/* Helper function for expand_omp_{for_*,simd}.  If this is the outermost
+   of the combined collapse > 1 loop constructs, generate code like:
+	if (__builtin_expect (N32 cond3 N31, 0)) goto ZERO_ITER_BB;
+	if (cond3 is <)
+	  adj = STEP3 - 1;
+	else
+	  adj = STEP3 + 1;
+	count3 = (adj + N32 - N31) / STEP3;
+	if (__builtin_expect (N22 cond2 N21, 0)) goto ZERO_ITER_BB;
+	if (cond2 is <)
+	  adj = STEP2 - 1;
+	else
+	  adj = STEP2 + 1;
+	count2 = (adj + N22 - N21) / STEP2;
+	if (__builtin_expect (N12 cond1 N11, 0)) goto ZERO_ITER_BB;
+	if (cond1 is <)
+	  adj = STEP1 - 1;
+	else
+	  adj = STEP1 + 1;
+	count1 = (adj + N12 - N11) / STEP1;
+	count = count1 * count2 * count3;
+   Furthermore, if ZERO_ITER_BB is NULL, create a BB which does:
+	count = 0;
+   and set ZERO_ITER_BB to that bb.  If this isn't the outermost
+   of the combined loop constructs, just initialize COUNTS array
+   from the _looptemp_ clauses.  */
+
+/* NOTE: It *could* be better to moosh all of the BBs together,
+   creating one larger BB with all the computation and the unexpected
+   jump at the end.  I.e.
+
+   bool zero3, zero2, zero1, zero;
+
+   zero3 = N32 c3 N31;
+   count3 = (N32 - N31) /[cl] STEP3;
+   zero2 = N22 c2 N21;
+   count2 = (N22 - N21) /[cl] STEP2;
+   zero1 = N12 c1 N11;
+   count1 = (N12 - N11) /[cl] STEP1;
+   zero = zero3 || zero2 || zero1;
+   count = count1 * count2 * count3;
+   if (__builtin_expect(zero, false)) goto zero_iter_bb;
+
+   After all, we expect the zero=false, and thus we expect to have to
+   evaluate all of the comparison expressions, so short-circuiting
+   oughtn't be a win.  Since the condition isn't protecting a
+   denominator, we're not concerned about divide-by-zero, so we can
+   fully evaluate count even if a numerator turned out to be wrong.
+
+   It seems like putting this all together would create much better
+   scheduling opportunities, and less pressure on the chip's branch
+   predictor.  */
 
 static void
 expand_omp_for_init_counts (struct omp_for_data *fd, gimple_stmt_iterator *gsi,
@@ -8037,6 +8395,10 @@ expand_omp (struct omp_region *region)
 
       switch (region->type)
 	{
+	case GIMPLE_OACC_PARALLEL:
+	  expand_oacc_parallel (region);
+	  break;
+
 	case GIMPLE_OMP_PARALLEL:
 	case GIMPLE_OMP_TASK:
 	  expand_omp_taskreg (region);
@@ -8203,80 +8565,362 @@ build_omp_regions (void)
 
 /* Main entry point for expanding OMP-GIMPLE into runtime calls.  */
 
-static unsigned int
-execute_expand_omp (void)
-{
-  build_omp_regions ();
+static unsigned int
+execute_expand_omp (void)
+{
+  build_omp_regions ();
+
+  if (!root_omp_region)
+    return 0;
+
+  if (dump_file)
+    {
+      fprintf (dump_file, "\nOMP region tree\n\n");
+      dump_omp_region (dump_file, root_omp_region, 0);
+      fprintf (dump_file, "\n");
+    }
+
+  remove_exit_barriers (root_omp_region);
+
+  expand_omp (root_omp_region);
+
+  cleanup_tree_cfg ();
+
+  free_omp_regions ();
+
+  return 0;
+}
+
+/* OMP expansion -- the default pass, run before creation of SSA form.  */
+
+static bool
+gate_expand_omp (void)
+{
+  return ((flag_openacc || flag_openmp)
+	  && !seen_error ());
+}
+
+namespace {
+
+const pass_data pass_data_expand_omp =
+{
+  GIMPLE_PASS, /* type */
+  "ompexp", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  true, /* has_gate */
+  true, /* has_execute */
+  TV_NONE, /* tv_id */
+  PROP_gimple_any, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
+};
+
+class pass_expand_omp : public gimple_opt_pass
+{
+public:
+  pass_expand_omp (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_expand_omp, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  bool gate () { return gate_expand_omp (); }
+  unsigned int execute () { return execute_expand_omp (); }
+
+}; // class pass_expand_omp
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_expand_omp (gcc::context *ctxt)
+{
+  return new pass_expand_omp (ctxt);
+}
+\f
+/* Routines to lower OpenMP directives into OMP-GIMPLE.  */
+
+/* Lower the OpenACC parallel directive in the current statement
+   in GSI_P.  CTX holds context information for the directive.  */
+
+static void
+lower_oacc_parallel (gimple_stmt_iterator *gsi_p, omp_context *ctx)
+{
+  tree clauses;
+  tree child_fn, t, c;
+  gimple stmt = gsi_stmt (*gsi_p);
+  gimple par_bind, bind;
+  gimple_seq par_body, olist, ilist, new_body;
+  struct gimplify_ctx gctx;
+  location_t loc = gimple_location (stmt);
+  unsigned int map_cnt = 0;
+
+  clauses = gimple_oacc_parallel_clauses (stmt);
+  par_bind = gimple_seq_first_stmt (gimple_omp_body (stmt));
+  par_body = gimple_bind_body (par_bind);
+  child_fn = ctx->cb.dst_fn;
+
+  push_gimplify_context (&gctx);
+
+  for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+    switch (OMP_CLAUSE_CODE (c))
+      {
+	tree var, x;
+
+      default:
+	break;
+      case OMP_CLAUSE_MAP:
+      case OMP_CLAUSE_TO:
+      case OMP_CLAUSE_FROM:
+	var = OMP_CLAUSE_DECL (c);
+	if (!DECL_P (var))
+	  {
+	    if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP
+		|| !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c))
+	      map_cnt++;
+	    continue;
+	  }
+
+	if (DECL_SIZE (var)
+	    && TREE_CODE (DECL_SIZE (var)) != INTEGER_CST)
+	  {
+	    tree var2 = DECL_VALUE_EXPR (var);
+	    gcc_assert (TREE_CODE (var2) == INDIRECT_REF);
+	    var2 = TREE_OPERAND (var2, 0);
+	    gcc_assert (DECL_P (var2));
+	    var = var2;
+	  }
+
+	if (!maybe_lookup_field (var, ctx))
+	  continue;
+
+	/* Preserve indentation of lower_omp_target.  */
+	if (1)
+	  {
+	    x = build_receiver_ref (var, true, ctx);
+	    tree new_var = lookup_decl (var, ctx);
+	    if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+		&& OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER
+		&& !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c)
+		&& TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE)
+	      x = build_simple_mem_ref (x);
+	    SET_DECL_VALUE_EXPR (new_var, x);
+	    DECL_HAS_VALUE_EXPR_P (new_var) = 1;
+	  }
+	map_cnt++;
+      }
+
+  target_nesting_level++;
+  lower_omp (&par_body, ctx);
+  target_nesting_level--;
 
-  if (!root_omp_region)
-    return 0;
+  /* Declare all the variables created by mapping and the variables
+     declared in the scope of the body.  */
+  record_vars_into (ctx->block_vars, child_fn);
+  record_vars_into (gimple_bind_vars (par_bind), child_fn);
 
-  if (dump_file)
+  olist = NULL;
+  ilist = NULL;
+  if (ctx->record_type)
     {
-      fprintf (dump_file, "\nOMP region tree\n\n");
-      dump_omp_region (dump_file, root_omp_region, 0);
-      fprintf (dump_file, "\n");
-    }
+      ctx->sender_decl
+	= create_tmp_var (ctx->record_type, ".omp_data_arr");
+      DECL_NAMELESS (ctx->sender_decl) = 1;
+      TREE_ADDRESSABLE (ctx->sender_decl) = 1;
+      t = make_tree_vec (3);
+      TREE_VEC_ELT (t, 0) = ctx->sender_decl;
+      TREE_VEC_ELT (t, 1)
+	= create_tmp_var (build_array_type_nelts (size_type_node, map_cnt),
+			  ".omp_data_sizes");
+      DECL_NAMELESS (TREE_VEC_ELT (t, 1)) = 1;
+      TREE_ADDRESSABLE (TREE_VEC_ELT (t, 1)) = 1;
+      TREE_STATIC (TREE_VEC_ELT (t, 1)) = 1;
+      TREE_VEC_ELT (t, 2)
+	= create_tmp_var (build_array_type_nelts (unsigned_char_type_node,
+						  map_cnt),
+			  ".omp_data_kinds");
+      DECL_NAMELESS (TREE_VEC_ELT (t, 2)) = 1;
+      TREE_ADDRESSABLE (TREE_VEC_ELT (t, 2)) = 1;
+      TREE_STATIC (TREE_VEC_ELT (t, 2)) = 1;
+      gimple_oacc_parallel_set_data_arg (stmt, t);
 
-  remove_exit_barriers (root_omp_region);
+      vec<constructor_elt, va_gc> *vsize;
+      vec<constructor_elt, va_gc> *vkind;
+      vec_alloc (vsize, map_cnt);
+      vec_alloc (vkind, map_cnt);
+      unsigned int map_idx = 0;
 
-  expand_omp (root_omp_region);
+      for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+	switch (OMP_CLAUSE_CODE (c))
+	  {
+	    tree ovar, nc;
 
-  cleanup_tree_cfg ();
+	  default:
+	    break;
+	  case OMP_CLAUSE_MAP:
+	  case OMP_CLAUSE_TO:
+	  case OMP_CLAUSE_FROM:
+	    nc = c;
+	    ovar = OMP_CLAUSE_DECL (c);
+	    if (!DECL_P (ovar))
+	      {
+		if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+		    && OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c))
+		  {
+		    gcc_checking_assert (OMP_CLAUSE_DECL (OMP_CLAUSE_CHAIN (c))
+					 == get_base_address (ovar));
+		    nc = OMP_CLAUSE_CHAIN (c);
+		    ovar = OMP_CLAUSE_DECL (nc);
+		  }
+		else
+		  {
+		    tree x = build_sender_ref (ovar, ctx);
+		    tree v
+		      = build_fold_addr_expr_with_type (ovar, ptr_type_node);
+		    gimplify_assign (x, v, &ilist);
+		    nc = NULL_TREE;
+		  }
+	      }
+	    else
+	      {
+		if (DECL_SIZE (ovar)
+		    && TREE_CODE (DECL_SIZE (ovar)) != INTEGER_CST)
+		  {
+		    tree ovar2 = DECL_VALUE_EXPR (ovar);
+		    gcc_assert (TREE_CODE (ovar2) == INDIRECT_REF);
+		    ovar2 = TREE_OPERAND (ovar2, 0);
+		    gcc_assert (DECL_P (ovar2));
+		    ovar = ovar2;
+		  }
+		if (!maybe_lookup_field (ovar, ctx))
+		  continue;
+	      }
 
-  free_omp_regions ();
+	    if (nc)
+	      {
+		tree var = lookup_decl_in_outer_ctx (ovar, ctx);
+		tree x = build_sender_ref (ovar, ctx);
+		if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+		    && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER
+		    && !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c)
+		    && TREE_CODE (TREE_TYPE (ovar)) == ARRAY_TYPE)
+		  {
+		    tree avar
+		      = create_tmp_var (TREE_TYPE (TREE_TYPE (x)), NULL);
+		    mark_addressable (avar);
+		    gimplify_assign (avar, build_fold_addr_expr (var), &ilist);
+		    avar = build_fold_addr_expr (avar);
+		    gimplify_assign (x, avar, &ilist);
+		  }
+		else if (is_gimple_reg (var))
+		  {
+		    tree avar = create_tmp_var (TREE_TYPE (var), NULL);
+		    mark_addressable (avar);
+		    if (OMP_CLAUSE_MAP_KIND (c) != OMP_CLAUSE_MAP_ALLOC
+			&& OMP_CLAUSE_MAP_KIND (c) != OMP_CLAUSE_MAP_FROM)
+		      gimplify_assign (avar, var, &ilist);
+		    avar = build_fold_addr_expr (avar);
+		    gimplify_assign (x, avar, &ilist);
+		    if ((OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_FROM
+			 || OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_TOFROM)
+			&& !TYPE_READONLY (TREE_TYPE (var)))
+		      {
+			x = build_sender_ref (ovar, ctx);
+			x = build_simple_mem_ref (x);
+			gimplify_assign (var, x, &olist);
+		      }
+		  }
+		else
+		  {
+		    var = build_fold_addr_expr (var);
+		    gimplify_assign (x, var, &ilist);
+		  }
+	      }
+	    tree s = OMP_CLAUSE_SIZE (c);
+	    if (s == NULL_TREE)
+	      s = TYPE_SIZE_UNIT (TREE_TYPE (ovar));
+	    s = fold_convert (size_type_node, s);
+	    tree purpose = size_int (map_idx++);
+	    CONSTRUCTOR_APPEND_ELT (vsize, purpose, s);
+	    if (TREE_CODE (s) != INTEGER_CST)
+	      TREE_STATIC (TREE_VEC_ELT (t, 1)) = 0;
 
-  return 0;
-}
+	    unsigned char tkind = 0;
+	    switch (OMP_CLAUSE_CODE (c))
+	      {
+	      case OMP_CLAUSE_MAP:
+		tkind = OMP_CLAUSE_MAP_KIND (c);
+		break;
+	      case OMP_CLAUSE_TO:
+		tkind = OMP_CLAUSE_MAP_TO;
+		break;
+	      case OMP_CLAUSE_FROM:
+		tkind = OMP_CLAUSE_MAP_FROM;
+		break;
+	      default:
+		gcc_unreachable ();
+	      }
+	    unsigned int talign = TYPE_ALIGN_UNIT (TREE_TYPE (ovar));
+	    if (DECL_P (ovar) && DECL_ALIGN_UNIT (ovar) > talign)
+	      talign = DECL_ALIGN_UNIT (ovar);
+	    talign = ceil_log2 (talign);
+	    tkind |= talign << 3;
+	    CONSTRUCTOR_APPEND_ELT (vkind, purpose,
+				    build_int_cst (unsigned_char_type_node,
+						   tkind));
+	    if (nc && nc != c)
+	      c = nc;
+	  }
 
-/* OMP expansion -- the default pass, run before creation of SSA form.  */
+      gcc_assert (map_idx == map_cnt);
 
-static bool
-gate_expand_omp (void)
-{
-  return ((flag_openacc || flag_openmp)
-	  && !seen_error ());
-}
+      DECL_INITIAL (TREE_VEC_ELT (t, 1))
+	= build_constructor (TREE_TYPE (TREE_VEC_ELT (t, 1)), vsize);
+      DECL_INITIAL (TREE_VEC_ELT (t, 2))
+	= build_constructor (TREE_TYPE (TREE_VEC_ELT (t, 2)), vkind);
+      if (!TREE_STATIC (TREE_VEC_ELT (t, 1)))
+	{
+	  gimple_seq initlist = NULL;
+	  force_gimple_operand (build1 (DECL_EXPR, void_type_node,
+					TREE_VEC_ELT (t, 1)),
+				&initlist, true, NULL_TREE);
+	  gimple_seq_add_seq (&ilist, initlist);
+	}
 
-namespace {
+      tree clobber = build_constructor (ctx->record_type, NULL);
+      TREE_THIS_VOLATILE (clobber) = 1;
+      gimple_seq_add_stmt (&olist, gimple_build_assign (ctx->sender_decl,
+							clobber));
+    }
 
-const pass_data pass_data_expand_omp =
-{
-  GIMPLE_PASS, /* type */
-  "ompexp", /* name */
-  OPTGROUP_NONE, /* optinfo_flags */
-  true, /* has_gate */
-  true, /* has_execute */
-  TV_NONE, /* tv_id */
-  PROP_gimple_any, /* properties_required */
-  0, /* properties_provided */
-  0, /* properties_destroyed */
-  0, /* todo_flags_start */
-  0, /* todo_flags_finish */
-};
+  /* Once all the expansions are done, sequence all the different
+     fragments inside gimple_omp_body.  */
 
-class pass_expand_omp : public gimple_opt_pass
-{
-public:
-  pass_expand_omp (gcc::context *ctxt)
-    : gimple_opt_pass (pass_data_expand_omp, ctxt)
-  {}
+  new_body = NULL;
 
-  /* opt_pass methods: */
-  bool gate () { return gate_expand_omp (); }
-  unsigned int execute () { return execute_expand_omp (); }
+  if (ctx->record_type)
+    {
+      t = build_fold_addr_expr_loc (loc, ctx->sender_decl);
+      /* fixup_child_record_type might have changed receiver_decl's type.  */
+      t = fold_convert_loc (loc, TREE_TYPE (ctx->receiver_decl), t);
+      gimple_seq_add_stmt (&new_body,
+			   gimple_build_assign (ctx->receiver_decl, t));
+    }
 
-}; // class pass_expand_omp
+  gimple_seq_add_seq (&new_body, par_body);
+  gcc_assert (!ctx->cancellable);
+  new_body = maybe_catch_exception (new_body);
+  gimple_seq_add_stmt (&new_body, gimple_build_omp_return (false));
+  gimple_omp_set_body (stmt, new_body);
 
-} // anon namespace
+  bind = gimple_build_bind (NULL, NULL, gimple_bind_block (par_bind));
+  gsi_replace (gsi_p, bind, true);
+  gimple_bind_add_seq (bind, ilist);
+  gimple_bind_add_stmt (bind, stmt);
+  gimple_bind_add_seq (bind, olist);
 
-gimple_opt_pass *
-make_pass_expand_omp (gcc::context *ctxt)
-{
-  return new pass_expand_omp (ctxt);
+  pop_gimplify_context (NULL);
 }
-\f
-/* Routines to lower OpenMP directives into OMP-GIMPLE.  */
 
 /* If ctx is a worksharing context inside of a cancellable parallel
    region and it isn't nowait, add lhs to its GIMPLE_OMP_RETURN
@@ -8286,6 +8930,8 @@ make_pass_expand_omp (gcc::context *ctxt)
 static void
 maybe_add_implicit_barrier_cancel (omp_context *ctx, gimple_seq *body)
 {
+  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
+
   gimple omp_return = gimple_seq_last_stmt (*body);
   gcc_assert (gimple_code (omp_return) == GIMPLE_OMP_RETURN);
   if (gimple_omp_return_nowait_p (omp_return))
@@ -9051,6 +9697,8 @@ task_copyfn_remap_type (struct omp_taskcopy_context *tcctx, tree orig_type)
 static void
 create_task_copyfn (gimple task_stmt, omp_context *ctx)
 {
+  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
+
   struct function *child_cfun;
   tree child_fn, t, c, src, dst, f, sf, arg, sarg, decl;
   tree record_type, srecord_type, bind, list;
@@ -9909,6 +10557,12 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p, omp_context *ctx)
     case GIMPLE_BIND:
       lower_omp (gimple_bind_body_ptr (stmt), ctx);
       break;
+    case GIMPLE_OACC_PARALLEL:
+      ctx = maybe_lookup_ctx (stmt);
+      gcc_assert (ctx);
+      gcc_assert (!ctx->cancellable);
+      lower_oacc_parallel (gsi_p, ctx);
+      break;
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
       ctx = maybe_lookup_ctx (stmt);
@@ -10357,6 +11011,7 @@ make_gimple_omp_edges (basic_block bb, struct omp_region **region)
 
   switch (code)
     {
+    case GIMPLE_OACC_PARALLEL:
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
     case GIMPLE_OMP_FOR:
diff --git gcc/testsuite/c-c++-common/goacc-gomp/nesting-fail-1.c gcc/testsuite/c-c++-common/goacc-gomp/nesting-fail-1.c
new file mode 100644
index 0000000..875ec66
--- /dev/null
+++ gcc/testsuite/c-c++-common/goacc-gomp/nesting-fail-1.c
@@ -0,0 +1,121 @@
+/* TODO: Some of these should either be allowed or fail with a more sensible
+   error message.  */
+void
+f1 (void)
+{
+  int i;
+
+#pragma omp parallel
+  {
+#pragma acc parallel	/* { dg-error "may not be nested" } */
+    ;
+  }
+
+#pragma omp for
+  for (i = 0; i < 3; i++)
+    {
+#pragma acc parallel	/* { dg-error "may not be nested" } */
+      ;
+    }
+
+#pragma omp sections
+  {
+#pragma acc parallel	/* { dg-error "may not be nested" } */
+    ;
+  }
+
+#pragma omp single
+  {
+#pragma acc parallel	/* { dg-error "may not be nested" } */
+    ;
+  }
+
+#pragma omp task
+  {
+#pragma acc parallel	/* { dg-error "may not be nested" } */
+    ;
+  }
+
+#pragma omp master
+  {
+#pragma acc parallel	/* { dg-error "may not be nested" } */
+    ;
+  }
+
+#pragma omp critical
+  {
+#pragma acc parallel	/* { dg-error "may not be nested" } */
+    ;
+  }
+
+#pragma omp ordered
+  {
+#pragma acc parallel	/* { dg-error "may not be nested" } */
+    ;
+  }
+}
+
+/* TODO: Some of these should either be allowed or fail with a more sensible
+   error message.  */
+void
+f2 (void)
+{
+#pragma acc parallel
+  {
+#pragma omp parallel	/* { dg-error "may not be nested" } */
+    ;
+  }
+
+#pragma acc parallel
+  {
+    int i;
+#pragma omp for		/* { dg-error "may not be nested" } */
+    for (i = 0; i < 3; i++)
+      ;
+  }
+
+#pragma acc parallel
+  {
+#pragma omp sections	/* { dg-error "may not be nested" } */
+    {
+      ;
+    }
+  }
+
+#pragma acc parallel
+  {
+#pragma omp single	/* { dg-error "may not be nested" } */
+    ;
+  }
+
+#pragma acc parallel
+  {
+#pragma omp task	/* { dg-error "may not be nested" } */
+    ;
+  }
+
+#pragma acc parallel
+  {
+#pragma omp master	/* { dg-error "may not be nested" } */
+    ;
+  }
+
+#pragma acc parallel
+  {
+#pragma omp critical	/* { dg-error "may not be nested" } */
+    ;
+  }
+
+#pragma acc parallel
+  {
+    int i;
+#pragma omp atomic write
+    i = 0;		/* { dg-error "may not be nested" } */
+  }
+
+#pragma acc parallel
+  {
+#pragma omp ordered	/* { dg-error "may not be nested" } */
+    ;
+  }
+}
diff --git gcc/testsuite/c-c++-common/goacc/nesting-fail-1.c gcc/testsuite/c-c++-common/goacc/nesting-fail-1.c
new file mode 100644
index 0000000..6501397
--- /dev/null
+++ gcc/testsuite/c-c++-common/goacc/nesting-fail-1.c
@@ -0,0 +1,11 @@
+/* TODO: While the OpenACC specification does allow for certain kinds of
+   nesting, we don't support that yet.  */
+void
+f1 (void)
+{
+#pragma acc parallel
+  {
+#pragma acc parallel	/* { dg-error "may not be nested" } */
+    ;
+  }
+}
diff --git gcc/testsuite/c-c++-common/goacc/parallel-1.c gcc/testsuite/c-c++-common/goacc/parallel-1.c
new file mode 100644
index 0000000..cd19527
--- /dev/null
+++ gcc/testsuite/c-c++-common/goacc/parallel-1.c
@@ -0,0 +1,6 @@
+void
+foo (void)
+{
+#pragma acc parallel
+  foo ();
+}
diff --git gcc/testsuite/c-c++-common/goacc/parallel-fail-1.c gcc/testsuite/c-c++-common/goacc/parallel-fail-1.c
new file mode 100644
index 0000000..efc6f14
--- /dev/null
+++ gcc/testsuite/c-c++-common/goacc/parallel-fail-1.c
@@ -0,0 +1,6 @@
+void
+foo (void)
+{
+#pragma acc parallel foo	/* { dg-error "expected clause before 'foo'" } */
+  foo ();
+}
diff --git gcc/tree-inline.c gcc/tree-inline.c
index 74f333b..eeb4992 100644
--- gcc/tree-inline.c
+++ gcc/tree-inline.c
@@ -1299,6 +1299,9 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
 	  copy = gimple_build_wce (s1);
 	  break;
 
+	case GIMPLE_OACC_PARALLEL:
+          abort ();
+
 	case GIMPLE_OMP_PARALLEL:
 	  s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
 	  copy = gimple_build_omp_parallel
@@ -3849,6 +3852,7 @@ estimate_num_insns (gimple stmt, eni_weights *weights)
               + estimate_num_insns_seq (gimple_omp_body (stmt), weights)
               + estimate_num_insns_seq (gimple_omp_for_pre_body (stmt), weights));
 
+    case GIMPLE_OACC_PARALLEL:
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
     case GIMPLE_OMP_CRITICAL:
diff --git gcc/tree-nested.c gcc/tree-nested.c
index dc63ef6..8aba4f4 100644
--- gcc/tree-nested.c
+++ gcc/tree-nested.c
@@ -1238,6 +1238,9 @@ convert_nonlocal_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
 	}
       break;
 
+    case GIMPLE_OACC_PARALLEL:
+      abort ();
+
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
       save_suppress = info->suppress_expansion;
@@ -1679,6 +1682,9 @@ convert_local_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
 
   switch (gimple_code (stmt))
     {
+    case GIMPLE_OACC_PARALLEL:
+      abort ();
+
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
       save_suppress = info->suppress_expansion;
@@ -2008,6 +2014,9 @@ convert_tramp_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
 	break;
       }
 
+    case GIMPLE_OACC_PARALLEL:
+      abort ();
+
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
       {
@@ -2068,6 +2077,9 @@ convert_gimple_call (gimple_stmt_iterator *gsi, bool *handled_ops_p,
 	}
       break;
 
+    case GIMPLE_OACC_PARALLEL:
+      abort ();
+
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
       save_static_chain_added = info->static_chain_added;
diff --git gcc/tree-pretty-print.c gcc/tree-pretty-print.c
index fe75633..153d01f 100644
--- gcc/tree-pretty-print.c
+++ gcc/tree-pretty-print.c
@@ -2346,6 +2346,11 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
       pp_string (buffer, " > ");
       break;
 
+    case OACC_PARALLEL:
+      pp_string (buffer, "#pragma acc parallel");
+      dump_omp_clauses (buffer, OACC_PARALLEL_CLAUSES (node), spc, flags);
+      goto dump_omp_body;
+
     case OMP_PARALLEL:
       pp_string (buffer, "#pragma omp parallel");
       dump_omp_clauses (buffer, OMP_PARALLEL_CLAUSES (node), spc, flags);
diff --git gcc/tree.def gcc/tree.def
index 399b5af..87fec57 100644
--- gcc/tree.def
+++ gcc/tree.def
@@ -1000,8 +1000,15 @@ DEFTREECODE (TARGET_MEM_REF, "target_mem_ref", tcc_reference, 5)
    chain of component references offsetting p by c.  */
 DEFTREECODE (MEM_REF, "mem_ref", tcc_reference, 2)
 
-/* The ordering of the codes between OMP_PARALLEL and OMP_CRITICAL is
-   exposed to TREE_RANGE_CHECK.  */
+/* OpenACC and OpenMP.  As it is exposed in TREE_RANGE_CHECK invocations, do
+   not change the ordering of these codes.  */
+
+/* OpenACC - #pragma acc parallel [clause1 ... clauseN]
+   Operand 0: OACC_PARALLEL_BODY: Code to be executed in parallel.
+   Operand 1: OACC_PARALLEL_CLAUSES: List of clauses.  */
+
+DEFTREECODE (OACC_PARALLEL, "oacc_parallel", tcc_statement, 2)
+
 /* OpenMP - #pragma omp parallel [clause1 ... clauseN]
    Operand 0: OMP_PARALLEL_BODY: Code to be executed by all threads.
    Operand 1: OMP_PARALLEL_CLAUSES: List of clauses.  */
diff --git gcc/tree.h gcc/tree.h
index 22a576f..06d94cf 100644
--- gcc/tree.h
+++ gcc/tree.h
@@ -1171,9 +1171,14 @@ extern void protected_set_expr_location (tree, location_t);
 /* OpenMP directive and clause accessors.  */
 
 #define OMP_BODY(NODE) \
-  TREE_OPERAND (TREE_RANGE_CHECK (NODE, OMP_PARALLEL, OMP_CRITICAL), 0)
+  TREE_OPERAND (TREE_RANGE_CHECK (NODE, OACC_PARALLEL, OMP_CRITICAL), 0)
 #define OMP_CLAUSES(NODE) \
-  TREE_OPERAND (TREE_RANGE_CHECK (NODE, OMP_PARALLEL, OMP_SINGLE), 1)
+  TREE_OPERAND (TREE_RANGE_CHECK (NODE, OACC_PARALLEL, OMP_SINGLE), 1)
+
+#define OACC_PARALLEL_BODY(NODE) \
+  TREE_OPERAND (OACC_PARALLEL_CHECK (NODE), 0)
+#define OACC_PARALLEL_CLAUSES(NODE) \
+  TREE_OPERAND (OACC_PARALLEL_CHECK (NODE), 1)
 
 #define OMP_PARALLEL_BODY(NODE)    TREE_OPERAND (OMP_PARALLEL_CHECK (NODE), 0)
 #define OMP_PARALLEL_CLAUSES(NODE) TREE_OPERAND (OMP_PARALLEL_CHECK (NODE), 1)
diff --git libgomp/Makefile.am libgomp/Makefile.am
index 0b5c097..37b36bd 100644
--- libgomp/Makefile.am
+++ libgomp/Makefile.am
@@ -60,7 +60,7 @@ libgomp_la_LINK = $(LINK) $(libgomp_la_LDFLAGS)
 libgomp_la_SOURCES = alloc.c barrier.c critical.c env.c error.c iter.c \
 	iter_ull.c loop.c loop_ull.c ordered.c parallel.c sections.c single.c \
 	task.c team.c work.c lock.c mutex.c proc.c sem.c bar.c ptrlock.c \
-	time.c fortran.c affinity.c target.c
+	time.c fortran.c affinity.c target.c oacc-parallel.c
 
 nodist_noinst_HEADERS = libgomp_f.h
 nodist_libsubinclude_HEADERS = omp.h openacc.h
diff --git libgomp/Makefile.in libgomp/Makefile.in
index 9ee1bec..bc60253d 100644
--- libgomp/Makefile.in
+++ libgomp/Makefile.in
@@ -96,7 +96,7 @@ am_libgomp_la_OBJECTS = alloc.lo barrier.lo critical.lo env.lo \
 	error.lo iter.lo iter_ull.lo loop.lo loop_ull.lo ordered.lo \
 	parallel.lo sections.lo single.lo task.lo team.lo work.lo \
 	lock.lo mutex.lo proc.lo sem.lo bar.lo ptrlock.lo time.lo \
-	fortran.lo affinity.lo target.lo
+	fortran.lo affinity.lo target.lo oacc-parallel.lo
 libgomp_la_OBJECTS = $(am_libgomp_la_OBJECTS)
 DEFAULT_INCLUDES = -I.@am__isrc@
 depcomp = $(SHELL) $(top_srcdir)/../depcomp
@@ -317,7 +317,7 @@ libgomp_la_LINK = $(LINK) $(libgomp_la_LDFLAGS)
 libgomp_la_SOURCES = alloc.c barrier.c critical.c env.c error.c iter.c \
 	iter_ull.c loop.c loop_ull.c ordered.c parallel.c sections.c single.c \
 	task.c team.c work.c lock.c mutex.c proc.c sem.c bar.c ptrlock.c \
-	time.c fortran.c affinity.c target.c
+	time.c fortran.c affinity.c target.c oacc-parallel.c
 
 nodist_noinst_HEADERS = libgomp_f.h
 nodist_libsubinclude_HEADERS = omp.h openacc.h
@@ -469,6 +469,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loop.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loop_ull.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mutex.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oacc-parallel.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ordered.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parallel.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc.Plo@am__quote@
diff --git libgomp/libgomp.map libgomp/libgomp.map
index f094ed2..2b64d05 100644
--- libgomp/libgomp.map
+++ libgomp/libgomp.map
@@ -232,4 +232,6 @@ OACC_2.0 {
 };
 
 GOACC_2.0 {
+  global:
+	GOACC_parallel;
 };
diff --git libgomp/libgomp_g.h libgomp/libgomp_g.h
index 577956a..394f3a8 100644
--- libgomp/libgomp_g.h
+++ libgomp/libgomp_g.h
@@ -214,4 +214,9 @@ extern void GOMP_target_update (int, const void *,
 				size_t, void **, size_t *, unsigned char *);
 extern void GOMP_teams (unsigned int, unsigned int);
 
+/* oacc-parallel.c */
+
+extern void GOACC_parallel (int, void (*) (void *), const void *,
+			    size_t, void **, size_t *, unsigned char *);
+
 #endif /* LIBGOMP_G_H */
diff --git libgomp/oacc-parallel.c libgomp/oacc-parallel.c
new file mode 100644
index 0000000..730b83b
--- /dev/null
+++ libgomp/oacc-parallel.c
@@ -0,0 +1,36 @@
+/* Copyright (C) 2013 Free Software Foundation, Inc.
+
+   Contributed by Thomas Schwinge <thomas@codesourcery.com>.
+
+   This file is part of the GNU OpenMP Library (libgomp).
+
+   Libgomp is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+   FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* This file handles the OpenACC parallel construct.  */
+
+#include "libgomp_g.h"
+
+void
+GOACC_parallel (int device, void (*fn) (void *), const void *openmp_target,
+		size_t mapnum, void **hostaddrs, size_t *sizes,
+		unsigned char *kinds)
+{
+  GOMP_target (device, fn, openmp_target, mapnum, hostaddrs, sizes, kinds);
+}
diff --git libgomp/testsuite/libgomp.oacc-c/goacc_parallel.c libgomp/testsuite/libgomp.oacc-c/goacc_parallel.c
new file mode 100644
index 0000000..b9bdffa
--- /dev/null
+++ libgomp/testsuite/libgomp.oacc-c/goacc_parallel.c
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+
+#include "libgomp_g.h"
+
+extern void abort ();
+
+volatile int i;
+
+void
+f (void *data)
+{
+  if (i != -1)
+    abort ();
+  i = 42;
+}
+
+int main(void)
+{
+  i = -1;
+  GOACC_parallel (0, f, (const void *) 0, 0, (void *) 0, (void *) 0, (void *) 0);
+  if (i != 42)
+    abort ();
+
+  return 0;
+}
diff --git libgomp/testsuite/libgomp.oacc-c/parallel-1.c libgomp/testsuite/libgomp.oacc-c/parallel-1.c
new file mode 100644
index 0000000..b40545d
--- /dev/null
+++ libgomp/testsuite/libgomp.oacc-c/parallel-1.c
@@ -0,0 +1,26 @@
+/* { dg-do run } */
+
+extern void abort ();
+
+volatile int i;
+
+int main(void)
+{
+  volatile int j;
+
+  i = -0x42;
+  j = -42;
+#pragma acc parallel
+  {
+    if (i != -0x42 || j != -42)
+      abort ();
+    i = 42;
+    j = 0x42;
+    if (i != 42 || j != 0x42)
+      abort ();
+  }
+  if (i != 42 || j != 0x42)
+    abort ();
+
+  return 0;
+}
-- 
1.8.1.1

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

* [gomp4 7/9] OpenACC: Use OpenMP's lowering and expansion passes.
  2013-11-06 20:37           ` [gomp4 6/9] OpenACC: Infrastructure for builtins thomas
@ 2013-11-06 19:56             ` thomas
  2013-11-06 20:29               ` [gomp4 8/9] OpenACC: Basic support for #pragma acc in the C front end thomas
  2013-11-07  8:39               ` [gomp4 7/9] OpenACC: Use OpenMP's lowering and expansion passes Jakub Jelinek
  2013-11-07  8:23             ` [gomp4 6/9] OpenACC: Infrastructure for builtins Jakub Jelinek
  1 sibling, 2 replies; 44+ messages in thread
From: thomas @ 2013-11-06 19:56 UTC (permalink / raw)
  To: gcc-patches; +Cc: Thomas Schwinge

From: Thomas Schwinge <thomas@codesourcery.com>

	gcc/
	* gimplify.c (gimplify_body): Consider flag_openacc additionally
	to flag_openmp.
	* omp-low.c (execute_expand_omp, execute_lower_omp)
	(gate_diagnose_omp_blocks): Likewise.
	gcc/testsuite/
	* gcc.dg/goacc-gomp/goacc-gomp.exp: New file.
	* gcc.dg/goacc/goacc.exp: Likewise.
---
 gcc/gimplify.c                                 |  4 +--
 gcc/omp-low.c                                  | 10 ++++---
 gcc/testsuite/gcc.dg/goacc-gomp/goacc-gomp.exp | 38 ++++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/goacc/goacc.exp           | 37 +++++++++++++++++++++++++
 4 files changed, 83 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/goacc-gomp/goacc-gomp.exp
 create mode 100644 gcc/testsuite/gcc.dg/goacc/goacc.exp

diff --git gcc/gimplify.c gcc/gimplify.c
index 1f18466..30c2b45 100644
--- gcc/gimplify.c
+++ gcc/gimplify.c
@@ -8803,7 +8803,7 @@ gimplify_body (tree fndecl, bool do_parms)
   gcc_assert (gimplify_ctxp == NULL);
   push_gimplify_context (&gctx);
 
-  if (flag_openmp)
+  if (flag_openacc || flag_openmp)
     {
       gcc_assert (gimplify_omp_ctxp == NULL);
       if (lookup_attribute ("omp declare target", DECL_ATTRIBUTES (fndecl)))
@@ -8872,7 +8872,7 @@ gimplify_body (tree fndecl, bool do_parms)
       nonlocal_vlas = NULL;
     }
 
-  if (flag_openmp && gimplify_omp_ctxp)
+  if ((flag_openacc || flag_openmp) && gimplify_omp_ctxp)
     {
       delete_omp_context (gimplify_omp_ctxp);
       gimplify_omp_ctxp = NULL;
diff --git gcc/omp-low.c gcc/omp-low.c
index 94058af..99811d0 100644
--- gcc/omp-low.c
+++ gcc/omp-low.c
@@ -8234,7 +8234,8 @@ execute_expand_omp (void)
 static bool
 gate_expand_omp (void)
 {
-  return (flag_openmp != 0 && !seen_error ());
+  return ((flag_openacc || flag_openmp)
+	  && !seen_error ());
 }
 
 namespace {
@@ -10054,8 +10055,9 @@ execute_lower_omp (void)
   gimple_seq body;
 
   /* This pass always runs, to provide PROP_gimple_lomp.
-     But there is nothing to do unless -fopenmp is given.  */
-  if (flag_openmp == 0)
+     But there is nothing to do unless at least one of -fopenacc or -fopenmp is
+     given.  */
+  if (!(flag_openacc || flag_openmp))
     return 0;
 
   all_contexts = splay_tree_new (splay_tree_compare_pointers, 0,
@@ -10484,7 +10486,7 @@ diagnose_omp_structured_block_errors (void)
 static bool
 gate_diagnose_omp_blocks (void)
 {
-  return flag_openmp != 0;
+  return flag_openacc || flag_openmp;
 }
 
 namespace {
diff --git gcc/testsuite/gcc.dg/goacc-gomp/goacc-gomp.exp gcc/testsuite/gcc.dg/goacc-gomp/goacc-gomp.exp
new file mode 100644
index 0000000..29e9a93
--- /dev/null
+++ gcc/testsuite/gcc.dg/goacc-gomp/goacc-gomp.exp
@@ -0,0 +1,38 @@
+# Copyright (C) 2006-2013 Free Software Foundation, Inc.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+if { ![check_effective_target_fopenacc] \
+     || ![check_effective_target_fopenmp] } {
+  return
+}
+
+# Initialize `dg'.
+dg-init
+
+# Main loop.
+dg-runtest [lsort [concat \
+	[find $srcdir/$subdir *.c] \
+	[find $srcdir/c-c++-common/goacc-gomp *.c]]] "" "-fopenacc -fopenmp"
+
+# All done.
+dg-finish
diff --git gcc/testsuite/gcc.dg/goacc/goacc.exp gcc/testsuite/gcc.dg/goacc/goacc.exp
new file mode 100644
index 0000000..1137c99
--- /dev/null
+++ gcc/testsuite/gcc.dg/goacc/goacc.exp
@@ -0,0 +1,37 @@
+# Copyright (C) 2006-2013 Free Software Foundation, Inc.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+if ![check_effective_target_fopenacc] {
+  return
+}
+
+# Initialize `dg'.
+dg-init
+
+# Main loop.
+dg-runtest [lsort [concat \
+	[find $srcdir/$subdir *.c] \
+	[find $srcdir/c-c++-common/goacc *.c]]] "" "-fopenacc"
+
+# All done.
+dg-finish
-- 
1.8.1.1

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

* Re: [gomp4 9/9] OpenACC: Basic support for #pragma acc parallel.
  2013-11-06 19:53                 ` [gomp4 9/9] OpenACC: Basic support for #pragma acc parallel thomas
@ 2013-11-06 20:01                   ` Thomas Schwinge
  2013-11-07  8:48                     ` Jakub Jelinek
                                       ` (3 more replies)
  2013-11-06 20:03                   ` [gomp4 9/9] OpenACC: Basic support for #pragma acc parallel Jakub Jelinek
  1 sibling, 4 replies; 44+ messages in thread
From: Thomas Schwinge @ 2013-11-06 20:01 UTC (permalink / raw)
  To: gcc-patches

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

Hi!

On Wed, 6 Nov 2013 20:42:23 +0100, I wrote:
> diff --git gcc/omp-low.c gcc/omp-low.c
> index 99811d0..84fe466 100644
> --- gcc/omp-low.c
> +++ gcc/omp-low.c
> [...]
> @@ -4542,10 +4672,10 @@ expand_omp_build_assign (gimple_stmt_iterator *gsi_p, tree to, tree from)
>      }
>  }
>  
> -/* Expand the OpenMP parallel or task directive starting at REGION.  */
> +/* Expand the OpenACC parallel directive starting at REGION.  */
>  
>  static void
> -expand_omp_taskreg (struct omp_region *region)
> +expand_oacc_parallel (struct omp_region *region)
>  {
>    basic_block entry_bb, exit_bb, new_bb;
>    struct function *child_cfun;
> [...]
> +/* Expand the OpenMP parallel or task directive starting at REGION.  */
> +
> +static void
> +expand_omp_taskreg (struct omp_region *region)

Forgot to pass the --patience switch to Git, so the diff algorithm
decided to first patch the existing expand_omp_taskreg into
expand_oacc_parallel, and then later re-add expand_omp_taskreg.  Here's a
more readable version of that patch, avoiding all that back'n'forth:

	gcc/c-family/
	* c-pragma.h (pragma_kind): Add PRAGMA_OACC_PARALLEL.
	* c-pragma.c (oacc_pragmas): Add "parallel".
	gcc/c/
	* c-parser.c (c_parser_omp_structured_block): Update comment.
	(c_parser_oacc_parallel): New function.
	(c_parser_omp_construct): Handle PRAGMA_OACC_PARALLEL.

	gcc/
	* tree.def (OACC_PARALLEL): New code.
	* doc/generic.texi (OpenMP): Document it.
	* tree.h (OMP_BODY, OMP_CLAUSES): Include it.
	(OACC_PARALLEL_BODY, OACC_PARALLEL_CLAUSES): New macros.
	* tree-pretty-print.c (dump_generic_node): Handle OACC_PARALLEL.
	gcc/c/
	* c-tree.h (c_finish_oacc_parallel): New declaration.
	* c-typeck.c (c_finish_oacc_parallel): New function.
	gcc/c-family/
	* c-omp.c (c_omp_split_clauses): Catch OACC_PARALLEL.

	gcc/
	* gimple.def (GIMPLE_OACC_PARALLEL): New code.
	* doc/gimple.texi: Document it.
	* gimple.h (gimple_build_oacc_parallel): New declaration.
	(gimple_oacc_parallel_clauses, gimple_oacc_parallel_clauses_ptr)
	(gimple_oacc_parallel_set_clauses, gimple_oacc_parallel_child_fn)
	(gimple_oacc_parallel_child_fn_ptr)
	(gimple_oacc_parallel_set_child_fn, gimple_oacc_parallel_data_arg)
	(gimple_oacc_parallel_data_arg_ptr)
	(gimple_oacc_parallel_set_data_arg): New inline functions.
	(CASE_GIMPLE_OMP): Add GIMPLE_OACC_PARALLEL.
	* gimple.c (gimple_build_oacc_parallel): New function.
	(walk_gimple_op, walk_gimple_stmt, gimple_copy): Handle
	GIMPLE_OACC_PARALLEL.
	* gimplify.c (is_gimple_stmt): Handle GIMPLE_OACC_PARALLEL.
	(gimplify_oacc_parallel): New function.
	(gimplify_expr): Handle OACC_PARALLEL.
	* cgraphbuild.c (build_cgraph_edges): Handle GIMPLE_OACC_PARALLEL.
	* gimple-low.c (lower_stmt): Likewise.
	* gimple-pretty-print.c (pp_gimple_stmt_1): Likewise.
	(dump_gimple_oacc_parallel): New function.
	* oacc-builtins.def (BUILT_IN_GOACC_PARALLEL): New macro.
	* omp-low.c (scan_oacc_parallel, expand_oacc_parallel)
	(lower_oacc_parallel): New functions.
	(use_pointer_for_field, build_outer_var_ref, scan_sharing_clauses)
	(create_omp_child_function, check_omp_nesting_restrictions)
	(scan_omp_1_stmt, lower_rec_simd_input_clauses)
	(lower_lastprivate_clauses, lower_reduction_clauses)
	(lower_copyprivate_clauses, lower_send_clauses)
	(lower_send_shared_vars, expand_omp)
	(maybe_add_implicit_barrier_cancel, create_task_copyfn)
	(lower_omp_1, make_gimple_omp_edges): Handle GIMPLE_OACC_PARALLEL,
	or catch it.
	* tree-inline.c (remap_gimple_stmt): Likewise.
	* tree-nested.c (convert_nonlocal_reference_stmt)
	(convert_local_reference_stmt, convert_tramp_reference_stmt)
	(convert_gimple_call): Likewise.
	gcc/testsuite/
	* c-c++-common/goacc-gomp/nesting-fail-1.c: New file.
	* c-c++-common/goacc/nesting-fail-1.c: Likewise.
	* c-c++-common/goacc/parallel-1.c: Likewise.
	* c-c++-common/goacc/parallel-fail-1.c: Likewise.

	libgomp/
	* oacc-parallel.c: New file.
	* Makefile.am (libgomp_la_SOURCES): Add it.
	* Makefile.in: Regenerate.
	* libgomp.map (GOACC_2.0): Add GOACC_parallel.
	* libgomp_g.h (GOACC_parallel): New declaration.
	* testsuite/libgomp.oacc-c/goacc_parallel.c: New file.
	* testsuite/libgomp.oacc-c/parallel-1.c: New file.
---
 gcc/c-family/c-omp.c                               |   1 +
 gcc/c-family/c-pragma.c                            |   1 +
 gcc/c-family/c-pragma.h                            |   1 +
 gcc/c/c-parser.c                                   |  42 +-
 gcc/c/c-tree.h                                     |   1 +
 gcc/c/c-typeck.c                                   |  19 +
 gcc/cgraphbuild.c                                  |  12 +-
 gcc/doc/generic.texi                               |   5 +
 gcc/doc/gimple.texi                                |   8 +
 gcc/gimple-low.c                                   |   1 +
 gcc/gimple-pretty-print.c                          |  58 ++
 gcc/gimple.c                                       |  36 ++
 gcc/gimple.def                                     |  10 +-
 gcc/gimple.h                                       |  89 +++
 gcc/gimplify.c                                     |  38 ++
 gcc/oacc-builtins.def                              |   3 +
 gcc/omp-low.c                                      | 661 ++++++++++++++++++++-
 .../c-c++-common/goacc-gomp/nesting-fail-1.c       | 121 ++++
 gcc/testsuite/c-c++-common/goacc/nesting-fail-1.c  |  11 +
 gcc/testsuite/c-c++-common/goacc/parallel-1.c      |   6 +
 gcc/testsuite/c-c++-common/goacc/parallel-fail-1.c |   6 +
 gcc/tree-inline.c                                  |   4 +
 gcc/tree-nested.c                                  |  12 +
 gcc/tree-pretty-print.c                            |   5 +
 gcc/tree.def                                       |  11 +-
 gcc/tree.h                                         |   9 +-
 libgomp/Makefile.am                                |   2 +-
 libgomp/Makefile.in                                |   5 +-
 libgomp/libgomp.map                                |   2 +
 libgomp/libgomp_g.h                                |   5 +
 libgomp/oacc-parallel.c                            |  36 ++
 libgomp/testsuite/libgomp.oacc-c/goacc_parallel.c  |  25 +
 libgomp/testsuite/libgomp.oacc-c/parallel-1.c      |  26 +
 33 files changed, 1257 insertions(+), 15 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/goacc-gomp/nesting-fail-1.c
 create mode 100644 gcc/testsuite/c-c++-common/goacc/nesting-fail-1.c
 create mode 100644 gcc/testsuite/c-c++-common/goacc/parallel-1.c
 create mode 100644 gcc/testsuite/c-c++-common/goacc/parallel-fail-1.c
 create mode 100644 libgomp/oacc-parallel.c
 create mode 100644 libgomp/testsuite/libgomp.oacc-c/goacc_parallel.c
 create mode 100644 libgomp/testsuite/libgomp.oacc-c/parallel-1.c

diff --git gcc/c-family/c-omp.c gcc/c-family/c-omp.c
index f001a75..f7d2bd9 100644
--- gcc/c-family/c-omp.c
+++ gcc/c-family/c-omp.c
@@ -627,6 +627,7 @@ c_omp_split_clauses (location_t loc, enum tree_code code,
   enum c_omp_clause_split s;
   int i;
 
+  gcc_assert (code != OACC_PARALLEL);
   for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++)
     cclauses[i] = NULL;
   /* Add implicit nowait clause on
diff --git gcc/c-family/c-pragma.c gcc/c-family/c-pragma.c
index 98f98d0..c329f8d 100644
--- gcc/c-family/c-pragma.c
+++ gcc/c-family/c-pragma.c
@@ -1165,6 +1165,7 @@ static vec<pragma_ns_name> registered_pp_pragmas;
 
 struct omp_pragma_def { const char *name; unsigned int id; };
 static const struct omp_pragma_def oacc_pragmas[] = {
+  { "parallel", PRAGMA_OACC_PARALLEL },
 };
 static const struct omp_pragma_def omp_pragmas[] = {
   { "atomic", PRAGMA_OMP_ATOMIC },
diff --git gcc/c-family/c-pragma.h gcc/c-family/c-pragma.h
index 705bcb4..5c58e32 100644
--- gcc/c-family/c-pragma.h
+++ gcc/c-family/c-pragma.h
@@ -27,6 +27,7 @@ along with GCC; see the file COPYING3.  If not see
 typedef enum pragma_kind {
   PRAGMA_NONE = 0,
 
+  PRAGMA_OACC_PARALLEL,
   PRAGMA_OMP_ATOMIC,
   PRAGMA_OMP_BARRIER,
   PRAGMA_OMP_CANCEL,
diff --git gcc/c/c-parser.c gcc/c/c-parser.c
index 8a1e988..297b6da7 100644
--- gcc/c/c-parser.c
+++ gcc/c/c-parser.c
@@ -4478,6 +4478,17 @@ c_parser_label (c_parser *parser)
      @throw expression ;
      @throw ;
 
+   OpenACC:
+
+   statement:
+     openacc-construct
+
+   openacc-construct:
+     parallel-construct
+
+   parallel-construct:
+     parallel-directive structured-block
+
    OpenMP:
 
    statement:
@@ -10754,7 +10765,7 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask,
   return clauses;
 }
 
-/* OpenMP 2.5:
+/* OpenACC 2.0, OpenMP 2.5:
    structured-block:
      statement
 
@@ -10770,6 +10781,32 @@ c_parser_omp_structured_block (c_parser *parser)
   return pop_stmt_list (stmt);
 }
 
+/* OpenACC 2.0:
+   # pragma acc parallel oacc-parallel-clause[optseq] new-line
+
+   LOC is the location of the #pragma token.
+*/
+
+#define OACC_PARALLEL_CLAUSE_MASK			\
+	PRAGMA_OMP_CLAUSE_NONE
+
+static tree
+c_parser_oacc_parallel (location_t loc, c_parser *parser)
+{
+  tree stmt, clauses, block;
+
+  clauses =  c_parser_omp_all_clauses (parser, OACC_PARALLEL_CLAUSE_MASK,
+				       "#pragma acc parallel");
+  gcc_assert (clauses == NULL);
+
+  block = c_begin_omp_parallel ();
+  add_stmt (c_parser_omp_structured_block (parser));
+
+  stmt = c_finish_oacc_parallel (loc, clauses, block);
+
+  return stmt;
+}
+
 /* OpenMP 2.5:
    # pragma omp atomic new-line
      expression-stmt
@@ -12948,6 +12985,9 @@ c_parser_omp_construct (c_parser *parser)
 
   switch (p_kind)
     {
+    case PRAGMA_OACC_PARALLEL:
+      stmt = c_parser_oacc_parallel (loc, parser);
+      break;
     case PRAGMA_OMP_ATOMIC:
       c_parser_omp_atomic (loc, parser);
       return;
diff --git gcc/c/c-tree.h gcc/c/c-tree.h
index 2565ccb..f524e31 100644
--- gcc/c/c-tree.h
+++ gcc/c/c-tree.h
@@ -635,6 +635,7 @@ extern tree c_finish_bc_stmt (location_t, tree *, bool);
 extern tree c_finish_goto_label (location_t, tree);
 extern tree c_finish_goto_ptr (location_t, tree);
 extern tree c_expr_to_decl (tree, bool *, bool *);
+extern tree c_finish_oacc_parallel (location_t, tree, tree);
 extern tree c_begin_omp_parallel (void);
 extern tree c_finish_omp_parallel (location_t, tree, tree);
 extern tree c_begin_omp_task (void);
diff --git gcc/c/c-typeck.c gcc/c/c-typeck.c
index 8f1d3a4..e7096e6 100644
--- gcc/c/c-typeck.c
+++ gcc/c/c-typeck.c
@@ -10644,6 +10644,25 @@ c_expr_to_decl (tree expr, bool *tc ATTRIBUTE_UNUSED, bool *se)
     return expr;
 }
 \f
+/* Generate OACC_PARALLEL, with CLAUSES and BLOCK as its compound
+   statement.  LOC is the location of the OACC_PARALLEL.  */
+
+tree
+c_finish_oacc_parallel (location_t loc, tree clauses, tree block)
+{
+  tree stmt;
+
+  block = c_end_compound_stmt (loc, block, true);
+
+  stmt = make_node (OACC_PARALLEL);
+  TREE_TYPE (stmt) = void_type_node;
+  OACC_PARALLEL_CLAUSES (stmt) = clauses;
+  OACC_PARALLEL_BODY (stmt) = block;
+  SET_EXPR_LOCATION (stmt, loc);
+
+  return add_stmt (stmt);
+}
+
 /* Like c_begin_compound_stmt, except force the retention of the BLOCK.  */
 
 tree
diff --git gcc/cgraphbuild.c gcc/cgraphbuild.c
index 87e06e3..efad3d9 100644
--- gcc/cgraphbuild.c
+++ gcc/cgraphbuild.c
@@ -333,7 +333,15 @@ build_cgraph_edges (void)
 					     bb->count, freq);
 	    }
 	  ipa_record_stmt_references (node, stmt);
-	  if (gimple_code (stmt) == GIMPLE_OMP_PARALLEL
+	  if (gimple_code (stmt) == GIMPLE_OACC_PARALLEL
+	      && gimple_oacc_parallel_child_fn (stmt))
+	    {
+	      tree fn = gimple_oacc_parallel_child_fn (stmt);
+	      ipa_record_reference (node,
+				    cgraph_get_create_real_symbol_node (fn),
+				    IPA_REF_ADDR, stmt);
+	    }
+	  else if (gimple_code (stmt) == GIMPLE_OMP_PARALLEL
 	      && gimple_omp_parallel_child_fn (stmt))
 	    {
 	      tree fn = gimple_omp_parallel_child_fn (stmt);
@@ -341,7 +349,7 @@ build_cgraph_edges (void)
 				    cgraph_get_create_real_symbol_node (fn),
 				    IPA_REF_ADDR, stmt);
 	    }
-	  if (gimple_code (stmt) == GIMPLE_OMP_TASK)
+	  else if (gimple_code (stmt) == GIMPLE_OMP_TASK)
 	    {
 	      tree fn = gimple_omp_task_child_fn (stmt);
 	      if (fn)
diff --git gcc/doc/generic.texi gcc/doc/generic.texi
index 73dd123..812f5a9 100644
--- gcc/doc/generic.texi
+++ gcc/doc/generic.texi
@@ -2049,6 +2049,7 @@ edge.  Rethrowing the exception is represented using @code{RESX_EXPR}.
 
 @node OpenMP
 @subsection OpenMP
+@tindex OACC_PARALLEL
 @tindex OMP_PARALLEL
 @tindex OMP_FOR
 @tindex OMP_SECTIONS
@@ -2066,6 +2067,10 @@ All the statements starting with @code{OMP_} represent directives and
 clauses used by the OpenMP API @w{@uref{http://www.openmp.org/}}.
 
 @table @code
+@item OACC_PARALLEL
+
+Represents @code{#pragma acc parallel [clause1 @dots{} clauseN]}.
+
 @item OMP_PARALLEL
 
 Represents @code{#pragma omp parallel [clause1 @dots{} clauseN]}. It
diff --git gcc/doc/gimple.texi gcc/doc/gimple.texi
index 7bd9fd5..0f1bbe6 100644
--- gcc/doc/gimple.texi
+++ gcc/doc/gimple.texi
@@ -338,6 +338,7 @@ The following table briefly describes the GIMPLE instruction set.
 @item @code{GIMPLE_GOTO}		@tab x			@tab x
 @item @code{GIMPLE_LABEL}		@tab x			@tab x
 @item @code{GIMPLE_NOP}			@tab x			@tab x
+@item @code{GIMPLE_OACC_PARALLEL}	@tab x			@tab x
 @item @code{GIMPLE_OMP_ATOMIC_LOAD}	@tab x			@tab x
 @item @code{GIMPLE_OMP_ATOMIC_STORE}	@tab x			@tab x
 @item @code{GIMPLE_OMP_CONTINUE}	@tab x			@tab x
@@ -905,6 +906,7 @@ Return a deep copy of statement @code{STMT}.
 * @code{GIMPLE_EH_FILTER}::
 * @code{GIMPLE_LABEL}::
 * @code{GIMPLE_NOP}::
+* @code{GIMPLE_OACC_PARALLEL}::
 * @code{GIMPLE_OMP_ATOMIC_LOAD}::
 * @code{GIMPLE_OMP_ATOMIC_STORE}::
 * @code{GIMPLE_OMP_CONTINUE}::
@@ -1554,6 +1556,12 @@ Build a @code{GIMPLE_NOP} statement.
 Returns @code{TRUE} if statement @code{G} is a @code{GIMPLE_NOP}.
 @end deftypefn
 
+
+@node @code{GIMPLE_OACC_PARALLEL}
+@subsection @code{GIMPLE_OACC_PARALLEL}
+@cindex @code{GIMPLE_OACC_PARALLEL}
+
+
 @node @code{GIMPLE_OMP_ATOMIC_LOAD}
 @subsection @code{GIMPLE_OMP_ATOMIC_LOAD}
 @cindex @code{GIMPLE_OMP_ATOMIC_LOAD}
diff --git gcc/gimple-low.c gcc/gimple-low.c
index d527d86..74c9925 100644
--- gcc/gimple-low.c
+++ gcc/gimple-low.c
@@ -368,6 +368,7 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
       }
       break;
 
+    case GIMPLE_OACC_PARALLEL:
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
     case GIMPLE_OMP_TARGET:
diff --git gcc/gimple-pretty-print.c gcc/gimple-pretty-print.c
index 6842213..59cb5bb 100644
--- gcc/gimple-pretty-print.c
+++ gcc/gimple-pretty-print.c
@@ -1823,6 +1823,60 @@ dump_gimple_phi (pretty_printer *buffer, gimple phi, int spc, bool comment,
 }
 
 
+/* Dump a GIMPLE_OACC_PARALLEL tuple on the pretty_printer BUFFER, SPC spaces
+   of indent.  FLAGS specifies details to show in the dump (see TDF_* in
+   dumpfile.h).  */
+
+static void
+dump_gimple_oacc_parallel (pretty_printer *buffer, gimple gs, int spc,
+                          int flags)
+{
+  if (flags & TDF_RAW)
+    {
+      dump_gimple_fmt (buffer, spc, flags, "%G <%+BODY <%S>%nCLAUSES <", gs,
+                       gimple_omp_body (gs));
+      dump_omp_clauses (buffer, gimple_oacc_parallel_clauses (gs), spc, flags);
+      dump_gimple_fmt (buffer, spc, flags, " >, %T, %T%n>",
+                       gimple_oacc_parallel_child_fn (gs),
+                       gimple_oacc_parallel_data_arg (gs));
+    }
+  else
+    {
+      gimple_seq body;
+      pp_string (buffer, "#pragma acc parallel");
+      dump_omp_clauses (buffer, gimple_oacc_parallel_clauses (gs), spc, flags);
+      if (gimple_oacc_parallel_child_fn (gs))
+	{
+	  pp_string (buffer, " [child fn: ");
+	  dump_generic_node (buffer, gimple_oacc_parallel_child_fn (gs),
+			     spc, flags, false);
+	  pp_string (buffer, " (");
+	  if (gimple_oacc_parallel_data_arg (gs))
+	    dump_generic_node (buffer, gimple_oacc_parallel_data_arg (gs),
+			       spc, flags, false);
+	  else
+	    pp_string (buffer, "???");
+	  pp_string (buffer, ")]");
+	}
+      body = gimple_omp_body (gs);
+      if (body && gimple_code (gimple_seq_first_stmt (body)) != GIMPLE_BIND)
+	{
+	  newline_and_indent (buffer, spc + 2);
+	  pp_left_brace (buffer);
+	  pp_newline (buffer);
+	  dump_gimple_seq (buffer, body, spc + 4, flags);
+	  newline_and_indent (buffer, spc + 2);
+	  pp_right_brace (buffer);
+	}
+      else if (body)
+	{
+	  pp_newline (buffer);
+	  dump_gimple_seq (buffer, body, spc + 2, flags);
+	}
+    }
+}
+
+
 /* Dump a GIMPLE_OMP_PARALLEL tuple on the pretty_printer BUFFER, SPC spaces
    of indent.  FLAGS specifies details to show in the dump (see TDF_* in
    dumpfile.h).  */
@@ -2123,6 +2177,10 @@ pp_gimple_stmt_1 (pretty_printer *buffer, gimple gs, int spc, int flags)
       dump_gimple_phi (buffer, gs, spc, false, flags);
       break;
 
+    case GIMPLE_OACC_PARALLEL:
+      dump_gimple_oacc_parallel (buffer, gs, spc, flags);
+      break;
+
     case GIMPLE_OMP_PARALLEL:
       dump_gimple_omp_parallel (buffer, gs, spc, flags);
       break;
diff --git gcc/gimple.c gcc/gimple.c
index 20f6010..ea96d26 100644
--- gcc/gimple.c
+++ gcc/gimple.c
@@ -898,6 +898,23 @@ gimple_build_debug_source_bind_stat (tree var, tree value,
 }
 
 
+/* Build a GIMPLE_OACC_PARALLEL statement.
+
+   BODY is sequence of statements which are executed in parallel.
+   CLAUSES are the OpenACC parallel construct's clauses.  */
+
+gimple
+gimple_build_oacc_parallel (gimple_seq body, tree clauses)
+{
+  gimple p = gimple_alloc (GIMPLE_OACC_PARALLEL, 0);
+  if (body)
+    gimple_omp_set_body (p, body);
+  gimple_oacc_parallel_set_clauses (p, clauses);
+
+  return p;
+}
+
+
 /* Build a GIMPLE_OMP_CRITICAL statement.
 
    BODY is the sequence of statements for which only one thread can execute.
@@ -1571,6 +1588,21 @@ walk_gimple_op (gimple stmt, walk_tree_fn callback_op,
 	return ret;
       break;
 
+    case GIMPLE_OACC_PARALLEL:
+      ret = walk_tree (gimple_oacc_parallel_clauses_ptr (stmt), callback_op,
+		       wi, pset);
+      if (ret)
+	return ret;
+      ret = walk_tree (gimple_oacc_parallel_child_fn_ptr (stmt), callback_op,
+		       wi, pset);
+      if (ret)
+	return ret;
+      ret = walk_tree (gimple_oacc_parallel_data_arg_ptr (stmt), callback_op,
+		       wi, pset);
+      if (ret)
+	return ret;
+      break;
+
     case GIMPLE_OMP_CONTINUE:
       ret = walk_tree (gimple_omp_continue_control_def_ptr (stmt),
 	  	       callback_op, wi, pset);
@@ -1866,6 +1898,7 @@ walk_gimple_stmt (gimple_stmt_iterator *gsi, walk_stmt_fn callback_stmt,
 	return wi->callback_result;
 
       /* FALL THROUGH.  */
+    case GIMPLE_OACC_PARALLEL:
     case GIMPLE_OMP_CRITICAL:
     case GIMPLE_OMP_MASTER:
     case GIMPLE_OMP_TASKGROUP:
@@ -2306,6 +2339,9 @@ gimple_copy (gimple stmt)
 	  gimple_try_set_cleanup (copy, new_seq);
 	  break;
 
+	case GIMPLE_OACC_PARALLEL:
+          abort ();
+
 	case GIMPLE_OMP_FOR:
 	  new_seq = gimple_seq_copy (gimple_omp_for_pre_body (stmt));
 	  gimple_omp_for_set_pre_body (copy, new_seq);
diff --git gcc/gimple.def gcc/gimple.def
index 07370ae..9ff9ab3 100644
--- gcc/gimple.def
+++ gcc/gimple.def
@@ -205,10 +205,16 @@ DEFGSCODE(GIMPLE_NOP, "gimple_nop", GSS_BASE)
 
 /* IMPORTANT.
 
-   Do not rearrange any of the GIMPLE_OMP_* codes.  This ordering is
-   exposed by the range check in gimple_omp_subcode().  */
+   Do not rearrange any of the GIMPLE_OACC_* and GIMPLE_OMP_* codes.  This
+   ordering is exposed by the range check in gimple_omp_subcode.  */
 
 
+/* GIMPLE_OACC_PARALLEL <BODY, CLAUSES, CHILD_FN, DATA_ARG> represents
+
+   #pragma acc parallel [CLAUSES]
+   BODY */
+DEFGSCODE(GIMPLE_OACC_PARALLEL, "gimple_oacc_parallel", GSS_OMP_PARALLEL)
+
 /* Tuples used for lowering of OMP_ATOMIC.  Although the form of the OMP_ATOMIC
    expression is very simple (just in form mem op= expr), various implicit
    conversions may cause the expression to become more complex, so that it does
diff --git gcc/gimple.h gcc/gimple.h
index b34424c..c9be1c9 100644
--- gcc/gimple.h
+++ gcc/gimple.h
@@ -786,6 +786,7 @@ gimple gimple_build_resx (int);
 gimple gimple_build_eh_dispatch (int);
 gimple gimple_build_switch_nlabels (unsigned, tree, tree);
 gimple gimple_build_switch (tree, tree, vec<tree> );
+gimple gimple_build_oacc_parallel (gimple_seq, tree);
 gimple gimple_build_omp_parallel (gimple_seq, tree, tree, tree);
 gimple gimple_build_omp_task (gimple_seq, tree, tree, tree, tree, tree, tree);
 gimple gimple_build_omp_for (gimple_seq, int, tree, size_t, gimple_seq);
@@ -1256,6 +1257,7 @@ gimple_has_substatements (gimple g)
     case GIMPLE_EH_FILTER:
     case GIMPLE_EH_ELSE:
     case GIMPLE_TRY:
+    case GIMPLE_OACC_PARALLEL:
     case GIMPLE_OMP_FOR:
     case GIMPLE_OMP_MASTER:
     case GIMPLE_OMP_TASKGROUP:
@@ -4061,6 +4063,92 @@ gimple_omp_set_body (gimple gs, gimple_seq body)
 }
 
 
+/* Return the clauses associated with OACC_PARALLEL statement GS.  */
+
+static inline tree
+gimple_oacc_parallel_clauses (const_gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OACC_PARALLEL);
+  return gs->gimple_omp_parallel.clauses;
+}
+
+/* Return a pointer to the clauses associated with OACC_PARALLEL statement
+   GS.  */
+
+static inline tree *
+gimple_oacc_parallel_clauses_ptr (gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OACC_PARALLEL);
+  return &gs->gimple_omp_parallel.clauses;
+}
+
+/* Set CLAUSES to be the list of clauses associated with OACC_PARALLEL
+   statement GS.  */
+
+static inline void
+gimple_oacc_parallel_set_clauses (gimple gs, tree clauses)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OACC_PARALLEL);
+  gs->gimple_omp_parallel.clauses = clauses;
+}
+
+/* Return the child function used to hold the body of OACC_PARALLEL statement
+   GS.  */
+
+static inline tree
+gimple_oacc_parallel_child_fn (const_gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OACC_PARALLEL);
+  return gs->gimple_omp_parallel.child_fn;
+}
+
+/* Return a pointer to the child function used to hold the body of
+   OACC_PARALLEL statement GS.  */
+
+static inline tree *
+gimple_oacc_parallel_child_fn_ptr (gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OACC_PARALLEL);
+  return &gs->gimple_omp_parallel.child_fn;
+}
+
+/* Set CHILD_FN to be the child function for OACC_PARALLEL statement GS.  */
+
+static inline void
+gimple_oacc_parallel_set_child_fn (gimple gs, tree child_fn)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OACC_PARALLEL);
+  gs->gimple_omp_parallel.child_fn = child_fn;
+}
+
+/* Return the data argument for OACC_PARALLEL statement GS.  */
+
+static inline tree
+gimple_oacc_parallel_data_arg (const_gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OACC_PARALLEL);
+  return gs->gimple_omp_parallel.data_arg;
+}
+
+/* Return a pointer to the data argument for OACC_PARALLEL statement GS.  */
+
+static inline tree *
+gimple_oacc_parallel_data_arg_ptr (gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OACC_PARALLEL);
+  return &gs->gimple_omp_parallel.data_arg;
+}
+
+/* Set DATA_ARG to be the data argument for OACC_PARALLEL statement GS.  */
+
+static inline void
+gimple_oacc_parallel_set_data_arg (gimple gs, tree data_arg)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OACC_PARALLEL);
+  gs->gimple_omp_parallel.data_arg = data_arg;
+}
+
+
 /* Return the name associated with OMP_CRITICAL statement GS.  */
 
 static inline tree
@@ -5269,6 +5357,7 @@ gimple_return_set_retbnd (gimple gs, tree retval)
 /* Returns true when the gimple statement STMT is any of the OpenMP types.  */
 
 #define CASE_GIMPLE_OMP				\
+    case GIMPLE_OACC_PARALLEL:			\
     case GIMPLE_OMP_PARALLEL:			\
     case GIMPLE_OMP_TASK:			\
     case GIMPLE_OMP_FOR:			\
diff --git gcc/gimplify.c gcc/gimplify.c
index 30c2b45..0c45729 100644
--- gcc/gimplify.c
+++ gcc/gimplify.c
@@ -4641,6 +4641,7 @@ is_gimple_stmt (tree t)
     case CATCH_EXPR:
     case ASM_EXPR:
     case STATEMENT_LIST:
+    case OACC_PARALLEL:
     case OMP_PARALLEL:
     case OMP_FOR:
     case OMP_SIMD:
@@ -6745,6 +6746,37 @@ gimplify_adjust_omp_clauses (tree *list_p)
   delete_omp_context (ctx);
 }
 
+/* Gimplify the contents of an OACC_PARALLEL statement.  This involves
+   gimplification of the body, as well as scanning the body for used
+   variables.  We need to do this scan now, because variable-sized
+   decls will be decomposed during gimplification.  */
+
+static void
+gimplify_oacc_parallel (tree *expr_p, gimple_seq *pre_p)
+{
+  tree expr = *expr_p;
+  gimple g;
+  gimple_seq body = NULL;
+  struct gimplify_ctx gctx;
+
+  gimplify_scan_omp_clauses (&OACC_PARALLEL_CLAUSES (expr), pre_p,
+			     ORT_TARGET);
+
+  push_gimplify_context (&gctx);
+
+  g = gimplify_and_return_first (OACC_PARALLEL_BODY (expr), &body);
+  if (gimple_code (g) == GIMPLE_BIND)
+    pop_gimplify_context (g);
+  else
+    pop_gimplify_context (NULL);
+
+  gimplify_adjust_omp_clauses (&OACC_PARALLEL_CLAUSES (expr));
+
+  g = gimple_build_oacc_parallel (body, OACC_PARALLEL_CLAUSES (expr));
+  gimplify_seq_add_stmt (pre_p, g);
+  *expr_p = NULL_TREE;
+}
+
 /* Gimplify the contents of an OMP_PARALLEL statement.  This involves
    gimplification of the body, as well as scanning the body for used
    variables.  We need to do this scan now, because variable-sized
@@ -8169,6 +8201,11 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
 	  ret = GS_ALL_DONE;
 	  break;
 
+	case OACC_PARALLEL:
+	  gimplify_oacc_parallel (expr_p, pre_p);
+	  ret = GS_ALL_DONE;
+	  break;
+
 	case OMP_PARALLEL:
 	  gimplify_omp_parallel (expr_p, pre_p);
 	  ret = GS_ALL_DONE;
@@ -8575,6 +8612,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
 		  && code != LOOP_EXPR
 		  && code != SWITCH_EXPR
 		  && code != TRY_FINALLY_EXPR
+		  && code != OACC_PARALLEL
 		  && code != OMP_CRITICAL
 		  && code != OMP_FOR
 		  && code != OMP_MASTER
diff --git gcc/oacc-builtins.def gcc/oacc-builtins.def
index fd630e0..a75e42d 100644
--- gcc/oacc-builtins.def
+++ gcc/oacc-builtins.def
@@ -26,3 +26,6 @@ along with GCC; see the file COPYING3.  If not see
      DEF_GOACC_BUILTIN (ENUM, NAME, TYPE, ATTRS)
 
    See builtins.def for details.  */
+
+DEF_GOACC_BUILTIN (BUILT_IN_GOACC_PARALLEL, "GOACC_parallel",
+		   BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR, ATTR_NOTHROW_LIST)
diff --git gcc/omp-low.c gcc/omp-low.c
index 99811d0..84fe466 100644
--- gcc/omp-low.c
+++ gcc/omp-low.c
@@ -844,6 +844,8 @@ use_pointer_for_field (tree decl, omp_context *shared_ctx)
      when we know the value is not accessible from an outer scope.  */
   if (shared_ctx)
     {
+      gcc_assert (gimple_code (shared_ctx->stmt) != GIMPLE_OACC_PARALLEL);
+
       /* ??? Trivially accessible from anywhere.  But why would we even
 	 be passing an address in this case?  Should we simply assert
 	 this to be false, or should we have a cleanup pass that removes
@@ -985,6 +987,8 @@ build_receiver_ref (tree var, bool by_ref, omp_context *ctx)
 static tree
 build_outer_var_ref (tree var, omp_context *ctx)
 {
+  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
+
   tree x;
 
   if (is_global_var (maybe_lookup_decl_in_outer_ctx (var, ctx)))
@@ -1484,6 +1488,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
       switch (OMP_CLAUSE_CODE (c))
 	{
 	case OMP_CLAUSE_PRIVATE:
+	  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	  decl = OMP_CLAUSE_DECL (c);
 	  if (OMP_CLAUSE_PRIVATE_OUTER_REF (c))
 	    goto do_private;
@@ -1492,6 +1497,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 	  break;
 
 	case OMP_CLAUSE_SHARED:
+	  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	  /* Ignore shared directives in teams construct.  */
 	  if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS)
 	    break;
@@ -1518,6 +1524,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 	  goto do_private;
 
 	case OMP_CLAUSE_LASTPRIVATE:
+	  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	  /* Let the corresponding firstprivate clause create
 	     the variable.  */
 	  if (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c))
@@ -1527,6 +1534,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 	case OMP_CLAUSE_FIRSTPRIVATE:
 	case OMP_CLAUSE_REDUCTION:
 	case OMP_CLAUSE_LINEAR:
+	  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	  decl = OMP_CLAUSE_DECL (c);
 	do_private:
 	  if (is_variable_sized (decl))
@@ -1555,6 +1563,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 	  break;
 
 	case OMP_CLAUSE__LOOPTEMP_:
+	  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	  gcc_assert (is_parallel_ctx (ctx));
 	  decl = OMP_CLAUSE_DECL (c);
 	  install_var_field (decl, false, 3, ctx);
@@ -1563,12 +1572,14 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 
 	case OMP_CLAUSE_COPYPRIVATE:
 	case OMP_CLAUSE_COPYIN:
+	  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	  decl = OMP_CLAUSE_DECL (c);
 	  by_ref = use_pointer_for_field (decl, NULL);
 	  install_var_field (decl, by_ref, 3, ctx);
 	  break;
 
 	case OMP_CLAUSE_DEFAULT:
+	  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	  ctx->default_kind = OMP_CLAUSE_DEFAULT_KIND (c);
 	  break;
 
@@ -1581,6 +1592,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 	case OMP_CLAUSE_SCHEDULE:
 	case OMP_CLAUSE_DIST_SCHEDULE:
 	case OMP_CLAUSE_DEPEND:
+	  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	  if (ctx->outer)
 	    scan_omp_op (&OMP_CLAUSE_OPERAND (c, 0), ctx->outer);
 	  break;
@@ -1599,10 +1611,14 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 	      && is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx))
 	      && lookup_attribute ("omp declare target",
 				   DECL_ATTRIBUTES (decl)))
+	    {
+	      gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	    break;
+	    }
 	  if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
 	      && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER)
 	    {
+	      gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	      /* Ignore OMP_CLAUSE_MAP_POINTER kind for arrays in
 		 #pragma omp target data, there is nothing to map for
 		 those.  */
@@ -1632,8 +1648,9 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 		    install_var_field (decl, true, 7, ctx);
 		  else
 		    install_var_field (decl, true, 3, ctx);
-		  if (gimple_omp_target_kind (ctx->stmt)
-		      == GF_OMP_TARGET_KIND_REGION)
+		  if (gimple_code (ctx->stmt) == GIMPLE_OACC_PARALLEL
+		      || (gimple_omp_target_kind (ctx->stmt)
+			  == GF_OMP_TARGET_KIND_REGION))
 		    install_var_local (decl, ctx);
 		}
 	    }
@@ -1673,9 +1690,11 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 	case OMP_CLAUSE_MERGEABLE:
 	case OMP_CLAUSE_PROC_BIND:
 	case OMP_CLAUSE_SAFELEN:
+	  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	  break;
 
 	case OMP_CLAUSE_ALIGNED:
+	  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	  decl = OMP_CLAUSE_DECL (c);
 	  if (is_global_var (decl)
 	      && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
@@ -1692,6 +1711,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
       switch (OMP_CLAUSE_CODE (c))
 	{
 	case OMP_CLAUSE_LASTPRIVATE:
+	  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	  /* Let the corresponding firstprivate clause create
 	     the variable.  */
 	  if (OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c))
@@ -1704,6 +1724,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 	case OMP_CLAUSE_FIRSTPRIVATE:
 	case OMP_CLAUSE_REDUCTION:
 	case OMP_CLAUSE_LINEAR:
+	  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	  decl = OMP_CLAUSE_DECL (c);
 	  if (is_variable_sized (decl))
 	    install_var_local (decl, ctx);
@@ -1716,6 +1737,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 	  break;
 
 	case OMP_CLAUSE_SHARED:
+	  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	  /* Ignore shared directives in teams construct.  */
 	  if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS)
 	    break;
@@ -1725,14 +1747,18 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 	  break;
 
 	case OMP_CLAUSE_MAP:
-	  if (gimple_omp_target_kind (ctx->stmt) == GF_OMP_TARGET_KIND_DATA)
+	  if (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL
+	      && gimple_omp_target_kind (ctx->stmt) == GF_OMP_TARGET_KIND_DATA)
 	    break;
 	  decl = OMP_CLAUSE_DECL (c);
 	  if (DECL_P (decl)
 	      && is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx))
 	      && lookup_attribute ("omp declare target",
 				   DECL_ATTRIBUTES (decl)))
+	    {
+	      gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	    break;
+	    }
 	  if (DECL_P (decl))
 	    {
 	      if (OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER
@@ -1781,6 +1807,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 	case OMP_CLAUSE__LOOPTEMP_:
 	case OMP_CLAUSE_TO:
 	case OMP_CLAUSE_FROM:
+	  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
 	  break;
 
 	default:
@@ -1789,6 +1816,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
     }
 
   if (scan_array_reductions)
+    {
+      gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
     for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
       if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
 	  && OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
@@ -1799,6 +1828,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
       else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
 	       && OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c))
 	scan_omp (&OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c), ctx);
+    }
 }
 
 /* Create a new name for omp child function.  Returns an identifier.  */
@@ -1830,6 +1860,8 @@ create_omp_child_function (omp_context *ctx, bool task_copy)
   decl = build_decl (gimple_location (ctx->stmt),
 		     FUNCTION_DECL, name, type);
 
+  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL
+	      || !task_copy);
   if (!task_copy)
     ctx->cb.dst_fn = decl;
   else
@@ -1861,6 +1893,8 @@ create_omp_child_function (omp_context *ctx, bool task_copy)
 	    break;
 	  }
     }
+  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL
+	      || !target_p);
   if (target_p)
     DECL_ATTRIBUTES (decl)
       = tree_cons (get_identifier ("omp declare target"),
@@ -1935,6 +1969,52 @@ find_combined_for (gimple_stmt_iterator *gsi_p,
   return NULL;
 }
 
+/* Scan an OpenACC parallel directive.  */
+
+static void
+scan_oacc_parallel (gimple stmt, omp_context *outer_ctx)
+{
+  omp_context *ctx;
+  tree name;
+
+  gcc_assert (taskreg_nesting_level == 0);
+  gcc_assert (target_nesting_level == 0);
+
+  ctx = new_omp_context (stmt, outer_ctx);
+  ctx->field_map = splay_tree_new (splay_tree_compare_pointers, 0, 0);
+  ctx->default_kind = OMP_CLAUSE_DEFAULT_SHARED;
+  ctx->record_type = lang_hooks.types.make_type (RECORD_TYPE);
+  name = create_tmp_var_name (".omp_data_t");
+  name = build_decl (gimple_location (stmt),
+		     TYPE_DECL, name, ctx->record_type);
+  DECL_ARTIFICIAL (name) = 1;
+  DECL_NAMELESS (name) = 1;
+  TYPE_NAME (ctx->record_type) = name;
+  create_omp_child_function (ctx, false);
+  gimple_oacc_parallel_set_child_fn (stmt, ctx->cb.dst_fn);
+
+  scan_sharing_clauses (gimple_oacc_parallel_clauses (stmt), ctx);
+  scan_omp (gimple_omp_body_ptr (stmt), ctx);
+
+  if (TYPE_FIELDS (ctx->record_type) == NULL)
+    ctx->record_type = ctx->receiver_decl = NULL;
+  else
+    {
+      TYPE_FIELDS (ctx->record_type)
+	= nreverse (TYPE_FIELDS (ctx->record_type));
+#ifdef ENABLE_CHECKING
+      tree field;
+      unsigned int align = DECL_ALIGN (TYPE_FIELDS (ctx->record_type));
+      for (field = TYPE_FIELDS (ctx->record_type);
+	   field;
+	   field = DECL_CHAIN (field))
+	gcc_assert (DECL_ALIGN (field) == align);
+#endif
+      layout_type (ctx->record_type);
+      fixup_child_record_type (ctx);
+    }
+}
+
 /* Scan an OpenMP parallel directive.  */
 
 static void
@@ -2225,6 +2305,38 @@ scan_omp_teams (gimple stmt, omp_context *outer_ctx)
 static bool
 check_omp_nesting_restrictions (gimple stmt, omp_context *ctx)
 {
+  omp_context *ctx_;
+
+  /* TODO: While the OpenACC specification does allow for certain kinds of
+     nesting, we don't support that yet.  */
+  /* No nesting of STMT (which is an OpenACC or OpenMP one, or a GOMP builtin)
+     inside any OpenACC CTX.  */
+  for (ctx_ = ctx; ctx_ != NULL; ctx_ = ctx_->outer)
+    switch (gimple_code (ctx_->stmt))
+      {
+      case GIMPLE_OACC_PARALLEL:
+	error_at (gimple_location (stmt),
+		  "may not be nested");
+	return false;
+      default:
+	break;
+      }
+  /* No nesting of OpenACC STMT inside any OpenACC or OpenMP CTX.  */
+  switch (gimple_code (stmt))
+    {
+    case GIMPLE_OACC_PARALLEL:
+      for (ctx_ = ctx; ctx_ != NULL; ctx_ = ctx_->outer)
+	if (is_gimple_omp (ctx_->stmt))
+	  {
+	    error_at (gimple_location (stmt),
+		      "may not be nested");
+	    return false;
+	  }
+      break;
+    default:
+      break;
+    }
+
   if (ctx != NULL)
     {
       if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR
@@ -2584,6 +2696,10 @@ scan_omp_1_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
 
   switch (gimple_code (stmt))
     {
+    case GIMPLE_OACC_PARALLEL:
+      scan_oacc_parallel (stmt, ctx);
+      break;
+
     case GIMPLE_OMP_PARALLEL:
       taskreg_nesting_level++;
       scan_omp_parallel (gsi, ctx);
@@ -2910,6 +3026,8 @@ static bool
 lower_rec_simd_input_clauses (tree new_var, omp_context *ctx, int &max_vf,
 			      tree &idx, tree &lane, tree &ivar, tree &lvar)
 {
+  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
+
   if (max_vf == 0)
     {
       max_vf = omp_max_vf ();
@@ -2959,6 +3077,8 @@ static void
 lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
 			 omp_context *ctx, struct omp_for_data *fd)
 {
+  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
+
   tree c, dtor, copyin_seq, x, ptr;
   bool copyin_by_ref = false;
   bool lastprivate_firstprivate = false;
@@ -3617,6 +3737,8 @@ static void
 lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *stmt_list,
 			   omp_context *ctx)
 {
+  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
+
   tree x, c, label = NULL, orig_clauses = clauses;
   bool par_clauses = false;
   tree simduid = NULL, lastlane = NULL;
@@ -3752,6 +3874,8 @@ lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *stmt_list,
 static void
 lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp, omp_context *ctx)
 {
+  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
+
   gimple_seq sub_seq = NULL;
   gimple stmt;
   tree x, c;
@@ -3853,6 +3977,8 @@ static void
 lower_copyprivate_clauses (tree clauses, gimple_seq *slist, gimple_seq *rlist,
 			    omp_context *ctx)
 {
+  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
+
   tree c;
 
   for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
@@ -3903,6 +4029,8 @@ static void
 lower_send_clauses (tree clauses, gimple_seq *ilist, gimple_seq *olist,
     		    omp_context *ctx)
 {
+  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
+
   tree c;
 
   for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
@@ -3994,6 +4122,8 @@ lower_send_clauses (tree clauses, gimple_seq *ilist, gimple_seq *olist,
 static void
 lower_send_shared_vars (gimple_seq *ilist, gimple_seq *olist, omp_context *ctx)
 {
+  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
+
   tree var, ovar, nvar, f, x, record_type;
 
   if (ctx->record_type == NULL)
@@ -4542,6 +4672,234 @@ expand_omp_build_assign (gimple_stmt_iterator *gsi_p, tree to, tree from)
     }
 }
 
+/* Expand the OpenACC parallel directive starting at REGION.  */
+
+static void
+expand_oacc_parallel (struct omp_region *region)
+{
+  basic_block entry_bb, exit_bb, new_bb;
+  struct function *child_cfun;
+  tree child_fn, block, t;
+  gimple_stmt_iterator gsi;
+  gimple entry_stmt, stmt;
+  edge e;
+
+  entry_stmt = last_stmt (region->entry);
+  child_fn = gimple_oacc_parallel_child_fn (entry_stmt);
+  child_cfun = DECL_STRUCT_FUNCTION (child_fn);
+
+  /* Supported by expand_omp_taskreg, but not here.  */
+  gcc_assert (!child_cfun->cfg);
+  gcc_assert (!gimple_in_ssa_p (cfun));
+
+  entry_bb = region->entry;
+  exit_bb = region->exit;
+
+  /* Preserve indentation of expand_omp_target and expand_omp_taskreg.  */
+  if (1)
+    {
+      unsigned srcidx, dstidx, num;
+
+      /* If the parallel region needs data sent from the parent
+	 function, then the very first statement (except possible
+	 tree profile counter updates) of the parallel body
+	 is a copy assignment .OMP_DATA_I = &.OMP_DATA_O.  Since
+	 &.OMP_DATA_O is passed as an argument to the child function,
+	 we need to replace it with the argument as seen by the child
+	 function.
+
+	 In most cases, this will end up being the identity assignment
+	 .OMP_DATA_I = .OMP_DATA_I.  However, if the parallel body had
+	 a function call that has been inlined, the original PARM_DECL
+	 .OMP_DATA_I may have been converted into a different local
+	 variable.  In which case, we need to keep the assignment.  */
+      if (gimple_oacc_parallel_data_arg (entry_stmt))
+	{
+	  basic_block entry_succ_bb = single_succ (entry_bb);
+	  gimple_stmt_iterator gsi;
+	  tree arg;
+	  gimple parcopy_stmt = NULL;
+	  tree sender
+	    = TREE_VEC_ELT (gimple_oacc_parallel_data_arg (entry_stmt), 0);
+
+	  for (gsi = gsi_start_bb (entry_succ_bb); ; gsi_next (&gsi))
+	    {
+	      gcc_assert (!gsi_end_p (gsi));
+	      stmt = gsi_stmt (gsi);
+	      if (gimple_code (stmt) != GIMPLE_ASSIGN)
+		continue;
+
+	      if (gimple_num_ops (stmt) == 2)
+		{
+		  tree arg = gimple_assign_rhs1 (stmt);
+
+		  /* We're ignore the subcode because we're
+		     effectively doing a STRIP_NOPS.  */
+
+		  if (TREE_CODE (arg) == ADDR_EXPR
+		      && TREE_OPERAND (arg, 0) == sender)
+		    {
+		      parcopy_stmt = stmt;
+		      break;
+		    }
+		}
+	    }
+
+	  gcc_assert (parcopy_stmt != NULL);
+	  arg = DECL_ARGUMENTS (child_fn);
+
+	  gcc_assert (gimple_assign_lhs (parcopy_stmt) == arg);
+	  gsi_remove (&gsi, true);
+	}
+
+      /* Declare local variables needed in CHILD_CFUN.  */
+      block = DECL_INITIAL (child_fn);
+      BLOCK_VARS (block) = vec2chain (child_cfun->local_decls);
+      /* The gimplifier could record temporaries in the block
+	 rather than in containing function's local_decls chain,
+	 which would mean cgraph missed finalizing them.  Do it now.  */
+      for (t = BLOCK_VARS (block); t; t = DECL_CHAIN (t))
+	if (TREE_CODE (t) == VAR_DECL
+	    && TREE_STATIC (t)
+	    && !DECL_EXTERNAL (t))
+	  varpool_finalize_decl (t);
+      DECL_SAVED_TREE (child_fn) = NULL;
+      /* We'll create a CFG for child_fn, so no gimple body is needed.  */
+      gimple_set_body (child_fn, NULL);
+      TREE_USED (block) = 1;
+
+      /* Reset DECL_CONTEXT on function arguments.  */
+      for (t = DECL_ARGUMENTS (child_fn); t; t = DECL_CHAIN (t))
+	DECL_CONTEXT (t) = child_fn;
+
+      /* Split ENTRY_BB at GIMPLE_OACC_PARALLEL,
+	 so that it can be moved to the child function.  */
+      gsi = gsi_last_bb (entry_bb);
+      stmt = gsi_stmt (gsi);
+      gcc_assert (stmt && (gimple_code (stmt) == GIMPLE_OACC_PARALLEL));
+      gsi_remove (&gsi, true);
+      e = split_block (entry_bb, stmt);
+      entry_bb = e->dest;
+      single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
+
+      /* Convert GIMPLE_OMP_RETURN into a RETURN_EXPR.  */
+      if (exit_bb)
+	{
+	  gsi = gsi_last_bb (exit_bb);
+	  gcc_assert (!gsi_end_p (gsi)
+		      && gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
+	  stmt = gimple_build_return (NULL);
+	  gsi_insert_after (&gsi, stmt, GSI_SAME_STMT);
+	  gsi_remove (&gsi, true);
+	}
+
+      /* Move the region into CHILD_CFUN.  */
+
+      block = gimple_block (entry_stmt);
+
+      new_bb = move_sese_region_to_fn (child_cfun, entry_bb, exit_bb, block);
+      if (exit_bb)
+	single_succ_edge (new_bb)->flags = EDGE_FALLTHRU;
+      /* When the expansion process cannot guarantee an up-to-date
+         loop tree arrange for the child function to fixup loops.  */
+      if (loops_state_satisfies_p (LOOPS_NEED_FIXUP))
+	child_cfun->x_current_loops->state |= LOOPS_NEED_FIXUP;
+
+      /* Remove non-local VAR_DECLs from child_cfun->local_decls list.  */
+      num = vec_safe_length (child_cfun->local_decls);
+      for (srcidx = 0, dstidx = 0; srcidx < num; srcidx++)
+	{
+	  t = (*child_cfun->local_decls)[srcidx];
+	  if (DECL_CONTEXT (t) == cfun->decl)
+	    continue;
+	  if (srcidx != dstidx)
+	    (*child_cfun->local_decls)[dstidx] = t;
+	  dstidx++;
+	}
+      if (dstidx != num)
+	vec_safe_truncate (child_cfun->local_decls, dstidx);
+
+      /* Inform the callgraph about the new function.  */
+      DECL_STRUCT_FUNCTION (child_fn)->curr_properties = cfun->curr_properties;
+      cgraph_add_new_function (child_fn, true);
+
+      /* Fix the callgraph edges for child_cfun.  Those for cfun will be
+	 fixed in a following pass.  */
+      push_cfun (child_cfun);
+      rebuild_cgraph_edges ();
+
+      /* Some EH regions might become dead, see PR34608.  If
+	 pass_cleanup_cfg isn't the first pass to happen with the
+	 new child, these dead EH edges might cause problems.
+	 Clean them up now.  */
+      if (flag_exceptions)
+	{
+	  basic_block bb;
+	  bool changed = false;
+
+	  FOR_EACH_BB (bb)
+	    changed |= gimple_purge_dead_eh_edges (bb);
+	  if (changed)
+	    cleanup_tree_cfg ();
+	}
+      pop_cfun ();
+    }
+
+  /* Emit a library call to launch CHILD_FN.  */
+  tree t1, t2, t3, t4, device, c, clauses;
+  enum built_in_function start_ix;
+  location_t clause_loc;
+
+  clauses = gimple_oacc_parallel_clauses (entry_stmt);
+
+  start_ix = BUILT_IN_GOACC_PARALLEL;
+
+  /* By default, the value of DEVICE is -1 (let runtime library choose).  */
+  device = build_int_cst (integer_type_node, -1);
+
+  c = find_omp_clause (clauses, OMP_CLAUSE_DEVICE);
+  gcc_assert (c == NULL);
+  if (c)
+    {
+      device = OMP_CLAUSE_DEVICE_ID (c);
+      clause_loc = OMP_CLAUSE_LOCATION (c);
+    }
+  else
+    clause_loc = gimple_location (entry_stmt);
+
+  /* Ensure 'device' is of the correct type.  */
+  device = fold_convert_loc (clause_loc, integer_type_node, device);
+
+  gsi = gsi_last_bb (new_bb);
+  t = gimple_oacc_parallel_data_arg (entry_stmt);
+  if (t == NULL)
+    {
+      t1 = size_zero_node;
+      t2 = build_zero_cst (ptr_type_node);
+      t3 = t2;
+      t4 = t2;
+    }
+  else
+    {
+      t1 = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (TREE_VEC_ELT (t, 1))));
+      t1 = size_binop (PLUS_EXPR, t1, size_int (1));
+      t2 = build_fold_addr_expr (TREE_VEC_ELT (t, 0));
+      t3 = build_fold_addr_expr (TREE_VEC_ELT (t, 1));
+      t4 = build_fold_addr_expr (TREE_VEC_ELT (t, 2));
+    }
+
+  gimple g;
+  /* FIXME: This will be address of
+     extern char __OPENMP_TARGET__[] __attribute__((visibility ("hidden")))
+     symbol, as soon as the linker plugin is able to create it for us.  */
+  tree openmp_target = build_zero_cst (ptr_type_node);
+  tree fnaddr = build_fold_addr_expr (child_fn);
+  g = gimple_build_call (builtin_decl_explicit (start_ix),
+			 7, device, fnaddr, openmp_target, t1, t2, t3, t4);
+  gimple_set_location (g, gimple_location (entry_stmt));
+  gsi_insert_before (&gsi, g, GSI_SAME_STMT);
+}
+
 /* Expand the OpenMP parallel or task directive starting at REGION.  */
 
 static void
@@ -8037,6 +8395,10 @@ expand_omp (struct omp_region *region)
 
       switch (region->type)
 	{
+	case GIMPLE_OACC_PARALLEL:
+	  expand_oacc_parallel (region);
+	  break;
+
 	case GIMPLE_OMP_PARALLEL:
 	case GIMPLE_OMP_TASK:
 	  expand_omp_taskreg (region);
@@ -8278,6 +8640,288 @@ make_pass_expand_omp (gcc::context *ctxt)
 \f
 /* Routines to lower OpenMP directives into OMP-GIMPLE.  */
 
+/* Lower the OpenACC parallel directive in the current statement
+   in GSI_P.  CTX holds context information for the directive.  */
+
+static void
+lower_oacc_parallel (gimple_stmt_iterator *gsi_p, omp_context *ctx)
+{
+  tree clauses;
+  tree child_fn, t, c;
+  gimple stmt = gsi_stmt (*gsi_p);
+  gimple par_bind, bind;
+  gimple_seq par_body, olist, ilist, new_body;
+  struct gimplify_ctx gctx;
+  location_t loc = gimple_location (stmt);
+  unsigned int map_cnt = 0;
+
+  clauses = gimple_oacc_parallel_clauses (stmt);
+  par_bind = gimple_seq_first_stmt (gimple_omp_body (stmt));
+  par_body = gimple_bind_body (par_bind);
+  child_fn = ctx->cb.dst_fn;
+
+  push_gimplify_context (&gctx);
+
+  for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+    switch (OMP_CLAUSE_CODE (c))
+      {
+	tree var, x;
+
+      default:
+	break;
+      case OMP_CLAUSE_MAP:
+      case OMP_CLAUSE_TO:
+      case OMP_CLAUSE_FROM:
+	var = OMP_CLAUSE_DECL (c);
+	if (!DECL_P (var))
+	  {
+	    if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP
+		|| !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c))
+	      map_cnt++;
+	    continue;
+	  }
+
+	if (DECL_SIZE (var)
+	    && TREE_CODE (DECL_SIZE (var)) != INTEGER_CST)
+	  {
+	    tree var2 = DECL_VALUE_EXPR (var);
+	    gcc_assert (TREE_CODE (var2) == INDIRECT_REF);
+	    var2 = TREE_OPERAND (var2, 0);
+	    gcc_assert (DECL_P (var2));
+	    var = var2;
+	  }
+
+	if (!maybe_lookup_field (var, ctx))
+	  continue;
+
+	/* Preserve indentation of lower_omp_target.  */
+	if (1)
+	  {
+	    x = build_receiver_ref (var, true, ctx);
+	    tree new_var = lookup_decl (var, ctx);
+	    if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+		&& OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER
+		&& !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c)
+		&& TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE)
+	      x = build_simple_mem_ref (x);
+	    SET_DECL_VALUE_EXPR (new_var, x);
+	    DECL_HAS_VALUE_EXPR_P (new_var) = 1;
+	  }
+	map_cnt++;
+      }
+
+  target_nesting_level++;
+  lower_omp (&par_body, ctx);
+  target_nesting_level--;
+
+  /* Declare all the variables created by mapping and the variables
+     declared in the scope of the body.  */
+  record_vars_into (ctx->block_vars, child_fn);
+  record_vars_into (gimple_bind_vars (par_bind), child_fn);
+
+  olist = NULL;
+  ilist = NULL;
+  if (ctx->record_type)
+    {
+      ctx->sender_decl
+	= create_tmp_var (ctx->record_type, ".omp_data_arr");
+      DECL_NAMELESS (ctx->sender_decl) = 1;
+      TREE_ADDRESSABLE (ctx->sender_decl) = 1;
+      t = make_tree_vec (3);
+      TREE_VEC_ELT (t, 0) = ctx->sender_decl;
+      TREE_VEC_ELT (t, 1)
+	= create_tmp_var (build_array_type_nelts (size_type_node, map_cnt),
+			  ".omp_data_sizes");
+      DECL_NAMELESS (TREE_VEC_ELT (t, 1)) = 1;
+      TREE_ADDRESSABLE (TREE_VEC_ELT (t, 1)) = 1;
+      TREE_STATIC (TREE_VEC_ELT (t, 1)) = 1;
+      TREE_VEC_ELT (t, 2)
+	= create_tmp_var (build_array_type_nelts (unsigned_char_type_node,
+						  map_cnt),
+			  ".omp_data_kinds");
+      DECL_NAMELESS (TREE_VEC_ELT (t, 2)) = 1;
+      TREE_ADDRESSABLE (TREE_VEC_ELT (t, 2)) = 1;
+      TREE_STATIC (TREE_VEC_ELT (t, 2)) = 1;
+      gimple_oacc_parallel_set_data_arg (stmt, t);
+
+      vec<constructor_elt, va_gc> *vsize;
+      vec<constructor_elt, va_gc> *vkind;
+      vec_alloc (vsize, map_cnt);
+      vec_alloc (vkind, map_cnt);
+      unsigned int map_idx = 0;
+
+      for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+	switch (OMP_CLAUSE_CODE (c))
+	  {
+	    tree ovar, nc;
+
+	  default:
+	    break;
+	  case OMP_CLAUSE_MAP:
+	  case OMP_CLAUSE_TO:
+	  case OMP_CLAUSE_FROM:
+	    nc = c;
+	    ovar = OMP_CLAUSE_DECL (c);
+	    if (!DECL_P (ovar))
+	      {
+		if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+		    && OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c))
+		  {
+		    gcc_checking_assert (OMP_CLAUSE_DECL (OMP_CLAUSE_CHAIN (c))
+					 == get_base_address (ovar));
+		    nc = OMP_CLAUSE_CHAIN (c);
+		    ovar = OMP_CLAUSE_DECL (nc);
+		  }
+		else
+		  {
+		    tree x = build_sender_ref (ovar, ctx);
+		    tree v
+		      = build_fold_addr_expr_with_type (ovar, ptr_type_node);
+		    gimplify_assign (x, v, &ilist);
+		    nc = NULL_TREE;
+		  }
+	      }
+	    else
+	      {
+		if (DECL_SIZE (ovar)
+		    && TREE_CODE (DECL_SIZE (ovar)) != INTEGER_CST)
+		  {
+		    tree ovar2 = DECL_VALUE_EXPR (ovar);
+		    gcc_assert (TREE_CODE (ovar2) == INDIRECT_REF);
+		    ovar2 = TREE_OPERAND (ovar2, 0);
+		    gcc_assert (DECL_P (ovar2));
+		    ovar = ovar2;
+		  }
+		if (!maybe_lookup_field (ovar, ctx))
+		  continue;
+	      }
+
+	    if (nc)
+	      {
+		tree var = lookup_decl_in_outer_ctx (ovar, ctx);
+		tree x = build_sender_ref (ovar, ctx);
+		if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+		    && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER
+		    && !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c)
+		    && TREE_CODE (TREE_TYPE (ovar)) == ARRAY_TYPE)
+		  {
+		    tree avar
+		      = create_tmp_var (TREE_TYPE (TREE_TYPE (x)), NULL);
+		    mark_addressable (avar);
+		    gimplify_assign (avar, build_fold_addr_expr (var), &ilist);
+		    avar = build_fold_addr_expr (avar);
+		    gimplify_assign (x, avar, &ilist);
+		  }
+		else if (is_gimple_reg (var))
+		  {
+		    tree avar = create_tmp_var (TREE_TYPE (var), NULL);
+		    mark_addressable (avar);
+		    if (OMP_CLAUSE_MAP_KIND (c) != OMP_CLAUSE_MAP_ALLOC
+			&& OMP_CLAUSE_MAP_KIND (c) != OMP_CLAUSE_MAP_FROM)
+		      gimplify_assign (avar, var, &ilist);
+		    avar = build_fold_addr_expr (avar);
+		    gimplify_assign (x, avar, &ilist);
+		    if ((OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_FROM
+			 || OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_TOFROM)
+			&& !TYPE_READONLY (TREE_TYPE (var)))
+		      {
+			x = build_sender_ref (ovar, ctx);
+			x = build_simple_mem_ref (x);
+			gimplify_assign (var, x, &olist);
+		      }
+		  }
+		else
+		  {
+		    var = build_fold_addr_expr (var);
+		    gimplify_assign (x, var, &ilist);
+		  }
+	      }
+	    tree s = OMP_CLAUSE_SIZE (c);
+	    if (s == NULL_TREE)
+	      s = TYPE_SIZE_UNIT (TREE_TYPE (ovar));
+	    s = fold_convert (size_type_node, s);
+	    tree purpose = size_int (map_idx++);
+	    CONSTRUCTOR_APPEND_ELT (vsize, purpose, s);
+	    if (TREE_CODE (s) != INTEGER_CST)
+	      TREE_STATIC (TREE_VEC_ELT (t, 1)) = 0;
+
+	    unsigned char tkind = 0;
+	    switch (OMP_CLAUSE_CODE (c))
+	      {
+	      case OMP_CLAUSE_MAP:
+		tkind = OMP_CLAUSE_MAP_KIND (c);
+		break;
+	      case OMP_CLAUSE_TO:
+		tkind = OMP_CLAUSE_MAP_TO;
+		break;
+	      case OMP_CLAUSE_FROM:
+		tkind = OMP_CLAUSE_MAP_FROM;
+		break;
+	      default:
+		gcc_unreachable ();
+	      }
+	    unsigned int talign = TYPE_ALIGN_UNIT (TREE_TYPE (ovar));
+	    if (DECL_P (ovar) && DECL_ALIGN_UNIT (ovar) > talign)
+	      talign = DECL_ALIGN_UNIT (ovar);
+	    talign = ceil_log2 (talign);
+	    tkind |= talign << 3;
+	    CONSTRUCTOR_APPEND_ELT (vkind, purpose,
+				    build_int_cst (unsigned_char_type_node,
+						   tkind));
+	    if (nc && nc != c)
+	      c = nc;
+	  }
+
+      gcc_assert (map_idx == map_cnt);
+
+      DECL_INITIAL (TREE_VEC_ELT (t, 1))
+	= build_constructor (TREE_TYPE (TREE_VEC_ELT (t, 1)), vsize);
+      DECL_INITIAL (TREE_VEC_ELT (t, 2))
+	= build_constructor (TREE_TYPE (TREE_VEC_ELT (t, 2)), vkind);
+      if (!TREE_STATIC (TREE_VEC_ELT (t, 1)))
+	{
+	  gimple_seq initlist = NULL;
+	  force_gimple_operand (build1 (DECL_EXPR, void_type_node,
+					TREE_VEC_ELT (t, 1)),
+				&initlist, true, NULL_TREE);
+	  gimple_seq_add_seq (&ilist, initlist);
+	}
+
+      tree clobber = build_constructor (ctx->record_type, NULL);
+      TREE_THIS_VOLATILE (clobber) = 1;
+      gimple_seq_add_stmt (&olist, gimple_build_assign (ctx->sender_decl,
+							clobber));
+    }
+
+  /* Once all the expansions are done, sequence all the different
+     fragments inside gimple_omp_body.  */
+
+  new_body = NULL;
+
+  if (ctx->record_type)
+    {
+      t = build_fold_addr_expr_loc (loc, ctx->sender_decl);
+      /* fixup_child_record_type might have changed receiver_decl's type.  */
+      t = fold_convert_loc (loc, TREE_TYPE (ctx->receiver_decl), t);
+      gimple_seq_add_stmt (&new_body,
+			   gimple_build_assign (ctx->receiver_decl, t));
+    }
+
+  gimple_seq_add_seq (&new_body, par_body);
+  gcc_assert (!ctx->cancellable);
+  new_body = maybe_catch_exception (new_body);
+  gimple_seq_add_stmt (&new_body, gimple_build_omp_return (false));
+  gimple_omp_set_body (stmt, new_body);
+
+  bind = gimple_build_bind (NULL, NULL, gimple_bind_block (par_bind));
+  gsi_replace (gsi_p, bind, true);
+  gimple_bind_add_seq (bind, ilist);
+  gimple_bind_add_stmt (bind, stmt);
+  gimple_bind_add_seq (bind, olist);
+
+  pop_gimplify_context (NULL);
+}
+
 /* If ctx is a worksharing context inside of a cancellable parallel
    region and it isn't nowait, add lhs to its GIMPLE_OMP_RETURN
    and conditional branch to parallel's cancel_label to handle
@@ -8286,6 +8930,8 @@ make_pass_expand_omp (gcc::context *ctxt)
 static void
 maybe_add_implicit_barrier_cancel (omp_context *ctx, gimple_seq *body)
 {
+  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
+
   gimple omp_return = gimple_seq_last_stmt (*body);
   gcc_assert (gimple_code (omp_return) == GIMPLE_OMP_RETURN);
   if (gimple_omp_return_nowait_p (omp_return))
@@ -9051,6 +9697,8 @@ task_copyfn_remap_type (struct omp_taskcopy_context *tcctx, tree orig_type)
 static void
 create_task_copyfn (gimple task_stmt, omp_context *ctx)
 {
+  gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OACC_PARALLEL);
+
   struct function *child_cfun;
   tree child_fn, t, c, src, dst, f, sf, arg, sarg, decl;
   tree record_type, srecord_type, bind, list;
@@ -9909,6 +10557,12 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p, omp_context *ctx)
     case GIMPLE_BIND:
       lower_omp (gimple_bind_body_ptr (stmt), ctx);
       break;
+    case GIMPLE_OACC_PARALLEL:
+      ctx = maybe_lookup_ctx (stmt);
+      gcc_assert (ctx);
+      gcc_assert (!ctx->cancellable);
+      lower_oacc_parallel (gsi_p, ctx);
+      break;
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
       ctx = maybe_lookup_ctx (stmt);
@@ -10357,6 +11011,7 @@ make_gimple_omp_edges (basic_block bb, struct omp_region **region)
 
   switch (code)
     {
+    case GIMPLE_OACC_PARALLEL:
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
     case GIMPLE_OMP_FOR:
diff --git gcc/testsuite/c-c++-common/goacc-gomp/nesting-fail-1.c gcc/testsuite/c-c++-common/goacc-gomp/nesting-fail-1.c
new file mode 100644
index 0000000..875ec66
--- /dev/null
+++ gcc/testsuite/c-c++-common/goacc-gomp/nesting-fail-1.c
@@ -0,0 +1,121 @@
+/* TODO: Some of these should either be allowed or fail with a more sensible
+   error message.  */
+void
+f1 (void)
+{
+  int i;
+
+#pragma omp parallel
+  {
+#pragma acc parallel	/* { dg-error "may not be nested" } */
+    ;
+  }
+
+#pragma omp for
+  for (i = 0; i < 3; i++)
+    {
+#pragma acc parallel	/* { dg-error "may not be nested" } */
+      ;
+    }
+
+#pragma omp sections
+  {
+#pragma acc parallel	/* { dg-error "may not be nested" } */
+    ;
+  }
+
+#pragma omp single
+  {
+#pragma acc parallel	/* { dg-error "may not be nested" } */
+    ;
+  }
+
+#pragma omp task
+  {
+#pragma acc parallel	/* { dg-error "may not be nested" } */
+    ;
+  }
+
+#pragma omp master
+  {
+#pragma acc parallel	/* { dg-error "may not be nested" } */
+    ;
+  }
+
+#pragma omp critical
+  {
+#pragma acc parallel	/* { dg-error "may not be nested" } */
+    ;
+  }
+
+#pragma omp ordered
+  {
+#pragma acc parallel	/* { dg-error "may not be nested" } */
+    ;
+  }
+}
+
+/* TODO: Some of these should either be allowed or fail with a more sensible
+   error message.  */
+void
+f2 (void)
+{
+#pragma acc parallel
+  {
+#pragma omp parallel	/* { dg-error "may not be nested" } */
+    ;
+  }
+
+#pragma acc parallel
+  {
+    int i;
+#pragma omp for		/* { dg-error "may not be nested" } */
+    for (i = 0; i < 3; i++)
+      ;
+  }
+
+#pragma acc parallel
+  {
+#pragma omp sections	/* { dg-error "may not be nested" } */
+    {
+      ;
+    }
+  }
+
+#pragma acc parallel
+  {
+#pragma omp single	/* { dg-error "may not be nested" } */
+    ;
+  }
+
+#pragma acc parallel
+  {
+#pragma omp task	/* { dg-error "may not be nested" } */
+    ;
+  }
+
+#pragma acc parallel
+  {
+#pragma omp master	/* { dg-error "may not be nested" } */
+    ;
+  }
+
+#pragma acc parallel
+  {
+#pragma omp critical	/* { dg-error "may not be nested" } */
+    ;
+  }
+
+#pragma acc parallel
+  {
+    int i;
+#pragma omp atomic write
+    i = 0;		/* { dg-error "may not be nested" } */
+  }
+
+#pragma acc parallel
+  {
+#pragma omp ordered	/* { dg-error "may not be nested" } */
+    ;
+  }
+}
diff --git gcc/testsuite/c-c++-common/goacc/nesting-fail-1.c gcc/testsuite/c-c++-common/goacc/nesting-fail-1.c
new file mode 100644
index 0000000..6501397
--- /dev/null
+++ gcc/testsuite/c-c++-common/goacc/nesting-fail-1.c
@@ -0,0 +1,11 @@
+/* TODO: While the OpenACC specification does allow for certain kinds of
+   nesting, we don't support that yet.  */
+void
+f1 (void)
+{
+#pragma acc parallel
+  {
+#pragma acc parallel	/* { dg-error "may not be nested" } */
+    ;
+  }
+}
diff --git gcc/testsuite/c-c++-common/goacc/parallel-1.c gcc/testsuite/c-c++-common/goacc/parallel-1.c
new file mode 100644
index 0000000..cd19527
--- /dev/null
+++ gcc/testsuite/c-c++-common/goacc/parallel-1.c
@@ -0,0 +1,6 @@
+void
+foo (void)
+{
+#pragma acc parallel
+  foo ();
+}
diff --git gcc/testsuite/c-c++-common/goacc/parallel-fail-1.c gcc/testsuite/c-c++-common/goacc/parallel-fail-1.c
new file mode 100644
index 0000000..efc6f14
--- /dev/null
+++ gcc/testsuite/c-c++-common/goacc/parallel-fail-1.c
@@ -0,0 +1,6 @@
+void
+foo (void)
+{
+#pragma acc parallel foo	/* { dg-error "expected clause before 'foo'" } */
+  foo ();
+}
diff --git gcc/tree-inline.c gcc/tree-inline.c
index 74f333b..eeb4992 100644
--- gcc/tree-inline.c
+++ gcc/tree-inline.c
@@ -1299,6 +1299,9 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
 	  copy = gimple_build_wce (s1);
 	  break;
 
+	case GIMPLE_OACC_PARALLEL:
+          abort ();
+
 	case GIMPLE_OMP_PARALLEL:
 	  s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
 	  copy = gimple_build_omp_parallel
@@ -3849,6 +3852,7 @@ estimate_num_insns (gimple stmt, eni_weights *weights)
               + estimate_num_insns_seq (gimple_omp_body (stmt), weights)
               + estimate_num_insns_seq (gimple_omp_for_pre_body (stmt), weights));
 
+    case GIMPLE_OACC_PARALLEL:
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
     case GIMPLE_OMP_CRITICAL:
diff --git gcc/tree-nested.c gcc/tree-nested.c
index dc63ef6..8aba4f4 100644
--- gcc/tree-nested.c
+++ gcc/tree-nested.c
@@ -1238,6 +1238,9 @@ convert_nonlocal_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
 	}
       break;
 
+    case GIMPLE_OACC_PARALLEL:
+      abort ();
+
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
       save_suppress = info->suppress_expansion;
@@ -1679,6 +1682,9 @@ convert_local_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
 
   switch (gimple_code (stmt))
     {
+    case GIMPLE_OACC_PARALLEL:
+      abort ();
+
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
       save_suppress = info->suppress_expansion;
@@ -2008,6 +2014,9 @@ convert_tramp_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
 	break;
       }
 
+    case GIMPLE_OACC_PARALLEL:
+      abort ();
+
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
       {
@@ -2068,6 +2077,9 @@ convert_gimple_call (gimple_stmt_iterator *gsi, bool *handled_ops_p,
 	}
       break;
 
+    case GIMPLE_OACC_PARALLEL:
+      abort ();
+
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
       save_static_chain_added = info->static_chain_added;
diff --git gcc/tree-pretty-print.c gcc/tree-pretty-print.c
index fe75633..153d01f 100644
--- gcc/tree-pretty-print.c
+++ gcc/tree-pretty-print.c
@@ -2346,6 +2346,11 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
       pp_string (buffer, " > ");
       break;
 
+    case OACC_PARALLEL:
+      pp_string (buffer, "#pragma acc parallel");
+      dump_omp_clauses (buffer, OACC_PARALLEL_CLAUSES (node), spc, flags);
+      goto dump_omp_body;
+
     case OMP_PARALLEL:
       pp_string (buffer, "#pragma omp parallel");
       dump_omp_clauses (buffer, OMP_PARALLEL_CLAUSES (node), spc, flags);
diff --git gcc/tree.def gcc/tree.def
index 399b5af..87fec57 100644
--- gcc/tree.def
+++ gcc/tree.def
@@ -1000,8 +1000,15 @@ DEFTREECODE (TARGET_MEM_REF, "target_mem_ref", tcc_reference, 5)
    chain of component references offsetting p by c.  */
 DEFTREECODE (MEM_REF, "mem_ref", tcc_reference, 2)
 
-/* The ordering of the codes between OMP_PARALLEL and OMP_CRITICAL is
-   exposed to TREE_RANGE_CHECK.  */
+/* OpenACC and OpenMP.  As it is exposed in TREE_RANGE_CHECK invocations, do
+   not change the ordering of these codes.  */
+
+/* OpenACC - #pragma acc parallel [clause1 ... clauseN]
+   Operand 0: OACC_PARALLEL_BODY: Code to be executed in parallel.
+   Operand 1: OACC_PARALLEL_CLAUSES: List of clauses.  */
+
+DEFTREECODE (OACC_PARALLEL, "oacc_parallel", tcc_statement, 2)
+
 /* OpenMP - #pragma omp parallel [clause1 ... clauseN]
    Operand 0: OMP_PARALLEL_BODY: Code to be executed by all threads.
    Operand 1: OMP_PARALLEL_CLAUSES: List of clauses.  */
diff --git gcc/tree.h gcc/tree.h
index 22a576f..06d94cf 100644
--- gcc/tree.h
+++ gcc/tree.h
@@ -1171,9 +1171,14 @@ extern void protected_set_expr_location (tree, location_t);
 /* OpenMP directive and clause accessors.  */
 
 #define OMP_BODY(NODE) \
-  TREE_OPERAND (TREE_RANGE_CHECK (NODE, OMP_PARALLEL, OMP_CRITICAL), 0)
+  TREE_OPERAND (TREE_RANGE_CHECK (NODE, OACC_PARALLEL, OMP_CRITICAL), 0)
 #define OMP_CLAUSES(NODE) \
-  TREE_OPERAND (TREE_RANGE_CHECK (NODE, OMP_PARALLEL, OMP_SINGLE), 1)
+  TREE_OPERAND (TREE_RANGE_CHECK (NODE, OACC_PARALLEL, OMP_SINGLE), 1)
+
+#define OACC_PARALLEL_BODY(NODE) \
+  TREE_OPERAND (OACC_PARALLEL_CHECK (NODE), 0)
+#define OACC_PARALLEL_CLAUSES(NODE) \
+  TREE_OPERAND (OACC_PARALLEL_CHECK (NODE), 1)
 
 #define OMP_PARALLEL_BODY(NODE)    TREE_OPERAND (OMP_PARALLEL_CHECK (NODE), 0)
 #define OMP_PARALLEL_CLAUSES(NODE) TREE_OPERAND (OMP_PARALLEL_CHECK (NODE), 1)
diff --git libgomp/Makefile.am libgomp/Makefile.am
index 0b5c097..37b36bd 100644
--- libgomp/Makefile.am
+++ libgomp/Makefile.am
@@ -60,7 +60,7 @@ libgomp_la_LINK = $(LINK) $(libgomp_la_LDFLAGS)
 libgomp_la_SOURCES = alloc.c barrier.c critical.c env.c error.c iter.c \
 	iter_ull.c loop.c loop_ull.c ordered.c parallel.c sections.c single.c \
 	task.c team.c work.c lock.c mutex.c proc.c sem.c bar.c ptrlock.c \
-	time.c fortran.c affinity.c target.c
+	time.c fortran.c affinity.c target.c oacc-parallel.c
 
 nodist_noinst_HEADERS = libgomp_f.h
 nodist_libsubinclude_HEADERS = omp.h openacc.h
diff --git libgomp/Makefile.in libgomp/Makefile.in
index 9ee1bec..bc60253d 100644
--- libgomp/Makefile.in
+++ libgomp/Makefile.in
@@ -96,7 +96,7 @@ am_libgomp_la_OBJECTS = alloc.lo barrier.lo critical.lo env.lo \
 	error.lo iter.lo iter_ull.lo loop.lo loop_ull.lo ordered.lo \
 	parallel.lo sections.lo single.lo task.lo team.lo work.lo \
 	lock.lo mutex.lo proc.lo sem.lo bar.lo ptrlock.lo time.lo \
-	fortran.lo affinity.lo target.lo
+	fortran.lo affinity.lo target.lo oacc-parallel.lo
 libgomp_la_OBJECTS = $(am_libgomp_la_OBJECTS)
 DEFAULT_INCLUDES = -I.@am__isrc@
 depcomp = $(SHELL) $(top_srcdir)/../depcomp
@@ -317,7 +317,7 @@ libgomp_la_LINK = $(LINK) $(libgomp_la_LDFLAGS)
 libgomp_la_SOURCES = alloc.c barrier.c critical.c env.c error.c iter.c \
 	iter_ull.c loop.c loop_ull.c ordered.c parallel.c sections.c single.c \
 	task.c team.c work.c lock.c mutex.c proc.c sem.c bar.c ptrlock.c \
-	time.c fortran.c affinity.c target.c
+	time.c fortran.c affinity.c target.c oacc-parallel.c
 
 nodist_noinst_HEADERS = libgomp_f.h
 nodist_libsubinclude_HEADERS = omp.h openacc.h
@@ -469,6 +469,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loop.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loop_ull.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mutex.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oacc-parallel.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ordered.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parallel.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc.Plo@am__quote@
diff --git libgomp/libgomp.map libgomp/libgomp.map
index f094ed2..2b64d05 100644
--- libgomp/libgomp.map
+++ libgomp/libgomp.map
@@ -232,4 +232,6 @@ OACC_2.0 {
 };
 
 GOACC_2.0 {
+  global:
+	GOACC_parallel;
 };
diff --git libgomp/libgomp_g.h libgomp/libgomp_g.h
index 577956a..394f3a8 100644
--- libgomp/libgomp_g.h
+++ libgomp/libgomp_g.h
@@ -214,4 +214,9 @@ extern void GOMP_target_update (int, const void *,
 				size_t, void **, size_t *, unsigned char *);
 extern void GOMP_teams (unsigned int, unsigned int);
 
+/* oacc-parallel.c */
+
+extern void GOACC_parallel (int, void (*) (void *), const void *,
+			    size_t, void **, size_t *, unsigned char *);
+
 #endif /* LIBGOMP_G_H */
diff --git libgomp/oacc-parallel.c libgomp/oacc-parallel.c
new file mode 100644
index 0000000..730b83b
--- /dev/null
+++ libgomp/oacc-parallel.c
@@ -0,0 +1,36 @@
+/* Copyright (C) 2013 Free Software Foundation, Inc.
+
+   Contributed by Thomas Schwinge <thomas@codesourcery.com>.
+
+   This file is part of the GNU OpenMP Library (libgomp).
+
+   Libgomp is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+   FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* This file handles the OpenACC parallel construct.  */
+
+#include "libgomp_g.h"
+
+void
+GOACC_parallel (int device, void (*fn) (void *), const void *openmp_target,
+		size_t mapnum, void **hostaddrs, size_t *sizes,
+		unsigned char *kinds)
+{
+  GOMP_target (device, fn, openmp_target, mapnum, hostaddrs, sizes, kinds);
+}
diff --git libgomp/testsuite/libgomp.oacc-c/goacc_parallel.c libgomp/testsuite/libgomp.oacc-c/goacc_parallel.c
new file mode 100644
index 0000000..b9bdffa
--- /dev/null
+++ libgomp/testsuite/libgomp.oacc-c/goacc_parallel.c
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+
+#include "libgomp_g.h"
+
+extern void abort ();
+
+volatile int i;
+
+void
+f (void *data)
+{
+  if (i != -1)
+    abort ();
+  i = 42;
+}
+
+int main(void)
+{
+  i = -1;
+  GOACC_parallel (0, f, (const void *) 0, 0, (void *) 0, (void *) 0, (void *) 0);
+  if (i != 42)
+    abort ();
+
+  return 0;
+}
diff --git libgomp/testsuite/libgomp.oacc-c/parallel-1.c libgomp/testsuite/libgomp.oacc-c/parallel-1.c
new file mode 100644
index 0000000..b40545d
--- /dev/null
+++ libgomp/testsuite/libgomp.oacc-c/parallel-1.c
@@ -0,0 +1,26 @@
+/* { dg-do run } */
+
+extern void abort ();
+
+volatile int i;
+
+int main(void)
+{
+  volatile int j;
+
+  i = -0x42;
+  j = -42;
+#pragma acc parallel
+  {
+    if (i != -0x42 || j != -42)
+      abort ();
+    i = 42;
+    j = 0x42;
+    if (i != 42 || j != 0x42)
+      abort ();
+  }
+  if (i != 42 || j != 0x42)
+    abort ();
+
+  return 0;
+}


Grüße,
 Thomas

[-- Attachment #2: Type: application/pgp-signature, Size: 489 bytes --]

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

* Re: [gomp4 9/9] OpenACC: Basic support for #pragma acc parallel.
  2013-11-06 19:53                 ` [gomp4 9/9] OpenACC: Basic support for #pragma acc parallel thomas
  2013-11-06 20:01                   ` Thomas Schwinge
@ 2013-11-06 20:03                   ` Jakub Jelinek
  2013-11-07 19:00                     ` Thomas Schwinge
  1 sibling, 1 reply; 44+ messages in thread
From: Jakub Jelinek @ 2013-11-06 20:03 UTC (permalink / raw)
  To: thomas; +Cc: gcc-patches

On Wed, Nov 06, 2013 at 08:42:23PM +0100, thomas@codesourcery.com wrote:
> +#define OACC_PARALLEL_CLAUSE_MASK			\
> +	PRAGMA_OMP_CLAUSE_NONE

This is incorrect, either you should define in c-common.h
also OMP_CLAUSE_MASK_0 and define this to it, or
it needs to be (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NONE).
Otherwise it won't compile on 32-bit HWI targets where omp_clause_mask
is a C++ class.

	Jakub

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

* [gomp4 8/9] OpenACC: Basic support for #pragma acc in the C front end.
  2013-11-06 19:56             ` [gomp4 7/9] OpenACC: Use OpenMP's lowering and expansion passes thomas
@ 2013-11-06 20:29               ` thomas
  2013-11-06 19:53                 ` [gomp4 9/9] OpenACC: Basic support for #pragma acc parallel thomas
  2013-11-07  8:41                 ` [gomp4 8/9] OpenACC: Basic support for #pragma acc in the C front end Jakub Jelinek
  2013-11-07  8:39               ` [gomp4 7/9] OpenACC: Use OpenMP's lowering and expansion passes Jakub Jelinek
  1 sibling, 2 replies; 44+ messages in thread
From: thomas @ 2013-11-06 20:29 UTC (permalink / raw)
  To: gcc-patches; +Cc: Thomas Schwinge

From: Thomas Schwinge <thomas@codesourcery.com>

	gcc/c-family/
	* c-pragma.c (oacc_pragmas): New array.
	(c_pp_lookup_pragma, init_pragma): Handle it.
	gcc/
	* doc/invoke.texi (-fopenacc): Update.

	gcc/c/
	* c-parser.c (c_parser_omp_all_clauses): Make a parser error
	message suitable for OpenACC, too.
	gcc/cp/
	* parser.c (cp_parser_omp_all_clauses): Make a parser error
	message suitable for OpenACC, too.
---
 gcc/c-family/c-pragma.c | 22 ++++++++++++++++++++++
 gcc/c/c-parser.c        |  2 +-
 gcc/cp/parser.c         |  2 +-
 gcc/doc/invoke.texi     |  2 +-
 4 files changed, 25 insertions(+), 3 deletions(-)

diff --git gcc/c-family/c-pragma.c gcc/c-family/c-pragma.c
index 3ce77a2..98f98d0 100644
--- gcc/c-family/c-pragma.c
+++ gcc/c-family/c-pragma.c
@@ -1164,6 +1164,8 @@ typedef struct
 static vec<pragma_ns_name> registered_pp_pragmas;
 
 struct omp_pragma_def { const char *name; unsigned int id; };
+static const struct omp_pragma_def oacc_pragmas[] = {
+};
 static const struct omp_pragma_def omp_pragmas[] = {
   { "atomic", PRAGMA_OMP_ATOMIC },
   { "barrier", PRAGMA_OMP_BARRIER },
@@ -1194,9 +1196,18 @@ static const struct omp_pragma_def omp_pragmas[] = {
 void
 c_pp_lookup_pragma (unsigned int id, const char **space, const char **name)
 {
+  const int n_oacc_pragmas = sizeof (oacc_pragmas) / sizeof (*oacc_pragmas);
   const int n_omp_pragmas = sizeof (omp_pragmas) / sizeof (*omp_pragmas);
   int i;
 
+  for (i = 0; i < n_oacc_pragmas; ++i)
+    if (oacc_pragmas[i].id == id)
+      {
+	*space = "acc";
+	*name = oacc_pragmas[i].name;
+	return;
+      }
+
   for (i = 0; i < n_omp_pragmas; ++i)
     if (omp_pragmas[i].id == id)
       {
@@ -1348,6 +1359,17 @@ c_invoke_pragma_handler (unsigned int id)
 void
 init_pragma (void)
 {
+  if (flag_openacc)
+    {
+      const int n_oacc_pragmas
+	= sizeof (oacc_pragmas) / sizeof (*oacc_pragmas);
+      int i;
+
+      for (i = 0; i < n_oacc_pragmas; ++i)
+	cpp_register_deferred_pragma (parse_in, "acc", oacc_pragmas[i].name,
+				      oacc_pragmas[i].id, true, true);
+    }
+
   if (flag_openmp)
     {
       const int n_omp_pragmas = sizeof (omp_pragmas) / sizeof (*omp_pragmas);
diff --git gcc/c/c-parser.c gcc/c/c-parser.c
index a8f4774..8a1e988 100644
--- gcc/c/c-parser.c
+++ gcc/c/c-parser.c
@@ -10730,7 +10730,7 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask,
 	  c_name = "simdlen";
 	  break;
 	default:
-	  c_parser_error (parser, "expected %<#pragma omp%> clause");
+	  c_parser_error (parser, "expected clause");
 	  goto saw_error;
 	}
 
diff --git gcc/cp/parser.c gcc/cp/parser.c
index bbc8e75..c3345ee 100644
--- gcc/cp/parser.c
+++ gcc/cp/parser.c
@@ -27911,7 +27911,7 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask,
 	  c_name = "simdlen";
 	  break;
 	default:
-	  cp_parser_error (parser, "expected %<#pragma omp%> clause");
+	  cp_parser_error (parser, "expected clause");
 	  goto saw_error;
 	}
 
diff --git gcc/doc/invoke.texi gcc/doc/invoke.texi
index af8973a..cc4a6da 100644
--- gcc/doc/invoke.texi
+++ gcc/doc/invoke.texi
@@ -1835,7 +1835,7 @@ freestanding and hosted environments.
 @item -fopenacc
 @opindex fopenacc
 @cindex OpenACC accelerator programming
-Enable handling of OpenACC.
+Enable handling of OpenACC directives @code{#pragma acc} in C.
 When @option{-fopenacc} is specified, the
 compiler generates accelerated code according to the OpenACC Application
 Programming Interface v2.0 @w{@uref{http://www.openacc.org/}}.  This option
-- 
1.8.1.1

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

* [gomp4 6/9] OpenACC: Infrastructure for builtins.
  2013-11-06 19:45         ` [gomp4 5/9] OpenACC: preprocessor definition, Fortran integer parameter thomas
@ 2013-11-06 20:37           ` thomas
  2013-11-06 19:56             ` [gomp4 7/9] OpenACC: Use OpenMP's lowering and expansion passes thomas
  2013-11-07  8:23             ` [gomp4 6/9] OpenACC: Infrastructure for builtins Jakub Jelinek
  2013-11-07  8:19           ` [gomp4 5/9] OpenACC: preprocessor definition, Fortran integer parameter Jakub Jelinek
  1 sibling, 2 replies; 44+ messages in thread
From: thomas @ 2013-11-06 20:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: Thomas Schwinge

From: Thomas Schwinge <thomas@codesourcery.com>

	gcc/
	* oacc-builtins.def: New file.
	* Makefile.in (BUILTINS_DEF): Add oacc-builtins.def.
	* builtins.def (DEF_GOACC_BUILTIN): New macro.
	Include "oacc-builtins.def".
	gcc/fortran/
	* f95-lang.c (DEF_GOACC_BUILTIN): New macro.
	Include "../oacc-builtins.def".
	libgomp/
	* libgomp.map (GOACC_2.0): New symbol version.
---
 gcc/Makefile.in        |  3 ++-
 gcc/builtins.def       | 10 ++++++++++
 gcc/fortran/f95-lang.c | 10 ++++++++++
 gcc/oacc-builtins.def  | 28 ++++++++++++++++++++++++++++
 libgomp/libgomp.map    |  3 +++
 5 files changed, 53 insertions(+), 1 deletion(-)
 create mode 100644 gcc/oacc-builtins.def

diff --git gcc/Makefile.in gcc/Makefile.in
index cc88fb8..0511097 100644
--- gcc/Makefile.in
+++ gcc/Makefile.in
@@ -871,7 +871,8 @@ FIXED_VALUE_H = fixed-value.h $(MACHMODE_H) double-int.h
 RTL_H = $(RTL_BASE_H) $(FLAGS_H) genrtl.h
 READ_MD_H = $(OBSTACK_H) $(HASHTAB_H) read-md.h
 PARAMS_H = params.h params.def
-BUILTINS_DEF = builtins.def sync-builtins.def omp-builtins.def \
+BUILTINS_DEF = builtins.def sync-builtins.def \
+	oacc-builtins.def omp-builtins.def \
 	gtm-builtins.def sanitizer.def cilkplus.def cilk-builtins.def
 INTERNAL_FN_DEF = internal-fn.def
 INTERNAL_FN_H = internal-fn.h $(INTERNAL_FN_DEF)
diff --git gcc/builtins.def gcc/builtins.def
index e2d8849..9a9a20a 100644
--- gcc/builtins.def
+++ gcc/builtins.def
@@ -139,6 +139,13 @@ along with GCC; see the file COPYING3.  If not see
   DEF_BUILTIN (ENUM, NAME, BUILT_IN_NORMAL, BT_LAST, BT_LAST, false, false, \
 	       false, ATTR_LAST, false, false)
 
+/* Builtin used by the implementation of GNU OpenACC.  None of these are
+   actually implemented in the compiler; they're all in libgomp.  */
+#undef DEF_GOACC_BUILTIN
+#define DEF_GOACC_BUILTIN(ENUM, NAME, TYPE, ATTRS) \
+  DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE,    \
+               false, true, true, ATTRS, false, flag_openacc)
+
 /* Builtin used by the implementation of GNU OpenMP.  None of these are
    actually implemented in the compiler; they're all in libgomp.  */
 #undef DEF_GOMP_BUILTIN
@@ -856,6 +863,9 @@ DEF_GCC_BUILTIN (BUILT_IN_LINE, "LINE", BT_FN_INT, ATTR_NOTHROW_LEAF_LIST)
 /* Synchronization Primitives.  */
 #include "sync-builtins.def"
 
+/* OpenACC builtins.  */
+#include "oacc-builtins.def"
+
 /* OpenMP builtins.  */
 #include "omp-builtins.def"
 
diff --git gcc/fortran/f95-lang.c gcc/fortran/f95-lang.c
index 873c137..69012b6 100644
--- gcc/fortran/f95-lang.c
+++ gcc/fortran/f95-lang.c
@@ -1035,6 +1035,16 @@ gfc_init_builtin_functions (void)
 #include "../sync-builtins.def"
 #undef DEF_SYNC_BUILTIN
 
+  if (gfc_option.gfc_flag_openacc)
+    {
+#undef DEF_GOACC_BUILTIN
+#define DEF_GOACC_BUILTIN(code, name, type, attr) \
+      gfc_define_builtin ("__builtin_" name, builtin_types[type], \
+			  code, name, attr);
+#include "../oacc-builtins.def"
+#undef DEF_GOACC_BUILTIN
+    }
+
   if (gfc_option.gfc_flag_openmp || flag_tree_parallelize_loops)
     {
 #undef DEF_GOMP_BUILTIN
diff --git gcc/oacc-builtins.def gcc/oacc-builtins.def
new file mode 100644
index 0000000..fd630e0
--- /dev/null
+++ gcc/oacc-builtins.def
@@ -0,0 +1,28 @@
+/* This file contains the definitions and documentation for the
+   OpenACC builtins used in the GNU compiler.
+
+   Copyright (C) 2013 Free Software Foundation, Inc.
+
+   Contributed by Thomas Schwinge <thomas@codesourcery.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+/* Before including this file, you should define a macro:
+
+     DEF_GOACC_BUILTIN (ENUM, NAME, TYPE, ATTRS)
+
+   See builtins.def for details.  */
diff --git libgomp/libgomp.map libgomp/libgomp.map
index 4f87d00..f094ed2 100644
--- libgomp/libgomp.map
+++ libgomp/libgomp.map
@@ -230,3 +230,6 @@ GOMP_4.0 {
 
 OACC_2.0 {
 };
+
+GOACC_2.0 {
+};
-- 
1.8.1.1

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

* [gomp4 4/9] OpenACC: The runtime library will be implemented in libgomp, too.
  2013-11-06 19:47     ` [gomp4 3/9] OpenACC: Recognize -fopenacc thomas
@ 2013-11-06 20:39       ` thomas
  2013-11-06 19:45         ` [gomp4 5/9] OpenACC: preprocessor definition, Fortran integer parameter thomas
  2013-11-07  8:18         ` [gomp4 4/9] OpenACC: The runtime library will be implemented in libgomp, too Jakub Jelinek
  2013-11-07  8:17       ` [gomp4 3/9] OpenACC: Recognize -fopenacc Jakub Jelinek
  1 sibling, 2 replies; 44+ messages in thread
From: thomas @ 2013-11-06 20:39 UTC (permalink / raw)
  To: gcc-patches; +Cc: Thomas Schwinge

From: Thomas Schwinge <thomas@codesourcery.com>

	gcc/
	* gcc.c (LINK_COMMAND_SPEC, GOMP_SELF_SPECS): For -fopenacc, link
	to libgomp and its dependencies.
	* config/arc/arc.h (LINK_COMMAND_SPEC): Likewise.
	* config/darwin.h (LINK_COMMAND_SPEC_A): Likewise.
	* config/i386/mingw32.h (GOMP_SELF_SPECS): Likewise.
	* config/ia64/hpux.h (LIB_SPEC): Likewise.
	* config/pa/pa-hpux11.h (LIB_SPEC): Likewise.
	* config/pa/pa64-hpux.h (LIB_SPEC): Likewise.
	* doc/invoke.texi (-fopenacc): Update.
	libgomp/
	* libgomp.map (OACC_2.0): New symbol version.
	* libgomp.spec.in: Update comment.
	* configure.ac: Likewise.
	* configure: Regenerate.
	* Makefile.am (nodist_libsubinclude_HEADERS): Add openacc.h.
	(nodist_finclude_HEADERS): Add openacc_lib.h, openacc.f90,
	openacc.mod, and openacc_kinds.mod.
	(openacc_kinds.mod): New target.
	(%.mod): New target, generalized from omp_lib.mod.
	* Makefile.in: Regenerate.
	* openacc.f90: New file.
	* openacc.h: Likewise.
	* openacc_lib.h: Likewise.
	* testsuite/libgomp.oacc-c++/c++.exp: Likewise.
	* testsuite/libgomp.oacc-c/c.exp: Likewise.
	* testsuite/libgomp.oacc-c/lib-1.c: Likewise.
	* testsuite/libgomp.oacc-fortran/fortran.exp: Likewise.
	* testsuite/libgomp.oacc-fortran/lib-1.f90: Likewise.
	* testsuite/libgomp.oacc-fortran/lib-2.f: Likewise.
	* testsuite/libgomp.oacc-fortran/lib-3.f: Likewise.
---
 gcc/config/arc/arc.h                               |  2 +-
 gcc/config/darwin.h                                |  2 +-
 gcc/config/i386/mingw32.h                          |  2 +-
 gcc/config/ia64/hpux.h                             |  2 +-
 gcc/config/pa/pa-hpux11.h                          |  2 +-
 gcc/config/pa/pa64-hpux.h                          | 12 ++--
 gcc/doc/invoke.texi                                |  4 +-
 gcc/gcc.c                                          |  7 ++-
 libgomp/Makefile.am                                |  9 ++-
 libgomp/Makefile.in                                | 10 +++-
 libgomp/configure                                  |  2 +-
 libgomp/configure.ac                               |  2 +-
 libgomp/libgomp.map                                |  3 +
 libgomp/libgomp.spec.in                            |  2 +-
 libgomp/openacc.f90                                | 37 ++++++++++++
 libgomp/openacc.h                                  | 45 ++++++++++++++
 libgomp/openacc_lib.h                              | 26 ++++++++
 libgomp/testsuite/libgomp.oacc-c++/c++.exp         | 66 +++++++++++++++++++++
 libgomp/testsuite/libgomp.oacc-c/c.exp             | 36 +++++++++++
 libgomp/testsuite/libgomp.oacc-c/lib-1.c           |  7 +++
 libgomp/testsuite/libgomp.oacc-fortran/fortran.exp | 69 ++++++++++++++++++++++
 libgomp/testsuite/libgomp.oacc-fortran/lib-1.f90   |  3 +
 libgomp/testsuite/libgomp.oacc-fortran/lib-2.f     |  3 +
 libgomp/testsuite/libgomp.oacc-fortran/lib-3.f     |  3 +
 24 files changed, 332 insertions(+), 24 deletions(-)
 create mode 100644 libgomp/openacc.f90
 create mode 100644 libgomp/openacc.h
 create mode 100644 libgomp/openacc_lib.h
 create mode 100644 libgomp/testsuite/libgomp.oacc-c++/c++.exp
 create mode 100644 libgomp/testsuite/libgomp.oacc-c/c.exp
 create mode 100644 libgomp/testsuite/libgomp.oacc-c/lib-1.c
 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/fortran.exp
 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/lib-1.f90
 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/lib-2.f
 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/lib-3.f

diff --git gcc/config/arc/arc.h gcc/config/arc/arc.h
index 637f7b6..14fc717 100644
--- gcc/config/arc/arc.h
+++ gcc/config/arc/arc.h
@@ -174,7 +174,7 @@ along with GCC; see the file COPYING3.  If not see
     %(linker) %l " LINK_PIE_SPEC "%X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r}\
     %{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
     %{static:} %{L*} %(mfwrap) %(link_libgcc) %o\
-    %{fopenmp:%:include(libgomp.spec)%(link_gomp)} %(mflib)\
+    %{fopenacc|fopenmp:%:include(libgomp.spec)%(link_gomp)} %(mflib)\
     %{fprofile-arcs|fprofile-generate|coverage:-lgcov}\
     %{!nostdlib:%{!nodefaultlibs:%(link_ssp) %(link_gcc_c_sequence)}}\
     %{!A:%{!nostdlib:%{!nostartfiles:%E}}} %{T*} }}}}}}"
diff --git gcc/config/darwin.h gcc/config/darwin.h
index 596c9ef..735b6b9 100644
--- gcc/config/darwin.h
+++ gcc/config/darwin.h
@@ -176,7 +176,7 @@ extern GTY(()) int darwin_ms_struct;
     %{o*}%{!o:-o a.out} \
     %{!nostdlib:%{!nostartfiles:%S}} \
     %{L*} %(link_libgcc) %o %{fprofile-arcs|fprofile-generate*|coverage:-lgcov} \
-    %{fopenmp|ftree-parallelize-loops=*: \
+    %{fopenacc|fopenmp|ftree-parallelize-loops=*: \
       %{static|static-libgcc|static-libstdc++|static-libgfortran: libgomp.a%s; : -lgomp } } \
     %{fgnu-tm: \
       %{static|static-libgcc|static-libstdc++|static-libgfortran: libitm.a%s; : -litm } } \
diff --git gcc/config/i386/mingw32.h gcc/config/i386/mingw32.h
index 1ac5544..6f5c3a4 100644
--- gcc/config/i386/mingw32.h
+++ gcc/config/i386/mingw32.h
@@ -198,7 +198,7 @@ do {						         \
 
 /* mingw32 uses the  -mthreads option to enable thread support.  */
 #undef GOMP_SELF_SPECS
-#define GOMP_SELF_SPECS "%{fopenmp|ftree-parallelize-loops=*: " \
+#define GOMP_SELF_SPECS "%{fopenacc|fopenmp|ftree-parallelize-loops=*: " \
 			"-mthreads -pthread}"
 #undef GTM_SELF_SPECS
 #define GTM_SELF_SPECS "%{fgnu-tm:-mthreads -pthread}"
diff --git gcc/config/ia64/hpux.h gcc/config/ia64/hpux.h
index ca592e4..e0158ba 100644
--- gcc/config/ia64/hpux.h
+++ gcc/config/ia64/hpux.h
@@ -92,7 +92,7 @@ do {							\
 #undef  LIB_SPEC
 #define LIB_SPEC \
   "%{!shared: \
-     %{mt|pthread:%{fopenmp:-lrt} -lpthread} \
+     %{mt|pthread:%{fopenacc|fopenmp:-lrt} -lpthread} \
      %{p:%{!mlp64:-L/usr/lib/hpux32/libp} \
 	 %{mlp64:-L/usr/lib/hpux64/libp} -lprof} \
      %{pg:%{!mlp64:-L/usr/lib/hpux32/libp} \
diff --git gcc/config/pa/pa-hpux11.h gcc/config/pa/pa-hpux11.h
index c217398..0676d74 100644
--- gcc/config/pa/pa-hpux11.h
+++ gcc/config/pa/pa-hpux11.h
@@ -120,7 +120,7 @@ along with GCC; see the file COPYING3.  If not see
 #undef LIB_SPEC
 #define LIB_SPEC \
   "%{!shared:\
-     %{fopenmp:%{static:-a archive_shared} -lrt %{static:-a archive}}\
+     %{fopenacc|fopenmp:%{static:-a archive_shared} -lrt %{static:-a archive}}\
      %{mt|pthread:-lpthread} -lc\
      %{static:%{!nolibdld:-a archive_shared -ldld -a archive -lc}\
        %{!mt:%{!pthread:-a shared -lc -a archive}}}}\
diff --git gcc/config/pa/pa64-hpux.h gcc/config/pa/pa64-hpux.h
index a3e21d3..fdccf51 100644
--- gcc/config/pa/pa64-hpux.h
+++ gcc/config/pa/pa64-hpux.h
@@ -58,19 +58,19 @@ along with GCC; see the file COPYING3.  If not see
 #if ((TARGET_DEFAULT | TARGET_CPU_DEFAULT) & MASK_GNU_LD)
 #define LIB_SPEC \
   "%{!shared:\
-     %{!p:%{!pg:%{fopenmp:%{static:-a shared} -lrt %{static:-a archive}}\
+     %{!p:%{!pg:%{fopenacc|fopenmp:%{static:-a shared} -lrt %{static:-a archive}}\
 	    %{mt|pthread:-lpthread} -lc\
 	    %{static:%{!nolibdld:-a shared -ldld -a archive -lc}\
 		%{!mt:%{!pthread:-a shared -lc -a archive}}}}}\
      %{p:%{!pg:%{static:%{!mhp-ld:-a shared}%{mhp-ld:-a archive_shared}}\
 	   -lprof %{static:-a archive}\
-	   %{fopenmp:%{static:-a shared} -lrt %{static:-a archive}}\
+	   %{fopenacc|fopenmp:%{static:-a shared} -lrt %{static:-a archive}}\
 	   %{mt|pthread:-lpthread} -lc\
 	   %{static:%{!nolibdld:-a shared -ldld -a archive -lc}\
 		%{!mt:%{!pthread:-a shared -lc -a archive}}}}}\
      %{pg:%{static:%{!mhp-ld:-a shared}%{mhp-ld:-a archive_shared}}\
        -lgprof %{static:-a archive}\
-       %{fopenmp:%{static:-a shared} -lrt %{static:-a archive}}\
+       %{fopenacc|fopenmp:%{static:-a shared} -lrt %{static:-a archive}}\
        %{mt|pthread:-lpthread} -lc\
        %{static:%{!nolibdld:-a shared -ldld -a archive -lc}\
 		%{!mt:%{!pthread:-a shared -lc -a archive}}}}}\
@@ -78,19 +78,19 @@ along with GCC; see the file COPYING3.  If not see
 #else
 #define LIB_SPEC \
   "%{!shared:\
-     %{!p:%{!pg:%{fopenmp:%{static:-a shared} -lrt %{static:-a archive}}\
+     %{!p:%{!pg:%{fopenacc|fopenmp:%{static:-a shared} -lrt %{static:-a archive}}\
 	    %{mt|pthread:-lpthread} -lc\
 	    %{static:%{!nolibdld:-a shared -ldld -a archive -lc}\
 		%{!mt:%{!pthread:-a shared -lc -a archive}}}}}\
      %{p:%{!pg:%{static:%{mgnu-ld:-a shared}%{!mgnu-ld:-a archive_shared}}\
 	   -lprof %{static:-a archive}\
-	   %{fopenmp:%{static:-a shared} -lrt %{static:-a archive}}\
+	   %{fopenacc|fopenmp:%{static:-a shared} -lrt %{static:-a archive}}\
 	   %{mt|pthread:-lpthread} -lc\
 	   %{static:%{!nolibdld:-a shared -ldld -a archive -lc}\
 		%{!mt:%{!pthread:-a shared -lc -a archive}}}}}\
      %{pg:%{static:%{mgnu-ld:-a shared}%{!mgnu-ld:-a archive_shared}}\
        -lgprof %{static:-a archive}\
-       %{fopenmp:%{static:-a shared} -lrt %{static:-a archive}}\
+       %{fopenacc|fopenmp:%{static:-a shared} -lrt %{static:-a archive}}\
        %{mt|pthread:-lpthread} -lc\
        %{static:%{!nolibdld:-a shared -ldld -a archive -lc}\
 		%{!mt:%{!pthread:-a shared -lc -a archive}}}}}\
diff --git gcc/doc/invoke.texi gcc/doc/invoke.texi
index e393139..af8973a 100644
--- gcc/doc/invoke.texi
+++ gcc/doc/invoke.texi
@@ -1838,7 +1838,9 @@ freestanding and hosted environments.
 Enable handling of OpenACC.
 When @option{-fopenacc} is specified, the
 compiler generates accelerated code according to the OpenACC Application
-Programming Interface v2.0 @w{@uref{http://www.openacc.org/}}.
+Programming Interface v2.0 @w{@uref{http://www.openacc.org/}}.  This option
+implies @option{-pthread}, and thus is only supported on targets that
+have support for @option{-pthread}.
 
 @item -fopenmp
 @opindex fopenmp
diff --git gcc/gcc.c gcc/gcc.c
index 2298249..fdc0db5 100644
--- gcc/gcc.c
+++ gcc/gcc.c
@@ -765,7 +765,7 @@ proper position among the other output files.  */
     %X %{o*} %{e*} %{N} %{n} %{r}\
     %{s} %{t} %{u*} %{z} %{Z} %{!nostdlib:%{!nostartfiles:%S}} " VTABLE_VERIFICATION_SPEC " \
     %{static:} %{L*} %(mfwrap) %(link_libgcc) " SANITIZER_EARLY_SPEC " %o\
-    %{fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)}\
+    %{fopenacc|fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)}\
     %{fgnu-tm:%:include(libitm.spec)%(link_itm)}\
     %(mflib) " STACK_SPLIT_SPEC "\
     %{fprofile-arcs|fprofile-generate*|coverage:-lgcov} " SANITIZER_SPEC " \
@@ -921,10 +921,11 @@ static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS;
 #define DRIVER_SELF_SPECS ""
 #endif
 
-/* Adding -fopenmp should imply pthreads.  This is particularly important
+/* Linking to libgomp implies pthreads.  This is particularly important
    for targets that use different start files and suchlike.  */
 #ifndef GOMP_SELF_SPECS
-#define GOMP_SELF_SPECS "%{fopenmp|ftree-parallelize-loops=*: -pthread}"
+#define GOMP_SELF_SPECS "%{fopenacc|fopenmp|ftree-parallelize-loops=*: " \
+  "-pthread}"
 #endif
 
 /* Likewise for -fgnu-tm.  */
diff --git libgomp/Makefile.am libgomp/Makefile.am
index 427415e..0b5c097 100644
--- libgomp/Makefile.am
+++ libgomp/Makefile.am
@@ -63,9 +63,10 @@ libgomp_la_SOURCES = alloc.c barrier.c critical.c env.c error.c iter.c \
 	time.c fortran.c affinity.c target.c
 
 nodist_noinst_HEADERS = libgomp_f.h
-nodist_libsubinclude_HEADERS = omp.h
+nodist_libsubinclude_HEADERS = omp.h openacc.h
 if USE_FORTRAN
-nodist_finclude_HEADERS = omp_lib.h omp_lib.f90 omp_lib.mod omp_lib_kinds.mod
+nodist_finclude_HEADERS = omp_lib.h omp_lib.f90 omp_lib.mod omp_lib_kinds.mod \
+	openacc_lib.h openacc.f90 openacc.mod openacc_kinds.mod
 endif
 
 LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS))
@@ -75,7 +76,9 @@ LINK = $(LIBTOOL) --tag CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
 
 omp_lib_kinds.mod: omp_lib.mod
 	:
-omp_lib.mod: omp_lib.f90
+openacc_kinds.mod: openacc.mod
+	:
+%.mod: %.f90
 	$(FC) $(FCFLAGS) -fsyntax-only $<
 fortran.lo: libgomp_f.h
 fortran.o: libgomp_f.h
diff --git libgomp/Makefile.in libgomp/Makefile.in
index 5cd666f..9ee1bec 100644
--- libgomp/Makefile.in
+++ libgomp/Makefile.in
@@ -320,8 +320,10 @@ libgomp_la_SOURCES = alloc.c barrier.c critical.c env.c error.c iter.c \
 	time.c fortran.c affinity.c target.c
 
 nodist_noinst_HEADERS = libgomp_f.h
-nodist_libsubinclude_HEADERS = omp.h
-@USE_FORTRAN_TRUE@nodist_finclude_HEADERS = omp_lib.h omp_lib.f90 omp_lib.mod omp_lib_kinds.mod
+nodist_libsubinclude_HEADERS = omp.h openacc.h
+@USE_FORTRAN_TRUE@nodist_finclude_HEADERS = omp_lib.h omp_lib.f90 omp_lib.mod omp_lib_kinds.mod \
+@USE_FORTRAN_TRUE@	openacc_lib.h openacc.f90 openacc.mod openacc_kinds.mod
+
 LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS))
 LINK = $(LIBTOOL) --tag CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
 	$(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LTLDFLAGS) -o $@
@@ -1085,7 +1087,9 @@ vpath % $(strip $(search_path))
 
 omp_lib_kinds.mod: omp_lib.mod
 	:
-omp_lib.mod: omp_lib.f90
+openacc_kinds.mod: openacc.mod
+	:
+%.mod: %.f90
 	$(FC) $(FCFLAGS) -fsyntax-only $<
 fortran.lo: libgomp_f.h
 fortran.o: libgomp_f.h
diff --git libgomp/configure libgomp/configure
index e754eff..704f22a 100755
--- libgomp/configure
+++ libgomp/configure
@@ -16217,7 +16217,7 @@ else
 fi
 
 # Set up the set of libraries that we need to link against for libgomp.
-# Note that the GOMP_SELF_SPEC in gcc.c will force -pthread for -fopenmp,
+# Note that the GOMP_SELF_SPEC in gcc.c may force -pthread,
 # which will force linkage against -lpthread (or equivalent for the system).
 # That's not 100% ideal, but about the best we can do easily.
 if test $enable_shared = yes; then
diff --git libgomp/configure.ac libgomp/configure.ac
index 67f28ed..da06426 100644
--- libgomp/configure.ac
+++ libgomp/configure.ac
@@ -283,7 +283,7 @@ else
 fi
 
 # Set up the set of libraries that we need to link against for libgomp.
-# Note that the GOMP_SELF_SPEC in gcc.c will force -pthread for -fopenmp,
+# Note that the GOMP_SELF_SPEC in gcc.c may force -pthread,
 # which will force linkage against -lpthread (or equivalent for the system).
 # That's not 100% ideal, but about the best we can do easily.
 if test $enable_shared = yes; then
diff --git libgomp/libgomp.map libgomp/libgomp.map
index b102fd8..4f87d00 100644
--- libgomp/libgomp.map
+++ libgomp/libgomp.map
@@ -227,3 +227,6 @@ GOMP_4.0 {
 	GOMP_target_update;
 	GOMP_teams;
 } GOMP_3.0;
+
+OACC_2.0 {
+};
diff --git libgomp/libgomp.spec.in libgomp/libgomp.spec.in
index b7319f3..5651603 100644
--- libgomp/libgomp.spec.in
+++ libgomp/libgomp.spec.in
@@ -1,3 +1,3 @@
 # This spec file is read by gcc when linking.  It is used to specify the
-# standard libraries we need in order to link with -fopenmp.
+# standard libraries we need in order to link with libgomp.
 *link_gomp: @link_gomp@
diff --git libgomp/openacc.f90 libgomp/openacc.f90
new file mode 100644
index 0000000..55b79c2
--- /dev/null
+++ libgomp/openacc.f90
@@ -0,0 +1,37 @@
+!  OpenACC Runtime Library Definitions.
+
+!  Copyright (C) 2013 Free Software Foundation, Inc.
+
+!  Contributed by Thomas Schwinge <thomas@codesourcery.com>.
+
+!  This file is part of the GNU OpenMP Library (libgomp).
+
+!  Libgomp is free software; you can redistribute it and/or modify it
+!  under the terms of the GNU General Public License as published by
+!  the Free Software Foundation; either version 3, or (at your option)
+!  any later version.
+
+!  Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
+!  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+!  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+!  more details.
+
+!  Under Section 7 of GPL version 3, you are granted additional
+!  permissions described in the GCC Runtime Library Exception, version
+!  3.1, as published by the Free Software Foundation.
+
+!  You should have received a copy of the GNU General Public License and
+!  a copy of the GCC Runtime Library Exception along with this program;
+!  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+!  <http://www.gnu.org/licenses/>.
+
+module openacc_kinds
+  implicit none
+
+end module openacc_kinds
+
+module openacc
+  use openacc_kinds
+  implicit none
+
+end module openacc
diff --git libgomp/openacc.h libgomp/openacc.h
new file mode 100644
index 0000000..a6f7ec94
--- /dev/null
+++ libgomp/openacc.h
@@ -0,0 +1,45 @@
+/* OpenACC Runtime Library Declarations
+
+   Copyright (C) 2013 Free Software Foundation, Inc.
+
+   Contributed by Thomas Schwinge <thomas@codesourcery.com>.
+
+   This file is part of the GNU OpenMP Library (libgomp).
+
+   Libgomp is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+   FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _OPENACC_H
+#define _OPENACC_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+# define __GOACC_NOTHROW throw ()
+#else
+# define __GOACC_NOTHROW __attribute__ ((__nothrow__))
+#endif
+  
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OPENACC_H */
diff --git libgomp/openacc_lib.h libgomp/openacc_lib.h
new file mode 100644
index 0000000..b2cb679
--- /dev/null
+++ libgomp/openacc_lib.h
@@ -0,0 +1,26 @@
+!  OpenACC Runtime Library Definitions.                   -*- mode: fortran -*-
+
+!  Copyright (C) 2013 Free Software Foundation, Inc.
+
+!  Contributed by Thomas Schwinge <thomas@codesourcery.com>.
+
+!  This file is part of the GNU OpenMP Library (libgomp).
+
+!  Libgomp is free software; you can redistribute it and/or modify it
+!  under the terms of the GNU General Public License as published by
+!  the Free Software Foundation; either version 3, or (at your option)
+!  any later version.
+
+!  Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
+!  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+!  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+!  more details.
+
+!  Under Section 7 of GPL version 3, you are granted additional
+!  permissions described in the GCC Runtime Library Exception, version
+!  3.1, as published by the Free Software Foundation.
+
+!  You should have received a copy of the GNU General Public License and
+!  a copy of the GCC Runtime Library Exception along with this program;
+!  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+!  <http://www.gnu.org/licenses/>.
diff --git libgomp/testsuite/libgomp.oacc-c++/c++.exp libgomp/testsuite/libgomp.oacc-c++/c++.exp
new file mode 100644
index 0000000..4c0a3e3
--- /dev/null
+++ libgomp/testsuite/libgomp.oacc-c++/c++.exp
@@ -0,0 +1,66 @@
+# This whole file adapted from libgomp.c++/c++.exp.
+
+load_lib libgomp-dg.exp
+load_gcc_lib gcc-dg.exp
+
+global shlib_ext
+
+set shlib_ext [get_shlib_extension]
+set lang_link_flags "-lstdc++"
+set lang_test_file_found 0
+set lang_library_path "../libstdc++-v3/src/.libs"
+
+# Initialize dg.
+dg-init
+
+# Turn on OpenACC.
+lappend ALWAYS_CFLAGS "additional_flags=-fopenacc"
+
+set blddir [lookfor_file [get_multilibs] libgomp]
+
+
+if { $blddir != "" } {
+    # Look for a static libstdc++ first.
+    if [file exists "${blddir}/${lang_library_path}/libstdc++.a"] {
+        set lang_test_file "${lang_library_path}/libstdc++.a"
+        set lang_test_file_found 1
+        # We may have a shared only build, so look for a shared libstdc++.
+    } elseif [file exists "${blddir}/${lang_library_path}/libstdc++.${shlib_ext}"] {
+        set lang_test_file "${lang_library_path}/libstdc++.${shlib_ext}"
+        set lang_test_file_found 1
+    } else {
+        puts "No libstdc++ library found, will not execute c++ tests"
+    }
+} elseif { [info exists GXX_UNDER_TEST] } {
+    set lang_test_file_found 1
+    # Needs to exist for libgomp.exp.
+    set lang_test_file ""
+} else {
+    puts "GXX_UNDER_TEST not defined, will not execute c++ tests"
+}
+
+if { $lang_test_file_found } {
+    # Gather a list of all tests.
+    set tests [lsort [glob -nocomplain $srcdir/$subdir/*.C]]
+
+    if { $blddir != "" } {
+        set ld_library_path "$always_ld_library_path:${blddir}/${lang_library_path}"
+    } else {
+        set ld_library_path "$always_ld_library_path"
+    }
+    append ld_library_path [gcc-set-multilib-library-path $GCC_UNDER_TEST]
+    set_ld_library_path_env_vars
+
+    set flags_file "${blddir}/../libstdc++-v3/scripts/testsuite_flags"
+    if { [file exists $flags_file] } {
+	set libstdcxx_includes [exec sh $flags_file --build-includes]
+    } else {
+	set libstdcxx_includes ""
+    }
+
+    # Main loop.
+    dg-runtest $tests "" $libstdcxx_includes
+}
+
+# All done.
+dg-finish
diff --git libgomp/testsuite/libgomp.oacc-c/c.exp libgomp/testsuite/libgomp.oacc-c/c.exp
new file mode 100644
index 0000000..8307ecd
--- /dev/null
+++ libgomp/testsuite/libgomp.oacc-c/c.exp
@@ -0,0 +1,36 @@
+# This whole file adapted from libgomp.c/c.exp.
+
+if [info exists lang_library_path] then {
+    unset lang_library_path
+    unset lang_link_flags
+}
+if [info exists lang_test_file] then {
+    unset lang_test_file
+}
+
+load_lib libgomp-dg.exp
+load_gcc_lib gcc-dg.exp
+
+# If a testcase doesn't have special options, use these.
+if ![info exists DEFAULT_CFLAGS] then {
+    set DEFAULT_CFLAGS "-O2"
+}
+
+# Initialize dg.
+dg-init
+
+# Turn on OpenACC.
+lappend ALWAYS_CFLAGS "additional_flags=-fopenacc"
+
+# Gather a list of all tests.
+set tests [lsort [find $srcdir/$subdir *.c]]
+
+set ld_library_path $always_ld_library_path
+append ld_library_path [gcc-set-multilib-library-path $GCC_UNDER_TEST]
+set_ld_library_path_env_vars
+
+# Main loop.
+dg-runtest $tests "" $DEFAULT_CFLAGS
+
+# All done.
+dg-finish
diff --git libgomp/testsuite/libgomp.oacc-c/lib-1.c libgomp/testsuite/libgomp.oacc-c/lib-1.c
new file mode 100644
index 0000000..8ad1b19
--- /dev/null
+++ libgomp/testsuite/libgomp.oacc-c/lib-1.c
@@ -0,0 +1,7 @@
+#include <openacc.h>
+
+int
+main (void)
+{
+  return 0;
+}
diff --git libgomp/testsuite/libgomp.oacc-fortran/fortran.exp libgomp/testsuite/libgomp.oacc-fortran/fortran.exp
new file mode 100644
index 0000000..4070df5
--- /dev/null
+++ libgomp/testsuite/libgomp.oacc-fortran/fortran.exp
@@ -0,0 +1,69 @@
+# This whole file adapted from libgomp.fortran/fortran.exp.
+
+load_lib libgomp-dg.exp
+load_gcc_lib gcc-dg.exp
+load_gcc_lib gfortran-dg.exp
+
+global shlib_ext
+global ALWAYS_CFLAGS
+
+set shlib_ext [get_shlib_extension]
+set lang_library_path	"../libgfortran/.libs"
+set lang_link_flags	"-lgfortran"
+set lang_test_file_found 0
+set quadmath_library_path "../libquadmath/.libs"
+
+
+# Initialize dg.
+dg-init
+
+# Turn on OpenACC.
+lappend ALWAYS_CFLAGS "additional_flags=-fopenacc"
+
+if { $blddir != "" } {
+    lappend ALWAYS_CFLAGS "additional_flags=-fintrinsic-modules-path=${blddir}"
+    # Look for a static libgfortran first.
+    if [file exists "${blddir}/${lang_library_path}/libgfortran.a"] {
+        set lang_test_file "${lang_library_path}/libgfortran.a"
+        set lang_test_file_found 1
+	# We may have a shared only build, so look for a shared libgfortran.
+    } elseif [file exists "${blddir}/${lang_library_path}/libgfortran.${shlib_ext}"] {
+        set lang_test_file "${lang_library_path}/libgfortran.${shlib_ext}"
+        set lang_test_file_found 1
+    } else {
+        puts "No libgfortran library found, will not execute fortran tests"
+    }
+} elseif [info exists GFORTRAN_UNDER_TEST] {
+    set lang_test_file_found 1
+    # Needs to exist for libgomp.exp.
+    set lang_test_file ""
+} else {
+    puts "GFORTRAN_UNDER_TEST not defined, will not execute fortran tests"
+}
+
+if { $lang_test_file_found } {
+    # Gather a list of all tests.
+    set tests [lsort [find $srcdir/$subdir *.\[fF\]{,90,95,03,08}]]
+
+    if { $blddir != "" } {
+	if { [file exists "${blddir}/${quadmath_library_path}/libquadmath.a"]
+	     || [file exists "${blddir}/${quadmath_library_path}/libquadmath.${shlib_ext}"] } {
+	    lappend ALWAYS_CFLAGS "ldflags=-L${blddir}/${quadmath_library_path}/"
+	    # Allow for spec subsitution.
+	    lappend ALWAYS_CFLAGS "additional_flags=-B${blddir}/${quadmath_library_path}/"
+	    set ld_library_path "$always_ld_library_path:${blddir}/${lang_library_path}:${blddir}/${quadmath_library_path}"
+	} else {
+	    set ld_library_path "$always_ld_library_path:${blddir}/${lang_library_path}"
+	}
+    } else {
+        set ld_library_path "$always_ld_library_path"
+    }
+    append ld_library_path [gcc-set-multilib-library-path $GCC_UNDER_TEST]
+    set_ld_library_path_env_vars
+
+    # Main loop.
+    gfortran-dg-runtest $tests ""
+}
+
+# All done.
+dg-finish
diff --git libgomp/testsuite/libgomp.oacc-fortran/lib-1.f90 libgomp/testsuite/libgomp.oacc-fortran/lib-1.f90
new file mode 100644
index 0000000..124aa87
--- /dev/null
+++ libgomp/testsuite/libgomp.oacc-fortran/lib-1.f90
@@ -0,0 +1,3 @@
+use openacc
+
+end
diff --git libgomp/testsuite/libgomp.oacc-fortran/lib-2.f libgomp/testsuite/libgomp.oacc-fortran/lib-2.f
new file mode 100644
index 0000000..64beb9e
--- /dev/null
+++ libgomp/testsuite/libgomp.oacc-fortran/lib-2.f
@@ -0,0 +1,3 @@
+      USE OPENACC
+
+      END
diff --git libgomp/testsuite/libgomp.oacc-fortran/lib-3.f libgomp/testsuite/libgomp.oacc-fortran/lib-3.f
new file mode 100644
index 0000000..3f9940b
--- /dev/null
+++ libgomp/testsuite/libgomp.oacc-fortran/lib-3.f
@@ -0,0 +1,3 @@
+      INCLUDE "openacc_lib.h"
+
+      END
-- 
1.8.1.1

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

* Re: [gomp4 1/9] Add missing include.
  2013-11-06 19:44 ` [gomp4 1/9] Add missing include thomas
  2013-11-06 19:44   ` [gomp4 2/9] libgomp: Prepare for testcases without -fopenmp thomas
@ 2013-11-07  8:15   ` Jakub Jelinek
  1 sibling, 0 replies; 44+ messages in thread
From: Jakub Jelinek @ 2013-11-07  8:15 UTC (permalink / raw)
  To: thomas; +Cc: gcc-patches

On Wed, Nov 06, 2013 at 08:42:15PM +0100, thomas@codesourcery.com wrote:
> From: Thomas Schwinge <thomas@codesourcery.com>
> 
> 	libgomp/
> 	* libgomp_g.h: Include <stddef.h> for size_t.

I'm surprised why it is needed, because libgomp.h that includes it includes
stdlib.h that should provide size_t too.  But, including this certainly
doesn't hurt and makes the header more self-contained.  So, ok for
trunk/gomp-4_0-branch.

	Jakub

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

* Re: [gomp4 2/9] libgomp: Prepare for testcases without -fopenmp.
  2013-11-06 19:44   ` [gomp4 2/9] libgomp: Prepare for testcases without -fopenmp thomas
  2013-11-06 19:47     ` [gomp4 3/9] OpenACC: Recognize -fopenacc thomas
@ 2013-11-07  8:16     ` Jakub Jelinek
  2017-09-28  7:41       ` [libgomp, testsuite] Remove superfluous -fopenmp from libgomp testcases Tom de Vries
  1 sibling, 1 reply; 44+ messages in thread
From: Jakub Jelinek @ 2013-11-07  8:16 UTC (permalink / raw)
  To: thomas; +Cc: gcc-patches

On Wed, Nov 06, 2013 at 08:42:16PM +0100, thomas@codesourcery.com wrote:
> From: Thomas Schwinge <thomas@codesourcery.com>
> 
> 	libgomp/
> 	* testsuite/lib/libgomp.exp (libgomp_init): Don't add -fopenmp to
> 	ALWAYS_CFLAGS.
> 	* testsuite/libgomp.c++/c++.exp (ALWAYS_CFLAGS): Add -fopenmp.
> 	* testsuite/libgomp.c/c.exp (ALWAYS_CFLAGS): Likewise.
> 	* testsuite/libgomp.fortran/fortran.exp (ALWAYS_CFLAGS): Likewise.
> 	* testsuite/libgomp.graphite/graphite.exp (ALWAYS_CFLAGS):
> 	Likewise.

Ok for trunk/gomp-4_0-branch.

	Jakub

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

* Re: [gomp4 3/9] OpenACC: Recognize -fopenacc.
  2013-11-06 19:47     ` [gomp4 3/9] OpenACC: Recognize -fopenacc thomas
  2013-11-06 20:39       ` [gomp4 4/9] OpenACC: The runtime library will be implemented in libgomp, too thomas
@ 2013-11-07  8:17       ` Jakub Jelinek
  1 sibling, 0 replies; 44+ messages in thread
From: Jakub Jelinek @ 2013-11-07  8:17 UTC (permalink / raw)
  To: thomas; +Cc: gcc-patches

On Wed, Nov 06, 2013 at 08:42:17PM +0100, thomas@codesourcery.com wrote:
> From: Thomas Schwinge <thomas@codesourcery.com>
> 
> 	gcc/c-family/
> 	* c.opt (fopenacc): New option.
> 	gcc/fortran/
> 	* lang.opt (fopenacc): New option.
> 	* invoke.texi (-fopenacc): Document it.
> 	* gfortran.h (gfc_option_t): New member.
> 	* options.c (gfc_init_options, gfc_handle_option): Handle it.
> 	gcc/testsuite/
> 	* lib/target-supports.exp (check_effective_target_fopenacc): New
> 	procedure.
> 	gcc/
> 	* doc/invoke.texi (-fopenacc): Document it.
> 	* doc/sourcebuild.texi (fopenacc): Document it.
> 	gcc/testsuite/
> 	* c-c++-common/cpp/openacc-define-1.c: New file.
> 	* c-c++-common/cpp/openacc-define-2.c: Likewise.
> 	* c-c++-common/cpp/openacc-define-3.c: Likewise.
> 	* gfortran.dg/openacc-define-1.f90: Likewise.
> 	* gfortran.dg/openacc-define-2.f90: Likewise.
> 	* gfortran.dg/openacc-define-3.f90: Likewise.

Ok for branch.

	Jakub

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

* Re: [gomp4 4/9] OpenACC: The runtime library will be implemented in libgomp, too.
  2013-11-06 20:39       ` [gomp4 4/9] OpenACC: The runtime library will be implemented in libgomp, too thomas
  2013-11-06 19:45         ` [gomp4 5/9] OpenACC: preprocessor definition, Fortran integer parameter thomas
@ 2013-11-07  8:18         ` Jakub Jelinek
  2013-11-07 14:05           ` Generally link to libgomp for -ftree-parallelize-loops=* (was: [gomp4 4/9] OpenACC: The runtime library will be implemented in libgomp, too.) Thomas Schwinge
  1 sibling, 1 reply; 44+ messages in thread
From: Jakub Jelinek @ 2013-11-07  8:18 UTC (permalink / raw)
  To: thomas; +Cc: gcc-patches

On Wed, Nov 06, 2013 at 08:42:18PM +0100, thomas@codesourcery.com wrote:
> --- gcc/config/arc/arc.h
> +++ gcc/config/arc/arc.h
> @@ -174,7 +174,7 @@ along with GCC; see the file COPYING3.  If not see
>      %(linker) %l " LINK_PIE_SPEC "%X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r}\
>      %{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
>      %{static:} %{L*} %(mfwrap) %(link_libgcc) %o\
> -    %{fopenmp:%:include(libgomp.spec)%(link_gomp)} %(mflib)\
> +    %{fopenacc|fopenmp:%:include(libgomp.spec)%(link_gomp)} %(mflib)\

Perhaps add here |ftree-parallelize-loops=* too?

>    "%{!shared: \
> -     %{mt|pthread:%{fopenmp:-lrt} -lpthread} \
> +     %{mt|pthread:%{fopenacc|fopenmp:-lrt} -lpthread} \

Likewise.

>       %{p:%{!mlp64:-L/usr/lib/hpux32/libp} \
>  	 %{mlp64:-L/usr/lib/hpux64/libp} -lprof} \
>       %{pg:%{!mlp64:-L/usr/lib/hpux32/libp} \
> diff --git gcc/config/pa/pa-hpux11.h gcc/config/pa/pa-hpux11.h
> index c217398..0676d74 100644
> --- gcc/config/pa/pa-hpux11.h
> +++ gcc/config/pa/pa-hpux11.h
> @@ -120,7 +120,7 @@ along with GCC; see the file COPYING3.  If not see
>  #undef LIB_SPEC
>  #define LIB_SPEC \
>    "%{!shared:\
> -     %{fopenmp:%{static:-a archive_shared} -lrt %{static:-a archive}}\
> +     %{fopenacc|fopenmp:%{static:-a archive_shared} -lrt %{static:-a archive}}\

Ditto (and several times further).

Otherwise LGTM for branch.

	Jakub

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

* Re: [gomp4 5/9] OpenACC: preprocessor definition, Fortran integer parameter.
  2013-11-06 19:45         ` [gomp4 5/9] OpenACC: preprocessor definition, Fortran integer parameter thomas
  2013-11-06 20:37           ` [gomp4 6/9] OpenACC: Infrastructure for builtins thomas
@ 2013-11-07  8:19           ` Jakub Jelinek
  1 sibling, 0 replies; 44+ messages in thread
From: Jakub Jelinek @ 2013-11-07  8:19 UTC (permalink / raw)
  To: thomas; +Cc: gcc-patches

On Wed, Nov 06, 2013 at 08:42:19PM +0100, thomas@codesourcery.com wrote:
> From: Thomas Schwinge <thomas@codesourcery.com>
> 
> 	gcc/c-family/
> 	* c-cppbuiltin.c (c_cpp_builtins): Conditionally define _OPENACC.
> 	gcc/fortran/
> 	* cpp.c (cpp_define_builtins): Conditionally define _OPENACC.
> 	gcc/testsuite/
> 	* c-c++-common/cpp/openacc-define-1.c: Test _OPENACC.
> 	* c-c++-common/cpp/openacc-define-2.c: Likewise.
> 	* c-c++-common/cpp/openacc-define-3.c: Likewise.
> 	* gfortran.dg/openacc-define-1.f90: Likewise.
> 	* gfortran.dg/openacc-define-2.f90: Likewise.
> 	* gfortran.dg/openacc-define-3.f90: Likewise.
> 	libgomp/
> 	* openacc.f90 (openacc_version): New integer parameter.
> 	* openacc_lib.h (openacc_version): Likewise.
> 	* testsuite/libgomp.oacc-fortran/openacc_version-1.f: New file.
> 	* testsuite/libgomp.oacc-fortran/openacc_version-2.f90: Likewise.

Ok for branch.

	Jakub

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

* Re: [gomp4 6/9] OpenACC: Infrastructure for builtins.
  2013-11-06 20:37           ` [gomp4 6/9] OpenACC: Infrastructure for builtins thomas
  2013-11-06 19:56             ` [gomp4 7/9] OpenACC: Use OpenMP's lowering and expansion passes thomas
@ 2013-11-07  8:23             ` Jakub Jelinek
  1 sibling, 0 replies; 44+ messages in thread
From: Jakub Jelinek @ 2013-11-07  8:23 UTC (permalink / raw)
  To: thomas; +Cc: gcc-patches

On Wed, Nov 06, 2013 at 08:42:20PM +0100, thomas@codesourcery.com wrote:
> From: Thomas Schwinge <thomas@codesourcery.com>
> 
> 	gcc/
> 	* oacc-builtins.def: New file.
> 	* Makefile.in (BUILTINS_DEF): Add oacc-builtins.def.
> 	* builtins.def (DEF_GOACC_BUILTIN): New macro.
> 	Include "oacc-builtins.def".
> 	gcc/fortran/
> 	* f95-lang.c (DEF_GOACC_BUILTIN): New macro.
> 	Include "../oacc-builtins.def".
> 	libgomp/
> 	* libgomp.map (GOACC_2.0): New symbol version.

Ok for branch.

	Jakub

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

* Re: [gomp4 7/9] OpenACC: Use OpenMP's lowering and expansion passes.
  2013-11-06 19:56             ` [gomp4 7/9] OpenACC: Use OpenMP's lowering and expansion passes thomas
  2013-11-06 20:29               ` [gomp4 8/9] OpenACC: Basic support for #pragma acc in the C front end thomas
@ 2013-11-07  8:39               ` Jakub Jelinek
  1 sibling, 0 replies; 44+ messages in thread
From: Jakub Jelinek @ 2013-11-07  8:39 UTC (permalink / raw)
  To: thomas; +Cc: gcc-patches

On Wed, Nov 06, 2013 at 08:42:21PM +0100, thomas@codesourcery.com wrote:
> From: Thomas Schwinge <thomas@codesourcery.com>
> 
> 	gcc/
> 	* gimplify.c (gimplify_body): Consider flag_openacc additionally
> 	to flag_openmp.
> 	* omp-low.c (execute_expand_omp, execute_lower_omp)
> 	(gate_diagnose_omp_blocks): Likewise.
> 	gcc/testsuite/
> 	* gcc.dg/goacc-gomp/goacc-gomp.exp: New file.
> 	* gcc.dg/goacc/goacc.exp: Likewise.

Ok for branch.

	Jakub

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

* Re: [gomp4 8/9] OpenACC: Basic support for #pragma acc in the C front end.
  2013-11-06 20:29               ` [gomp4 8/9] OpenACC: Basic support for #pragma acc in the C front end thomas
  2013-11-06 19:53                 ` [gomp4 9/9] OpenACC: Basic support for #pragma acc parallel thomas
@ 2013-11-07  8:41                 ` Jakub Jelinek
  1 sibling, 0 replies; 44+ messages in thread
From: Jakub Jelinek @ 2013-11-07  8:41 UTC (permalink / raw)
  To: thomas; +Cc: gcc-patches

On Wed, Nov 06, 2013 at 08:42:22PM +0100, thomas@codesourcery.com wrote:
> From: Thomas Schwinge <thomas@codesourcery.com>
> 
> 	gcc/c-family/
> 	* c-pragma.c (oacc_pragmas): New array.
> 	(c_pp_lookup_pragma, init_pragma): Handle it.
> 	gcc/
> 	* doc/invoke.texi (-fopenacc): Update.
> 
> 	gcc/c/
> 	* c-parser.c (c_parser_omp_all_clauses): Make a parser error
> 	message suitable for OpenACC, too.
> 	gcc/cp/
> 	* parser.c (cp_parser_omp_all_clauses): Make a parser error
> 	message suitable for OpenACC, too.

Ok for branch.

	Jakub

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

* Re: [gomp4 9/9] OpenACC: Basic support for #pragma acc parallel.
  2013-11-06 20:01                   ` Thomas Schwinge
@ 2013-11-07  8:48                     ` Jakub Jelinek
  2014-02-27 19:58                     ` [gomp4] Gimplification: Merge gimplify_oacc_parallel into gimplify_omp_workshare. (was: [gomp4 9/9] OpenACC: Basic support for #pragma acc parallel.) Thomas Schwinge
                                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 44+ messages in thread
From: Jakub Jelinek @ 2013-11-07  8:48 UTC (permalink / raw)
  To: Thomas Schwinge; +Cc: gcc-patches

On Wed, Nov 06, 2013 at 08:53:00PM +0100, Thomas Schwinge wrote:
> Forgot to pass the --patience switch to Git, so the diff algorithm
> decided to first patch the existing expand_omp_taskreg into
> expand_oacc_parallel, and then later re-add expand_omp_taskreg.  Here's a
> more readable version of that patch, avoiding all that back'n'forth:

I've just quickly skimmed this, other than what I've mentioned earlier
I haven't found anything totally wrong, so with that thing fixed I guess
it is ok for the branch, but my quick skimming was far from a proper review.

	Jakub

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

* Generally link to libgomp for -ftree-parallelize-loops=* (was: [gomp4 4/9] OpenACC: The runtime library will be implemented in libgomp, too.)
  2013-11-07  8:18         ` [gomp4 4/9] OpenACC: The runtime library will be implemented in libgomp, too Jakub Jelinek
@ 2013-11-07 14:05           ` Thomas Schwinge
  2013-11-07 14:48             ` Jakub Jelinek
  0 siblings, 1 reply; 44+ messages in thread
From: Thomas Schwinge @ 2013-11-07 14:05 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

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

Hi!

On Thu, 7 Nov 2013 09:15:45 +0100, Jakub Jelinek <jakub@redhat.com> wrote:
> On Wed, Nov 06, 2013 at 08:42:18PM +0100, thomas@codesourcery.com wrote:
> > --- gcc/config/arc/arc.h
> > +++ gcc/config/arc/arc.h
> > @@ -174,7 +174,7 @@ along with GCC; see the file COPYING3.  If not see
> >      %(linker) %l " LINK_PIE_SPEC "%X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r}\
> >      %{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
> >      %{static:} %{L*} %(mfwrap) %(link_libgcc) %o\
> > -    %{fopenmp:%:include(libgomp.spec)%(link_gomp)} %(mflib)\
> > +    %{fopenacc|fopenmp:%:include(libgomp.spec)%(link_gomp)} %(mflib)\
> 
> Perhaps add here |ftree-parallelize-loops=* too?  [...]

Like this (for trunk and gomp-4_0-branch)?

	gcc/
	* config/arc/arc.h (LINK_COMMAND_SPEC): For
	-ftree-parallelize-loops=*, link to libgomp and its dependencies.
	* config/ia64/hpux.h (LIB_SPEC): Likewise.
	* config/pa/pa-hpux11.h (LIB_SPEC): Likewise.
	* config/pa/pa64-hpux.h (LIB_SPEC): Likewise.
	* gcc.c (GOMP_SELF_SPECS): Update comment about libgomp's
	dependencies.
	libgomp/
	* libgomp.spec.in: Update comment about libgomp's dependencies.
	* configure.ac: Likewise.
	* configure: Regenerate.

diff --git gcc/config/arc/arc.h gcc/config/arc/arc.h
index 637f7b6..87908d4 100644
--- gcc/config/arc/arc.h
+++ gcc/config/arc/arc.h
@@ -174,7 +174,8 @@ along with GCC; see the file COPYING3.  If not see
     %(linker) %l " LINK_PIE_SPEC "%X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r}\
     %{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
     %{static:} %{L*} %(mfwrap) %(link_libgcc) %o\
-    %{fopenmp:%:include(libgomp.spec)%(link_gomp)} %(mflib)\
+    %{fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)}\
+    %(mflib)\
     %{fprofile-arcs|fprofile-generate|coverage:-lgcov}\
     %{!nostdlib:%{!nodefaultlibs:%(link_ssp) %(link_gcc_c_sequence)}}\
     %{!A:%{!nostdlib:%{!nostartfiles:%E}}} %{T*} }}}}}}"
diff --git gcc/config/ia64/hpux.h gcc/config/ia64/hpux.h
index ca592e4..517132c 100644
--- gcc/config/ia64/hpux.h
+++ gcc/config/ia64/hpux.h
@@ -92,7 +92,7 @@ do {							\
 #undef  LIB_SPEC
 #define LIB_SPEC \
   "%{!shared: \
-     %{mt|pthread:%{fopenmp:-lrt} -lpthread} \
+     %{mt|pthread:%{fopenmp|ftree-parallelize-loops=*:-lrt} -lpthread} \
      %{p:%{!mlp64:-L/usr/lib/hpux32/libp} \
 	 %{mlp64:-L/usr/lib/hpux64/libp} -lprof} \
      %{pg:%{!mlp64:-L/usr/lib/hpux32/libp} \
diff --git gcc/config/pa/pa-hpux11.h gcc/config/pa/pa-hpux11.h
index c217398..4da1b09 100644
--- gcc/config/pa/pa-hpux11.h
+++ gcc/config/pa/pa-hpux11.h
@@ -120,7 +120,8 @@ along with GCC; see the file COPYING3.  If not see
 #undef LIB_SPEC
 #define LIB_SPEC \
   "%{!shared:\
-     %{fopenmp:%{static:-a archive_shared} -lrt %{static:-a archive}}\
+     %{fopenmp|ftree-parallelize-loops=*:%{static:-a archive_shared} -lrt\
+       %{static:-a archive}}\
      %{mt|pthread:-lpthread} -lc\
      %{static:%{!nolibdld:-a archive_shared -ldld -a archive -lc}\
        %{!mt:%{!pthread:-a shared -lc -a archive}}}}\
diff --git gcc/config/pa/pa64-hpux.h gcc/config/pa/pa64-hpux.h
index a3e21d3..9efc137 100644
--- gcc/config/pa/pa64-hpux.h
+++ gcc/config/pa/pa64-hpux.h
@@ -58,19 +58,22 @@ along with GCC; see the file COPYING3.  If not see
 #if ((TARGET_DEFAULT | TARGET_CPU_DEFAULT) & MASK_GNU_LD)
 #define LIB_SPEC \
   "%{!shared:\
-     %{!p:%{!pg:%{fopenmp:%{static:-a shared} -lrt %{static:-a archive}}\
+     %{!p:%{!pg:%{fopenmp|ftree-parallelize-loops=*:%{static:-a shared} -lrt\
+                  %{static:-a archive}}\
 	    %{mt|pthread:-lpthread} -lc\
 	    %{static:%{!nolibdld:-a shared -ldld -a archive -lc}\
 		%{!mt:%{!pthread:-a shared -lc -a archive}}}}}\
      %{p:%{!pg:%{static:%{!mhp-ld:-a shared}%{mhp-ld:-a archive_shared}}\
 	   -lprof %{static:-a archive}\
-	   %{fopenmp:%{static:-a shared} -lrt %{static:-a archive}}\
+	   %{fopenmp|ftree-parallelize-loops=*:%{static:-a shared} -lrt\
+             %{static:-a archive}}\
 	   %{mt|pthread:-lpthread} -lc\
 	   %{static:%{!nolibdld:-a shared -ldld -a archive -lc}\
 		%{!mt:%{!pthread:-a shared -lc -a archive}}}}}\
      %{pg:%{static:%{!mhp-ld:-a shared}%{mhp-ld:-a archive_shared}}\
        -lgprof %{static:-a archive}\
-       %{fopenmp:%{static:-a shared} -lrt %{static:-a archive}}\
+       %{fopenmp|ftree-parallelize-loops=*:%{static:-a shared} -lrt\
+         %{static:-a archive}}\
        %{mt|pthread:-lpthread} -lc\
        %{static:%{!nolibdld:-a shared -ldld -a archive -lc}\
 		%{!mt:%{!pthread:-a shared -lc -a archive}}}}}\
@@ -78,19 +81,22 @@ along with GCC; see the file COPYING3.  If not see
 #else
 #define LIB_SPEC \
   "%{!shared:\
-     %{!p:%{!pg:%{fopenmp:%{static:-a shared} -lrt %{static:-a archive}}\
+     %{!p:%{!pg:%{fopenmp|ftree-parallelize-loops=*:%{static:-a shared} -lrt\
+                  %{static:-a archive}}\
 	    %{mt|pthread:-lpthread} -lc\
 	    %{static:%{!nolibdld:-a shared -ldld -a archive -lc}\
 		%{!mt:%{!pthread:-a shared -lc -a archive}}}}}\
      %{p:%{!pg:%{static:%{mgnu-ld:-a shared}%{!mgnu-ld:-a archive_shared}}\
 	   -lprof %{static:-a archive}\
-	   %{fopenmp:%{static:-a shared} -lrt %{static:-a archive}}\
+	   %{fopenmp|ftree-parallelize-loops=*:%{static:-a shared} -lrt\
+             %{static:-a archive}}\
 	   %{mt|pthread:-lpthread} -lc\
 	   %{static:%{!nolibdld:-a shared -ldld -a archive -lc}\
 		%{!mt:%{!pthread:-a shared -lc -a archive}}}}}\
      %{pg:%{static:%{mgnu-ld:-a shared}%{!mgnu-ld:-a archive_shared}}\
        -lgprof %{static:-a archive}\
-       %{fopenmp:%{static:-a shared} -lrt %{static:-a archive}}\
+       %{fopenmp|ftree-parallelize-loops=*:%{static:-a shared} -lrt\
+         %{static:-a archive}}\
        %{mt|pthread:-lpthread} -lc\
        %{static:%{!nolibdld:-a shared -ldld -a archive -lc}\
 		%{!mt:%{!pthread:-a shared -lc -a archive}}}}}\
diff --git gcc/gcc.c gcc/gcc.c
index 83607e5..dff7477 100644
--- gcc/gcc.c
+++ gcc/gcc.c
@@ -924,7 +924,7 @@ static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS;
 #define DRIVER_SELF_SPECS ""
 #endif
 
-/* Adding -fopenmp should imply pthreads.  This is particularly important
+/* Linking to libgomp implies pthreads.  This is particularly important
    for targets that use different start files and suchlike.  */
 #ifndef GOMP_SELF_SPECS
 #define GOMP_SELF_SPECS "%{fopenmp|ftree-parallelize-loops=*: -pthread}"
diff --git libgomp/configure.ac libgomp/configure.ac
index e7fbb31..84d250f 100644
--- libgomp/configure.ac
+++ libgomp/configure.ac
@@ -274,7 +274,7 @@ else
 fi
 
 # Set up the set of libraries that we need to link against for libgomp.
-# Note that the GOMP_SELF_SPEC in gcc.c will force -pthread for -fopenmp,
+# Note that the GOMP_SELF_SPEC in gcc.c may force -pthread,
 # which will force linkage against -lpthread (or equivalent for the system).
 # That's not 100% ideal, but about the best we can do easily.
 if test $enable_shared = yes; then
diff --git libgomp/libgomp.spec.in libgomp/libgomp.spec.in
index b7319f3..5651603 100644
--- libgomp/libgomp.spec.in
+++ libgomp/libgomp.spec.in
@@ -1,3 +1,3 @@
 # This spec file is read by gcc when linking.  It is used to specify the
-# standard libraries we need in order to link with -fopenmp.
+# standard libraries we need in order to link with libgomp.
 *link_gomp: @link_gomp@


Grüße,
 Thomas

[-- Attachment #2: Type: application/pgp-signature, Size: 489 bytes --]

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

* Re: Generally link to libgomp for -ftree-parallelize-loops=* (was: [gomp4 4/9] OpenACC: The runtime library will be implemented in libgomp, too.)
  2013-11-07 14:05           ` Generally link to libgomp for -ftree-parallelize-loops=* (was: [gomp4 4/9] OpenACC: The runtime library will be implemented in libgomp, too.) Thomas Schwinge
@ 2013-11-07 14:48             ` Jakub Jelinek
  0 siblings, 0 replies; 44+ messages in thread
From: Jakub Jelinek @ 2013-11-07 14:48 UTC (permalink / raw)
  To: Thomas Schwinge; +Cc: gcc-patches

On Thu, Nov 07, 2013 at 02:58:31PM +0100, Thomas Schwinge wrote:
> On Thu, 7 Nov 2013 09:15:45 +0100, Jakub Jelinek <jakub@redhat.com> wrote:
> > On Wed, Nov 06, 2013 at 08:42:18PM +0100, thomas@codesourcery.com wrote:
> > > --- gcc/config/arc/arc.h
> > > +++ gcc/config/arc/arc.h
> > > @@ -174,7 +174,7 @@ along with GCC; see the file COPYING3.  If not see
> > >      %(linker) %l " LINK_PIE_SPEC "%X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r}\
> > >      %{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
> > >      %{static:} %{L*} %(mfwrap) %(link_libgcc) %o\
> > > -    %{fopenmp:%:include(libgomp.spec)%(link_gomp)} %(mflib)\
> > > +    %{fopenacc|fopenmp:%:include(libgomp.spec)%(link_gomp)} %(mflib)\
> > 
> > Perhaps add here |ftree-parallelize-loops=* too?  [...]
> 
> Like this (for trunk and gomp-4_0-branch)?
> 
> 	gcc/
> 	* config/arc/arc.h (LINK_COMMAND_SPEC): For
> 	-ftree-parallelize-loops=*, link to libgomp and its dependencies.
> 	* config/ia64/hpux.h (LIB_SPEC): Likewise.
> 	* config/pa/pa-hpux11.h (LIB_SPEC): Likewise.
> 	* config/pa/pa64-hpux.h (LIB_SPEC): Likewise.
> 	* gcc.c (GOMP_SELF_SPECS): Update comment about libgomp's
> 	dependencies.
> 	libgomp/
> 	* libgomp.spec.in: Update comment about libgomp's dependencies.
> 	* configure.ac: Likewise.
> 	* configure: Regenerate.

Yes, thanks.

	Jakub

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

* RE: Initial submission of OpenACC support integrated into OpenMP's lowering and expansion passes
  2013-11-06 19:44 Initial submission of OpenACC support integrated into OpenMP's lowering and expansion passes Thomas Schwinge
  2013-11-06 19:44 ` [gomp4 1/9] Add missing include thomas
@ 2013-11-07 18:14 ` Evgeny Gavrin
  2013-11-27 23:23   ` Thomas Schwinge
       [not found]   ` <004b01cedc68$a5f3c950$f1db5bf0$%b@samsung.com>
  1 sibling, 2 replies; 44+ messages in thread
From: Evgeny Gavrin @ 2013-11-07 18:14 UTC (permalink / raw)
  To: 'Thomas Schwinge', jakub
  Cc: i.usmanov, 'Dmitry Bocharnikov',
	Slava Garbuzov, gcc-patches, e.gavrin

Hi, Thomas!

This is really great!
I've looked at your changes and in most of front-end parts it looks reasonable to me. As you know, we're like-minded with you about how OpenACC's front-ends should look like. So, I think it's good that you have working flow for your implementation. Now we can start to merge front-ends from openacc-1_0-branch to GOMP, while keeping all understandings of ACC in sync and working.

Jakub, don't you mind if I prepare a few front-end patches likewise for review to extend Thomas' vision with the things that was already done by my colleagues on the ACC branch? I hope it'll much speed up the development.

> the last patch adds GOACC_parallel, which so far simply branches to 
> GOMP_target.  There's more to come.
I've reviewed ACC-related code from [openacc-1_0-branch] and from the patches, I noticed there are some mess around marking OpenACC specific code. There are ACC, GACC, OACC, GOACC abbreviations used across code, which one is the best? I prefer ACC, this is not critical, I'm just curious how to resolve this.

> Due to the conceptual similarity compared to OpenMP, and that (later) 
> it is reasonable to expect to embed OpenACC directives into OpenMP 
> ones, the approach I've chosen is to directly embed OpenACC handling 
> into the existing OpenMP infrastructure/passes.
Regarding front-ends, not only from view of OMP/ACC, but front-ends itself, it makes sense to move some parsing routines out of gomp/acc context. This will be useful to implement not only ACC, but also HMPP, if someone is interested, or other similar technology. And of cause, these functions should be used behind the existing facilities - not to break current implementation and other dependencies. So it won't not introduce any difficulties for back porting, while generalizing front-ends a bit.
For now, I prefer to extend the approved way of developing, but keep it in mind, please.

> This patch series doesn't contain any substantial rumtime library work 
> yet;
Can you share some technical details/ideas about further implementation, it's not going to be trivial. On the [openacc-1_0-branch] we resolved it with OpenCL-driven runtime. Also, OpenACC 2.0 standard declares some vendor-specific routines, this should be noted too.

> This is in contrast to Samsung's work, who are implementing OpenACC
> separately from the existing OpenMP support.
I'm not fully agree that this in contrast to things are taking place in [openacc-1_0-branch]. The main reason for keeping middle-end and back-end solutions far from GOMP is the understanding of OpenACC semantics and unclear understanding of what should be done to generalize support of accelerators in GCC. OpenACC and OpenOMP has some semantically differences, but such things matters only for middle-end and further code generation. The main one, is the memory concept. The 

> Yet, I hope we'll be able to share/re-use at least front end and some
middle end code.
I absolutely agree, it's needed to merge our efforts regarding front-ends.
Many things from ACC in [openacc-1_0-branch] is already done, so it doesn't necessary to re-implement same things. Maybe we can polish front-ends together and then commit changes to GOMP?

> We directly strive for OpenACC 2.0 support, skipping OpenACC 1.  We're 
> focussing on the C front end implementation first, following on with 
> C++ and Fortran later on.
How do you think, does it make sense to adopt current Fortran implementation from the OpenACC branch? This can be done quite soon. Also, I may help to extend C and C++ front-end the same way it's done now, by adding other implemented directives, too.

Regarding proposed patches:
[8/9] c_parser_omp_all_clauses and cp_parser_omp_all_clauses
-	  c_parser_error (parser, "expected %<#pragma omp%> clause");
+	  c_parser_error (parser, "expected clause");

-	  cp_parser_error (parser, "expected %<#pragma omp%> clause");
+	  cp_parser_error (parser, "expected clause");
Does it really needed to remove %<#pragma omp%> in these cases? We handle both, I think.

[9/9]
* gimple.h (gimple_build_oacc_*): New declaration.
gimple_oacc_parallel_* and other functions like that. Let's move these functions out of gimple.* to gimple-oacc.*! There are going to be much more of the stuff like this, maybe it'll make sense to keep it externally? May be not only gimple manipulation functions but also pretty-print Also, have a look on openacc_1-0_branch please, for gimple-oacc.*, is OK if I'll add some of this?

Handling clauses.
+  GIMPLE_CHECK (gs, GIMPLE_OACC_PARALLEL);  
+ gs->gimple_omp_parallel.clauses = clauses;
I think, we can freely add some kind of flag to gimple_omp_parallel to indicate that we're are working with ACC.
Or even add new gimple_acc_* statements.

On gimplification, lowering stuff and further, I think it's okay if targeting GOMP_target, but on my view, this is going to prevent us from emiting OpenCL or do some extended analysis of the code for error analysis to be offloaded. May be introduce some switch that turns on OpenCL generation or GOMP_targeting dependently on the state?

I hope my colleagues will correct me, if I forgot something.

-
Thanks,  
    Evgeny.

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

* Re: [gomp4 9/9] OpenACC: Basic support for #pragma acc parallel.
  2013-11-06 20:03                   ` [gomp4 9/9] OpenACC: Basic support for #pragma acc parallel Jakub Jelinek
@ 2013-11-07 19:00                     ` Thomas Schwinge
  0 siblings, 0 replies; 44+ messages in thread
From: Thomas Schwinge @ 2013-11-07 19:00 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

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

Hi!

Thanks for the quick review of the patch series!  Committed earlier
today, with the revisions as discussed.


On Wed, 6 Nov 2013 20:55:01 +0100, Jakub Jelinek <jakub@redhat.com> wrote:
> On Wed, Nov 06, 2013 at 08:42:23PM +0100, thomas@codesourcery.com wrote:
> > +#define OACC_PARALLEL_CLAUSE_MASK			\
> > +	PRAGMA_OMP_CLAUSE_NONE
> 
> This is incorrect, either you should define in c-common.h
> also OMP_CLAUSE_MASK_0 and define this to it, or
> it needs to be (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NONE).
> Otherwise it won't compile on 32-bit HWI targets where omp_clause_mask
> is a C++ class.

You're right -- yet, thanks to the wonders of legacy C support, this
doesn't even result in any compiler warning or error.  Anyway, I went
with your latter suggestion: this is scheduled for removal anyway, as one
of my next steps is adding support for clauses for OpenACC parallel.


I also notice that we're basically wasting one bit of the clause mask,
because (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NONE) == 1, and not 0,
but as we're currently using 37 bits and have 64 bits available, that
doesn't matter much (and so I didn't feel like reworking that code).


Grüße,
 Thomas

[-- Attachment #2: Type: application/pgp-signature, Size: 489 bytes --]

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

* RE: Initial submission of OpenACC support integrated into OpenMP's lowering and expansion passes
  2013-11-07 18:14 ` Initial submission of OpenACC support integrated into OpenMP's lowering and expansion passes Evgeny Gavrin
@ 2013-11-27 23:23   ` Thomas Schwinge
       [not found]   ` <004b01cedc68$a5f3c950$f1db5bf0$%b@samsung.com>
  1 sibling, 0 replies; 44+ messages in thread
From: Thomas Schwinge @ 2013-11-27 23:23 UTC (permalink / raw)
  To: Evgeny Gavrin
  Cc: i.usmanov, 'Dmitry Bocharnikov',
	Slava Garbuzov, gcc-patches, jakub

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

Hi!

I'm sorry for the very late answer!


On Thu, 7 Nov 2013 22:10:15 +0400, Evgeny Gavrin <e.gavrin@samsung.com> wrote:
> I've looked at your changes and in most of front-end parts it looks reasonable to me. As you know, we're like-minded with you about how OpenACC's front-ends should look like. So, I think it's good that you have working flow for your implementation. Now we can start to merge front-ends from openacc-1_0-branch to GOMP, while keeping all understandings of ACC in sync and working.
> 
> Jakub, don't you mind if I prepare a few front-end patches likewise for review to extend Thomas' vision with the things that was already done by my colleagues on the ACC branch? I hope it'll much speed up the development.

I'd be happy if you did that, sure!  (And, as Jakub didn't argue against
this, but has allowed for OpenACC development to happen on the
gomp-4_0-branch, I suppose he's fine with that, too.)


> > the last patch adds GOACC_parallel, which so far simply branches to 
> > GOMP_target.  There's more to come.
> I've reviewed ACC-related code from [openacc-1_0-branch] and from the patches, I noticed there are some mess around marking OpenACC specific code. There are ACC, GACC, OACC, GOACC abbreviations used across code, which one is the best? I prefer ACC, this is not critical, I'm just curious how to resolve this.

In the "GNU or GCC world", generally the G prefix is used for any
additions/extensions/modifications that are, for example, part of the
external GNU ABI but not in the standard.  So, for example, in libgomp
there is a omp_get_team_size symbol exported as that function name is
mandated by the OpenMP standard.  On the other hand, for the internal
»#pragma omp parallel« implementation, libgomp exports a GNU-only
GOMP_parallel symbol, which GCC knows and uses.  The same scheme I
started using for OpenACC.

As for ACC vs. OACC, my reasoning is two-fold: OACC makes it look nicely
next to OMP ;-), and there are already quite some ACC* things in the
compiler (meaning: accept, access, account, accumulate, ...), making it a
bit hard to grep for ACC* things -- a problem we don't have with OACC.  I
don't insist on this however: can for example also use ACC or maybe even
OPENACC if there's consensus that'd be better.


> > This patch series doesn't contain any substantial rumtime library work 
> > yet;
> Can you share some technical details/ideas about further implementation, it's not going to be trivial. On the [openacc-1_0-branch] we resolved it with OpenCL-driven runtime. Also, OpenACC 2.0 standard declares some vendor-specific routines, this should be noted too.

Yes, we're working on some kind of design sketch similar to what you sent
for the OpenACC to OpenCL translation.  I think a page on the GCC wiki
would be a good place to keep this information for the moment, and then
later transfer it into the (internals) documentation of libgomp (or any
new library).  I have just created a stub page,
<http://gcc.gnu.org/wiki/OpenACC>, and will add to that later.


> > This is in contrast to Samsung's work, who are implementing OpenACC
> > separately from the existing OpenMP support.
> I'm not fully agree that this in contrast to things are taking place in [openacc-1_0-branch]. The main reason for keeping middle-end and back-end solutions far from GOMP is the understanding of OpenACC semantics and unclear understanding of what should be done to generalize support of accelerators in GCC. OpenACC and OpenOMP has some semantically differences, but such things matters only for middle-end and further code generation. The main one, is the memory concept. The 

My approach was (and still is), to first use what we already have (for
example, GOMP_target/»#pragma omp target« for implementing #pragma acc
parallel«), so that we get something that does something, and then
extend/rework that to implement what OpenACC actually requires, for
example.


> > Yet, I hope we'll be able to share/re-use at least front end and some
> middle end code.
> I absolutely agree, it's needed to merge our efforts regarding front-ends.
> Many things from ACC in [openacc-1_0-branch] is already done, so it doesn't necessary to re-implement same things. Maybe we can polish front-ends together and then commit changes to GOMP?

Yep, that'd be good to do.

> > We directly strive for OpenACC 2.0 support, skipping OpenACC 1.  We're 
> > focussing on the C front end implementation first, following on with 
> > C++ and Fortran later on.
> How do you think, does it make sense to adopt current Fortran implementation from the OpenACC branch? This can be done quite soon. Also, I may help to extend C and C++ front-end the same way it's done now, by adding other implemented directives, too.

Sure, that sounds good.


> Regarding proposed patches:
> [8/9] c_parser_omp_all_clauses and cp_parser_omp_all_clauses
> -	  c_parser_error (parser, "expected %<#pragma omp%> clause");
> +	  c_parser_error (parser, "expected clause");
> 
> -	  cp_parser_error (parser, "expected %<#pragma omp%> clause");
> +	  cp_parser_error (parser, "expected clause");
> Does it really needed to remove %<#pragma omp%> in these cases? We handle both, I think.

Hmm, how do you mean »both«?  I originally thought this code would be
shared with OpenACC -- but maybe that's actually not the best approach
here, so I might revert these two changes later.


> [9/9]
> * gimple.h (gimple_build_oacc_*): New declaration.
> gimple_oacc_parallel_* and other functions like that. Let's move these functions out of gimple.* to gimple-oacc.*! There are going to be much more of the stuff like this, maybe it'll make sense to keep it externally? May be not only gimple manipulation functions but also pretty-print Also, have a look on openacc_1-0_branch please, for gimple-oacc.*, is OK if I'll add some of this?

I'll have a look.  Again, here I just followed the pattern how things
were done for OpenMP, and added to that.  But keeping all these little
helper functions in a separate file may be a sensible thing to do.


> Handling clauses.
> +  GIMPLE_CHECK (gs, GIMPLE_OACC_PARALLEL);  
> + gs->gimple_omp_parallel.clauses = clauses;
> I think, we can freely add some kind of flag to gimple_omp_parallel to indicate that we're are working with ACC.
> Or even add new gimple_acc_* statements.

We can, but so far I had no need to, so I just used what was already
there instead of adding new infrastructure that does the same thing as
the existing one.


> On gimplification, lowering stuff and further, I think it's okay if targeting GOMP_target, but on my view, this is going to prevent us from emiting OpenCL or do some extended analysis of the code for error analysis to be offloaded. May be introduce some switch that turns on OpenCL generation or GOMP_targeting dependently on the state?

Am I wrong assuming that targeting OpenCL would be another instance of
the "offloading" functionality we're currently discussing elsewhere?  The
idea is to stream out (LTO streaming) the intermediate representation of
the structured block attached to a OpenACC/OpenMP/Cilk
Plus/... directive, and then have the GCC driver invoke the lto1
targeting the acceleration device's architecture, which will then read it
in again, and process it further.  For example, in our case, this would
be a nvptx-none lto1 that then produces PTX code, which is then fed back
into the "main" GCC driver, and embedded (as a text string, basically)
into the x86-64 object file that this one is creating.  Would it make
sense to see OpenCL as another target "architecture"; does it fit into
this design, or should this be handled differently?


> I hope my colleagues will correct me, if I forgot something.

Should I, by the way, always add all of you to the CC field when I send
emails that I think your group might be interested in?  (No problem doing
that, if you'd like me to.)


Grüße,
 Thomas

[-- Attachment #2: Type: application/pgp-signature, Size: 489 bytes --]

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

* RE: Initial submission of OpenACC support integrated into OpenMP's lowering and expansion passes
       [not found]   ` <004b01cedc68$a5f3c950$f1db5bf0$%b@samsung.com>
@ 2013-11-27 23:25     ` Thomas Schwinge
  0 siblings, 0 replies; 44+ messages in thread
From: Thomas Schwinge @ 2013-11-27 23:25 UTC (permalink / raw)
  To: Dmitry Bocharnikov, 'Evgeny Gavrin'
  Cc: i.usmanov, 'Slava Garbuzov', gcc-patches, jakub

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

Hi!

Again, I'm sorry for the late answer.


On Fri, 8 Nov 2013 13:55:24 +0400, Dmitry Bocharnikov <dmitry.b@samsung.com> wrote:
> > > This is in contrast to Samsung's work, who are implementing OpenACC
> > > separately from the existing OpenMP support.
> > I'm not fully agree that this in contrast to things are taking place in
> > [openacc-1_0-branch]. The main reason for keeping middle-end and back-
> > end solutions far from GOMP is the understanding of OpenACC semantics
> > and unclear understanding of what should be done to generalize support
> > of accelerators in GCC. OpenACC and OpenOMP has some semantically
> > differences, but such things matters only for middle-end and further
> 
> I suppose that there is a misunderstanding in OpenMP and OpenACC 
> compatibility.

Well, not exactly a misunderstanding, but I just didn't address the
differences yet, as I first wanted to get something that basically works,
even if not yet according to the OpenACC standard's precise details, and
then later work on extending/reworking the compiler and runtime library
(relying on what already exists in libgomp) to properly implement what
both OpenMP and OpenACC require.

> OpenMP standard specifically states [...]

> On the other hand, OpenACC standard [...]

> Moreover, there is at least one commercial implementation that already 
> performs data dependency
> checking and feedback to user results of loop parallelization. However, in its 
> current state OpenMP
> implementation framework does not provide any means to do data dependency 
> checking.
> Would be it useful, if GCC implementation will be worse in that sense?

The "right" interpretation of the standards is certainly something we
should be discussing (and can also talk to the OpenACC committee, and
other OpenACC implementors), but I propose this to be an iterative
process, once the basic infrastructure is all there, and then by example
of (for example) specific testcases argue what should be done, how the
standard should be laid out.


Grüße,
 Thomas

[-- Attachment #2: Type: application/pgp-signature, Size: 489 bytes --]

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

* [gomp4] Gimplification: Merge gimplify_oacc_parallel into gimplify_omp_workshare. (was: [gomp4 9/9] OpenACC: Basic support for #pragma acc parallel.)
  2013-11-06 20:01                   ` Thomas Schwinge
  2013-11-07  8:48                     ` Jakub Jelinek
@ 2014-02-27 19:58                     ` Thomas Schwinge
  2014-03-20 14:28                     ` [gomp4 9/9] OpenACC: Basic support for #pragma acc parallel Thomas Schwinge
  2014-11-12 13:35                     ` OpenACC GIMPLE_OACC_* -- or not? (was: [gomp4 9/9] OpenACC: Basic support for #pragma acc parallel.) Thomas Schwinge
  3 siblings, 0 replies; 44+ messages in thread
From: Thomas Schwinge @ 2014-02-27 19:58 UTC (permalink / raw)
  To: gcc-patches

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

Hi!

On Wed, 6 Nov 2013 20:53:00 +0100, I wrote:
> 	gcc/
> 	* gimplify.c [...]
> 	(gimplify_oacc_parallel): New function.

To get rid of code duplication, I have applied the following in r208206:

commit 9ffb216dd43bda84f56ce7fe68ae15cc08110924
Author: tschwinge <tschwinge@138bc75d-0d04-0410-961f-82ee72b054a4>
Date:   Thu Feb 27 19:56:28 2014 +0000

    Gimplification: Merge gimplify_oacc_parallel into gimplify_omp_workshare.
    
    	gcc/
    	* gimplify.c (gimplify_oacc_parallel): Merge into
    	gimplify_omp_workshare.  Update all callers.
    
    git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@208206 138bc75d-0d04-0410-961f-82ee72b054a4

diff --git gcc/ChangeLog.gomp gcc/ChangeLog.gomp
index 9f5941f..3d9b06d 100644
--- gcc/ChangeLog.gomp
+++ gcc/ChangeLog.gomp
@@ -1,3 +1,8 @@
+2014-02-27  Thomas Schwinge  <thomas@codesourcery.com>
+
+	* gimplify.c (gimplify_oacc_parallel): Merge into
+	gimplify_omp_workshare.  Update all callers.
+
 2014-02-27  Ilmir Usmanov  <i.usmanov@samsung.com>
 
 	Fix OpenACC ASYNC clause: it cannot contain integer-expression-list.
diff --git gcc/gimplify.c gcc/gimplify.c
index d0a4779..6dbabfa 100644
--- gcc/gimplify.c
+++ gcc/gimplify.c
@@ -6572,38 +6572,6 @@ gimplify_adjust_omp_clauses (tree *list_p)
   delete_omp_context (ctx);
 }
 
-/* Gimplify the contents of an OACC_PARALLEL statement.  This involves
-   gimplification of the body, as well as scanning the body for used
-   variables.  We need to do this scan now, because variable-sized
-   decls will be decomposed during gimplification.  */
-
-static void
-gimplify_oacc_parallel (tree *expr_p, gimple_seq *pre_p)
-{
-  tree expr = *expr_p;
-  gimple g;
-  gimple_seq body = NULL;
-  enum omp_region_type ort = (enum omp_region_type) (ORT_TARGET
-						     | ORT_TARGET_OFFLOAD
-						     | ORT_TARGET_MAP_FORCE);
-
-  gimplify_scan_omp_clauses (&OACC_PARALLEL_CLAUSES (expr), pre_p, ort);
-
-  push_gimplify_context ();
-
-  g = gimplify_and_return_first (OACC_PARALLEL_BODY (expr), &body);
-  if (gimple_code (g) == GIMPLE_BIND)
-    pop_gimplify_context (g);
-  else
-    pop_gimplify_context (NULL);
-
-  gimplify_adjust_omp_clauses (&OACC_PARALLEL_CLAUSES (expr));
-
-  g = gimple_build_oacc_parallel (body, OACC_PARALLEL_CLAUSES (expr));
-  gimplify_seq_add_stmt (pre_p, g);
-  *expr_p = NULL_TREE;
-}
-
 /* Gimplify the contents of an OMP_PARALLEL statement.  This involves
    gimplification of the body, as well as scanning the body for used
    variables.  We need to do this scan now, because variable-sized
@@ -7039,6 +7007,11 @@ gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p)
       ort = (enum omp_region_type) (ORT_TARGET
 				    | ORT_TARGET_MAP_FORCE);
       break;
+    case OACC_PARALLEL:
+      ort = (enum omp_region_type) (ORT_TARGET
+				    | ORT_TARGET_OFFLOAD
+				    | ORT_TARGET_MAP_FORCE);
+      break;
     case OMP_SECTIONS:
     case OMP_SINGLE:
       ort = ORT_WORKSHARE;
@@ -7097,6 +7070,9 @@ gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p)
       stmt = gimple_build_omp_target (body, GF_OMP_TARGET_KIND_OACC_DATA,
 				      OACC_DATA_CLAUSES (expr));
       break;
+    case OACC_PARALLEL:
+      stmt = gimple_build_oacc_parallel (body, OACC_PARALLEL_CLAUSES (expr));
+      break;
     case OMP_SECTIONS:
       stmt = gimple_build_omp_sections (body, OMP_CLAUSES (expr));
       break;
@@ -8060,11 +8036,6 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
 	  ret = GS_ALL_DONE;
 	  break;
 
-	case OACC_PARALLEL:
-	  gimplify_oacc_parallel (expr_p, pre_p);
-	  ret = GS_ALL_DONE;
-	  break;
-
 	case OACC_KERNELS:
 	case OACC_HOST_DATA:
 	case OACC_DECLARE:
@@ -8095,6 +8066,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
 	  break;
 
 	case OACC_DATA:
+	case OACC_PARALLEL:
 	case OMP_SECTIONS:
 	case OMP_SINGLE:
 	case OMP_TARGET:


Grüße,
 Thomas

[-- Attachment #2: Type: application/pgp-signature, Size: 489 bytes --]

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

* Re: [gomp4 9/9] OpenACC: Basic support for #pragma acc parallel.
  2013-11-06 20:01                   ` Thomas Schwinge
  2013-11-07  8:48                     ` Jakub Jelinek
  2014-02-27 19:58                     ` [gomp4] Gimplification: Merge gimplify_oacc_parallel into gimplify_omp_workshare. (was: [gomp4 9/9] OpenACC: Basic support for #pragma acc parallel.) Thomas Schwinge
@ 2014-03-20 14:28                     ` Thomas Schwinge
  2014-11-12 13:35                     ` OpenACC GIMPLE_OACC_* -- or not? (was: [gomp4 9/9] OpenACC: Basic support for #pragma acc parallel.) Thomas Schwinge
  3 siblings, 0 replies; 44+ messages in thread
From: Thomas Schwinge @ 2014-03-20 14:28 UTC (permalink / raw)
  To: gcc-patches

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

Hi!

On Wed, 6 Nov 2013 20:53:00 +0100, I wrote:
> --- /dev/null
> +++ gcc/testsuite/c-c++-common/goacc/parallel-1.c
> @@ -0,0 +1,6 @@
> +void
> +foo (void)
> +{
> +#pragma acc parallel
> +  foo ();
> +}

Applied in r208699 on gomp-4_0-branch:

commit 4a854d643b300adc0b79ad5dadd132aa1cdd535a
Author: tschwinge <tschwinge@138bc75d-0d04-0410-961f-82ee72b054a4>
Date:   Thu Mar 20 14:22:41 2014 +0000

    Fix OpenACC parallel testcase to avoid nonsensical recursion.
    
    	gcc/testsuite/
    	* c-c++-common/goacc/parallel-1.c: Don't recurse.
    
    git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@208699 138bc75d-0d04-0410-961f-82ee72b054a4

diff --git gcc/testsuite/ChangeLog.gomp gcc/testsuite/ChangeLog.gomp
index 1f4d704..81876ec 100644
--- gcc/testsuite/ChangeLog.gomp
+++ gcc/testsuite/ChangeLog.gomp
@@ -1,5 +1,7 @@
 2014-03-20  Thomas Schwinge  <thomas@codesourcery.com>
 
+	* c-c++-common/goacc/parallel-1.c: Don't recurse.
+
 	* gfortran.dg/goacc/cache-1.f95: Replace dg-excess-errors usage
 	with dg-prune-output.
 	* gfortran.dg/goacc/coarray.f95: Likewise.
diff --git gcc/testsuite/c-c++-common/goacc/parallel-1.c gcc/testsuite/c-c++-common/goacc/parallel-1.c
index cd19527..a860526 100644
--- gcc/testsuite/c-c++-common/goacc/parallel-1.c
+++ gcc/testsuite/c-c++-common/goacc/parallel-1.c
@@ -2,5 +2,5 @@ void
 foo (void)
 {
 #pragma acc parallel
-  foo ();
+  ;
 }


Grüße,
 Thomas

[-- Attachment #2: Type: application/pgp-signature, Size: 472 bytes --]

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

* OpenACC GIMPLE_OACC_* -- or not?  (was: [gomp4 9/9] OpenACC: Basic support for #pragma acc parallel.)
  2013-11-06 20:01                   ` Thomas Schwinge
                                       ` (2 preceding siblings ...)
  2014-03-20 14:28                     ` [gomp4 9/9] OpenACC: Basic support for #pragma acc parallel Thomas Schwinge
@ 2014-11-12 13:35                     ` Thomas Schwinge
  2014-11-12 13:46                       ` Jakub Jelinek
  3 siblings, 1 reply; 44+ messages in thread
From: Thomas Schwinge @ 2014-11-12 13:35 UTC (permalink / raw)
  To: gcc-patches, Jakub Jelinek, Cesar Philippidis, Tom de Vries

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

Hi!

On Wed, 6 Nov 2013 20:53:00 +0100, I wrote:
> --- gcc/gimple.def
> +++ gcc/gimple.def
> @@ -205,10 +205,16 @@ DEFGSCODE(GIMPLE_NOP, "gimple_nop", GSS_BASE)
>  
>  /* IMPORTANT.
>  
> -   Do not rearrange any of the GIMPLE_OMP_* codes.  This ordering is
> -   exposed by the range check in gimple_omp_subcode().  */
> +   Do not rearrange any of the GIMPLE_OACC_* and GIMPLE_OMP_* codes.  This
> +   ordering is exposed by the range check in gimple_omp_subcode.  */
>  
>  
> +/* GIMPLE_OACC_PARALLEL <BODY, CLAUSES, CHILD_FN, DATA_ARG> represents
> +
> +   #pragma acc parallel [CLAUSES]
> +   BODY */
> +DEFGSCODE(GIMPLE_OACC_PARALLEL, "gimple_oacc_parallel", GSS_OMP_PARALLEL)

Months later, with months' worth of GCC internals experience, I now came
to realize that maybe this has not actually been a useful thing to do
(and likewise for the GIMPLE_OACC_KERNELS also added later on,
<http://news.gmane.org/find-root.php?message_id=%3C1393579386-11666-1-git-send-email-thomas%40codesourcery.com%3E>).
All handling of GIMPLE_OACC_PARALLEL and GIMPLE_OACC_KERNELS closely
follows that of GIMPLE_OMP_TARGET's GF_OMP_TARGET_KIND_REGION, with only
minor divergence.  What I did not understand back then, has not been
obvious to me, was that the underlying structure of all those codes will
in fact be the same (as already made apparent by using the one
GIMPLE_OMP_TARGET for all of: OpenMP target offloading regions, OpenMP
target data regions, OpenMP target data maintenenace "executable"
statements), and any "customization" then happens via the clauses
attached to GIMPLE_OMP_TARGET.

So, sanity check: should we now merge GIMPLE_OACC_PARALLEL and
GIMPLE_OACC_KERNELS into being "subtypes" of GIMPLE_OMP_TARGET (like
GF_OMP_TARGET_KIND_REGION), as already done for
GF_OMP_TARGET_KIND_OACC_DATA (like GF_OMP_TARGET_KIND_DATA), and
GF_OMP_TARGET_KIND_OACC_UPDATE and
GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA (like GF_OMP_TARGET_KIND_UPDATE).


That said, in r217419 I have applied the following (related) cleanup to
gomp-4_0-branch:

> --- gcc/omp-low.c
> +++ gcc/omp-low.c

> +/* Scan an OpenACC parallel directive.  */
> +
> +static void
> +scan_oacc_parallel (gimple stmt, omp_context *outer_ctx)
> +{

> +/* Expand the OpenACC parallel directive starting at REGION.  */
> +
> +static void
> +expand_oacc_parallel (struct omp_region *region)
> +{

> +/* Lower the OpenACC parallel directive in the current statement
> +   in GSI_P.  CTX holds context information for the directive.  */
> +
> +static void
> +lower_oacc_parallel (gimple_stmt_iterator *gsi_p, omp_context *ctx)
> +{

commit 77c7a5b72c20f41b226100ed5de053d1fdb32602
Author: tschwinge <tschwinge@138bc75d-0d04-0410-961f-82ee72b054a4>
Date:   Wed Nov 12 13:32:01 2014 +0000

    Middle end: Merge *_oacc_offload functions into *_omp_target.
    
    	gcc/
    	* omp-low.c (scan_oacc_offload, expand_oacc_offload)
    	(lower_oacc_offload): Merge into scan_omp_target,
    	expand_omp_target, lower_omp_target, respectively.  Update all
    	users.
    
    git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@217419 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/ChangeLog.gomp |    7 +
 gcc/omp-low.c      | 1293 ++++++++++++++--------------------------------------
 2 files changed, 338 insertions(+), 962 deletions(-)

diff --git gcc/ChangeLog.gomp gcc/ChangeLog.gomp
index 4ea28e2..2008542 100644
--- gcc/ChangeLog.gomp
+++ gcc/ChangeLog.gomp
@@ -1,3 +1,10 @@
+2014-11-12  Thomas Schwinge  <thomas@codesourcery.com>
+
+	* omp-low.c (scan_oacc_offload, expand_oacc_offload)
+	(lower_oacc_offload): Merge into scan_omp_target,
+	expand_omp_target, lower_omp_target, respectively.  Update all
+	users.
+
 2014-11-11  Thomas Schwinge  <thomas@codesourcery.com>
 
 	* omp-low.c (scan_sharing_clauses): Remove bogus assertion.
diff --git gcc/omp-low.c gcc/omp-low.c
index 1263409..44e14b4 100644
--- gcc/omp-low.c
+++ gcc/omp-low.c
@@ -2354,69 +2354,6 @@ find_combined_for (gimple_stmt_iterator *gsi_p,
   return NULL;
 }
 
-/* Scan an OpenACC offload directive.  */
-
-static void
-scan_oacc_offload (gimple stmt, omp_context *outer_ctx)
-{
-  omp_context *ctx;
-  tree name;
-  void (*gimple_omp_set_child_fn) (gimple, tree);
-  tree (*gimple_omp_clauses) (const_gimple);
-  switch (gimple_code (stmt))
-    {
-    case GIMPLE_OACC_KERNELS:
-      gimple_omp_set_child_fn = gimple_oacc_kernels_set_child_fn;
-      gimple_omp_clauses = gimple_oacc_kernels_clauses;
-      break;
-    case GIMPLE_OACC_PARALLEL:
-      gimple_omp_set_child_fn = gimple_oacc_parallel_set_child_fn;
-      gimple_omp_clauses = gimple_oacc_parallel_clauses;
-      break;
-    default:
-      gcc_unreachable ();
-    }
-
-  gcc_assert (taskreg_nesting_level == 0);
-  gcc_assert (target_nesting_level == 0);
-
-  ctx = new_omp_context (stmt, outer_ctx);
-  ctx->field_map = splay_tree_new (splay_tree_compare_pointers, 0, 0);
-  ctx->default_kind = OMP_CLAUSE_DEFAULT_SHARED;
-  ctx->record_type = lang_hooks.types.make_type (RECORD_TYPE);
-  name = create_tmp_var_name (".omp_data_t");
-  name = build_decl (gimple_location (stmt),
-		     TYPE_DECL, name, ctx->record_type);
-  DECL_ARTIFICIAL (name) = 1;
-  DECL_NAMELESS (name) = 1;
-  TYPE_NAME (ctx->record_type) = name;
-  create_omp_child_function (ctx, false);
-  ctx->reduction_map = splay_tree_new (splay_tree_compare_pointers, 0, 0);
-
-  gimple_omp_set_child_fn (stmt, ctx->cb.dst_fn);
-
-  scan_sharing_clauses (gimple_omp_clauses (stmt), ctx);
-  scan_omp (gimple_omp_body_ptr (stmt), ctx);
-
-  if (TYPE_FIELDS (ctx->record_type) == NULL)
-    ctx->record_type = ctx->receiver_decl = NULL;
-  else
-    {
-      TYPE_FIELDS (ctx->record_type)
-	= nreverse (TYPE_FIELDS (ctx->record_type));
-#ifdef ENABLE_CHECKING
-      tree field;
-      unsigned int align = DECL_ALIGN (TYPE_FIELDS (ctx->record_type));
-      for (field = TYPE_FIELDS (ctx->record_type);
-	   field;
-	   field = DECL_CHAIN (field))
-	gcc_assert (DECL_ALIGN (field) == align);
-#endif
-      layout_type (ctx->record_type);
-      fixup_child_record_type (ctx);
-    }
-}
-
 /* Scan an OpenMP parallel directive.  */
 
 static void
@@ -2712,10 +2649,30 @@ scan_omp_target (gimple stmt, omp_context *outer_ctx)
 {
   omp_context *ctx;
   tree name;
-  int kind = gimple_omp_target_kind (stmt);
+  bool offloaded;
+  void (*gimple_omp_set_child_fn) (gimple, tree);
+  tree (*gimple_omp_clauses) (const_gimple);
 
-  if (kind == GF_OMP_TARGET_KIND_OACC_DATA
-      || kind == GF_OMP_TARGET_KIND_OACC_UPDATE)
+  offloaded = is_gimple_omp_offloaded (stmt);
+  switch (gimple_code (stmt))
+    {
+    case GIMPLE_OACC_KERNELS:
+      gimple_omp_set_child_fn = gimple_oacc_kernels_set_child_fn;
+      gimple_omp_clauses = gimple_oacc_kernels_clauses;
+      break;
+    case GIMPLE_OACC_PARALLEL:
+      gimple_omp_set_child_fn = gimple_oacc_parallel_set_child_fn;
+      gimple_omp_clauses = gimple_oacc_parallel_clauses;
+      break;
+    case GIMPLE_OMP_TARGET:
+      gimple_omp_set_child_fn = gimple_omp_target_set_child_fn;
+      gimple_omp_clauses = gimple_omp_target_clauses;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  if (is_gimple_omp_oacc_specifically (stmt))
     {
       gcc_assert (taskreg_nesting_level == 0);
       gcc_assert (target_nesting_level == 0);
@@ -2731,13 +2688,17 @@ scan_omp_target (gimple stmt, omp_context *outer_ctx)
   DECL_ARTIFICIAL (name) = 1;
   DECL_NAMELESS (name) = 1;
   TYPE_NAME (ctx->record_type) = name;
-  if (kind == GF_OMP_TARGET_KIND_REGION)
+  if (offloaded)
     {
+      if (is_gimple_omp_oacc_specifically (stmt))
+	ctx->reduction_map = splay_tree_new (splay_tree_compare_pointers,
+					     0, 0);
+
       create_omp_child_function (ctx, false);
-      gimple_omp_target_set_child_fn (stmt, ctx->cb.dst_fn);
+      gimple_omp_set_child_fn (stmt, ctx->cb.dst_fn);
     }
 
-  scan_sharing_clauses (gimple_omp_target_clauses (stmt), ctx);
+  scan_sharing_clauses (gimple_omp_clauses (stmt), ctx);
   scan_omp (gimple_omp_body_ptr (stmt), ctx);
 
   if (TYPE_FIELDS (ctx->record_type) == NULL)
@@ -2755,7 +2716,7 @@ scan_omp_target (gimple stmt, omp_context *outer_ctx)
 	gcc_assert (DECL_ALIGN (field) == align);
 #endif
       layout_type (ctx->record_type);
-      if (kind == GF_OMP_TARGET_KIND_REGION)
+      if (offloaded)
 	fixup_child_record_type (ctx);
     }
 }
@@ -3215,11 +3176,6 @@ scan_omp_1_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
 
   switch (gimple_code (stmt))
     {
-    case GIMPLE_OACC_KERNELS:
-    case GIMPLE_OACC_PARALLEL:
-      scan_oacc_offload (stmt, ctx);
-      break;
-
     case GIMPLE_OMP_PARALLEL:
       taskreg_nesting_level++;
       scan_omp_parallel (gsi, ctx);
@@ -3253,6 +3209,8 @@ scan_omp_1_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
       scan_omp (gimple_omp_body_ptr (stmt), ctx);
       break;
 
+    case GIMPLE_OACC_KERNELS:
+    case GIMPLE_OACC_PARALLEL:
     case GIMPLE_OMP_TARGET:
       scan_omp_target (stmt, ctx);
       break;
@@ -5384,411 +5342,6 @@ expand_omp_build_assign (gimple_stmt_iterator *gsi_p, tree to, tree from)
     }
 }
 
-/* Expand the OpenACC offload directive starting at REGION.  */
-
-static void
-expand_oacc_offload (struct omp_region *region)
-{
-  basic_block entry_bb, exit_bb, new_bb;
-  struct function *child_cfun;
-  tree child_fn, block, t;
-  gimple_stmt_iterator gsi;
-  gimple entry_stmt, stmt;
-  edge e;
-  tree (*gimple_omp_child_fn) (const_gimple);
-  tree (*gimple_omp_data_arg) (const_gimple);
-  switch (region->type)
-    {
-    case GIMPLE_OACC_KERNELS:
-      gimple_omp_child_fn = gimple_oacc_kernels_child_fn;
-      gimple_omp_data_arg = gimple_oacc_kernels_data_arg;
-      break;
-    case GIMPLE_OACC_PARALLEL:
-      gimple_omp_child_fn = gimple_oacc_parallel_child_fn;
-      gimple_omp_data_arg = gimple_oacc_parallel_data_arg;
-      break;
-    default:
-      gcc_unreachable ();
-    }
-
-  entry_stmt = last_stmt (region->entry);
-  child_fn = gimple_omp_child_fn (entry_stmt);
-  child_cfun = DECL_STRUCT_FUNCTION (child_fn);
-
-  /* Supported by expand_omp_taskreg, but not here.  */
-  gcc_assert (!child_cfun->cfg);
-  gcc_assert (!gimple_in_ssa_p (cfun));
-
-  entry_bb = region->entry;
-  exit_bb = region->exit;
-
-  /* Preserve indentation of expand_omp_target and expand_omp_taskreg.  */
-  if (1)
-    {
-      unsigned srcidx, dstidx, num;
-
-      /* If the parallel region needs data sent from the parent
-	 function, then the very first statement (except possible
-	 tree profile counter updates) of the parallel body
-	 is a copy assignment .OMP_DATA_I = &.OMP_DATA_O.  Since
-	 &.OMP_DATA_O is passed as an argument to the child function,
-	 we need to replace it with the argument as seen by the child
-	 function.
-
-	 In most cases, this will end up being the identity assignment
-	 .OMP_DATA_I = .OMP_DATA_I.  However, if the parallel body had
-	 a function call that has been inlined, the original PARM_DECL
-	 .OMP_DATA_I may have been converted into a different local
-	 variable.  In which case, we need to keep the assignment.  */
-      if (gimple_omp_data_arg (entry_stmt))
-	{
-	  basic_block entry_succ_bb = single_succ (entry_bb);
-	  gimple_stmt_iterator gsi;
-	  tree arg;
-	  gimple parcopy_stmt = NULL;
-	  tree sender = TREE_VEC_ELT (gimple_omp_data_arg (entry_stmt), 0);
-
-	  for (gsi = gsi_start_bb (entry_succ_bb); ; gsi_next (&gsi))
-	    {
-	      gcc_assert (!gsi_end_p (gsi));
-	      stmt = gsi_stmt (gsi);
-	      if (gimple_code (stmt) != GIMPLE_ASSIGN)
-		continue;
-
-	      if (gimple_num_ops (stmt) == 2)
-		{
-		  tree arg = gimple_assign_rhs1 (stmt);
-
-		  /* We're ignore the subcode because we're
-		     effectively doing a STRIP_NOPS.  */
-
-		  if (TREE_CODE (arg) == ADDR_EXPR
-		      && TREE_OPERAND (arg, 0) == sender)
-		    {
-		      parcopy_stmt = stmt;
-		      break;
-		    }
-		}
-	    }
-
-	  gcc_assert (parcopy_stmt != NULL);
-	  arg = DECL_ARGUMENTS (child_fn);
-
-	  gcc_assert (gimple_assign_lhs (parcopy_stmt) == arg);
-	  gsi_remove (&gsi, true);
-	}
-
-      /* Declare local variables needed in CHILD_CFUN.  */
-      block = DECL_INITIAL (child_fn);
-      BLOCK_VARS (block) = vec2chain (child_cfun->local_decls);
-      /* The gimplifier could record temporaries in the block
-	 rather than in containing function's local_decls chain,
-	 which would mean cgraph missed finalizing them.  Do it now.  */
-      for (t = BLOCK_VARS (block); t; t = DECL_CHAIN (t))
-	if (TREE_CODE (t) == VAR_DECL
-	    && TREE_STATIC (t)
-	    && !DECL_EXTERNAL (t))
-	  varpool_node::finalize_decl (t);
-      DECL_SAVED_TREE (child_fn) = NULL;
-      /* We'll create a CFG for child_fn, so no gimple body is needed.  */
-      gimple_set_body (child_fn, NULL);
-      TREE_USED (block) = 1;
-
-      /* Reset DECL_CONTEXT on function arguments.  */
-      for (t = DECL_ARGUMENTS (child_fn); t; t = DECL_CHAIN (t))
-	DECL_CONTEXT (t) = child_fn;
-
-      /* Split ENTRY_BB at GIMPLE_OACC_PARALLEL,
-	 so that it can be moved to the child function.  */
-      gsi = gsi_last_bb (entry_bb);
-      stmt = gsi_stmt (gsi);
-      gcc_assert (stmt && (gimple_code (stmt) == GIMPLE_OACC_KERNELS
-			   || gimple_code (stmt) == GIMPLE_OACC_PARALLEL));
-      gsi_remove (&gsi, true);
-      e = split_block (entry_bb, stmt);
-      entry_bb = e->dest;
-      single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
-
-      /* Convert GIMPLE_OMP_RETURN into a RETURN_EXPR.  */
-      if (exit_bb)
-	{
-	  gsi = gsi_last_bb (exit_bb);
-	  gcc_assert (!gsi_end_p (gsi)
-		      && gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
-	  stmt = gimple_build_return (NULL);
-	  gsi_insert_after (&gsi, stmt, GSI_SAME_STMT);
-	  gsi_remove (&gsi, true);
-	}
-
-      /* Move the region into CHILD_CFUN.  */
-
-      block = gimple_block (entry_stmt);
-
-      new_bb = move_sese_region_to_fn (child_cfun, entry_bb, exit_bb, block);
-      if (exit_bb)
-	single_succ_edge (new_bb)->flags = EDGE_FALLTHRU;
-      /* When the expansion process cannot guarantee an up-to-date
-         loop tree arrange for the child function to fixup loops.  */
-      if (loops_state_satisfies_p (LOOPS_NEED_FIXUP))
-	child_cfun->x_current_loops->state |= LOOPS_NEED_FIXUP;
-
-      /* Remove non-local VAR_DECLs from child_cfun->local_decls list.  */
-      num = vec_safe_length (child_cfun->local_decls);
-      for (srcidx = 0, dstidx = 0; srcidx < num; srcidx++)
-	{
-	  t = (*child_cfun->local_decls)[srcidx];
-	  if (DECL_CONTEXT (t) == cfun->decl)
-	    continue;
-	  if (srcidx != dstidx)
-	    (*child_cfun->local_decls)[dstidx] = t;
-	  dstidx++;
-	}
-      if (dstidx != num)
-	vec_safe_truncate (child_cfun->local_decls, dstidx);
-
-      /* Inform the callgraph about the new function.  */
-      DECL_STRUCT_FUNCTION (child_fn)->curr_properties = cfun->curr_properties;
-      cgraph_node::add_new_function (child_fn, true);
-
-      /* Add the new function to the offload table.  */
-      vec_safe_push (offload_funcs, child_fn);
-
-      /* Fix the callgraph edges for child_cfun.  Those for cfun will be
-	 fixed in a following pass.  */
-      push_cfun (child_cfun);
-      cgraph_edge::rebuild_edges ();
-
-      /* Some EH regions might become dead, see PR34608.  If
-	 pass_cleanup_cfg isn't the first pass to happen with the
-	 new child, these dead EH edges might cause problems.
-	 Clean them up now.  */
-      if (flag_exceptions)
-	{
-	  basic_block bb;
-	  bool changed = false;
-
-	  FOR_EACH_BB_FN (bb, cfun)
-	    changed |= gimple_purge_dead_eh_edges (bb);
-	  if (changed)
-	    cleanup_tree_cfg ();
-	}
-      pop_cfun ();
-    }
-
-  /* Emit a library call to launch CHILD_FN.  */
-  tree t1, t2, t3, t4,
-    t_num_gangs, t_num_workers, t_vector_length, t_async,
-    device, cond, c, clauses;
-  enum built_in_function start_ix;
-  location_t clause_loc;
-  tree (*gimple_omp_clauses) (const_gimple);
-  switch (region->type)
-    {
-    case GIMPLE_OACC_KERNELS:
-      gimple_omp_clauses = gimple_oacc_kernels_clauses;
-      start_ix = BUILT_IN_GOACC_KERNELS;
-      break;
-    case GIMPLE_OACC_PARALLEL:
-      gimple_omp_clauses = gimple_oacc_parallel_clauses;
-      start_ix = BUILT_IN_GOACC_PARALLEL;
-      break;
-    default:
-      gcc_unreachable ();
-    }
-
-  clauses = gimple_omp_clauses (entry_stmt);
-
-  /* Default values for NUM_GANGS, NUM_WORKERS, and VECTOR_LENGTH.  */
-  t_num_gangs = t_num_workers = t_vector_length
-    = fold_convert_loc (gimple_location (entry_stmt),
-			integer_type_node, integer_one_node);
-  /* TODO: XXX FIX -2.  */
-  t_async = fold_convert_loc (gimple_location (entry_stmt),
-			integer_type_node, build_int_cst (integer_type_node, -2));
-  switch (region->type)
-    {
-    case GIMPLE_OACC_PARALLEL:
-      /* ..., but if present, use the values specified by the respective
-	 clauses, making sure these are of the correct type.  */
-      c = find_omp_clause (clauses, OMP_CLAUSE_NUM_GANGS);
-      if (c)
-	t_num_gangs = fold_convert_loc (OMP_CLAUSE_LOCATION (c),
-					integer_type_node,
-					OMP_CLAUSE_NUM_GANGS_EXPR (c));
-      c = find_omp_clause (clauses, OMP_CLAUSE_NUM_WORKERS);
-      if (c)
-	t_num_workers = fold_convert_loc (OMP_CLAUSE_LOCATION (c),
-					  integer_type_node,
-					  OMP_CLAUSE_NUM_WORKERS_EXPR (c));
-      c = find_omp_clause (clauses, OMP_CLAUSE_VECTOR_LENGTH);
-      if (c)
-	t_vector_length = fold_convert_loc (OMP_CLAUSE_LOCATION (c),
-					    integer_type_node,
-					    OMP_CLAUSE_VECTOR_LENGTH_EXPR (c));
-      /* FALL THROUGH.  */
-    case GIMPLE_OACC_KERNELS:
-      c = find_omp_clause (clauses, OMP_CLAUSE_ASYNC);
-      if (c)
-	t_async = fold_convert_loc (OMP_CLAUSE_LOCATION (c),
-					    integer_type_node,
-					    OMP_CLAUSE_ASYNC_EXPR (c));
-      break;
-
-    default:
-      break;
-    }
-
-  /* By default, the value of DEVICE is -1 (let runtime library choose)
-     and there is no conditional.  */
-  cond = NULL_TREE;
-  device = build_int_cst (integer_type_node, -1);
-
-  c = find_omp_clause (clauses, OMP_CLAUSE_IF);
-  if (c)
-    cond = OMP_CLAUSE_IF_EXPR (c);
-
-  c = find_omp_clause (clauses, OMP_CLAUSE_DEVICE);
-  gcc_assert (c == NULL);
-  if (c)
-    {
-      device = OMP_CLAUSE_DEVICE_ID (c);
-      clause_loc = OMP_CLAUSE_LOCATION (c);
-    }
-  else
-    clause_loc = gimple_location (entry_stmt);
-
-  /* Ensure 'device' is of the correct type.  */
-  device = fold_convert_loc (clause_loc, integer_type_node, device);
-
-  /* If we found the clause 'if (cond)', build
-     (cond ? device : -2).  */
-  if (cond)
-    {
-      cond = gimple_boolify (cond);
-
-      basic_block cond_bb, then_bb, else_bb;
-      edge e;
-      tree tmp_var;
-
-      tmp_var = create_tmp_var (TREE_TYPE (device), NULL);
-      /* Preserve indentation of expand_omp_target.  */
-      if (0)
-	{
-	  gsi = gsi_last_bb (new_bb);
-	  gsi_prev (&gsi);
-	  e = split_block (new_bb, gsi_stmt (gsi));
-	}
-      else
-	e = split_block (new_bb, NULL);
-      cond_bb = e->src;
-      new_bb = e->dest;
-      remove_edge (e);
-
-      then_bb = create_empty_bb (cond_bb);
-      else_bb = create_empty_bb (then_bb);
-      set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);
-      set_immediate_dominator (CDI_DOMINATORS, else_bb, cond_bb);
-
-      stmt = gimple_build_cond_empty (cond);
-      gsi = gsi_last_bb (cond_bb);
-      gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
-
-      gsi = gsi_start_bb (then_bb);
-      stmt = gimple_build_assign (tmp_var, device);
-      gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
-
-      gsi = gsi_start_bb (else_bb);
-      stmt = gimple_build_assign (tmp_var,
-				  build_int_cst (integer_type_node, -2));
-      gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
-
-      make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE);
-      make_edge (cond_bb, else_bb, EDGE_FALSE_VALUE);
-      add_bb_to_loop (then_bb, cond_bb->loop_father);
-      add_bb_to_loop (else_bb, cond_bb->loop_father);
-      make_edge (then_bb, new_bb, EDGE_FALLTHRU);
-      make_edge (else_bb, new_bb, EDGE_FALLTHRU);
-
-      device = tmp_var;
-    }
-
-  gsi = gsi_last_bb (new_bb);
-  t = gimple_omp_data_arg (entry_stmt);
-  if (t == NULL)
-    {
-      t1 = size_zero_node;
-      t2 = build_zero_cst (ptr_type_node);
-      t3 = t2;
-      t4 = t2;
-    }
-  else
-    {
-      t1 = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (TREE_VEC_ELT (t, 1))));
-      t1 = size_binop (PLUS_EXPR, t1, size_int (1));
-      t2 = build_fold_addr_expr (TREE_VEC_ELT (t, 0));
-      t3 = build_fold_addr_expr (TREE_VEC_ELT (t, 1));
-      t4 = build_fold_addr_expr (TREE_VEC_ELT (t, 2));
-    }
-
-  gimple g;
-  tree openmp_target = get_offload_symbol_decl ();
-  tree fnaddr = build_fold_addr_expr (child_fn);
-
-  vec<tree> *args;
-  int idx;
-  unsigned int argcnt = 12;
-
-  c = find_omp_clause (clauses, OMP_CLAUSE_WAIT);
-  if (c)
-    {
-      for (t = c; t; t = OMP_CLAUSE_CHAIN (t))
-	{
-	  if (OMP_CLAUSE_CODE (t) == OMP_CLAUSE_WAIT)
-	    argcnt++;
-	}
-    }
-
-  vec_alloc (args, argcnt);
-  args->quick_push (device);
-  args->quick_push (fnaddr);
-  args->quick_push (build_fold_addr_expr (openmp_target));
-  args->quick_push (t1);
-  args->quick_push (t2);
-  args->quick_push (t3);
-  args->quick_push (t4);
-  args->quick_push (t_num_gangs);
-  args->quick_push (t_num_workers);
-  args->quick_push (t_vector_length);
-  args->quick_push (t_async);
-  idx = args->length ();
-  args->quick_push (fold_convert_loc (gimple_location (entry_stmt),
-			integer_type_node, integer_minus_one_node));
-  if (c)
-    {
-      int n = 0;
-
-      for (t = c; t; t = OMP_CLAUSE_CHAIN (t))
-	{
-	  if (OMP_CLAUSE_CODE (t) == OMP_CLAUSE_WAIT)
-	    {
-	      args->quick_push (fold_convert (integer_type_node,
-				OMP_CLAUSE_WAIT_EXPR (t)));
-	      n++;
-	    }
-	}
-
-        args->ordered_remove (idx);
-	args->quick_insert (idx, fold_convert_loc (gimple_location (entry_stmt),
-				 integer_type_node,
-				 build_int_cst (integer_type_node, n)));
-    }
-
-  g = gimple_build_call_vec (builtin_decl_explicit (start_ix), *args);
-  args->release ();
-  gimple_set_location (g, gimple_location (entry_stmt));
-  gsi_insert_before (&gsi, g, GSI_SAME_STMT);
-}
-
 /* Expand the OpenMP parallel or task directive starting at REGION.  */
 
 static void
@@ -9225,49 +8778,93 @@ static void
 expand_omp_target (struct omp_region *region)
 {
   basic_block entry_bb, exit_bb, new_bb;
-  struct function *child_cfun = NULL;
-  tree child_fn = NULL_TREE, block, t;
+  struct function *child_cfun;
+  tree child_fn, block, t;
   gimple_stmt_iterator gsi;
   gimple entry_stmt, stmt;
   edge e;
+  bool offloaded, data_region;
+  tree (*gimple_omp_child_fn) (const_gimple);
+  tree (*gimple_omp_data_arg) (const_gimple);
 
   entry_stmt = last_stmt (region->entry);
   new_bb = region->entry;
-  int kind = gimple_omp_target_kind (entry_stmt);
-  if (kind == GF_OMP_TARGET_KIND_REGION)
+
+  offloaded = is_gimple_omp_offloaded (entry_stmt);
+  data_region = false;
+  switch (region->type)
     {
-      child_fn = gimple_omp_target_child_fn (entry_stmt);
+    case GIMPLE_OACC_KERNELS:
+      gimple_omp_child_fn = gimple_oacc_kernels_child_fn;
+      gimple_omp_data_arg = gimple_oacc_kernels_data_arg;
+      break;
+    case GIMPLE_OACC_PARALLEL:
+      gimple_omp_child_fn = gimple_oacc_parallel_child_fn;
+      gimple_omp_data_arg = gimple_oacc_parallel_data_arg;
+      break;
+    case GIMPLE_OMP_TARGET:
+      switch (gimple_omp_target_kind (entry_stmt))
+	{
+	case GF_OMP_TARGET_KIND_DATA:
+	case GF_OMP_TARGET_KIND_OACC_DATA:
+	  data_region = true;
+	  break;
+	case GF_OMP_TARGET_KIND_REGION:
+	case GF_OMP_TARGET_KIND_UPDATE:
+	case GF_OMP_TARGET_KIND_OACC_UPDATE:
+	case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA:
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+
+      gimple_omp_child_fn = gimple_omp_target_child_fn;
+      gimple_omp_data_arg = gimple_omp_target_data_arg;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  child_fn = NULL_TREE;
+  child_cfun = NULL;
+  if (offloaded)
+    {
+      child_fn = gimple_omp_child_fn (entry_stmt);
       child_cfun = DECL_STRUCT_FUNCTION (child_fn);
     }
 
+  /* Supported by expand_omp_taskreg, but not here.  */
+  if (child_cfun != NULL)
+    gcc_assert (!child_cfun->cfg);
+  gcc_assert (!gimple_in_ssa_p (cfun));
+
   entry_bb = region->entry;
   exit_bb = region->exit;
 
-  if (kind == GF_OMP_TARGET_KIND_REGION)
+  if (offloaded)
     {
       unsigned srcidx, dstidx, num;
 
-      /* If the target region needs data sent from the parent
+      /* If the offloading region needs data sent from the parent
 	 function, then the very first statement (except possible
-	 tree profile counter updates) of the parallel body
+	 tree profile counter updates) of the offloading body
 	 is a copy assignment .OMP_DATA_I = &.OMP_DATA_O.  Since
 	 &.OMP_DATA_O is passed as an argument to the child function,
 	 we need to replace it with the argument as seen by the child
 	 function.
 
 	 In most cases, this will end up being the identity assignment
-	 .OMP_DATA_I = .OMP_DATA_I.  However, if the parallel body had
+	 .OMP_DATA_I = .OMP_DATA_I.  However, if the offloading body had
 	 a function call that has been inlined, the original PARM_DECL
 	 .OMP_DATA_I may have been converted into a different local
 	 variable.  In which case, we need to keep the assignment.  */
-      if (gimple_omp_target_data_arg (entry_stmt))
+      if (gimple_omp_data_arg (entry_stmt))
 	{
 	  basic_block entry_succ_bb = single_succ (entry_bb);
 	  gimple_stmt_iterator gsi;
 	  tree arg;
 	  gimple tgtcopy_stmt = NULL;
-	  tree sender
-	    = TREE_VEC_ELT (gimple_omp_target_data_arg (entry_stmt), 0);
+	  tree sender = TREE_VEC_ELT (gimple_omp_data_arg (entry_stmt), 0);
 
 	  for (gsi = gsi_start_bb (entry_succ_bb); ; gsi_next (&gsi))
 	    {
@@ -9302,7 +8899,7 @@ expand_omp_target (struct omp_region *region)
       /* Declare local variables needed in CHILD_CFUN.  */
       block = DECL_INITIAL (child_fn);
       BLOCK_VARS (block) = vec2chain (child_cfun->local_decls);
-      /* The gimplifier could record temporaries in target block
+      /* The gimplifier could record temporaries in the offloading block
 	 rather than in containing function's local_decls chain,
 	 which would mean cgraph missed finalizing them.  Do it now.  */
       for (t = BLOCK_VARS (block); t; t = DECL_CHAIN (t))
@@ -9319,13 +8916,12 @@ expand_omp_target (struct omp_region *region)
       for (t = DECL_ARGUMENTS (child_fn); t; t = DECL_CHAIN (t))
 	DECL_CONTEXT (t) = child_fn;
 
-      /* Split ENTRY_BB at GIMPLE_OMP_TARGET,
+      /* Split ENTRY_BB at GIMPLE_*,
 	 so that it can be moved to the child function.  */
       gsi = gsi_last_bb (entry_bb);
       stmt = gsi_stmt (gsi);
-      gcc_assert (stmt && gimple_code (stmt) == GIMPLE_OMP_TARGET
-		  && gimple_omp_target_kind (stmt)
-		     == GF_OMP_TARGET_KIND_REGION);
+      gcc_assert (stmt &&
+		  gimple_code (stmt) == gimple_code (entry_stmt));
       gsi_remove (&gsi, true);
       e = split_block (entry_bb, stmt);
       entry_bb = e->dest;
@@ -9342,7 +8938,7 @@ expand_omp_target (struct omp_region *region)
 	  gsi_remove (&gsi, true);
 	}
 
-      /* Move the target region into CHILD_CFUN.  */
+      /* Move the offloading region into CHILD_CFUN.  */
 
       block = gimple_block (entry_stmt);
 
@@ -9397,38 +8993,55 @@ expand_omp_target (struct omp_region *region)
       pop_cfun ();
     }
 
-  /* Emit a library call to launch the target region, or do data
+  /* Emit a library call to launch the offloading region, or do data
      transfers.  */
   tree t1, t2, t3, t4, device, cond, c, clauses;
   enum built_in_function start_ix;
   location_t clause_loc;
+  tree (*gimple_omp_clauses) (const_gimple);
 
-  clauses = gimple_omp_target_clauses (entry_stmt);
-
-  switch (kind)
+  switch (region->type)
     {
-    case GF_OMP_TARGET_KIND_REGION:
-      start_ix = BUILT_IN_GOMP_TARGET;
+    case GIMPLE_OACC_KERNELS:
+      gimple_omp_clauses = gimple_oacc_kernels_clauses;
+      start_ix = BUILT_IN_GOACC_KERNELS;
       break;
-    case GF_OMP_TARGET_KIND_DATA:
-      start_ix = BUILT_IN_GOMP_TARGET_DATA;
+    case GIMPLE_OACC_PARALLEL:
+      gimple_omp_clauses = gimple_oacc_parallel_clauses;
+      start_ix = BUILT_IN_GOACC_PARALLEL;
       break;
-    case GF_OMP_TARGET_KIND_UPDATE:
-      start_ix = BUILT_IN_GOMP_TARGET_UPDATE;
-      break;
-    case GF_OMP_TARGET_KIND_OACC_DATA:
-      start_ix = BUILT_IN_GOACC_DATA_START;
-      break;
-    case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA:
-      start_ix = BUILT_IN_GOACC_ENTER_EXIT_DATA;
-      break;
-    case GF_OMP_TARGET_KIND_OACC_UPDATE:
-      start_ix = BUILT_IN_GOACC_UPDATE;
+    case GIMPLE_OMP_TARGET:
+      gimple_omp_clauses = gimple_omp_target_clauses;
+      switch (gimple_omp_target_kind (entry_stmt))
+	{
+	case GF_OMP_TARGET_KIND_REGION:
+	  start_ix = BUILT_IN_GOMP_TARGET;
+	  break;
+	case GF_OMP_TARGET_KIND_DATA:
+	  start_ix = BUILT_IN_GOMP_TARGET_DATA;
+	  break;
+	case GF_OMP_TARGET_KIND_UPDATE:
+	  start_ix = BUILT_IN_GOMP_TARGET_UPDATE;
+	  break;
+	case GF_OMP_TARGET_KIND_OACC_DATA:
+	  start_ix = BUILT_IN_GOACC_DATA_START;
+	  break;
+	case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA:
+	  start_ix = BUILT_IN_GOACC_ENTER_EXIT_DATA;
+	  break;
+	case GF_OMP_TARGET_KIND_OACC_UPDATE:
+	  start_ix = BUILT_IN_GOACC_UPDATE;
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
       break;
     default:
       gcc_unreachable ();
     }
 
+  clauses = gimple_omp_clauses (entry_stmt);
+
   /* By default, the value of DEVICE is -1 (let runtime library choose)
      and there is no conditional.  */
   cond = NULL_TREE;
@@ -9441,8 +9054,11 @@ expand_omp_target (struct omp_region *region)
   c = find_omp_clause (clauses, OMP_CLAUSE_DEVICE);
   if (c)
     {
-      gcc_assert (kind != GF_OMP_TARGET_KIND_OACC_DATA
-		  && kind != GF_OMP_TARGET_KIND_OACC_UPDATE);
+      /* Even if we pass it to all library function calls, it is currently only
+	 defined/used for the OpenMP target ones.  */
+      gcc_assert (start_ix == BUILT_IN_GOMP_TARGET
+		  || start_ix == BUILT_IN_GOMP_TARGET_DATA
+		  || start_ix == BUILT_IN_GOMP_TARGET_UPDATE);
 
       device = OMP_CLAUSE_DEVICE_ID (c);
       clause_loc = OMP_CLAUSE_LOCATION (c);
@@ -9464,14 +9080,16 @@ expand_omp_target (struct omp_region *region)
       tree tmp_var;
 
       tmp_var = create_tmp_var (TREE_TYPE (device), NULL);
-      if (kind != GF_OMP_TARGET_KIND_REGION)
+      if (offloaded)
+	{
+	  e = split_block (new_bb, NULL);
+	}
+      else
 	{
 	  gsi = gsi_last_bb (new_bb);
 	  gsi_prev (&gsi);
 	  e = split_block (new_bb, gsi_stmt (gsi));
 	}
-      else
-	e = split_block (new_bb, NULL);
       cond_bb = e->src;
       new_bb = e->dest;
       remove_edge (e);
@@ -9505,7 +9123,7 @@ expand_omp_target (struct omp_region *region)
     }
 
   gsi = gsi_last_bb (new_bb);
-  t = gimple_omp_target_data_arg (entry_stmt);
+  t = gimple_omp_data_arg (entry_stmt);
   if (t == NULL)
     {
       t1 = size_zero_node;
@@ -9525,90 +9143,122 @@ expand_omp_target (struct omp_region *region)
   gimple g;
   tree openmp_target = get_offload_symbol_decl ();
   vec<tree> *args;
-  unsigned int argcnt = 6;
-
-  if (kind ==  GF_OMP_TARGET_KIND_REGION)
-    argcnt++;
-  else if (kind == GF_OMP_TARGET_KIND_OACC_DATA
-      || kind == GF_OMP_TARGET_KIND_OACC_UPDATE)
-    argcnt += 2;
-
-  c = find_omp_clause (clauses, OMP_CLAUSE_WAIT);
-  if (c)
-    {
-      for (t = c; t; t = OMP_CLAUSE_CHAIN (t))
-	{
-	  if (OMP_CLAUSE_CODE (t) == OMP_CLAUSE_WAIT)
-	    argcnt++;
-	}
-    }
+  /* The maximum number used by any start_ix, without varargs.  */
+  unsigned int argcnt = 12;
 
   vec_alloc (args, argcnt);
   args->quick_push (device);
-
-  if (kind ==  GF_OMP_TARGET_KIND_REGION)
+  if (offloaded)
     args->quick_push (build_fold_addr_expr (child_fn));
-
   args->quick_push (build_fold_addr_expr (openmp_target));
   args->quick_push (t1);
   args->quick_push (t2);
   args->quick_push (t3);
   args->quick_push (t4);
-
-  if (kind == GF_OMP_TARGET_KIND_OACC_DATA
-      || kind == GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA
-      || kind == GF_OMP_TARGET_KIND_OACC_UPDATE)
+  switch (start_ix)
     {
-      int idx;
+    case BUILT_IN_GOACC_DATA_START:
+    case BUILT_IN_GOMP_TARGET:
+    case BUILT_IN_GOMP_TARGET_DATA:
+    case BUILT_IN_GOMP_TARGET_UPDATE:
+      break;
+    case BUILT_IN_GOACC_KERNELS:
+    case BUILT_IN_GOACC_PARALLEL:
+      {
+	tree t_num_gangs, t_num_workers, t_vector_length;
 
-      c = find_omp_clause (clauses, OMP_CLAUSE_ASYNC);
-      if (c)
-	t1 = fold_convert_loc (OMP_CLAUSE_LOCATION (c), integer_type_node,
-				OMP_CLAUSE_ASYNC_EXPR (c));
-      else /* TODO: XXX FIX -2.  */
-	t1 = fold_convert_loc (gimple_location (entry_stmt),
-		      integer_type_node, build_int_cst (integer_type_node, -2));
+	/* Default values for num_gangs, num_workers, and vector_length.  */
+	t_num_gangs = t_num_workers = t_vector_length
+	  = fold_convert_loc (gimple_location (entry_stmt),
+			      integer_type_node, integer_one_node);
+	/* ..., but if present, use the value specified by the respective
+	   clause, making sure that are of the correct type.  */
+	c = find_omp_clause (clauses, OMP_CLAUSE_NUM_GANGS);
+	if (c)
+	  t_num_gangs = fold_convert_loc (OMP_CLAUSE_LOCATION (c),
+					  integer_type_node,
+					  OMP_CLAUSE_NUM_GANGS_EXPR (c));
+	c = find_omp_clause (clauses, OMP_CLAUSE_NUM_WORKERS);
+	if (c)
+	  t_num_workers = fold_convert_loc (OMP_CLAUSE_LOCATION (c),
+					    integer_type_node,
+					    OMP_CLAUSE_NUM_WORKERS_EXPR (c));
+	c = find_omp_clause (clauses, OMP_CLAUSE_VECTOR_LENGTH);
+	if (c)
+	  t_vector_length = fold_convert_loc (OMP_CLAUSE_LOCATION (c),
+					      integer_type_node,
+					      OMP_CLAUSE_VECTOR_LENGTH_EXPR (c));
+	args->quick_push (t_num_gangs);
+	args->quick_push (t_num_workers);
+	args->quick_push (t_vector_length);
+      }
+      /* FALLTHRU */
+    case BUILT_IN_GOACC_ENTER_EXIT_DATA:
+    case BUILT_IN_GOACC_UPDATE:
+      {
+	tree t_async;
+	int t_wait_idx;
 
-      args->safe_push (t1);
-      idx = args->length ();
-      args->safe_push (fold_convert_loc (gimple_location (entry_stmt),
-			integer_type_node, integer_minus_one_node));
+	/* Default values for t_async.  */
+	/* TODO: XXX FIX -2.  */
+	t_async = fold_convert_loc (gimple_location (entry_stmt),
+				    integer_type_node,
+				    build_int_cst (integer_type_node, -2));
+	/* ..., but if present, use the value specified by the respective
+	   clause, making sure that is of the correct type.  */
+	c = find_omp_clause (clauses, OMP_CLAUSE_ASYNC);
+	if (c)
+	  t_async = fold_convert_loc (OMP_CLAUSE_LOCATION (c),
+				      integer_type_node,
+				      OMP_CLAUSE_ASYNC_EXPR (c));
 
-      c = find_omp_clause (clauses, OMP_CLAUSE_WAIT);
-      if (c)
-	{
-	  int n = 0;
+	args->quick_push (t_async);
+	/* Save the index, and... */
+	t_wait_idx = args->length ();
+	/* ... push a default value.  */
+	args->quick_push (fold_convert_loc (gimple_location (entry_stmt),
+					    integer_type_node,
+					    integer_zero_node));
+	c = find_omp_clause (clauses, OMP_CLAUSE_WAIT);
+	if (c)
+	  {
+	    int n = 0;
 
-	  for (t = c; t; t = OMP_CLAUSE_CHAIN (t))
-	    {
-	      if (OMP_CLAUSE_CODE (t) == OMP_CLAUSE_WAIT)
-		{
-		  args->safe_push (fold_convert (integer_type_node,
-				OMP_CLAUSE_WAIT_EXPR (t)));
-		  n++;
-		}
-	    }
+	    for (; c; c = OMP_CLAUSE_CHAIN (c))
+	      {
+		if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_WAIT)
+		  {
+		    args->safe_push (fold_convert_loc (OMP_CLAUSE_LOCATION (c),
+						       integer_type_node,
+						       OMP_CLAUSE_WAIT_EXPR (c)));
+		    n++;
+		  }
+	      }
 
-	    args->ordered_remove (idx);
-	    args->quick_insert (idx,
+	    /* Now that we know the number, replace the default value.  */
+	    args->ordered_remove (t_wait_idx);
+	    args->quick_insert (t_wait_idx,
 				fold_convert_loc (gimple_location (entry_stmt),
-				integer_type_node,
-				build_int_cst (integer_type_node, n)));
-	}
+						  integer_type_node,
+						  build_int_cst (integer_type_node, n)));
+	  }
+      }
+      break;
+    default:
+      gcc_unreachable ();
     }
 
   g = gimple_build_call_vec (builtin_decl_explicit (start_ix), *args);
   args->release ();
   gimple_set_location (g, gimple_location (entry_stmt));
   gsi_insert_before (&gsi, g, GSI_SAME_STMT);
-  if (kind != GF_OMP_TARGET_KIND_REGION)
+  if (!offloaded)
     {
       g = gsi_stmt (gsi);
       gcc_assert (g && gimple_code (g) == GIMPLE_OMP_TARGET);
       gsi_remove (&gsi, true);
     }
-  if ((kind == GF_OMP_TARGET_KIND_DATA
-       || kind == GF_OMP_TARGET_KIND_OACC_DATA)
+  if (data_region
       && region->exit)
     {
       gsi = gsi_last_bb (region->exit);
@@ -9651,11 +9301,6 @@ expand_omp (struct omp_region *region)
 
       switch (region->type)
 	{
-	case GIMPLE_OACC_KERNELS:
-	case GIMPLE_OACC_PARALLEL:
-	  expand_oacc_offload (region);
-	  break;
-
 	case GIMPLE_OMP_PARALLEL:
 	case GIMPLE_OMP_TASK:
 	  expand_omp_taskreg (region);
@@ -9690,6 +9335,8 @@ expand_omp (struct omp_region *region)
 	  expand_omp_atomic (region);
 	  break;
 
+	case GIMPLE_OACC_KERNELS:
+	case GIMPLE_OACC_PARALLEL:
 	case GIMPLE_OMP_TARGET:
 	  expand_omp_target (region);
 	  break;
@@ -10294,324 +9941,6 @@ process_reduction_data (gimple_seq *body, gimple_seq *in_stmt_seqp,
 
 /* Routines to lower OpenMP directives into OMP-GIMPLE.  */
 
-/* Lower the OpenACC offload directive in the current statement
-   in GSI_P.  CTX holds context information for the directive.  */
-
-static void
-lower_oacc_offload (gimple_stmt_iterator *gsi_p, omp_context *ctx)
-{
-  tree clauses;
-  tree child_fn, t, c;
-  gimple stmt = gsi_stmt (*gsi_p);
-  gimple par_bind, bind;
-  gimple_seq par_body, olist, ilist, orlist, irlist, new_body;
-  location_t loc = gimple_location (stmt);
-  unsigned int map_cnt = 0;
-  tree (*gimple_omp_clauses) (const_gimple);
-  void (*gimple_omp_set_data_arg) (gimple, tree);
-  switch (gimple_code (stmt))
-    {
-    case GIMPLE_OACC_KERNELS:
-      gimple_omp_clauses = gimple_oacc_kernels_clauses;
-      gimple_omp_set_data_arg = gimple_oacc_kernels_set_data_arg;
-      break;
-    case GIMPLE_OACC_PARALLEL:
-      gimple_omp_clauses = gimple_oacc_parallel_clauses;
-      gimple_omp_set_data_arg = gimple_oacc_parallel_set_data_arg;
-      break;
-    default:
-      gcc_unreachable ();
-    }
-
-  clauses = gimple_omp_clauses (stmt);
-  par_bind = gimple_seq_first_stmt (gimple_omp_body (stmt));
-  par_body = gimple_bind_body (par_bind);
-  child_fn = ctx->cb.dst_fn;
-
-  push_gimplify_context ();
-
-  irlist = NULL;
-  orlist = NULL;
-  process_reduction_data (&par_body, &irlist, &orlist, ctx);
-
-  for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
-    switch (OMP_CLAUSE_CODE (c))
-      {
-	tree var, x;
-
-      default:
-	break;
-      case OMP_CLAUSE_MAP:
-	var = OMP_CLAUSE_DECL (c);
-	if (!DECL_P (var))
-	  {
-	    if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP
-		|| !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c))
-	      map_cnt++;
-	    continue;
-	  }
-
-	if (DECL_SIZE (var)
-	    && TREE_CODE (DECL_SIZE (var)) != INTEGER_CST)
-	  {
-	    tree var2 = DECL_VALUE_EXPR (var);
-	    gcc_assert (TREE_CODE (var2) == INDIRECT_REF);
-	    var2 = TREE_OPERAND (var2, 0);
-	    gcc_assert (DECL_P (var2));
-	    var = var2;
-	  }
-
-	if (!maybe_lookup_field (var, ctx))
-	  continue;
-
-	/* Preserve indentation of lower_omp_target.  */
-	if (1)
-	  {
-	    x = build_receiver_ref (var, true, ctx);
-	    tree new_var = lookup_decl (var, ctx);
-	    gcc_assert (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP
-			|| (OMP_CLAUSE_MAP_KIND (c)
-			    != OMP_CLAUSE_MAP_FORCE_DEVICEPTR)
-			|| TREE_CODE (TREE_TYPE (var)) != ARRAY_TYPE);
-	    if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
-		&& OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER
-		&& !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c)
-		&& TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE)
-	      x = build_simple_mem_ref (x);
-	    SET_DECL_VALUE_EXPR (new_var, x);
-	    DECL_HAS_VALUE_EXPR_P (new_var) = 1;
-	  }
-	map_cnt++;
-      }
-
-  target_nesting_level++;
-  lower_omp (&par_body, ctx);
-  target_nesting_level--;
-
-  /* Declare all the variables created by mapping and the variables
-     declared in the scope of the body.  */
-  record_vars_into (ctx->block_vars, child_fn);
-  record_vars_into (gimple_bind_vars (par_bind), child_fn);
-
-  olist = NULL;
-  ilist = NULL;
-  if (ctx->record_type)
-    {
-      ctx->sender_decl
-	= create_tmp_var (ctx->record_type, ".omp_data_arr");
-      DECL_NAMELESS (ctx->sender_decl) = 1;
-      TREE_ADDRESSABLE (ctx->sender_decl) = 1;
-      t = make_tree_vec (3);
-      TREE_VEC_ELT (t, 0) = ctx->sender_decl;
-      TREE_VEC_ELT (t, 1)
-	= create_tmp_var (build_array_type_nelts (size_type_node, map_cnt),
-			  ".omp_data_sizes");
-      DECL_NAMELESS (TREE_VEC_ELT (t, 1)) = 1;
-      TREE_ADDRESSABLE (TREE_VEC_ELT (t, 1)) = 1;
-      TREE_STATIC (TREE_VEC_ELT (t, 1)) = 1;
-      TREE_VEC_ELT (t, 2)
-	= create_tmp_var (build_array_type_nelts (short_unsigned_type_node,
-						  map_cnt),
-			  ".omp_data_kinds");
-      DECL_NAMELESS (TREE_VEC_ELT (t, 2)) = 1;
-      TREE_ADDRESSABLE (TREE_VEC_ELT (t, 2)) = 1;
-      TREE_STATIC (TREE_VEC_ELT (t, 2)) = 1;
-      gimple_omp_set_data_arg (stmt, t);
-
-      vec<constructor_elt, va_gc> *vsize;
-      vec<constructor_elt, va_gc> *vkind;
-      vec_alloc (vsize, map_cnt);
-      vec_alloc (vkind, map_cnt);
-      unsigned int map_idx = 0;
-
-      for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
-	switch (OMP_CLAUSE_CODE (c))
-	  {
-	    tree ovar, nc;
-
-	  default:
-	    break;
-	  case OMP_CLAUSE_MAP:
-	    nc = c;
-	    ovar = OMP_CLAUSE_DECL (c);
-	    if (!DECL_P (ovar))
-	      {
-		if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
-		    && OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c))
-		  {
-		    gcc_checking_assert (OMP_CLAUSE_DECL (OMP_CLAUSE_CHAIN (c))
-					 == get_base_address (ovar));
-		    nc = OMP_CLAUSE_CHAIN (c);
-		    ovar = OMP_CLAUSE_DECL (nc);
-		  }
-		else
-		  {
-		    tree x = build_sender_ref (ovar, ctx);
-		    tree v
-		      = build_fold_addr_expr_with_type (ovar, ptr_type_node);
-		    gimplify_assign (x, v, &ilist);
-		    nc = NULL_TREE;
-		  }
-	      }
-	    else
-	      {
-		if (DECL_SIZE (ovar)
-		    && TREE_CODE (DECL_SIZE (ovar)) != INTEGER_CST)
-		  {
-		    tree ovar2 = DECL_VALUE_EXPR (ovar);
-		    gcc_assert (TREE_CODE (ovar2) == INDIRECT_REF);
-		    ovar2 = TREE_OPERAND (ovar2, 0);
-		    gcc_assert (DECL_P (ovar2));
-		    ovar = ovar2;
-		  }
-		if (!maybe_lookup_field (ovar, ctx))
-		  continue;
-	      }
-
-	    unsigned int talign = TYPE_ALIGN_UNIT (TREE_TYPE (ovar));
-	    if (DECL_P (ovar) && DECL_ALIGN_UNIT (ovar) > talign)
-	      talign = DECL_ALIGN_UNIT (ovar);
-	    if (nc)
-	      {
-		tree var = lookup_decl_in_outer_ctx (ovar, ctx);
-		tree x = build_sender_ref (ovar, ctx);
-		gcc_assert (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP
-			    || (OMP_CLAUSE_MAP_KIND (c)
-				!= OMP_CLAUSE_MAP_FORCE_DEVICEPTR)
-			    || TREE_CODE (TREE_TYPE (ovar)) != ARRAY_TYPE);
-		if (maybe_lookup_reduction (var, ctx))
-		  {
-		    gimplify_assign (x, var, &ilist);
-		  }
-		else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
-			 && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER
-			 && !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c)
-			 && TREE_CODE (TREE_TYPE (ovar)) == ARRAY_TYPE)
-		  {
-		    tree avar
-		      = create_tmp_var (TREE_TYPE (TREE_TYPE (x)), NULL);
-		    mark_addressable (avar);
-		    gimplify_assign (avar, build_fold_addr_expr (var), &ilist);
-		    talign = DECL_ALIGN_UNIT (avar);
-		    avar = build_fold_addr_expr (avar);
-		    gimplify_assign (x, avar, &ilist);
-		  }
-		else if (is_gimple_reg (var))
-		  {
-		    tree avar = create_tmp_var (TREE_TYPE (var), NULL);
-		    mark_addressable (avar);
-		    enum omp_clause_map_kind map_kind
-		      = OMP_CLAUSE_MAP_KIND (c);
-		    if ((!(map_kind & OMP_CLAUSE_MAP_SPECIAL)
-			 && (map_kind & OMP_CLAUSE_MAP_TO))
-			|| map_kind == OMP_CLAUSE_MAP_POINTER
-			|| map_kind == OMP_CLAUSE_MAP_TO_PSET
-			|| map_kind == OMP_CLAUSE_MAP_FORCE_DEVICEPTR)
-		      gimplify_assign (avar, var, &ilist);
-		    avar = build_fold_addr_expr (avar);
-		    gimplify_assign (x, avar, &ilist);
-		    if (((!(map_kind & OMP_CLAUSE_MAP_SPECIAL)
-			  && (map_kind & OMP_CLAUSE_MAP_FROM))
-			 || map_kind == OMP_CLAUSE_MAP_FORCE_DEVICEPTR)
-			&& !TYPE_READONLY (TREE_TYPE (var)))
-		      {
-			x = build_sender_ref (ovar, ctx);
-			x = build_simple_mem_ref (x);
-			gimplify_assign (var, x, &olist);
-		      }
-		  }
-		else
-		  {
-		    var = build_fold_addr_expr (var);
-		    gimplify_assign (x, var, &ilist);
-		  }
-	      }
-	    tree s = OMP_CLAUSE_SIZE (c);
-	    if (s == NULL_TREE)
-	      s = TYPE_SIZE_UNIT (TREE_TYPE (ovar));
-	    s = fold_convert (size_type_node, s);
-	    tree purpose = size_int (map_idx++);
-	    CONSTRUCTOR_APPEND_ELT (vsize, purpose, s);
-	    if (TREE_CODE (s) != INTEGER_CST)
-	      TREE_STATIC (TREE_VEC_ELT (t, 1)) = 0;
-
-	    unsigned short tkind = 0;
-	    switch (OMP_CLAUSE_CODE (c))
-	      {
-	      case OMP_CLAUSE_MAP:
-		tkind = OMP_CLAUSE_MAP_KIND (c);
-		break;
-	      default:
-		gcc_unreachable ();
-	      }
-	    talign = ceil_log2 (talign);
-	    tkind |= talign << 8;
-	    CONSTRUCTOR_APPEND_ELT (vkind, purpose,
-				    build_int_cst (short_unsigned_type_node,
-						   tkind));
-	    if (nc && nc != c)
-	      c = nc;
-	  }
-
-      gcc_assert (map_idx == map_cnt);
-
-      DECL_INITIAL (TREE_VEC_ELT (t, 1))
-	= build_constructor (TREE_TYPE (TREE_VEC_ELT (t, 1)), vsize);
-      DECL_INITIAL (TREE_VEC_ELT (t, 2))
-	= build_constructor (TREE_TYPE (TREE_VEC_ELT (t, 2)), vkind);
-      if (!TREE_STATIC (TREE_VEC_ELT (t, 1)))
-	{
-	  gimple_seq initlist = NULL;
-	  force_gimple_operand (build1 (DECL_EXPR, void_type_node,
-					TREE_VEC_ELT (t, 1)),
-				&initlist, true, NULL_TREE);
-	  gimple_seq_add_seq (&ilist, initlist);
-
-	  tree clobber = build_constructor (TREE_TYPE (TREE_VEC_ELT (t, 1)),
-					    NULL);
-	  TREE_THIS_VOLATILE (clobber) = 1;
-	  gimple_seq_add_stmt (&olist,
-			       gimple_build_assign (TREE_VEC_ELT (t, 1),
-						    clobber));
-	}
-
-      tree clobber = build_constructor (ctx->record_type, NULL);
-      TREE_THIS_VOLATILE (clobber) = 1;
-      gimple_seq_add_stmt (&olist, gimple_build_assign (ctx->sender_decl,
-							clobber));
-    }
-
-  /* Once all the expansions are done, sequence all the different
-     fragments inside gimple_omp_body.  */
-
-  new_body = NULL;
-
-  if (ctx->record_type)
-    {
-      t = build_fold_addr_expr_loc (loc, ctx->sender_decl);
-      /* fixup_child_record_type might have changed receiver_decl's type.  */
-      t = fold_convert_loc (loc, TREE_TYPE (ctx->receiver_decl), t);
-      gimple_seq_add_stmt (&new_body,
-			   gimple_build_assign (ctx->receiver_decl, t));
-    }
-
-  gimple_seq_add_seq (&new_body, par_body);
-  gcc_assert (!ctx->cancellable);
-  new_body = maybe_catch_exception (new_body);
-  gimple_seq_add_stmt (&new_body, gimple_build_omp_return (false));
-  gimple_omp_set_body (stmt, new_body);
-
-  bind = gimple_build_bind (NULL, NULL, gimple_bind_block (par_bind));
-  gsi_replace (gsi_p, bind, true);
-  gimple_bind_add_seq (bind, irlist);
-  gimple_bind_add_seq (bind, ilist);
-  gimple_bind_add_stmt (bind, stmt);
-  gimple_bind_add_seq (bind, olist);
-  gimple_bind_add_seq (bind, orlist);
-
-  pop_gimplify_context (NULL);
-}
-
 /* If ctx is a worksharing context inside of a cancellable parallel
    region and it isn't nowait, add lhs to its GIMPLE_OMP_RETURN
    and conditional branch to parallel's cancel_label to handle
@@ -11814,25 +11143,76 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
   tree clauses;
   tree child_fn, t, c;
   gimple stmt = gsi_stmt (*gsi_p);
-  gimple tgt_bind = NULL, bind;
-  gimple_seq tgt_body = NULL, olist, ilist, new_body;
+  gimple tgt_bind, bind;
+  gimple_seq tgt_body, olist, ilist, orlist, irlist, new_body;
   location_t loc = gimple_location (stmt);
-  int kind = gimple_omp_target_kind (stmt);
+  bool offloaded, data_region;
   unsigned int map_cnt = 0;
+  tree (*gimple_omp_clauses) (const_gimple);
+  void (*gimple_omp_set_data_arg) (gimple, tree);
 
-  clauses = gimple_omp_target_clauses (stmt);
-  if (kind == GF_OMP_TARGET_KIND_REGION)
+  offloaded = is_gimple_omp_offloaded (stmt);
+  data_region = false;
+  switch (gimple_code (stmt))
+    {
+    case GIMPLE_OACC_KERNELS:
+      gimple_omp_clauses = gimple_oacc_kernels_clauses;
+      gimple_omp_set_data_arg = gimple_oacc_kernels_set_data_arg;
+      break;
+    case GIMPLE_OACC_PARALLEL:
+      gimple_omp_clauses = gimple_oacc_parallel_clauses;
+      gimple_omp_set_data_arg = gimple_oacc_parallel_set_data_arg;
+      break;
+    case GIMPLE_OMP_TARGET:
+      switch (gimple_omp_target_kind (stmt))
+	{
+	case GF_OMP_TARGET_KIND_DATA:
+	case GF_OMP_TARGET_KIND_OACC_DATA:
+	  data_region = true;
+	  break;
+	case GF_OMP_TARGET_KIND_REGION:
+	case GF_OMP_TARGET_KIND_UPDATE:
+	case GF_OMP_TARGET_KIND_OACC_UPDATE:
+	case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA:
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+
+      gimple_omp_clauses = gimple_omp_target_clauses;
+      gimple_omp_set_data_arg = gimple_omp_target_set_data_arg;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  clauses = gimple_omp_clauses (stmt);
+
+  tgt_bind = NULL;
+  tgt_body = NULL;
+  if (offloaded)
     {
       tgt_bind = gimple_seq_first_stmt (gimple_omp_body (stmt));
       tgt_body = gimple_bind_body (tgt_bind);
     }
-  else if (kind == GF_OMP_TARGET_KIND_DATA
-	   || kind == GF_OMP_TARGET_KIND_OACC_DATA)
+  else if (data_region)
     tgt_body = gimple_omp_body (stmt);
   child_fn = ctx->cb.dst_fn;
 
   push_gimplify_context ();
 
+  irlist = NULL;
+  orlist = NULL;
+  switch (gimple_code (stmt))
+    {
+    case GIMPLE_OACC_KERNELS:
+    case GIMPLE_OACC_PARALLEL:
+      process_reduction_data (&tgt_body, &irlist, &orlist, ctx);
+      break;
+    default:
+      break;
+    }
+
   for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
     switch (OMP_CLAUSE_CODE (c))
       {
@@ -11859,21 +11239,19 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
 	  case OMP_CLAUSE_MAP_FORCE_PRESENT:
 	  case OMP_CLAUSE_MAP_FORCE_DEALLOC:
 	  case OMP_CLAUSE_MAP_FORCE_DEVICEPTR:
-	    gcc_assert (kind == GF_OMP_TARGET_KIND_OACC_DATA
-			|| kind == GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA
-			|| kind == GF_OMP_TARGET_KIND_OACC_UPDATE);
+	    gcc_assert (is_gimple_omp_oacc_specifically (stmt));
 	    break;
 	  default:
 	    gcc_unreachable ();
 	  }
 #endif
 	  /* FALLTHRU */
-
       case OMP_CLAUSE_TO:
       case OMP_CLAUSE_FROM:
 	if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP)
-	  gcc_assert (kind != GF_OMP_TARGET_KIND_OACC_DATA
-		      && kind != GF_OMP_TARGET_KIND_OACC_UPDATE);
+	  gcc_assert (gimple_code (stmt) == GIMPLE_OMP_TARGET
+		      && (gimple_omp_target_kind (stmt)
+			  == GF_OMP_TARGET_KIND_UPDATE));
 	var = OMP_CLAUSE_DECL (c);
 	if (!DECL_P (var))
 	  {
@@ -11896,16 +11274,15 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
 	if (!maybe_lookup_field (var, ctx))
 	  continue;
 
-	if (kind == GF_OMP_TARGET_KIND_REGION)
+	if (offloaded)
 	  {
 	    x = build_receiver_ref (var, true, ctx);
 	    tree new_var = lookup_decl (var, ctx);
-	    gcc_assert (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP
-			|| (OMP_CLAUSE_MAP_KIND (c)
-			    != OMP_CLAUSE_MAP_FORCE_DEVICEPTR)
+	    gcc_assert (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP);
+	    gcc_assert ((OMP_CLAUSE_MAP_KIND (c)
+			 != OMP_CLAUSE_MAP_FORCE_DEVICEPTR)
 			|| TREE_CODE (TREE_TYPE (var)) != ARRAY_TYPE);
-	    if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
-		&& OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER
+	    if (OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER
 		&& !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c)
 		&& TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE)
 	      x = build_simple_mem_ref (x);
@@ -11915,17 +11292,16 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
 	map_cnt++;
       }
 
-  if (kind == GF_OMP_TARGET_KIND_REGION)
+  if (offloaded)
     {
       target_nesting_level++;
       lower_omp (&tgt_body, ctx);
       target_nesting_level--;
     }
-  else if (kind == GF_OMP_TARGET_KIND_DATA
-	   || kind == GF_OMP_TARGET_KIND_OACC_DATA)
+  else if (data_region)
     lower_omp (&tgt_body, ctx);
 
-  if (kind == GF_OMP_TARGET_KIND_REGION)
+  if (offloaded)
     {
       /* Declare all the variables created by mapping and the variables
 	 declared in the scope of the target body.  */
@@ -11951,22 +11327,15 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
       TREE_STATIC (TREE_VEC_ELT (t, 1)) = 1;
       tree tkind_type;
       int talign_shift;
-      switch (kind)
+      if (is_gimple_omp_oacc_specifically (stmt))
 	{
-	case GF_OMP_TARGET_KIND_REGION:
-	case GF_OMP_TARGET_KIND_DATA:
-	case GF_OMP_TARGET_KIND_UPDATE:
-	  tkind_type = unsigned_char_type_node;
-	  talign_shift = 3;
-	  break;
-	case GF_OMP_TARGET_KIND_OACC_DATA:
-	case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA:
-	case GF_OMP_TARGET_KIND_OACC_UPDATE:
 	  tkind_type = short_unsigned_type_node;
 	  talign_shift = 8;
-	  break;
-	default:
-	  gcc_unreachable ();
+	}
+      else
+	{
+	  tkind_type = unsigned_char_type_node;
+	  talign_shift = 3;
 	}
       TREE_VEC_ELT (t, 2)
 	= create_tmp_var (build_array_type_nelts (tkind_type, map_cnt),
@@ -11974,7 +11343,7 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
       DECL_NAMELESS (TREE_VEC_ELT (t, 2)) = 1;
       TREE_ADDRESSABLE (TREE_VEC_ELT (t, 2)) = 1;
       TREE_STATIC (TREE_VEC_ELT (t, 2)) = 1;
-      gimple_omp_target_set_data_arg (stmt, t);
+      gimple_omp_set_data_arg (stmt, t);
 
       vec<constructor_elt, va_gc> *vsize;
       vec<constructor_elt, va_gc> *vkind;
@@ -12039,12 +11408,18 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
 			    || (OMP_CLAUSE_MAP_KIND (c)
 				!= OMP_CLAUSE_MAP_FORCE_DEVICEPTR)
 			    || TREE_CODE (TREE_TYPE (ovar)) != ARRAY_TYPE);
-		if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
-		    && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER
-		    && !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c)
-		    && TREE_CODE (TREE_TYPE (ovar)) == ARRAY_TYPE)
+		if (maybe_lookup_reduction (var, ctx))
 		  {
-		    gcc_assert (kind == GF_OMP_TARGET_KIND_REGION);
+		    gcc_assert (gimple_code (stmt) == GIMPLE_OACC_KERNELS
+				|| gimple_code (stmt) == GIMPLE_OACC_PARALLEL);
+		    gimplify_assign (x, var, &ilist);
+		  }
+		else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+			 && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER
+			 && !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c)
+			 && TREE_CODE (TREE_TYPE (ovar)) == ARRAY_TYPE)
+		  {
+		    gcc_assert (offloaded);
 		    tree avar
 		      = create_tmp_var (TREE_TYPE (TREE_TYPE (x)), NULL);
 		    mark_addressable (avar);
@@ -12055,7 +11430,7 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
 		  }
 		else if (is_gimple_reg (var))
 		  {
-		    gcc_assert (kind == GF_OMP_TARGET_KIND_REGION);
+		    gcc_assert (offloaded);
 		    tree avar = create_tmp_var (TREE_TYPE (var), NULL);
 		    mark_addressable (avar);
 		    enum omp_clause_map_kind map_kind
@@ -12151,7 +11526,8 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
 
   new_body = NULL;
 
-  if (ctx->record_type && kind == GF_OMP_TARGET_KIND_REGION)
+  if (offloaded
+      && ctx->record_type)
     {
       t = build_fold_addr_expr_loc (loc, ctx->sender_decl);
       /* fixup_child_record_type might have changed receiver_decl's type.  */
@@ -12160,17 +11536,14 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
 	  		   gimple_build_assign (ctx->receiver_decl, t));
     }
 
-  if (kind == GF_OMP_TARGET_KIND_REGION)
+  if (offloaded)
     {
       gimple_seq_add_seq (&new_body, tgt_body);
       new_body = maybe_catch_exception (new_body);
     }
-  else if (kind == GF_OMP_TARGET_KIND_DATA
-	   || kind == GF_OMP_TARGET_KIND_OACC_DATA)
+  else if (data_region)
     new_body = tgt_body;
-  if (kind != GF_OMP_TARGET_KIND_UPDATE
-      && kind != GF_OMP_TARGET_KIND_OACC_UPDATE
-      && kind != GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA)
+  if (offloaded || data_region)
     {
       gimple_seq_add_stmt (&new_body, gimple_build_omp_return (false));
       gimple_omp_set_body (stmt, new_body);
@@ -12180,9 +11553,11 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
 			    tgt_bind ? gimple_bind_block (tgt_bind)
 				     : NULL_TREE);
   gsi_replace (gsi_p, bind, true);
+  gimple_bind_add_seq (bind, irlist);
   gimple_bind_add_seq (bind, ilist);
   gimple_bind_add_stmt (bind, stmt);
   gimple_bind_add_seq (bind, olist);
+  gimple_bind_add_seq (bind, orlist);
 
   pop_gimplify_context (NULL);
 }
@@ -12327,13 +11702,6 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p, omp_context *ctx)
     case GIMPLE_BIND:
       lower_omp (gimple_bind_body_ptr (stmt), ctx);
       break;
-    case GIMPLE_OACC_KERNELS:
-    case GIMPLE_OACC_PARALLEL:
-      ctx = maybe_lookup_ctx (stmt);
-      gcc_assert (ctx);
-      gcc_assert (!ctx->cancellable);
-      lower_oacc_offload (gsi_p, ctx);
-      break;
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
       ctx = maybe_lookup_ctx (stmt);
@@ -12387,11 +11755,12 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p, omp_context *ctx)
 			lower_omp_regimplify_p, ctx ? NULL : &wi, NULL))
 	gimple_regimplify_operands (stmt, gsi_p);
       break;
+    case GIMPLE_OACC_KERNELS:
+    case GIMPLE_OACC_PARALLEL:
     case GIMPLE_OMP_TARGET:
       ctx = maybe_lookup_ctx (stmt);
       gcc_assert (ctx);
-      if (gimple_omp_target_kind (stmt) == GF_OMP_TARGET_KIND_OACC_DATA
-	  || gimple_omp_target_kind (stmt) == GF_OMP_TARGET_KIND_OACC_UPDATE)
+      if (is_gimple_omp_oacc_specifically (stmt))
 	gcc_assert (!ctx->cancellable);
       lower_omp_target (gsi_p, ctx);
       break;


Grpße,
 Thomas

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 472 bytes --]

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

* Re: OpenACC GIMPLE_OACC_* -- or not?  (was: [gomp4 9/9] OpenACC: Basic support for #pragma acc parallel.)
  2014-11-12 13:35                     ` OpenACC GIMPLE_OACC_* -- or not? (was: [gomp4 9/9] OpenACC: Basic support for #pragma acc parallel.) Thomas Schwinge
@ 2014-11-12 13:46                       ` Jakub Jelinek
  2014-12-10  9:58                         ` OpenACC GIMPLE_OACC_* -- or not? Thomas Schwinge
  2014-12-10 10:02                         ` Nested OpenACC/OpenMP constructs (was: OpenACC GIMPLE_OACC_* -- or not?) Thomas Schwinge
  0 siblings, 2 replies; 44+ messages in thread
From: Jakub Jelinek @ 2014-11-12 13:46 UTC (permalink / raw)
  To: Thomas Schwinge; +Cc: gcc-patches, Cesar Philippidis, Tom de Vries

On Wed, Nov 12, 2014 at 02:33:43PM +0100, Thomas Schwinge wrote:
> Months later, with months' worth of GCC internals experience, I now came
> to realize that maybe this has not actually been a useful thing to do
> (and likewise for the GIMPLE_OACC_KERNELS also added later on,
> <http://news.gmane.org/find-root.php?message_id=%3C1393579386-11666-1-git-send-email-thomas%40codesourcery.com%3E>).
> All handling of GIMPLE_OACC_PARALLEL and GIMPLE_OACC_KERNELS closely
> follows that of GIMPLE_OMP_TARGET's GF_OMP_TARGET_KIND_REGION, with only
> minor divergence.  What I did not understand back then, has not been
> obvious to me, was that the underlying structure of all those codes will
> in fact be the same (as already made apparent by using the one
> GIMPLE_OMP_TARGET for all of: OpenMP target offloading regions, OpenMP
> target data regions, OpenMP target data maintenenace "executable"
> statements), and any "customization" then happens via the clauses
> attached to GIMPLE_OMP_TARGET.

I'm fine with merging them into kinds, just please make sure we'll have
some tests on mixing OpenMP and OpenACC directives in the same functions
(it is fine if we error out on combinations that don't make sense or are
too hard to support).
E.g. supporting OpenACC #pragma omp target counterpart inside
of #pragma omp parallel or #pragma omp task should be presumably fine,
supporting OpenACC inside of #pragma omp target should be IMHO just
diagnosed, mixing target data and openacc is generically hard to diagnose,
perhaps at runtime, supporting #pragma omp directives inside of OpenACC
regions not needed (perhaps there are exceptions you want to support?).

> So, sanity check: should we now merge GIMPLE_OACC_PARALLEL and
> GIMPLE_OACC_KERNELS into being "subtypes" of GIMPLE_OMP_TARGET (like
> GF_OMP_TARGET_KIND_REGION), as already done for
> GF_OMP_TARGET_KIND_OACC_DATA (like GF_OMP_TARGET_KIND_DATA), and
> GF_OMP_TARGET_KIND_OACC_UPDATE and
> GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA (like GF_OMP_TARGET_KIND_UPDATE).

Yep.

	Jakub

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

* Re: OpenACC GIMPLE_OACC_* -- or not?
  2014-11-12 13:46                       ` Jakub Jelinek
@ 2014-12-10  9:58                         ` Thomas Schwinge
  2014-12-10 10:07                           ` Thomas Schwinge
  2014-12-10 10:02                         ` Nested OpenACC/OpenMP constructs (was: OpenACC GIMPLE_OACC_* -- or not?) Thomas Schwinge
  1 sibling, 1 reply; 44+ messages in thread
From: Thomas Schwinge @ 2014-12-10  9:58 UTC (permalink / raw)
  To: gcc-patches, Jakub Jelinek; +Cc: Cesar Philippidis, Tom de Vries, Bernd Schmidt

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

Hi!

On Wed, 12 Nov 2014 14:45:02 +0100, Jakub Jelinek <jakub@redhat.com> wrote:
> On Wed, Nov 12, 2014 at 02:33:43PM +0100, Thomas Schwinge wrote:
> > Months later, with months' worth of GCC internals experience, I now came
> > to realize that maybe this has not actually been a useful thing to do
> > (and likewise for the GIMPLE_OACC_KERNELS also added later on,
> > <http://news.gmane.org/find-root.php?message_id=%3C1393579386-11666-1-git-send-email-thomas%40codesourcery.com%3E>).
> > All handling of GIMPLE_OACC_PARALLEL and GIMPLE_OACC_KERNELS closely
> > follows that of GIMPLE_OMP_TARGET's GF_OMP_TARGET_KIND_REGION, with only
> > minor divergence.  What I did not understand back then, has not been
> > obvious to me, was that the underlying structure of all those codes will
> > in fact be the same (as already made apparent by using the one
> > GIMPLE_OMP_TARGET for all of: OpenMP target offloading regions, OpenMP
> > target data regions, OpenMP target data maintenenace "executable"
> > statements), and any "customization" then happens via the clauses
> > attached to GIMPLE_OMP_TARGET.
> 
> I'm fine with merging them into kinds, [...]
> 
> > So, sanity check: should we now merge GIMPLE_OACC_PARALLEL and
> > GIMPLE_OACC_KERNELS into being "subtypes" of GIMPLE_OMP_TARGET (like
> > GF_OMP_TARGET_KIND_REGION), as already done for
> > GF_OMP_TARGET_KIND_OACC_DATA (like GF_OMP_TARGET_KIND_DATA), and
> > GF_OMP_TARGET_KIND_OACC_UPDATE and
> > GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA (like GF_OMP_TARGET_KIND_UPDATE).
> 
> Yep.

In r218568, I applied the following to gomp-4_0-branch:

commit 28629d718a63a782170cfb06a4d0278de0779039
Author: tschwinge <tschwinge@138bc75d-0d04-0410-961f-82ee72b054a4>
Date:   Wed Dec 10 09:52:28 2014 +0000

    Merge GIMPLE_OACC_KERNELS and GIMPLE_OACC_PARALLEL into GIMPLE_OMP_TARGET.
    
    	gcc/
    	* gimple.def (GIMPLE_OACC_KERNELS, GIMPLE_OACC_PARALLEL): Merge
    	into GIMPLE_OMP_TARGET.  Update all users.
    
    	gcc/
    	* cgraphbuild.c (pass_build_cgraph_edges::execute): Remove
    	handling of GIMPLE_OACC_PARALLEL.
    	* gimple-pretty-print.c (dump_gimple_omp_target): Dump a bit more
    	data, pretty-printing.
    
    git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@218568 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/ChangeLog.gomp                            |  11 ++
 gcc/cgraphbuild.c                             |  13 +-
 gcc/doc/gimple.texi                           |  15 --
 gcc/gimple-low.c                              |   2 -
 gcc/gimple-pretty-print.c                     | 118 +++--------
 gcc/gimple-walk.c                             |  32 ---
 gcc/gimple.c                                  |  40 +---
 gcc/gimple.def                                |  35 +---
 gcc/gimple.h                                  | 273 ++------------------------
 gcc/gimplify.c                                |   6 +-
 gcc/omp-low.c                                 | 225 +++++++--------------
 gcc/testsuite/gfortran.dg/goacc/private-1.f95 |   2 +-
 gcc/tree-inline.c                             |   6 -
 gcc/tree-nested.c                             |  16 --
 14 files changed, 136 insertions(+), 658 deletions(-)

diff --git gcc/ChangeLog.gomp gcc/ChangeLog.gomp
index bece7c1..06e8583 100644
--- gcc/ChangeLog.gomp
+++ gcc/ChangeLog.gomp
@@ -1,4 +1,15 @@
 2014-12-10  Thomas Schwinge  <thomas@codesourcery.com>
+	    Bernd Schmidt  <bernds@codesourcery.com>
+
+	* gimple.def (GIMPLE_OACC_KERNELS, GIMPLE_OACC_PARALLEL): Merge
+	into GIMPLE_OMP_TARGET.  Update all users.
+
+2014-12-10  Thomas Schwinge  <thomas@codesourcery.com>
+
+	* cgraphbuild.c (pass_build_cgraph_edges::execute): Remove
+	handling of GIMPLE_OACC_PARALLEL.
+	* gimple-pretty-print.c (dump_gimple_omp_target): Dump a bit more
+	data, pretty-printing.
 
 	* omp-low.c (build_omp_regions_1, make_gimple_omp_edges)
 	<GIMPLE_OMP_TARGET>: Handle
diff --git gcc/cgraphbuild.c gcc/cgraphbuild.c
index 9b078bc..c72ceab 100644
--- gcc/cgraphbuild.c
+++ gcc/cgraphbuild.c
@@ -368,21 +368,14 @@ pass_build_cgraph_edges::execute (function *fun)
 					    bb->count, freq);
 	    }
 	  node->record_stmt_references (stmt);
-	  if (gimple_code (stmt) == GIMPLE_OACC_PARALLEL
-	      && gimple_oacc_parallel_child_fn (stmt))
-	    {
-	      tree fn = gimple_oacc_parallel_child_fn (stmt);
-	      node->create_reference (cgraph_node::get_create (fn),
-				      IPA_REF_ADDR, stmt);
-	    }
-	  else if (gimple_code (stmt) == GIMPLE_OMP_PARALLEL
-		   && gimple_omp_parallel_child_fn (stmt))
+	  if (gimple_code (stmt) == GIMPLE_OMP_PARALLEL
+	      && gimple_omp_parallel_child_fn (stmt))
 	    {
 	      tree fn = gimple_omp_parallel_child_fn (stmt);
 	      node->create_reference (cgraph_node::get_create (fn),
 				      IPA_REF_ADDR, stmt);
 	    }
-	  else if (gimple_code (stmt) == GIMPLE_OMP_TASK)
+	  if (gimple_code (stmt) == GIMPLE_OMP_TASK)
 	    {
 	      tree fn = gimple_omp_task_child_fn (stmt);
 	      if (fn)
diff --git gcc/doc/gimple.texi gcc/doc/gimple.texi
index 4c59748..696c10e 100644
--- gcc/doc/gimple.texi
+++ gcc/doc/gimple.texi
@@ -439,8 +439,6 @@ The following table briefly describes the GIMPLE instruction set.
 @item @code{GIMPLE_GOTO}		@tab x			@tab x
 @item @code{GIMPLE_LABEL}		@tab x			@tab x
 @item @code{GIMPLE_NOP}			@tab x			@tab x
-@item @code{GIMPLE_OACC_KERNELS}	@tab x			@tab x
-@item @code{GIMPLE_OACC_PARALLEL}	@tab x			@tab x
 @item @code{GIMPLE_OMP_ATOMIC_LOAD}	@tab x			@tab x
 @item @code{GIMPLE_OMP_ATOMIC_STORE}	@tab x			@tab x
 @item @code{GIMPLE_OMP_CONTINUE}	@tab x			@tab x
@@ -1008,8 +1006,6 @@ Return a deep copy of statement @code{STMT}.
 * @code{GIMPLE_EH_FILTER}::
 * @code{GIMPLE_LABEL}::
 * @code{GIMPLE_NOP}::
-* @code{GIMPLE_OACC_KERNELS}::
-* @code{GIMPLE_OACC_PARALLEL}::
 * @code{GIMPLE_OMP_ATOMIC_LOAD}::
 * @code{GIMPLE_OMP_ATOMIC_STORE}::
 * @code{GIMPLE_OMP_CONTINUE}::
@@ -1655,17 +1651,6 @@ Build a @code{GIMPLE_NOP} statement.
 Returns @code{TRUE} if statement @code{G} is a @code{GIMPLE_NOP}.
 @end deftypefn
 
-
-@node @code{GIMPLE_OACC_KERNELS}
-@subsection @code{GIMPLE_OACC_KERNELS}
-@cindex @code{GIMPLE_OACC_KERNELS}
-
-
-@node @code{GIMPLE_OACC_PARALLEL}
-@subsection @code{GIMPLE_OACC_PARALLEL}
-@cindex @code{GIMPLE_OACC_PARALLEL}
-
-
 @node @code{GIMPLE_OMP_ATOMIC_LOAD}
 @subsection @code{GIMPLE_OMP_ATOMIC_LOAD}
 @cindex @code{GIMPLE_OMP_ATOMIC_LOAD}
diff --git gcc/gimple-low.c gcc/gimple-low.c
index 60a7792e..3507d3c 100644
--- gcc/gimple-low.c
+++ gcc/gimple-low.c
@@ -368,8 +368,6 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
       }
       break;
 
-    case GIMPLE_OACC_KERNELS:
-    case GIMPLE_OACC_PARALLEL:
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
     case GIMPLE_OMP_TARGET:
diff --git gcc/gimple-pretty-print.c gcc/gimple-pretty-print.c
index 72dfac6..38d39f7 100644
--- gcc/gimple-pretty-print.c
+++ gcc/gimple-pretty-print.c
@@ -1338,15 +1338,21 @@ dump_gimple_omp_target (pretty_printer *buffer, gimple gs, int spc, int flags)
     case GF_OMP_TARGET_KIND_UPDATE:
       kind = " update";
       break;
+    case GF_OMP_TARGET_KIND_OACC_KERNELS:
+      kind = " oacc_kernels";
+      break;
+    case GF_OMP_TARGET_KIND_OACC_PARALLEL:
+      kind = " oacc_parallel";
+      break;
     case GF_OMP_TARGET_KIND_OACC_DATA:
       kind = " oacc_data";
       break;
-    case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA:
-      kind = " oacc_enter_exit_data";
-      break;
     case GF_OMP_TARGET_KIND_OACC_UPDATE:
       kind = " oacc_update";
       break;
+    case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA:
+      kind = " oacc_enter_exit_data";
+      break;
     default:
       gcc_unreachable ();
     }
@@ -1355,7 +1361,9 @@ dump_gimple_omp_target (pretty_printer *buffer, gimple gs, int spc, int flags)
       dump_gimple_fmt (buffer, spc, flags, "%G%s <%+BODY <%S>%nCLAUSES <", gs,
 		       kind, gimple_omp_body (gs));
       dump_omp_clauses (buffer, gimple_omp_target_clauses (gs), spc, flags);
-      dump_gimple_fmt (buffer, spc, flags, " >");
+      dump_gimple_fmt (buffer, spc, flags, " >, %T, %T%n>",
+		       gimple_omp_target_child_fn (gs),
+		       gimple_omp_target_data_arg (gs));
     }
   else
     {
@@ -1367,16 +1375,28 @@ dump_gimple_omp_target (pretty_printer *buffer, gimple gs, int spc, int flags)
 	  pp_string (buffer, " [child fn: ");
 	  dump_generic_node (buffer, gimple_omp_target_child_fn (gs),
 			     spc, flags, false);
-	  pp_right_bracket (buffer);
+	  pp_string (buffer, " (");
+	  if (gimple_omp_target_data_arg (gs))
+	    dump_generic_node (buffer, gimple_omp_target_data_arg (gs),
+			       spc, flags, false);
+	  else
+	    pp_string (buffer, "???");
+	  pp_string (buffer, ")]");
 	}
-      if (!gimple_seq_empty_p (gimple_omp_body (gs)))
+      gimple_seq body = gimple_omp_body (gs);
+      if (body && gimple_code (gimple_seq_first_stmt (body)) != GIMPLE_BIND)
 	{
 	  newline_and_indent (buffer, spc + 2);
-	  pp_character (buffer, '{');
+	  pp_left_brace (buffer);
 	  pp_newline (buffer);
-	  dump_gimple_seq (buffer, gimple_omp_body (gs), spc + 4, flags);
+	  dump_gimple_seq (buffer, body, spc + 4, flags);
 	  newline_and_indent (buffer, spc + 2);
-	  pp_character (buffer, '}');
+	  pp_right_brace (buffer);
+	}
+      else if (body)
+	{
+	  pp_newline (buffer);
+	  dump_gimple_seq (buffer, body, spc + 2, flags);
 	}
     }
 }
@@ -1878,81 +1898,6 @@ dump_gimple_phi (pretty_printer *buffer, gimple phi, int spc, bool comment,
 }
 
 
-/* Dump an OpenACC offload tuple on the pretty_printer BUFFER, SPC spaces
-   of indent.  FLAGS specifies details to show in the dump (see TDF_* in
-   dumpfile.h).  */
-
-static void
-dump_gimple_oacc_offload (pretty_printer *buffer, gimple gs, int spc,
-			  int flags)
-{
-  tree (*gimple_omp_clauses) (const_gimple);
-  tree (*gimple_omp_child_fn) (const_gimple);
-  tree (*gimple_omp_data_arg) (const_gimple);
-  const char *kind;
-  switch (gimple_code (gs))
-    {
-    case GIMPLE_OACC_KERNELS:
-      gimple_omp_clauses = gimple_oacc_kernels_clauses;
-      gimple_omp_child_fn = gimple_oacc_kernels_child_fn;
-      gimple_omp_data_arg = gimple_oacc_kernels_data_arg;
-      kind = "kernels";
-      break;
-    case GIMPLE_OACC_PARALLEL:
-      gimple_omp_clauses = gimple_oacc_parallel_clauses;
-      gimple_omp_child_fn = gimple_oacc_parallel_child_fn;
-      gimple_omp_data_arg = gimple_oacc_parallel_data_arg;
-      kind = "parallel";
-      break;
-    default:
-      gcc_unreachable ();
-    }
-  if (flags & TDF_RAW)
-    {
-      dump_gimple_fmt (buffer, spc, flags, "%G <%+BODY <%S>%nCLAUSES <", gs,
-                       gimple_omp_body (gs));
-      dump_omp_clauses (buffer, gimple_omp_clauses (gs), spc, flags);
-      dump_gimple_fmt (buffer, spc, flags, " >, %T, %T%n>",
-                       gimple_omp_child_fn (gs), gimple_omp_data_arg (gs));
-    }
-  else
-    {
-      gimple_seq body;
-      pp_string (buffer, "#pragma acc ");
-      pp_string (buffer, kind);
-      dump_omp_clauses (buffer, gimple_omp_clauses (gs), spc, flags);
-      if (gimple_omp_child_fn (gs))
-	{
-	  pp_string (buffer, " [child fn: ");
-	  dump_generic_node (buffer, gimple_omp_child_fn (gs),
-			     spc, flags, false);
-	  pp_string (buffer, " (");
-	  if (gimple_omp_data_arg (gs))
-	    dump_generic_node (buffer, gimple_omp_data_arg (gs),
-			       spc, flags, false);
-	  else
-	    pp_string (buffer, "???");
-	  pp_string (buffer, ")]");
-	}
-      body = gimple_omp_body (gs);
-      if (body && gimple_code (gimple_seq_first_stmt (body)) != GIMPLE_BIND)
-	{
-	  newline_and_indent (buffer, spc + 2);
-	  pp_left_brace (buffer);
-	  pp_newline (buffer);
-	  dump_gimple_seq (buffer, body, spc + 4, flags);
-	  newline_and_indent (buffer, spc + 2);
-	  pp_right_brace (buffer);
-	}
-      else if (body)
-	{
-	  pp_newline (buffer);
-	  dump_gimple_seq (buffer, body, spc + 2, flags);
-	}
-    }
-}
-
-
 /* Dump a GIMPLE_OMP_PARALLEL tuple on the pretty_printer BUFFER, SPC spaces
    of indent.  FLAGS specifies details to show in the dump (see TDF_* in
    dumpfile.h).  */
@@ -2237,11 +2182,6 @@ pp_gimple_stmt_1 (pretty_printer *buffer, gimple gs, int spc, int flags)
       dump_gimple_phi (buffer, gs, spc, false, flags);
       break;
 
-    case GIMPLE_OACC_KERNELS:
-    case GIMPLE_OACC_PARALLEL:
-      dump_gimple_oacc_offload (buffer, gs, spc, flags);
-      break;
-
     case GIMPLE_OMP_PARALLEL:
       dump_gimple_omp_parallel (buffer, gs, spc, flags);
       break;
diff --git gcc/gimple-walk.c gcc/gimple-walk.c
index cc74d34..bfa3532 100644
--- gcc/gimple-walk.c
+++ gcc/gimple-walk.c
@@ -304,36 +304,6 @@ walk_gimple_op (gimple stmt, walk_tree_fn callback_op,
 	return ret;
       break;
 
-    case GIMPLE_OACC_KERNELS:
-      ret = walk_tree (gimple_oacc_kernels_clauses_ptr (stmt), callback_op,
-		       wi, pset);
-      if (ret)
-	return ret;
-      ret = walk_tree (gimple_oacc_kernels_child_fn_ptr (stmt), callback_op,
-		       wi, pset);
-      if (ret)
-	return ret;
-      ret = walk_tree (gimple_oacc_kernels_data_arg_ptr (stmt), callback_op,
-		       wi, pset);
-      if (ret)
-	return ret;
-      break;
-
-    case GIMPLE_OACC_PARALLEL:
-      ret = walk_tree (gimple_oacc_parallel_clauses_ptr (stmt), callback_op,
-		       wi, pset);
-      if (ret)
-	return ret;
-      ret = walk_tree (gimple_oacc_parallel_child_fn_ptr (stmt), callback_op,
-		       wi, pset);
-      if (ret)
-	return ret;
-      ret = walk_tree (gimple_oacc_parallel_data_arg_ptr (stmt), callback_op,
-		       wi, pset);
-      if (ret)
-	return ret;
-      break;
-
     case GIMPLE_OMP_CONTINUE:
       ret = walk_tree (gimple_omp_continue_control_def_ptr (stmt),
 	  	       callback_op, wi, pset);
@@ -629,8 +599,6 @@ walk_gimple_stmt (gimple_stmt_iterator *gsi, walk_stmt_fn callback_stmt,
 	return wi->callback_result;
 
       /* FALL THROUGH.  */
-    case GIMPLE_OACC_KERNELS:
-    case GIMPLE_OACC_PARALLEL:
     case GIMPLE_OMP_CRITICAL:
     case GIMPLE_OMP_MASTER:
     case GIMPLE_OMP_TASKGROUP:
diff --git gcc/gimple.c gcc/gimple.c
index e6de836..32615e8 100644
--- gcc/gimple.c
+++ gcc/gimple.c
@@ -811,40 +811,6 @@ gimple_build_debug_source_bind_stat (tree var, tree value,
 }
 
 
-/* Build a GIMPLE_OACC_KERNELS statement.
-
-   BODY is sequence of statements which are executed as kernels.
-   CLAUSES are the OpenACC kernels construct's clauses.  */
-
-gimple
-gimple_build_oacc_kernels (gimple_seq body, tree clauses)
-{
-  gimple p = gimple_alloc (GIMPLE_OACC_KERNELS, 0);
-  if (body)
-    gimple_omp_set_body (p, body);
-  gimple_oacc_kernels_set_clauses (p, clauses);
-
-  return p;
-}
-
-
-/* Build a GIMPLE_OACC_PARALLEL statement.
-
-   BODY is sequence of statements which are executed in parallel.
-   CLAUSES are the OpenACC parallel construct's clauses.  */
-
-gimple
-gimple_build_oacc_parallel (gimple_seq body, tree clauses)
-{
-  gimple p = gimple_alloc (GIMPLE_OACC_PARALLEL, 0);
-  if (body)
-    gimple_omp_set_body (p, body);
-  gimple_oacc_parallel_set_clauses (p, clauses);
-
-  return p;
-}
-
-
 /* Build a GIMPLE_OMP_CRITICAL statement.
 
    BODY is the sequence of statements for which only one thread can execute.
@@ -1077,7 +1043,7 @@ gimple_build_omp_single (gimple_seq body, tree clauses)
 /* Build a GIMPLE_OMP_TARGET statement.
 
    BODY is the sequence of statements that will be executed.
-   KIND is the kind of target region.
+   KIND is the kind of the region.
    CLAUSES are any of the construct's clauses.  */
 
 gimple
@@ -1719,10 +1685,6 @@ gimple_copy (gimple stmt)
 	  gimple_try_set_cleanup (copy, new_seq);
 	  break;
 
-	case GIMPLE_OACC_KERNELS:
-	case GIMPLE_OACC_PARALLEL:
-          gcc_unreachable ();
-
 	case GIMPLE_OMP_FOR:
 	  gcc_assert (!is_gimple_omp_oacc_specifically (stmt));
 	  new_seq = gimple_seq_copy (gimple_omp_for_pre_body (stmt));
diff --git gcc/gimple.def gcc/gimple.def
index e2e912c..269c2d7 100644
--- gcc/gimple.def
+++ gcc/gimple.def
@@ -205,33 +205,8 @@ DEFGSCODE(GIMPLE_NOP, "gimple_nop", GSS_BASE)
 
 /* IMPORTANT.
 
-   Do not rearrange any of the GIMPLE_OACC_* and GIMPLE_OMP_* codes.  This
-   ordering is exposed by the range check in gimple_omp_subcode.  */
-
-
-/* GIMPLE_OACC_KERNELS <BODY, CLAUSES, CHILD_FN, DATA_ARG> represents
-   #pragma acc kernels [CLAUSES]
-   BODY is the sequence of statements inside the kernels construct.
-   CLAUSES is an OMP_CLAUSE chain holding the associated clauses.
-   CHILD_FN is set when outlining the body of the kernels region.
-   All the statements in BODY are moved into this newly created
-   function when converting OMP constructs into low-GIMPLE.
-   DATA_ARG is a vec of 3 local variables in the parent function
-   containing data to be mapped to CHILD_FN.  This is used to
-   implement the MAP clauses.  */
-DEFGSCODE(GIMPLE_OACC_KERNELS, "gimple_oacc_kernels", GSS_OMP_PARALLEL_LAYOUT)
-
-/* GIMPLE_OACC_PARALLEL <BODY, CLAUSES, CHILD_FN, DATA_ARG> represents
-   #pragma acc parallel [CLAUSES]
-   BODY is the sequence of statements inside the parallel construct.
-   CLAUSES is an OMP_CLAUSE chain holding the associated clauses.
-   CHILD_FN is set when outlining the body of the parallel region.
-   All the statements in BODY are moved into this newly created
-   function when converting OMP constructs into low-GIMPLE.
-   DATA_ARG is a vec of 3 local variables in the parent function
-   containing data to be mapped to CHILD_FN.  This is used to
-   implement the MAP clauses.  */
-DEFGSCODE(GIMPLE_OACC_PARALLEL, "gimple_oacc_parallel", GSS_OMP_PARALLEL_LAYOUT)
+   Do not rearrange any of the GIMPLE_OMP_* codes.  This ordering is
+   exposed by the range check in gimple_omp_subcode.  */
 
 /* Tuples used for lowering of OMP_ATOMIC.  Although the form of the OMP_ATOMIC
    expression is very simple (just in form mem op= expr), various implicit
@@ -381,12 +356,12 @@ DEFGSCODE(GIMPLE_OMP_SECTIONS_SWITCH, "gimple_omp_sections_switch", GSS_BASE)
 DEFGSCODE(GIMPLE_OMP_SINGLE, "gimple_omp_single", GSS_OMP_SINGLE_LAYOUT)
 
 /* GIMPLE_OMP_TARGET <BODY, CLAUSES, CHILD_FN> represents
-   #pragma acc data
+   #pragma acc {kernels,parallel,data}
    #pragma omp target {,data,update}
-   BODY is the sequence of statements inside the target construct
+   BODY is the sequence of statements inside the construct
    (NULL for target update).
    CLAUSES is an OMP_CLAUSE chain holding the associated clauses.
-   CHILD_FN is set when outlining the body of the target region.
+   CHILD_FN is set when outlining the body of the offloaded region.
    All the statements in BODY are moved into this newly created
    function when converting OMP constructs into low-GIMPLE.
    DATA_ARG is a vec of 3 local variables in the parent function
diff --git gcc/gimple.h gcc/gimple.h
index a91bd4e..60c2469 100644
--- gcc/gimple.h
+++ gcc/gimple.h
@@ -108,9 +108,11 @@ enum gf_mask {
     GF_OMP_TARGET_KIND_REGION	= 0,
     GF_OMP_TARGET_KIND_DATA	= 1,
     GF_OMP_TARGET_KIND_UPDATE	= 2,
-    GF_OMP_TARGET_KIND_OACC_DATA = 3,
-    GF_OMP_TARGET_KIND_OACC_UPDATE = 4,
-    GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA = 5,
+    GF_OMP_TARGET_KIND_OACC_PARALLEL = 3,
+    GF_OMP_TARGET_KIND_OACC_KERNELS = 4,
+    GF_OMP_TARGET_KIND_OACC_DATA = 5,
+    GF_OMP_TARGET_KIND_OACC_UPDATE = 6,
+    GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA = 7,
 
     /* True on an GIMPLE_OMP_RETURN statement if the return does not require
        a thread synchronization via some sort of barrier.  The exact barrier
@@ -560,8 +562,8 @@ struct GTY((tag("GSS_OMP_FOR")))
 };
 
 
-/* GIMPLE_OACC_KERNELS, GIMPLE_OACC_PARALLEL, GIMPLE_OMP_PARALLEL,
-   GIMPLE_OMP_TARGET, GIMPLE_OMP_TASK */
+/* GIMPLE_OMP_PARALLEL, GIMPLE_OMP_TARGET, GIMPLE_OMP_TASK */
+
 struct GTY((tag("GSS_OMP_PARALLEL_LAYOUT")))
   gimple_statement_omp_parallel_layout : public gimple_statement_omp
 {
@@ -580,22 +582,6 @@ struct GTY((tag("GSS_OMP_PARALLEL_LAYOUT")))
   tree data_arg;
 };
 
-/* GIMPLE_OACC_KERNELS */
-struct GTY((tag("GSS_OMP_PARALLEL_LAYOUT")))
-  gimple_statement_oacc_kernels : public gimple_statement_omp_parallel_layout
-{
-    /* No extra fields; adds invariant:
-         stmt->code == GIMPLE_OACC_KERNELS.  */
-};
-
-/* GIMPLE_OACC_PARALLEL */
-struct GTY((tag("GSS_OMP_PARALLEL_LAYOUT")))
-  gimple_statement_oacc_parallel : public gimple_statement_omp_parallel_layout
-{
-    /* No extra fields; adds invariant:
-         stmt->code == GIMPLE_OACC_PARALLEL.  */
-};
-
 /* GIMPLE_OMP_PARALLEL or GIMPLE_TASK */
 struct GTY((tag("GSS_OMP_PARALLEL_LAYOUT")))
   gimple_statement_omp_taskreg : public gimple_statement_omp_parallel_layout
@@ -913,22 +899,6 @@ is_a_helper <gimple_statement_omp_for *>::test (gimple gs)
 template <>
 template <>
 inline bool
-is_a_helper <gimple_statement_oacc_kernels *>::test (gimple gs)
-{
-  return gs->code == GIMPLE_OACC_KERNELS;
-}
-
-template <>
-template <>
-inline bool
-is_a_helper <gimple_statement_oacc_parallel *>::test (gimple gs)
-{
-  return gs->code == GIMPLE_OACC_PARALLEL;
-}
-
-template <>
-template <>
-inline bool
 is_a_helper <gimple_statement_omp_taskreg *>::test (gimple gs)
 {
   return gs->code == GIMPLE_OMP_PARALLEL || gs->code == GIMPLE_OMP_TASK;
@@ -1121,22 +1091,6 @@ is_a_helper <const gimple_statement_omp_for *>::test (const_gimple gs)
 template <>
 template <>
 inline bool
-is_a_helper <const gimple_statement_oacc_kernels *>::test (const_gimple gs)
-{
-  return gs->code == GIMPLE_OACC_KERNELS;
-}
-
-template <>
-template <>
-inline bool
-is_a_helper <const gimple_statement_oacc_parallel *>::test (const_gimple gs)
-{
-  return gs->code == GIMPLE_OACC_PARALLEL;
-}
-
-template <>
-template <>
-inline bool
 is_a_helper <const gimple_statement_omp_taskreg *>::test (const_gimple gs)
 {
   return gs->code == GIMPLE_OMP_PARALLEL || gs->code == GIMPLE_OMP_TASK;
@@ -1260,8 +1214,6 @@ gimple gimple_build_debug_bind_stat (tree, tree, gimple MEM_STAT_DECL);
 gimple gimple_build_debug_source_bind_stat (tree, tree, gimple MEM_STAT_DECL);
 #define gimple_build_debug_source_bind(var,val,stmt)			\
   gimple_build_debug_source_bind_stat ((var), (val), (stmt) MEM_STAT_INFO)
-gimple gimple_build_oacc_kernels (gimple_seq, tree);
-gimple gimple_build_oacc_parallel (gimple_seq, tree);
 gimple gimple_build_omp_critical (gimple_seq, tree);
 gimple gimple_build_omp_for (gimple_seq, int, tree, size_t, gimple_seq);
 gimple gimple_build_omp_parallel (gimple_seq, tree, tree, tree);
@@ -1500,8 +1452,6 @@ gimple_has_substatements (gimple g)
     case GIMPLE_EH_FILTER:
     case GIMPLE_EH_ELSE:
     case GIMPLE_TRY:
-    case GIMPLE_OACC_KERNELS:
-    case GIMPLE_OACC_PARALLEL:
     case GIMPLE_OMP_FOR:
     case GIMPLE_OMP_MASTER:
     case GIMPLE_OMP_TASKGROUP:
@@ -4362,197 +4312,6 @@ gimple_omp_set_body (gimple gs, gimple_seq body)
 }
 
 
-/* Return the clauses associated with OACC_KERNELS statement GS.  */
-
-static inline tree
-gimple_oacc_kernels_clauses (const_gimple gs)
-{
-  const gimple_statement_oacc_kernels *oacc_kernels_stmt =
-    as_a <const gimple_statement_oacc_kernels *> (gs);
-  return oacc_kernels_stmt->clauses;
-}
-
-/* Return a pointer to the clauses associated with OACC_KERNELS statement GS.  */
-
-static inline tree *
-gimple_oacc_kernels_clauses_ptr (gimple gs)
-{
-  gimple_statement_oacc_kernels *oacc_kernels_stmt =
-    as_a <gimple_statement_oacc_kernels *> (gs);
-  return &oacc_kernels_stmt->clauses;
-}
-
-/* Set CLAUSES to be the list of clauses associated with OACC_KERNELS statement
-   GS.  */
-
-static inline void
-gimple_oacc_kernels_set_clauses (gimple gs, tree clauses)
-{
-  gimple_statement_oacc_kernels *oacc_kernels_stmt =
-    as_a <gimple_statement_oacc_kernels *> (gs);
-  oacc_kernels_stmt->clauses = clauses;
-}
-
-/* Return the child function used to hold the body of OACC_KERNELS statement
-   GS.  */
-
-static inline tree
-gimple_oacc_kernels_child_fn (const_gimple gs)
-{
-  const gimple_statement_oacc_kernels *oacc_kernels_stmt =
-    as_a <const gimple_statement_oacc_kernels *> (gs);
-  return oacc_kernels_stmt->child_fn;
-}
-
-/* Return a pointer to the child function used to hold the body of OACC_KERNELS
-   statement GS.  */
-
-static inline tree *
-gimple_oacc_kernels_child_fn_ptr (gimple gs)
-{
-  gimple_statement_oacc_kernels *oacc_kernels_stmt =
-    as_a <gimple_statement_oacc_kernels *> (gs);
-  return &oacc_kernels_stmt->child_fn;
-}
-
-/* Set CHILD_FN to be the child function for OACC_KERNELS statement GS.  */
-
-static inline void
-gimple_oacc_kernels_set_child_fn (gimple gs, tree child_fn)
-{
-  gimple_statement_oacc_kernels *oacc_kernels_stmt =
-    as_a <gimple_statement_oacc_kernels *> (gs);
-  oacc_kernels_stmt->child_fn = child_fn;
-}
-
-/* Return the artificial argument used to send variables and values
-   from the parent to the children threads in OACC_KERNELS statement GS.  */
-
-static inline tree
-gimple_oacc_kernels_data_arg (const_gimple gs)
-{
-  const gimple_statement_oacc_kernels *oacc_kernels_stmt =
-    as_a <const gimple_statement_oacc_kernels *> (gs);
-  return oacc_kernels_stmt->data_arg;
-}
-
-/* Return a pointer to the data argument for OACC_KERNELS statement GS.  */
-
-static inline tree *
-gimple_oacc_kernels_data_arg_ptr (gimple gs)
-{
-  gimple_statement_oacc_kernels *oacc_kernels_stmt =
-    as_a <gimple_statement_oacc_kernels *> (gs);
-  return &oacc_kernels_stmt->data_arg;
-}
-
-/* Set DATA_ARG to be the data argument for OACC_KERNELS statement GS.  */
-
-static inline void
-gimple_oacc_kernels_set_data_arg (gimple gs, tree data_arg)
-{
-  gimple_statement_oacc_kernels *oacc_kernels_stmt =
-    as_a <gimple_statement_oacc_kernels *> (gs);
-  oacc_kernels_stmt->data_arg = data_arg;
-}
-
-
-/* Return the clauses associated with OACC_PARALLEL statement GS.  */
-
-static inline tree
-gimple_oacc_parallel_clauses (const_gimple gs)
-{
-  const gimple_statement_oacc_parallel *oacc_parallel_stmt =
-    as_a <const gimple_statement_oacc_parallel *> (gs);
-  return oacc_parallel_stmt->clauses;
-}
-
-/* Return a pointer to the clauses associated with OACC_PARALLEL statement
-   GS.  */
-
-static inline tree *
-gimple_oacc_parallel_clauses_ptr (gimple gs)
-{
-  gimple_statement_oacc_parallel *oacc_parallel_stmt =
-    as_a <gimple_statement_oacc_parallel *> (gs);
-  return &oacc_parallel_stmt->clauses;
-}
-
-/* Set CLAUSES to be the list of clauses associated with OACC_PARALLEL
-   statement GS.  */
-
-static inline void
-gimple_oacc_parallel_set_clauses (gimple gs, tree clauses)
-{
-  gimple_statement_oacc_parallel *oacc_parallel_stmt =
-    as_a <gimple_statement_oacc_parallel *> (gs);
-  oacc_parallel_stmt->clauses = clauses;
-}
-
-/* Return the child function used to hold the body of OACC_PARALLEL statement
-   GS.  */
-
-static inline tree
-gimple_oacc_parallel_child_fn (const_gimple gs)
-{
-  const gimple_statement_oacc_parallel *oacc_parallel_stmt =
-    as_a <const gimple_statement_oacc_parallel *> (gs);
-  return oacc_parallel_stmt->child_fn;
-}
-
-/* Return a pointer to the child function used to hold the body of
-   OACC_PARALLEL statement GS.  */
-
-static inline tree *
-gimple_oacc_parallel_child_fn_ptr (gimple gs)
-{
-  gimple_statement_oacc_parallel *oacc_parallel_stmt =
-    as_a <gimple_statement_oacc_parallel *> (gs);
-  return &oacc_parallel_stmt->child_fn;
-}
-
-/* Set CHILD_FN to be the child function for OACC_PARALLEL statement GS.  */
-
-static inline void
-gimple_oacc_parallel_set_child_fn (gimple gs, tree child_fn)
-{
-  gimple_statement_oacc_parallel *oacc_parallel_stmt =
-    as_a <gimple_statement_oacc_parallel *> (gs);
-  oacc_parallel_stmt->child_fn = child_fn;
-}
-
-/* Return the artificial argument used to send variables and values
-   from the parent to the children threads in OACC_PARALLEL statement GS.  */
-
-static inline tree
-gimple_oacc_parallel_data_arg (const_gimple gs)
-{
-  const gimple_statement_oacc_parallel *oacc_parallel_stmt =
-    as_a <const gimple_statement_oacc_parallel *> (gs);
-  return oacc_parallel_stmt->data_arg;
-}
-
-/* Return a pointer to the data argument for OACC_PARALLEL statement GS.  */
-
-static inline tree *
-gimple_oacc_parallel_data_arg_ptr (gimple gs)
-{
-  gimple_statement_oacc_parallel *oacc_parallel_stmt =
-    as_a <gimple_statement_oacc_parallel *> (gs);
-  return &oacc_parallel_stmt->data_arg;
-}
-
-/* Set DATA_ARG to be the data argument for OACC_PARALLEL statement GS.  */
-
-static inline void
-gimple_oacc_parallel_set_data_arg (gimple gs, tree data_arg)
-{
-  gimple_statement_oacc_parallel *oacc_parallel_stmt =
-    as_a <gimple_statement_oacc_parallel *> (gs);
-  oacc_parallel_stmt->data_arg = data_arg;
-}
-
-
 /* Return the name associated with OMP_CRITICAL statement GS.  */
 
 static inline tree
@@ -5374,7 +5133,7 @@ gimple_omp_target_set_clauses (gimple gs, tree clauses)
 }
 
 
-/* Return the kind of OMP target statemement.  */
+/* Return the kind of the OMP_TARGET G.  */
 
 static inline int
 gimple_omp_target_kind (const_gimple g)
@@ -5384,7 +5143,7 @@ gimple_omp_target_kind (const_gimple g)
 }
 
 
-/* Set the OMP target kind.  */
+/* Set the kind of the OMP_TARGET G.  */
 
 static inline void
 gimple_omp_target_set_kind (gimple g, int kind)
@@ -5854,8 +5613,6 @@ gimple_return_set_retbnd (gimple gs, tree retval)
 /* Returns true when the gimple statement STMT is any of the OpenMP types.  */
 
 #define CASE_GIMPLE_OMP				\
-    case GIMPLE_OACC_KERNELS:			\
-    case GIMPLE_OACC_PARALLEL:			\
     case GIMPLE_OMP_PARALLEL:			\
     case GIMPLE_OMP_TASK:			\
     case GIMPLE_OMP_FOR:			\
@@ -5898,9 +5655,6 @@ is_gimple_omp_oacc_specifically (const_gimple stmt)
   gcc_assert (is_gimple_omp (stmt));
   switch (gimple_code (stmt))
     {
-    case GIMPLE_OACC_KERNELS:
-    case GIMPLE_OACC_PARALLEL:
-      return true;
     case GIMPLE_OMP_FOR:
       switch (gimple_omp_for_kind (stmt))
 	{
@@ -5908,10 +5662,12 @@ is_gimple_omp_oacc_specifically (const_gimple stmt)
 	  return true;
 	default:
 	  return false;
-	}      
+	}
     case GIMPLE_OMP_TARGET:
       switch (gimple_omp_target_kind (stmt))
 	{
+	case GF_OMP_TARGET_KIND_OACC_PARALLEL:
+	case GF_OMP_TARGET_KIND_OACC_KERNELS:
 	case GF_OMP_TARGET_KIND_OACC_DATA:
 	case GF_OMP_TARGET_KIND_OACC_UPDATE:
 	case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA:
@@ -5933,13 +5689,12 @@ is_gimple_omp_offloaded (const_gimple stmt)
   gcc_assert (is_gimple_omp (stmt));
   switch (gimple_code (stmt))
     {
-    case GIMPLE_OACC_KERNELS:
-    case GIMPLE_OACC_PARALLEL:
-      return true;
     case GIMPLE_OMP_TARGET:
       switch (gimple_omp_target_kind (stmt))
 	{
 	case GF_OMP_TARGET_KIND_REGION:
+	case GF_OMP_TARGET_KIND_OACC_PARALLEL:
+	case GF_OMP_TARGET_KIND_OACC_KERNELS:
 	  return true;
 	default:
 	  return false;
diff --git gcc/gimplify.c gcc/gimplify.c
index ad48d51..eb9d930 100644
--- gcc/gimplify.c
+++ gcc/gimplify.c
@@ -7315,10 +7315,12 @@ gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p)
 				      OACC_DATA_CLAUSES (expr));
       break;
     case OACC_KERNELS:
-      stmt = gimple_build_oacc_kernels (body, OACC_KERNELS_CLAUSES (expr));
+      stmt = gimple_build_omp_target (body, GF_OMP_TARGET_KIND_OACC_KERNELS,
+				      OMP_CLAUSES (expr));
       break;
     case OACC_PARALLEL:
-      stmt = gimple_build_oacc_parallel (body, OACC_PARALLEL_CLAUSES (expr));
+      stmt = gimple_build_omp_target (body, GF_OMP_TARGET_KIND_OACC_PARALLEL,
+				      OMP_CLAUSES (expr));
       break;
     case OMP_SECTIONS:
       stmt = gimple_build_omp_sections (body, OMP_CLAUSES (expr));
diff --git gcc/omp-low.c gcc/omp-low.c
index 6fed38f..39e2f22 100644
--- gcc/omp-low.c
+++ gcc/omp-low.c
@@ -272,10 +272,12 @@ oacc_max_threads (omp_context *ctx)
      Scan for the innermost vector_length clause.  */
   for (omp_context *oc = ctx; oc; oc = oc->outer)
     {
-      if (gimple_code (oc->stmt) != GIMPLE_OACC_PARALLEL)
+      if (gimple_code (oc->stmt) != GIMPLE_OMP_TARGET
+	  || (gimple_omp_target_kind (oc->stmt)
+	      != GF_OMP_TARGET_KIND_OACC_PARALLEL))
 	continue;
 
-      clauses = gimple_oacc_parallel_clauses (oc->stmt);
+      clauses = gimple_omp_target_clauses (oc->stmt);
 
       vector_length = find_omp_clause (clauses, OMP_CLAUSE_VECTOR_LENGTH);
       if (vector_length)
@@ -2643,28 +2645,7 @@ scan_omp_target (gimple stmt, omp_context *outer_ctx)
 {
   omp_context *ctx;
   tree name;
-  bool offloaded;
-  void (*gimple_omp_set_child_fn) (gimple, tree);
-  tree (*gimple_omp_clauses) (const_gimple);
-
-  offloaded = is_gimple_omp_offloaded (stmt);
-  switch (gimple_code (stmt))
-    {
-    case GIMPLE_OACC_KERNELS:
-      gimple_omp_set_child_fn = gimple_oacc_kernels_set_child_fn;
-      gimple_omp_clauses = gimple_oacc_kernels_clauses;
-      break;
-    case GIMPLE_OACC_PARALLEL:
-      gimple_omp_set_child_fn = gimple_oacc_parallel_set_child_fn;
-      gimple_omp_clauses = gimple_oacc_parallel_clauses;
-      break;
-    case GIMPLE_OMP_TARGET:
-      gimple_omp_set_child_fn = gimple_omp_target_set_child_fn;
-      gimple_omp_clauses = gimple_omp_target_clauses;
-      break;
-    default:
-      gcc_unreachable ();
-    }
+  bool offloaded = is_gimple_omp_offloaded (stmt);
 
   if (is_gimple_omp_oacc_specifically (stmt))
     {
@@ -2689,10 +2670,10 @@ scan_omp_target (gimple stmt, omp_context *outer_ctx)
 					     0, 0);
 
       create_omp_child_function (ctx, false);
-      gimple_omp_set_child_fn (stmt, ctx->cb.dst_fn);
+      gimple_omp_target_set_child_fn (stmt, ctx->cb.dst_fn);
     }
 
-  scan_sharing_clauses (gimple_omp_clauses (stmt), ctx);
+  scan_sharing_clauses (gimple_omp_target_clauses (stmt), ctx);
   scan_omp (gimple_omp_body_ptr (stmt), ctx);
 
   if (TYPE_FIELDS (ctx->record_type) == NULL)
@@ -2944,8 +2925,6 @@ check_omp_nesting_restrictions (gimple stmt, omp_context *ctx)
 		      "of work-sharing, critical, ordered, master or explicit "
 		      "task region");
 	    return false;
-	  case GIMPLE_OACC_KERNELS:
-	  case GIMPLE_OACC_PARALLEL:
 	  case GIMPLE_OMP_PARALLEL:
 	    return true;
 	  default:
@@ -3203,8 +3182,6 @@ scan_omp_1_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
       scan_omp (gimple_omp_body_ptr (stmt), ctx);
       break;
 
-    case GIMPLE_OACC_KERNELS:
-    case GIMPLE_OACC_PARALLEL:
     case GIMPLE_OMP_TARGET:
       scan_omp_target (stmt, ctx);
       break;
@@ -8780,42 +8757,24 @@ expand_omp_target (struct omp_region *region)
   gimple entry_stmt, stmt;
   edge e;
   bool offloaded, data_region;
-  tree (*gimple_omp_child_fn) (const_gimple);
-  tree (*gimple_omp_data_arg) (const_gimple);
 
   entry_stmt = last_stmt (region->entry);
   new_bb = region->entry;
 
   offloaded = is_gimple_omp_offloaded (entry_stmt);
-  data_region = false;
-  switch (region->type)
+  switch (gimple_omp_target_kind (entry_stmt))
     {
-    case GIMPLE_OACC_KERNELS:
-      gimple_omp_child_fn = gimple_oacc_kernels_child_fn;
-      gimple_omp_data_arg = gimple_oacc_kernels_data_arg;
+    case GF_OMP_TARGET_KIND_REGION:
+    case GF_OMP_TARGET_KIND_UPDATE:
+    case GF_OMP_TARGET_KIND_OACC_PARALLEL:
+    case GF_OMP_TARGET_KIND_OACC_KERNELS:
+    case GF_OMP_TARGET_KIND_OACC_UPDATE:
+    case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA:
+      data_region = false;
       break;
-    case GIMPLE_OACC_PARALLEL:
-      gimple_omp_child_fn = gimple_oacc_parallel_child_fn;
-      gimple_omp_data_arg = gimple_oacc_parallel_data_arg;
-      break;
-    case GIMPLE_OMP_TARGET:
-      switch (gimple_omp_target_kind (entry_stmt))
-	{
-	case GF_OMP_TARGET_KIND_DATA:
-	case GF_OMP_TARGET_KIND_OACC_DATA:
-	  data_region = true;
-	  break;
-	case GF_OMP_TARGET_KIND_REGION:
-	case GF_OMP_TARGET_KIND_UPDATE:
-	case GF_OMP_TARGET_KIND_OACC_UPDATE:
-	case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA:
-	  break;
-	default:
-	  gcc_unreachable ();
-	}
-
-      gimple_omp_child_fn = gimple_omp_target_child_fn;
-      gimple_omp_data_arg = gimple_omp_target_data_arg;
+    case GF_OMP_TARGET_KIND_DATA:
+    case GF_OMP_TARGET_KIND_OACC_DATA:
+      data_region = true;
       break;
     default:
       gcc_unreachable ();
@@ -8825,7 +8784,7 @@ expand_omp_target (struct omp_region *region)
   child_cfun = NULL;
   if (offloaded)
     {
-      child_fn = gimple_omp_child_fn (entry_stmt);
+      child_fn = gimple_omp_target_child_fn (entry_stmt);
       child_cfun = DECL_STRUCT_FUNCTION (child_fn);
     }
 
@@ -8854,13 +8813,14 @@ expand_omp_target (struct omp_region *region)
 	 a function call that has been inlined, the original PARM_DECL
 	 .OMP_DATA_I may have been converted into a different local
 	 variable.  In which case, we need to keep the assignment.  */
-      if (gimple_omp_data_arg (entry_stmt))
+      tree data_arg = gimple_omp_target_data_arg (entry_stmt);
+      if (data_arg)
 	{
 	  basic_block entry_succ_bb = single_succ (entry_bb);
 	  gimple_stmt_iterator gsi;
 	  tree arg;
 	  gimple tgtcopy_stmt = NULL;
-	  tree sender = TREE_VEC_ELT (gimple_omp_data_arg (entry_stmt), 0);
+	  tree sender = TREE_VEC_ELT (data_arg, 0);
 
 	  for (gsi = gsi_start_bb (entry_succ_bb); ; gsi_next (&gsi))
 	    {
@@ -8994,49 +8954,38 @@ expand_omp_target (struct omp_region *region)
   tree t1, t2, t3, t4, device, cond, c, clauses;
   enum built_in_function start_ix;
   location_t clause_loc;
-  tree (*gimple_omp_clauses) (const_gimple);
 
-  switch (region->type)
+  switch (gimple_omp_target_kind (entry_stmt))
     {
-    case GIMPLE_OACC_KERNELS:
-      gimple_omp_clauses = gimple_oacc_kernels_clauses;
-      start_ix = BUILT_IN_GOACC_KERNELS;
+    case GF_OMP_TARGET_KIND_REGION:
+      start_ix = BUILT_IN_GOMP_TARGET;
       break;
-    case GIMPLE_OACC_PARALLEL:
-      gimple_omp_clauses = gimple_oacc_parallel_clauses;
+    case GF_OMP_TARGET_KIND_DATA:
+      start_ix = BUILT_IN_GOMP_TARGET_DATA;
+      break;
+    case GF_OMP_TARGET_KIND_UPDATE:
+      start_ix = BUILT_IN_GOMP_TARGET_UPDATE;
+      break;
+    case GF_OMP_TARGET_KIND_OACC_PARALLEL:
       start_ix = BUILT_IN_GOACC_PARALLEL;
       break;
-    case GIMPLE_OMP_TARGET:
-      gimple_omp_clauses = gimple_omp_target_clauses;
-      switch (gimple_omp_target_kind (entry_stmt))
-	{
-	case GF_OMP_TARGET_KIND_REGION:
-	  start_ix = BUILT_IN_GOMP_TARGET;
-	  break;
-	case GF_OMP_TARGET_KIND_DATA:
-	  start_ix = BUILT_IN_GOMP_TARGET_DATA;
-	  break;
-	case GF_OMP_TARGET_KIND_UPDATE:
-	  start_ix = BUILT_IN_GOMP_TARGET_UPDATE;
-	  break;
-	case GF_OMP_TARGET_KIND_OACC_DATA:
-	  start_ix = BUILT_IN_GOACC_DATA_START;
-	  break;
-	case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA:
-	  start_ix = BUILT_IN_GOACC_ENTER_EXIT_DATA;
-	  break;
-	case GF_OMP_TARGET_KIND_OACC_UPDATE:
-	  start_ix = BUILT_IN_GOACC_UPDATE;
-	  break;
-	default:
-	  gcc_unreachable ();
-	}
+    case GF_OMP_TARGET_KIND_OACC_KERNELS:
+      start_ix = BUILT_IN_GOACC_KERNELS;
+      break;
+    case GF_OMP_TARGET_KIND_OACC_DATA:
+      start_ix = BUILT_IN_GOACC_DATA_START;
+      break;
+    case GF_OMP_TARGET_KIND_OACC_UPDATE:
+      start_ix = BUILT_IN_GOACC_UPDATE;
+      break;
+    case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA:
+      start_ix = BUILT_IN_GOACC_ENTER_EXIT_DATA;
       break;
     default:
       gcc_unreachable ();
     }
 
-  clauses = gimple_omp_clauses (entry_stmt);
+  clauses = gimple_omp_target_clauses (entry_stmt);
 
   /* By default, the value of DEVICE is -1 (let runtime library choose)
      and there is no conditional.  */
@@ -9119,7 +9068,7 @@ expand_omp_target (struct omp_region *region)
     }
 
   gsi = gsi_last_bb (new_bb);
-  t = gimple_omp_data_arg (entry_stmt);
+  t = gimple_omp_target_data_arg (entry_stmt);
   if (t == NULL)
     {
       t1 = size_zero_node;
@@ -9331,8 +9280,6 @@ expand_omp (struct omp_region *region)
 	  expand_omp_atomic (region);
 	  break;
 
-	case GIMPLE_OACC_KERNELS:
-	case GIMPLE_OACC_PARALLEL:
 	case GIMPLE_OMP_TARGET:
 	  expand_omp_target (region);
 	  break;
@@ -9679,22 +9626,18 @@ oacc_initialize_reduction_data (tree clauses, tree nthreads,
   tree c, t, oc;
   gimple stmt;
   omp_context *octx;
-  tree (*gimple_omp_clauses) (const_gimple);
-  void (*gimple_omp_set_clauses) (gimple, tree);
 
   /* Find the innermost PARALLEL openmp context.  FIXME: OpenACC kernels
      may require extra care unless they are converted to openmp for loops.  */
-
-  if (gimple_code (ctx->stmt) == GIMPLE_OACC_PARALLEL)
+  if (gimple_code (ctx->stmt) == GIMPLE_OMP_TARGET
+      && (gimple_omp_target_kind (ctx->stmt)
+	  == GF_OMP_TARGET_KIND_OACC_PARALLEL))
     octx = ctx;
   else
     octx = ctx->outer;
 
-  gimple_omp_clauses = gimple_oacc_parallel_clauses;
-  gimple_omp_set_clauses = gimple_oacc_parallel_set_clauses;
-
   /* Extract the clauses.  */
-  oc = gimple_omp_clauses (octx->stmt);
+  oc = gimple_omp_target_clauses (octx->stmt);
 
   /* Find the last outer clause.  */
   for (; oc && OMP_CLAUSE_CHAIN (oc); oc = OMP_CLAUSE_CHAIN (oc))
@@ -9744,7 +9687,7 @@ oacc_initialize_reduction_data (tree clauses, tree nthreads,
       if (oc)
 	OMP_CLAUSE_CHAIN (oc) = t;
       else
-	gimple_omp_set_clauses (octx->stmt, t);
+	gimple_omp_target_set_clauses (octx->stmt, t);
       OMP_CLAUSE_SIZE (t) = size;
       oc = t;
     }
@@ -11195,45 +11138,27 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
   location_t loc = gimple_location (stmt);
   bool offloaded, data_region;
   unsigned int map_cnt = 0;
-  tree (*gimple_omp_clauses) (const_gimple);
-  void (*gimple_omp_set_data_arg) (gimple, tree);
 
   offloaded = is_gimple_omp_offloaded (stmt);
-  data_region = false;
-  switch (gimple_code (stmt))
+  switch (gimple_omp_target_kind (stmt))
     {
-    case GIMPLE_OACC_KERNELS:
-      gimple_omp_clauses = gimple_oacc_kernels_clauses;
-      gimple_omp_set_data_arg = gimple_oacc_kernels_set_data_arg;
+    case GF_OMP_TARGET_KIND_REGION:
+    case GF_OMP_TARGET_KIND_UPDATE:
+    case GF_OMP_TARGET_KIND_OACC_PARALLEL:
+    case GF_OMP_TARGET_KIND_OACC_KERNELS:
+    case GF_OMP_TARGET_KIND_OACC_UPDATE:
+    case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA:
+      data_region = false;
       break;
-    case GIMPLE_OACC_PARALLEL:
-      gimple_omp_clauses = gimple_oacc_parallel_clauses;
-      gimple_omp_set_data_arg = gimple_oacc_parallel_set_data_arg;
-      break;
-    case GIMPLE_OMP_TARGET:
-      switch (gimple_omp_target_kind (stmt))
-	{
-	case GF_OMP_TARGET_KIND_DATA:
-	case GF_OMP_TARGET_KIND_OACC_DATA:
-	  data_region = true;
-	  break;
-	case GF_OMP_TARGET_KIND_REGION:
-	case GF_OMP_TARGET_KIND_UPDATE:
-	case GF_OMP_TARGET_KIND_OACC_UPDATE:
-	case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA:
-	  break;
-	default:
-	  gcc_unreachable ();
-	}
-
-      gimple_omp_clauses = gimple_omp_target_clauses;
-      gimple_omp_set_data_arg = gimple_omp_target_set_data_arg;
+    case GF_OMP_TARGET_KIND_DATA:
+    case GF_OMP_TARGET_KIND_OACC_DATA:
+      data_region = true;
       break;
     default:
       gcc_unreachable ();
     }
 
-  clauses = gimple_omp_clauses (stmt);
+  clauses = gimple_omp_target_clauses (stmt);
 
   tgt_bind = NULL;
   tgt_body = NULL;
@@ -11250,15 +11175,9 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
 
   irlist = NULL;
   orlist = NULL;
-  switch (gimple_code (stmt))
-    {
-    case GIMPLE_OACC_KERNELS:
-    case GIMPLE_OACC_PARALLEL:
-      oacc_process_reduction_data (&tgt_body, &irlist, &orlist, ctx);
-      break;
-    default:
-      break;
-    }
+  if (offloaded
+      && is_gimple_omp_oacc_specifically (stmt))
+    oacc_process_reduction_data (&tgt_body, &irlist, &orlist, ctx);
 
   for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
     switch (OMP_CLAUSE_CODE (c))
@@ -11390,7 +11309,7 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
       DECL_NAMELESS (TREE_VEC_ELT (t, 2)) = 1;
       TREE_ADDRESSABLE (TREE_VEC_ELT (t, 2)) = 1;
       TREE_STATIC (TREE_VEC_ELT (t, 2)) = 1;
-      gimple_omp_set_data_arg (stmt, t);
+      gimple_omp_target_set_data_arg (stmt, t);
 
       vec<constructor_elt, va_gc> *vsize;
       vec<constructor_elt, va_gc> *vkind;
@@ -11457,8 +11376,8 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
 			    || TREE_CODE (TREE_TYPE (ovar)) != ARRAY_TYPE);
 		if (maybe_lookup_oacc_reduction (var, ctx))
 		  {
-		    gcc_assert (gimple_code (stmt) == GIMPLE_OACC_KERNELS
-				|| gimple_code (stmt) == GIMPLE_OACC_PARALLEL);
+		    gcc_assert (offloaded
+				&& is_gimple_omp_oacc_specifically (stmt));
 		    gimplify_assign (x, var, &ilist);
 		  }
 		else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
@@ -11802,8 +11721,6 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p, omp_context *ctx)
 			lower_omp_regimplify_p, ctx ? NULL : &wi, NULL))
 	gimple_regimplify_operands (stmt, gsi_p);
       break;
-    case GIMPLE_OACC_KERNELS:
-    case GIMPLE_OACC_PARALLEL:
     case GIMPLE_OMP_TARGET:
       ctx = maybe_lookup_ctx (stmt);
       gcc_assert (ctx);
@@ -12095,8 +12012,6 @@ diagnose_sb_1 (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
     {
     WALK_SUBSTMTS;
 
-    case GIMPLE_OACC_KERNELS:
-    case GIMPLE_OACC_PARALLEL:
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
     case GIMPLE_OMP_SECTIONS:
@@ -12155,8 +12070,6 @@ diagnose_sb_2 (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
     {
     WALK_SUBSTMTS;
 
-    case GIMPLE_OACC_KERNELS:
-    case GIMPLE_OACC_PARALLEL:
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
     case GIMPLE_OMP_SECTIONS:
@@ -12252,8 +12165,6 @@ make_gimple_omp_edges (basic_block bb, struct omp_region **region,
 
   switch (code)
     {
-    case GIMPLE_OACC_KERNELS:
-    case GIMPLE_OACC_PARALLEL:
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
     case GIMPLE_OMP_FOR:
diff --git gcc/testsuite/gfortran.dg/goacc/private-1.f95 gcc/testsuite/gfortran.dg/goacc/private-1.f95
index 54c027d..23ce95a 100644
--- gcc/testsuite/gfortran.dg/goacc/private-1.f95
+++ gcc/testsuite/gfortran.dg/goacc/private-1.f95
@@ -31,7 +31,7 @@ program test
   end do
   !$acc end parallel
 end program test
-! { dg-final { scan-tree-dump-times "pragma acc parallel" 3 "omplower" } }
+! { dg-final { scan-tree-dump-times "pragma omp target oacc_parallel" 3 "omplower" } }
 ! { dg-final { scan-tree-dump-times "private\\(i\\)" 3 "omplower" } }
 ! { dg-final { scan-tree-dump-times "private\\(j\\)" 2 "omplower" } }
 ! { dg-final { scan-tree-dump-times "private\\(k\\)" 1 "omplower" } }
diff --git gcc/tree-inline.c gcc/tree-inline.c
index 54b3514..89cb1eb 100644
--- gcc/tree-inline.c
+++ gcc/tree-inline.c
@@ -1395,10 +1395,6 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
 	  copy = gimple_build_wce (s1);
 	  break;
 
-	case GIMPLE_OACC_KERNELS:
-	case GIMPLE_OACC_PARALLEL:
-          gcc_unreachable ();
-
 	case GIMPLE_OMP_PARALLEL:
 	  s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
 	  copy = gimple_build_omp_parallel
@@ -4112,8 +4108,6 @@ estimate_num_insns (gimple stmt, eni_weights *weights)
               + estimate_num_insns_seq (gimple_omp_body (stmt), weights)
               + estimate_num_insns_seq (gimple_omp_for_pre_body (stmt), weights));
 
-    case GIMPLE_OACC_KERNELS:
-    case GIMPLE_OACC_PARALLEL:
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
     case GIMPLE_OMP_CRITICAL:
diff --git gcc/tree-nested.c gcc/tree-nested.c
index b5d6543..4da6297 100644
--- gcc/tree-nested.c
+++ gcc/tree-nested.c
@@ -1325,10 +1325,6 @@ convert_nonlocal_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
 	}
       break;
 
-    case GIMPLE_OACC_KERNELS:
-    case GIMPLE_OACC_PARALLEL:
-      gcc_unreachable ();
-
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
       save_suppress = info->suppress_expansion;
@@ -1898,10 +1894,6 @@ convert_local_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
 
   switch (gimple_code (stmt))
     {
-    case GIMPLE_OACC_KERNELS:
-    case GIMPLE_OACC_PARALLEL:
-      gcc_unreachable ();
-
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
       save_suppress = info->suppress_expansion;
@@ -2289,10 +2281,6 @@ convert_tramp_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
 	break;
       }
 
-    case GIMPLE_OACC_KERNELS:
-    case GIMPLE_OACC_PARALLEL:
-      gcc_unreachable ();
-
     case GIMPLE_OMP_TARGET:
       gcc_assert (!is_gimple_omp_oacc_specifically (stmt));
       if (gimple_omp_target_kind (stmt) != GF_OMP_TARGET_KIND_REGION)
@@ -2360,10 +2348,6 @@ convert_gimple_call (gimple_stmt_iterator *gsi, bool *handled_ops_p,
 	}
       break;
 
-    case GIMPLE_OACC_KERNELS:
-    case GIMPLE_OACC_PARALLEL:
-      gcc_unreachable ();
-
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
       save_static_chain_added = info->static_chain_added;


Grüße,
 Thomas

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 472 bytes --]

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

* Nested OpenACC/OpenMP constructs (was: OpenACC GIMPLE_OACC_* -- or not?)
  2014-11-12 13:46                       ` Jakub Jelinek
  2014-12-10  9:58                         ` OpenACC GIMPLE_OACC_* -- or not? Thomas Schwinge
@ 2014-12-10 10:02                         ` Thomas Schwinge
  2014-12-10 10:10                           ` Thomas Schwinge
  1 sibling, 1 reply; 44+ messages in thread
From: Thomas Schwinge @ 2014-12-10 10:02 UTC (permalink / raw)
  To: Jakub Jelinek, gcc-patches

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

Hi!

On Wed, 12 Nov 2014 14:45:02 +0100, Jakub Jelinek <jakub@redhat.com> wrote:
> please make sure we'll have
> some tests on mixing OpenMP and OpenACC directives in the same functions
> (it is fine if we error out on combinations that don't make sense or are
> too hard to support).
> E.g. supporting OpenACC #pragma omp target counterpart inside
> of #pragma omp parallel or #pragma omp task should be presumably fine,
> supporting OpenACC inside of #pragma omp target should be IMHO just
> diagnosed, mixing target data and openacc is generically hard to diagnose,
> perhaps at runtime, supporting #pragma omp directives inside of OpenACC
> regions not needed (perhaps there are exceptions you want to support?).

We have not yet tested such nested OpenACC/OpenMP constructs (one thing
after the other), so I'm not confident to claim support for that, and
earlier on had already enable checking for such nesting.  In r218569, I
have now committed to gomp-4_0-branch the following patch to rework this:

commit 30b2cd7ac340764d4f7eb14730b16a49e8799e32
Author: tschwinge <tschwinge@138bc75d-0d04-0410-961f-82ee72b054a4>
Date:   Wed Dec 10 09:52:42 2014 +0000

    OpenACC: Rework nested constructs checking.
    
    	gcc/
    	* omp-low.c (scan_omp_target): Remove taskreg_nesting_level and
    	target_nesting_level assertions.
    	(check_omp_nesting_restrictions): Rework OpenACC constructs
    	handling.  Update and extend the relevant test cases.
    
    git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@218569 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/ChangeLog.gomp                                 |   7 +
 gcc/omp-low.c                                      | 124 +++++++-----
 .../c-c++-common/goacc-gomp/nesting-fail-1.c       | 212 +++++++++++++--------
 gcc/testsuite/c-c++-common/goacc/nesting-1.c       |  49 +++++
 gcc/testsuite/c-c++-common/goacc/nesting-2.c       |  11 --
 gcc/testsuite/c-c++-common/goacc/nesting-fail-1.c  |  22 ++-
 .../gfortran.dg/goacc/parallel-kernels-regions.f95 |  25 ++-
 7 files changed, 288 insertions(+), 162 deletions(-)

diff --git gcc/ChangeLog.gomp gcc/ChangeLog.gomp
index 06e8583..970e744 100644
--- gcc/ChangeLog.gomp
+++ gcc/ChangeLog.gomp
@@ -1,4 +1,11 @@
 2014-12-10  Thomas Schwinge  <thomas@codesourcery.com>
+
+	* omp-low.c (scan_omp_target): Remove taskreg_nesting_level and
+	target_nesting_level assertions.
+	(check_omp_nesting_restrictions): Rework OpenACC constructs
+	handling.  Update and extend the relevant test cases.
+
+2014-12-10  Thomas Schwinge  <thomas@codesourcery.com>
 	    Bernd Schmidt  <bernds@codesourcery.com>
 
 	* gimple.def (GIMPLE_OACC_KERNELS, GIMPLE_OACC_PARALLEL): Merge
diff --git gcc/omp-low.c gcc/omp-low.c
index 39e2f22..d16e2de 100644
--- gcc/omp-low.c
+++ gcc/omp-low.c
@@ -2647,12 +2647,6 @@ scan_omp_target (gimple stmt, omp_context *outer_ctx)
   tree name;
   bool offloaded = is_gimple_omp_offloaded (stmt);
 
-  if (is_gimple_omp_oacc_specifically (stmt))
-    {
-      gcc_assert (taskreg_nesting_level == 0);
-      gcc_assert (target_nesting_level == 0);
-    }
-
   ctx = new_omp_context (stmt, outer_ctx);
   ctx->field_map = splay_tree_new (splay_tree_compare_pointers, 0, 0);
   ctx->default_kind = OMP_CLAUSE_DEFAULT_SHARED;
@@ -2706,46 +2700,26 @@ scan_omp_teams (gimple stmt, omp_context *outer_ctx)
   scan_omp (gimple_omp_body_ptr (stmt), ctx);
 }
 
-/* Check OpenMP nesting restrictions.  */
+/* Check nesting restrictions.  */
 static bool
 check_omp_nesting_restrictions (gimple stmt, omp_context *ctx)
 {
-  /* TODO: While the OpenACC specification does allow for certain kinds of
-     nesting, we don't support many of these yet.  */
-  if (is_gimple_omp (stmt)
-      && is_gimple_omp_oacc_specifically (stmt))
+  /* TODO: Some OpenACC/OpenMP nesting should be allowed.  */
+
+  /* No nesting of non-OpenACC STMT (that is, an OpenMP one, or a GOMP builtin)
+     inside an OpenACC CTX.  */
+  if (!(is_gimple_omp (stmt)
+	&& is_gimple_omp_oacc_specifically (stmt)))
     {
-      /* Regular handling of OpenACC loop constructs.  */
-      if (gimple_code (stmt) == GIMPLE_OMP_FOR
-	  && gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_OACC_LOOP)
-	goto cont;
-      /* No nesting of OpenACC STMT inside any OpenACC or OpenMP CTX different
-	 from an OpenACC data construct.  */
-      for (omp_context *ctx_ = ctx; ctx_ != NULL; ctx_ = ctx_->outer)
-	if (is_gimple_omp (ctx_->stmt)
-	    && !(gimple_code (ctx_->stmt) == GIMPLE_OMP_TARGET
-		 && (gimple_omp_target_kind (ctx_->stmt)
-		     == GF_OMP_TARGET_KIND_OACC_DATA)))
-	  {
-	    error_at (gimple_location (stmt),
-		      "may not be nested");
-	    return false;
-	  }
-    }
-  else
-    {
-      /* No nesting of non-OpenACC STMT (that is, an OpenMP one, or a GOMP
-	 builtin) inside any OpenACC CTX.  */
       for (omp_context *ctx_ = ctx; ctx_ != NULL; ctx_ = ctx_->outer)
 	if (is_gimple_omp (ctx_->stmt)
 	    && is_gimple_omp_oacc_specifically (ctx_->stmt))
 	  {
 	    error_at (gimple_location (stmt),
-		      "may not be nested");
+		      "non-OpenACC construct inside of OpenACC region");
 	    return false;
 	  }
     }
- cont:
 
   if (ctx != NULL)
     {
@@ -3003,20 +2977,74 @@ check_omp_nesting_restrictions (gimple stmt, omp_context *ctx)
       break;
     case GIMPLE_OMP_TARGET:
       for (; ctx != NULL; ctx = ctx->outer)
-	if (gimple_code (ctx->stmt) == GIMPLE_OMP_TARGET
-	    && gimple_omp_target_kind (ctx->stmt) == GF_OMP_TARGET_KIND_REGION)
-	  {
-	    const char *name;
-	    switch (gimple_omp_target_kind (stmt))
-	      {
-	      case GF_OMP_TARGET_KIND_REGION: name = "target"; break;
-	      case GF_OMP_TARGET_KIND_DATA: name = "target data"; break;
-	      case GF_OMP_TARGET_KIND_UPDATE: name = "target update"; break;
-	      default: gcc_unreachable ();
-	      }
-	    warning_at (gimple_location (stmt), 0,
-			"%s construct inside of target region", name);
-	  }
+	{
+	  if (gimple_code (ctx->stmt) != GIMPLE_OMP_TARGET)
+	    {
+	      if (is_gimple_omp (stmt)
+		  && is_gimple_omp_oacc_specifically (stmt)
+		  && is_gimple_omp (ctx->stmt))
+		{
+		  error_at (gimple_location (stmt),
+			    "OpenACC construct inside of non-OpenACC region");
+		  return false;
+		}
+	      continue;
+	    }
+
+	  const char *stmt_name, *ctx_stmt_name;
+	  switch (gimple_omp_target_kind (stmt))
+	    {
+	    case GF_OMP_TARGET_KIND_REGION: stmt_name = "target"; break;
+	    case GF_OMP_TARGET_KIND_DATA: stmt_name = "target data"; break;
+	    case GF_OMP_TARGET_KIND_UPDATE: stmt_name = "target update"; break;
+	    case GF_OMP_TARGET_KIND_OACC_PARALLEL: stmt_name = "parallel"; break;
+	    case GF_OMP_TARGET_KIND_OACC_KERNELS: stmt_name = "kernels"; break;
+	    case GF_OMP_TARGET_KIND_OACC_DATA: stmt_name = "data"; break;
+	    case GF_OMP_TARGET_KIND_OACC_UPDATE: stmt_name = "update"; break;
+	    case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA: stmt_name = "enter/exit data"; break;
+	    default: gcc_unreachable ();
+	    }
+	  switch (gimple_omp_target_kind (ctx->stmt))
+	    {
+	    case GF_OMP_TARGET_KIND_REGION: ctx_stmt_name = "target"; break;
+	    case GF_OMP_TARGET_KIND_DATA: ctx_stmt_name = "target data"; break;
+	    case GF_OMP_TARGET_KIND_OACC_PARALLEL: ctx_stmt_name = "parallel"; break;
+	    case GF_OMP_TARGET_KIND_OACC_KERNELS: ctx_stmt_name = "kernels"; break;
+	    case GF_OMP_TARGET_KIND_OACC_DATA: ctx_stmt_name = "data"; break;
+	    default: gcc_unreachable ();
+	    }
+
+	  /* OpenACC/OpenMP mismatch?  */
+	  if (is_gimple_omp_oacc_specifically (stmt)
+	      != is_gimple_omp_oacc_specifically (ctx->stmt))
+	    {
+	      error_at (gimple_location (stmt),
+			"%s %s construct inside of %s %s region",
+			(is_gimple_omp_oacc_specifically (stmt)
+			 ? "OpenACC" : "OpenMP"), stmt_name,
+			(is_gimple_omp_oacc_specifically (ctx->stmt)
+			 ? "OpenACC" : "OpenMP"), ctx_stmt_name);
+	      return false;
+	    }
+	  if (is_gimple_omp_offloaded (ctx->stmt))
+	    {
+	      /* No GIMPLE_OMP_TARGET inside offloaded OpenACC CTX.  */
+	      if (is_gimple_omp_oacc_specifically (ctx->stmt))
+		{
+		  error_at (gimple_location (stmt),
+			    "%s construct inside of %s region",
+			    stmt_name, ctx_stmt_name);
+		  return false;
+		}
+	      else
+		{
+		  gcc_assert (!is_gimple_omp_oacc_specifically (stmt));
+		  warning_at (gimple_location (stmt), 0,
+			      "%s construct inside of %s region",
+			      stmt_name, ctx_stmt_name);
+		}
+	    }
+	}
       break;
     default:
       break;
diff --git gcc/testsuite/c-c++-common/goacc-gomp/nesting-fail-1.c gcc/testsuite/c-c++-common/goacc-gomp/nesting-fail-1.c
index 59f41a8..d52c7c0 100644
--- gcc/testsuite/c-c++-common/goacc-gomp/nesting-fail-1.c
+++ gcc/testsuite/c-c++-common/goacc-gomp/nesting-fail-1.c
@@ -1,5 +1,3 @@
-/* TODO: Some of these should either be allowed or fail with a more sensible
-   error message.  */
 void
 f_omp (void)
 {
@@ -7,24 +5,30 @@ f_omp (void)
 
 #pragma omp parallel
   {
-#pragma acc parallel	/* { dg-error "may not be nested" } */
+#pragma acc parallel /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
     ;
-#pragma acc kernels	/* { dg-error "may not be nested" } */
+#pragma acc kernels /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
     ;
-#pragma acc data	/* { dg-error "may not be nested" } */
+#pragma acc data /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
     ;
+#pragma acc update host(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
+#pragma acc enter data copyin(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
+#pragma acc exit data delete(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
   }
 
 #pragma omp for
   for (i = 0; i < 3; i++)
     {
-#pragma acc parallel	/* { dg-error "may not be nested" } */
+#pragma acc parallel /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
       ;
-#pragma acc kernels	/* { dg-error "may not be nested" } */
+#pragma acc kernels /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
       ;
-#pragma acc data	/* { dg-error "may not be nested" } */
+#pragma acc data /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
       ;
-#pragma acc loop	/* { dg-error "may not be closely nested" } */
+#pragma acc update host(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
+#pragma acc enter data copyin(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
+#pragma acc exit data delete(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
+#pragma acc loop /* { dg-error "may not be closely nested" } */
       for (i = 0; i < 2; ++i)
 	;
     }
@@ -32,22 +36,34 @@ f_omp (void)
 #pragma omp sections
   {
     {
-#pragma acc parallel	/* { dg-error "may not be nested" } */
+#pragma acc parallel /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
       ;
     }
 #pragma omp section
     {
-#pragma acc kernels	/* { dg-error "may not be nested" } */
+#pragma acc kernels /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
       ;
     }
 #pragma omp section
     {
-#pragma acc data	/* { dg-error "may not be nested" } */
+#pragma acc data /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
       ;
     }
 #pragma omp section
     {
-#pragma acc loop	/* { dg-error "may not be closely nested" } */
+#pragma acc update host(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
+    }
+#pragma omp section
+    {
+#pragma acc enter data copyin(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
+    }
+#pragma omp section
+    {
+#pragma acc exit data delete(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
+    }
+#pragma omp section
+    {
+#pragma acc loop /* { dg-error "may not be closely nested" } */
       for (i = 0; i < 2; ++i)
 	;
     }
@@ -55,105 +71,121 @@ f_omp (void)
 
 #pragma omp single
   {
-#pragma acc parallel	/* { dg-error "may not be nested" } */
+#pragma acc parallel /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
     ;
-#pragma acc kernels	/* { dg-error "may not be nested" } */
+#pragma acc kernels /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
     ;
-#pragma acc data	/* { dg-error "may not be nested" } */
+#pragma acc data /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
     ;
-#pragma acc loop	/* { dg-error "may not be closely nested" } */
+#pragma acc update host(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
+#pragma acc enter data copyin(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
+#pragma acc exit data delete(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
+#pragma acc loop /* { dg-error "may not be closely nested" } */
     for (i = 0; i < 2; ++i)
       ;
   }
 
 #pragma omp task
   {
-#pragma acc parallel	/* { dg-error "may not be nested" } */
+#pragma acc parallel /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
     ;
-#pragma acc kernels	/* { dg-error "may not be nested" } */
+#pragma acc kernels /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
     ;
-#pragma acc data	/* { dg-error "may not be nested" } */
+#pragma acc data /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
     ;
-#pragma acc loop	/* { dg-error "may not be closely nested" } */
+#pragma acc update host(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
+#pragma acc enter data copyin(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
+#pragma acc exit data delete(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
+#pragma acc loop /* { dg-error "may not be closely nested" } */
     for (i = 0; i < 2; ++i)
       ;
   }
 
 #pragma omp master
   {
-#pragma acc parallel	/* { dg-error "may not be nested" } */
+#pragma acc parallel /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
     ;
-#pragma acc kernels	/* { dg-error "may not be nested" } */
+#pragma acc kernels /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
     ;
-#pragma acc data	/* { dg-error "may not be nested" } */
+#pragma acc data /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
     ;
-#pragma acc loop	/* { dg-error "may not be closely nested" } */
+#pragma acc update host(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
+#pragma acc enter data copyin(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
+#pragma acc exit data delete(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
+#pragma acc loop /* { dg-error "may not be closely nested" } */
     for (i = 0; i < 2; ++i)
       ;
   }
 
 #pragma omp critical
   {
-#pragma acc parallel	/* { dg-error "may not be nested" } */
+#pragma acc parallel /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
     ;
-#pragma acc kernels	/* { dg-error "may not be nested" } */
+#pragma acc kernels /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
     ;
-#pragma acc data	/* { dg-error "may not be nested" } */
+#pragma acc data /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
     ;
-#pragma acc loop	/* { dg-error "may not be closely nested" } */
+#pragma acc update host(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
+#pragma acc enter data copyin(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
+#pragma acc exit data delete(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
+#pragma acc loop /* { dg-error "may not be closely nested" } */
     for (i = 0; i < 2; ++i)
       ;
   }
 
 #pragma omp ordered
   {
-#pragma acc parallel	/* { dg-error "may not be nested" } */
+#pragma acc parallel /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
     ;
-#pragma acc kernels	/* { dg-error "may not be nested" } */
+#pragma acc kernels /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
     ;
-#pragma acc data	/* { dg-error "may not be nested" } */
+#pragma acc data /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
     ;
-#pragma acc loop	/* { dg-error "may not be closely nested" } */
+#pragma acc update host(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
+#pragma acc enter data copyin(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
+#pragma acc exit data delete(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
+#pragma acc loop /* { dg-error "may not be closely nested" } */
     for (i = 0; i < 2; ++i)
       ;
   }
 
 #pragma omp target
   {
-#pragma acc parallel	/* { dg-error "may not be nested" } */
+#pragma acc parallel /* { dg-error "OpenACC parallel construct inside of OpenMP target region" } */
     ;
-#pragma acc kernels	/* { dg-error "may not be nested" } */
+#pragma acc kernels /* { dg-error "OpenACC kernels construct inside of OpenMP target region" } */
     ;
-#pragma acc data	/* { dg-error "may not be nested" } */
+#pragma acc data /* { dg-error "OpenACC data construct inside of OpenMP target region" } */
     ;
+#pragma acc update host(i) /* { dg-error "OpenACC update construct inside of OpenMP target region" } */
+#pragma acc enter data copyin(i) /* { dg-error "OpenACC enter/exit data construct inside of OpenMP target region" } */
+#pragma acc exit data delete(i) /* { dg-error "OpenACC enter/exit data construct inside of OpenMP target region" } */
 #pragma acc loop
     for (i = 0; i < 2; ++i)
       ;
   }
 }
 
-/* TODO: Some of these should either be allowed or fail with a more sensible
-   error message.  */
 void
 f_acc_parallel (void)
 {
 #pragma acc parallel
   {
-#pragma omp parallel	/* { dg-error "may not be nested" } */
+#pragma omp parallel /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     ;
   }
 
 #pragma acc parallel
   {
     int i;
-#pragma omp for		/* { dg-error "may not be nested" } */
+#pragma omp for /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     for (i = 0; i < 3; i++)
       ;
   }
 
 #pragma acc parallel
   {
-#pragma omp sections	/* { dg-error "may not be nested" } */
+#pragma omp sections /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     {
       ;
     }
@@ -161,25 +193,25 @@ f_acc_parallel (void)
 
 #pragma acc parallel
   {
-#pragma omp single	/* { dg-error "may not be nested" } */
+#pragma omp single /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     ;
   }
 
 #pragma acc parallel
   {
-#pragma omp task	/* { dg-error "may not be nested" } */
+#pragma omp task /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     ;
   }
 
 #pragma acc parallel
   {
-#pragma omp master	/* { dg-error "may not be nested" } */
+#pragma omp master /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     ;
   }
 
 #pragma acc parallel
   {
-#pragma omp critical	/* { dg-error "may not be nested" } */
+#pragma omp critical /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     ;
   }
 
@@ -187,44 +219,47 @@ f_acc_parallel (void)
   {
     int i;
 #pragma omp atomic write
-    i = 0;		/* { dg-error "may not be nested" } */
+    i = 0; /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
   }
 
 #pragma acc parallel
   {
-#pragma omp ordered	/* { dg-error "may not be nested" } */
+#pragma omp ordered /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     ;
   }
 
 #pragma acc parallel
   {
-#pragma omp target	/* { dg-error "may not be nested" } */
+    int i;
+
+#pragma omp target /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
+    ;
+#pragma omp target data /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     ;
+#pragma omp target update to(i) /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
   }
 }
 
-/* TODO: Some of these should either be allowed or fail with a more sensible
-   error message.  */
 void
 f_acc_kernels (void)
 {
 #pragma acc kernels
   {
-#pragma omp parallel	/* { dg-error "may not be nested" } */
+#pragma omp parallel /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     ;
   }
 
 #pragma acc kernels
   {
     int i;
-#pragma omp for		/* { dg-error "may not be nested" } */
+#pragma omp for /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     for (i = 0; i < 3; i++)
       ;
   }
 
 #pragma acc kernels
   {
-#pragma omp sections	/* { dg-error "may not be nested" } */
+#pragma omp sections /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     {
       ;
     }
@@ -232,25 +267,25 @@ f_acc_kernels (void)
 
 #pragma acc kernels
   {
-#pragma omp single	/* { dg-error "may not be nested" } */
+#pragma omp single /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     ;
   }
 
 #pragma acc kernels
   {
-#pragma omp task	/* { dg-error "may not be nested" } */
+#pragma omp task /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     ;
   }
 
 #pragma acc kernels
   {
-#pragma omp master	/* { dg-error "may not be nested" } */
+#pragma omp master /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     ;
   }
 
 #pragma acc kernels
   {
-#pragma omp critical	/* { dg-error "may not be nested" } */
+#pragma omp critical /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     ;
   }
 
@@ -258,44 +293,47 @@ f_acc_kernels (void)
   {
     int i;
 #pragma omp atomic write
-    i = 0;		/* { dg-error "may not be nested" } */
+    i = 0; /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
   }
 
 #pragma acc kernels
   {
-#pragma omp ordered	/* { dg-error "may not be nested" } */
+#pragma omp ordered /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     ;
   }
 
 #pragma acc kernels
   {
-#pragma omp target	/* { dg-error "may not be nested" } */
+    int i;
+
+#pragma omp target /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
+    ;
+#pragma omp target data /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     ;
+#pragma omp target update to(i) /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
   }
 }
 
-/* TODO: Some of these should either be allowed or fail with a more sensible
-   error message.  */
 void
 f_acc_data (void)
 {
 #pragma acc data
   {
-#pragma omp parallel	/* { dg-error "may not be nested" } */
+#pragma omp parallel /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     ;
   }
 
 #pragma acc data
   {
     int i;
-#pragma omp for		/* { dg-error "may not be nested" } */
+#pragma omp for /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     for (i = 0; i < 3; i++)
       ;
   }
 
 #pragma acc data
   {
-#pragma omp sections	/* { dg-error "may not be nested" } */
+#pragma omp sections /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     {
       ;
     }
@@ -303,25 +341,25 @@ f_acc_data (void)
 
 #pragma acc data
   {
-#pragma omp single	/* { dg-error "may not be nested" } */
+#pragma omp single /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     ;
   }
 
 #pragma acc data
   {
-#pragma omp task	/* { dg-error "may not be nested" } */
+#pragma omp task /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     ;
   }
 
 #pragma acc data
   {
-#pragma omp master	/* { dg-error "may not be nested" } */
+#pragma omp master /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     ;
   }
 
 #pragma acc data
   {
-#pragma omp critical	/* { dg-error "may not be nested" } */
+#pragma omp critical /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     ;
   }
 
@@ -329,24 +367,27 @@ f_acc_data (void)
   {
     int i;
 #pragma omp atomic write
-    i = 0;		/* { dg-error "may not be nested" } */
+    i = 0; /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
   }
 
 #pragma acc data
   {
-#pragma omp ordered	/* { dg-error "may not be nested" } */
+#pragma omp ordered /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     ;
   }
 
 #pragma acc data
   {
-#pragma omp target	/* { dg-error "may not be nested" } */
+    int i;
+
+#pragma omp target /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
+    ;
+#pragma omp target data /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     ;
+#pragma omp target update to(i) /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
   }
 }
 
-/* TODO: Some of these should either be allowed or fail with a more sensible
-   error message.  */
 void
 f_acc_loop (void)
 {
@@ -355,14 +396,14 @@ f_acc_loop (void)
 #pragma acc loop
   for (i = 0; i < 2; ++i)
     {
-#pragma omp parallel	/* { dg-error "may not be nested" } */
+#pragma omp parallel /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
       ;
     }
 
 #pragma acc loop
   for (i = 0; i < 2; ++i)
     {
-#pragma omp for		/* { dg-error "may not be nested" } */
+#pragma omp for /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
       for (i = 0; i < 3; i++)
 	;
     }
@@ -370,7 +411,7 @@ f_acc_loop (void)
 #pragma acc loop
   for (i = 0; i < 2; ++i)
     {
-#pragma omp sections	/* { dg-error "may not be nested" } */
+#pragma omp sections /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
       {
 	;
       }
@@ -379,28 +420,28 @@ f_acc_loop (void)
 #pragma acc loop
   for (i = 0; i < 2; ++i)
     {
-#pragma omp single	/* { dg-error "may not be nested" } */
+#pragma omp single /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
       ;
     }
 
 #pragma acc loop
   for (i = 0; i < 2; ++i)
     {
-#pragma omp task	/* { dg-error "may not be nested" } */
+#pragma omp task /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
       ;
     }
 
 #pragma acc loop
   for (i = 0; i < 2; ++i)
     {
-#pragma omp master	/* { dg-error "may not be nested" } */
+#pragma omp master /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
       ;
     }
 
 #pragma acc loop
   for (i = 0; i < 2; ++i)
     {
-#pragma omp critical	/* { dg-error "may not be nested" } */
+#pragma omp critical /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
       ;
     }
 
@@ -408,20 +449,23 @@ f_acc_loop (void)
   for (i = 0; i < 2; ++i)
     {
 #pragma omp atomic write
-      i = 0;		/* { dg-error "may not be nested" } */
+      i = 0; /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     }
 
 #pragma acc loop
   for (i = 0; i < 2; ++i)
     {
-#pragma omp ordered	/* { dg-error "may not be nested" } */
+#pragma omp ordered /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
       ;
     }
 
 #pragma acc loop
   for (i = 0; i < 2; ++i)
     {
-#pragma omp target	/* { dg-error "may not be nested" } */
+#pragma omp target /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
       ;
+#pragma omp target data /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
+      ;
+#pragma omp target update to(i) /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     }
 }
diff --git gcc/testsuite/c-c++-common/goacc/nesting-1.c gcc/testsuite/c-c++-common/goacc/nesting-1.c
index a489d2d..4fbf018 100644
--- gcc/testsuite/c-c++-common/goacc/nesting-1.c
+++ gcc/testsuite/c-c++-common/goacc/nesting-1.c
@@ -46,11 +46,60 @@ f_acc_data (void)
 #pragma acc kernels
     ;
 
+#pragma acc kernels
+    {
+#pragma acc loop
+      for (i = 0; i < 2; ++i)
+	;
+    }
+
 #pragma acc data
     ;
 
+#pragma acc update host(i)
+
+#pragma acc enter data copyin(i)
+
+#pragma acc exit data delete(i)
+
 #pragma acc loop
     for (i = 0; i < 2; ++i)
       ;
+
+#pragma acc data
+    {
+#pragma acc parallel
+      ;
+
+#pragma acc parallel
+      {
+#pragma acc loop
+	for (i = 0; i < 2; ++i)
+	  ;
+      }
+
+#pragma acc kernels
+      ;
+
+#pragma acc kernels
+      {
+#pragma acc loop
+	for (i = 0; i < 2; ++i)
+	  ;
+      }
+
+#pragma acc data
+      ;
+
+#pragma acc update host(i)
+
+#pragma acc enter data copyin(i)
+
+#pragma acc exit data delete(i)
+
+#pragma acc loop
+      for (i = 0; i < 2; ++i)
+	;
+    }
   }
 }
diff --git gcc/testsuite/c-c++-common/goacc/nesting-2.c gcc/testsuite/c-c++-common/goacc/nesting-2.c
deleted file mode 100644
index 0d350c6..0000000
--- gcc/testsuite/c-c++-common/goacc/nesting-2.c
+++ /dev/null
@@ -1,11 +0,0 @@
-int i;
-
-void
-f_acc_data (void)
-{
-#pragma acc data
-  {
-#pragma acc update host(i)
-#pragma acc enter data copyin(i)
-  }
-}
diff --git gcc/testsuite/c-c++-common/goacc/nesting-fail-1.c gcc/testsuite/c-c++-common/goacc/nesting-fail-1.c
index 00dc602..a833806 100644
--- gcc/testsuite/c-c++-common/goacc/nesting-fail-1.c
+++ gcc/testsuite/c-c++-common/goacc/nesting-fail-1.c
@@ -5,12 +5,17 @@ f_acc_parallel (void)
 {
 #pragma acc parallel
   {
-#pragma acc parallel	/* { dg-error "may not be nested" } */
+    int i;
+
+#pragma acc parallel /* { dg-bogus "parallel construct inside of parallel region" "not implemented" { xfail *-*-* } } */
     ;
-#pragma acc kernels	/* { dg-error "may not be nested" } */
+#pragma acc kernels /* { dg-bogus "kernels construct inside of parallel region" "not implemented" { xfail *-*-* } } */
     ;
-#pragma acc data	/* { dg-error "may not be nested" } */
+#pragma acc data /* { dg-error "data construct inside of parallel region" } */
     ;
+#pragma acc update host(i) /* { dg-error "update construct inside of parallel region" } */
+#pragma acc enter data copyin(i) /* { dg-error "enter/exit data construct inside of parallel region" } */
+#pragma acc exit data delete(i) /* { dg-error "enter/exit data construct inside of parallel region" } */
   }
 }
 
@@ -21,11 +26,16 @@ f_acc_kernels (void)
 {
 #pragma acc kernels
   {
-#pragma acc parallel	/* { dg-error "may not be nested" } */
+    int i;
+
+#pragma acc parallel /* { dg-bogus "parallel construct inside of kernels region" "not implemented" { xfail *-*-* } } */
     ;
-#pragma acc kernels	/* { dg-error "may not be nested" } */
+#pragma acc kernels /* { dg-bogus "kernels construct inside of kernels region" "not implemented" { xfail *-*-* } } */
     ;
-#pragma acc data	/* { dg-error "may not be nested" } */
+#pragma acc data /* { dg-error "data construct inside of kernels region" } */
     ;
+#pragma acc update host(i) /* { dg-error "update construct inside of kernels region" } */
+#pragma acc enter data copyin(i) /* { dg-error "enter/exit data construct inside of kernels region" } */
+#pragma acc exit data delete(i) /* { dg-error "enter/exit data construct inside of kernels region" } */
   }
 }
diff --git gcc/testsuite/gfortran.dg/goacc/parallel-kernels-regions.f95 gcc/testsuite/gfortran.dg/goacc/parallel-kernels-regions.f95
index 33cb9cb..8b8e989 100644
--- gcc/testsuite/gfortran.dg/goacc/parallel-kernels-regions.f95
+++ gcc/testsuite/gfortran.dg/goacc/parallel-kernels-regions.f95
@@ -1,7 +1,7 @@
 ! { dg-do compile } 
 
-! OpenACC 2.0 allows nested parallel/kernels regions
-! However, in middle-end there is check for nested parallel
+! OpenACC 2.0 allows nested parallel/kernels regions, but this is not yet
+! supported.
 
 program test
   implicit none
@@ -9,48 +9,47 @@ program test
   integer :: i
 
   !$acc parallel
-    !$acc kernels 
+    !$acc kernels ! { dg-bogus "kernels construct inside of parallel region" "not implemented" { xfail *-*-* } }
     !$acc end kernels
   !$acc end parallel
 
   !$acc parallel
-    !$acc parallel ! { dg-error "may not be nested" }
+    !$acc parallel ! { dg-bogus "parallel construct inside of parallel region" "not implemented" { xfail *-*-* } }
     !$acc end parallel
   !$acc end parallel
 
   !$acc parallel
-    !$acc parallel ! { dg-error "may not be nested" }
+    !$acc parallel ! { dg-bogus "parallel construct inside of parallel region" "not implemented" { xfail *-*-* } }
     !$acc end parallel
-    !$acc kernels 
+    !$acc kernels ! { dg-bogus "kernels construct inside of parallel region" "not implemented" { xfail *-*-* } }
     !$acc end kernels
   !$acc end parallel
 
   !$acc kernels
-    !$acc kernels 
+    !$acc kernels ! { dg-bogus "kernels construct inside of kernels region" "not implemented" { xfail *-*-* } }
     !$acc end kernels
   !$acc end kernels
 
   !$acc kernels
-    !$acc parallel 
+    !$acc parallel ! { dg-bogus "parallel construct inside of kernels region" "not implemented" { xfail *-*-* } }
     !$acc end parallel
   !$acc end kernels
 
   !$acc kernels
-    !$acc parallel 
+    !$acc parallel ! { dg-bogus "parallel construct inside of kernels region" "not implemented" { xfail *-*-* } }
     !$acc end parallel
-    !$acc kernels 
+    !$acc kernels ! { dg-bogus "kernels construct inside of kernels region" "not implemented" { xfail *-*-* } }
     !$acc end kernels
   !$acc end kernels
 
   !$acc parallel
-    !$acc data ! { dg-error "may not be nested" }
+    !$acc data ! { dg-error "data construct inside of parallel region" }
     !$acc end data
   !$acc end parallel
 
   !$acc kernels
-    !$acc data
+    !$acc data ! { dg-error "data construct inside of kernels region" }
     !$acc end data
   !$acc end kernels
   
 end program test
-! { dg-prune-output "Error: may not be nested" }


Grüße,
 Thomas

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 472 bytes --]

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

* Re: OpenACC GIMPLE_OACC_* -- or not?
  2014-12-10  9:58                         ` OpenACC GIMPLE_OACC_* -- or not? Thomas Schwinge
@ 2014-12-10 10:07                           ` Thomas Schwinge
  2014-12-10 10:10                             ` Jakub Jelinek
  0 siblings, 1 reply; 44+ messages in thread
From: Thomas Schwinge @ 2014-12-10 10:07 UTC (permalink / raw)
  To: gcc-patches, Jakub Jelinek

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

Hi Jakub!

On Wed, 10 Dec 2014 10:57:58 +0100, I wrote:
> In r218568, I applied the following to gomp-4_0-branch:
> 
> commit 28629d718a63a782170cfb06a4d0278de0779039
> Author: tschwinge <tschwinge@138bc75d-0d04-0410-961f-82ee72b054a4>
> Date:   Wed Dec 10 09:52:28 2014 +0000
> 
>     Merge GIMPLE_OACC_KERNELS and GIMPLE_OACC_PARALLEL into GIMPLE_OMP_TARGET.
>     
>     	gcc/
>     	* gimple.def (GIMPLE_OACC_KERNELS, GIMPLE_OACC_PARALLEL): Merge
>     	into GIMPLE_OMP_TARGET.  Update all users.

Regarding this change:

> --- gcc/gimple-walk.c
> +++ gcc/gimple-walk.c
> @@ -304,36 +304,6 @@ walk_gimple_op (gimple stmt, walk_tree_fn callback_op,
>  	return ret;
>        break;
>  
> -    case GIMPLE_OACC_KERNELS:
> -      ret = walk_tree (gimple_oacc_kernels_clauses_ptr (stmt), callback_op,
> -		       wi, pset);
> -      if (ret)
> -	return ret;
> -      ret = walk_tree (gimple_oacc_kernels_child_fn_ptr (stmt), callback_op,
> -		       wi, pset);
> -      if (ret)
> -	return ret;
> -      ret = walk_tree (gimple_oacc_kernels_data_arg_ptr (stmt), callback_op,
> -		       wi, pset);
> -      if (ret)
> -	return ret;
> -      break;
> -
> -    case GIMPLE_OACC_PARALLEL:
> -      ret = walk_tree (gimple_oacc_parallel_clauses_ptr (stmt), callback_op,
> -		       wi, pset);
> -      if (ret)
> -	return ret;
> -      ret = walk_tree (gimple_oacc_parallel_child_fn_ptr (stmt), callback_op,
> -		       wi, pset);
> -      if (ret)
> -	return ret;
> -      ret = walk_tree (gimple_oacc_parallel_data_arg_ptr (stmt), callback_op,
> -		       wi, pset);
> -      if (ret)
> -	return ret;
> -      break;
> -
>      case GIMPLE_OMP_CONTINUE:
>        ret = walk_tree (gimple_omp_continue_control_def_ptr (stmt),
>  	  	       callback_op, wi, pset);

..., I noticed that GIMPLE_OMP_TARGET doesn't walk the child_fn and
data_arg.  Is that intentional, or should that be done?  If the latter
(but this doesn't seem to cause any ill effects -- why?), OK to commit
the following to trunk?

 gcc/gimple-walk.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git gcc/gimple-walk.c gcc/gimple-walk.c
index bfa3532..1330c04 100644
--- gcc/gimple-walk.c
+++ gcc/gimple-walk.c
@@ -416,6 +416,14 @@ walk_gimple_op (gimple stmt, walk_tree_fn callback_op,
 		       pset);
       if (ret)
 	return ret;
+      ret = walk_tree (gimple_omp_target_child_fn_ptr (stmt), callback_op, wi,
+		       pset);
+      if (ret)
+	return ret;
+      ret = walk_tree (gimple_omp_target_data_arg_ptr (stmt), callback_op, wi,
+		       pset);
+      if (ret)
+	return ret;
       break;
 
     case GIMPLE_OMP_TEAMS:


Grüße,
 Thomas

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 472 bytes --]

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

* Re: OpenACC GIMPLE_OACC_* -- or not?
  2014-12-10 10:07                           ` Thomas Schwinge
@ 2014-12-10 10:10                             ` Jakub Jelinek
  2014-12-12 20:02                               ` Thomas Schwinge
  0 siblings, 1 reply; 44+ messages in thread
From: Jakub Jelinek @ 2014-12-10 10:10 UTC (permalink / raw)
  To: Thomas Schwinge; +Cc: gcc-patches

On Wed, Dec 10, 2014 at 11:07:37AM +0100, Thomas Schwinge wrote:
> ..., I noticed that GIMPLE_OMP_TARGET doesn't walk the child_fn and
> data_arg.  Is that intentional, or should that be done?  If the latter
> (but this doesn't seem to cause any ill effects -- why?), OK to commit
> the following to trunk?

Ok with proper ChangeLog.

>  gcc/gimple-walk.c | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git gcc/gimple-walk.c gcc/gimple-walk.c
> index bfa3532..1330c04 100644
> --- gcc/gimple-walk.c
> +++ gcc/gimple-walk.c
> @@ -416,6 +416,14 @@ walk_gimple_op (gimple stmt, walk_tree_fn callback_op,
>  		       pset);
>        if (ret)
>  	return ret;
> +      ret = walk_tree (gimple_omp_target_child_fn_ptr (stmt), callback_op, wi,
> +		       pset);
> +      if (ret)
> +	return ret;
> +      ret = walk_tree (gimple_omp_target_data_arg_ptr (stmt), callback_op, wi,
> +		       pset);
> +      if (ret)
> +	return ret;
>        break;
>  
>      case GIMPLE_OMP_TEAMS:

	Jakub

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

* Re: Nested OpenACC/OpenMP constructs (was: OpenACC GIMPLE_OACC_* -- or not?)
  2014-12-10 10:02                         ` Nested OpenACC/OpenMP constructs (was: OpenACC GIMPLE_OACC_* -- or not?) Thomas Schwinge
@ 2014-12-10 10:10                           ` Thomas Schwinge
  2014-12-10 10:16                             ` Jakub Jelinek
  0 siblings, 1 reply; 44+ messages in thread
From: Thomas Schwinge @ 2014-12-10 10:10 UTC (permalink / raw)
  To: Jakub Jelinek, gcc-patches

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

Hi Jakub!

On Wed, 10 Dec 2014 11:02:24 +0100, I wrote:
>     OpenACC: Rework nested constructs checking.
>     
>     	gcc/
>     	* omp-low.c (scan_omp_target): Remove taskreg_nesting_level and
>     	target_nesting_level assertions.
>     	(check_omp_nesting_restrictions): Rework OpenACC constructs
>     	handling.  Update and extend the relevant test cases.

Regarding the check_omp_nesting_restrictions rework:

> --- gcc/omp-low.c
> +++ gcc/omp-low.c
> @@ -2706,46 +2700,26 @@ scan_omp_teams (gimple stmt, omp_context *outer_ctx)
>    scan_omp (gimple_omp_body_ptr (stmt), ctx);
>  }
>  
> -/* Check OpenMP nesting restrictions.  */
> +/* Check nesting restrictions.  */
>  static bool
>  check_omp_nesting_restrictions (gimple stmt, omp_context *ctx)
>  {
> -  /* TODO: While the OpenACC specification does allow for certain kinds of
> -     nesting, we don't support many of these yet.  */
> -  if (is_gimple_omp (stmt)
> -      && is_gimple_omp_oacc_specifically (stmt))
> +  /* TODO: Some OpenACC/OpenMP nesting should be allowed.  */
> +
> +  /* No nesting of non-OpenACC STMT (that is, an OpenMP one, or a GOMP builtin)
> +     inside an OpenACC CTX.  */
> +  if (!(is_gimple_omp (stmt)
> +	&& is_gimple_omp_oacc_specifically (stmt)))
>      {
> -      /* Regular handling of OpenACC loop constructs.  */
> -      if (gimple_code (stmt) == GIMPLE_OMP_FOR
> -	  && gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_OACC_LOOP)
> -	goto cont;
> -      /* No nesting of OpenACC STMT inside any OpenACC or OpenMP CTX different
> -	 from an OpenACC data construct.  */
> -      for (omp_context *ctx_ = ctx; ctx_ != NULL; ctx_ = ctx_->outer)
> -	if (is_gimple_omp (ctx_->stmt)
> -	    && !(gimple_code (ctx_->stmt) == GIMPLE_OMP_TARGET
> -		 && (gimple_omp_target_kind (ctx_->stmt)
> -		     == GF_OMP_TARGET_KIND_OACC_DATA)))
> -	  {
> -	    error_at (gimple_location (stmt),
> -		      "may not be nested");
> -	    return false;
> -	  }
> -    }
> -  else
> -    {
> -      /* No nesting of non-OpenACC STMT (that is, an OpenMP one, or a GOMP
> -	 builtin) inside any OpenACC CTX.  */
>        for (omp_context *ctx_ = ctx; ctx_ != NULL; ctx_ = ctx_->outer)
>  	if (is_gimple_omp (ctx_->stmt)
>  	    && is_gimple_omp_oacc_specifically (ctx_->stmt))
>  	  {
>  	    error_at (gimple_location (stmt),
> -		      "may not be nested");
> +		      "non-OpenACC construct inside of OpenACC region");
>  	    return false;
>  	  }
>      }
> - cont:
>  
>    if (ctx != NULL)
>      {
> @@ -3003,20 +2977,74 @@ check_omp_nesting_restrictions (gimple stmt, omp_context *ctx)
>        break;
>      case GIMPLE_OMP_TARGET:
>        for (; ctx != NULL; ctx = ctx->outer)
> -	if (gimple_code (ctx->stmt) == GIMPLE_OMP_TARGET
> -	    && gimple_omp_target_kind (ctx->stmt) == GF_OMP_TARGET_KIND_REGION)
> -	  {
> -	    const char *name;
> -	    switch (gimple_omp_target_kind (stmt))
> -	      {
> -	      case GF_OMP_TARGET_KIND_REGION: name = "target"; break;
> -	      case GF_OMP_TARGET_KIND_DATA: name = "target data"; break;
> -	      case GF_OMP_TARGET_KIND_UPDATE: name = "target update"; break;
> -	      default: gcc_unreachable ();
> -	      }
> -	    warning_at (gimple_location (stmt), 0,
> -			"%s construct inside of target region", name);
> -	  }
> +	{
> +	  if (gimple_code (ctx->stmt) != GIMPLE_OMP_TARGET)
> +	    {
> +	      if (is_gimple_omp (stmt)
> +		  && is_gimple_omp_oacc_specifically (stmt)
> +		  && is_gimple_omp (ctx->stmt))
> +		{
> +		  error_at (gimple_location (stmt),
> +			    "OpenACC construct inside of non-OpenACC region");
> +		  return false;
> +		}
> +	      continue;
> +	    }
> +
> +	  const char *stmt_name, *ctx_stmt_name;
> +	  switch (gimple_omp_target_kind (stmt))
> +	    {
> +	    case GF_OMP_TARGET_KIND_REGION: stmt_name = "target"; break;
> +	    case GF_OMP_TARGET_KIND_DATA: stmt_name = "target data"; break;
> +	    case GF_OMP_TARGET_KIND_UPDATE: stmt_name = "target update"; break;
> +	    case GF_OMP_TARGET_KIND_OACC_PARALLEL: stmt_name = "parallel"; break;
> +	    case GF_OMP_TARGET_KIND_OACC_KERNELS: stmt_name = "kernels"; break;
> +	    case GF_OMP_TARGET_KIND_OACC_DATA: stmt_name = "data"; break;
> +	    case GF_OMP_TARGET_KIND_OACC_UPDATE: stmt_name = "update"; break;
> +	    case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA: stmt_name = "enter/exit data"; break;
> +	    default: gcc_unreachable ();
> +	    }
> +	  switch (gimple_omp_target_kind (ctx->stmt))
> +	    {
> +	    case GF_OMP_TARGET_KIND_REGION: ctx_stmt_name = "target"; break;
> +	    case GF_OMP_TARGET_KIND_DATA: ctx_stmt_name = "target data"; break;
> +	    case GF_OMP_TARGET_KIND_OACC_PARALLEL: ctx_stmt_name = "parallel"; break;
> +	    case GF_OMP_TARGET_KIND_OACC_KERNELS: ctx_stmt_name = "kernels"; break;
> +	    case GF_OMP_TARGET_KIND_OACC_DATA: ctx_stmt_name = "data"; break;
> +	    default: gcc_unreachable ();
> +	    }
> +
> +	  /* OpenACC/OpenMP mismatch?  */
> +	  if (is_gimple_omp_oacc_specifically (stmt)
> +	      != is_gimple_omp_oacc_specifically (ctx->stmt))
> +	    {
> +	      error_at (gimple_location (stmt),
> +			"%s %s construct inside of %s %s region",
> +			(is_gimple_omp_oacc_specifically (stmt)
> +			 ? "OpenACC" : "OpenMP"), stmt_name,
> +			(is_gimple_omp_oacc_specifically (ctx->stmt)
> +			 ? "OpenACC" : "OpenMP"), ctx_stmt_name);
> +	      return false;
> +	    }
> +	  if (is_gimple_omp_offloaded (ctx->stmt))
> +	    {
> +	      /* No GIMPLE_OMP_TARGET inside offloaded OpenACC CTX.  */
> +	      if (is_gimple_omp_oacc_specifically (ctx->stmt))
> +		{
> +		  error_at (gimple_location (stmt),
> +			    "%s construct inside of %s region",
> +			    stmt_name, ctx_stmt_name);
> +		  return false;
> +		}
> +	      else
> +		{
> +		  gcc_assert (!is_gimple_omp_oacc_specifically (stmt));
> +		  warning_at (gimple_location (stmt), 0,
> +			      "%s construct inside of %s region",
> +			      stmt_name, ctx_stmt_name);
> +		}
> +	    }
> +	}
>        break;
>      default:
>        break;

For guarding against OpenMP target regressions, I used the following
tests -- OK to commit to trunk?

 gcc/testsuite/c-c++-common/gomp/nesting-1.c      | 77 ++++++++++++++++++++++++
 gcc/testsuite/c-c++-common/gomp/nesting-warn-1.c | 23 +++++++
 2 files changed, 100 insertions(+)

diff --git gcc/testsuite/c-c++-common/gomp/nesting-1.c gcc/testsuite/c-c++-common/gomp/nesting-1.c
new file mode 100644
index 0000000..70b3e8d
--- /dev/null
+++ gcc/testsuite/c-c++-common/gomp/nesting-1.c
@@ -0,0 +1,77 @@
+void
+f_omp_parallel (void)
+{
+#pragma omp parallel
+  {
+    int i;
+
+#pragma omp parallel
+    ;
+
+#pragma omp target
+    ;
+
+#pragma omp target data
+    ;
+
+#pragma omp target update to(i)
+
+#pragma omp target data
+    {
+#pragma omp parallel
+      ;
+
+#pragma omp target
+      ;
+
+#pragma omp target data
+      ;
+
+#pragma omp target update to(i)
+    }
+  }
+}
+
+void
+f_omp_target (void)
+{
+#pragma omp target
+  {
+#pragma omp parallel
+    ;
+  }
+}
+
+void
+f_omp_target_data (void)
+{
+#pragma omp target data
+  {
+    int i;
+
+#pragma omp parallel
+    ;
+
+#pragma omp target
+    ;
+
+#pragma omp target data
+    ;
+
+#pragma omp target update to(i)
+
+#pragma omp target data
+    {
+#pragma omp parallel
+      ;
+
+#pragma omp target
+      ;
+
+#pragma omp target data
+      ;
+
+#pragma omp target update to(i)
+    }
+  }
+}
diff --git gcc/testsuite/c-c++-common/gomp/nesting-warn-1.c gcc/testsuite/c-c++-common/gomp/nesting-warn-1.c
new file mode 100644
index 0000000..6a65699
--- /dev/null
+++ gcc/testsuite/c-c++-common/gomp/nesting-warn-1.c
@@ -0,0 +1,23 @@
+void
+f_omp_target (void)
+{
+#pragma omp target
+  {
+    int i;
+
+#pragma omp target /* { dg-warning "target construct inside of target region" } */
+    ;
+#pragma omp target data /* { dg-warning "target data construct inside of target region" } */
+    ;
+#pragma omp target update to(i) /* { dg-warning "target update construct inside of target region" } */
+
+#pragma omp parallel
+    {
+#pragma omp target /* { dg-warning "target construct inside of target region" } */
+      ;
+#pragma omp target data /* { dg-warning "target data construct inside of target region" } */
+      ;
+#pragma omp target update to(i) /* { dg-warning "target update construct inside of target region" } */
+    }
+  }
+}


Grüße,
 Thomas

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 472 bytes --]

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

* Re: Nested OpenACC/OpenMP constructs (was: OpenACC GIMPLE_OACC_* -- or not?)
  2014-12-10 10:10                           ` Thomas Schwinge
@ 2014-12-10 10:16                             ` Jakub Jelinek
  2014-12-12 20:04                               ` Nested OpenACC/OpenMP constructs Thomas Schwinge
  0 siblings, 1 reply; 44+ messages in thread
From: Jakub Jelinek @ 2014-12-10 10:16 UTC (permalink / raw)
  To: Thomas Schwinge; +Cc: gcc-patches

On Wed, Dec 10, 2014 at 11:10:19AM +0100, Thomas Schwinge wrote:
> --- /dev/null
> +++ gcc/testsuite/c-c++-common/gomp/nesting-1.c
> @@ -0,0 +1,77 @@
> +void
> +f_omp_parallel (void)
> +{
> +#pragma omp parallel
> +  {
> +    int i;

Can you please use a global variable declared outside of
f_omp_parallel instead?

> +
> +#pragma omp parallel
> +    ;
> +
> +#pragma omp target
> +    ;
> +
> +#pragma omp target data
> +    ;
> +
> +#pragma omp target update to(i)

The thing is, if GCC tried harder, it could complain here,
because i can't really be mapped at this point and thus it would be always
undefined behavior.  If the var is global, it is possible
somebody uses
  #pragma omp target map(i)
  f_omp_parallel ();
and then it would be valid.  Similarly in other tests.

Otherwise LGTM.

	Jakub

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

* Re: OpenACC GIMPLE_OACC_* -- or not?
  2014-12-10 10:10                             ` Jakub Jelinek
@ 2014-12-12 20:02                               ` Thomas Schwinge
  0 siblings, 0 replies; 44+ messages in thread
From: Thomas Schwinge @ 2014-12-12 20:02 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

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

Hi!

On Wed, 10 Dec 2014 11:10:47 +0100, Jakub Jelinek <jakub@redhat.com> wrote:
> On Wed, Dec 10, 2014 at 11:07:37AM +0100, Thomas Schwinge wrote:
> > ..., I noticed that GIMPLE_OMP_TARGET doesn't walk the child_fn and
> > data_arg.  Is that intentional, or should that be done?  If the latter
> > (but this doesn't seem to cause any ill effects -- why?), OK to commit
> > the following to trunk?
> 
> Ok with proper ChangeLog.
> 
> >  gcc/gimple-walk.c | 8 ++++++++
> >  1 file changed, 8 insertions(+)
> > 
> > diff --git gcc/gimple-walk.c gcc/gimple-walk.c
> > index bfa3532..1330c04 100644
> > --- gcc/gimple-walk.c
> > +++ gcc/gimple-walk.c
> > @@ -416,6 +416,14 @@ walk_gimple_op (gimple stmt, walk_tree_fn callback_op,
> >  		       pset);
> >        if (ret)
> >  	return ret;
> > +      ret = walk_tree (gimple_omp_target_child_fn_ptr (stmt), callback_op, wi,
> > +		       pset);
> > +      if (ret)
> > +	return ret;
> > +      ret = walk_tree (gimple_omp_target_data_arg_ptr (stmt), callback_op, wi,
> > +		       pset);
> > +      if (ret)
> > +	return ret;
> >        break;
> >  
> >      case GIMPLE_OMP_TEAMS:

Committed to trunk in r218686:

commit c1277edd4b50623bae89bea8cba84def9b308e77
Author: tschwinge <tschwinge@138bc75d-0d04-0410-961f-82ee72b054a4>
Date:   Fri Dec 12 20:01:18 2014 +0000

    A bit of walk_gimple_op maintenance.
    
    	* gimple-walk.c (walk_gimple_op) <GIMPLE_OMP_FOR>: Also check
    	intermediate walk_tree results for for_incr.
    	<GIMPLE_OMP_TARGET>: Walk child_fn and data_arg, too.
    	<GIMPLE_OMP_CRITICAL, GIMPLE_OMP_ATOMIC_STORE>: Pretty printing.
    
    git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@218686 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/ChangeLog     |  7 +++++++
 gcc/gimple-walk.c | 49 +++++++++++++++++++++++++++++++------------------
 2 files changed, 38 insertions(+), 18 deletions(-)

diff --git gcc/ChangeLog gcc/ChangeLog
index bf9571b..3a20032 100644
--- gcc/ChangeLog
+++ gcc/ChangeLog
@@ -1,3 +1,10 @@
+2014-12-12  Thomas Schwinge  <thomas@codesourcery.com>
+
+	* gimple-walk.c (walk_gimple_op) <GIMPLE_OMP_FOR>: Also check
+	intermediate walk_tree results for for_incr.
+	<GIMPLE_OMP_TARGET>: Walk child_fn and data_arg, too.
+	<GIMPLE_OMP_CRITICAL, GIMPLE_OMP_ATOMIC_STORE>: Pretty printing.
+
 2014-12-12  Richard Sandiford  <richard.sandiford@arm.com>
 
 	PR middle-end/64182
diff --git gcc/gimple-walk.c gcc/gimple-walk.c
index 48fa05d..959d68e 100644
--- gcc/gimple-walk.c
+++ gcc/gimple-walk.c
@@ -321,11 +321,13 @@ walk_gimple_op (gimple stmt, walk_tree_fn callback_op,
       break;
 
     case GIMPLE_OMP_CRITICAL:
-      ret = walk_tree (gimple_omp_critical_name_ptr (
-			 as_a <gomp_critical *> (stmt)),
-		       callback_op, wi, pset);
-      if (ret)
-	return ret;
+      {
+	gomp_critical *omp_stmt = as_a <gomp_critical *> (stmt);
+	ret = walk_tree (gimple_omp_critical_name_ptr (omp_stmt),
+			 callback_op, wi, pset);
+	if (ret)
+	  return ret;
+      }
       break;
 
     case GIMPLE_OMP_FOR:
@@ -349,9 +351,9 @@ walk_gimple_op (gimple stmt, walk_tree_fn callback_op,
 	    return ret;
 	  ret = walk_tree (gimple_omp_for_incr_ptr (stmt, i), callback_op,
 			   wi, pset);
+	  if (ret)
+	    return ret;
 	}
-      if (ret)
-	return ret;
       break;
 
     case GIMPLE_OMP_PARALLEL:
@@ -404,7 +406,6 @@ walk_gimple_op (gimple stmt, walk_tree_fn callback_op,
 		       wi, pset);
       if (ret)
 	return ret;
-
       ret = walk_tree (gimple_omp_sections_control_ptr (stmt), callback_op,
 		       wi, pset);
       if (ret)
@@ -420,10 +421,21 @@ walk_gimple_op (gimple stmt, walk_tree_fn callback_op,
       break;
 
     case GIMPLE_OMP_TARGET:
-      ret = walk_tree (gimple_omp_target_clauses_ptr (stmt), callback_op, wi,
-		       pset);
-      if (ret)
-	return ret;
+      {
+	gomp_target *omp_stmt = as_a <gomp_target *> (stmt);
+	ret = walk_tree (gimple_omp_target_clauses_ptr (omp_stmt),
+			 callback_op, wi, pset);
+	if (ret)
+	  return ret;
+	ret = walk_tree (gimple_omp_target_child_fn_ptr (omp_stmt),
+			 callback_op, wi, pset);
+	if (ret)
+	  return ret;
+	ret = walk_tree (gimple_omp_target_data_arg_ptr (omp_stmt),
+			 callback_op, wi, pset);
+	if (ret)
+	  return ret;
+      }
       break;
 
     case GIMPLE_OMP_TEAMS:
@@ -440,7 +452,6 @@ walk_gimple_op (gimple stmt, walk_tree_fn callback_op,
 			 callback_op, wi, pset);
 	if (ret)
 	  return ret;
-
 	ret = walk_tree (gimple_omp_atomic_load_rhs_ptr (omp_stmt),
 			 callback_op, wi, pset);
 	if (ret)
@@ -449,11 +460,13 @@ walk_gimple_op (gimple stmt, walk_tree_fn callback_op,
       break;
 
     case GIMPLE_OMP_ATOMIC_STORE:
-      ret = walk_tree (gimple_omp_atomic_store_val_ptr (
-		         as_a <gomp_atomic_store *> (stmt)),
-		       callback_op, wi, pset);
-      if (ret)
-	return ret;
+      {
+	gomp_atomic_store *omp_stmt = as_a <gomp_atomic_store *> (stmt);
+	ret = walk_tree (gimple_omp_atomic_store_val_ptr (omp_stmt),
+			 callback_op, wi, pset);
+	if (ret)
+	  return ret;
+      }
       break;
 
     case GIMPLE_TRANSACTION:


Grüße,
 Thomas

[-- Attachment #2: Type: application/pgp-signature, Size: 472 bytes --]

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

* Re: Nested OpenACC/OpenMP constructs
  2014-12-10 10:16                             ` Jakub Jelinek
@ 2014-12-12 20:04                               ` Thomas Schwinge
  2014-12-17 22:21                                 ` OpenACC/OpenMP testing: Revise variable usage in constructs (was: Nested OpenACC/OpenMP constructs) Thomas Schwinge
  0 siblings, 1 reply; 44+ messages in thread
From: Thomas Schwinge @ 2014-12-12 20:04 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

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

Hi!

On Wed, 10 Dec 2014 11:16:08 +0100, Jakub Jelinek <jakub@redhat.com> wrote:
> On Wed, Dec 10, 2014 at 11:10:19AM +0100, Thomas Schwinge wrote:
> > --- /dev/null
> > +++ gcc/testsuite/c-c++-common/gomp/nesting-1.c
> > @@ -0,0 +1,77 @@
> > +void
> > +f_omp_parallel (void)
> > +{
> > +#pragma omp parallel
> > +  {
> > +    int i;
> 
> Can you please use a global variable declared outside of
> f_omp_parallel instead?
> 
> > +
> > +#pragma omp parallel
> > +    ;
> > +
> > +#pragma omp target
> > +    ;
> > +
> > +#pragma omp target data
> > +    ;
> > +
> > +#pragma omp target update to(i)
> 
> The thing is, if GCC tried harder, it could complain here,
> because i can't really be mapped at this point and thus it would be always
> undefined behavior.  If the var is global, it is possible
> somebody uses
>   #pragma omp target map(i)
>   f_omp_parallel ();
> and then it would be valid.

That makes sense, thanks.

> Similarly in other tests.

Will change on gomp-4_0-branch.

> Otherwise LGTM.

Committed to trunk in r218687:

commit 4c37888fdc6548eba74aa0d652e37b33dd097aea
Author: tschwinge <tschwinge@138bc75d-0d04-0410-961f-82ee72b054a4>
Date:   Fri Dec 12 20:01:29 2014 +0000

    OpenMP target nesting tests.
    
    	gcc/testsuite/
    	* c-c++-common/gomp/nesting-1.c: New file.
    	* c-c++-common/gomp/nesting-warn-1.c: Likewise.
    
    git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@218687 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/testsuite/ChangeLog                          |  5 ++
 gcc/testsuite/c-c++-common/gomp/nesting-1.c      | 75 ++++++++++++++++++++++++
 gcc/testsuite/c-c++-common/gomp/nesting-warn-1.c | 23 ++++++++
 3 files changed, 103 insertions(+)

diff --git gcc/testsuite/ChangeLog gcc/testsuite/ChangeLog
index 8e5b424..f2502ff 100644
--- gcc/testsuite/ChangeLog
+++ gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2014-12-12  Thomas Schwinge  <thomas@codesourcery.com>
+
+	* c-c++-common/gomp/nesting-1.c: New file.
+	* c-c++-common/gomp/nesting-warn-1.c: Likewise.
+
 2014-12-12  Kai Tietz  <ktietz@redhat.com>
 
 	PR c++/63996
diff --git gcc/testsuite/c-c++-common/gomp/nesting-1.c gcc/testsuite/c-c++-common/gomp/nesting-1.c
new file mode 100644
index 0000000..711ff8e
--- /dev/null
+++ gcc/testsuite/c-c++-common/gomp/nesting-1.c
@@ -0,0 +1,75 @@
+extern int i;
+
+void
+f_omp_parallel (void)
+{
+#pragma omp parallel
+  {
+#pragma omp parallel
+    ;
+
+#pragma omp target
+    ;
+
+#pragma omp target data
+    ;
+
+#pragma omp target update to(i)
+
+#pragma omp target data
+    {
+#pragma omp parallel
+      ;
+
+#pragma omp target
+      ;
+
+#pragma omp target data
+      ;
+
+#pragma omp target update to(i)
+    }
+  }
+}
+
+void
+f_omp_target (void)
+{
+#pragma omp target
+  {
+#pragma omp parallel
+    ;
+  }
+}
+
+void
+f_omp_target_data (void)
+{
+#pragma omp target data
+  {
+#pragma omp parallel
+    ;
+
+#pragma omp target
+    ;
+
+#pragma omp target data
+    ;
+
+#pragma omp target update to(i)
+
+#pragma omp target data
+    {
+#pragma omp parallel
+      ;
+
+#pragma omp target
+      ;
+
+#pragma omp target data
+      ;
+
+#pragma omp target update to(i)
+    }
+  }
+}
diff --git gcc/testsuite/c-c++-common/gomp/nesting-warn-1.c gcc/testsuite/c-c++-common/gomp/nesting-warn-1.c
new file mode 100644
index 0000000..c39dd49
--- /dev/null
+++ gcc/testsuite/c-c++-common/gomp/nesting-warn-1.c
@@ -0,0 +1,23 @@
+extern int i;
+
+void
+f_omp_target (void)
+{
+#pragma omp target
+  {
+#pragma omp target /* { dg-warning "target construct inside of target region" } */
+    ;
+#pragma omp target data /* { dg-warning "target data construct inside of target region" } */
+    ;
+#pragma omp target update to(i) /* { dg-warning "target update construct inside of target region" } */
+
+#pragma omp parallel
+    {
+#pragma omp target /* { dg-warning "target construct inside of target region" } */
+      ;
+#pragma omp target data /* { dg-warning "target data construct inside of target region" } */
+      ;
+#pragma omp target update to(i) /* { dg-warning "target update construct inside of target region" } */
+    }
+  }
+}


Grüße,
 Thomas

[-- Attachment #2: Type: application/pgp-signature, Size: 472 bytes --]

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

* OpenACC/OpenMP testing: Revise variable usage in constructs (was: Nested OpenACC/OpenMP constructs)
  2014-12-12 20:04                               ` Nested OpenACC/OpenMP constructs Thomas Schwinge
@ 2014-12-17 22:21                                 ` Thomas Schwinge
  0 siblings, 0 replies; 44+ messages in thread
From: Thomas Schwinge @ 2014-12-17 22:21 UTC (permalink / raw)
  To: Jakub Jelinek, gcc-patches

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

Hi!

On Fri, 12 Dec 2014 21:04:21 +0100, I wrote:
> On Wed, 10 Dec 2014 11:16:08 +0100, Jakub Jelinek <jakub@redhat.com> wrote:
> > On Wed, Dec 10, 2014 at 11:10:19AM +0100, Thomas Schwinge wrote:
> > > --- /dev/null
> > > +++ gcc/testsuite/c-c++-common/gomp/nesting-1.c
> > > @@ -0,0 +1,77 @@
> > > +void
> > > +f_omp_parallel (void)
> > > +{
> > > +#pragma omp parallel
> > > +  {
> > > +    int i;
> > 
> > Can you please use a global variable declared outside of
> > f_omp_parallel instead?
> > 
> > > +
> > > +#pragma omp parallel
> > > +    ;
> > > +
> > > +#pragma omp target
> > > +    ;
> > > +
> > > +#pragma omp target data
> > > +    ;
> > > +
> > > +#pragma omp target update to(i)
> > 
> > The thing is, if GCC tried harder, it could complain here,
> > because i can't really be mapped at this point and thus it would be always
> > undefined behavior.  If the var is global, it is possible
> > somebody uses
> >   #pragma omp target map(i)
> >   f_omp_parallel ();
> > and then it would be valid.
> 
> That makes sense, thanks.
> 
> > Similarly in other tests.
> 
> Will change on gomp-4_0-branch.

Committed to gomp-4_0-branch in r218838:

commit 01c48eb7ca8a04ca001a2caef57929c3ba40512f
Author: tschwinge <tschwinge@138bc75d-0d04-0410-961f-82ee72b054a4>
Date:   Wed Dec 17 22:15:09 2014 +0000

    OpenACC/OpenMP testing: Revise variable usage in constructs.
    
    	gcc/testsuite/
    	* c-c++-common/goacc-gomp/nesting-fail-1.c: Revise variable usage
    	in constructs.
    	* c-c++-common/goacc/nesting-1.c: Likewise.
    	* c-c++-common/goacc/nesting-fail-1.c: Likewise.
    
    git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@218838 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/testsuite/ChangeLog.gomp                           |  7 +++++++
 gcc/testsuite/c-c++-common/goacc-gomp/nesting-fail-1.c | 18 ++----------------
 gcc/testsuite/c-c++-common/goacc/nesting-1.c           |  8 ++------
 gcc/testsuite/c-c++-common/goacc/nesting-fail-1.c      |  6 ++----
 4 files changed, 13 insertions(+), 26 deletions(-)

diff --git gcc/testsuite/ChangeLog.gomp gcc/testsuite/ChangeLog.gomp
index 7a7b92d..e8dcb44 100644
--- gcc/testsuite/ChangeLog.gomp
+++ gcc/testsuite/ChangeLog.gomp
@@ -1,3 +1,10 @@
+2014-12-17  Thomas Schwinge  <thomas@codesourcery.com>
+
+	* c-c++-common/goacc-gomp/nesting-fail-1.c: Revise variable usage
+	in constructs.
+	* c-c++-common/goacc/nesting-1.c: Likewise.
+	* c-c++-common/goacc/nesting-fail-1.c: Likewise.
+
 2014-11-13  Cesar Philippidis  <cesar@codesourcery.com>
 
 	* gfortran.dg/gomp/omp_do1.f90: Update expected error.
diff --git gcc/testsuite/c-c++-common/goacc-gomp/nesting-fail-1.c gcc/testsuite/c-c++-common/goacc-gomp/nesting-fail-1.c
index d52c7c0..411fb5f 100644
--- gcc/testsuite/c-c++-common/goacc-gomp/nesting-fail-1.c
+++ gcc/testsuite/c-c++-common/goacc-gomp/nesting-fail-1.c
@@ -1,8 +1,8 @@
+extern int i;
+
 void
 f_omp (void)
 {
-  int i;
-
 #pragma omp parallel
   {
 #pragma acc parallel /* { dg-error "OpenACC construct inside of non-OpenACC region" } */
@@ -177,7 +177,6 @@ f_acc_parallel (void)
 
 #pragma acc parallel
   {
-    int i;
 #pragma omp for /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     for (i = 0; i < 3; i++)
       ;
@@ -217,7 +216,6 @@ f_acc_parallel (void)
 
 #pragma acc parallel
   {
-    int i;
 #pragma omp atomic write
     i = 0; /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
   }
@@ -230,8 +228,6 @@ f_acc_parallel (void)
 
 #pragma acc parallel
   {
-    int i;
-
 #pragma omp target /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     ;
 #pragma omp target data /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
@@ -251,7 +247,6 @@ f_acc_kernels (void)
 
 #pragma acc kernels
   {
-    int i;
 #pragma omp for /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     for (i = 0; i < 3; i++)
       ;
@@ -291,7 +286,6 @@ f_acc_kernels (void)
 
 #pragma acc kernels
   {
-    int i;
 #pragma omp atomic write
     i = 0; /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
   }
@@ -304,8 +298,6 @@ f_acc_kernels (void)
 
 #pragma acc kernels
   {
-    int i;
-
 #pragma omp target /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     ;
 #pragma omp target data /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
@@ -325,7 +317,6 @@ f_acc_data (void)
 
 #pragma acc data
   {
-    int i;
 #pragma omp for /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     for (i = 0; i < 3; i++)
       ;
@@ -365,7 +356,6 @@ f_acc_data (void)
 
 #pragma acc data
   {
-    int i;
 #pragma omp atomic write
     i = 0; /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
   }
@@ -378,8 +368,6 @@ f_acc_data (void)
 
 #pragma acc data
   {
-    int i;
-
 #pragma omp target /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
     ;
 #pragma omp target data /* { dg-error "non-OpenACC construct inside of OpenACC region" } */
@@ -391,8 +379,6 @@ f_acc_data (void)
 void
 f_acc_loop (void)
 {
-  int i;
-
 #pragma acc loop
   for (i = 0; i < 2; ++i)
     {
diff --git gcc/testsuite/c-c++-common/goacc/nesting-1.c gcc/testsuite/c-c++-common/goacc/nesting-1.c
index 4fbf018..b4b863f 100644
--- gcc/testsuite/c-c++-common/goacc/nesting-1.c
+++ gcc/testsuite/c-c++-common/goacc/nesting-1.c
@@ -1,10 +1,10 @@
+extern int i;
+
 void
 f_acc_parallel (void)
 {
 #pragma acc parallel
   {
-    int i;
-
 #pragma acc loop
     for (i = 0; i < 2; ++i)
       ;
@@ -17,8 +17,6 @@ f_acc_kernels (void)
 {
 #pragma acc kernels
   {
-    int i;
-
 #pragma acc loop
     for (i = 0; i < 2; ++i)
       ;
@@ -31,8 +29,6 @@ f_acc_data (void)
 {
 #pragma acc data
   {
-    int i;
-
 #pragma acc parallel
     ;
 
diff --git gcc/testsuite/c-c++-common/goacc/nesting-fail-1.c gcc/testsuite/c-c++-common/goacc/nesting-fail-1.c
index a833806..b13d2de 100644
--- gcc/testsuite/c-c++-common/goacc/nesting-fail-1.c
+++ gcc/testsuite/c-c++-common/goacc/nesting-fail-1.c
@@ -1,3 +1,5 @@
+extern int i;
+
 /* TODO: While the OpenACC specification does allow for certain kinds of
    nesting, we don't support many of these yet.  */
 void
@@ -5,8 +7,6 @@ f_acc_parallel (void)
 {
 #pragma acc parallel
   {
-    int i;
-
 #pragma acc parallel /* { dg-bogus "parallel construct inside of parallel region" "not implemented" { xfail *-*-* } } */
     ;
 #pragma acc kernels /* { dg-bogus "kernels construct inside of parallel region" "not implemented" { xfail *-*-* } } */
@@ -26,8 +26,6 @@ f_acc_kernels (void)
 {
 #pragma acc kernels
   {
-    int i;
-
 #pragma acc parallel /* { dg-bogus "parallel construct inside of kernels region" "not implemented" { xfail *-*-* } } */
     ;
 #pragma acc kernels /* { dg-bogus "kernels construct inside of kernels region" "not implemented" { xfail *-*-* } } */


Grüße,
 Thomas

[-- Attachment #2: Type: application/pgp-signature, Size: 472 bytes --]

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

* [libgomp, testsuite] Remove superfluous -fopenmp from libgomp testcases
  2013-11-07  8:16     ` [gomp4 2/9] libgomp: Prepare for testcases without -fopenmp Jakub Jelinek
@ 2017-09-28  7:41       ` Tom de Vries
  2017-09-28  8:37         ` Thomas Schwinge
  2017-09-28  8:46         ` Jakub Jelinek
  0 siblings, 2 replies; 44+ messages in thread
From: Tom de Vries @ 2017-09-28  7:41 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: thomas, gcc-patches

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

[ was: Re: [gomp4 2/9] libgomp: Prepare for testcases without -fopenmp. ]

On 11/07/2013 09:11 AM, Jakub Jelinek wrote:
> On Wed, Nov 06, 2013 at 08:42:16PM +0100, thomas@codesourcery.com wrote:
>> From: Thomas Schwinge <thomas@codesourcery.com>
>>
>> 	libgomp/
>> 	* testsuite/lib/libgomp.exp (libgomp_init): Don't add -fopenmp to
>> 	ALWAYS_CFLAGS.
>> 	* testsuite/libgomp.c++/c++.exp (ALWAYS_CFLAGS): Add -fopenmp.
>> 	* testsuite/libgomp.c/c.exp (ALWAYS_CFLAGS): Likewise.
>> 	* testsuite/libgomp.fortran/fortran.exp (ALWAYS_CFLAGS): Likewise.
>> 	* testsuite/libgomp.graphite/graphite.exp (ALWAYS_CFLAGS):
>> 	Likewise.
> 
> Ok for trunk/gomp-4_0-branch.

Following up on this, how about we drop the now superfluous -fopenmp in 
current test-cases?

Tested on x86_64. Verified by analyzing libgomp.log that -fopenmp is 
still passed to test-cases as required.

OK for trunk?

Thanks,
- Tom

[-- Attachment #2: 0001-Remove-superfluous-fopenmp-from-libgomp-testcases.patch --]
[-- Type: text/x-patch, Size: 12785 bytes --]

Remove superfluous -fopenmp from libgomp testcases

2017-09-16  Tom de Vries  <tom@codesourcery.com>

	* testsuite/libgomp.c++/for-12.C: Remove superfluous -fopenmp option
	setting.
	* testsuite/libgomp.c++/pr69393.C: Same.
	* testsuite/libgomp.c++/taskloop-1.C: Same.
	* testsuite/libgomp.c++/taskloop-3.C: Same.
	* testsuite/libgomp.c++/taskloop-4.C: Same.
	* testsuite/libgomp.c/for-4.c: Same.
	* testsuite/libgomp.c/pr66199-3.c: Same.
	* testsuite/libgomp.c/pr66199-4.c: Same.
	* testsuite/libgomp.c/pr66199-6.c: Same.
	* testsuite/libgomp.c/taskloop-1.c: Same.
	* testsuite/libgomp.c/taskloop-3.c: Same.
	* testsuite/libgomp.c/taskloop-4.c: Same.
	* testsuite/libgomp.fortran/aligned1.f03: Same.
	* testsuite/libgomp.fortran/condinc1.f: Same.
	* testsuite/libgomp.fortran/condinc3.f90: Same.
	* testsuite/libgomp.fortran/crayptr1.f90: Same.
	* testsuite/libgomp.fortran/crayptr2.f90: Same.
	* testsuite/libgomp.fortran/crayptr3.f90: Same.
	* testsuite/libgomp.fortran/omp_cond1.f: Same.
	* testsuite/libgomp.fortran/omp_cond3.F90: Same.
	* testsuite/libgomp.fortran/pr66199-1.f90: Same.
	* testsuite/libgomp.fortran/pr66199-2.f90: Same.
	* testsuite/libgomp.fortran/recursion1.f90: Same.
	* testsuite/libgomp.fortran/target2.f90: Same.
	* testsuite/libgomp.fortran/target5.f90: Same.
	* testsuite/libgomp.fortran/task3.f90: Same.

---
 libgomp/testsuite/libgomp.c++/for-12.C           | 2 --
 libgomp/testsuite/libgomp.c++/pr69393.C          | 2 +-
 libgomp/testsuite/libgomp.c++/taskloop-1.C       | 2 +-
 libgomp/testsuite/libgomp.c++/taskloop-3.C       | 2 +-
 libgomp/testsuite/libgomp.c++/taskloop-4.C       | 2 +-
 libgomp/testsuite/libgomp.c/for-4.c              | 2 +-
 libgomp/testsuite/libgomp.c/pr66199-3.c          | 2 +-
 libgomp/testsuite/libgomp.c/pr66199-4.c          | 2 +-
 libgomp/testsuite/libgomp.c/pr66199-6.c          | 2 +-
 libgomp/testsuite/libgomp.c/taskloop-1.c         | 2 +-
 libgomp/testsuite/libgomp.c/taskloop-3.c         | 2 +-
 libgomp/testsuite/libgomp.c/taskloop-4.c         | 2 +-
 libgomp/testsuite/libgomp.fortran/aligned1.f03   | 2 +-
 libgomp/testsuite/libgomp.fortran/condinc1.f     | 1 -
 libgomp/testsuite/libgomp.fortran/condinc3.f90   | 1 -
 libgomp/testsuite/libgomp.fortran/crayptr1.f90   | 2 +-
 libgomp/testsuite/libgomp.fortran/crayptr2.f90   | 2 +-
 libgomp/testsuite/libgomp.fortran/crayptr3.f90   | 2 +-
 libgomp/testsuite/libgomp.fortran/omp_cond1.f    | 1 -
 libgomp/testsuite/libgomp.fortran/omp_cond3.F90  | 1 -
 libgomp/testsuite/libgomp.fortran/pr66199-1.f90  | 2 +-
 libgomp/testsuite/libgomp.fortran/pr66199-2.f90  | 2 +-
 libgomp/testsuite/libgomp.fortran/recursion1.f90 | 2 +-
 libgomp/testsuite/libgomp.fortran/target2.f90    | 2 +-
 libgomp/testsuite/libgomp.fortran/target5.f90    | 1 -
 libgomp/testsuite/libgomp.fortran/task3.f90      | 1 -
 26 files changed, 19 insertions(+), 27 deletions(-)

diff --git a/libgomp/testsuite/libgomp.c++/for-12.C b/libgomp/testsuite/libgomp.c++/for-12.C
index ea32192..295b12f 100644
--- a/libgomp/testsuite/libgomp.c++/for-12.C
+++ b/libgomp/testsuite/libgomp.c++/for-12.C
@@ -1,5 +1,3 @@
-/* { dg-options "-fopenmp" } */
-
 extern "C" void abort (void);
 
 #define M(x, y, z) O(x, y, z)
diff --git a/libgomp/testsuite/libgomp.c++/pr69393.C b/libgomp/testsuite/libgomp.c++/pr69393.C
index e3f0de1..02605e0 100644
--- a/libgomp/testsuite/libgomp.c++/pr69393.C
+++ b/libgomp/testsuite/libgomp.c++/pr69393.C
@@ -1,6 +1,6 @@
 // { dg-do run }
 // { dg-require-effective-target lto }
-// { dg-options "-flto -g -fopenmp" }
+// { dg-options "-flto -g" }
 
 int e = 5;
 
diff --git a/libgomp/testsuite/libgomp.c++/taskloop-1.C b/libgomp/testsuite/libgomp.c++/taskloop-1.C
index 66f8e0b..7fc6e46 100644
--- a/libgomp/testsuite/libgomp.c++/taskloop-1.C
+++ b/libgomp/testsuite/libgomp.c++/taskloop-1.C
@@ -1,4 +1,4 @@
 // { dg-do run }
-// { dg-options "-O2 -fopenmp" }
+// { dg-options "-O2" }
 
 #include "../libgomp.c/taskloop-1.c"
diff --git a/libgomp/testsuite/libgomp.c++/taskloop-3.C b/libgomp/testsuite/libgomp.c++/taskloop-3.C
index bfd793c..c08a045 100644
--- a/libgomp/testsuite/libgomp.c++/taskloop-3.C
+++ b/libgomp/testsuite/libgomp.c++/taskloop-3.C
@@ -1,4 +1,4 @@
 // { dg-do run }
-// { dg-options "-O2 -fopenmp" }
+// { dg-options "-O2" }
 
 #include "../libgomp.c/taskloop-3.c"
diff --git a/libgomp/testsuite/libgomp.c++/taskloop-4.C b/libgomp/testsuite/libgomp.c++/taskloop-4.C
index 937cfcc..3783717 100644
--- a/libgomp/testsuite/libgomp.c++/taskloop-4.C
+++ b/libgomp/testsuite/libgomp.c++/taskloop-4.C
@@ -1,4 +1,4 @@
 // { dg-do run }
-// { dg-options "-O2 -fopenmp" }
+// { dg-options "-O2" }
 
 #include "../libgomp.c/taskloop-4.c"
diff --git a/libgomp/testsuite/libgomp.c/for-4.c b/libgomp/testsuite/libgomp.c/for-4.c
index ef5465e..14f900b 100644
--- a/libgomp/testsuite/libgomp.c/for-4.c
+++ b/libgomp/testsuite/libgomp.c/for-4.c
@@ -1,4 +1,4 @@
-/* { dg-options "-std=gnu99 -fopenmp" } */
+/* { dg-options "-std=gnu99" } */
 
 extern void abort (void);
 
diff --git a/libgomp/testsuite/libgomp.c/pr66199-3.c b/libgomp/testsuite/libgomp.c/pr66199-3.c
index fe0ccb4..ffe2858 100644
--- a/libgomp/testsuite/libgomp.c/pr66199-3.c
+++ b/libgomp/testsuite/libgomp.c/pr66199-3.c
@@ -1,6 +1,6 @@
 /* PR middle-end/66199 */
 /* { dg-do run } */
-/* { dg-options "-O2 -fopenmp" } */
+/* { dg-options "-O2" } */
 
 int u[1024], v[1024], w[1024];
 
diff --git a/libgomp/testsuite/libgomp.c/pr66199-4.c b/libgomp/testsuite/libgomp.c/pr66199-4.c
index a9b1bb8..6ffa2e5 100644
--- a/libgomp/testsuite/libgomp.c/pr66199-4.c
+++ b/libgomp/testsuite/libgomp.c/pr66199-4.c
@@ -1,6 +1,6 @@
 /* PR middle-end/66199 */
 /* { dg-do run } */
-/* { dg-options "-O2 -fopenmp" } */
+/* { dg-options "-O2" } */
 
 #pragma omp declare target
 int u[1024], v[1024], w[1024];
diff --git a/libgomp/testsuite/libgomp.c/pr66199-6.c b/libgomp/testsuite/libgomp.c/pr66199-6.c
index 6790f7d..14f8610 100644
--- a/libgomp/testsuite/libgomp.c/pr66199-6.c
+++ b/libgomp/testsuite/libgomp.c/pr66199-6.c
@@ -1,6 +1,6 @@
 /* PR middle-end/66199 */
 /* { dg-do run } */
-/* { dg-options "-O2 -fopenmp" } */
+/* { dg-options "-O2" } */
 
 #pragma omp declare target
 int u[1024], v[1024], w[1024];
diff --git a/libgomp/testsuite/libgomp.c/taskloop-1.c b/libgomp/testsuite/libgomp.c/taskloop-1.c
index 21551f2..edc7058 100644
--- a/libgomp/testsuite/libgomp.c/taskloop-1.c
+++ b/libgomp/testsuite/libgomp.c/taskloop-1.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -fopenmp -std=c99" } */
+/* { dg-options "-O2 -std=c99" } */
 
 int q, r, e;
 
diff --git a/libgomp/testsuite/libgomp.c/taskloop-3.c b/libgomp/testsuite/libgomp.c/taskloop-3.c
index 5356d7f..9c8c49c 100644
--- a/libgomp/testsuite/libgomp.c/taskloop-3.c
+++ b/libgomp/testsuite/libgomp.c/taskloop-3.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -fopenmp -std=c99" } */
+/* { dg-options "-O2 -std=c99" } */
 
 int g;
 int a[1024];
diff --git a/libgomp/testsuite/libgomp.c/taskloop-4.c b/libgomp/testsuite/libgomp.c/taskloop-4.c
index a69be19..4ac1b5a 100644
--- a/libgomp/testsuite/libgomp.c/taskloop-4.c
+++ b/libgomp/testsuite/libgomp.c/taskloop-4.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -fopenmp" } */
+/* { dg-options "-O2" } */
 
 int u[64], v;
 
diff --git a/libgomp/testsuite/libgomp.fortran/aligned1.f03 b/libgomp/testsuite/libgomp.fortran/aligned1.f03
index 67a9ab4..2db03e1 100644
--- a/libgomp/testsuite/libgomp.fortran/aligned1.f03
+++ b/libgomp/testsuite/libgomp.fortran/aligned1.f03
@@ -1,5 +1,5 @@
 ! { dg-do run }
-! { dg-options "-fopenmp -fcray-pointer" }
+! { dg-options "-fcray-pointer" }
 
   use iso_c_binding, only : c_ptr, c_ptrdiff_t, c_loc
   interface
diff --git a/libgomp/testsuite/libgomp.fortran/condinc1.f b/libgomp/testsuite/libgomp.fortran/condinc1.f
index d94fe8d..6d05635 100644
--- a/libgomp/testsuite/libgomp.fortran/condinc1.f
+++ b/libgomp/testsuite/libgomp.fortran/condinc1.f
@@ -1,4 +1,3 @@
-! { dg-options "-fopenmp" }
       program condinc1
       logical l
       l = .false.
diff --git a/libgomp/testsuite/libgomp.fortran/condinc3.f90 b/libgomp/testsuite/libgomp.fortran/condinc3.f90
index 16b937a..7c24303 100644
--- a/libgomp/testsuite/libgomp.fortran/condinc3.f90
+++ b/libgomp/testsuite/libgomp.fortran/condinc3.f90
@@ -1,4 +1,3 @@
-  ! { dg-options "-fopenmp" }
 program condinc3
   logical l
   l = .false.
diff --git a/libgomp/testsuite/libgomp.fortran/crayptr1.f90 b/libgomp/testsuite/libgomp.fortran/crayptr1.f90
index 57c59f7..fb9495e 100644
--- a/libgomp/testsuite/libgomp.fortran/crayptr1.f90
+++ b/libgomp/testsuite/libgomp.fortran/crayptr1.f90
@@ -1,5 +1,5 @@
 ! { dg-do run }
-! { dg-options "-fopenmp -fcray-pointer" }
+! { dg-options "-fcray-pointer" }
 
   use omp_lib
   integer :: a, b, c, p
diff --git a/libgomp/testsuite/libgomp.fortran/crayptr2.f90 b/libgomp/testsuite/libgomp.fortran/crayptr2.f90
index c88cc7a..7e69b87 100644
--- a/libgomp/testsuite/libgomp.fortran/crayptr2.f90
+++ b/libgomp/testsuite/libgomp.fortran/crayptr2.f90
@@ -1,5 +1,5 @@
 ! { dg-do run }
-! { dg-options "-fopenmp -fcray-pointer" }
+! { dg-options "-fcray-pointer" }
 ! { dg-require-effective-target tls_runtime }
 
   use omp_lib
diff --git a/libgomp/testsuite/libgomp.fortran/crayptr3.f90 b/libgomp/testsuite/libgomp.fortran/crayptr3.f90
index 9777c6b..5b3de65 100644
--- a/libgomp/testsuite/libgomp.fortran/crayptr3.f90
+++ b/libgomp/testsuite/libgomp.fortran/crayptr3.f90
@@ -1,5 +1,5 @@
 ! { dg-do run }
-! { dg-options "-fopenmp -fcray-pointer" }
+! { dg-options "-fcray-pointer" }
 
   use omp_lib
   integer :: a, b, c, i, p
diff --git a/libgomp/testsuite/libgomp.fortran/omp_cond1.f b/libgomp/testsuite/libgomp.fortran/omp_cond1.f
index b557d90..f51e868 100644
--- a/libgomp/testsuite/libgomp.fortran/omp_cond1.f
+++ b/libgomp/testsuite/libgomp.fortran/omp_cond1.f
@@ -1,5 +1,4 @@
 C Test conditional compilation in fixed form if -fopenmp
-! { dg-options "-fopenmp" }
    10 foo = 2
      &56
       if (foo.ne.256) call abort
diff --git a/libgomp/testsuite/libgomp.fortran/omp_cond3.F90 b/libgomp/testsuite/libgomp.fortran/omp_cond3.F90
index 6c4e36e..fe8c783 100644
--- a/libgomp/testsuite/libgomp.fortran/omp_cond3.F90
+++ b/libgomp/testsuite/libgomp.fortran/omp_cond3.F90
@@ -1,5 +1,4 @@
 ! Test conditional compilation in free form if -fopenmp
-! { dg-options "-fopenmp" }
    10 foo = 2&
   &56
   if (foo.ne.256) call abort
diff --git a/libgomp/testsuite/libgomp.fortran/pr66199-1.f90 b/libgomp/testsuite/libgomp.fortran/pr66199-1.f90
index 0cd232f..55ad627 100644
--- a/libgomp/testsuite/libgomp.fortran/pr66199-1.f90
+++ b/libgomp/testsuite/libgomp.fortran/pr66199-1.f90
@@ -1,6 +1,6 @@
 ! PR middle-end/66199
 ! { dg-do run }
-! { dg-options "-O2 -fopenmp" }
+! { dg-options "-O2" }
 
   integer :: u(1024), v(1024), w(1024), a, b, c, d, e, a1, b1, a2, b2, d1, d2
   a = 1
diff --git a/libgomp/testsuite/libgomp.fortran/pr66199-2.f90 b/libgomp/testsuite/libgomp.fortran/pr66199-2.f90
index e17ab96..0cc0fa5 100644
--- a/libgomp/testsuite/libgomp.fortran/pr66199-2.f90
+++ b/libgomp/testsuite/libgomp.fortran/pr66199-2.f90
@@ -1,6 +1,6 @@
 ! PR middle-end/66199
 ! { dg-do run }
-! { dg-options "-O2 -fopenmp" }
+! { dg-options "-O2" }
 
   integer :: u(1024), v(1024), w(1024), a, b, c, d, e, a1, b1, a2, b2, d1, d2
   a = 1
diff --git a/libgomp/testsuite/libgomp.fortran/recursion1.f90 b/libgomp/testsuite/libgomp.fortran/recursion1.f90
index 35cb878..0cae261 100644
--- a/libgomp/testsuite/libgomp.fortran/recursion1.f90
+++ b/libgomp/testsuite/libgomp.fortran/recursion1.f90
@@ -1,5 +1,5 @@
 ! { dg-do run }
-! { dg-options "-fopenmp -fcheck=recursion" }
+! { dg-options "-fcheck=recursion" }
 !
 ! PR 42517: Bogus runtime error with -fopenmp -fcheck=recursion
 !
diff --git a/libgomp/testsuite/libgomp.fortran/target2.f90 b/libgomp/testsuite/libgomp.fortran/target2.f90
index 42f704f..40b7b0b 100644
--- a/libgomp/testsuite/libgomp.fortran/target2.f90
+++ b/libgomp/testsuite/libgomp.fortran/target2.f90
@@ -1,5 +1,5 @@
 ! { dg-do run }
-! { dg-options "-fopenmp -ffree-line-length-160" }
+! { dg-options "-ffree-line-length-160" }
 
 module target2
 contains
diff --git a/libgomp/testsuite/libgomp.fortran/target5.f90 b/libgomp/testsuite/libgomp.fortran/target5.f90
index c46faf2..4aad88e 100644
--- a/libgomp/testsuite/libgomp.fortran/target5.f90
+++ b/libgomp/testsuite/libgomp.fortran/target5.f90
@@ -1,5 +1,4 @@
 ! { dg-do compile }
-! { dg-options "-fopenmp" }
 
   integer :: r
   r = 0
diff --git a/libgomp/testsuite/libgomp.fortran/task3.f90 b/libgomp/testsuite/libgomp.fortran/task3.f90
index 30ff980..83b0e9f 100644
--- a/libgomp/testsuite/libgomp.fortran/task3.f90
+++ b/libgomp/testsuite/libgomp.fortran/task3.f90
@@ -1,5 +1,4 @@
 ! { dg-do run }
-! { dg-options "-fopenmp" }
 !
 ! PR fortran/47886
 !

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

* Re: [libgomp, testsuite] Remove superfluous -fopenmp from libgomp testcases
  2017-09-28  7:41       ` [libgomp, testsuite] Remove superfluous -fopenmp from libgomp testcases Tom de Vries
@ 2017-09-28  8:37         ` Thomas Schwinge
  2017-09-28 12:12           ` Tom de Vries
  2017-09-28  8:46         ` Jakub Jelinek
  1 sibling, 1 reply; 44+ messages in thread
From: Thomas Schwinge @ 2017-09-28  8:37 UTC (permalink / raw)
  To: Tom de Vries; +Cc: gcc-patches, Jakub Jelinek

Hi Tom!

On Thu, 28 Sep 2017 09:41:15 +0200, Tom de Vries <Tom_deVries@mentor.com> wrote:
> On 11/07/2013 09:11 AM, Jakub Jelinek wrote:
> > On Wed, Nov 06, 2013 at 08:42:16PM +0100, thomas@codesourcery.com wrote:
> >> From: Thomas Schwinge <thomas@codesourcery.com>
> >>
> >> 	libgomp/
> >> 	* testsuite/lib/libgomp.exp (libgomp_init): Don't add -fopenmp to
> >> 	ALWAYS_CFLAGS.
> >> 	* testsuite/libgomp.c++/c++.exp (ALWAYS_CFLAGS): Add -fopenmp.
> >> 	* testsuite/libgomp.c/c.exp (ALWAYS_CFLAGS): Likewise.
> >> 	* testsuite/libgomp.fortran/fortran.exp (ALWAYS_CFLAGS): Likewise.
> >> 	* testsuite/libgomp.graphite/graphite.exp (ALWAYS_CFLAGS):
> >> 	Likewise.

Note that my patch just moved *where* the flag gets set, so...

> Following up on this, how about we drop the now superfluous -fopenmp in 
> current test-cases?

... it has already been superfluous before.  ;-)

Anyway: ACK conceptually.

> Tested on x86_64. Verified by analyzing libgomp.log that -fopenmp is 
> still passed to test-cases as required.
> 
> OK for trunk?

> --- a/libgomp/testsuite/libgomp.c++/for-12.C
> +++ b/libgomp/testsuite/libgomp.c++/for-12.C
> @@ -1,5 +1,3 @@
> -/* { dg-options "-fopenmp" } */

As far as I remember, this means that instead of "-fopenmp" the
"DEFAULT_CFLAGS" will then be used: "-O2", so this effectively changes
testing from "-O2" to "-O2".  Same for a few other cases where you remove
"dg-options" altogether.  Special consideration required for fortran,
which should never specify these in "dg-options" because it cycles
("torture testing") through different optimization flags.

With that fixed: Reviewed-by: Thomas Schwinge <thomas@codesourcery.com>
(See
<http://mid.mail-archive.com/87tvzuk29t.fsf@euler.schwinge.homeip.net>.)
But I can't formally approve, of course.


Grüße
 Thomas

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

* Re: [libgomp, testsuite] Remove superfluous -fopenmp from libgomp testcases
  2017-09-28  7:41       ` [libgomp, testsuite] Remove superfluous -fopenmp from libgomp testcases Tom de Vries
  2017-09-28  8:37         ` Thomas Schwinge
@ 2017-09-28  8:46         ` Jakub Jelinek
  1 sibling, 0 replies; 44+ messages in thread
From: Jakub Jelinek @ 2017-09-28  8:46 UTC (permalink / raw)
  To: Tom de Vries; +Cc: thomas, gcc-patches

On Thu, Sep 28, 2017 at 09:41:15AM +0200, Tom de Vries wrote:
> [ was: Re: [gomp4 2/9] libgomp: Prepare for testcases without -fopenmp. ]
> 
> On 11/07/2013 09:11 AM, Jakub Jelinek wrote:
> > On Wed, Nov 06, 2013 at 08:42:16PM +0100, thomas@codesourcery.com wrote:
> > > From: Thomas Schwinge <thomas@codesourcery.com>
> > > 
> > > 	libgomp/
> > > 	* testsuite/lib/libgomp.exp (libgomp_init): Don't add -fopenmp to
> > > 	ALWAYS_CFLAGS.
> > > 	* testsuite/libgomp.c++/c++.exp (ALWAYS_CFLAGS): Add -fopenmp.
> > > 	* testsuite/libgomp.c/c.exp (ALWAYS_CFLAGS): Likewise.
> > > 	* testsuite/libgomp.fortran/fortran.exp (ALWAYS_CFLAGS): Likewise.
> > > 	* testsuite/libgomp.graphite/graphite.exp (ALWAYS_CFLAGS):
> > > 	Likewise.
> > 
> > Ok for trunk/gomp-4_0-branch.
> 
> Following up on this, how about we drop the now superfluous -fopenmp in
> current test-cases?
> 
> Tested on x86_64. Verified by analyzing libgomp.log that -fopenmp is still
> passed to test-cases as required.
> 
> OK for trunk?
> 
> Thanks,
> - Tom

> Remove superfluous -fopenmp from libgomp testcases
> 
> 2017-09-16  Tom de Vries  <tom@codesourcery.com>
> 
> 	* testsuite/libgomp.c++/for-12.C: Remove superfluous -fopenmp option
> 	setting.
> 	* testsuite/libgomp.c++/pr69393.C: Same.
> 	* testsuite/libgomp.c++/taskloop-1.C: Same.
> 	* testsuite/libgomp.c++/taskloop-3.C: Same.
> 	* testsuite/libgomp.c++/taskloop-4.C: Same.
> 	* testsuite/libgomp.c/for-4.c: Same.
> 	* testsuite/libgomp.c/pr66199-3.c: Same.
> 	* testsuite/libgomp.c/pr66199-4.c: Same.
> 	* testsuite/libgomp.c/pr66199-6.c: Same.
> 	* testsuite/libgomp.c/taskloop-1.c: Same.
> 	* testsuite/libgomp.c/taskloop-3.c: Same.
> 	* testsuite/libgomp.c/taskloop-4.c: Same.
> 	* testsuite/libgomp.fortran/aligned1.f03: Same.
> 	* testsuite/libgomp.fortran/condinc1.f: Same.
> 	* testsuite/libgomp.fortran/condinc3.f90: Same.
> 	* testsuite/libgomp.fortran/crayptr1.f90: Same.
> 	* testsuite/libgomp.fortran/crayptr2.f90: Same.
> 	* testsuite/libgomp.fortran/crayptr3.f90: Same.
> 	* testsuite/libgomp.fortran/omp_cond1.f: Same.
> 	* testsuite/libgomp.fortran/omp_cond3.F90: Same.
> 	* testsuite/libgomp.fortran/pr66199-1.f90: Same.
> 	* testsuite/libgomp.fortran/pr66199-2.f90: Same.
> 	* testsuite/libgomp.fortran/recursion1.f90: Same.
> 	* testsuite/libgomp.fortran/target2.f90: Same.
> 	* testsuite/libgomp.fortran/target5.f90: Same.
> 	* testsuite/libgomp.fortran/task3.f90: Same.

Ok.

	Jakub

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

* Re: [libgomp, testsuite] Remove superfluous -fopenmp from libgomp testcases
  2017-09-28  8:37         ` Thomas Schwinge
@ 2017-09-28 12:12           ` Tom de Vries
  0 siblings, 0 replies; 44+ messages in thread
From: Tom de Vries @ 2017-09-28 12:12 UTC (permalink / raw)
  To: Thomas Schwinge; +Cc: gcc-patches, Jakub Jelinek

On 09/28/2017 10:37 AM, Thomas Schwinge wrote:
> Hi Tom!
> 
> On Thu, 28 Sep 2017 09:41:15 +0200, Tom de Vries <Tom_deVries@mentor.com> wrote:
>> On 11/07/2013 09:11 AM, Jakub Jelinek wrote:
>>> On Wed, Nov 06, 2013 at 08:42:16PM +0100, thomas@codesourcery.com wrote:
>>>> From: Thomas Schwinge <thomas@codesourcery.com>
>>>>
>>>> 	libgomp/
>>>> 	* testsuite/lib/libgomp.exp (libgomp_init): Don't add -fopenmp to
>>>> 	ALWAYS_CFLAGS.
>>>> 	* testsuite/libgomp.c++/c++.exp (ALWAYS_CFLAGS): Add -fopenmp.
>>>> 	* testsuite/libgomp.c/c.exp (ALWAYS_CFLAGS): Likewise.
>>>> 	* testsuite/libgomp.fortran/fortran.exp (ALWAYS_CFLAGS): Likewise.
>>>> 	* testsuite/libgomp.graphite/graphite.exp (ALWAYS_CFLAGS):
>>>> 	Likewise.
> 
> Note that my patch just moved *where* the flag gets set, so...
> 
>> Following up on this, how about we drop the now superfluous -fopenmp in
>> current test-cases?
> 
> ... it has already been superfluous before.  ;-)
> 
> Anyway: ACK conceptually.
> 
>> Tested on x86_64. Verified by analyzing libgomp.log that -fopenmp is
>> still passed to test-cases as required.
>>
>> OK for trunk?
> 
>> --- a/libgomp/testsuite/libgomp.c++/for-12.C
>> +++ b/libgomp/testsuite/libgomp.c++/for-12.C
>> @@ -1,5 +1,3 @@
>> -/* { dg-options "-fopenmp" } */
> 
> As far as I remember, this means that instead of "-fopenmp" the
> "DEFAULT_CFLAGS" will then be used: "-O2", so this effectively changes
> testing from "-O2" to "-O2".

I think you mean from "-O0" to "-O2", but yes.

I was explicit about this in an earlier commit ( 
https://gcc.gnu.org/ml/gcc-patches/2015-06/msg00487.html ), but forgot 
again about it here.

Anyway, I think we only care about preserving explicit "-O0" settings, 
so this should be ok.

> With that fixed: Reviewed-by: Thomas Schwinge <thomas@codesourcery.com>

You just got the first review credits in the commit log since 2004 ;)

Thanks,
- Tom

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

end of thread, other threads:[~2017-09-28 12:12 UTC | newest]

Thread overview: 44+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-11-06 19:44 Initial submission of OpenACC support integrated into OpenMP's lowering and expansion passes Thomas Schwinge
2013-11-06 19:44 ` [gomp4 1/9] Add missing include thomas
2013-11-06 19:44   ` [gomp4 2/9] libgomp: Prepare for testcases without -fopenmp thomas
2013-11-06 19:47     ` [gomp4 3/9] OpenACC: Recognize -fopenacc thomas
2013-11-06 20:39       ` [gomp4 4/9] OpenACC: The runtime library will be implemented in libgomp, too thomas
2013-11-06 19:45         ` [gomp4 5/9] OpenACC: preprocessor definition, Fortran integer parameter thomas
2013-11-06 20:37           ` [gomp4 6/9] OpenACC: Infrastructure for builtins thomas
2013-11-06 19:56             ` [gomp4 7/9] OpenACC: Use OpenMP's lowering and expansion passes thomas
2013-11-06 20:29               ` [gomp4 8/9] OpenACC: Basic support for #pragma acc in the C front end thomas
2013-11-06 19:53                 ` [gomp4 9/9] OpenACC: Basic support for #pragma acc parallel thomas
2013-11-06 20:01                   ` Thomas Schwinge
2013-11-07  8:48                     ` Jakub Jelinek
2014-02-27 19:58                     ` [gomp4] Gimplification: Merge gimplify_oacc_parallel into gimplify_omp_workshare. (was: [gomp4 9/9] OpenACC: Basic support for #pragma acc parallel.) Thomas Schwinge
2014-03-20 14:28                     ` [gomp4 9/9] OpenACC: Basic support for #pragma acc parallel Thomas Schwinge
2014-11-12 13:35                     ` OpenACC GIMPLE_OACC_* -- or not? (was: [gomp4 9/9] OpenACC: Basic support for #pragma acc parallel.) Thomas Schwinge
2014-11-12 13:46                       ` Jakub Jelinek
2014-12-10  9:58                         ` OpenACC GIMPLE_OACC_* -- or not? Thomas Schwinge
2014-12-10 10:07                           ` Thomas Schwinge
2014-12-10 10:10                             ` Jakub Jelinek
2014-12-12 20:02                               ` Thomas Schwinge
2014-12-10 10:02                         ` Nested OpenACC/OpenMP constructs (was: OpenACC GIMPLE_OACC_* -- or not?) Thomas Schwinge
2014-12-10 10:10                           ` Thomas Schwinge
2014-12-10 10:16                             ` Jakub Jelinek
2014-12-12 20:04                               ` Nested OpenACC/OpenMP constructs Thomas Schwinge
2014-12-17 22:21                                 ` OpenACC/OpenMP testing: Revise variable usage in constructs (was: Nested OpenACC/OpenMP constructs) Thomas Schwinge
2013-11-06 20:03                   ` [gomp4 9/9] OpenACC: Basic support for #pragma acc parallel Jakub Jelinek
2013-11-07 19:00                     ` Thomas Schwinge
2013-11-07  8:41                 ` [gomp4 8/9] OpenACC: Basic support for #pragma acc in the C front end Jakub Jelinek
2013-11-07  8:39               ` [gomp4 7/9] OpenACC: Use OpenMP's lowering and expansion passes Jakub Jelinek
2013-11-07  8:23             ` [gomp4 6/9] OpenACC: Infrastructure for builtins Jakub Jelinek
2013-11-07  8:19           ` [gomp4 5/9] OpenACC: preprocessor definition, Fortran integer parameter Jakub Jelinek
2013-11-07  8:18         ` [gomp4 4/9] OpenACC: The runtime library will be implemented in libgomp, too Jakub Jelinek
2013-11-07 14:05           ` Generally link to libgomp for -ftree-parallelize-loops=* (was: [gomp4 4/9] OpenACC: The runtime library will be implemented in libgomp, too.) Thomas Schwinge
2013-11-07 14:48             ` Jakub Jelinek
2013-11-07  8:17       ` [gomp4 3/9] OpenACC: Recognize -fopenacc Jakub Jelinek
2013-11-07  8:16     ` [gomp4 2/9] libgomp: Prepare for testcases without -fopenmp Jakub Jelinek
2017-09-28  7:41       ` [libgomp, testsuite] Remove superfluous -fopenmp from libgomp testcases Tom de Vries
2017-09-28  8:37         ` Thomas Schwinge
2017-09-28 12:12           ` Tom de Vries
2017-09-28  8:46         ` Jakub Jelinek
2013-11-07  8:15   ` [gomp4 1/9] Add missing include Jakub Jelinek
2013-11-07 18:14 ` Initial submission of OpenACC support integrated into OpenMP's lowering and expansion passes Evgeny Gavrin
2013-11-27 23:23   ` Thomas Schwinge
     [not found]   ` <004b01cedc68$a5f3c950$f1db5bf0$%b@samsung.com>
2013-11-27 23:25     ` Thomas Schwinge

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