This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: OpenACC middle end changes


On Thu, Nov 13, 2014 at 5:59 PM, Thomas Schwinge
<thomas@codesourcery.com> wrote:
> Hi!
>
> Here is our current set of OpenACC middle end changes.  As discussed
> before, this is not yet all of OpenACC 2.0 -- we shall a) document what
> is working already, and b) continue to work on closing the gap.
>
> This patch is based on the last merge of trunk into gomp-4_0-branch,
> 9be82689 (trunk r216846, 2014-10-29), and still includes an old version
> of the offloading patches, as currently present on gomp-4_0-branch.
> We're already working on rebasing onto the set of offloading patches that
> has just been committed to trunk, but I didn't want to have this delay
> any further (it seems, the rebase/merge is not always trivial) the
> submission of the OpenACC middle end changes; I asssume the gist of those
> can already be reviewed based on this version.  (That means, just skip
> over the offloading hunks in the patch, and we'll supply the updated
> changes later.)
>
> A few items are still open, such as:
>
>   * whether to use GIMPLE_OACC_* codes oder not,
>     <http://news.gmane.org/find-root.php?message_id=%3C87sihoczm0.fsf%40kepler.schwinge.homeip.net%3E>;
>   * the patch includes some changes to gcc/gimplify.c that are not
>     strictly required ("refactoring", though not fully executed,
>     admittedly) -- is that OK as-is, should present these changes
>     separately, or drop altogether;
>   * include/gomp-constants.h needs to be used more (also in OpenMP code
>     paths; cleanup for later);
>   * I'd like to change some of the values in gcc/tree-core.h:enum
>     omp_clause_map_kind to make these more simple to use in libgomp (and
>     obviously use include/gomp-constants.h here, too);
>   * there are currently a lot of assertions or gcc_unreachable statements
>     being placed in code paths that either genuinely should not be hit
>     for OpenACC codes, or that we have not yet reviewed for suitability
>     for OpenACC (for example, gcc/tree-inline.c, gcc/tree-nested.c),
>     these will gradually be removed as we're completing OpenACC support;
>   * should gcc/oacc-builtins.def just be merged into
>     gcc/omp-builtins.def;
>   * ChangeLog snippets still need to be written.

Badly needed - I wonder why you need changes to LTO files at all.

Richard.

>  configure.ac                                 |   23
>  gcc/Makefile.in                              |   29
>  gcc/ada/gcc-interface/utils.c                |   18
>  gcc/builtin-types.def                        |   10
>  gcc/builtins.c                               |   50
>  gcc/builtins.def                             |   14
>  gcc/c-family/c-common.c                      |   17
>  gcc/cgraph.h                                 |    5
>  gcc/cgraphunit.c                             |   39
>  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                    |    4
>  gcc/config/pa/pa64-hpux.h                    |   24
>  gcc/configure.ac                             |   36
>  gcc/doc/generic.texi                         |   74 +
>  gcc/doc/gimple.texi                          |   20
>  gcc/doc/invoke.texi                          |   14
>  gcc/doc/sourcebuild.texi                     |    3
>  gcc/doc/tm.texi                              |    6
>  gcc/doc/tm.texi.in                           |    2
>  gcc/fortran/f95-lang.c                       |   47
>  gcc/fortran/types.def                        |   11
>  gcc/gcc.c                                    |   37
>  gcc/gengtype.c                               |    2
>  gcc/gimple-low.c                             |    2
>  gcc/gimple-pretty-print.c                    |  117 +
>  gcc/gimple-walk.c                            |   32
>  gcc/gimple.c                                 |   46
>  gcc/gimple.def                               |   34
>  gcc/gimple.h                                 |  417 ++++++
>  gcc/gimplify.c                               |  380 ++++--
>  gcc/ipa-inline-analysis.c                    |   12
>  gcc/lto-cgraph.c                             |  107 +
>  gcc/lto-section-in.c                         |    3
>  gcc/lto-section-names.h                      |    8
>  gcc/lto-streamer-out.c                       |    2
>  gcc/lto-streamer.c                           |    5
>  gcc/lto-streamer.h                           |    4
>  gcc/lto-wrapper.c                            |  272 ++++
>  gcc/lto/lto-lang.c                           |   17
>  gcc/lto/lto-object.c                         |    3
>  gcc/lto/lto-partition.c                      |    3
>  gcc/lto/lto.c                                |    8
>  gcc/oacc-builtins.def                        |   56
>  gcc/omp-low.c                                | 1633 ++++++++++++++++++++++++---
>  gcc/omp-low.h                                |    4
>  gcc/passes.c                                 |    6
>  gcc/target.def                               |    8
>  gcc/testsuite/g++.dg/gomp/block-1.C          |    2
>  gcc/testsuite/g++.dg/gomp/block-2.C          |    2
>  gcc/testsuite/g++.dg/gomp/block-3.C          |    4
>  gcc/testsuite/g++.dg/gomp/block-5.C          |    2
>  gcc/testsuite/g++.dg/gomp/target-1.C         |    2
>  gcc/testsuite/g++.dg/gomp/target-2.C         |    2
>  gcc/testsuite/g++.dg/gomp/taskgroup-1.C      |    2
>  gcc/testsuite/g++.dg/gomp/teams-1.C          |    4
>  gcc/testsuite/gcc.dg/cilk-plus/jump-openmp.c |    4
>  gcc/testsuite/gcc.dg/cilk-plus/jump.c        |    4
>  gcc/testsuite/gcc.dg/gomp/block-1.c          |    4
>  gcc/testsuite/gcc.dg/gomp/block-10.c         |   12
>  gcc/testsuite/gcc.dg/gomp/block-2.c          |    4
>  gcc/testsuite/gcc.dg/gomp/block-3.c          |    8
>  gcc/testsuite/gcc.dg/gomp/block-4.c          |    2
>  gcc/testsuite/gcc.dg/gomp/block-5.c          |    4
>  gcc/testsuite/gcc.dg/gomp/block-6.c          |    2
>  gcc/testsuite/gcc.dg/gomp/block-7.c          |   12
>  gcc/testsuite/gcc.dg/gomp/block-8.c          |    2
>  gcc/testsuite/gcc.dg/gomp/block-9.c          |    2
>  gcc/testsuite/gcc.dg/gomp/target-1.c         |    6
>  gcc/testsuite/gcc.dg/gomp/target-2.c         |    6
>  gcc/testsuite/gcc.dg/gomp/taskgroup-1.c      |    6
>  gcc/testsuite/gcc.dg/gomp/teams-1.c          |   12
>  gcc/toplev.c                                 |    3
>  gcc/tree-core.h                              |  101 +
>  gcc/tree-inline.c                            |    8
>  gcc/tree-nested.c                            |   26
>  gcc/tree-pass.h                              |    2
>  gcc/tree-pretty-print.c                      |  145 ++
>  gcc/tree.c                                   |   38
>  gcc/tree.def                                 |   56
>  gcc/tree.h                                   |   80 +
>  libgcc/Makefile.in                           |    6
>  libgcc/configure.ac                          |   12
>  libgcc/ompstuff.c                            |   73 +
>  86 files changed, 3857 insertions(+), 475 deletions(-)
>
> diff --git configure.ac configure.ac
> index b62af38..7b24958 100644
> --- configure.ac
> +++ configure.ac
> @@ -286,6 +286,15 @@ case ${with_newlib} in
>    yes) skipdirs=`echo " ${skipdirs} " | sed -e 's/ target-newlib / /'` ;;
>  esac
>
> +AC_ARG_ENABLE(offload-targets,
> +[AS_HELP_STRING([--enable-offload-targets=LIST],
> + [enable offloading to devices from LIST])],
> +[
> +  if test x"$enable_offload_targets" = x; then
> +    AC_MSG_ERROR([no offload targets specified])
> +  fi
> +], [enable_offload_targets=])
> +
>  # Handle --enable-gold, --enable-ld.
>  # --disable-gold [--enable-ld]
>  #     Build only ld.  Default option.
> @@ -1852,7 +1861,6 @@ if test -d ${srcdir}/gcc; then
>    new_enable_languages=,c,
>
>    # If LTO is enabled, add the LTO front end.
> -  extra_host_libiberty_configure_flags=
>    if test "$enable_lto" = "yes" ; then
>      case ,${enable_languages}, in
>        *,lto,*) ;;
> @@ -1860,10 +1868,8 @@ if test -d ${srcdir}/gcc; then
>      esac
>      if test "${build_lto_plugin}" = "yes" ; then
>        configdirs="$configdirs lto-plugin"
> -      extra_host_libiberty_configure_flags=--enable-shared
>      fi
>    fi
> -  AC_SUBST(extra_host_libiberty_configure_flags)
>
>    missing_languages=`echo ",$enable_languages," | sed -e s/,all,/,/ -e s/,c,/,/ `
>    potential_languages=,c,
> @@ -2177,6 +2183,17 @@ then
>    esac
>  fi
>
> +# Sometimes we have special requirements for the host libiberty.
> +extra_host_libiberty_configure_flags=
> +case " $configdirs " in
> +  *" lto-plugin "* | *" libcc1 "*)
> +    # When these are to be built as shared libraries, the same applies to
> +    # libiberty.
> +    extra_host_libiberty_configure_flags=--enable-shared
> +    ;;
> +esac
> +AC_SUBST(extra_host_libiberty_configure_flags)
> +
>  # Produce a warning message for the subdirs we can't configure.
>  # This isn't especially interesting in the Cygnus tree, but in the individual
>  # FSF releases, it's important to let people know when their machine isn't
> diff --git gcc/Makefile.in gcc/Makefile.in
> index a74df1f..946040c 100644
> --- gcc/Makefile.in
> +++ gcc/Makefile.in
> @@ -58,6 +58,7 @@ build=@build@
>  host=@host@
>  target=@target@
>  target_noncanonical:=@target_noncanonical@
> +real_target_noncanonical:=@real_target_noncanonical@
>
>  # Sed command to transform gcc to installed name.
>  program_transform_name := @program_transform_name@
> @@ -66,6 +67,10 @@ program_transform_name := @program_transform_name@
>  # Directories used during build
>  # -----------------------------
>
> +# Normally identical to target_noncanonical, except for compilers built
> +# as accelerator targets.
> +accel_dir_suffix = @accel_dir_suffix@
> +
>  # Directory where sources are, from where we are.
>  srcdir = @srcdir@
>  gcc_docdir = @srcdir@/doc
> @@ -362,6 +367,8 @@ enable_plugin = @enable_plugin@
>
>  enable_host_shared = @enable_host_shared@
>
> +enable_as_accelerator = @enable_as_accelerator@
> +
>  CPPLIB = ../libcpp/libcpp.a
>  CPPINC = -I$(srcdir)/../libcpp/include
>
> @@ -573,9 +580,9 @@ libexecdir = @libexecdir@
>  # --------
>
>  # Directory in which the compiler finds libraries etc.
> -libsubdir = $(libdir)/gcc/$(target_noncanonical)/$(version)
> +libsubdir = $(libdir)/gcc/$(real_target_noncanonical)/$(version)$(accel_dir_suffix)
>  # Directory in which the compiler finds executables
> -libexecsubdir = $(libexecdir)/gcc/$(target_noncanonical)/$(version)
> +libexecsubdir = $(libexecdir)/gcc/$(real_target_noncanonical)/$(version)$(accel_dir_suffix)
>  # Directory in which all plugin resources are installed
>  plugin_resourcesdir = $(libsubdir)/plugin
>   # Directory in which plugin headers are installed
> @@ -583,7 +590,11 @@ plugin_includedir = $(plugin_resourcesdir)/include
>  # Directory in which plugin specific executables are installed
>  plugin_bindir = $(libexecsubdir)/plugin
>  # Used to produce a relative $(gcc_tooldir) in gcc.o
> +ifeq ($(enable_as_accelerator),yes)
> +unlibsubdir = ../../../../..
> +else
>  unlibsubdir = ../../..
> +endif
>  # $(prefix), expressed as a path relative to $(libsubdir).
>  #
>  # An explanation of the sed strings:
> @@ -861,7 +872,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)
> @@ -1942,9 +1954,11 @@ DRIVER_DEFINES = \
>    -DSTANDARD_EXEC_PREFIX=\"$(libdir)/gcc/\" \
>    -DSTANDARD_LIBEXEC_PREFIX=\"$(libexecdir)/gcc/\" \
>    -DDEFAULT_TARGET_VERSION=\"$(version)\" \
> +  -DDEFAULT_REAL_TARGET_MACHINE=\"$(real_target_noncanonical)\" \
>    -DDEFAULT_TARGET_MACHINE=\"$(target_noncanonical)\" \
>    -DSTANDARD_BINDIR_PREFIX=\"$(bindir)/\" \
>    -DTOOLDIR_BASE_PREFIX=\"$(libsubdir_to_prefix)$(prefix_to_exec_prefix)\" \
> +  -DACCEL_DIR_SUFFIX=\"$(accel_dir_suffix)\" \
>    @TARGET_SYSTEM_ROOT_DEFINE@ \
>    $(VALGRIND_DRIVER_DEFINES) \
>    $(if $(SHLIB),$(if $(filter yes,@enable_shared@),-DENABLE_SHARED_LIBGCC)) \
> @@ -2291,6 +2305,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
>    $(srcdir)/tree-profile.c $(srcdir)/tree-nested.c \
>    $(srcdir)/tree-parloops.c \
>    $(srcdir)/omp-low.c \
> +  $(srcdir)/omp-low.h \
>    $(srcdir)/targhooks.c $(out_file) $(srcdir)/passes.c $(srcdir)/cgraphunit.c \
>    $(srcdir)/cgraphclones.c \
>    $(srcdir)/tree-phinodes.c \
> @@ -3280,17 +3295,19 @@ install-common: native lang.install-common installdirs
>  install-driver: installdirs xgcc$(exeext)
>         -rm -f $(DESTDIR)$(bindir)/$(GCC_INSTALL_NAME)$(exeext)
>         -$(INSTALL_PROGRAM) xgcc$(exeext) $(DESTDIR)$(bindir)/$(GCC_INSTALL_NAME)$(exeext)
> -       -if [ "$(GCC_INSTALL_NAME)" != "$(target_noncanonical)-gcc-$(version)" ]; then \
> +       -if test "@enable_as_accelerator@" != "yes" ; then \
> +       if [ "$(GCC_INSTALL_NAME)" != "$(target_noncanonical)-gcc-$(version)" ]; then \
>           rm -f $(DESTDIR)$(bindir)/$(target_noncanonical)-gcc-$(version)$(exeext); \
>           ( cd $(DESTDIR)$(bindir) && \
>             $(LN) $(GCC_INSTALL_NAME)$(exeext) $(target_noncanonical)-gcc-$(version)$(exeext) ); \
> -       fi
> -       -if [ ! -f gcc-cross$(exeext) ] \
> +       fi; \
> +       if [ ! -f gcc-cross$(exeext) ] \
>             && [ "$(GCC_INSTALL_NAME)" != "$(GCC_TARGET_INSTALL_NAME)" ]; then \
>           rm -f $(DESTDIR)$(bindir)/$(target_noncanonical)-gcc-tmp$(exeext); \
>           ( cd $(DESTDIR)$(bindir) && \
>             $(LN) $(GCC_INSTALL_NAME)$(exeext) $(target_noncanonical)-gcc-tmp$(exeext) && \
>             mv -f $(target_noncanonical)-gcc-tmp$(exeext) $(GCC_TARGET_INSTALL_NAME)$(exeext) ); \
> +       fi; \
>         fi
>
>  # Install the info files.
> diff --git gcc/ada/gcc-interface/utils.c gcc/ada/gcc-interface/utils.c
> index 39350f7..4289c5f 100644
> --- gcc/ada/gcc-interface/utils.c
> +++ gcc/ada/gcc-interface/utils.c
> @@ -5353,6 +5353,12 @@ enum c_builtin_type
>  #define DEF_FUNCTION_TYPE_VAR_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
>  #define DEF_FUNCTION_TYPE_VAR_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
>    NAME,
> +#define DEF_FUNCTION_TYPE_VAR_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
> +                               ARG6, ARG7, ARG8)                       \
> +  NAME,
> +#define DEF_FUNCTION_TYPE_VAR_12(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
> +                                ARG6, ARG7, ARG8, ARG9, ARG10, ARG11, ARG12) \
> +  NAME,
>  #define DEF_POINTER_TYPE(NAME, TYPE) NAME,
>  #include "builtin-types.def"
>  #undef DEF_PRIMITIVE_TYPE
> @@ -5371,6 +5377,8 @@ enum c_builtin_type
>  #undef DEF_FUNCTION_TYPE_VAR_3
>  #undef DEF_FUNCTION_TYPE_VAR_4
>  #undef DEF_FUNCTION_TYPE_VAR_5
> +#undef DEF_FUNCTION_TYPE_VAR_8
> +#undef DEF_FUNCTION_TYPE_VAR_12
>  #undef DEF_POINTER_TYPE
>    BT_LAST
>  };
> @@ -5476,6 +5484,14 @@ install_builtin_function_types (void)
>    def_fn_type (ENUM, RETURN, 1, 4, ARG1, ARG2, ARG3, ARG4);
>  #define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
>    def_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, ARG4, ARG5);
> +#define DEF_FUNCTION_TYPE_VAR_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
> +                               ARG6, ARG7, ARG8)                       \
> +  def_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \
> +              ARG7, ARG8);
> +#define DEF_FUNCTION_TYPE_VAR_12(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
> +                                ARG6, ARG7, ARG8, ARG9, ARG10, ARG11, ARG12) \
> +  def_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \
> +              ARG7, ARG8, ARG9, ARG10, ARG11, ARG12);
>  #define DEF_POINTER_TYPE(ENUM, TYPE) \
>    builtin_types[(int) ENUM] = build_pointer_type (builtin_types[(int) TYPE]);
>
> @@ -5497,6 +5513,8 @@ install_builtin_function_types (void)
>  #undef DEF_FUNCTION_TYPE_VAR_3
>  #undef DEF_FUNCTION_TYPE_VAR_4
>  #undef DEF_FUNCTION_TYPE_VAR_5
> +#undef DEF_FUNCTION_TYPE_VAR_8
> +#undef DEF_FUNCTION_TYPE_VAR_12
>  #undef DEF_POINTER_TYPE
>    builtin_types[(int) BT_LAST] = NULL_TREE;
>  }
> diff --git gcc/builtin-types.def gcc/builtin-types.def
> index 6434bf2..13f6d52 100644
> --- gcc/builtin-types.def
> +++ gcc/builtin-types.def
> @@ -537,6 +537,8 @@ DEF_FUNCTION_TYPE_VAR_2 (BT_FN_INT_INT_CONST_STRING_VAR,
>                          BT_INT, BT_INT, BT_CONST_STRING)
>  DEF_FUNCTION_TYPE_VAR_2 (BT_FN_PTR_CONST_PTR_SIZE_VAR, BT_PTR,
>                          BT_CONST_PTR, BT_SIZE)
> +DEF_FUNCTION_TYPE_VAR_2 (BT_FN_VOID_INT_INT_VAR, BT_VOID,
> +                        BT_INT, BT_INT)
>
>  DEF_FUNCTION_TYPE_VAR_3 (BT_FN_INT_STRING_SIZE_CONST_STRING_VAR,
>                          BT_INT, BT_STRING, BT_SIZE, BT_CONST_STRING)
> @@ -555,6 +557,14 @@ DEF_FUNCTION_TYPE_VAR_5 (BT_FN_INT_STRING_SIZE_INT_SIZE_CONST_STRING_VAR,
>  DEF_FUNCTION_TYPE_VAR_5 (BT_FN_INT_INT_INT_INT_INT_INT_VAR,
>                          BT_INT, BT_INT, BT_INT, BT_INT, BT_INT, BT_INT)
>
> +DEF_FUNCTION_TYPE_VAR_8 (BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR_INT_INT_VAR,
> +                        BT_VOID, BT_INT, BT_PTR, BT_SIZE, BT_PTR, BT_PTR,
> +                        BT_PTR, BT_INT, BT_INT)
> +
> +DEF_FUNCTION_TYPE_VAR_12 (BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR_INT_INT_INT_INT_INT_VAR,
> +        BT_VOID, BT_INT, BT_PTR_FN_VOID_PTR, BT_PTR, BT_SIZE, BT_PTR, BT_PTR,
> +        BT_PTR, BT_INT, BT_INT, BT_INT, BT_INT, BT_INT)
> +
>  DEF_POINTER_TYPE (BT_PTR_FN_VOID_VAR, BT_FN_VOID_VAR)
>  DEF_FUNCTION_TYPE_3 (BT_FN_PTR_PTR_FN_VOID_VAR_PTR_SIZE,
>                      BT_PTR, BT_PTR_FN_VOID_VAR, BT_PTR, BT_SIZE)
> diff --git gcc/builtins.c gcc/builtins.c
> index dd0869d..98c62a2 100644
> --- gcc/builtins.c
> +++ gcc/builtins.c
> @@ -5751,6 +5751,49 @@ expand_stack_save (void)
>    return ret;
>  }
>
> +
> +/* Expand OpenACC acc_on_device.
> +
> +   This has to happen late (that is, not in early folding; expand_builtin_*,
> +   rather than fold_builtin_*), as we have to act differently for host and
> +   acceleration device (ACCEL_COMPILER conditional).  */
> +
> +static rtx
> +expand_builtin_acc_on_device (tree exp, rtx target ATTRIBUTE_UNUSED)
> +{
> +  if (!validate_arglist (exp, INTEGER_TYPE, VOID_TYPE))
> +    return NULL_RTX;
> +
> +  tree arg, v1, v2, ret;
> +  location_t loc;
> +
> +  arg = CALL_EXPR_ARG (exp, 0);
> +  arg = builtin_save_expr (arg);
> +  loc = EXPR_LOCATION (exp);
> +
> +  /* Build: (arg == v1 || arg == v2) ? 1 : 0.  */
> +
> +#ifdef ACCEL_COMPILER
> +  v1 = build_int_cst (TREE_TYPE (arg), /* TODO: acc_device_not_host */ 3);
> +  v2 = build_int_cst (TREE_TYPE (arg), ACCEL_COMPILER_acc_device);
> +#else
> +  v1 = build_int_cst (TREE_TYPE (arg), /* TODO: acc_device_none */ 0);
> +  v2 = build_int_cst (TREE_TYPE (arg), /* TODO: acc_device_host */ 2);
> +#endif
> +
> +  v1 = fold_build2_loc (loc, EQ_EXPR, integer_type_node, arg, v1);
> +  v2 = fold_build2_loc (loc, EQ_EXPR, integer_type_node, arg, v2);
> +
> +  /* Can't use TRUTH_ORIF_EXPR, as that is not supported by
> +     expand_expr_real*.  */
> +  ret = fold_build3_loc (loc, COND_EXPR, integer_type_node, v1, v1, v2);
> +  ret = fold_build3_loc (loc, COND_EXPR, integer_type_node,
> +                        ret, integer_one_node, integer_zero_node);
> +
> +  return expand_normal (ret);
> +}
> +
> +
>  /* Expand an expression EXP that calls a built-in function,
>     with result going to TARGET if that's convenient
>     (and in mode MODE if that's convenient).
> @@ -6828,6 +6871,12 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
>        expand_builtin_cilk_pop_frame (exp);
>        return const0_rtx;
>
> +    case BUILT_IN_ACC_ON_DEVICE:
> +      target = expand_builtin_acc_on_device (exp, target);
> +      if (target)
> +       return target;
> +      break;
> +
>      default:   /* just do library call, if unknown builtin */
>        break;
>      }
> @@ -12705,6 +12754,7 @@ is_inexpensive_builtin (tree decl)
>        case BUILT_IN_LABS:
>        case BUILT_IN_LLABS:
>        case BUILT_IN_PREFETCH:
> +      case BUILT_IN_ACC_ON_DEVICE:
>         return true;
>
>        default:
> diff --git gcc/builtins.def gcc/builtins.def
> index cd823a3..b9b8e74 100644
> --- gcc/builtins.def
> +++ gcc/builtins.def
> @@ -146,6 +146,17 @@ 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.  Few of these are
> +   actually implemented in the compiler; most are 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)
> +#undef DEF_GOACC_BUILTIN_COMPILER
> +#define DEF_GOACC_BUILTIN_COMPILER(ENUM, NAME, TYPE, ATTRS) \
> +  DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE,    \
> +               flag_openacc, true, true, ATTRS, false, true)
> +
>  /* 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
> @@ -864,6 +875,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/c-family/c-common.c gcc/c-family/c-common.c
> index 03137fe..64f1edb 100644
> --- gcc/c-family/c-common.c
> +++ gcc/c-family/c-common.c
> @@ -5187,6 +5187,11 @@ enum c_builtin_type
>  #define DEF_FUNCTION_TYPE_VAR_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
>  #define DEF_FUNCTION_TYPE_VAR_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
>    NAME,
> +#define DEF_FUNCTION_TYPE_VAR_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
> +                               ARG6, ARG7, ARG8) NAME,
> +#define DEF_FUNCTION_TYPE_VAR_12(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
> +                                ARG6, ARG7, ARG8, ARG9, ARG10, ARG11,       \
> +                                ARG12) NAME,
>  #define DEF_POINTER_TYPE(NAME, TYPE) NAME,
>  #include "builtin-types.def"
>  #undef DEF_PRIMITIVE_TYPE
> @@ -5205,6 +5210,8 @@ enum c_builtin_type
>  #undef DEF_FUNCTION_TYPE_VAR_3
>  #undef DEF_FUNCTION_TYPE_VAR_4
>  #undef DEF_FUNCTION_TYPE_VAR_5
> +#undef DEF_FUNCTION_TYPE_VAR_8
> +#undef DEF_FUNCTION_TYPE_VAR_12
>  #undef DEF_POINTER_TYPE
>    BT_LAST
>  };
> @@ -5297,6 +5304,14 @@ c_define_builtins (tree va_list_ref_type_node, tree va_list_arg_type_node)
>    def_fn_type (ENUM, RETURN, 1, 4, ARG1, ARG2, ARG3, ARG4);
>  #define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
>    def_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, ARG4, ARG5);
> +#define DEF_FUNCTION_TYPE_VAR_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
> +                               ARG6, ARG7, ARG8)                           \
> +  def_fn_type (ENUM, RETURN, 1, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6,      \
> +              ARG7, ARG8);
> +#define DEF_FUNCTION_TYPE_VAR_12(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
> +                                ARG6, ARG7, ARG8, ARG9, ARG10, ARG11, ARG12) \
> +  def_fn_type (ENUM, RETURN, 1, 12, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6,      \
> +              ARG7, ARG8, ARG9, ARG10, ARG11, ARG12);
>  #define DEF_POINTER_TYPE(ENUM, TYPE) \
>    builtin_types[(int) ENUM] = build_pointer_type (builtin_types[(int) TYPE]);
>
> @@ -5318,6 +5333,8 @@ c_define_builtins (tree va_list_ref_type_node, tree va_list_arg_type_node)
>  #undef DEF_FUNCTION_TYPE_VAR_3
>  #undef DEF_FUNCTION_TYPE_VAR_4
>  #undef DEF_FUNCTION_TYPE_VAR_5
> +#undef DEF_FUNCTION_TYPE_VAR_8
> +#undef DEF_FUNCTION_TYPE_VAR_12
>  #undef DEF_POINTER_TYPE
>    builtin_types[(int) BT_LAST] = NULL_TREE;
>
> diff --git gcc/cgraph.h gcc/cgraph.h
> index ae73f07..6f9dcee 100644
> --- gcc/cgraph.h
> +++ gcc/cgraph.h
> @@ -450,6 +450,11 @@ public:
>    /* Set when init priority is set.  */
>    unsigned in_init_priority_hash : 1;
>
> +  /* Set when symbol needs to be dumped into LTO bytecode for LTO,
> +     or in pragma omp target case, for separate compilation targeting
> +     a different architecture.  */
> +  unsigned need_dump : 1;
> +
>
>    /* Ordering of all symtab entries.  */
>    int order;
> diff --git gcc/cgraphunit.c gcc/cgraphunit.c
> index 6f61f5c..8b7e6c9 100644
> --- gcc/cgraphunit.c
> +++ gcc/cgraphunit.c
> @@ -223,6 +223,8 @@ along with GCC; see the file COPYING3.  If not see
>  #include "tree-nested.h"
>  #include "gimplify.h"
>  #include "dbgcnt.h"
> +#include "omp-low.h"
> +#include "lto-section-names.h"
>
>  /* Queue of cgraph nodes scheduled to be added into cgraph.  This is a
>     secondary queue used during optimization to accommodate passes that
> @@ -2009,6 +2011,24 @@ output_in_order (bool no_reorder)
>    free (nodes);
>  }
>
> +/* Collect all global variables with "omp declare target" attribute into
> +   OFFLOAD_VARS.  It will be streamed out in ipa_write_summaries.  */
> +
> +static void
> +init_offload_var_table (void)
> +{
> +  struct varpool_node *vnode;
> +  FOR_EACH_DEFINED_VARIABLE (vnode)
> +    {
> +      if (!lookup_attribute ("omp declare target",
> +                            DECL_ATTRIBUTES (vnode->decl))
> +         || TREE_CODE (vnode->decl) != VAR_DECL
> +         || DECL_SIZE (vnode->decl) == 0)
> +       continue;
> +      vec_safe_push (offload_vars, vnode->decl);
> +    }
> +}
> +
>  static void
>  ipa_passes (void)
>  {
> @@ -2056,7 +2076,22 @@ ipa_passes (void)
>      targetm.asm_out.lto_start ();
>
>    if (!in_lto_p)
> -    ipa_write_summaries ();
> +    {
> +      init_offload_var_table ();
> +
> +      if ((flag_openacc || flag_openmp)
> +         && !(vec_safe_is_empty (offload_funcs)
> +              && vec_safe_is_empty (offload_vars)))
> +       {
> +         section_name_prefix = OMP_SECTION_NAME_PREFIX;
> +         ipa_write_summaries (true);
> +       }
> +      if (flag_lto)
> +       {
> +         section_name_prefix = LTO_SECTION_NAME_PREFIX;
> +         ipa_write_summaries (false);
> +       }
> +    }
>
>    if (flag_generate_lto)
>      targetm.asm_out.lto_end ();
> @@ -2137,7 +2172,7 @@ symbol_table::compile (void)
>    state = IPA;
>
>    /* If LTO is enabled, initialize the streamer hooks needed by GIMPLE.  */
> -  if (flag_lto)
> +  if (flag_lto || flag_openacc || flag_openmp)
>      lto_streamer_hooks_init ();
>
>    /* Don't run the IPA passes if there was any error or sorry messages.  */
> diff --git gcc/config/arc/arc.h gcc/config/arc/arc.h
> index d40f5c3..b278f56 100644
> --- gcc/config/arc/arc.h
> +++ gcc/config/arc/arc.h
> @@ -173,7 +173,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|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)}\
> +    %{fopenacc|fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)}\
>      %(mflib)\
>      %{fprofile-arcs|fprofile-generate|coverage:-lgcov}\
>      %{!nostdlib:%{!nodefaultlibs:%(link_ssp) %(link_gcc_c_sequence)}}\
> diff --git gcc/config/darwin.h gcc/config/darwin.h
> index d973d1d..6f1d5cc 100644
> --- gcc/config/darwin.h
> +++ gcc/config/darwin.h
> @@ -177,7 +177,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 4cfd5f0..cc3aa31 100644
> --- gcc/config/i386/mingw32.h
> +++ gcc/config/i386/mingw32.h
> @@ -199,7 +199,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 fa9aca5..6197b63 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|ftree-parallelize-loops=*:-lrt} -lpthread} \
> +     %{mt|pthread:%{fopenacc|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 8885cd0..42e5f9f 100644
> --- gcc/config/pa/pa-hpux11.h
> +++ gcc/config/pa/pa-hpux11.h
> @@ -122,8 +122,8 @@ along with GCC; see the file COPYING3.  If not see
>  #undef LIB_SPEC
>  #define LIB_SPEC \
>    "%{!shared:\
> -     %{fopenmp|ftree-parallelize-loops=*:%{static:-a archive_shared} -lrt\
> -       %{static:-a archive}}\
> +     %{fopenacc|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 fede450..51a7450 100644
> --- gcc/config/pa/pa64-hpux.h
> +++ gcc/config/pa/pa64-hpux.h
> @@ -58,22 +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|ftree-parallelize-loops=*:%{static:-a shared} -lrt\
> -                  %{static:-a archive}}\
> +     %{!p:%{!pg:%{fopenacc|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|ftree-parallelize-loops=*:%{static:-a shared} -lrt\
> -             %{static:-a archive}}\
> +          %{fopenacc|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|ftree-parallelize-loops=*:%{static:-a shared} -lrt\
> -         %{static:-a archive}}\
> +       %{fopenacc|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}}}}}\
> @@ -81,22 +81,22 @@ along with GCC; see the file COPYING3.  If not see
>  #else
>  #define LIB_SPEC \
>    "%{!shared:\
> -     %{!p:%{!pg:%{fopenmp|ftree-parallelize-loops=*:%{static:-a shared} -lrt\
> -                  %{static:-a archive}}\
> +     %{!p:%{!pg:%{fopenacc|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|ftree-parallelize-loops=*:%{static:-a shared} -lrt\
> -             %{static:-a archive}}\
> +          %{fopenacc|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|ftree-parallelize-loops=*:%{static:-a shared} -lrt\
> -         %{static:-a archive}}\
> +       %{fopenacc|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/configure.ac gcc/configure.ac
> index 02bb306..9fc7d51 100644
> --- gcc/configure.ac
> +++ gcc/configure.ac
> @@ -38,6 +38,10 @@ AC_CANONICAL_TARGET
>  # Determine the noncanonical target name, for directory use.
>  ACX_NONCANONICAL_TARGET
>
> +# Used for constructing correct paths for offload compilers.
> +real_target_noncanonical=${target_noncanonical}
> +accel_dir_suffix=
> +
>  # Determine the target- and build-specific subdirectories
>  GCC_TOPLEV_SUBDIRS
>
> @@ -883,6 +887,36 @@ AC_ARG_ENABLE(languages,
>  esac],
>  [enable_languages=c])
>
> +AC_ARG_ENABLE(as-accelerator-for,
> +[AS_HELP_STRING([--enable-as-accelerator-for], [build compiler as accelerator target for given host])],
> +[
> +  AC_DEFINE(ACCEL_COMPILER, 1,
> +   [Define if this compiler should be built and used as the target
> +    device compiler for OpenACC.])
> +  enable_as_accelerator=yes
> +  sedscript="s#${target_noncanonical}#${enable_as_accelerator_for}-accel-${target_noncanonical}#"
> +  program_transform_name=`echo $program_transform_name | sed $sedscript`
> +  accel_dir_suffix=/accel/${target_noncanonical}
> +  real_target_noncanonical=${enable_as_accelerator_for}
> +], [enable_as_accelerator=no])
> +AC_SUBST(enable_as_accelerator)
> +
> +AC_ARG_ENABLE(offload-targets,
> +[AS_HELP_STRING([--enable-offload-targets=LIST],
> + [enable offloading to devices from LIST])],
> +[
> +  if test x"$enable_offload_targets" = x; then
> +    AC_MSG_ERROR([no offload targets specified])
> +  fi
> +], [enable_offload_targets=])
> +enable_offload_targets=`echo "$enable_offload_targets" | sed -e 's#,#:#g'`
> +AC_DEFINE_UNQUOTED(OFFLOAD_TARGETS, "$enable_offload_targets",
> + [Define to hold the list of target names suitable for offloading.])
> +if test x"$enable_offload_targets" != x; then
> +  AC_DEFINE(ENABLE_OFFLOADING, 1,
> +    [Define this to enable support for offloading.])
> +fi
> +
>  AC_ARG_WITH(multilib-list,
>  [AS_HELP_STRING([--with-multilib-list], [select multilibs (AArch64, SH and x86-64 only)])],
>  :,
> @@ -5512,6 +5546,8 @@ AC_SUBST(c_target_objs)
>  AC_SUBST(cxx_target_objs)
>  AC_SUBST(fortran_target_objs)
>  AC_SUBST(target_cpu_default)
> +AC_SUBST(real_target_noncanonical)
> +AC_SUBST(accel_dir_suffix)
>
>  AC_SUBST_FILE(language_hooks)
>
> diff --git gcc/doc/generic.texi gcc/doc/generic.texi
> index 8a2481e..0d12851 100644
> --- gcc/doc/generic.texi
> +++ gcc/doc/generic.texi
> @@ -1818,7 +1818,7 @@ There are also several varieties of complex statements.
>  * Empty Statements::
>  * Jumps::
>  * Cleanups::
> -* OpenMP::
> +* OpenACC and OpenMP::
>  @end menu
>
>  @node Basic Statements
> @@ -2047,8 +2047,18 @@ EH lowering pass which runs before most of the optimization passes
>  eliminates these expressions by explicitly adding the cleanup to each
>  edge.  Rethrowing the exception is represented using @code{RESX_EXPR}.
>
> -@node OpenMP
> -@subsection OpenMP
> +@node OpenACC and OpenMP
> +@subsection OpenACC and OpenMP
> +@tindex OACC_CACHE
> +@tindex OACC_DATA
> +@tindex OACC_DECLARE
> +@tindex OACC_ENTER_DATA
> +@tindex OACC_EXIT_DATA
> +@tindex OACC_HOST_DATA
> +@tindex OACC_KERNELS
> +@tindex OACC_LOOP
> +@tindex OACC_PARALLEL
> +@tindex OACC_UPDATE
>  @tindex OMP_PARALLEL
>  @tindex OMP_FOR
>  @tindex OMP_SECTIONS
> @@ -2062,10 +2072,54 @@ edge.  Rethrowing the exception is represented using @code{RESX_EXPR}.
>  @tindex OMP_ATOMIC
>  @tindex OMP_CLAUSE
>
> -All the statements starting with @code{OMP_} represent directives and
> -clauses used by the OpenMP API @w{@uref{http://www.openmp.org/}}.
> +All the statements starting with @code{OACC_}, and @code{OMP_}
> +represent directives and clauses used by the OpenACC API
> +@w{@uref{http://www.openacc.org/}}, and OpenMP API
> +@w{@uref{http://www.openmp.org/}}, respectively.
>
>  @table @code
> +@item OACC_CACHE
> +
> +Represents @code{#pragma acc cache (var @dots{})}.
> +
> +@item OACC_DATA
> +
> +Represents @code{#pragma acc data [clause1 @dots{} clauseN]}.
> +
> +@item OACC_DECLARE
> +
> +Represents @code{#pragma acc declare [clause1 @dots{} clauseN]}.
> +
> +@item OACC_ENTER_DATA
> +
> +Represents @code{#pragma acc enter data [clause1 @dots{} clauseN]}.
> +
> +@item OACC_EXIT_DATA
> +
> +Represents @code{#pragma acc exit data [clause1 @dots{} clauseN]}.
> +
> +@item OACC_HOST_DATA
> +
> +Represents @code{#pragma acc host_data [clause1 @dots{} clauseN]}.
> +
> +@item OACC_KERNELS
> +
> +Represents @code{#pragma acc kernels [clause1 @dots{} clauseN]}.
> +
> +@item OACC_LOOP
> +
> +Represents @code{#pragma acc loop [clause1 @dots{} clauseN]}.
> +
> +See the description of the @code{OMP_FOR} code.
> +
> +@item OACC_PARALLEL
> +
> +Represents @code{#pragma acc parallel [clause1 @dots{} clauseN]}.
> +
> +@item OACC_UPDATE
> +
> +Represents @code{#pragma acc update [clause1 @dots{} clauseN]}.
> +
>  @item OMP_PARALLEL
>
>  Represents @code{#pragma omp parallel [clause1 @dots{} clauseN]}. It
> @@ -2093,8 +2147,8 @@ variables.
>
>  @item OMP_FOR
>
> -Represents @code{#pragma omp for [clause1 @dots{} clauseN]}.  It
> -has 5 operands:
> +Represents @code{#pragma omp for [clause1 @dots{} clauseN]}.  It has
> +six operands:
>
>  Operand @code{OMP_FOR_BODY} contains the loop body.
>
> @@ -2184,10 +2238,10 @@ building code (@code{omp-low.c}).
>  @item OMP_CONTINUE
>
>  Similarly, this instruction does not represent an OpenMP
> -directive, it is used by @code{OMP_FOR} and
> +directive, it is used by @code{OMP_FOR} (and similar codes, such as
> +@code{OACC_LOOP}) as well as
>  @code{OMP_SECTIONS} to mark the place where the code needs to
> -loop to the next iteration (in the case of @code{OMP_FOR}) or
> -the next section (in the case of @code{OMP_SECTIONS}).
> +loop to the next iteration, or the next section, respectively.
>
>  In some cases, @code{OMP_CONTINUE} is placed right before
>  @code{OMP_RETURN}.  But if there are cleanups that need to
> diff --git gcc/doc/gimple.texi gcc/doc/gimple.texi
> index 1e5473d..4c59748 100644
> --- gcc/doc/gimple.texi
> +++ gcc/doc/gimple.texi
> @@ -439,6 +439,8 @@ 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
> @@ -1006,6 +1008,8 @@ 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}::
> @@ -1651,6 +1655,17 @@ 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}
> @@ -1765,9 +1780,8 @@ Set @code{NAME} to be the name associated with @code{OMP} critical statement @co
>  tree clauses, tree index, tree initial, tree final, tree incr, @
>  gimple_seq pre_body, enum tree_code omp_for_cond)
>  Build a @code{GIMPLE_OMP_FOR} statement. @code{BODY} is sequence of statements
> -inside the for loop.  @code{CLAUSES}, are any of the @code{OMP} loop
> -construct's clauses: private, firstprivate,  lastprivate,
> -reductions, ordered, schedule, and nowait.  @code{PRE_BODY} is the
> +inside the for loop.  @code{CLAUSES}, are any of the loop
> +construct's clauses.  @code{PRE_BODY} is the
>  sequence of statements that are loop invariant.  @code{INDEX} is the
>  index variable.  @code{INITIAL} is the initial value of @code{INDEX}.  @code{FINAL} is
>  final value of @code{INDEX}.  OMP_FOR_COND is the predicate used to
> diff --git gcc/doc/invoke.texi gcc/doc/invoke.texi
> index 792f25b..0fe875b 100644
> --- gcc/doc/invoke.texi
> +++ gcc/doc/invoke.texi
> @@ -168,8 +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 -fopenmp-simd -fms-extensions @gol
> --fplan9-extensions -trigraphs  -traditional  -traditional-cpp @gol
> +-fhosted  -ffreestanding -fopenacc -fopenmp -fopenmp-simd @gol
> +-fms-extensions -fplan9-extensions -trigraphs -traditional -traditional-cpp @gol
>  -fallow-single-precision  -fcond-mismatch -flax-vector-conversions @gol
>  -fsigned-bitfields  -fsigned-char @gol
>  -funsigned-bitfields  -funsigned-char}
> @@ -1869,6 +1869,16 @@ 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 directives @code{#pragma acc} in C/C++ and
> +@code{!$acc} in Fortran.  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
> +implies @option{-pthread}, and thus is only supported on targets that
> +have support for @option{-pthread}.
> +
>  @item -fopenmp
>  @opindex fopenmp
>  @cindex OpenMP parallel
> diff --git gcc/doc/sourcebuild.texi gcc/doc/sourcebuild.texi
> index 20a206d..d27fac0 100644
> --- gcc/doc/sourcebuild.texi
> +++ gcc/doc/sourcebuild.texi
> @@ -1827,6 +1827,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/doc/tm.texi gcc/doc/tm.texi
> index bb04401..51e189f 100644
> --- gcc/doc/tm.texi
> +++ gcc/doc/tm.texi
> @@ -11250,3 +11250,9 @@ All and all it does not take long to convert ports that the
>  maintainer is familiar with.
>
>  @end defmac
> +
> +@deftypefn {Target Hook} void TARGET_RECORD_OFFLOAD_SYMBOL (tree)
> +Used when offloaded functions are seen in the compilation unit and no named
> +sections are available.  It is called once for each symbol that must be
> +recorded in the offload function and variable table.
> +@end deftypefn
> diff --git gcc/doc/tm.texi.in gcc/doc/tm.texi.in
> index aa19360..a373e8a 100644
> --- gcc/doc/tm.texi.in
> +++ gcc/doc/tm.texi.in
> @@ -8212,3 +8212,5 @@ All and all it does not take long to convert ports that the
>  maintainer is familiar with.
>
>  @end defmac
> +
> +@hook TARGET_RECORD_OFFLOAD_SYMBOL
> diff --git gcc/fortran/f95-lang.c gcc/fortran/f95-lang.c
> index 9c3ff22..4451c61 100644
> --- gcc/fortran/f95-lang.c
> +++ gcc/fortran/f95-lang.c
> @@ -662,6 +662,11 @@ gfc_init_builtin_functions (void)
>  #define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
>                             ARG6, ARG7, ARG8) NAME,
>  #define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME,
> +#define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME,
> +#define DEF_FUNCTION_TYPE_VAR_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
> +                               ARG6, ARG7, ARG8) NAME,
> +#define DEF_FUNCTION_TYPE_VAR_12(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
> +                                ARG6, ARG7, ARG8, ARG9, ARG10, ARG11, ARG12) NAME,
>  #define DEF_POINTER_TYPE(NAME, TYPE) NAME,
>  #include "types.def"
>  #undef DEF_PRIMITIVE_TYPE
> @@ -675,6 +680,9 @@ gfc_init_builtin_functions (void)
>  #undef DEF_FUNCTION_TYPE_7
>  #undef DEF_FUNCTION_TYPE_8
>  #undef DEF_FUNCTION_TYPE_VAR_0
> +#undef DEF_FUNCTION_TYPE_VAR_2
> +#undef DEF_FUNCTION_TYPE_VAR_8
> +#undef DEF_FUNCTION_TYPE_VAR_12
>  #undef DEF_POINTER_TYPE
>      BT_LAST
>    };
> @@ -1109,6 +1117,42 @@ gfc_init_builtin_functions (void)
>    builtin_types[(int) ENUM]                                            \
>      = build_varargs_function_type_list (builtin_types[(int) RETURN],    \
>                                          NULL_TREE);
> +#define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, ARG1, ARG2)              \
> +  builtin_types[(int) ENUM]                                            \
> +    = build_varargs_function_type_list (builtin_types[(int) RETURN],           \
> +                                       builtin_types[(int) ARG1],      \
> +                                       builtin_types[(int) ARG2],      \
> +                                       NULL_TREE);
> +#define DEF_FUNCTION_TYPE_VAR_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
> +                               ARG6, ARG7, ARG8)                       \
> +  builtin_types[(int) ENUM]                                            \
> +    = build_varargs_function_type_list (builtin_types[(int) RETURN],           \
> +                                       builtin_types[(int) ARG1],      \
> +                                       builtin_types[(int) ARG2],      \
> +                                       builtin_types[(int) ARG3],      \
> +                                       builtin_types[(int) ARG4],      \
> +                                       builtin_types[(int) ARG5],      \
> +                                       builtin_types[(int) ARG6],      \
> +                                       builtin_types[(int) ARG7],      \
> +                                       builtin_types[(int) ARG8],      \
> +                                       NULL_TREE);
> +#define DEF_FUNCTION_TYPE_VAR_12(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
> +                                ARG6, ARG7, ARG8, ARG9, ARG10, ARG11, ARG12) \
> +  builtin_types[(int) ENUM]                                            \
> +    = build_varargs_function_type_list (builtin_types[(int) RETURN],           \
> +                                       builtin_types[(int) ARG1],      \
> +                                       builtin_types[(int) ARG2],      \
> +                                       builtin_types[(int) ARG3],      \
> +                                       builtin_types[(int) ARG4],      \
> +                                       builtin_types[(int) ARG5],      \
> +                                       builtin_types[(int) ARG6],      \
> +                                       builtin_types[(int) ARG7],      \
> +                                       builtin_types[(int) ARG8],      \
> +                                       builtin_types[(int) ARG9],      \
> +                                       builtin_types[(int) ARG10],     \
> +                                       builtin_types[(int) ARG11],     \
> +                                       builtin_types[(int) ARG12],     \
> +                                       NULL_TREE);
>  #define DEF_POINTER_TYPE(ENUM, TYPE)                   \
>    builtin_types[(int) ENUM]                            \
>      = build_pointer_type (builtin_types[(int) TYPE]);
> @@ -1124,6 +1168,9 @@ gfc_init_builtin_functions (void)
>  #undef DEF_FUNCTION_TYPE_7
>  #undef DEF_FUNCTION_TYPE_8
>  #undef DEF_FUNCTION_TYPE_VAR_0
> +#undef DEF_FUNCTION_TYPE_VAR_2
> +#undef DEF_FUNCTION_TYPE_VAR_8
> +#undef DEF_FUNCTION_TYPE_VAR_12
>  #undef DEF_POINTER_TYPE
>    builtin_types[(int) BT_LAST] = NULL_TREE;
>
> diff --git gcc/fortran/types.def gcc/fortran/types.def
> index 99198e9..5c838bc 100644
> --- gcc/fortran/types.def
> +++ gcc/fortran/types.def
> @@ -82,6 +82,7 @@ DEF_FUNCTION_TYPE_0 (BT_FN_VOID, BT_VOID)
>  DEF_FUNCTION_TYPE_1 (BT_FN_VOID_PTR, BT_VOID, BT_PTR)
>  DEF_FUNCTION_TYPE_1 (BT_FN_VOID_PTRPTR, BT_VOID, BT_PTR_PTR)
>  DEF_FUNCTION_TYPE_1 (BT_FN_VOID_VPTR, BT_VOID, BT_VOLATILE_PTR)
> +DEF_FUNCTION_TYPE_1 (BT_FN_INT_INT, BT_INT, BT_INT)
>  DEF_FUNCTION_TYPE_1 (BT_FN_UINT_UINT, BT_UINT, BT_UINT)
>  DEF_FUNCTION_TYPE_1 (BT_FN_PTR_PTR, BT_PTR, BT_PTR)
>  DEF_FUNCTION_TYPE_1 (BT_FN_VOID_INT, BT_VOID, BT_INT)
> @@ -209,3 +210,13 @@ DEF_FUNCTION_TYPE_8 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR,
>                      BT_BOOL, BT_UINT, BT_PTR)
>
>  DEF_FUNCTION_TYPE_VAR_0 (BT_FN_VOID_VAR, BT_VOID)
> +
> +DEF_FUNCTION_TYPE_VAR_2 (BT_FN_VOID_INT_INT_VAR, BT_VOID, BT_INT, BT_INT)
> +
> +DEF_FUNCTION_TYPE_VAR_8 (BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR_INT_INT_VAR,
> +                        BT_VOID, BT_INT, BT_PTR, BT_SIZE, BT_PTR, BT_PTR,
> +                        BT_PTR, BT_INT, BT_INT)
> +
> +DEF_FUNCTION_TYPE_VAR_12 (BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR_INT_INT_INT_INT_INT_VAR,
> +        BT_VOID, BT_INT, BT_PTR_FN_VOID_PTR, BT_PTR, BT_SIZE, BT_PTR, BT_PTR,
> +        BT_PTR, BT_INT, BT_INT, BT_INT, BT_INT, BT_INT)
> diff --git gcc/gcc.c gcc/gcc.c
> index e013d52..a9ef6ad 100644
> --- gcc/gcc.c
> +++ gcc/gcc.c
> @@ -157,6 +157,7 @@ static const char *const spec_version = DEFAULT_TARGET_VERSION;
>  /* The target machine.  */
>
>  static const char *spec_machine = DEFAULT_TARGET_MACHINE;
> +static const char *spec_host_machine = DEFAULT_REAL_TARGET_MACHINE;
>
>  /* Nonzero if cross-compiling.
>     When -b is used, the value comes from the `specs' file.  */
> @@ -824,7 +825,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)}\
>      %{fcilkplus:%:include(libcilkrts.spec)%(link_cilkrts)}\
>      %{fgnu-tm:%:include(libitm.spec)%(link_itm)}\
>      %(mflib) " STACK_SPLIT_SPEC "\
> @@ -985,7 +986,8 @@ static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS;
>  /* 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.  */
> @@ -1296,6 +1298,9 @@ static const char *const standard_startfile_prefix_2
>     relative to the driver.  */
>  static const char *const tooldir_base_prefix = TOOLDIR_BASE_PREFIX;
>
> +/* A prefix to be used when this is an accelerator compiler.  */
> +static const char *const accel_dir_suffix = ACCEL_DIR_SUFFIX;
> +
>  /* Subdirectory to use for locating libraries.  Set by
>     set_multilib_dir based on the compilation options.  */
>
> @@ -4122,15 +4127,15 @@ process_command (unsigned int decoded_options_count,
>      }
>
>    gcc_assert (!IS_ABSOLUTE_PATH (tooldir_base_prefix));
> -  tooldir_prefix2 = concat (tooldir_base_prefix, spec_machine,
> +  tooldir_prefix2 = concat (tooldir_base_prefix, spec_host_machine,
>                             dir_separator_str, NULL);
>
>    /* Look for tools relative to the location from which the driver is
>       running, or, if that is not available, the configured prefix.  */
>    tooldir_prefix
>      = concat (gcc_exec_prefix ? gcc_exec_prefix : standard_exec_prefix,
> -             spec_machine, dir_separator_str,
> -             spec_version, dir_separator_str, tooldir_prefix2, NULL);
> +             spec_host_machine, dir_separator_str, spec_version,
> +             accel_dir_suffix, dir_separator_str, tooldir_prefix2, NULL);
>    free (tooldir_prefix2);
>
>    add_prefix (&exec_prefixes,
> @@ -6976,8 +6981,8 @@ driver::set_up_specs () const
>
>    /* Read specs from a file if there is one.  */
>
> -  machine_suffix = concat (spec_machine, dir_separator_str,
> -                          spec_version, dir_separator_str, NULL);
> +  machine_suffix = concat (spec_host_machine, dir_separator_str, spec_version,
> +                          accel_dir_suffix, dir_separator_str, NULL);
>    just_machine_suffix = concat (spec_machine, dir_separator_str, NULL);
>
>    specs_file = find_a_file (&startfile_prefixes, "specs", R_OK, true);
> @@ -6987,16 +6992,17 @@ driver::set_up_specs () const
>    else
>      init_spec ();
>
> +#ifndef ACCEL_COMPILER
>    /* We need to check standard_exec_prefix/just_machine_suffix/specs
>       for any override of as, ld and libraries.  */
>    specs_file = (char *) alloca (strlen (standard_exec_prefix)
>                        + strlen (just_machine_suffix) + sizeof ("specs"));
> -
>    strcpy (specs_file, standard_exec_prefix);
>    strcat (specs_file, just_machine_suffix);
>    strcat (specs_file, "specs");
>    if (access (specs_file, R_OK) == 0)
>      read_specs (specs_file, true, false);
> +#endif
>
>    /* Process any configure-time defaults specified for the command line
>       options, via OPTION_DEFAULT_SPECS.  */
> @@ -7175,8 +7181,9 @@ driver::set_up_specs () const
>
>    /* If we have a GCC_EXEC_PREFIX envvar, modify it for cpp's sake.  */
>    if (gcc_exec_prefix)
> -    gcc_exec_prefix = concat (gcc_exec_prefix, spec_machine, dir_separator_str,
> -                             spec_version, dir_separator_str, NULL);
> +    gcc_exec_prefix = concat (gcc_exec_prefix, spec_host_machine,
> +                             dir_separator_str, spec_version,
> +                             accel_dir_suffix, dir_separator_str, NULL);
>
>    /* Now we have the specs.
>       Set the `valid' bits for switches that match anything in any spec.  */
> @@ -7199,6 +7206,16 @@ driver::putenv_COLLECT_GCC (const char *argv0) const
>    obstack_grow (&collect_obstack, "COLLECT_GCC=", sizeof ("COLLECT_GCC=") - 1);
>    obstack_grow (&collect_obstack, argv0, strlen (argv0) + 1);
>    xputenv (XOBFINISH (&collect_obstack, char *));
> +
> +  if (strlen (OFFLOAD_TARGETS) > 0)
> +    {
> +      obstack_init (&collect_obstack);
> +      obstack_grow (&collect_obstack, "OFFLOAD_TARGET_NAMES=",
> +                   sizeof ("OFFLOAD_TARGET_NAMES=") - 1);
> +      obstack_grow (&collect_obstack, OFFLOAD_TARGETS,
> +                   strlen (OFFLOAD_TARGETS) + 1);
> +      xputenv (XOBFINISH (&collect_obstack, char *));
> +    }
>  }
>
>  /* Set up to remember the pathname of the lto wrapper. */
> diff --git gcc/gengtype.c gcc/gengtype.c
> index d55d530..83e926c 100644
> --- gcc/gengtype.c
> +++ gcc/gengtype.c
> @@ -1843,7 +1843,7 @@ open_base_files (void)
>        "tree-ssa.h", "reload.h", "cpp-id-data.h", "tree-chrec.h",
>        "except.h", "output.h",  "cfgloop.h", "target.h", "lto-streamer.h",
>        "target-globals.h", "ipa-ref.h", "cgraph.h", "ipa-prop.h",
> -      "ipa-inline.h", "dwarf2out.h", NULL
> +      "ipa-inline.h", "dwarf2out.h", "omp-low.h", NULL
>      };
>      const char *const *ifp;
>      outf_p gtype_desc_c;
> diff --git gcc/gimple-low.c gcc/gimple-low.c
> index 310ade8..0f3343b 100644
> --- gcc/gimple-low.c
> +++ gcc/gimple-low.c
> @@ -358,6 +358,8 @@ 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 6ae7817..c8f978d 100644
> --- gcc/gimple-pretty-print.c
> +++ gcc/gimple-pretty-print.c
> @@ -1136,18 +1136,21 @@ dump_gimple_omp_for (pretty_printer *buffer, gimple gs, int spc, int flags)
>         case GF_OMP_FOR_KIND_FOR:
>           kind = "";
>           break;
> -       case GF_OMP_FOR_KIND_SIMD:
> -         kind = " simd";
> -         break;
> -       case GF_OMP_FOR_KIND_CILKSIMD:
> -         kind = " cilksimd";
> -         break;
>         case GF_OMP_FOR_KIND_DISTRIBUTE:
>           kind = " distribute";
>           break;
>         case GF_OMP_FOR_KIND_CILKFOR:
>           kind = " _Cilk_for";
>           break;
> +       case GF_OMP_FOR_KIND_OACC_LOOP:
> +         kind = " oacc_loop";
> +         break;
> +       case GF_OMP_FOR_KIND_SIMD:
> +         kind = " simd";
> +         break;
> +       case GF_OMP_FOR_KIND_CILKSIMD:
> +         kind = " cilksimd";
> +         break;
>         default:
>           gcc_unreachable ();
>         }
> @@ -1173,17 +1176,20 @@ dump_gimple_omp_for (pretty_printer *buffer, gimple gs, int spc, int flags)
>         case GF_OMP_FOR_KIND_FOR:
>           pp_string (buffer, "#pragma omp for");
>           break;
> +       case GF_OMP_FOR_KIND_DISTRIBUTE:
> +         pp_string (buffer, "#pragma omp distribute");
> +         break;
> +       case GF_OMP_FOR_KIND_CILKFOR:
> +         break;
> +       case GF_OMP_FOR_KIND_OACC_LOOP:
> +         pp_string (buffer, "#pragma acc loop");
> +         break;
>         case GF_OMP_FOR_KIND_SIMD:
>           pp_string (buffer, "#pragma omp simd");
>           break;
>         case GF_OMP_FOR_KIND_CILKSIMD:
>           pp_string (buffer, "#pragma simd");
>           break;
> -       case GF_OMP_FOR_KIND_DISTRIBUTE:
> -         pp_string (buffer, "#pragma omp distribute");
> -         break;
> -       case GF_OMP_FOR_KIND_CILKFOR:
> -         break;
>         default:
>           gcc_unreachable ();
>         }
> @@ -1326,6 +1332,15 @@ 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_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;
>      default:
>        gcc_unreachable ();
>      }
> @@ -1857,6 +1872,81 @@ 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).  */
> @@ -2141,6 +2231,11 @@ 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 bfa3532..cc74d34 100644
> --- gcc/gimple-walk.c
> +++ gcc/gimple-walk.c
> @@ -304,6 +304,36 @@ 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);
> @@ -599,6 +629,8 @@ 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 b86f85c..a9174e6 100644
> --- gcc/gimple.c
> +++ gcc/gimple.c
> @@ -810,6 +810,40 @@ 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.
> @@ -830,8 +864,7 @@ gimple_build_omp_critical (gimple_seq body, tree name)
>
>     BODY is sequence of statements inside the for loop.
>     KIND is the `for' variant.
> -   CLAUSES, are any of the OMP loop construct's clauses: private, firstprivate,
> -   lastprivate, reductions, ordered, schedule, and nowait.
> +   CLAUSES, are any of the loop construct's clauses.
>     COLLAPSE is the collapse count.
>     PRE_BODY is the sequence of statements that are loop invariant.  */
>
> @@ -1043,7 +1076,8 @@ 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.
> -   CLAUSES are any of the OMP target construct's clauses.  */
> +   KIND is the kind of target region.
> +   CLAUSES are any of the construct's clauses.  */
>
>  gimple
>  gimple_build_omp_target (gimple_seq body, int kind, tree clauses)
> @@ -1684,7 +1718,12 @@ 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));
>           gimple_omp_for_set_pre_body (copy, new_seq);
>           t = unshare_expr (gimple_omp_for_clauses (stmt));
> @@ -1754,6 +1793,7 @@ gimple_copy (gimple stmt)
>         case GIMPLE_OMP_TASKGROUP:
>         case GIMPLE_OMP_ORDERED:
>         copy_omp_body:
> +         gcc_assert (!is_gimple_omp_oacc_specifically (stmt));
>           new_seq = gimple_seq_copy (gimple_omp_body (stmt));
>           gimple_omp_set_body (copy, new_seq);
>           break;
> diff --git gcc/gimple.def gcc/gimple.def
> index dfe4b77..e7dbe67 100644
> --- gcc/gimple.def
> +++ gcc/gimple.def
> @@ -205,10 +205,34 @@ 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_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)
> +
>  /* 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
> @@ -243,6 +267,9 @@ DEFGSCODE(GIMPLE_OMP_CRITICAL, "gimple_omp_critical", GSS_OMP_CRITICAL)
>     for (INDEX = INITIAL; INDEX COND FINAL; INDEX {+=,-=} INCR)
>     BODY
>
> +   Likewise for:
> +   #pragma acc loop [clause1 ... clauseN]
> +
>     BODY is the loop body.
>
>     CLAUSES is the list of clauses.
> @@ -269,7 +296,7 @@ DEFGSCODE(GIMPLE_OMP_CRITICAL, "gimple_omp_critical", GSS_OMP_CRITICAL)
>     INITIAL, FINAL and INCR are required to be loop invariant integer
>     expressions that are evaluated without any synchronization.
>     The evaluation order, frequency of evaluation and side-effects are
> -   unspecified by the standard.  */
> +   unspecified by the standards.  */
>  DEFGSCODE(GIMPLE_OMP_FOR, "gimple_omp_for", GSS_OMP_FOR)
>
>  /* GIMPLE_OMP_MASTER <BODY> represents #pragma omp master.
> @@ -354,6 +381,7 @@ 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,enter data,exit data,update}
>     #pragma omp target {,data,update}
>     BODY is the sequence of statements inside the target construct
>     (NULL for target update).
> diff --git gcc/gimple.h gcc/gimple.h
> index 7f1240f..0322270 100644
> --- gcc/gimple.h
> +++ gcc/gimple.h
> @@ -92,20 +92,24 @@ enum gf_mask {
>      GF_CALL_INTERNAL           = 1 << 6,
>      GF_CALL_CTRL_ALTERING       = 1 << 7,
>      GF_OMP_PARALLEL_COMBINED   = 1 << 0,
> -    GF_OMP_FOR_KIND_MASK       = 7 << 0,
> +    GF_OMP_FOR_KIND_MASK       = (1 << 3) - 1,
>      GF_OMP_FOR_KIND_FOR                = 0,
>      GF_OMP_FOR_KIND_DISTRIBUTE = 1,
>      GF_OMP_FOR_KIND_CILKFOR     = 2,
> +    GF_OMP_FOR_KIND_OACC_LOOP  = 3,
>      /* Flag for SIMD variants of OMP_FOR kinds.  */
>      GF_OMP_FOR_SIMD            = 1 << 2,
>      GF_OMP_FOR_KIND_SIMD       = GF_OMP_FOR_SIMD | 0,
>      GF_OMP_FOR_KIND_CILKSIMD   = GF_OMP_FOR_SIMD | 1,
>      GF_OMP_FOR_COMBINED                = 1 << 3,
>      GF_OMP_FOR_COMBINED_INTO   = 1 << 4,
> -    GF_OMP_TARGET_KIND_MASK    = (1 << 2) - 1,
> +    GF_OMP_TARGET_KIND_MASK    = (1 << 3) - 1,
>      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,
>
>      /* True on an GIMPLE_OMP_RETURN statement if the return does not require
>         a thread synchronization via some sort of barrier.  The exact barrier
> @@ -555,7 +559,8 @@ struct GTY((tag("GSS_OMP_FOR")))
>  };
>
>
> -/* GIMPLE_OMP_PARALLEL, GIMPLE_OMP_TARGET */
> +/* GIMPLE_OACC_KERNELS, GIMPLE_OACC_PARALLEL, 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
>  {
> @@ -574,6 +579,22 @@ 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
> @@ -583,7 +604,6 @@ struct GTY((tag("GSS_OMP_PARALLEL_LAYOUT")))
>          || stmt->code == GIMPLE_OMP_TASK.  */
>  };
>
> -
>  /* GIMPLE_OMP_PARALLEL */
>  struct GTY((tag("GSS_OMP_PARALLEL_LAYOUT")))
>    gimple_statement_omp_parallel : public gimple_statement_omp_taskreg
> @@ -592,6 +612,7 @@ struct GTY((tag("GSS_OMP_PARALLEL_LAYOUT")))
>           stmt->code == GIMPLE_OMP_PARALLEL.  */
>  };
>
> +/* GIMPLE_OMP_TARGET */
>  struct GTY((tag("GSS_OMP_PARALLEL_LAYOUT")))
>    gimple_statement_omp_target : public gimple_statement_omp_parallel_layout
>  {
> @@ -891,6 +912,22 @@ 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;
> @@ -1083,6 +1120,22 @@ 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;
> @@ -1206,6 +1259,8 @@ 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);
> @@ -1444,6 +1499,8 @@ 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:
> @@ -4279,6 +4336,197 @@ 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
> @@ -4312,7 +4560,7 @@ gimple_omp_critical_set_name (gimple gs, tree name)
>  }
>
>
> -/* Return the kind of OMP for statemement.  */
> +/* Return the kind of the OMP_FOR statemement G.  */
>
>  static inline int
>  gimple_omp_for_kind (const_gimple g)
> @@ -4322,7 +4570,7 @@ gimple_omp_for_kind (const_gimple g)
>  }
>
>
> -/* Set the OMP for kind.  */
> +/* Set the kind of the OMP_FOR statement G.  */
>
>  static inline void
>  gimple_omp_for_set_kind (gimple g, int kind)
> @@ -4333,7 +4581,7 @@ gimple_omp_for_set_kind (gimple g, int kind)
>  }
>
>
> -/* Return true if OMP for statement G has the
> +/* Return true if OMP_FOR statement G has the
>     GF_OMP_FOR_COMBINED flag set.  */
>
>  static inline bool
> @@ -4344,8 +4592,8 @@ gimple_omp_for_combined_p (const_gimple g)
>  }
>
>
> -/* Set the GF_OMP_FOR_COMBINED field in G depending on the boolean
> -   value of COMBINED_P.  */
> +/* Set the GF_OMP_FOR_COMBINED field in the OMP_FOR statement G depending on
> +   the boolean value of COMBINED_P.  */
>
>  static inline void
>  gimple_omp_for_set_combined_p (gimple g, bool combined_p)
> @@ -4358,7 +4606,7 @@ gimple_omp_for_set_combined_p (gimple g, bool combined_p)
>  }
>
>
> -/* Return true if OMP for statement G has the
> +/* Return true if the OMP_FOR statement G has the
>     GF_OMP_FOR_COMBINED_INTO flag set.  */
>
>  static inline bool
> @@ -4369,8 +4617,8 @@ gimple_omp_for_combined_into_p (const_gimple g)
>  }
>
>
> -/* Set the GF_OMP_FOR_COMBINED_INTO field in G depending on the boolean
> -   value of COMBINED_P.  */
> +/* Set the GF_OMP_FOR_COMBINED_INTO field in the OMP_FOR statement G depending
> +   on the boolean value of COMBINED_P.  */
>
>  static inline void
>  gimple_omp_for_set_combined_into_p (gimple g, bool combined_p)
> @@ -4383,7 +4631,7 @@ gimple_omp_for_set_combined_into_p (gimple g, bool combined_p)
>  }
>
>
> -/* Return the clauses associated with OMP_FOR GS.  */
> +/* Return the clauses associated with the OMP_FOR statement GS.  */
>
>  static inline tree
>  gimple_omp_for_clauses (const_gimple gs)
> @@ -4394,7 +4642,8 @@ gimple_omp_for_clauses (const_gimple gs)
>  }
>
>
> -/* Return a pointer to the OMP_FOR GS.  */
> +/* Return a pointer to the clauses associated with the OMP_FOR statement
> +   GS.  */
>
>  static inline tree *
>  gimple_omp_for_clauses_ptr (gimple gs)
> @@ -4405,7 +4654,8 @@ gimple_omp_for_clauses_ptr (gimple gs)
>  }
>
>
> -/* Set CLAUSES to be the list of clauses associated with OMP_FOR GS.  */
> +/* Set CLAUSES to be the list of clauses associated with the OMP_FOR statement
> +   GS.  */
>
>  static inline void
>  gimple_omp_for_set_clauses (gimple gs, tree clauses)
> @@ -4416,7 +4666,7 @@ gimple_omp_for_set_clauses (gimple gs, tree clauses)
>  }
>
>
> -/* Get the collapse count of OMP_FOR GS.  */
> +/* Get the collapse count of the OMP_FOR statement GS.  */
>
>  static inline size_t
>  gimple_omp_for_collapse (gimple gs)
> @@ -4427,7 +4677,7 @@ gimple_omp_for_collapse (gimple gs)
>  }
>
>
> -/* Return the index variable for OMP_FOR GS.  */
> +/* Return the index variable for the OMP_FOR statement GS.  */
>
>  static inline tree
>  gimple_omp_for_index (const_gimple gs, size_t i)
> @@ -4439,7 +4689,7 @@ gimple_omp_for_index (const_gimple gs, size_t i)
>  }
>
>
> -/* Return a pointer to the index variable for OMP_FOR GS.  */
> +/* Return a pointer to the index variable for the OMP_FOR statement GS.  */
>
>  static inline tree *
>  gimple_omp_for_index_ptr (gimple gs, size_t i)
> @@ -4451,7 +4701,7 @@ gimple_omp_for_index_ptr (gimple gs, size_t i)
>  }
>
>
> -/* Set INDEX to be the index variable for OMP_FOR GS.  */
> +/* Set INDEX to be the index variable for the OMP_FOR statement GS.  */
>
>  static inline void
>  gimple_omp_for_set_index (gimple gs, size_t i, tree index)
> @@ -4463,7 +4713,7 @@ gimple_omp_for_set_index (gimple gs, size_t i, tree index)
>  }
>
>
> -/* Return the initial value for OMP_FOR GS.  */
> +/* Return the initial value for the OMP_FOR statement GS.  */
>
>  static inline tree
>  gimple_omp_for_initial (const_gimple gs, size_t i)
> @@ -4475,7 +4725,7 @@ gimple_omp_for_initial (const_gimple gs, size_t i)
>  }
>
>
> -/* Return a pointer to the initial value for OMP_FOR GS.  */
> +/* Return a pointer to the initial value for the OMP_FOR statement GS.  */
>
>  static inline tree *
>  gimple_omp_for_initial_ptr (gimple gs, size_t i)
> @@ -4487,7 +4737,7 @@ gimple_omp_for_initial_ptr (gimple gs, size_t i)
>  }
>
>
> -/* Set INITIAL to be the initial value for OMP_FOR GS.  */
> +/* Set INITIAL to be the initial value for the OMP_FOR statement GS.  */
>
>  static inline void
>  gimple_omp_for_set_initial (gimple gs, size_t i, tree initial)
> @@ -4499,7 +4749,7 @@ gimple_omp_for_set_initial (gimple gs, size_t i, tree initial)
>  }
>
>
> -/* Return the final value for OMP_FOR GS.  */
> +/* Return the final value for the OMP_FOR statement GS.  */
>
>  static inline tree
>  gimple_omp_for_final (const_gimple gs, size_t i)
> @@ -4511,7 +4761,7 @@ gimple_omp_for_final (const_gimple gs, size_t i)
>  }
>
>
> -/* Return a pointer to the final value for OMP_FOR GS.  */
> +/* Return a pointer to the final value for the OMP_FOR statement GS.  */
>
>  static inline tree *
>  gimple_omp_for_final_ptr (gimple gs, size_t i)
> @@ -4523,7 +4773,7 @@ gimple_omp_for_final_ptr (gimple gs, size_t i)
>  }
>
>
> -/* Set FINAL to be the final value for OMP_FOR GS.  */
> +/* Set FINAL to be the final value for the OMP_FOR statement GS.  */
>
>  static inline void
>  gimple_omp_for_set_final (gimple gs, size_t i, tree final)
> @@ -4535,7 +4785,32 @@ gimple_omp_for_set_final (gimple gs, size_t i, tree final)
>  }
>
>
> -/* Return the increment value for OMP_FOR GS.  */
> +/* Set COND to be the condition code for the OMP_FOR statement GS.  */
> +
> +static inline void
> +gimple_omp_for_set_cond (gimple gs, size_t i, enum tree_code cond)
> +{
> +  gimple_statement_omp_for *omp_for_stmt =
> +    as_a <gimple_statement_omp_for *> (gs);
> +  gcc_gimple_checking_assert (TREE_CODE_CLASS (cond) == tcc_comparison
> +                             && i < omp_for_stmt->collapse);
> +  omp_for_stmt->iter[i].cond = cond;
> +}
> +
> +
> +/* Return the condition code associated with the OMP_FOR statement GS.  */
> +
> +static inline enum tree_code
> +gimple_omp_for_cond (const_gimple gs, size_t i)
> +{
> +  const gimple_statement_omp_for *omp_for_stmt =
> +    as_a <const gimple_statement_omp_for *> (gs);
> +  gcc_gimple_checking_assert (i < omp_for_stmt->collapse);
> +  return omp_for_stmt->iter[i].cond;
> +}
> +
> +
> +/* Return the increment value for the OMP_FOR statement GS.  */
>
>  static inline tree
>  gimple_omp_for_incr (const_gimple gs, size_t i)
> @@ -4547,7 +4822,7 @@ gimple_omp_for_incr (const_gimple gs, size_t i)
>  }
>
>
> -/* Return a pointer to the increment value for OMP_FOR GS.  */
> +/* Return a pointer to the increment value for the OMP_FOR statement GS.  */
>
>  static inline tree *
>  gimple_omp_for_incr_ptr (gimple gs, size_t i)
> @@ -4559,7 +4834,7 @@ gimple_omp_for_incr_ptr (gimple gs, size_t i)
>  }
>
>
> -/* Set INCR to be the increment value for OMP_FOR GS.  */
> +/* Set INCR to be the increment value for the OMP_FOR statement GS.  */
>
>  static inline void
>  gimple_omp_for_set_incr (gimple gs, size_t i, tree incr)
> @@ -5264,31 +5539,6 @@ gimple_omp_sections_set_control (gimple gs, tree control)
>  }
>
>
> -/* Set COND to be the condition code for OMP_FOR GS.  */
> -
> -static inline void
> -gimple_omp_for_set_cond (gimple gs, size_t i, enum tree_code cond)
> -{
> -  gimple_statement_omp_for *omp_for_stmt =
> -    as_a <gimple_statement_omp_for *> (gs);
> -  gcc_gimple_checking_assert (TREE_CODE_CLASS (cond) == tcc_comparison
> -                             && i < omp_for_stmt->collapse);
> -  omp_for_stmt->iter[i].cond = cond;
> -}
> -
> -
> -/* Return the condition code associated with OMP_FOR GS.  */
> -
> -static inline enum tree_code
> -gimple_omp_for_cond (const_gimple gs, size_t i)
> -{
> -  const gimple_statement_omp_for *omp_for_stmt =
> -    as_a <const gimple_statement_omp_for *> (gs);
> -  gcc_gimple_checking_assert (i < omp_for_stmt->collapse);
> -  return omp_for_stmt->iter[i].cond;
> -}
> -
> -
>  /* Set the value being stored in an atomic store.  */
>
>  static inline void
> @@ -5558,6 +5808,8 @@ gimple_return_set_retval (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:                       \
> @@ -5588,6 +5840,65 @@ is_gimple_omp (const_gimple stmt)
>      }
>  }
>
> +/* Return true if STMT is any of the OpenACC types specifically.  */
> +
> +static inline bool
> +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))
> +       {
> +       case GF_OMP_FOR_KIND_OACC_LOOP:
> +         return true;
> +       default:
> +         return false;
> +       }
> +    case GIMPLE_OMP_TARGET:
> +      switch (gimple_omp_target_kind (stmt))
> +       {
> +       case GF_OMP_TARGET_KIND_OACC_DATA:
> +       case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA:
> +       case GF_OMP_TARGET_KIND_OACC_UPDATE:
> +         return true;
> +       default:
> +         return false;
> +       }
> +    default:
> +      return false;
> +    }
> +}
> +
> +
> +/* Return true if OMP_* STMT is offloaded.  */
> +
> +static inline bool
> +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:
> +         return true;
> +       default:
> +         return false;
> +       }
> +    default:
> +      return false;
> +    }
> +}
> +
>
>  /* Returns TRUE if statement G is a GIMPLE_NOP.  */
>
> diff --git gcc/gimplify.c gcc/gimplify.c
> index 38be0ce..30fc042 100644
> --- gcc/gimplify.c
> +++ gcc/gimplify.c
> @@ -90,7 +90,11 @@ enum gimplify_omp_var_data
>    GOVD_PRIVATE_OUTER_REF = 1024,
>    GOVD_LINEAR = 2048,
>    GOVD_ALIGNED = 4096,
> +
> +  /* Flags for GOVD_MAP.  */
> +  /* Don't copy back.  */
>    GOVD_MAP_TO_ONLY = 8192,
> +
>    GOVD_DATA_SHARE_CLASS = (GOVD_SHARED | GOVD_PRIVATE | GOVD_FIRSTPRIVATE
>                            | GOVD_LASTPRIVATE | GOVD_REDUCTION | GOVD_LINEAR
>                            | GOVD_LOCAL)
> @@ -99,15 +103,16 @@ enum gimplify_omp_var_data
>
>  enum omp_region_type
>  {
> -  ORT_WORKSHARE = 0,
> -  ORT_SIMD = 1,
> -  ORT_PARALLEL = 2,
> -  ORT_COMBINED_PARALLEL = 3,
> -  ORT_TASK = 4,
> -  ORT_UNTIED_TASK = 5,
> -  ORT_TEAMS = 8,
> -  ORT_TARGET_DATA = 16,
> -  ORT_TARGET = 32
> +  /* An undefined region type.  */
> +  ORT_INVALID = 0,
> +
> +  ORT_WORKSHARE,
> +  ORT_SIMD,
> +  ORT_PARALLEL,
> +  ORT_COMBINED_PARALLEL,
> +  ORT_TASK,
> +  ORT_TEAMS,
> +  ORT_TARGET
>  };
>
>  /* Gimplify hashtable helper.  */
> @@ -149,6 +154,21 @@ struct gimplify_omp_ctx
>    location_t location;
>    enum omp_clause_default_kind default_kind;
>    enum omp_region_type region_type;
> +  union
> +  {
> +    /* ORT_TASK.  */
> +    struct
> +    {
> +      /* Has an untied clause.  */
> +      unsigned untied : 1;
> +    } task;
> +    /* ORT_TARGET.  */
> +    struct
> +    {
> +      /* Prepare this region for offloading.  */
> +      unsigned offload : 1;
> +    } target;
> +  } region_type_flags;
>    bool combined_loop;
>    bool distribute;
>  };
> @@ -356,7 +376,7 @@ splay_tree_compare_decl_uid (splay_tree_key xa, splay_tree_key xb)
>  /* Create a new omp construct that deals with variable remapping.  */
>
>  static struct gimplify_omp_ctx *
> -new_omp_context (enum omp_region_type region_type)
> +new_omp_context (void)
>  {
>    struct gimplify_omp_ctx *c;
>
> @@ -365,11 +385,8 @@ new_omp_context (enum omp_region_type region_type)
>    c->variables = splay_tree_new (splay_tree_compare_decl_uid, 0, 0);
>    c->privatized_types = new hash_set<tree>;
>    c->location = input_location;
> -  c->region_type = region_type;
> -  if ((region_type & ORT_TASK) == 0)
> -    c->default_kind = OMP_CLAUSE_DEFAULT_SHARED;
> -  else
> -    c->default_kind = OMP_CLAUSE_DEFAULT_UNSPECIFIED;
> +  c->default_kind = OMP_CLAUSE_DEFAULT_SHARED;
> +  c->region_type = ORT_INVALID;
>
>    return c;
>  }
> @@ -1544,9 +1561,10 @@ gimplify_case_label_expr (tree *expr_p, gimple_seq *pre_p)
>    struct gimplify_ctx *ctxp;
>    gimple gimple_label;
>
> -  /* Invalid OpenMP programs can play Duff's Device type games with
> +  /* Invalid programs can play Duff's Device type games with, for example,
>       #pragma omp parallel.  At least in the C front end, we don't
> -     detect such invalid branches until after gimplification.  */
> +     detect such invalid branches until after gimplification, in the
> +     diagnose_omp_blocks pass.  */
>    for (ctxp = gimplify_ctxp; ; ctxp = ctxp->prev_context)
>      if (ctxp->case_labels.exists ())
>        break;
> @@ -2240,7 +2258,7 @@ gimplify_arg (tree *arg_p, gimple_seq *pre_p, location_t call_location)
>    return gimplify_expr (arg_p, pre_p, NULL, test, fb);
>  }
>
> -/* Don't fold STMT inside ORT_TARGET, because it can break code by adding decl
> +/* Don't fold inside offloading regsion: it can break code by adding decl
>     references that weren't in the source.  We'll do it during omplower pass
>     instead.  */
>
> @@ -2249,7 +2267,8 @@ maybe_fold_stmt (gimple_stmt_iterator *gsi)
>  {
>    struct gimplify_omp_ctx *ctx;
>    for (ctx = gimplify_omp_ctxp; ctx; ctx = ctx->outer_context)
> -    if (ctx->region_type == ORT_TARGET)
> +    if (ctx->region_type == ORT_TARGET
> +       && ctx->region_type_flags.target.offload)
>        return false;
>    return fold_stmt (gsi);
>  }
> @@ -4404,11 +4423,21 @@ is_gimple_stmt (tree t)
>      case CATCH_EXPR:
>      case ASM_EXPR:
>      case STATEMENT_LIST:
> +    case OACC_PARALLEL:
> +    case OACC_KERNELS:
> +    case OACC_DATA:
> +    case OACC_HOST_DATA:
> +    case OACC_DECLARE:
> +    case OACC_UPDATE:
> +    case OACC_ENTER_DATA:
> +    case OACC_EXIT_DATA:
> +    case OACC_CACHE:
>      case OMP_PARALLEL:
>      case OMP_FOR:
>      case OMP_SIMD:
>      case CILK_SIMD:
>      case OMP_DISTRIBUTE:
> +    case OACC_LOOP:
>      case OMP_SECTIONS:
>      case OMP_SECTION:
>      case OMP_SINGLE:
> @@ -5447,10 +5476,12 @@ omp_firstprivatize_variable (struct gimplify_omp_ctx *ctx, tree decl)
>             return;
>         }
>        else if (ctx->region_type == ORT_TARGET)
> -       omp_add_variable (ctx, decl, GOVD_MAP | GOVD_MAP_TO_ONLY);
> +       {
> +         if (ctx->region_type_flags.target.offload)
> +           omp_add_variable (ctx, decl, GOVD_MAP | GOVD_MAP_TO_ONLY);
> +       }
>        else if (ctx->region_type != ORT_WORKSHARE
> -              && ctx->region_type != ORT_SIMD
> -              && ctx->region_type != ORT_TARGET_DATA)
> +              && ctx->region_type != ORT_SIMD)
>         omp_add_variable (ctx, decl, GOVD_FIRSTPRIVATE);
>
>        ctx = ctx->outer_context;
> @@ -5559,9 +5590,12 @@ omp_add_variable (struct gimplify_omp_ctx *ctx, tree decl, unsigned int flags)
>          copy into or out of the context.  */
>        if (!(flags & GOVD_LOCAL))
>         {
> -         nflags = flags & GOVD_MAP
> -                  ? GOVD_MAP | GOVD_MAP_TO_ONLY | GOVD_EXPLICIT
> -                  : flags & GOVD_PRIVATE ? GOVD_PRIVATE : GOVD_FIRSTPRIVATE;
> +         if (flags & GOVD_MAP)
> +           nflags = GOVD_MAP | GOVD_MAP_TO_ONLY | GOVD_EXPLICIT;
> +         else if (flags & GOVD_PRIVATE)
> +           nflags = GOVD_PRIVATE;
> +         else
> +           nflags = GOVD_FIRSTPRIVATE;
>           nflags |= flags & GOVD_SEEN;
>           t = DECL_VALUE_EXPR (decl);
>           gcc_assert (TREE_CODE (t) == INDIRECT_REF);
> @@ -5628,7 +5662,8 @@ omp_notice_threadprivate_variable (struct gimplify_omp_ctx *ctx, tree decl,
>    struct gimplify_omp_ctx *octx;
>
>    for (octx = ctx; octx; octx = octx->outer_context)
> -    if (octx->region_type == ORT_TARGET)
> +    if (octx->region_type == ORT_TARGET
> +       && octx->region_type_flags.target.offload)
>        {
>         n = splay_tree_lookup (octx->variables, (splay_tree_key)decl);
>         if (n == NULL)
> @@ -5642,7 +5677,7 @@ omp_notice_threadprivate_variable (struct gimplify_omp_ctx *ctx, tree decl,
>           splay_tree_insert (octx->variables, (splay_tree_key)decl2, 0);
>        }
>
> -  if (ctx->region_type != ORT_UNTIED_TASK)
> +  if (!(ctx->region_type == ORT_TASK && ctx->region_type_flags.task.untied))
>      return false;
>    n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl);
>    if (n == NULL)
> @@ -5689,7 +5724,8 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code)
>      }
>
>    n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl);
> -  if (ctx->region_type == ORT_TARGET)
> +  if (ctx->region_type == ORT_TARGET
> +      && ctx->region_type_flags.target.offload)
>      {
>        ret = lang_hooks.decls.omp_disregard_value_expr (decl, true);
>        if (n == NULL)
> @@ -5720,7 +5756,8 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code)
>
>        if (ctx->region_type == ORT_WORKSHARE
>           || ctx->region_type == ORT_SIMD
> -         || ctx->region_type == ORT_TARGET_DATA)
> +         || (ctx->region_type == ORT_TARGET
> +             && !ctx->region_type_flags.target.offload))
>         goto do_outer;
>
>        /* ??? Some compiler-generated variables (like SAVE_EXPRs) could be
> @@ -5734,13 +5771,14 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code)
>        switch (default_kind)
>         {
>         case OMP_CLAUSE_DEFAULT_NONE:
> -         if ((ctx->region_type & ORT_PARALLEL) != 0)
> +         if (ctx->region_type == ORT_PARALLEL
> +             || ctx->region_type == ORT_COMBINED_PARALLEL)
>             {
>               error ("%qE not specified in enclosing parallel",
>                      DECL_NAME (lang_hooks.decls.omp_report_decl (decl)));
>               error_at (ctx->location, "enclosing parallel");
>             }
> -         else if ((ctx->region_type & ORT_TASK) != 0)
> +         else if (ctx->region_type == ORT_TASK)
>             {
>               error ("%qE not specified in enclosing task",
>                      DECL_NAME (lang_hooks.decls.omp_report_decl (decl)));
> @@ -5766,14 +5804,14 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code)
>           break;
>         case OMP_CLAUSE_DEFAULT_UNSPECIFIED:
>           /* decl will be either GOVD_FIRSTPRIVATE or GOVD_SHARED.  */
> -         gcc_assert ((ctx->region_type & ORT_TASK) != 0);
> +         gcc_assert (ctx->region_type == ORT_TASK);
>           if (ctx->outer_context)
>             omp_notice_variable (ctx->outer_context, decl, in_code);
>           for (octx = ctx->outer_context; octx; octx = octx->outer_context)
>             {
>               splay_tree_node n2;
>
> -             if ((octx->region_type & (ORT_TARGET_DATA | ORT_TARGET)) != 0)
> +             if (octx->region_type == ORT_TARGET)
>                 continue;
>               n2 = splay_tree_lookup (octx->variables, (splay_tree_key) decl);
>               if (n2 && (n2->value & GOVD_DATA_SHARE_CLASS) != GOVD_SHARED)
> @@ -5781,7 +5819,9 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code)
>                   flags |= GOVD_FIRSTPRIVATE;
>                   break;
>                 }
> -             if ((octx->region_type & (ORT_PARALLEL | ORT_TEAMS)) != 0)
> +             if (octx->region_type == ORT_PARALLEL
> +                 || octx->region_type == ORT_COMBINED_PARALLEL
> +                 || octx->region_type == ORT_TEAMS)
>                 break;
>             }
>           if (flags & GOVD_FIRSTPRIVATE)
> @@ -5926,7 +5966,7 @@ omp_check_private (struct gimplify_omp_ctx *ctx, tree decl, bool copyprivate)
>                  || (!copyprivate
>                      && lang_hooks.decls.omp_privatize_by_reference (decl)));
>
> -      if ((ctx->region_type & (ORT_TARGET | ORT_TARGET_DATA)) != 0)
> +      if (ctx->region_type == ORT_TARGET)
>         continue;
>
>        n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl);
> @@ -5938,19 +5978,17 @@ omp_check_private (struct gimplify_omp_ctx *ctx, tree decl, bool copyprivate)
>    return false;
>  }
>
> -/* Scan the OpenMP clauses in *LIST_P, installing mappings into a new
> -   and previous omp contexts.  */
> +/* Scan the clauses in *LIST_P, installing mappings into CTX as well as outer
> +   contexts, if applicable.  Before returning, CTX will also be pushed to the
> +   top of GIMPLIFY_OMP_CTXP.  */
>
>  static void
>  gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
> -                          enum omp_region_type region_type)
> +                          struct gimplify_omp_ctx *ctx)
>  {
> -  struct gimplify_omp_ctx *ctx, *outer_ctx;
> +  struct gimplify_omp_ctx *outer_ctx = ctx->outer_context;
>    tree c;
>
> -  ctx = new_omp_context (region_type);
> -  outer_ctx = ctx->outer_context;
> -
>    while ((c = *list_p) != NULL)
>      {
>        bool remove = false;
> @@ -6049,6 +6087,7 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
>
>         case OMP_CLAUSE_TO:
>         case OMP_CLAUSE_FROM:
> +       case OMP_CLAUSE__CACHE_:
>           decl = OMP_CLAUSE_DECL (c);
>           if (error_operand_p (decl))
>             {
> @@ -6192,7 +6231,7 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
>           if (outer_ctx)
>             omp_notice_variable (outer_ctx, decl, true);
>           if (check_non_private
> -             && region_type == ORT_WORKSHARE
> +             && ctx->region_type == ORT_WORKSHARE
>               && omp_check_private (ctx, decl, false))
>             {
>               error ("%s variable %qE is private in outer context",
> @@ -6214,11 +6253,25 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
>         case OMP_CLAUSE_DIST_SCHEDULE:
>         case OMP_CLAUSE_DEVICE:
>         case OMP_CLAUSE__CILK_FOR_COUNT_:
> +       case OMP_CLAUSE_NUM_GANGS:
> +       case OMP_CLAUSE_NUM_WORKERS:
> +       case OMP_CLAUSE_VECTOR_LENGTH:
>           if (gimplify_expr (&OMP_CLAUSE_OPERAND (c, 0), pre_p, NULL,
>                              is_gimple_val, fb_rvalue) == GS_ERROR)
>             remove = true;
>           break;
>
> +       case OMP_CLAUSE_DEVICE_RESIDENT:
> +       case OMP_CLAUSE_USE_DEVICE:
> +       case OMP_CLAUSE_GANG:
> +       case OMP_CLAUSE_ASYNC:
> +       case OMP_CLAUSE_WAIT:
> +       case OMP_CLAUSE_INDEPENDENT:
> +       case OMP_CLAUSE_WORKER:
> +       case OMP_CLAUSE_VECTOR:
> +         remove = true;
> +         break;
> +
>         case OMP_CLAUSE_NOWAIT:
>         case OMP_CLAUSE_ORDERED:
>         case OMP_CLAUSE_UNTIED:
> @@ -6343,9 +6396,12 @@ gimplify_adjust_omp_clauses_1 (splay_tree_node n, void *data)
>      OMP_CLAUSE_PRIVATE_OUTER_REF (clause) = 1;
>    else if (code == OMP_CLAUSE_MAP)
>      {
> -      OMP_CLAUSE_MAP_KIND (clause) = flags & GOVD_MAP_TO_ONLY
> -                                    ? OMP_CLAUSE_MAP_TO
> -                                    : OMP_CLAUSE_MAP_TOFROM;
> +      enum omp_clause_map_kind map_kind;
> +      map_kind = (flags & GOVD_MAP_TO_ONLY
> +                 ? OMP_CLAUSE_MAP_TO
> +                 : OMP_CLAUSE_MAP_TOFROM);
> +      OMP_CLAUSE_MAP_KIND (clause) = map_kind;
> +
>        if (DECL_SIZE (decl)
>           && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
>         {
> @@ -6393,6 +6449,9 @@ gimplify_adjust_omp_clauses_1 (splay_tree_node n, void *data)
>    return 0;
>  }
>
> +/* Apply adjustments to the clauses in *LIST_P.  Before returning, the current
> +   context will also be destroyed, and popped off of GIMPLIFY_OMP_CTXP.  */
> +
>  static void
>  gimplify_adjust_omp_clauses (gimple_seq *pre_p, tree *list_p)
>  {
> @@ -6512,12 +6571,20 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, tree *list_p)
>           if (!DECL_P (decl))
>             break;
>           n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl);
> -         if (ctx->region_type == ORT_TARGET && !(n->value & GOVD_SEEN))
> +         if (ctx->region_type == ORT_TARGET
> +             && ctx->region_type_flags.target.offload
> +             && !(n->value & GOVD_SEEN))
>             remove = true;
>           else if (DECL_SIZE (decl)
>                    && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST
>                    && OMP_CLAUSE_MAP_KIND (c) != OMP_CLAUSE_MAP_POINTER)
>             {
> +             /* For OMP_CLAUSE_MAP_FORCE_DEVICEPTR, we'll never enter here,
> +                because for these, TREE_CODE (DECL_SIZE (decl)) will always be
> +                INTEGER_CST.  */
> +             gcc_assert (OMP_CLAUSE_MAP_KIND (c)
> +                         != OMP_CLAUSE_MAP_FORCE_DEVICEPTR);
> +
>               tree decl2 = DECL_VALUE_EXPR (decl);
>               gcc_assert (TREE_CODE (decl2) == INDIRECT_REF);
>               decl2 = TREE_OPERAND (decl2, 0);
> @@ -6546,6 +6613,7 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, tree *list_p)
>
>         case OMP_CLAUSE_TO:
>         case OMP_CLAUSE_FROM:
> +       case OMP_CLAUSE__CACHE_:
>           decl = OMP_CLAUSE_DECL (c);
>           if (!DECL_P (decl))
>             break;
> @@ -6591,8 +6659,19 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, tree *list_p)
>         case OMP_CLAUSE_SAFELEN:
>         case OMP_CLAUSE_DEPEND:
>         case OMP_CLAUSE__CILK_FOR_COUNT_:
> +       case OMP_CLAUSE_NUM_GANGS:
> +       case OMP_CLAUSE_NUM_WORKERS:
> +       case OMP_CLAUSE_VECTOR_LENGTH:
>           break;
>
> +       case OMP_CLAUSE_DEVICE_RESIDENT:
> +       case OMP_CLAUSE_USE_DEVICE:
> +       case OMP_CLAUSE_GANG:
> +       case OMP_CLAUSE_ASYNC:
> +       case OMP_CLAUSE_WAIT:
> +       case OMP_CLAUSE_INDEPENDENT:
> +       case OMP_CLAUSE_WORKER:
> +       case OMP_CLAUSE_VECTOR:
>         default:
>           gcc_unreachable ();
>         }
> @@ -6613,6 +6692,24 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, tree *list_p)
>    delete_omp_context (ctx);
>  }
>
> +/* Gimplify OACC_CACHE.  */
> +
> +static void
> +gimplify_oacc_cache (tree *expr_p, gimple_seq *pre_p)
> +{
> +  tree expr = *expr_p;
> +  struct gimplify_omp_ctx *ctx = new_omp_context ();
> +
> +  ctx->region_type = ORT_WORKSHARE;
> +
> +  gimplify_scan_omp_clauses (&OACC_CACHE_CLAUSES (expr), pre_p, ctx);
> +  gimplify_adjust_omp_clauses (pre_p, &OACC_CACHE_CLAUSES (expr));
> +
> +  /* TODO: Do something sensible with this information.  */
> +
> +  *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
> @@ -6624,11 +6721,12 @@ gimplify_omp_parallel (tree *expr_p, gimple_seq *pre_p)
>    tree expr = *expr_p;
>    gimple g;
>    gimple_seq body = NULL;
> +  struct gimplify_omp_ctx *ctx = new_omp_context ();
>
> -  gimplify_scan_omp_clauses (&OMP_PARALLEL_CLAUSES (expr), pre_p,
> -                            OMP_PARALLEL_COMBINED (expr)
> -                            ? ORT_COMBINED_PARALLEL
> -                            : ORT_PARALLEL);
> +  ctx->region_type
> +    = OMP_PARALLEL_COMBINED (expr) ? ORT_COMBINED_PARALLEL : ORT_PARALLEL;
> +
> +  gimplify_scan_omp_clauses (&OMP_PARALLEL_CLAUSES (expr), pre_p, ctx);
>
>    push_gimplify_context ();
>
> @@ -6660,11 +6758,14 @@ gimplify_omp_task (tree *expr_p, gimple_seq *pre_p)
>    tree expr = *expr_p;
>    gimple g;
>    gimple_seq body = NULL;
> +  struct gimplify_omp_ctx *ctx = new_omp_context ();
>
> -  gimplify_scan_omp_clauses (&OMP_TASK_CLAUSES (expr), pre_p,
> -                            find_omp_clause (OMP_TASK_CLAUSES (expr),
> -                                             OMP_CLAUSE_UNTIED)
> -                            ? ORT_UNTIED_TASK : ORT_TASK);
> +  ctx->default_kind = OMP_CLAUSE_DEFAULT_UNSPECIFIED;
> +  ctx->region_type = ORT_TASK;
> +  if (find_omp_clause (OMP_TASK_CLAUSES (expr), OMP_CLAUSE_UNTIED))
> +    ctx->region_type_flags.task.untied = true;
> +
> +  gimplify_scan_omp_clauses (&OMP_TASK_CLAUSES (expr), pre_p, ctx);
>
>    push_gimplify_context ();
>
> @@ -6724,13 +6825,29 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
>    int i;
>    bool simd;
>    bitmap has_decl_expr = NULL;
> +  struct gimplify_omp_ctx *ctx = new_omp_context ();
>
>    orig_for_stmt = for_stmt = *expr_p;
>
> -  simd = (TREE_CODE (for_stmt) == OMP_SIMD
> -         || TREE_CODE (for_stmt) == CILK_SIMD);
> -  gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p,
> -                            simd ? ORT_SIMD : ORT_WORKSHARE);
> +  switch (TREE_CODE (for_stmt))
> +    {
> +    case OMP_FOR:
> +    case CILK_FOR:
> +    case OMP_DISTRIBUTE:
> +    case OACC_LOOP:
> +      simd = false;
> +      ctx->region_type = ORT_WORKSHARE;
> +      break;
> +    case OMP_SIMD:
> +    case CILK_SIMD:
> +      simd = true;
> +      ctx->region_type = ORT_SIMD;
> +      break;
> +    default:
> +      gcc_unreachable ();
> +    }
> +
> +  gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p, ctx);
>    if (TREE_CODE (for_stmt) == OMP_DISTRIBUTE)
>      gimplify_omp_ctxp->distribute = true;
>
> @@ -6764,6 +6881,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
>
>    if (OMP_FOR_INIT (for_stmt) == NULL_TREE)
>      {
> +      gcc_assert (TREE_CODE (for_stmt) != OACC_LOOP);
>        for_stmt = walk_tree (&OMP_FOR_BODY (for_stmt), find_combined_omp_for,
>                             NULL, NULL);
>        gcc_assert (for_stmt != NULL_TREE);
> @@ -7065,6 +7183,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
>      case CILK_SIMD: kind = GF_OMP_FOR_KIND_CILKSIMD; break;
>      case CILK_FOR: kind = GF_OMP_FOR_KIND_CILKFOR; break;
>      case OMP_DISTRIBUTE: kind = GF_OMP_FOR_KIND_DISTRIBUTE; break;
> +    case OACC_LOOP: kind = GF_OMP_FOR_KIND_OACC_LOOP; break;
>      default:
>        gcc_unreachable ();
>      }
> @@ -7105,9 +7224,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
>    return GS_ALL_DONE;
>  }
>
> -/* Gimplify the gross structure of other OpenMP constructs.
> -   In particular, OMP_SECTIONS, OMP_SINGLE, OMP_TARGET, OMP_TARGET_DATA
> -   and OMP_TEAMS.  */
> +/* Gimplify the gross structure of several OpenACC or OpenMP constructs.  */
>
>  static void
>  gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p)
> @@ -7115,27 +7232,34 @@ gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p)
>    tree expr = *expr_p;
>    gimple stmt;
>    gimple_seq body = NULL;
> -  enum omp_region_type ort = ORT_WORKSHARE;
> +  struct gimplify_omp_ctx *ctx = new_omp_context ();
>
>    switch (TREE_CODE (expr))
>      {
>      case OMP_SECTIONS:
>      case OMP_SINGLE:
> +      ctx->region_type = ORT_WORKSHARE;
>        break;
> +    case OACC_KERNELS:
> +    case OACC_PARALLEL:
>      case OMP_TARGET:
> -      ort = ORT_TARGET;
> +      ctx->region_type = ORT_TARGET;
> +      ctx->region_type_flags.target.offload = true;
>        break;
> +    case OACC_DATA:
>      case OMP_TARGET_DATA:
> -      ort = ORT_TARGET_DATA;
> +      ctx->region_type = ORT_TARGET;
>        break;
>      case OMP_TEAMS:
> -      ort = ORT_TEAMS;
> +      ctx->region_type = ORT_TEAMS;
>        break;
>      default:
>        gcc_unreachable ();
>      }
> -  gimplify_scan_omp_clauses (&OMP_CLAUSES (expr), pre_p, ort);
> -  if (ort == ORT_TARGET || ort == ORT_TARGET_DATA)
> +
> +  gimplify_scan_omp_clauses (&OMP_CLAUSES (expr), pre_p, ctx);
> +
> +  if (ctx->region_type == ORT_TARGET)
>      {
>        push_gimplify_context ();
>        gimple g = gimplify_and_return_first (OMP_BODY (expr), &body);
> @@ -7143,11 +7267,23 @@ gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p)
>         pop_gimplify_context (g);
>        else
>         pop_gimplify_context (NULL);
> -      if (ort == ORT_TARGET_DATA)
> +      if (!ctx->region_type_flags.target.offload)
>         {
> -         gimple_seq cleanup = NULL;
> -         tree fn = builtin_decl_explicit (BUILT_IN_GOMP_TARGET_END_DATA);
> +         enum built_in_function end_ix;
> +         switch (TREE_CODE (expr))
> +           {
> +           case OACC_DATA:
> +             end_ix = BUILT_IN_GOACC_DATA_END;
> +             break;
> +           case OMP_TARGET_DATA:
> +             end_ix = BUILT_IN_GOMP_TARGET_END_DATA;
> +             break;
> +           default:
> +             gcc_unreachable ();
> +           }
> +         tree fn = builtin_decl_explicit (end_ix);
>           g = gimple_build_call (fn, 0);
> +         gimple_seq cleanup = NULL;
>           gimple_seq_add_stmt (&cleanup, g);
>           g = gimple_build_try (body, cleanup, GIMPLE_TRY_FINALLY);
>           body = NULL;
> @@ -7160,6 +7296,16 @@ gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p)
>
>    switch (TREE_CODE (expr))
>      {
> +    case OACC_DATA:
> +      stmt = gimple_build_omp_target (body, GF_OMP_TARGET_KIND_OACC_DATA,
> +                                     OACC_DATA_CLAUSES (expr));
> +      break;
> +    case OACC_KERNELS:
> +      stmt = gimple_build_oacc_kernels (body, OACC_KERNELS_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;
> @@ -7185,19 +7331,42 @@ gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p)
>    *expr_p = NULL_TREE;
>  }
>
> -/* Gimplify the gross structure of OpenMP target update construct.  */
> +/* Gimplify the gross structure of OpenACC enter data and exit data, OpenACC
> +   update, and OpenMP target update constructs.  */
>
>  static void
>  gimplify_omp_target_update (tree *expr_p, gimple_seq *pre_p)
>  {
> -  tree expr = *expr_p;
> +  tree expr = *expr_p, clauses;
> +  int kind;
>    gimple stmt;
> +  struct gimplify_omp_ctx *ctx = new_omp_context ();
>
> -  gimplify_scan_omp_clauses (&OMP_TARGET_UPDATE_CLAUSES (expr), pre_p,
> -                            ORT_WORKSHARE);
> -  gimplify_adjust_omp_clauses (pre_p, &OMP_TARGET_UPDATE_CLAUSES (expr));
> -  stmt = gimple_build_omp_target (NULL, GF_OMP_TARGET_KIND_UPDATE,
> -                                 OMP_TARGET_UPDATE_CLAUSES (expr));
> +  switch (TREE_CODE (expr))
> +    {
> +    case OACC_ENTER_DATA:
> +      clauses = OACC_ENTER_DATA_CLAUSES (expr);
> +      kind = GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA;
> +      break;
> +    case OACC_EXIT_DATA:
> +      clauses = OACC_EXIT_DATA_CLAUSES (expr);
> +      kind = GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA;
> +      break;
> +    case OACC_UPDATE:
> +      clauses = OACC_UPDATE_CLAUSES (expr);
> +      kind = GF_OMP_TARGET_KIND_OACC_UPDATE;
> +      break;
> +    case OMP_TARGET_UPDATE:
> +      clauses = OMP_TARGET_UPDATE_CLAUSES (expr);
> +      kind = GF_OMP_TARGET_KIND_UPDATE;
> +      break;
> +    default:
> +      gcc_unreachable ();
> +    }
> +  ctx->region_type = ORT_WORKSHARE;
> +  gimplify_scan_omp_clauses (&clauses, pre_p, ctx);
> +  gimplify_adjust_omp_clauses (pre_p, &clauses);
> +  stmt = gimple_build_omp_target (NULL, kind, clauses);
>
>    gimplify_seq_add_stmt (pre_p, stmt);
>    *expr_p = NULL_TREE;
> @@ -8138,9 +8307,38 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
>         case CILK_SIMD:
>         case CILK_FOR:
>         case OMP_DISTRIBUTE:
> +       case OACC_LOOP:
>           ret = gimplify_omp_for (expr_p, pre_p);
>           break;
>
> +       case OACC_CACHE:
> +         gimplify_oacc_cache (expr_p, pre_p);
> +         ret = GS_ALL_DONE;
> +         break;
> +
> +       case OACC_DECLARE:
> +       case OACC_HOST_DATA:
> +         sorry ("directive not yet implemented");
> +         ret = GS_ALL_DONE;
> +         break;
> +
> +       case OACC_KERNELS:
> +         if (OACC_KERNELS_COMBINED (*expr_p))
> +           sorry ("directive not yet implemented");
> +         else
> +           gimplify_omp_workshare (expr_p, pre_p);
> +         ret = GS_ALL_DONE;
> +         break;
> +
> +       case OACC_PARALLEL:
> +         if (OACC_PARALLEL_COMBINED (*expr_p))
> +           sorry ("directive not yet implemented");
> +         else
> +           gimplify_omp_workshare (expr_p, pre_p);
> +         ret = GS_ALL_DONE;
> +         break;
> +
> +       case OACC_DATA:
>         case OMP_SECTIONS:
>         case OMP_SINGLE:
>         case OMP_TARGET:
> @@ -8150,6 +8348,9 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
>           ret = GS_ALL_DONE;
>           break;
>
> +       case OACC_ENTER_DATA:
> +       case OACC_EXIT_DATA:
> +       case OACC_UPDATE:
>         case OMP_TARGET_UPDATE:
>           gimplify_omp_target_update (expr_p, pre_p);
>           ret = GS_ALL_DONE;
> @@ -8531,8 +8732,18 @@ 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 != OACC_KERNELS
> +                 && code != OACC_DATA
> +                 && code != OACC_HOST_DATA
> +                 && code != OACC_DECLARE
> +                 && code != OACC_UPDATE
> +                 && code != OACC_ENTER_DATA
> +                 && code != OACC_EXIT_DATA
> +                 && code != OACC_CACHE
>                   && code != OMP_CRITICAL
>                   && code != OMP_FOR
> +                 && code != OACC_LOOP
>                   && code != OMP_MASTER
>                   && code != OMP_TASKGROUP
>                   && code != OMP_ORDERED
> @@ -8758,11 +8969,17 @@ gimplify_body (tree fndecl, bool do_parms)
>    gcc_assert (gimplify_ctxp == NULL);
>    push_gimplify_context ();
>
> -  if (flag_openmp)
> +  if (flag_openacc || flag_openmp)
>      {
>        gcc_assert (gimplify_omp_ctxp == NULL);
>        if (lookup_attribute ("omp declare target", DECL_ATTRIBUTES (fndecl)))
> -       gimplify_omp_ctxp = new_omp_context (ORT_TARGET);
> +       {
> +         struct gimplify_omp_ctx *ctx = new_omp_context ();
> +         ctx->region_type = ORT_TARGET;
> +         ctx->region_type_flags.target.offload = true;
> +
> +         gimplify_omp_ctxp = ctx;
> +       }
>      }
>
>    /* Unshare most shared trees in the body and in that of any nested functions.
> @@ -8842,7 +9059,8 @@ gimplify_body (tree fndecl, bool do_parms)
>        nonlocal_vlas = NULL;
>      }
>
> -  if ((flag_openmp || flag_openmp_simd) && gimplify_omp_ctxp)
> +  if ((flag_openacc || flag_openmp || flag_openmp_simd)
> +      && gimplify_omp_ctxp)
>      {
>        delete_omp_context (gimplify_omp_ctxp);
>        gimplify_omp_ctxp = NULL;
> diff --git gcc/ipa-inline-analysis.c gcc/ipa-inline-analysis.c
> index 68b9de0..9f6f529 100644
> --- gcc/ipa-inline-analysis.c
> +++ gcc/ipa-inline-analysis.c
> @@ -4025,7 +4025,7 @@ inline_generate_summary (void)
>
>    /* When not optimizing, do not bother to analyze.  Inlining is still done
>       because edge redirection needs to happen there.  */
> -  if (!optimize && !flag_lto && !flag_wpa)
> +  if (!optimize && !flag_lto && !flag_wpa && !flag_openacc && !flag_openmp)
>      return;
>
>    function_insertion_hook_holder =
> @@ -4340,11 +4340,6 @@ void
>  inline_free_summary (void)
>  {
>    struct cgraph_node *node;
> -  if (!inline_edge_summary_vec.exists ())
> -    return;
> -  FOR_EACH_DEFINED_FUNCTION (node)
> -    if (!node->alias)
> -      reset_inline_summary (node);
>    if (function_insertion_hook_holder)
>      symtab->remove_cgraph_insertion_hook (function_insertion_hook_holder);
>    function_insertion_hook_holder = NULL;
> @@ -4359,6 +4354,11 @@ inline_free_summary (void)
>    node_duplication_hook_holder = NULL;
>    if (edge_duplication_hook_holder)
>      symtab->remove_edge_duplication_hook (edge_duplication_hook_holder);
> +  if (!inline_edge_summary_vec.exists ())
> +    return;
> +  FOR_EACH_DEFINED_FUNCTION (node)
> +    if (!node->alias)
> +      reset_inline_summary (node);
>    edge_duplication_hook_holder = NULL;
>    vec_free (inline_summary_vec);
>    inline_edge_summary_vec.release ();
> diff --git gcc/lto-cgraph.c gcc/lto-cgraph.c
> index 28ec341..20052a0 100644
> --- gcc/lto-cgraph.c
> +++ gcc/lto-cgraph.c
> @@ -61,6 +61,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "context.h"
>  #include "pass_manager.h"
>  #include "ipa-utils.h"
> +#include "omp-low.h"
>
>  /* True when asm nodes has been output.  */
>  bool asm_nodes_output = false;
> @@ -247,6 +248,9 @@ void
>  lto_set_symtab_encoder_in_partition (lto_symtab_encoder_t encoder,
>                                      symtab_node *node)
>  {
> +  /* Ignore not needed nodes.  */
> +  if (!node->need_dump)
> +    return;
>    int index = lto_symtab_encoder_encode (encoder, node);
>    encoder->nodes[index].in_partition = true;
>  }
> @@ -812,6 +816,17 @@ create_references (lto_symtab_encoder_t encoder, symtab_node *node)
>        lto_symtab_encoder_encode (encoder, ref->referred);
>  }
>
> +/* Select what needs to be dumped. In lto case dump everything.
> +   In omp target case only dump stuff makrked with attribute.  */
> +void
> +select_what_to_dump (bool is_omp)
> +{
> +  struct symtab_node *snode;
> +  FOR_EACH_SYMBOL(snode)
> +    snode->need_dump = !is_omp || lookup_attribute ("omp declare target",
> +                                                   DECL_ATTRIBUTES (snode->decl));
> +}
> +
>  /* Find all symbols we want to stream into given partition and insert them
>     to encoders.
>
> @@ -1035,6 +1050,49 @@ read_string (struct lto_input_block *ib)
>    return str;
>  }
>
> +/* Output function/variable tables that will allow libgomp to look up offload
> +   target code.  OFFLOAD_FUNCS is filled in expand_omp_target, OFFLOAD_VARS is
> +   filled in ipa_passes.  In WHOPR (partitioned) mode during the WPA stage both
> +   OFFLOAD_FUNCS and OFFLOAD_VARS are filled by input_offload_tables.  */
> +
> +void
> +output_offload_tables (void)
> +{
> +  if (vec_safe_is_empty (offload_funcs) && vec_safe_is_empty (offload_vars))
> +    return;
> +
> +  struct lto_simple_output_block *ob
> +    = lto_create_simple_output_block (LTO_section_offload_table);
> +
> +  for (unsigned i = 0; i < vec_safe_length (offload_funcs); i++)
> +    {
> +      streamer_write_enum (ob->main_stream, LTO_symtab_tags,
> +                          LTO_symtab_last_tag, LTO_symtab_unavail_node);
> +      lto_output_fn_decl_index (ob->decl_state, ob->main_stream,
> +                               (*offload_funcs)[i]);
> +    }
> +
> +  for (unsigned i = 0; i < vec_safe_length (offload_vars); i++)
> +    {
> +      streamer_write_enum (ob->main_stream, LTO_symtab_tags,
> +                          LTO_symtab_last_tag, LTO_symtab_variable);
> +      lto_output_var_decl_index (ob->decl_state, ob->main_stream,
> +                                (*offload_vars)[i]);
> +    }
> +
> +  streamer_write_uhwi_stream (ob->main_stream, 0);
> +  lto_destroy_simple_output_block (ob);
> +
> +  /* In WHOPR mode during the WPA stage the joint offload tables need to be
> +     streamed to one partition only.  That's why we free offload_funcs and
> +     offload_vars after the first call of output_offload_tables.  */
> +  if (flag_wpa)
> +    {
> +      vec_free (offload_funcs);
> +      vec_free (offload_vars);
> +    }
> +}
> +
>  /* Overwrite the information in NODE based on FILE_DATA, TAG, FLAGS,
>     STACK_SIZE, SELF_TIME and SELF_SIZE.  This is called either to initialize
>     NODE or to replace the values in it, for instance because the first
> @@ -1734,6 +1792,55 @@ input_symtab (void)
>      }
>  }
>
> +/* Input function/variable tables that will allow libgomp to look up offload
> +   target code, and store them into OFFLOAD_FUNCS and OFFLOAD_VARS.  */
> +
> +void
> +input_offload_tables (void)
> +{
> +  struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data ();
> +  struct lto_file_decl_data *file_data;
> +  unsigned int j = 0;
> +
> +  while ((file_data = file_data_vec[j++]))
> +    {
> +      const char *data;
> +      size_t len;
> +      struct lto_input_block *ib
> +       = lto_create_simple_input_block (file_data, LTO_section_offload_table,
> +                                        &data, &len);
> +      if (!ib)
> +       continue;
> +
> +      enum LTO_symtab_tags tag
> +       = streamer_read_enum (ib, LTO_symtab_tags, LTO_symtab_last_tag);
> +      while (tag)
> +       {
> +         if (tag == LTO_symtab_unavail_node)
> +           {
> +             int decl_index = streamer_read_uhwi (ib);
> +             tree fn_decl
> +               = lto_file_decl_data_get_fn_decl (file_data, decl_index);
> +             vec_safe_push (offload_funcs, fn_decl);
> +           }
> +         else if (tag == LTO_symtab_variable)
> +           {
> +             int decl_index = streamer_read_uhwi (ib);
> +             tree var_decl
> +               = lto_file_decl_data_get_var_decl (file_data, decl_index);
> +             vec_safe_push (offload_vars, var_decl);
> +           }
> +         else
> +           fatal_error ("invalid offload table in %s", file_data->file_name);
> +
> +         tag = streamer_read_enum (ib, LTO_symtab_tags, LTO_symtab_last_tag);
> +       }
> +
> +      lto_destroy_simple_input_block (file_data, LTO_section_offload_table,
> +                                     ib, data, len);
> +    }
> +}
> +
>  /* True when we need optimization summary for NODE.  */
>
>  static int
> diff --git gcc/lto-section-in.c gcc/lto-section-in.c
> index 042dd99..d54ca0f 100644
> --- gcc/lto-section-in.c
> +++ gcc/lto-section-in.c
> @@ -70,7 +70,8 @@ const char *lto_section_name[LTO_N_SECTION_TYPES] =
>    "cgraphopt",
>    "inline",
>    "ipcp_trans",
> -  "icf"
> +  "icf",
> +  "offload_table"
>  };
>
>
> diff --git gcc/lto-section-names.h gcc/lto-section-names.h
> index cb75230..47065b5 100644
> --- gcc/lto-section-names.h
> +++ gcc/lto-section-names.h
> @@ -29,5 +29,13 @@ along with GCC; see the file COPYING3.  If not see
>  /* Segment name for LTO sections.  This is only used for Mach-O.  */
>
>  #define LTO_SEGMENT_NAME "__GNU_LTO"
> +#define OMP_SECTION_NAME_PREFIX         ".gnu.target_lto_"
> +
> +/* Can be either OMP_SECTION_NAME_PREFIX when we stream pragma omp target
> +   stuff, or LTO_SECTION_NAME_PREFIX for lto case.  */
> +extern const char  *section_name_prefix;
> +
> +#define OFFLOAD_VAR_TABLE_SECTION_NAME "__gnu_offload_vars"
> +#define OFFLOAD_FUNC_TABLE_SECTION_NAME "__gnu_offload_funcs"
>
>  #endif /* GCC_LTO_SECTION_NAMES_H */
> diff --git gcc/lto-streamer-out.c gcc/lto-streamer-out.c
> index dc406da..98ee44d 100644
> --- gcc/lto-streamer-out.c
> +++ gcc/lto-streamer-out.c
> @@ -2308,6 +2308,8 @@ lto_output (void)
>       statements using the statement UIDs.  */
>    output_symtab ();
>
> +  output_offload_tables ();
> +
>  #ifdef ENABLE_CHECKING
>    lto_bitmap_free (output);
>  #endif
> diff --git gcc/lto-streamer.c gcc/lto-streamer.c
> index b6cac0b..00171a3 100644
> --- gcc/lto-streamer.c
> +++ gcc/lto-streamer.c
> @@ -60,6 +60,7 @@ struct lto_stats_d lto_stats;
>  static bitmap_obstack lto_obstack;
>  static bool lto_obstack_initialized;
>
> +const char *section_name_prefix = LTO_SECTION_NAME_PREFIX;
>
>  /* Return a string representing LTO tag TAG.  */
>
> @@ -189,7 +190,7 @@ lto_get_section_name (int section_type, const char *name, struct lto_file_decl_d
>      sprintf (post, "." HOST_WIDE_INT_PRINT_HEX_PURE, f->id);
>    else
>      sprintf (post, "." HOST_WIDE_INT_PRINT_HEX_PURE, get_random_seed (false));
> -  return concat (LTO_SECTION_NAME_PREFIX, sep, add, post, NULL);
> +  return concat (section_name_prefix, sep, add, post, NULL);
>  }
>
>
> @@ -327,7 +328,7 @@ lto_streamer_init (void)
>  bool
>  gate_lto_out (void)
>  {
> -  return ((flag_generate_lto || in_lto_p)
> +  return ((flag_generate_lto || in_lto_p || flag_openacc || flag_openmp)
>           /* Don't bother doing anything if the program has errors.  */
>           && !seen_error ());
>  }
> diff --git gcc/lto-streamer.h gcc/lto-streamer.h
> index 4b875a2..bc25725 100644
> --- gcc/lto-streamer.h
> +++ gcc/lto-streamer.h
> @@ -247,6 +247,7 @@ enum lto_section_type
>    LTO_section_inline_summary,
>    LTO_section_ipcp_transform,
>    LTO_section_ipa_icf,
> +  LTO_section_offload_table,
>    LTO_N_SECTION_TYPES          /* Must be last.  */
>  };
>
> @@ -822,6 +823,8 @@ bool lto_symtab_encoder_encode_initializer_p (lto_symtab_encoder_t,
>                                               varpool_node *);
>  void output_symtab (void);
>  void input_symtab (void);
> +void output_offload_tables (void);
> +void input_offload_tables (void);
>  bool referenced_from_other_partition_p (struct ipa_ref_list *,
>                                         lto_symtab_encoder_t);
>  bool reachable_from_other_partition_p (struct cgraph_node *,
> @@ -831,6 +834,7 @@ bool referenced_from_this_partition_p (symtab_node *,
>  bool reachable_from_this_partition_p (struct cgraph_node *,
>                                       lto_symtab_encoder_t);
>  lto_symtab_encoder_t compute_ltrans_boundary (lto_symtab_encoder_t encoder);
> +void select_what_to_dump (bool);
>
>
>  /* In lto-symtab.c.  */
> diff --git gcc/lto-wrapper.c gcc/lto-wrapper.c
> index 8033b15..6013514 100644
> --- gcc/lto-wrapper.c
> +++ gcc/lto-wrapper.c
> @@ -49,6 +49,8 @@ along with GCC; see the file COPYING3.  If not see
>  #include "lto-section-names.h"
>  #include "collect-utils.h"
>
> +#define OFFLOAD_TARGET_NAMES_ENV       "OFFLOAD_TARGET_NAMES"
> +
>  enum lto_mode_d {
>    LTO_MODE_NONE,                       /* Not doing LTO.  */
>    LTO_MODE_LTO,                                /* Normal LTO.  */
> @@ -63,6 +65,8 @@ static char *flto_out;
>  static unsigned int nr;
>  static char **input_names;
>  static char **output_names;
> +static char **offload_names;
> +static const char *ompbegin, *ompend;
>  static char *makefile;
>
>  const char tool_name[] = "lto-wrapper";
> @@ -364,6 +368,243 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>      }
>  }
>
> +/* Auxiliary function that frees elements of PTR and PTR itself.
> +   N is number of elements to be freed.
> +   If PTR is NULL, nothing is freed.  If an element is NULL, subsequent elements
> +   are not freed.  */
> +static void**
> +free_array_of_ptrs (void **ptr, unsigned n)
> +{
> +  unsigned i;
> +  if (!ptr)
> +    return NULL;
> +  for (i = 0; i < n; i++)
> +    {
> +      if (!ptr[i])
> +       break;
> +      free (ptr[i]);
> +    }
> +  free (ptr);
> +  return NULL;
> +}
> +
> +/* Parse STR, saving found tokens into PVALUES and return their number.
> +   Tokens are assumed to be delimited by ':'.  If APPEND is non-null,
> +   append it to every token we find.  */
> +
> +static unsigned
> +parse_env_var (const char *str, char ***pvalues, const char *append)
> +{
> +  const char *curval, *nextval;
> +  char **values;
> +  unsigned num = 1, i;
> +
> +  curval = strchr (str, ':');
> +  while (curval)
> +    {
> +      num++;
> +      curval = strchr (curval + 1, ':');
> +    }
> +
> +  values = (char**) xmalloc (num * sizeof (char*));
> +  curval = str;
> +  nextval = strchrnul (curval, ':');
> +
> +  int append_len = append ? strlen (append) : 0;
> +  for (i = 0; i < num; i++)
> +    {
> +      int l = nextval - curval;
> +      values[i] = (char*) xmalloc (l + 1 + append_len);
> +      memcpy (values[i], curval, l);
> +      values[i][l] = 0;
> +      if (append)
> +       strcat (values[i], append);
> +      curval = nextval + 1;
> +      nextval = strchrnul (curval, ':');
> +    }
> +  *pvalues = values;
> +  return num;
> +}
> +
> +/* Check whether NAME can be accessed in MODE.  This is like access,
> +   except that it never considers directories to be executable.  */
> +
> +static int
> +access_check (const char *name, int mode)
> +{
> +  if (mode == X_OK)
> +    {
> +      struct stat st;
> +
> +      if (stat (name, &st) < 0
> +         || S_ISDIR (st.st_mode))
> +       return -1;
> +    }
> +
> +  return access (name, mode);
> +}
> +
> +/* Prepare target image for target NAME.
> +   Firstly, we execute COMPILER, passing all input files to it to produce DSO.
> +   When target DSO is ready, we pass it to objcopy to place its image into a
> +   special data section.  After that we rename target image's symbols to values,
> +   expected by the host side, and return the name of the resultant file.  */
> +
> +static char*
> +prepare_target_image (const char *target, const char *compiler_path,
> +                     unsigned in_argc, char *in_argv[])
> +{
> +  const char **argv;
> +  struct obstack argv_obstack;
> +  unsigned i;
> +  char *filename = NULL;
> +  char *suffix = XALLOCAVEC (char, strlen ("/accel//mkoffload") + 1 + strlen (target));
> +  const char *compiler = NULL;
> +
> +  strcpy (suffix, "/accel/");
> +  strcat (suffix, target);
> +  strcat (suffix, "/mkoffload");
> +
> +  char **paths;
> +  int n_paths = parse_env_var (compiler_path, &paths, suffix);
> +
> +  for (int i = 0; i < n_paths; i++)
> +    if (access_check (paths[i], X_OK) == 0)
> +      {
> +       compiler = paths[i];
> +       break;
> +      }
> +
> +  if (compiler == NULL)
> +    goto out;
> +
> +  /* Generate temp file name.  */
> +  filename = make_temp_file (".target.o");
> +
> +  /* --------------------------------------  */
> +  /* Run gcc for target.  */
> +  obstack_init (&argv_obstack);
> +  obstack_ptr_grow (&argv_obstack, compiler);
> +  obstack_ptr_grow (&argv_obstack, "-o");
> +  obstack_ptr_grow (&argv_obstack, filename);
> +
> +  for (i = 1; i < in_argc; ++i)
> +    if (strncmp (in_argv[i], "-fresolution=", sizeof ("-fresolution=") - 1))
> +      obstack_ptr_grow (&argv_obstack, in_argv[i]);
> +  obstack_ptr_grow (&argv_obstack, NULL);
> +
> +  argv = XOBFINISH (&argv_obstack, const char **);
> +  fork_execute (argv[0], CONST_CAST (char **, argv), true);
> +  obstack_free (&argv_obstack, NULL);
> +
> + out:
> +  free_array_of_ptrs ((void**) paths, n_paths);
> +  return filename;
> +}
> +
> +
> +/* The main routine dealing with openmp offloading.
> +   The routine builds a target image for each offloading target.
> +   IN_ARGC and IN_ARGV specify input files.  As all of them could contain
> +   omp-sections, we pass them all to target compilers.
> +   Env-variable OFFLOAD_TARGET_NAMES_ENV describes for which targets we should
> +   build images.
> +   This function stores the names of the object files in the OFFLOAD_NAMES
> +   array.  */
> +
> +static void
> +compile_images_for_openmp_targets (unsigned in_argc, char *in_argv[])
> +{
> +  char *target_names;
> +  char **names;
> +  unsigned num_targets;
> +
> +  /* Obtain names of offload targets and corresponding compilers.  */
> +  target_names = getenv (OFFLOAD_TARGET_NAMES_ENV);
> +  if (!target_names)
> +    return;
> +
> +  num_targets = parse_env_var (target_names, &names, NULL);
> +
> +  const char *compiler_path = getenv ("COMPILER_PATH");
> +  if (compiler_path == NULL)
> +    goto out;
> +
> +  /* Prepare an image for each target.  The array is terminated by a NULL
> +     entry.  */
> +  offload_names = XCNEWVEC (char *, num_targets + 1);
> +  for (unsigned i = 0; i < num_targets; i++)
> +    {
> +      offload_names[i] = prepare_target_image (names[i], compiler_path,
> +                                              in_argc, in_argv);
> +      if (!offload_names[i])
> +       fatal_error ("problem with building target image for %s: %m",
> +                    names[i]);
> +    }
> +
> + out:
> +  free_array_of_ptrs ((void**) names, num_targets);
> +}
> +
> +/* Copy a file from SRC to DEST.  */
> +static void
> +copy_file (const char *dest, const char *src)
> +{
> +  FILE *d = fopen (dest, "wb");
> +  FILE *s = fopen (src, "rb");
> +  char buffer[512];
> +  while (!feof (s))
> +    {
> +      size_t len = fread (buffer, 1, 512, s);
> +      if (ferror (s) != 0)
> +       fatal_error ("reading input file");
> +      if (len > 0)
> +       {
> +         fwrite (buffer, 1, len, d);
> +         if (ferror (d) != 0)
> +           fatal_error ("writing output file");
> +       }
> +    }
> +}
> +
> +/* Find the omp_begin.o and omp_end.o files in LIBRARY_PATH, make copies
> +   and store the names of the copies in ompbegin and ompend.  */
> +
> +static void
> +find_ompbeginend (void)
> +{
> +  char **paths;
> +  const char *library_path = getenv ("LIBRARY_PATH");
> +  if (library_path == NULL)
> +    return;
> +  int n_paths = parse_env_var (library_path, &paths, "/crtompbegin.o");
> +
> +  int i;
> +  for (i = 0; i < n_paths; i++)
> +    if (access_check (paths[i], R_OK) == 0)
> +      {
> +       size_t len = strlen (paths[i]);
> +       char *tmp = xstrdup (paths[i]);
> +       strcpy (paths[i] + len - 7, "end.o");
> +       if (access_check (paths[i], R_OK) != 0)
> +         fatal_error ("installation error, can't find crtompend.o");
> +       /* The linker will delete the filenames we give it, so make
> +          copies.  */
> +       const char *omptmp1 = make_temp_file (".o");
> +       const char *omptmp2 = make_temp_file (".o");
> +       copy_file (omptmp1, tmp);
> +       ompbegin = omptmp1;
> +       copy_file (omptmp2, paths[i]);
> +       ompend = omptmp2;
> +       free (tmp);
> +       break;
> +      }
> +  if (i == n_paths)
> +    fatal_error ("installation error, can't find crtompbegin.o");
> +
> +  free_array_of_ptrs ((void**) paths, n_paths);
> +}
> +
>  /* Execute gcc. ARGC is the number of arguments. ARGV contains the arguments. */
>
>  static void
> @@ -384,6 +625,7 @@ run_gcc (unsigned argc, char *argv[])
>    unsigned int decoded_options_count;
>    struct obstack argv_obstack;
>    int new_head_argc;
> +  bool have_offload = false;
>
>    /* Get the driver and options.  */
>    collect_gcc = getenv ("COLLECT_GCC");
> @@ -439,6 +681,11 @@ run_gcc (unsigned argc, char *argv[])
>           close (fd);
>           continue;
>         }
> +      /* We may choose not to write out this .opts section in the future.  In
> +        that case we'll have to use something else to look for.  */
> +      if (simple_object_find_section (sobj, OMP_SECTION_NAME_PREFIX "." "opts",
> +                                     &offset, &length, &errmsg, &err))
> +       have_offload = true;
>        lseek (fd, file_offset + offset, SEEK_SET);
>        data = (char *)xmalloc (length);
>        read (fd, data, length);
> @@ -846,12 +1093,37 @@ cont:
>           for (i = 0; i < nr; ++i)
>             maybe_unlink (input_names[i]);
>         }
> +      if (have_offload)
> +       {
> +         compile_images_for_openmp_targets (argc, argv);
> +         if (offload_names)
> +           {
> +             find_ompbeginend ();
> +             for (i = 0; offload_names[i]; i++)
> +               {
> +                 fputs (offload_names[i], stdout);
> +                 putc ('\n', stdout);
> +               }
> +             free_array_of_ptrs ((void **)offload_names, i);
> +           }
> +       }
> +      if (ompbegin)
> +       {
> +         fputs (ompbegin, stdout);
> +         putc ('\n', stdout);
> +       }
> +
>        for (i = 0; i < nr; ++i)
>         {
>           fputs (output_names[i], stdout);
>           putc ('\n', stdout);
>           free (input_names[i]);
>         }
> +      if (ompend)
> +       {
> +         fputs (ompend, stdout);
> +         putc ('\n', stdout);
> +       }
>        nr = 0;
>        free (output_names);
>        free (input_names);
> diff --git gcc/lto/lto-lang.c gcc/lto/lto-lang.c
> index a4ae2a8..804a3f8 100644
> --- gcc/lto/lto-lang.c
> +++ gcc/lto/lto-lang.c
> @@ -171,6 +171,11 @@ enum lto_builtin_type
>  #define DEF_FUNCTION_TYPE_VAR_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
>  #define DEF_FUNCTION_TYPE_VAR_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG6) \
>    NAME,
> +#define DEF_FUNCTION_TYPE_VAR_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
> +                               ARG6, ARG7, ARG8) NAME,
> +#define DEF_FUNCTION_TYPE_VAR_12(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
> +                                ARG6, ARG7, ARG8, ARG9, ARG10, ARG11,       \
> +                                ARG12) NAME,
>  #define DEF_POINTER_TYPE(NAME, TYPE) NAME,
>  #include "builtin-types.def"
>  #undef DEF_PRIMITIVE_TYPE
> @@ -189,6 +194,8 @@ enum lto_builtin_type
>  #undef DEF_FUNCTION_TYPE_VAR_3
>  #undef DEF_FUNCTION_TYPE_VAR_4
>  #undef DEF_FUNCTION_TYPE_VAR_5
> +#undef DEF_FUNCTION_TYPE_VAR_8
> +#undef DEF_FUNCTION_TYPE_VAR_12
>  #undef DEF_POINTER_TYPE
>    BT_LAST
>  };
> @@ -673,6 +680,14 @@ lto_define_builtins (tree va_list_ref_type_node ATTRIBUTE_UNUSED,
>    def_fn_type (ENUM, RETURN, 1, 4, ARG1, ARG2, ARG3, ARG4);
>  #define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
>    def_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, ARG4, ARG5);
> +#define DEF_FUNCTION_TYPE_VAR_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
> +                               ARG6, ARG7, ARG8)                           \
> +  def_fn_type (ENUM, RETURN, 1, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6,      \
> +              ARG7, ARG8);
> +#define DEF_FUNCTION_TYPE_VAR_12(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
> +                                ARG6, ARG7, ARG8, ARG9, ARG10, ARG11, ARG12) \
> +  def_fn_type (ENUM, RETURN, 1, 12, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6,      \
> +              ARG7, ARG8, ARG9, ARG10, ARG11, ARG12);
>  #define DEF_POINTER_TYPE(ENUM, TYPE) \
>    builtin_types[(int) ENUM] = build_pointer_type (builtin_types[(int) TYPE]);
>
> @@ -694,6 +709,8 @@ lto_define_builtins (tree va_list_ref_type_node ATTRIBUTE_UNUSED,
>  #undef DEF_FUNCTION_TYPE_VAR_3
>  #undef DEF_FUNCTION_TYPE_VAR_4
>  #undef DEF_FUNCTION_TYPE_VAR_5
> +#undef DEF_FUNCTION_TYPE_VAR_8
> +#undef DEF_FUNCTION_TYPE_VAR_12
>  #undef DEF_POINTER_TYPE
>    builtin_types[(int) BT_LAST] = NULL_TREE;
>
> diff --git gcc/lto/lto-object.c gcc/lto/lto-object.c
> index 1178326..b4124f6 100644
> --- gcc/lto/lto-object.c
> +++ gcc/lto/lto-object.c
> @@ -242,8 +242,7 @@ lto_obj_add_section (void *data, const char *name, off_t offset,
>    void **slot;
>    struct lto_section_list *list = loasd->list;
>
> -  if (strncmp (name, LTO_SECTION_NAME_PREFIX,
> -              strlen (LTO_SECTION_NAME_PREFIX)) != 0)
> +  if (strncmp (name, section_name_prefix, strlen (section_name_prefix)))
>      return 1;
>
>    new_name = xstrdup (name);
> diff --git gcc/lto/lto-partition.c gcc/lto/lto-partition.c
> index c38931b..0a0f50d 100644
> --- gcc/lto/lto-partition.c
> +++ gcc/lto/lto-partition.c
> @@ -147,6 +147,7 @@ add_symbol_to_partition_1 (ltrans_partition part, symtab_node *node)
>    gcc_assert (c != SYMBOL_EXTERNAL
>               && (c == SYMBOL_DUPLICATE || !symbol_partitioned_p (node)));
>
> +  node->need_dump = true;
>    lto_set_symtab_encoder_in_partition (part->encoder, node);
>
>    if (symbol_partitioned_p (node))
> @@ -933,6 +934,8 @@ lto_promote_cross_file_statics (void)
>
>    gcc_assert (flag_wpa);
>
> +  select_what_to_dump (false);
> +
>    /* First compute boundaries.  */
>    n_sets = ltrans_partitions.length ();
>    for (i = 0; i < n_sets; i++)
> diff --git gcc/lto/lto.c gcc/lto/lto.c
> index d8519d9..ad4a132 100644
> --- gcc/lto/lto.c
> +++ gcc/lto/lto.c
> @@ -2137,7 +2137,7 @@ lto_section_with_id (const char *name, unsigned HOST_WIDE_INT *id)
>  {
>    const char *s;
>
> -  if (strncmp (name, LTO_SECTION_NAME_PREFIX, strlen (LTO_SECTION_NAME_PREFIX)))
> +  if (strncmp (name, section_name_prefix, strlen (section_name_prefix)))
>      return 0;
>    s = strrchr (name, '.');
>    return s && sscanf (s, "." HOST_WIDE_INT_PRINT_HEX_PURE, id) == 1;
> @@ -2912,6 +2912,10 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames)
>
>    timevar_push (TV_IPA_LTO_DECL_IN);
>
> +#ifdef ACCEL_COMPILER
> +    section_name_prefix = OMP_SECTION_NAME_PREFIX;
> +#endif
> +
>    real_file_decl_data
>      = decl_data = ggc_cleared_vec_alloc<lto_file_decl_data_ptr> (nfiles + 1);
>    real_file_count = nfiles;
> @@ -3030,6 +3034,8 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames)
>    /* Read the symtab.  */
>    input_symtab ();
>
> +  input_offload_tables ();
> +
>    /* Store resolutions into the symbol table.  */
>
>    ld_plugin_symbol_resolution_t *res;
> diff --git gcc/oacc-builtins.def gcc/oacc-builtins.def
> new file mode 100644
> index 0000000..7ed95ac
> --- /dev/null
> +++ gcc/oacc-builtins.def
> @@ -0,0 +1,56 @@
> +/* This file contains the definitions and documentation for the
> +   OpenACC builtins used in the GNU compiler.
> +
> +   Copyright (C) 2013-2014 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.  */
> +
> +DEF_GOACC_BUILTIN (BUILT_IN_ACC_GET_DEVICE_TYPE, "acc_get_device_type",
> +                  BT_FN_INT, ATTR_NOTHROW_LIST)
> +DEF_GOACC_BUILTIN (BUILT_IN_GOACC_DATA_START, "GOACC_data_start",
> +                  BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR, ATTR_NOTHROW_LIST)
> +DEF_GOACC_BUILTIN (BUILT_IN_GOACC_DATA_END, "GOACC_data_end",
> +                  BT_FN_VOID, ATTR_NOTHROW_LIST)
> +DEF_GOACC_BUILTIN (BUILT_IN_GOACC_ENTER_EXIT_DATA, "GOACC_enter_exit_data",
> +                  BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR_INT_INT_VAR,
> +                  ATTR_NOTHROW_LIST)
> +DEF_GOACC_BUILTIN (BUILT_IN_GOACC_KERNELS, "GOACC_kernels",
> +       BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR_INT_INT_INT_INT_INT_VAR,
> +       ATTR_NOTHROW_LIST)
> +DEF_GOACC_BUILTIN (BUILT_IN_GOACC_PARALLEL, "GOACC_parallel",
> +       BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR_INT_INT_INT_INT_INT_VAR,
> +       ATTR_NOTHROW_LIST)
> +DEF_GOACC_BUILTIN (BUILT_IN_GOACC_UPDATE, "GOACC_update",
> +                  BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR_INT_INT_VAR,
> +                  ATTR_NOTHROW_LIST)
> +DEF_GOACC_BUILTIN (BUILT_IN_GOACC_WAIT, "GOACC_wait",
> +                  BT_FN_VOID_INT_INT_VAR,
> +                  ATTR_NOTHROW_LIST)
> +DEF_GOACC_BUILTIN_COMPILER (BUILT_IN_ACC_ON_DEVICE, "acc_on_device",
> +                           BT_FN_INT_INT, ATTR_CONST_NOTHROW_LEAF_LIST)
> +DEF_GOACC_BUILTIN (BUILT_IN_GOACC_GET_THREAD_NUM, "GOACC_get_thread_num",
> +                  BT_FN_INT, ATTR_CONST_NOTHROW_LEAF_LIST)
> +DEF_GOACC_BUILTIN (BUILT_IN_GOACC_GET_NUM_THREADS, "GOACC_get_num_threads",
> +                  BT_FN_INT, ATTR_CONST_NOTHROW_LEAF_LIST)
> diff --git gcc/omp-low.c gcc/omp-low.c
> index 91f8e8f..1db77b4 100644
> --- gcc/omp-low.c
> +++ gcc/omp-low.c
> @@ -76,6 +76,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "optabs.h"
>  #include "cfgloop.h"
>  #include "target.h"
> +#include "common/common-target.h"
>  #include "omp-low.h"
>  #include "gimple-low.h"
>  #include "tree-cfgcleanup.h"
> @@ -85,6 +86,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "tree-nested.h"
>  #include "tree-eh.h"
>  #include "cilk.h"
> +#include "lto-section-names.h"
>
>
>  /* Lowering of OpenMP parallel and workshare constructs proceeds in two
> @@ -171,6 +173,11 @@ typedef struct omp_context
>       construct.  In the case of a parallel, this is in the child function.  */
>    tree block_vars;
>
> +  /* A map of reduction pointer variables.  For accelerators, each
> +     reduction variable is replaced with an array.  Each thread, in turn,
> +     is assigned to a slot on that array.  */
> +  splay_tree reduction_map;
> +
>    /* Label to which GOMP_cancel{,llation_point} and explicit and implicit
>       barriers should jump to during omplower pass.  */
>    tree cancel_label;
> @@ -191,6 +198,8 @@ typedef struct omp_context
>    bool cancellable;
>  } omp_context;
>
> +/* A structure holding the elements of:
> +   for (V = N1; V cond N2; V += STEP) [...] */
>
>  struct omp_for_data_loop
>  {
> @@ -233,6 +242,90 @@ static tree scan_omp_1_op (tree *, int *, void *);
>        *handled_ops_p = false; \
>        break;
>
> +/* Helper function to get the reduction array name */
> +static const char *
> +omp_get_id (tree node)
> +{
> +  const char *id = IDENTIFIER_POINTER (DECL_NAME (node));
> +  int len = strlen ("omp$") + strlen (id);
> +  char *temp_name = (char *)alloca (len+1);
> +  snprintf (temp_name, len+1, "gfc$%s", id);
> +  return IDENTIFIER_POINTER(get_identifier (temp_name));
> +}
> +
> +/* Determine the number of threads OpenACC threads used to determine the
> +   size of the array of partial reductions.  Currently, this is num_gangs
> +   * vector_length.  This value may be different than GOACC_GET_NUM_THREADS,
> +   because it is independed of the device used.  */
> +
> +static tree
> +oacc_max_threads (omp_context *ctx)
> +{
> +  tree nthreads, vector_length, gangs, clauses;
> +
> +  gangs = fold_convert (sizetype, integer_one_node);
> +  vector_length = gangs;
> +
> +  /* The reduction clause may be nested inside a loop directive.
> +     Scan for the innermost vector_length clause.  */
> +  for (omp_context *oc = ctx; oc; oc = oc->outer)
> +    {
> +      if (gimple_code (oc->stmt) != GIMPLE_OACC_PARALLEL)
> +       continue;
> +
> +      clauses = gimple_oacc_parallel_clauses (oc->stmt);
> +
> +      vector_length = find_omp_clause (clauses, OMP_CLAUSE_VECTOR_LENGTH);
> +      if (vector_length)
> +       vector_length = fold_convert_loc (OMP_CLAUSE_LOCATION (vector_length),
> +                                         sizetype,
> +                                         OMP_CLAUSE_VECTOR_LENGTH_EXPR
> +                                         (vector_length));
> +      else
> +       vector_length = fold_convert (sizetype, integer_one_node);
> +
> +      gangs = find_omp_clause (clauses, OMP_CLAUSE_NUM_GANGS);
> +      if (gangs)
> +        gangs = fold_convert_loc (OMP_CLAUSE_LOCATION (gangs), sizetype,
> +                                 OMP_CLAUSE_NUM_GANGS_EXPR (gangs));
> +      else
> +       gangs = fold_convert (sizetype, integer_one_node);
> +
> +      break;
> +    }
> +
> +  nthreads = fold_build2 (MULT_EXPR, sizetype, gangs, vector_length);
> +
> +  return nthreads;
> +}
> +
> +/* Holds a decl for __OPENMP_TARGET__.  */
> +static GTY(()) tree offload_symbol_decl;
> +
> +/* Holds offload tables with decls.  */
> +vec<tree, va_gc> *offload_funcs, *offload_vars;
> +
> +/* Get the __OPENMP_TARGET__ symbol.  */
> +static tree
> +get_offload_symbol_decl (void)
> +{
> +  if (!offload_symbol_decl)
> +    {
> +      tree decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
> +                             get_identifier ("__OPENMP_TARGET__"),
> +                             ptr_type_node);
> +      TREE_ADDRESSABLE (decl) = 1;
> +      TREE_PUBLIC (decl) = 1;
> +      DECL_EXTERNAL (decl) = 1;
> +      DECL_WEAK (decl) = 1;
> +      DECL_ATTRIBUTES (decl)
> +       = tree_cons (get_identifier ("weak"),
> +                    NULL_TREE, DECL_ATTRIBUTES (decl));
> +      offload_symbol_decl = decl;
> +    }
> +  return offload_symbol_decl;
> +}
> +
>  /* Convenience function for calling scan_omp_1_op on tree operands.  */
>
>  static inline tree
> @@ -596,6 +689,15 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd,
>        fd->loop.step = build_int_cst (TREE_TYPE (fd->loop.v), 1);
>        fd->loop.cond_code = LT_EXPR;
>      }
> +
> +  /* For OpenACC loops, force a chunk size of one, as this avoids the default
> +    scheduling where several subsequent iterations are being executed by the
> +    same thread.  */
> +  if (gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_OACC_LOOP)
> +    {
> +      gcc_assert (fd->chunk_size == NULL_TREE);
> +      fd->chunk_size = build_int_cst (TREE_TYPE (fd->loop.v), 1);
> +    }
>  }
>
>
> @@ -824,7 +926,18 @@ is_reference (tree decl)
>    return lang_hooks.decls.omp_privatize_by_reference (decl);
>  }
>
> -/* Lookup variables in the decl or field splay trees.  The "maybe" form
> +/* Return the type of a decl.  If the decl is reference type,
> +   return its base type.  */
> +static inline tree
> +get_base_type (tree decl)
> +{
> +  tree type = TREE_TYPE (decl);
> +  if (is_reference (decl))
> +    type = TREE_TYPE (type);
> +  return type;
> +}
> +
> +/* Lookup variables.  The "maybe" form
>     allows for the variable form to not have been entered, otherwise we
>     assert that the variable must have been entered.  */
>
> @@ -868,6 +981,25 @@ maybe_lookup_field (tree var, omp_context *ctx)
>    return n ? (tree) n->value : NULL_TREE;
>  }
>
> +static inline tree
> +lookup_reduction (const char *id, omp_context *ctx)
> +{
> +  gcc_assert (is_gimple_omp_oacc_specifically (ctx->stmt));
> +
> +  splay_tree_node n;
> +  n = splay_tree_lookup (ctx->reduction_map, (splay_tree_key) id);
> +  return (tree) n->value;
> +}
> +
> +static inline tree
> +maybe_lookup_reduction (tree var, omp_context *ctx)
> +{
> +  splay_tree_node n = NULL;
> +  if (ctx->reduction_map)
> +    n = splay_tree_lookup (ctx->reduction_map, (splay_tree_key) var);
> +  return n ? (tree) n->value : NULL_TREE;
> +}
> +
>  /* Return true if DECL should be copied by pointer.  SHARED_CTX is
>     the parallel context if DECL is to be shared.  */
>
> @@ -881,6 +1013,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 (!is_gimple_omp_oacc_specifically (shared_ctx->stmt));
> +
>        /* ??? 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
> @@ -1085,6 +1219,8 @@ install_var_field (tree var, bool by_ref, int mask, omp_context *ctx)
>               || !splay_tree_lookup (ctx->field_map, (splay_tree_key) var));
>    gcc_assert ((mask & 2) == 0 || !ctx->sfield_map
>               || !splay_tree_lookup (ctx->sfield_map, (splay_tree_key) var));
> +  gcc_assert ((mask & 3) == 3
> +             || !is_gimple_omp_oacc_specifically (ctx->stmt));
>
>    type = TREE_TYPE (var);
>    if (mask & 4)
> @@ -1361,6 +1497,7 @@ new_omp_context (gimple stmt, omp_context *outer_ctx)
>        ctx->cb = outer_ctx->cb;
>        ctx->cb.block = NULL;
>        ctx->depth = outer_ctx->depth + 1;
> +      ctx->reduction_map = outer_ctx->reduction_map;
>      }
>    else
>      {
> @@ -1431,6 +1568,11 @@ delete_omp_context (splay_tree_value value)
>      splay_tree_delete (ctx->field_map);
>    if (ctx->sfield_map)
>      splay_tree_delete (ctx->sfield_map);
> +  if (ctx->reduction_map
> +      /* Shared over several omp_contexts.  */
> +      && (ctx->outer == NULL
> +         || ctx->reduction_map != ctx->outer->reduction_map))
> +    splay_tree_delete (ctx->reduction_map);
>
>    /* We hijacked DECL_ABSTRACT_ORIGIN earlier.  We need to clear it before
>       it produces corrupt debug information.  */
> @@ -1527,6 +1669,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
>           break;
>
>         case OMP_CLAUSE_SHARED:
> +         gcc_assert (!is_gimple_omp_oacc_specifically (ctx->stmt));
>           decl = OMP_CLAUSE_DECL (c);
>           /* Ignore shared directives in teams construct.  */
>           if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS)
> @@ -1561,6 +1704,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
>           goto do_private;
>
>         case OMP_CLAUSE_LASTPRIVATE:
> +         gcc_assert (!is_gimple_omp_oacc_specifically (ctx->stmt));
>           /* Let the corresponding firstprivate clause create
>              the variable.  */
>           if (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c))
> @@ -1568,8 +1712,16 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
>           /* FALLTHRU */
>
>         case OMP_CLAUSE_FIRSTPRIVATE:
> -       case OMP_CLAUSE_REDUCTION:
> +         if (is_gimple_omp_oacc_specifically (ctx->stmt))
> +           {
> +             sorry ("clause not supported yet");
> +             break;
> +           }
> +         /* FALLTHRU */
>         case OMP_CLAUSE_LINEAR:
> +         gcc_assert (!is_gimple_omp_oacc_specifically (ctx->stmt));
> +         /* FALLTHRU */
> +       case OMP_CLAUSE_REDUCTION:
>           decl = OMP_CLAUSE_DECL (c);
>         do_private:
>           if (is_variable_sized (decl))
> @@ -1595,9 +1747,30 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
>                 install_var_field (decl, by_ref, 3, ctx);
>             }
>           install_var_local (decl, ctx);
> +         if (is_gimple_omp_oacc_specifically (ctx->stmt)
> +             && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)
> +           {
> +             /* Create a decl for the reduction array.  */
> +             tree var = OMP_CLAUSE_DECL (c);
> +             tree type = get_base_type (var);
> +             tree ptype = build_pointer_type (type);
> +             tree array = create_tmp_var (ptype, omp_get_id (var));
> +             omp_context *c = (ctx->field_map ? ctx : ctx->outer);
> +             install_var_field (array, true, 3, c);
> +             install_var_local (array, c);
> +
> +             /* Insert it into the current context.  */
> +             splay_tree_insert (ctx->reduction_map,
> +                                (splay_tree_key) omp_get_id(var),
> +                                (splay_tree_value) array);
> +             splay_tree_insert (ctx->reduction_map,
> +                                (splay_tree_key) array,
> +                                (splay_tree_value) array);
> +           }
>           break;
>
>         case OMP_CLAUSE__LOOPTEMP_:
> +         gcc_assert (!is_gimple_omp_oacc_specifically (ctx->stmt));
>           gcc_assert (is_parallel_ctx (ctx));
>           decl = OMP_CLAUSE_DECL (c);
>           install_var_field (decl, false, 3, ctx);
> @@ -1606,17 +1779,18 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
>
>         case OMP_CLAUSE_COPYPRIVATE:
>         case OMP_CLAUSE_COPYIN:
> +         gcc_assert (!is_gimple_omp_oacc_specifically (ctx->stmt));
>           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 (!is_gimple_omp_oacc_specifically (ctx->stmt));
>           ctx->default_kind = OMP_CLAUSE_DEFAULT_KIND (c);
>           break;
>
>         case OMP_CLAUSE_FINAL:
> -       case OMP_CLAUSE_IF:
>         case OMP_CLAUSE_NUM_THREADS:
>         case OMP_CLAUSE_NUM_TEAMS:
>         case OMP_CLAUSE_THREAD_LIMIT:
> @@ -1625,13 +1799,41 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
>         case OMP_CLAUSE_DIST_SCHEDULE:
>         case OMP_CLAUSE_DEPEND:
>         case OMP_CLAUSE__CILK_FOR_COUNT_:
> +         gcc_assert (!is_gimple_omp_oacc_specifically (ctx->stmt));
> +         /* FALLTHRU */
> +       case OMP_CLAUSE_IF:
> +       case OMP_CLAUSE_NUM_GANGS:
> +       case OMP_CLAUSE_NUM_WORKERS:
> +       case OMP_CLAUSE_VECTOR_LENGTH:
>           if (ctx->outer)
>             scan_omp_op (&OMP_CLAUSE_OPERAND (c, 0), ctx->outer);
>           break;
>
>         case OMP_CLAUSE_TO:
>         case OMP_CLAUSE_FROM:
> +         gcc_assert (!is_gimple_omp_oacc_specifically (ctx->stmt));
> +         /* FALLTHRU */
>         case OMP_CLAUSE_MAP:
> +         switch (OMP_CLAUSE_CODE (c))
> +           {
> +           case OMP_CLAUSE_TO:
> +           case OMP_CLAUSE_FROM:
> +             /* The to and from clauses are only ever seen with OpenMP target
> +                update constructs.  */
> +             gcc_assert (gimple_code (ctx->stmt) == GIMPLE_OMP_TARGET
> +                         && (gimple_omp_target_kind (ctx->stmt)
> +                             == GF_OMP_TARGET_KIND_UPDATE));
> +             break;
> +           case OMP_CLAUSE_MAP:
> +             /* The map clause is never seen with OpenMP target update
> +                constructs.  */
> +             gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OMP_TARGET
> +                         || (gimple_omp_target_kind (ctx->stmt)
> +                             != GF_OMP_TARGET_KIND_UPDATE));
> +             break;
> +           default:
> +             gcc_unreachable ();
> +           }
>           if (ctx->outer)
>             scan_omp_op (&OMP_CLAUSE_SIZE (c), ctx->outer);
>           decl = OMP_CLAUSE_DECL (c);
> @@ -1643,14 +1845,17 @@ 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)))
> -           break;
> +           {
> +             gcc_assert (!is_gimple_omp_oacc_specifically (ctx->stmt));
> +             break;
> +           }
>           if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
>               && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER)
>             {
>               /* Ignore OMP_CLAUSE_MAP_POINTER kind for arrays in
> -                #pragma omp target data, there is nothing to map for
> +                data regions that are not offloaded; there is nothing to map for
>                  those.  */
> -             if (gimple_omp_target_kind (ctx->stmt) == GF_OMP_TARGET_KIND_DATA
> +             if (!is_gimple_omp_offloaded (ctx->stmt)
>                   && !POINTER_TYPE_P (TREE_TYPE (decl)))
>                 break;
>             }
> @@ -1669,6 +1874,10 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
>                 }
>               else
>                 {
> +                 gcc_assert (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP
> +                             || (OMP_CLAUSE_MAP_KIND (c)
> +                                 != OMP_CLAUSE_MAP_FORCE_DEVICEPTR)
> +                             || TREE_CODE (TREE_TYPE (decl)) != 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)
> @@ -1676,8 +1885,7 @@ 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 (is_gimple_omp_offloaded (ctx->stmt))
>                     install_var_local (decl, ctx);
>                 }
>             }
> @@ -1717,20 +1925,35 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
>
>         case OMP_CLAUSE_NOWAIT:
>         case OMP_CLAUSE_ORDERED:
> -       case OMP_CLAUSE_COLLAPSE:
>         case OMP_CLAUSE_UNTIED:
>         case OMP_CLAUSE_MERGEABLE:
>         case OMP_CLAUSE_PROC_BIND:
>         case OMP_CLAUSE_SAFELEN:
> +         gcc_assert (!is_gimple_omp_oacc_specifically (ctx->stmt));
> +         /* FALLTHRU */
> +       case OMP_CLAUSE_COLLAPSE:
> +       case OMP_CLAUSE_ASYNC:
> +       case OMP_CLAUSE_WAIT:
>           break;
>
>         case OMP_CLAUSE_ALIGNED:
> +         gcc_assert (!is_gimple_omp_oacc_specifically (ctx->stmt));
>           decl = OMP_CLAUSE_DECL (c);
>           if (is_global_var (decl)
>               && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
>             install_var_local (decl, ctx);
>           break;
>
> +       case OMP_CLAUSE_DEVICE_RESIDENT:
> +       case OMP_CLAUSE_USE_DEVICE:
> +       case OMP_CLAUSE_GANG:
> +       case OMP_CLAUSE__CACHE_:
> +       case OMP_CLAUSE_INDEPENDENT:
> +       case OMP_CLAUSE_WORKER:
> +       case OMP_CLAUSE_VECTOR:
> +         sorry ("Clause not supported yet");
> +         break;
> +
>         default:
>           gcc_unreachable ();
>         }
> @@ -1741,6 +1964,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
>        switch (OMP_CLAUSE_CODE (c))
>         {
>         case OMP_CLAUSE_LASTPRIVATE:
> +         gcc_assert (!is_gimple_omp_oacc_specifically (ctx->stmt));
>           /* Let the corresponding firstprivate clause create
>              the variable.  */
>           if (OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c))
> @@ -1749,10 +1973,18 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
>             break;
>           /* FALLTHRU */
>
> -       case OMP_CLAUSE_PRIVATE:
>         case OMP_CLAUSE_FIRSTPRIVATE:
> -       case OMP_CLAUSE_REDUCTION:
> +         if (is_gimple_omp_oacc_specifically (ctx->stmt))
> +           {
> +             sorry ("clause not supported yet");
> +             break;
> +           }
> +         /* FALLTHRU */
>         case OMP_CLAUSE_LINEAR:
> +         gcc_assert (!is_gimple_omp_oacc_specifically (ctx->stmt));
> +         /* FALLTHRU */
> +       case OMP_CLAUSE_PRIVATE:
> +       case OMP_CLAUSE_REDUCTION:
>           decl = OMP_CLAUSE_DECL (c);
>           if (is_variable_sized (decl))
>             install_var_local (decl, ctx);
> @@ -1768,6 +2000,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
>           break;
>
>         case OMP_CLAUSE_SHARED:
> +         gcc_assert (!is_gimple_omp_oacc_specifically (ctx->stmt));
>           /* Ignore shared directives in teams construct.  */
>           if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS)
>             break;
> @@ -1777,16 +2010,27 @@ 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)
> +         /* The map clause is never seen with OpenMP target update
> +            constructs.  */
> +         gcc_assert (gimple_code (ctx->stmt) != GIMPLE_OMP_TARGET
> +                     || (gimple_omp_target_kind (ctx->stmt)
> +                         != GF_OMP_TARGET_KIND_UPDATE));
> +         if (!is_gimple_omp_offloaded (ctx->stmt))
>             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)))
> -           break;
> +           {
> +             gcc_assert (!is_gimple_omp_oacc_specifically (ctx->stmt));
> +             break;
> +           }
>           if (DECL_P (decl))
>             {
> +             gcc_assert ((OMP_CLAUSE_MAP_KIND (c)
> +                          != OMP_CLAUSE_MAP_FORCE_DEVICEPTR)
> +                         || TREE_CODE (TREE_TYPE (decl)) != ARRAY_TYPE);
>               if (OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER
>                   && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
>                   && !COMPLETE_TYPE_P (TREE_TYPE (decl)))
> @@ -1798,6 +2042,9 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
>               else if (DECL_SIZE (decl)
>                        && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
>                 {
> +                 gcc_assert (OMP_CLAUSE_MAP_KIND (c)
> +                             != OMP_CLAUSE_MAP_FORCE_DEVICEPTR);
> +
>                   tree decl2 = DECL_VALUE_EXPR (decl);
>                   gcc_assert (TREE_CODE (decl2) == INDIRECT_REF);
>                   decl2 = TREE_OPERAND (decl2, 0);
> @@ -1813,7 +2060,6 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
>         case OMP_CLAUSE_COPYPRIVATE:
>         case OMP_CLAUSE_COPYIN:
>         case OMP_CLAUSE_DEFAULT:
> -       case OMP_CLAUSE_IF:
>         case OMP_CLAUSE_NUM_THREADS:
>         case OMP_CLAUSE_NUM_TEAMS:
>         case OMP_CLAUSE_THREAD_LIMIT:
> @@ -1822,7 +2068,6 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
>         case OMP_CLAUSE_DIST_SCHEDULE:
>         case OMP_CLAUSE_NOWAIT:
>         case OMP_CLAUSE_ORDERED:
> -       case OMP_CLAUSE_COLLAPSE:
>         case OMP_CLAUSE_UNTIED:
>         case OMP_CLAUSE_FINAL:
>         case OMP_CLAUSE_MERGEABLE:
> @@ -1834,6 +2079,25 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
>         case OMP_CLAUSE_TO:
>         case OMP_CLAUSE_FROM:
>         case OMP_CLAUSE__CILK_FOR_COUNT_:
> +         gcc_assert (!is_gimple_omp_oacc_specifically (ctx->stmt));
> +         /* FALLTHRU */
> +       case OMP_CLAUSE_ASYNC:
> +       case OMP_CLAUSE_COLLAPSE:
> +       case OMP_CLAUSE_IF:
> +       case OMP_CLAUSE_NUM_GANGS:
> +       case OMP_CLAUSE_NUM_WORKERS:
> +       case OMP_CLAUSE_VECTOR_LENGTH:
> +       case OMP_CLAUSE_WAIT:
> +         break;
> +
> +       case OMP_CLAUSE_DEVICE_RESIDENT:
> +       case OMP_CLAUSE_USE_DEVICE:
> +       case OMP_CLAUSE_GANG:
> +       case OMP_CLAUSE__CACHE_:
> +       case OMP_CLAUSE_INDEPENDENT:
> +       case OMP_CLAUSE_WORKER:
> +       case OMP_CLAUSE_VECTOR:
> +         sorry ("Clause not supported yet");
>           break;
>
>         default:
> @@ -1841,6 +2105,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
>         }
>      }
>
> +  gcc_assert (!is_gimple_omp_oacc_specifically (ctx->stmt)
> +             || !scan_array_reductions);
>    if (scan_array_reductions)
>      for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
>        if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
> @@ -1923,6 +2189,8 @@ create_omp_child_function (omp_context *ctx, bool task_copy)
>
>    decl = build_decl (gimple_location (ctx->stmt), FUNCTION_DECL, name, type);
>
> +  gcc_assert (!is_gimple_omp_oacc_specifically (ctx->stmt)
> +             || !task_copy);
>    if (!task_copy)
>      ctx->cb.dst_fn = decl;
>    else
> @@ -1945,9 +2213,7 @@ create_omp_child_function (omp_context *ctx, bool task_copy)
>      {
>        omp_context *octx;
>        for (octx = ctx; octx; octx = octx->outer)
> -       if (gimple_code (octx->stmt) == GIMPLE_OMP_TARGET
> -           && gimple_omp_target_kind (octx->stmt)
> -              == GF_OMP_TARGET_KIND_REGION)
> +       if (is_gimple_omp_offloaded (octx->stmt))
>           {
>             target_p = true;
>             break;
> @@ -2284,7 +2550,7 @@ finish_taskreg_scan (omp_context *ctx)
>  }
>
>
> -/* Scan an OpenMP loop directive.  */
> +/* Scan a GIMPLE_OMP_FOR.  */
>
>  static void
>  scan_omp_for (gimple stmt, omp_context *outer_ctx)
> @@ -2344,14 +2610,41 @@ scan_omp_single (gimple stmt, omp_context *outer_ctx)
>      layout_type (ctx->record_type);
>  }
>
> -/* Scan an OpenMP target{, data, update} directive.  */
> +/* Scan a GIMPLE_OMP_TARGET.  */
>
>  static void
>  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);
> +
> +  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);
> +    }
>
>    ctx = new_omp_context (stmt, outer_ctx);
>    ctx->field_map = splay_tree_new (splay_tree_compare_pointers, 0, 0);
> @@ -2363,13 +2656,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)
> @@ -2387,7 +2684,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);
>      }
>  }
> @@ -2406,6 +2703,43 @@ scan_omp_teams (gimple stmt, omp_context *outer_ctx)
>  static bool
>  check_omp_nesting_restrictions (gimple stmt, omp_context *ctx)
>  {
> +  /* 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))
> +    {
> +      /* 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");
> +           return false;
> +         }
> +    }
> + cont:
> +
>    if (ctx != NULL)
>      {
>        if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR
> @@ -2584,6 +2918,8 @@ 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:
> @@ -2841,6 +3177,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;
> @@ -3135,6 +3473,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 (!is_gimple_omp_oacc_specifically (ctx->stmt));
> +
>    if (max_vf == 0)
>      {
>        max_vf = omp_max_vf ();
> @@ -4055,6 +4395,57 @@ lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *stmt_list,
>      gimple_seq_add_stmt (stmt_list, gimple_build_label (label));
>  }
>
> +static void
> +lower_reduction_var_helper (gimple_seq *stmt_seqp, omp_context *ctx, tree tid,
> +                           tree var, tree new_var)
> +{
> +  /* The atomic add at the end of the sum creates unnecessary
> +     write contention on accelerators.  To work around this,
> +     create an array to store the partial reductions. Later, in
> +     lower_omp_for (for openacc), the values of array will be
> +     combined.  */
> +
> +  tree t = NULL_TREE, array, x;
> +  tree type = get_base_type (var);
> +  gimple stmt;
> +
> +  /* Now insert the partial reductions into the array.  */
> +
> +  /* Find the reduction array.  */
> +
> +  tree ptype = build_pointer_type (type);
> +
> +  t = lookup_reduction (omp_get_id (var), ctx);
> +  t = build_receiver_ref (t, false, ctx->outer);
> +
> +  array = create_tmp_var (ptype, NULL);
> +  gimplify_assign (array, t, stmt_seqp);
> +
> +  tree ptr = create_tmp_var (TREE_TYPE (array), NULL);
> +
> +  /* Find the reduction array.  */
> +
> +  /* testing a unary conversion.  */
> +  tree offset = create_tmp_var (sizetype, NULL);
> +  gimplify_assign (offset, TYPE_SIZE_UNIT (type),
> +                  stmt_seqp);
> +  t = create_tmp_var (sizetype, NULL);
> +  gimplify_assign (t, unshare_expr (fold_build1 (NOP_EXPR, sizetype, tid)),
> +                  stmt_seqp);
> +  stmt = gimple_build_assign_with_ops (MULT_EXPR, offset, offset, t);
> +  gimple_seq_add_stmt (stmt_seqp, stmt);
> +
> +  /* Offset expression.  Does the POINTER_PLUS_EXPR take care
> +     of adding sizeof(var) to the array?  */
> +  ptr = create_tmp_var (ptype, NULL);
> +  stmt = gimple_build_assign_with_ops (POINTER_PLUS_EXPR, unshare_expr(ptr),
> +                                      array, offset);
> +  gimple_seq_add_stmt (stmt_seqp, stmt);
> +
> +  /* Move the local sum to gfc$sum[i].  */
> +  x = unshare_expr (build_simple_mem_ref (ptr));
> +  stmt = gimplify_assign (x, new_var, stmt_seqp);
> +}
>
>  /* Generate code to implement the REDUCTION clauses.  */
>
> @@ -4063,7 +4454,7 @@ lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp, omp_context *ctx)
>  {
>    gimple_seq sub_seq = NULL;
>    gimple stmt;
> -  tree x, c;
> +  tree x, c, tid = NULL_TREE;
>    int count = 0;
>
>    /* SIMD reductions are handled in lower_rec_input_clauses.  */
> @@ -4088,6 +4479,17 @@ lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp, omp_context *ctx)
>    if (count == 0)
>      return;
>
> +  /* Initialize thread info for OpenACC.  */
> +  if (is_gimple_omp_oacc_specifically (ctx->stmt))
> +    {
> +      /* Get the current thread id.  */
> +      tree call = builtin_decl_explicit (BUILT_IN_GOACC_GET_THREAD_NUM);
> +      tid = create_tmp_var (TREE_TYPE (TREE_TYPE (call)), NULL);
> +      gimple stmt = gimple_build_call (call, 0);
> +      gimple_call_set_lhs (stmt, tid);
> +      gimple_seq_add_stmt (stmt_seqp, stmt);
> +    }
> +
>    for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
>      {
>        tree var, ref, new_var;
> @@ -4109,7 +4511,13 @@ lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp, omp_context *ctx)
>        if (code == MINUS_EXPR)
>          code = PLUS_EXPR;
>
> -      if (count == 1)
> +      if (is_gimple_omp_oacc_specifically (ctx->stmt))
> +       {
> +         gcc_assert (!OMP_CLAUSE_REDUCTION_PLACEHOLDER (c));
> +
> +         lower_reduction_var_helper (stmt_seqp, ctx, tid, var, new_var);
> +       }
> +      else if (count == 1)
>         {
>           tree addr = build_fold_addr_expr_loc (clause_loc, ref);
>
> @@ -4120,8 +4528,7 @@ lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp, omp_context *ctx)
>           gimplify_and_add (x, stmt_seqp);
>           return;
>         }
> -
> -      if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
> +      else if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
>         {
>           tree placeholder = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c);
>
> @@ -4144,6 +4551,9 @@ lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp, omp_context *ctx)
>         }
>      }
>
> +  if (is_gimple_omp_oacc_specifically (ctx->stmt))
> +    return;
> +
>    stmt = gimple_build_call (builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_START),
>                             0);
>    gimple_seq_add_stmt (stmt_seqp, stmt);
> @@ -4162,6 +4572,8 @@ static void
>  lower_copyprivate_clauses (tree clauses, gimple_seq *slist, gimple_seq *rlist,
>                             omp_context *ctx)
>  {
> +  gcc_assert (!is_gimple_omp_oacc_specifically (ctx->stmt));
> +
>    tree c;
>
>    for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
> @@ -4212,6 +4624,8 @@ static void
>  lower_send_clauses (tree clauses, gimple_seq *ilist, gimple_seq *olist,
>                     omp_context *ctx)
>  {
> +  gcc_assert (!is_gimple_omp_oacc_specifically (ctx->stmt));
> +
>    tree c;
>
>    for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
> @@ -4303,6 +4717,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 (!is_gimple_omp_oacc_specifically (ctx->stmt));
> +
>    tree var, ovar, nvar, f, x, record_type;
>
>    if (ctx->record_type == NULL)
> @@ -5599,6 +6015,8 @@ expand_omp_for_generic (struct omp_region *region,
>                         enum built_in_function next_fn,
>                         gimple inner_stmt)
>  {
> +  gcc_assert (gimple_omp_for_kind (fd->for_stmt) != GF_OMP_FOR_KIND_OACC_LOOP);
> +
>    tree type, istart0, iend0, iend;
>    tree t, vmain, vback, bias = NULL_TREE;
>    basic_block entry_bb, cont_bb, exit_bb, l0_bb, l1_bb, collapse_bb;
> @@ -5668,6 +6086,9 @@ expand_omp_for_generic (struct omp_region *region,
>    gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
>    if (fd->collapse > 1)
>      {
> +      gcc_assert (gimple_omp_for_kind (gsi_stmt (gsi))
> +                 != GF_OMP_FOR_KIND_OACC_LOOP);
> +
>        int first_zero_iter = -1;
>        basic_block zero_iter_bb = NULL, l2_dom_bb = NULL;
>
> @@ -5696,6 +6117,9 @@ expand_omp_for_generic (struct omp_region *region,
>      }
>    if (in_combined_parallel)
>      {
> +      gcc_assert (gimple_omp_for_kind (gsi_stmt (gsi))
> +                 != GF_OMP_FOR_KIND_OACC_LOOP);
> +
>        /* In a combined parallel loop, emit a call to
>          GOMP_loop_foo_next.  */
>        t = build_call_expr (builtin_decl_explicit (next_fn), 2,
> @@ -5714,6 +6138,9 @@ expand_omp_for_generic (struct omp_region *region,
>        t0 = fd->loop.n1;
>        if (gimple_omp_for_combined_into_p (fd->for_stmt))
>         {
> +         gcc_assert (gimple_omp_for_kind (gsi_stmt (gsi))
> +                     != GF_OMP_FOR_KIND_OACC_LOOP);
> +
>           tree innerc = find_omp_clause (gimple_omp_for_clauses (fd->for_stmt),
>                                          OMP_CLAUSE__LOOPTEMP_);
>           gcc_assert (innerc);
> @@ -6031,12 +6458,14 @@ expand_omp_for_static_nochunk (struct omp_region *region,
>    gimple_stmt_iterator gsi;
>    gimple stmt;
>    edge ep;
> -  enum built_in_function get_num_threads = BUILT_IN_OMP_GET_NUM_THREADS;
> -  enum built_in_function get_thread_num = BUILT_IN_OMP_GET_THREAD_NUM;
>    bool broken_loop = region->cont == NULL;
>    tree *counts = NULL;
>    tree n1, n2, step;
>
> +  gcc_assert ((gimple_omp_for_kind (fd->for_stmt)
> +              != GF_OMP_FOR_KIND_OACC_LOOP)
> +             || !inner_stmt);
> +
>    itype = type = TREE_TYPE (fd->loop.v);
>    if (POINTER_TYPE_P (type))
>      itype = signed_type_for (type);
> @@ -6060,12 +6489,6 @@ expand_omp_for_static_nochunk (struct omp_region *region,
>    gsi = gsi_last_bb (entry_bb);
>    gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
>
> -  if (gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_DISTRIBUTE)
> -    {
> -      get_num_threads = BUILT_IN_OMP_GET_NUM_TEAMS;
> -      get_thread_num = BUILT_IN_OMP_GET_TEAM_NUM;
> -    }
> -
>    if (fd->collapse > 1)
>      {
>        int first_zero_iter = -1;
> @@ -6124,14 +6547,30 @@ expand_omp_for_static_nochunk (struct omp_region *region,
>        gsi = gsi_last_bb (entry_bb);
>      }
>
> -  t = build_call_expr (builtin_decl_explicit (get_num_threads), 0);
> -  t = fold_convert (itype, t);
> -  nthreads = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
> +  switch (gimple_omp_for_kind (fd->for_stmt))
> +    {
> +    case GF_OMP_FOR_KIND_FOR:
> +      nthreads = builtin_decl_explicit (BUILT_IN_OMP_GET_NUM_THREADS);
> +      threadid = builtin_decl_explicit (BUILT_IN_OMP_GET_THREAD_NUM);
> +      break;
> +    case GF_OMP_FOR_KIND_DISTRIBUTE:
> +      nthreads = builtin_decl_explicit (BUILT_IN_OMP_GET_NUM_TEAMS);
> +      threadid = builtin_decl_explicit (BUILT_IN_OMP_GET_TEAM_NUM);
> +      break;
> +    case GF_OMP_FOR_KIND_OACC_LOOP:
> +      nthreads = builtin_decl_explicit (BUILT_IN_GOACC_GET_NUM_THREADS);
> +      threadid = builtin_decl_explicit (BUILT_IN_GOACC_GET_THREAD_NUM);
> +      break;
> +    default:
> +      gcc_unreachable ();
> +    }
> +  nthreads = build_call_expr (nthreads, 0);
> +  nthreads = fold_convert (itype, nthreads);
> +  nthreads = force_gimple_operand_gsi (&gsi, nthreads, true, NULL_TREE,
>                                        true, GSI_SAME_STMT);
> -
> -  t = build_call_expr (builtin_decl_explicit (get_thread_num), 0);
> -  t = fold_convert (itype, t);
> -  threadid = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
> +  threadid = build_call_expr (threadid, 0);
> +  threadid = fold_convert (itype, threadid);
> +  threadid = force_gimple_operand_gsi (&gsi, threadid, true, NULL_TREE,
>                                        true, GSI_SAME_STMT);
>
>    n1 = fd->loop.n1;
> @@ -6139,6 +6578,9 @@ expand_omp_for_static_nochunk (struct omp_region *region,
>    step = fd->loop.step;
>    if (gimple_omp_for_combined_into_p (fd->for_stmt))
>      {
> +      gcc_assert (gimple_omp_for_kind (fd->for_stmt)
> +                 != GF_OMP_FOR_KIND_OACC_LOOP);
> +
>        tree innerc = find_omp_clause (gimple_omp_for_clauses (fd->for_stmt),
>                                      OMP_CLAUSE__LOOPTEMP_);
>        gcc_assert (innerc);
> @@ -6306,7 +6748,10 @@ expand_omp_for_static_nochunk (struct omp_region *region,
>    if (!gimple_omp_return_nowait_p (gsi_stmt (gsi)))
>      {
>        t = gimple_omp_return_lhs (gsi_stmt (gsi));
> -      gsi_insert_after (&gsi, build_omp_barrier (t), GSI_SAME_STMT);
> +      if (gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_OACC_LOOP)
> +       gcc_assert (t == NULL_TREE);
> +      else
> +       gsi_insert_after (&gsi, build_omp_barrier (t), GSI_SAME_STMT);
>      }
>    gsi_remove (&gsi, true);
>
> @@ -6324,6 +6769,9 @@ expand_omp_for_static_nochunk (struct omp_region *region,
>        ep = find_edge (cont_bb, body_bb);
>        if (gimple_omp_for_combined_p (fd->for_stmt))
>         {
> +         gcc_assert (gimple_omp_for_kind (fd->for_stmt)
> +                     != GF_OMP_FOR_KIND_OACC_LOOP);
> +
>           remove_edge (ep);
>           ep = NULL;
>         }
> @@ -6408,12 +6856,14 @@ expand_omp_for_static_chunk (struct omp_region *region,
>    gimple_stmt_iterator gsi;
>    gimple stmt;
>    edge se;
> -  enum built_in_function get_num_threads = BUILT_IN_OMP_GET_NUM_THREADS;
> -  enum built_in_function get_thread_num = BUILT_IN_OMP_GET_THREAD_NUM;
>    bool broken_loop = region->cont == NULL;
>    tree *counts = NULL;
>    tree n1, n2, step;
>
> +  gcc_assert ((gimple_omp_for_kind (fd->for_stmt)
> +              != GF_OMP_FOR_KIND_OACC_LOOP)
> +             || !inner_stmt);
> +
>    itype = type = TREE_TYPE (fd->loop.v);
>    if (POINTER_TYPE_P (type))
>      itype = signed_type_for (type);
> @@ -6441,12 +6891,6 @@ expand_omp_for_static_chunk (struct omp_region *region,
>    gsi = gsi_last_bb (entry_bb);
>    gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
>
> -  if (gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_DISTRIBUTE)
> -    {
> -      get_num_threads = BUILT_IN_OMP_GET_NUM_TEAMS;
> -      get_thread_num = BUILT_IN_OMP_GET_TEAM_NUM;
> -    }
> -
>    if (fd->collapse > 1)
>      {
>        int first_zero_iter = -1;
> @@ -6505,14 +6949,30 @@ expand_omp_for_static_chunk (struct omp_region *region,
>        gsi = gsi_last_bb (entry_bb);
>      }
>
> -  t = build_call_expr (builtin_decl_explicit (get_num_threads), 0);
> -  t = fold_convert (itype, t);
> -  nthreads = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
> +  switch (gimple_omp_for_kind (fd->for_stmt))
> +    {
> +    case GF_OMP_FOR_KIND_FOR:
> +      nthreads = builtin_decl_explicit (BUILT_IN_OMP_GET_NUM_THREADS);
> +      threadid = builtin_decl_explicit (BUILT_IN_OMP_GET_THREAD_NUM);
> +      break;
> +    case GF_OMP_FOR_KIND_DISTRIBUTE:
> +      nthreads = builtin_decl_explicit (BUILT_IN_OMP_GET_NUM_TEAMS);
> +      threadid = builtin_decl_explicit (BUILT_IN_OMP_GET_TEAM_NUM);
> +      break;
> +    case GF_OMP_FOR_KIND_OACC_LOOP:
> +      nthreads = builtin_decl_explicit (BUILT_IN_GOACC_GET_NUM_THREADS);
> +      threadid = builtin_decl_explicit (BUILT_IN_GOACC_GET_THREAD_NUM);
> +      break;
> +    default:
> +      gcc_unreachable ();
> +    }
> +  nthreads = build_call_expr (nthreads, 0);
> +  nthreads = fold_convert (itype, nthreads);
> +  nthreads = force_gimple_operand_gsi (&gsi, nthreads, true, NULL_TREE,
>                                        true, GSI_SAME_STMT);
> -
> -  t = build_call_expr (builtin_decl_explicit (get_thread_num), 0);
> -  t = fold_convert (itype, t);
> -  threadid = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
> +  threadid = build_call_expr (threadid, 0);
> +  threadid = fold_convert (itype, threadid);
> +  threadid = force_gimple_operand_gsi (&gsi, threadid, true, NULL_TREE,
>                                        true, GSI_SAME_STMT);
>
>    n1 = fd->loop.n1;
> @@ -6520,6 +6980,9 @@ expand_omp_for_static_chunk (struct omp_region *region,
>    step = fd->loop.step;
>    if (gimple_omp_for_combined_into_p (fd->for_stmt))
>      {
> +      gcc_assert (gimple_omp_for_kind (fd->for_stmt)
> +                 != GF_OMP_FOR_KIND_OACC_LOOP);
> +
>        tree innerc = find_omp_clause (gimple_omp_for_clauses (fd->for_stmt),
>                                      OMP_CLAUSE__LOOPTEMP_);
>        gcc_assert (innerc);
> @@ -6704,7 +7167,10 @@ expand_omp_for_static_chunk (struct omp_region *region,
>    if (!gimple_omp_return_nowait_p (gsi_stmt (gsi)))
>      {
>        t = gimple_omp_return_lhs (gsi_stmt (gsi));
> -      gsi_insert_after (&gsi, build_omp_barrier (t), GSI_SAME_STMT);
> +      if (gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_OACC_LOOP)
> +       gcc_assert (t == NULL_TREE);
> +      else
> +       gsi_insert_after (&gsi, build_omp_barrier (t), GSI_SAME_STMT);
>      }
>    gsi_remove (&gsi, true);
>
> @@ -6717,6 +7183,9 @@ expand_omp_for_static_chunk (struct omp_region *region,
>        se = find_edge (cont_bb, body_bb);
>        if (gimple_omp_for_combined_p (fd->for_stmt))
>         {
> +         gcc_assert (gimple_omp_for_kind (fd->for_stmt)
> +                     != GF_OMP_FOR_KIND_OACC_LOOP);
> +
>           remove_edge (se);
>           se = NULL;
>         }
> @@ -8253,55 +8722,99 @@ expand_omp_atomic (struct omp_region *region)
>  }
>
>
> -/* Expand the OpenMP target{, data, update} directive starting at REGION.  */
> +/* Expand the GIMPLE_OMP_TARGET starting at REGION.  */
>
>  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))
>             {
> @@ -8336,7 +8849,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))
> @@ -8353,13 +8866,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;
> @@ -8376,7 +8888,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);
>
> @@ -8406,6 +8918,9 @@ expand_omp_target (struct omp_region *region)
>        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);
> @@ -8428,20 +8943,54 @@ 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 (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;
> +    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 ();
> +    }
>
> -  if (kind == GF_OMP_TARGET_KIND_REGION)
> -    start_ix = BUILT_IN_GOMP_TARGET;
> -  else if (kind == GF_OMP_TARGET_KIND_DATA)
> -    start_ix = BUILT_IN_GOMP_TARGET_DATA;
> -  else
> -    start_ix = BUILT_IN_GOMP_TARGET_UPDATE;
> +  clauses = gimple_omp_clauses (entry_stmt);
>
>    /* By default, the value of DEVICE is -1 (let runtime library choose)
>       and there is no conditional.  */
> @@ -8455,6 +9004,12 @@ expand_omp_target (struct omp_region *region)
>    c = find_omp_clause (clauses, OMP_CLAUSE_DEVICE);
>    if (c)
>      {
> +      /* 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);
>      }
> @@ -8475,14 +9030,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);
> @@ -8516,7 +9073,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;
> @@ -8534,28 +9091,124 @@ expand_omp_target (struct omp_region *region)
>      }
>
>    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);
> -  if (kind == GF_OMP_TARGET_KIND_REGION)
> +  tree openmp_target = get_offload_symbol_decl ();
> +  vec<tree> *args;
> +  /* The maximum number used by any start_ix, without varargs.  */
> +  unsigned int argcnt = 12;
> +
> +  vec_alloc (args, argcnt);
> +  args->quick_push (device);
> +  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);
> +  switch (start_ix)
>      {
> -      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);
> +    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;
> +
> +       /* 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;
> +
> +       /* Default values for t_async.  */
> +       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));
> +
> +       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 (; 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++;
> +                 }
> +             }
> +
> +           /* 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)));
> +         }
> +      }
> +      break;
> +    default:
> +      gcc_unreachable ();
>      }
> -  else
> -    g = gimple_build_call (builtin_decl_explicit (start_ix), 6,
> -                          device, openmp_target, t1, t2, t3, t4);
> +
> +  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 && region->exit)
> +  if (data_region
> +      && region->exit)
>      {
>        gsi = gsi_last_bb (region->exit);
>        g = gsi_stmt (gsi);
> @@ -8631,6 +9284,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;
> @@ -8700,7 +9355,9 @@ build_omp_regions_1 (basic_block bb, struct omp_region *parent,
>           ;
>         }
>        else if (code == GIMPLE_OMP_TARGET
> -              && gimple_omp_target_kind (stmt) == GF_OMP_TARGET_KIND_UPDATE)
> +              && (gimple_omp_target_kind (stmt) == GF_OMP_TARGET_KIND_UPDATE
> +                  || (gimple_omp_target_kind (stmt)
> +                      == GF_OMP_TARGET_KIND_OACC_UPDATE)))
>         new_omp_region (bb, code, parent);
>        else
>         {
> @@ -8816,8 +9473,9 @@ public:
>    /* opt_pass methods: */
>    virtual bool gate (function *)
>      {
> -      return ((flag_openmp != 0 || flag_openmp_simd != 0
> -              || flag_cilkplus != 0) && !seen_error ());
> +      return ((flag_cilkplus != 0 || flag_openacc != 0 || flag_openmp != 0
> +              || flag_openmp_simd != 0)
> +             && !seen_error ());
>      }
>
>    virtual unsigned int execute (function *) { return execute_expand_omp (); }
> @@ -8834,6 +9492,397 @@ make_pass_expand_omp (gcc::context *ctxt)
>
>  /* Routines to lower OpenMP directives into OMP-GIMPLE.  */
>
> +/* Helper function to preform, potentially COMPLEX_TYPE, operation and
> +   convert it to gimple.  */
> +static void
> +omp_gimple_assign_with_ops (tree_code op, tree dest, tree src, gimple_seq *seq)
> +{
> +  gimple stmt;
> +
> +  if (TREE_CODE (TREE_TYPE (dest)) != COMPLEX_TYPE)
> +    {
> +      stmt = gimple_build_assign_with_ops (op, dest, dest, src);
> +      gimple_seq_add_stmt (seq, stmt);
> +      return;
> +    }
> +
> +  tree t = create_tmp_var (TREE_TYPE (TREE_TYPE (dest)), NULL);
> +  tree rdest = fold_build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (dest)), dest);
> +  gimplify_assign (t, rdest, seq);
> +  rdest = t;
> +
> +  t = create_tmp_var (TREE_TYPE (TREE_TYPE (dest)), NULL);
> +  tree idest = fold_build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (dest)), dest);
> +  gimplify_assign (t, idest, seq);
> +  idest = t;
> +
> +  t = create_tmp_var (TREE_TYPE (TREE_TYPE (src)), NULL);
> +  tree rsrc = fold_build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (src)), src);
> +  gimplify_assign (t, rsrc, seq);
> +  rsrc = t;
> +
> +  t = create_tmp_var (TREE_TYPE (TREE_TYPE (src)), NULL);
> +  tree isrc = fold_build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (src)), src);
> +  gimplify_assign (t, isrc, seq);
> +  isrc = t;
> +
> +  tree r = create_tmp_var (TREE_TYPE (TREE_TYPE (dest)), NULL);
> +  tree i = create_tmp_var (TREE_TYPE (TREE_TYPE (dest)), NULL);
> +  tree result;
> +
> +  gcc_assert (op == PLUS_EXPR || op == MULT_EXPR);
> +
> +  if (op == PLUS_EXPR)
> +    {
> +      stmt = gimple_build_assign_with_ops (op, r, rdest, rsrc);
> +      gimple_seq_add_stmt (seq, stmt);
> +
> +      stmt = gimple_build_assign_with_ops (op, i, idest, isrc);
> +      gimple_seq_add_stmt (seq, stmt);
> +    }
> +  else if (op == MULT_EXPR)
> +    {
> +      /* Let x = a + ib = dest, y = c + id = src.
> +        x * y = (ac - bd) + i(ad + bc)  */
> +      tree ac = create_tmp_var (TREE_TYPE (TREE_TYPE (dest)), NULL);
> +      tree bd = create_tmp_var (TREE_TYPE (TREE_TYPE (dest)), NULL);
> +      tree ad = create_tmp_var (TREE_TYPE (TREE_TYPE (dest)), NULL);
> +      tree bc = create_tmp_var (TREE_TYPE (TREE_TYPE (dest)), NULL);
> +
> +      stmt = gimple_build_assign_with_ops (MULT_EXPR, ac, rdest, rsrc);
> +      gimple_seq_add_stmt (seq, stmt);
> +
> +      stmt = gimple_build_assign_with_ops (MULT_EXPR, bd, idest, isrc);
> +      gimple_seq_add_stmt (seq, stmt);
> +
> +      stmt = gimple_build_assign_with_ops (MINUS_EXPR, r, ac, bd);
> +      gimple_seq_add_stmt (seq, stmt);
> +
> +      stmt = gimple_build_assign_with_ops (MULT_EXPR, ad, rdest, isrc);
> +      gimple_seq_add_stmt (seq, stmt);
> +
> +      stmt = gimple_build_assign_with_ops (MULT_EXPR, bd, idest, rsrc);
> +      gimple_seq_add_stmt (seq, stmt);
> +
> +      stmt = gimple_build_assign_with_ops (PLUS_EXPR, i, ad, bc);
> +      gimple_seq_add_stmt (seq, stmt);
> +    }
> +
> +  result = build2 (COMPLEX_EXPR, TREE_TYPE (dest), r, i);
> +  gimplify_assign (dest, result, seq);
> +}
> +
> +/* Helper function to initialize local data for the reduction arrays.
> +   The reduction arrays need to be placed inside the calling function
> +   for accelerators, or else the host won't be able to preform the final
> +   reduction.  */
> +
> +static void
> +initialize_reduction_data (tree clauses, tree nthreads, gimple_seq *stmt_seqp,
> +                          omp_context *ctx)
> +{
> +  gcc_assert (is_gimple_omp_oacc_specifically (ctx->stmt));
> +
> +  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 GIMPLE_OACC_PARALLEL ctx.  */
> +  if (gimple_code (ctx->stmt) == GIMPLE_OACC_PARALLEL)
> +    octx = ctx;
> +  else
> +    octx = ctx->outer;
> +  gcc_assert (gimple_code (octx->stmt) == GIMPLE_OACC_PARALLEL);
> +
> +  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);
> +
> +  /* Find the last outer clause.  */
> +  for (; oc && OMP_CLAUSE_CHAIN (oc); oc = OMP_CLAUSE_CHAIN (oc))
> +    ;
> +
> +  /* Allocate arrays for each reduction variable.  */
> +  for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
> +    {
> +      if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION)
> +       continue;
> +
> +      tree var = OMP_CLAUSE_DECL (c);
> +      tree type = get_base_type (var);
> +      tree array = lookup_reduction (omp_get_id (var), ctx);
> +      tree size, call;
> +
> +      /* Calculate size of the reduction array.  */
> +      t = create_tmp_var (TREE_TYPE (nthreads), NULL);
> +      stmt = gimple_build_assign_with_ops (MULT_EXPR, t, nthreads,
> +                        fold_convert (TREE_TYPE (nthreads),
> +                                      TYPE_SIZE_UNIT (type)));
> +      gimple_seq_add_stmt (stmt_seqp, stmt);
> +
> +      size = create_tmp_var (sizetype, NULL);
> +      gimplify_assign (size, fold_build1 (NOP_EXPR, sizetype, t), stmt_seqp);
> +
> +      /* Now allocate memory for it.  */
> +      call = unshare_expr (builtin_decl_explicit (BUILT_IN_ALLOCA));
> +      stmt = gimple_build_call (call, 1, size);
> +      gimple_call_set_lhs (stmt, array);
> +      gimple_seq_add_stmt (stmt_seqp, stmt);
> +
> +      /* Map this array into the accelerator.  */
> +
> +      /* Add the reduction array to the list of clauses.  */
> +      tree x = array;
> +      t = build_omp_clause (gimple_location (ctx->stmt), OMP_CLAUSE_MAP);
> +      OMP_CLAUSE_MAP_KIND (t) = OMP_CLAUSE_MAP_FORCE_FROM;
> +      OMP_CLAUSE_DECL (t) = x;
> +      OMP_CLAUSE_CHAIN (t) = NULL;
> +      if (oc)
> +       OMP_CLAUSE_CHAIN (oc) = t;
> +      else
> +       gimple_omp_set_clauses (octx->stmt, t);
> +      OMP_CLAUSE_SIZE (t) = size;
> +      oc = t;
> +    }
> +}
> +
> +/* Helper function to process the array of partial reductions.  Nthreads
> +   indicates the number of threads.  Unfortunately, GOACC_GET_NUM_THREADS
> +   cannot be used here, because nthreads on the host may be different than
> +   on the accelerator. */
> +
> +static void
> +finalize_reduction_data (tree clauses, tree nthreads, gimple_seq *stmt_seqp,
> +                        omp_context *ctx)
> +{
> +  gcc_assert (is_gimple_omp_oacc_specifically (ctx->stmt));
> +
> +  tree c, x, var, array, loop_header, loop_body, loop_exit, type;
> +  gimple stmt;
> +
> +  /* Create for loop.
> +
> +     let var = the original reduction variable
> +     let array = reduction variable array
> +
> +     for (i = 0; i < nthreads; i++)
> +       var op= array[i]
> + */
> +
> +  loop_header = create_artificial_label (UNKNOWN_LOCATION);
> +  loop_body = create_artificial_label (UNKNOWN_LOCATION);
> +  loop_exit = create_artificial_label (UNKNOWN_LOCATION);
> +
> +  /* Create and initialize an index variable.  */
> +  tree ix = create_tmp_var (sizetype, NULL);
> +  gimplify_assign (ix, fold_build1 (NOP_EXPR, sizetype, integer_zero_node),
> +                  stmt_seqp);
> +
> +  /* Insert the loop header label here.  */
> +  gimple_seq_add_stmt (stmt_seqp, gimple_build_label (loop_header));
> +
> +  /* Exit loop if ix >= nthreads.  */
> +  x = create_tmp_var (sizetype, NULL);
> +  gimplify_assign (x, fold_build1 (NOP_EXPR, sizetype, nthreads), stmt_seqp);
> +  stmt = gimple_build_cond (GE_EXPR, ix, x, loop_exit, loop_body);
> +  gimple_seq_add_stmt (stmt_seqp, stmt);
> +
> +  /* Insert the loop body label here.  */
> +  gimple_seq_add_stmt (stmt_seqp, gimple_build_label (loop_body));
> +
> +  /* Collapse each reduction array, one element at a time.  */
> +  for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
> +    {
> +      if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION)
> +       continue;
> +
> +      tree_code reduction_code = OMP_CLAUSE_REDUCTION_CODE (c);
> +
> +      /* reduction(-:var) sums up the partial results, so it acts
> +        identically to reduction(+:var).  */
> +      if (reduction_code == MINUS_EXPR)
> +        reduction_code = PLUS_EXPR;
> +
> +      /* Set up reduction variable var.  */
> +      var = OMP_CLAUSE_DECL (c);
> +      type = get_base_type (var);
> +      array = lookup_reduction (omp_get_id (OMP_CLAUSE_DECL (c)), ctx);
> +
> +      /* Calculate the array offset.  */
> +      tree offset = create_tmp_var (sizetype, NULL);
> +      gimplify_assign (offset, TYPE_SIZE_UNIT (type), stmt_seqp);
> +      stmt = gimple_build_assign_with_ops (MULT_EXPR, offset, offset, ix);
> +      gimple_seq_add_stmt (stmt_seqp, stmt);
> +
> +      tree ptr = create_tmp_var (TREE_TYPE (array), NULL);
> +      stmt = gimple_build_assign_with_ops (POINTER_PLUS_EXPR, ptr, array,
> +                                          offset);
> +      gimple_seq_add_stmt (stmt_seqp, stmt);
> +
> +      /* Extract array[ix] into mem.  */
> +      tree mem = create_tmp_var (type, NULL);
> +      gimplify_assign (mem, build_simple_mem_ref (ptr), stmt_seqp);
> +
> +      /* Find the original reduction variable.  */
> +      if (is_reference (var))
> +       var = build_simple_mem_ref (var);
> +
> +      tree t = create_tmp_var (type, NULL);
> +
> +      x = lang_hooks.decls.omp_clause_assign_op (c, t, var);
> +      gimplify_and_add (unshare_expr(x), stmt_seqp);
> +
> +      /* var = var op mem */
> +      switch (OMP_CLAUSE_REDUCTION_CODE (c))
> +       {
> +       case TRUTH_ANDIF_EXPR:
> +       case TRUTH_ORIF_EXPR:
> +         t = fold_build2 (OMP_CLAUSE_REDUCTION_CODE (c), integer_type_node,
> +                          t, mem);
> +         gimplify_and_add (t, stmt_seqp);
> +         break;
> +       default:
> +         /* The lhs isn't a gimple_reg when var is COMPLEX_TYPE.  */
> +         omp_gimple_assign_with_ops (OMP_CLAUSE_REDUCTION_CODE (c),
> +                                     t, mem, stmt_seqp);
> +       }
> +
> +      t = fold_build1 (NOP_EXPR, TREE_TYPE (var), t);
> +      x = lang_hooks.decls.omp_clause_assign_op (c, var, t);
> +      gimplify_and_add (unshare_expr(x), stmt_seqp);
> +    }
> +
> +  /* Increment the induction variable.  */
> +  tree one = fold_build1 (NOP_EXPR, sizetype, integer_one_node);
> +  stmt = gimple_build_assign_with_ops (PLUS_EXPR, ix, ix, one);
> +  gimple_seq_add_stmt (stmt_seqp, stmt);
> +
> +  /* Go back to the top of the loop.  */
> +  gimple_seq_add_stmt (stmt_seqp, gimple_build_goto (loop_header));
> +
> +  /* Place the loop exit label here.  */
> +  gimple_seq_add_stmt (stmt_seqp, gimple_build_label (loop_exit));
> +}
> +
> +/* Scan through all of the gimple stmts searching for an OMP_FOR_EXPR, and
> +   scan that for reductions.  */
> +
> +static void
> +process_reduction_data (gimple_seq *body, gimple_seq *in_stmt_seqp,
> +                       gimple_seq *out_stmt_seqp, omp_context *ctx)
> +{
> +  gcc_assert (is_gimple_omp_oacc_specifically (ctx->stmt));
> +
> +  gimple_stmt_iterator gsi;
> +  gimple_seq inner = NULL;
> +  gimple stmt;
> +
> +  /* A collapse clause may have inserted a new bind block.  */
> +  gsi = gsi_start (*body);
> +  while (!gsi_end_p (gsi))
> +    {
> +      stmt = gsi_stmt (gsi);
> +      if (gimple_code (stmt) == GIMPLE_BIND)
> +       {
> +         inner = gimple_bind_body (stmt);
> +         body = &inner;
> +         gsi = gsi_start (*body);
> +       }
> +      else if (gimple_code (stmt) == GIMPLE_OMP_FOR)
> +       break;
> +      else
> +       gsi_next (&gsi);
> +    }
> +
> +  for (gsi = gsi_start (*body); !gsi_end_p (gsi); gsi_next (&gsi))
> +    {
> +      tree clauses, nthreads, t, c, acc_device, acc_device_host, call,
> +       enter, exit;
> +      bool reduction_found = false;
> +
> +      stmt = gsi_stmt (gsi);
> +
> +      switch (gimple_code (stmt))
> +       {
> +       case GIMPLE_OMP_FOR:
> +         clauses = gimple_omp_for_clauses (stmt);
> +
> +         /* Search for a reduction clause.  */
> +         for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
> +           if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)
> +             {
> +               reduction_found = true;
> +               break;
> +             }
> +
> +         if (!reduction_found)
> +           break;
> +
> +         ctx = maybe_lookup_ctx (stmt);
> +         t = NULL_TREE;
> +
> +         /* Extract the number of threads.  */
> +         nthreads = create_tmp_var (sizetype, NULL);
> +         t = oacc_max_threads (ctx);
> +         gimplify_assign (nthreads, t, in_stmt_seqp);
> +
> +         /* Determine if this is kernel will be executed on the host.  */
> +         call = builtin_decl_explicit (BUILT_IN_ACC_GET_DEVICE_TYPE);
> +         acc_device = create_tmp_var (integer_type_node, ".acc_device_type");
> +         stmt = gimple_build_call (call, 0);
> +         gimple_call_set_lhs (stmt, acc_device);
> +         gimple_seq_add_stmt (in_stmt_seqp, stmt);
> +
> +         /* Set nthreads = 1 for ACC_DEVICE_TYPE=host.  */
> +         acc_device_host = create_tmp_var (integer_type_node,
> +                                           ".acc_device_host");
> +         gimplify_assign (acc_device_host, build_int_cst (integer_type_node,
> +                                                          2),
> +                          in_stmt_seqp);
> +
> +         enter = create_artificial_label (UNKNOWN_LOCATION);
> +         exit = create_artificial_label (UNKNOWN_LOCATION);
> +
> +         stmt = gimple_build_cond (EQ_EXPR, acc_device, acc_device_host,
> +                                   enter, exit);
> +         gimple_seq_add_stmt (in_stmt_seqp, stmt);
> +         gimple_seq_add_stmt (in_stmt_seqp, gimple_build_label (enter));
> +         gimplify_assign (nthreads, fold_build1 (NOP_EXPR, sizetype,
> +                                                 integer_one_node),
> +                          in_stmt_seqp);
> +         gimple_seq_add_stmt (in_stmt_seqp, gimple_build_label (exit));
> +
> +         /* Also, set nthreads = 1 for ACC_DEVICE_TYPE=host_nonshm.  */
> +         gimplify_assign (acc_device_host, build_int_cst (integer_type_node,
> +                                                          3),
> +                          in_stmt_seqp);
> +
> +         enter = create_artificial_label (UNKNOWN_LOCATION);
> +         exit = create_artificial_label (UNKNOWN_LOCATION);
> +
> +         stmt = gimple_build_cond (EQ_EXPR, acc_device, acc_device_host,
> +                                   enter, exit);
> +         gimple_seq_add_stmt (in_stmt_seqp, stmt);
> +         gimple_seq_add_stmt (in_stmt_seqp, gimple_build_label (enter));
> +         gimplify_assign (nthreads, fold_build1 (NOP_EXPR, sizetype,
> +                                                 integer_one_node),
> +                          in_stmt_seqp);
> +         gimple_seq_add_stmt (in_stmt_seqp, gimple_build_label (exit));
> +
> +         initialize_reduction_data (clauses, nthreads, in_stmt_seqp, ctx);
> +         finalize_reduction_data (clauses, nthreads, out_stmt_seqp, ctx);
> +         break;
> +       default:
> +         // Scan for other directives which support reduction here.
> +         break;
> +       }
> +    }
> +}
> +
>  /* 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
> @@ -9425,6 +10474,8 @@ lower_omp_for (gimple_stmt_iterator *gsi_p, omp_context *ctx)
>
>    if (gimple_omp_for_combined_into_p (stmt))
>      {
> +      gcc_assert (gimple_omp_for_kind (stmt) != GF_OMP_FOR_KIND_OACC_LOOP);
> +
>        extract_omp_for_data (stmt, &fd, NULL);
>        fdp = &fd;
>
> @@ -9614,6 +10665,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 (!is_gimple_omp_oacc_specifically (ctx->stmt));
> +
>    struct function *child_cfun;
>    tree child_fn, t, c, src, dst, f, sf, arg, sarg, decl;
>    tree record_type, srecord_type, bind, list;
> @@ -10023,7 +11076,7 @@ lower_omp_taskreg (gimple_stmt_iterator *gsi_p, omp_context *ctx)
>      }
>  }
>
> -/* Lower the OpenMP target directive in the current statement
> +/* Lower the GIMPLE_OMP_TARGET in the current statement
>     in GSI_P.  CTX holds context information for the directive.  */
>
>  static void
> @@ -10032,24 +11085,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)
> +  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))
>        {
> @@ -10058,8 +11163,37 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
>        default:
>         break;
>        case OMP_CLAUSE_MAP:
> +#ifdef ENABLE_CHECKING
> +       /* First check what we're prepared to handle in the following.  */
> +       switch (OMP_CLAUSE_MAP_KIND (c))
> +         {
> +         case OMP_CLAUSE_MAP_ALLOC:
> +         case OMP_CLAUSE_MAP_TO:
> +         case OMP_CLAUSE_MAP_FROM:
> +         case OMP_CLAUSE_MAP_TOFROM:
> +         case OMP_CLAUSE_MAP_POINTER:
> +         case OMP_CLAUSE_MAP_TO_PSET:
> +           break;
> +         case OMP_CLAUSE_MAP_FORCE_ALLOC:
> +         case OMP_CLAUSE_MAP_FORCE_TO:
> +         case OMP_CLAUSE_MAP_FORCE_FROM:
> +         case OMP_CLAUSE_MAP_FORCE_TOFROM:
> +         case OMP_CLAUSE_MAP_FORCE_PRESENT:
> +         case OMP_CLAUSE_MAP_FORCE_DEALLOC:
> +         case OMP_CLAUSE_MAP_FORCE_DEVICEPTR:
> +           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 (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))
>           {
> @@ -10082,12 +11216,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);
> -           if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
> -               && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER
> +           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_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);
> @@ -10097,16 +11234,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)
> +  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.  */
> @@ -10130,14 +11267,25 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
>        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 tkind_type;
> +      int talign_shift;
> +      if (is_gimple_omp_oacc_specifically (stmt))
> +       {
> +         tkind_type = short_unsigned_type_node;
> +         talign_shift = 8;
> +       }
> +      else
> +       {
> +         tkind_type = unsigned_char_type_node;
> +         talign_shift = 3;
> +       }
>        TREE_VEC_ELT (t, 2)
> -       = create_tmp_var (build_array_type_nelts (unsigned_char_type_node,
> -                                                 map_cnt),
> +       = create_tmp_var (build_array_type_nelts (tkind_type, 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_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;
> @@ -10198,12 +11346,22 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
>               {
>                 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)
> +               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))
>                   {
> -                   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);
> @@ -10214,16 +11372,22 @@ 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);
> -                   if (OMP_CLAUSE_MAP_KIND (c) != OMP_CLAUSE_MAP_ALLOC
> -                       && OMP_CLAUSE_MAP_KIND (c) != OMP_CLAUSE_MAP_FROM)
> +                   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 ((OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_FROM
> -                        || OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_TOFROM)
> +                   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);
> @@ -10246,7 +11410,7 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
>             if (TREE_CODE (s) != INTEGER_CST)
>               TREE_STATIC (TREE_VEC_ELT (t, 1)) = 0;
>
> -           unsigned char tkind = 0;
> +           unsigned HOST_WIDE_INT tkind;
>             switch (OMP_CLAUSE_CODE (c))
>               {
>               case OMP_CLAUSE_MAP:
> @@ -10261,11 +11425,12 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
>               default:
>                 gcc_unreachable ();
>               }
> +           gcc_assert (tkind < (HOST_WIDE_INT_C (1U) << talign_shift));
>             talign = ceil_log2 (talign);
> -           tkind |= talign << 3;
> +           tkind |= talign << talign_shift;
> +           gcc_assert (tkind <= tree_to_uhwi (TYPE_MAX_VALUE (tkind_type)));
>             CONSTRUCTOR_APPEND_ELT (vkind, purpose,
> -                                   build_int_cst (unsigned_char_type_node,
> -                                                  tkind));
> +                                   build_int_cstu (tkind_type, tkind));
>             if (nc && nc != c)
>               c = nc;
>           }
> @@ -10303,7 +11468,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.  */
> @@ -10312,14 +11478,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)
> +  else if (data_region)
>      new_body = tgt_body;
> -  if (kind != GF_OMP_TARGET_KIND_UPDATE)
> +  if (offloaded || data_region)
>      {
>        gimple_seq_add_stmt (&new_body, gimple_build_omp_return (false));
>        gimple_omp_set_body (stmt, new_body);
> @@ -10329,9 +11495,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);
>  }
> @@ -10529,9 +11697,13 @@ 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 (is_gimple_omp_oacc_specifically (stmt))
> +       gcc_assert (!ctx->cancellable);
>        lower_omp_target (gsi_p, ctx);
>        break;
>      case GIMPLE_OMP_TEAMS:
> @@ -10620,8 +11792,8 @@ lower_omp (gimple_seq *body, omp_context *ctx)
>    gimple_stmt_iterator gsi;
>    for (gsi = gsi_start (*body); !gsi_end_p (gsi); gsi_next (&gsi))
>      lower_omp_1 (&gsi, ctx);
> -  /* During gimplification, we have not always invoked fold_stmt
> -     (gimplify.c:maybe_fold_stmt); call it now.  */
> +  /* During gimplification, we haven't folded statments inside offloading
> +     regions (gimplify.c:maybe_fold_stmt); do that now.  */
>    if (target_nesting_level)
>      for (gsi = gsi_start (*body); !gsi_end_p (gsi); gsi_next (&gsi))
>        fold_stmt (&gsi);
> @@ -10638,8 +11810,9 @@ execute_lower_omp (void)
>    omp_context *ctx;
>
>    /* This pass always runs, to provide PROP_gimple_lomp.
> -     But there is nothing to do unless -fopenmp is given.  */
> -  if (flag_openmp == 0 && flag_openmp_simd == 0 && flag_cilkplus == 0)
> +     But often, there is nothing to do.  */
> +  if (flag_cilkplus == 0 && flag_openacc == 0 && flag_openmp == 0
> +      && flag_openmp_simd == 0)
>      return 0;
>
>    all_contexts = splay_tree_new (splay_tree_compare_pointers, 0,
> @@ -10705,7 +11878,7 @@ make_pass_lower_omp (gcc::context *ctxt)
>    return new pass_lower_omp (ctxt);
>  }
>
> -/* The following is a utility to diagnose OpenMP structured block violations.
> +/* The following is a utility to diagnose structured block violations.
>     It is not part of the "omplower" pass, as that's invoked too late.  It
>     should be invoked by the respective front ends after gimplification.  */
>
> @@ -10718,9 +11891,38 @@ static bool
>  diagnose_sb_0 (gimple_stmt_iterator *gsi_p,
>                gimple branch_ctx, gimple label_ctx)
>  {
> +  gcc_assert (!branch_ctx || is_gimple_omp (branch_ctx));
> +  gcc_assert (!label_ctx || is_gimple_omp (label_ctx));
> +
>    if (label_ctx == branch_ctx)
>      return false;
>
> +  const char* kind = NULL;
> +
> +  if (flag_cilkplus)
> +    {
> +      if ((branch_ctx
> +          && gimple_code (branch_ctx) == GIMPLE_OMP_FOR
> +          && gimple_omp_for_kind (branch_ctx) == GF_OMP_FOR_KIND_CILKSIMD)
> +         || (label_ctx
> +             && gimple_code (label_ctx) == GIMPLE_OMP_FOR
> +             && gimple_omp_for_kind (label_ctx) == GF_OMP_FOR_KIND_CILKSIMD))
> +       kind = "Cilk Plus";
> +    }
> +  if (flag_openacc)
> +    {
> +      if ((branch_ctx && is_gimple_omp_oacc_specifically (branch_ctx))
> +         || (label_ctx && is_gimple_omp_oacc_specifically (label_ctx)))
> +       {
> +         gcc_assert (kind == NULL);
> +         kind = "OpenACC";
> +       }
> +    }
> +  if (kind == NULL)
> +    {
> +      gcc_assert (flag_openmp);
> +      kind = "OpenMP";
> +    }
>
>    /*
>       Previously we kept track of the label's entire context in diagnose_sb_[12]
> @@ -10753,45 +11955,25 @@ diagnose_sb_0 (gimple_stmt_iterator *gsi_p,
>      }
>
>    if (exit_p)
> -    error ("invalid exit from OpenMP structured block");
> +    error ("invalid exit from %s structured block", kind);
>    else
> -    error ("invalid entry to OpenMP structured block");
> +    error ("invalid entry to %s structured block", kind);
>  #endif
>
> -  bool cilkplus_block = false;
> -  if (flag_cilkplus)
> -    {
> -      if ((branch_ctx
> -          && gimple_code (branch_ctx) == GIMPLE_OMP_FOR
> -          && gimple_omp_for_kind (branch_ctx) == GF_OMP_FOR_KIND_CILKSIMD)
> -         || (label_ctx
> -             && gimple_code (label_ctx) == GIMPLE_OMP_FOR
> -             && gimple_omp_for_kind (label_ctx) == GF_OMP_FOR_KIND_CILKSIMD))
> -       cilkplus_block = true;
> -    }
> -
>    /* If it's obvious we have an invalid entry, be specific about the error.  */
>    if (branch_ctx == NULL)
> -    {
> -      if (cilkplus_block)
> -       error ("invalid entry to Cilk Plus structured block");
> -      else
> -       error ("invalid entry to OpenMP structured block");
> -    }
> +    error ("invalid entry to %s structured block", kind);
>    else
>      {
>        /* Otherwise, be vague and lazy, but efficient.  */
> -      if (cilkplus_block)
> -       error ("invalid branch to/from a Cilk Plus structured block");
> -      else
> -       error ("invalid branch to/from an OpenMP structured block");
> +      error ("invalid branch to/from %s structured block", kind);
>      }
>
>    gsi_replace (gsi_p, gimple_build_nop (), false);
>    return true;
>  }
>
> -/* Pass 1: Create a minimal tree of OpenMP structured blocks, and record
> +/* Pass 1: Create a minimal tree of structured blocks, and record
>     where each label is found.  */
>
>  static tree
> @@ -10804,10 +11986,12 @@ diagnose_sb_1 (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
>
>    *handled_ops_p = true;
>
> - switch (gimple_code (stmt))
> +  switch (gimple_code (stmt))
>      {
>      WALK_SUBSTMTS;
>
> +    case GIMPLE_OACC_KERNELS:
> +    case GIMPLE_OACC_PARALLEL:
>      case GIMPLE_OMP_PARALLEL:
>      case GIMPLE_OMP_TASK:
>      case GIMPLE_OMP_SECTIONS:
> @@ -10866,6 +12050,8 @@ 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:
> @@ -10948,8 +12134,8 @@ diagnose_sb_2 (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
>    return NULL_TREE;
>  }
>
> -/* Called from tree-cfg.c::make_edges to create cfg edges for all GIMPLE_OMP
> -   codes.  */
> +/* Called from tree-cfg.c::make_edges to create cfg edges for all relevant
> +   GIMPLE_* codes.  */
>  bool
>  make_gimple_omp_edges (basic_block bb, struct omp_region **region,
>                        int *region_idx)
> @@ -10961,6 +12147,8 @@ 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:
> @@ -10978,7 +12166,10 @@ make_gimple_omp_edges (basic_block bb, struct omp_region **region,
>      case GIMPLE_OMP_TARGET:
>        cur_region = new_omp_region (bb, code, cur_region);
>        fallthru = true;
> -      if (gimple_omp_target_kind (last) == GF_OMP_TARGET_KIND_UPDATE)
> +      if (gimple_omp_target_kind (last) == GF_OMP_TARGET_KIND_UPDATE
> +         || (gimple_omp_target_kind (last)
> +             == GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA)
> +         || gimple_omp_target_kind (last) == GF_OMP_TARGET_KIND_OACC_UPDATE)
>         cur_region = cur_region->outer;
>        break;
>
> @@ -11116,7 +12307,10 @@ public:
>    {}
>
>    /* opt_pass methods: */
> -  virtual bool gate (function *) { return flag_openmp || flag_cilkplus; }
> +  virtual bool gate (function *)
> +  {
> +    return flag_cilkplus || flag_openacc || flag_openmp;
> +  }
>    virtual unsigned int execute (function *)
>      {
>        return diagnose_omp_structured_block_errors ();
> @@ -12360,4 +13554,89 @@ make_pass_omp_simd_clone (gcc::context *ctxt)
>    return new pass_omp_simd_clone (ctxt);
>  }
>
> +/* Helper function for omp_finish_file routine.
> +   Takes decls from V_DECLS and adds their addresses and sizes to
> +   constructor-vector V_CTOR.  It will be later used as DECL_INIT for decl
> +   representing a global symbol for OpenMP descriptor.  */
> +static void
> +add_decls_addresses_to_decl_constructor (vec<tree, va_gc> *v_decls,
> +                                        vec<constructor_elt, va_gc> *v_ctor)
> +{
> +  unsigned len = vec_safe_length (v_decls);
> +  for (unsigned i = 0; i < len; i++)
> +    {
> +      tree it = (*v_decls)[i];
> +      bool is_function = TREE_CODE (it) != VAR_DECL;
> +
> +      CONSTRUCTOR_APPEND_ELT (v_ctor, NULL_TREE, build_fold_addr_expr (it));
> +      if (!is_function)
> +       CONSTRUCTOR_APPEND_ELT (v_ctor, NULL_TREE,
> +                               fold_convert (const_ptr_type_node,
> +                                             DECL_SIZE (it)));
> +    }
> +}
> +
> +/* Create new symbol containing (address, size) pairs for omp-marked
> +   functions and global variables.  */
> +void
> +omp_finish_file (void)
> +{
> +  const char *funcs_section_name = OFFLOAD_FUNC_TABLE_SECTION_NAME;
> +  const char *vars_section_name = OFFLOAD_VAR_TABLE_SECTION_NAME;
> +
> +  unsigned num_funcs = vec_safe_length (offload_funcs);
> +  unsigned num_vars = vec_safe_length (offload_vars);
> +
> +  if (num_funcs == 0 && num_vars == 0)
> +    return;
> +
> +  if (targetm_common.have_named_sections)
> +    {
> +      vec<constructor_elt, va_gc> *v_f, *v_v;
> +      vec_alloc (v_f, num_funcs);
> +      vec_alloc (v_v, num_vars * 2);
> +
> +      add_decls_addresses_to_decl_constructor (offload_funcs, v_f);
> +      add_decls_addresses_to_decl_constructor (offload_vars, v_v);
> +
> +      tree vars_decl_type = build_array_type_nelts (pointer_sized_int_node,
> +                                                   num_vars * 2);
> +      tree funcs_decl_type = build_array_type_nelts (pointer_sized_int_node,
> +                                                    num_funcs);
> +      TYPE_ALIGN (vars_decl_type) = TYPE_ALIGN (pointer_sized_int_node);
> +      TYPE_ALIGN (funcs_decl_type) = TYPE_ALIGN (pointer_sized_int_node);
> +      tree ctor_v = build_constructor (vars_decl_type, v_v);
> +      tree ctor_f = build_constructor (funcs_decl_type, v_f);
> +      TREE_CONSTANT (ctor_v) = TREE_CONSTANT (ctor_f) = 1;
> +      TREE_STATIC (ctor_v) = TREE_STATIC (ctor_f) = 1;
> +      tree funcs_decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
> +                                   get_identifier (".omp_func_table"),
> +                                   funcs_decl_type);
> +      tree vars_decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
> +                                  get_identifier (".omp_var_table"),
> +                                  vars_decl_type);
> +      TREE_STATIC (funcs_decl) = TREE_STATIC (vars_decl) = 1;
> +      DECL_INITIAL (funcs_decl) = ctor_f;
> +      DECL_INITIAL (vars_decl) = ctor_v;
> +      set_decl_section_name (funcs_decl, funcs_section_name);
> +      set_decl_section_name (vars_decl, vars_section_name);
> +
> +      varpool_node::finalize_decl (funcs_decl);
> +      varpool_node::finalize_decl (vars_decl);
> +   }
> +  else
> +    {
> +      for (unsigned i = 0; i < num_funcs; i++)
> +       {
> +         tree it = (*offload_funcs)[i];
> +         targetm.record_offload_symbol (it);
> +       }
> +      for (unsigned i = 0; i < num_vars; i++)
> +       {
> +         tree it = (*offload_vars)[i];
> +         targetm.record_offload_symbol (it);
> +       }
> +    }
> +}
> +
>  #include "gt-omp-low.h"
> diff --git gcc/omp-low.h gcc/omp-low.h
> index d80c2d6..ac587d0 100644
> --- gcc/omp-low.h
> +++ gcc/omp-low.h
> @@ -27,5 +27,9 @@ extern void omp_expand_local (basic_block);
>  extern void free_omp_regions (void);
>  extern tree omp_reduction_init (tree, tree);
>  extern bool make_gimple_omp_edges (basic_block, struct omp_region **, int *);
> +extern void omp_finish_file (void);
> +
> +extern GTY(()) vec<tree, va_gc> *offload_funcs;
> +extern GTY(()) vec<tree, va_gc> *offload_vars;
>
>  #endif /* GCC_OMP_LOW_H */
> diff --git gcc/passes.c gcc/passes.c
> index f9d15b8..b3f9d97 100644
> --- gcc/passes.c
> +++ gcc/passes.c
> @@ -2306,7 +2306,7 @@ ipa_write_summaries_1 (lto_symtab_encoder_t encoder)
>  /* Write out summaries for all the nodes in the callgraph.  */
>
>  void
> -ipa_write_summaries (void)
> +ipa_write_summaries (bool is_omp)
>  {
>    lto_symtab_encoder_t encoder;
>    int i, order_pos;
> @@ -2314,9 +2314,11 @@ ipa_write_summaries (void)
>    struct cgraph_node *node;
>    struct cgraph_node **order;
>
> -  if (!flag_generate_lto || seen_error ())
> +  if (!(flag_generate_lto || flag_openacc || flag_openmp) || seen_error () )
>      return;
>
> +  select_what_to_dump (is_omp);
> +
>    encoder = lto_symtab_encoder_new (false);
>
>    /* Create the callgraph set in the same order used in
> diff --git gcc/target.def gcc/target.def
> index 14e19e8..45ed1d9 100644
> --- gcc/target.def
> +++ gcc/target.def
> @@ -1760,6 +1760,14 @@ HOOK_VECTOR_END (vectorize)
>  #undef HOOK_PREFIX
>  #define HOOK_PREFIX "TARGET_"
>
> +DEFHOOK
> +(record_offload_symbol,
> + "Used when offloaded functions are seen in the compilation unit and no named\n\
> +sections are available.  It is called once for each symbol that must be\n\
> +recorded in the offload function and variable table.",
> + void, (tree),
> + hook_void_tree)
> +
>  /* Allow target specific overriding of option settings after options have
>    been changed by an attribute or pragma or when it is reset at the
>    end of the code affected by an attribute or pragma.  */
> diff --git gcc/testsuite/g++.dg/gomp/block-1.C gcc/testsuite/g++.dg/gomp/block-1.C
> index d2b8664..f4badaf 100644
> --- gcc/testsuite/g++.dg/gomp/block-1.C
> +++ gcc/testsuite/g++.dg/gomp/block-1.C
> @@ -21,5 +21,5 @@ void foo()
>      }
>  }
>
> -// { dg-message "error: invalid branch to/from an OpenMP structured block" "" { target *-*-* } 7 }
> +// { dg-message "error: invalid branch to/from OpenMP structured block" "" { target *-*-* } 7 }
>  // { dg-message "error: invalid entry to OpenMP structured block" "" { target *-*-* } 9 }
> diff --git gcc/testsuite/g++.dg/gomp/block-2.C gcc/testsuite/g++.dg/gomp/block-2.C
> index 17d98d8..02f5f83d 100644
> --- gcc/testsuite/g++.dg/gomp/block-2.C
> +++ gcc/testsuite/g++.dg/gomp/block-2.C
> @@ -31,5 +31,5 @@ void foo()
>      continue;
>  }
>
> -// { dg-message "error: invalid branch to/from an OpenMP structured block" "" { target *-*-* } 14 }
> +// { dg-message "error: invalid branch to/from OpenMP structured block" "" { target *-*-* } 14 }
>  // { dg-message "error: invalid entry to OpenMP structured block" "" { target *-*-* } 16 }
> diff --git gcc/testsuite/g++.dg/gomp/block-3.C gcc/testsuite/g++.dg/gomp/block-3.C
> index ff28175..bb54166 100644
> --- gcc/testsuite/g++.dg/gomp/block-3.C
> +++ gcc/testsuite/g++.dg/gomp/block-3.C
> @@ -58,6 +58,6 @@ void foo()
>      }
>  }
>
> -// { dg-message "error: invalid branch to/from an OpenMP structured block" "" { target *-*-* } 21 }
> -// { dg-message "error: invalid branch to/from an OpenMP structured block" "" { target *-*-* } 26 }
> +// { dg-message "error: invalid branch to/from OpenMP structured block" "" { target *-*-* } 21 }
> +// { dg-message "error: invalid branch to/from OpenMP structured block" "" { target *-*-* } 26 }
>  // { dg-message "error: invalid entry to OpenMP structured block" "" { target *-*-* } 30 }
> diff --git gcc/testsuite/g++.dg/gomp/block-5.C gcc/testsuite/g++.dg/gomp/block-5.C
> index 391f8b6..0aa23a4 100644
> --- gcc/testsuite/g++.dg/gomp/block-5.C
> +++ gcc/testsuite/g++.dg/gomp/block-5.C
> @@ -14,4 +14,4 @@ void foo()
>      }
>  }
>
> -// { dg-message "error: invalid branch to/from an OpenMP structured block" "" { target *-*-* } 7 }
> +// { dg-message "error: invalid branch to/from OpenMP structured block" "" { target *-*-* } 7 }
> diff --git gcc/testsuite/g++.dg/gomp/target-1.C gcc/testsuite/g++.dg/gomp/target-1.C
> index b6ed4f8..767661f 100644
> --- gcc/testsuite/g++.dg/gomp/target-1.C
> +++ gcc/testsuite/g++.dg/gomp/target-1.C
> @@ -28,5 +28,5 @@ foo (int x)
>    }
>  }
>
> -// { dg-error "invalid branch to/from an OpenMP structured block" "" { target *-*-* } 8 }
> +// { dg-error "invalid branch to/from OpenMP structured block" "" { target *-*-* } 8 }
>  // { dg-error "invalid entry to OpenMP structured block" "" { target *-*-* } 10 }
> diff --git gcc/testsuite/g++.dg/gomp/target-2.C gcc/testsuite/g++.dg/gomp/target-2.C
> index 6a14f53..5a40dd4 100644
> --- gcc/testsuite/g++.dg/gomp/target-2.C
> +++ gcc/testsuite/g++.dg/gomp/target-2.C
> @@ -28,5 +28,5 @@ foo (int x, int y)
>    }
>  }
>
> -// { dg-error "invalid branch to/from an OpenMP structured block" "" { target *-*-* } 8 }
> +// { dg-error "invalid branch to/from OpenMP structured block" "" { target *-*-* } 8 }
>  // { dg-error "invalid entry to OpenMP structured block" "" { target *-*-* } 10 }
> diff --git gcc/testsuite/g++.dg/gomp/taskgroup-1.C gcc/testsuite/g++.dg/gomp/taskgroup-1.C
> index dcab0bb..a06edf1 100644
> --- gcc/testsuite/g++.dg/gomp/taskgroup-1.C
> +++ gcc/testsuite/g++.dg/gomp/taskgroup-1.C
> @@ -28,5 +28,5 @@ foo (int x)
>    }
>  }
>
> -// { dg-error "invalid branch to/from an OpenMP structured block" "" { target *-*-* } 8 }
> +// { dg-error "invalid branch to/from OpenMP structured block" "" { target *-*-* } 8 }
>  // { dg-error "invalid entry to OpenMP structured block" "" { target *-*-* } 10 }
> diff --git gcc/testsuite/g++.dg/gomp/teams-1.C gcc/testsuite/g++.dg/gomp/teams-1.C
> index ce40b55..05f1a7e 100644
> --- gcc/testsuite/g++.dg/gomp/teams-1.C
> +++ gcc/testsuite/g++.dg/gomp/teams-1.C
> @@ -60,7 +60,7 @@ bar (int x)
>    }
>  }
>
> -// { dg-error "invalid branch to/from an OpenMP structured block" "" { target *-*-* } 8 }
> +// { dg-error "invalid branch to/from OpenMP structured block" "" { target *-*-* } 8 }
>  // { dg-error "invalid entry to OpenMP structured block" "" { target *-*-* } 10 }
> -// { dg-error "invalid branch to/from an OpenMP structured block" "" { target *-*-* } 37 }
> +// { dg-error "invalid branch to/from OpenMP structured block" "" { target *-*-* } 37 }
>  // { dg-error "invalid entry to OpenMP structured block" "" { target *-*-* } 39 }
> diff --git gcc/testsuite/gcc.dg/cilk-plus/jump-openmp.c gcc/testsuite/gcc.dg/cilk-plus/jump-openmp.c
> index 95e6b2d..6adabf4 100644
> --- gcc/testsuite/gcc.dg/cilk-plus/jump-openmp.c
> +++ gcc/testsuite/gcc.dg/cilk-plus/jump-openmp.c
> @@ -11,7 +11,7 @@ void foo()
>      {
>        a[i] = b[i];
>        if (c == 5)
> -       return; /* { dg-error "invalid branch to/from a Cilk Plus structured block" } */
> +       return; /* { dg-error "invalid branch to/from Cilk Plus structured block" } */
>      }
>  }
>
> @@ -31,7 +31,7 @@ void baz()
>  {
>    bad1:
>    #pragma omp parallel
> -    goto bad1; /* { dg-error "invalid branch to/from an OpenMP structured block" } */
> +    goto bad1; /* { dg-error "invalid branch to/from OpenMP structured block" } */
>
>    goto bad2; /* { dg-error "invalid entry to OpenMP structured block" } */
>    #pragma omp parallel
> diff --git gcc/testsuite/gcc.dg/cilk-plus/jump.c gcc/testsuite/gcc.dg/cilk-plus/jump.c
> index 9ec3293..1ca886a 100644
> --- gcc/testsuite/gcc.dg/cilk-plus/jump.c
> +++ gcc/testsuite/gcc.dg/cilk-plus/jump.c
> @@ -10,7 +10,7 @@ void foo()
>      {
>        a[i] = b[i];
>        if (c == 5)
> -       return;  /* { dg-error "invalid branch to.from a Cilk" } */
> +       return; /* { dg-error "invalid branch to/from Cilk Plus structured block" } */
>      }
>  }
>
> @@ -23,5 +23,5 @@ void bar()
>        a[i] = b[i];
>      }
>    if (c == 6)
> -    goto lab; /* { dg-error "invalid entry to Cilk Plus" } */
> +    goto lab; /* { dg-error "invalid entry to Cilk Plus structured block" } */
>  }
> diff --git gcc/testsuite/gcc.dg/gomp/block-1.c gcc/testsuite/gcc.dg/gomp/block-1.c
> index dd7fe77..e67e6c3 100644
> --- gcc/testsuite/gcc.dg/gomp/block-1.c
> +++ gcc/testsuite/gcc.dg/gomp/block-1.c
> @@ -4,9 +4,9 @@ void foo()
>  {
>    bad1:
>    #pragma omp parallel
> -    goto bad1;                 // { dg-error "invalid branch" }
> +    goto bad1; // { dg-error "invalid branch to/from OpenMP structured block" }
>
> -  goto bad2;                   // { dg-error "invalid entry" }
> +  goto bad2; // { dg-error "invalid entry to OpenMP structured block" }
>    #pragma omp parallel
>      {
>        bad2: ;
> diff --git gcc/testsuite/gcc.dg/gomp/block-10.c gcc/testsuite/gcc.dg/gomp/block-10.c
> index 76ee397..69ae3c0 100644
> --- gcc/testsuite/gcc.dg/gomp/block-10.c
> +++ gcc/testsuite/gcc.dg/gomp/block-10.c
> @@ -3,28 +3,28 @@
>  void foo(int i)
>  {
>    int j;
> -  switch (i)                   // { dg-error "invalid entry" }
> +  switch (i) // { dg-error "invalid entry to OpenMP structured block" }
>    {
>    #pragma omp parallel
>      { case 0:; }
>    }
> -  switch (i)                   // { dg-error "invalid entry" }
> +  switch (i) // { dg-error "invalid entry to OpenMP structured block" }
>    {
>    #pragma omp for
>      for (j = 0; j < 10; ++ j)
>        { case 1:; }
>    }
> -  switch (i)                   // { dg-error "invalid entry" }
> +  switch (i) // { dg-error "invalid entry to OpenMP structured block" }
>    {
>    #pragma omp critical
>      { case 2:; }
>    }
> -  switch (i)                   // { dg-error "invalid entry" }
> +  switch (i) // { dg-error "invalid entry to OpenMP structured block" }
>    {
>    #pragma omp master
>      { case 3:; }
>    }
> -  switch (i)                   // { dg-error "invalid entry" }
> +  switch (i) // { dg-error "invalid entry to OpenMP structured block" }
>    {
>    #pragma omp sections
>      { case 4:;
> @@ -32,7 +32,7 @@ void foo(int i)
>         { case 5:; }
>      }
>    }
> -  switch (i)                   // { dg-error "invalid entry" }
> +  switch (i) // { dg-error "invalid entry to OpenMP structured block" }
>    {
>    #pragma omp ordered
>      { default:; }
> diff --git gcc/testsuite/gcc.dg/gomp/block-2.c gcc/testsuite/gcc.dg/gomp/block-2.c
> index 4c56add..5c01463 100644
> --- gcc/testsuite/gcc.dg/gomp/block-2.c
> +++ gcc/testsuite/gcc.dg/gomp/block-2.c
> @@ -11,9 +11,9 @@ void foo()
>    bad1:
>    #pragma omp for
>    for (i = 0; i < 10; ++i)
> -    goto bad1;                 // { dg-error "invalid branch" }
> +    goto bad1; // { dg-error "invalid branch to/from OpenMP structured block" }
>
> -  goto bad2;                   // { dg-error "invalid entry" }
> +  goto bad2; // { dg-error "invalid entry to OpenMP structured block" }
>    #pragma omp for
>    for (i = 0; i < 10; ++i)
>      {
> diff --git gcc/testsuite/gcc.dg/gomp/block-3.c gcc/testsuite/gcc.dg/gomp/block-3.c
> index b4530e9..0b21cb3 100644
> --- gcc/testsuite/gcc.dg/gomp/block-3.c
> +++ gcc/testsuite/gcc.dg/gomp/block-3.c
> @@ -9,7 +9,7 @@ void foo()
>      {
>        #pragma omp sections
>        {
> -       continue;               // { dg-error "invalid branch" }
> +       continue; // { dg-error "invalid branch to/from OpenMP structured block" }
>        }
>      }
>
> @@ -18,16 +18,16 @@ void foo()
>      #pragma omp section
>        { bad1: ; }
>      #pragma omp section
> -      goto bad1;               // { dg-error "invalid branch" }
> +      goto bad1; // { dg-error "invalid branch to/from OpenMP structured block" }
>      }
>
>    #pragma omp sections
>      {
> -      goto bad2;               // { dg-error "invalid branch" }
> +      goto bad2; // { dg-error "invalid branch to/from OpenMP structured block" }
>      }
>    bad2:;
>
> -  goto bad3;                   // { dg-error "invalid entry" }
> +  goto bad3; // { dg-error "invalid entry to OpenMP structured block" }
>    #pragma omp sections
>      {
>        bad3: ;
> diff --git gcc/testsuite/gcc.dg/gomp/block-4.c gcc/testsuite/gcc.dg/gomp/block-4.c
> index 61f490c..b2ef9b1 100644
> --- gcc/testsuite/gcc.dg/gomp/block-4.c
> +++ gcc/testsuite/gcc.dg/gomp/block-4.c
> @@ -4,6 +4,6 @@ void foo()
>  {
>    #pragma omp critical
>      {
> -      return;          // { dg-error "invalid branch" }
> +      return; // { dg-error "invalid branch to/from OpenMP structured block" }
>      }
>  }
> diff --git gcc/testsuite/gcc.dg/gomp/block-5.c gcc/testsuite/gcc.dg/gomp/block-5.c
> index 741049f..7f3b37c 100644
> --- gcc/testsuite/gcc.dg/gomp/block-5.c
> +++ gcc/testsuite/gcc.dg/gomp/block-5.c
> @@ -4,12 +4,12 @@ void foo()
>  {
>    #pragma omp master
>      {
> -      goto bad1;       // { dg-error "invalid branch" }
> +      goto bad1; // { dg-error "invalid branch to/from OpenMP structured block" }
>      }
>
>    #pragma omp master
>      {
>      bad1:
> -      return;          // { dg-error "invalid branch" }
> +      return; // { dg-error "invalid branch to/from OpenMP structured block" }
>      }
>  }
> diff --git gcc/testsuite/gcc.dg/gomp/block-6.c gcc/testsuite/gcc.dg/gomp/block-6.c
> index 87e6392..fc9fdc8 100644
> --- gcc/testsuite/gcc.dg/gomp/block-6.c
> +++ gcc/testsuite/gcc.dg/gomp/block-6.c
> @@ -4,6 +4,6 @@ void foo()
>  {
>    #pragma omp ordered
>      {
> -      return;          // { dg-error "invalid branch" }
> +      return; // { dg-error "invalid branch to/from OpenMP structured block" }
>      }
>  }
> diff --git gcc/testsuite/gcc.dg/gomp/block-7.c gcc/testsuite/gcc.dg/gomp/block-7.c
> index 2bc1cdb..6219e7e 100644
> --- gcc/testsuite/gcc.dg/gomp/block-7.c
> +++ gcc/testsuite/gcc.dg/gomp/block-7.c
> @@ -6,15 +6,15 @@ void foo()
>    for (i = 0; i < 10; ++i)
>      {
>        #pragma omp for
> -      for (j = ({ continue; 0; });     // { dg-error "invalid branch" }
> -          j < ({ continue; 10; });     // { dg-error "invalid branch" }
> -          j += ({ continue; 1; }))     // { dg-error "invalid branch" }
> +      for (j = ({ continue; 0; }); // { dg-error "invalid branch to/from OpenMP structured block" }
> +          j < ({ continue; 10; }); // { dg-error "invalid branch to/from OpenMP structured block" }
> +          j += ({ continue; 1; })) // { dg-error "invalid branch to/from OpenMP structured block" }
>         continue;
>
>        #pragma omp for
> -      for (j = ({ break; 0; });                // { dg-error "invalid branch" }
> -          j < ({ break; 10; });        // { dg-error "invalid branch" }
> -          j += ({ break; 1; }))        // { dg-error "invalid branch" }
> +      for (j = ({ break; 0; }); // { dg-error "invalid branch to/from OpenMP structured block" }
> +          j < ({ break; 10; }); // { dg-error "invalid branch to/from OpenMP structured block" }
> +          j += ({ break; 1; })) // { dg-error "invalid branch to/from OpenMP structured block" }
>         break;                          // { dg-error "break" }
>      }
>  }
> diff --git gcc/testsuite/gcc.dg/gomp/block-8.c gcc/testsuite/gcc.dg/gomp/block-8.c
> index 3c717d9..f410070 100644
> --- gcc/testsuite/gcc.dg/gomp/block-8.c
> +++ gcc/testsuite/gcc.dg/gomp/block-8.c
> @@ -7,5 +7,5 @@ int foo()
>
>    #pragma omp parallel for
>    for (i = 0; i < 10; ++i)
> -    return 0;                  // { dg-error "invalid branch" }
> +    return 0; // { dg-error "invalid branch to/from OpenMP structured block" }
>  }
> diff --git gcc/testsuite/gcc.dg/gomp/block-9.c gcc/testsuite/gcc.dg/gomp/block-9.c
> index 9217cb7..2fae3de 100644
> --- gcc/testsuite/gcc.dg/gomp/block-9.c
> +++ gcc/testsuite/gcc.dg/gomp/block-9.c
> @@ -3,7 +3,7 @@
>  void foo(int i)
>  {
>    int j;
> -  switch (i)                   // { dg-error "invalid entry" }
> +  switch (i) // { dg-error "invalid entry to OpenMP structured block" }
>    {
>    #pragma omp parallel
>      { case 0:; }
> diff --git gcc/testsuite/gcc.dg/gomp/target-1.c gcc/testsuite/gcc.dg/gomp/target-1.c
> index 09e65bd..aaa6a14 100644
> --- gcc/testsuite/gcc.dg/gomp/target-1.c
> +++ gcc/testsuite/gcc.dg/gomp/target-1.c
> @@ -5,9 +5,9 @@ foo (int x)
>  {
>    bad1:
>    #pragma omp target
> -    goto bad1;                 /* { dg-error "invalid branch" } */
> +    goto bad1; // { dg-error "invalid branch to/from OpenMP structured block" }
>
> -  goto bad2;                   /* { dg-error "invalid entry" } */
> +  goto bad2; // { dg-error "invalid entry to OpenMP structured block" }
>    #pragma omp target
>      {
>        bad2: ;
> @@ -21,7 +21,7 @@ foo (int x)
>         { ok1: break; }
>      }
>
> -  switch (x)                   /* { dg-error "invalid entry" } */
> +  switch (x) // { dg-error "invalid entry to OpenMP structured block" }
>    {
>    #pragma omp target
>      { case 0:; }
> diff --git gcc/testsuite/gcc.dg/gomp/target-2.c gcc/testsuite/gcc.dg/gomp/target-2.c
> index 546a1d0..3a7afc4 100644
> --- gcc/testsuite/gcc.dg/gomp/target-2.c
> +++ gcc/testsuite/gcc.dg/gomp/target-2.c
> @@ -5,9 +5,9 @@ foo (int x, int y)
>  {
>    bad1:
>    #pragma omp target data map(tofrom: y)
> -    goto bad1;                 /* { dg-error "invalid branch" } */
> +    goto bad1; // { dg-error "invalid branch to/from OpenMP structured block" }
>
> -  goto bad2;                   /* { dg-error "invalid entry" } */
> +  goto bad2; // { dg-error "invalid entry to OpenMP structured block" }
>    #pragma omp target data map(tofrom: y)
>      {
>        bad2: ;
> @@ -21,7 +21,7 @@ foo (int x, int y)
>         { ok1: break; }
>      }
>
> -  switch (x)                   /* { dg-error "invalid entry" } */
> +  switch (x) // { dg-error "invalid entry to OpenMP structured block" }
>    {
>    #pragma omp target data map(tofrom: y)
>      { case 0:; }
> diff --git gcc/testsuite/gcc.dg/gomp/taskgroup-1.c gcc/testsuite/gcc.dg/gomp/taskgroup-1.c
> index e301efc..1997e0c 100644
> --- gcc/testsuite/gcc.dg/gomp/taskgroup-1.c
> +++ gcc/testsuite/gcc.dg/gomp/taskgroup-1.c
> @@ -5,9 +5,9 @@ foo (int x)
>  {
>    bad1:
>    #pragma omp taskgroup
> -    goto bad1;                 /* { dg-error "invalid branch" } */
> +    goto bad1; // { dg-error "invalid branch to/from OpenMP structured block" }
>
> -  goto bad2;                   /* { dg-error "invalid entry" } */
> +  goto bad2; // { dg-error "invalid entry to OpenMP structured block" }
>    #pragma omp taskgroup
>      {
>        bad2: ;
> @@ -21,7 +21,7 @@ foo (int x)
>         { ok1: break; }
>      }
>
> -  switch (x)                   /* { dg-error "invalid entry" } */
> +  switch (x) // { dg-error "invalid entry to OpenMP structured block" }
>    {
>    #pragma omp taskgroup
>      { case 0:; }
> diff --git gcc/testsuite/gcc.dg/gomp/teams-1.c gcc/testsuite/gcc.dg/gomp/teams-1.c
> index 73c00de..ad5b100 100644
> --- gcc/testsuite/gcc.dg/gomp/teams-1.c
> +++ gcc/testsuite/gcc.dg/gomp/teams-1.c
> @@ -5,9 +5,9 @@ foo (int x)
>  {
>    bad1:
>    #pragma omp target teams
> -    goto bad1;                 /* { dg-error "invalid branch" } */
> +    goto bad1; // { dg-error "invalid branch to/from OpenMP structured block" }
>
> -  goto bad2;                   /* { dg-error "invalid entry" } */
> +  goto bad2; // { dg-error "invalid entry to OpenMP structured block" }
>    #pragma omp target teams
>      {
>        bad2: ;
> @@ -21,7 +21,7 @@ foo (int x)
>         { ok1: break; }
>      }
>
> -  switch (x)                   /* { dg-error "invalid entry" } */
> +  switch (x) // { dg-error "invalid entry to OpenMP structured block" }
>    {
>    #pragma omp target teams
>      { case 0:; }
> @@ -34,9 +34,9 @@ bar (int x)
>    bad1:
>    #pragma omp target
>    #pragma omp teams
> -    goto bad1;                 /* { dg-error "invalid branch" } */
> +    goto bad1; // { dg-error "invalid branch to/from OpenMP structured block" }
>
> -  goto bad2;                   /* { dg-error "invalid entry" } */
> +  goto bad2; // { dg-error "invalid entry to OpenMP structured block" }
>    #pragma omp target
>    #pragma omp teams
>      {
> @@ -52,7 +52,7 @@ bar (int x)
>         { ok1: break; }
>      }
>
> -  switch (x)                   /* { dg-error "invalid entry" } */
> +  switch (x) // { dg-error "invalid entry to OpenMP structured block" }
>    {
>    #pragma omp target
>    #pragma omp teams
> diff --git gcc/toplev.c gcc/toplev.c
> index 2c570d4..c6fedbe 100644
> --- gcc/toplev.c
> +++ gcc/toplev.c
> @@ -96,6 +96,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "ipa-prop.h"
>  #include "gcse.h"
>  #include "optabs.h"
> +#include "omp-low.h"
>
>  #if defined(DBX_DEBUGGING_INFO) || defined(XCOFF_DEBUGGING_INFO)
>  #include "dbxout.h"
> @@ -596,6 +597,8 @@ compile_file (void)
>        if (flag_sanitize & SANITIZE_THREAD)
>         tsan_finish_file ();
>
> +      omp_finish_file ();
> +
>        output_shared_constant_pool ();
>        output_object_blocks ();
>        finish_tm_clone_pairs ();
> diff --git gcc/tree-core.h gcc/tree-core.h
> index 30db893..1da8125 100644
> --- gcc/tree-core.h
> +++ gcc/tree-core.h
> @@ -213,19 +213,19 @@ enum omp_clause_code {
>       (c_parser_omp_variable_list).  */
>    OMP_CLAUSE_ERROR = 0,
>
> -  /* OpenMP clause: private (variable_list).  */
> +  /* OpenACC/OpenMP clause: private (variable_list).  */
>    OMP_CLAUSE_PRIVATE,
>
>    /* OpenMP clause: shared (variable_list).  */
>    OMP_CLAUSE_SHARED,
>
> -  /* OpenMP clause: firstprivate (variable_list).  */
> +  /* OpenACC/OpenMP clause: firstprivate (variable_list).  */
>    OMP_CLAUSE_FIRSTPRIVATE,
>
>    /* OpenMP clause: lastprivate (variable_list).  */
>    OMP_CLAUSE_LASTPRIVATE,
>
> -  /* OpenMP clause: reduction (operator:variable_list).
> +  /* OpenACC/OpenMP clause: reduction (operator:variable_list).
>       OMP_CLAUSE_REDUCTION_CODE: The tree_code of the operator.
>       Operand 1: OMP_CLAUSE_REDUCTION_INIT: Stmt-list to initialize the var.
>       Operand 2: OMP_CLAUSE_REDUCTION_MERGE: Stmt-list to merge private var
> @@ -258,13 +258,42 @@ enum omp_clause_code {
>    /* OpenMP clause: to (variable-list).  */
>    OMP_CLAUSE_TO,
>
> -  /* OpenMP clause: map ({alloc:,to:,from:,tofrom:,}variable-list).  */
> +  /* OpenACC clauses: {copy, copyin, copyout, create, delete, deviceptr,
> +     device, host (self), present, present_or_copy (pcopy), present_or_copyin
> +     (pcopyin), present_or_copyout (pcopyout), present_or_create (pcreate)}
> +     (variable-list).
> +
> +     OpenMP clause: map ({alloc:,to:,from:,tofrom:,}variable-list).  */
>    OMP_CLAUSE_MAP,
>
> +  /* Internal structure to hold OpenACC cache directive's variable-list.
> +     #pragma acc cache (variable-list).  */
> +  OMP_CLAUSE__CACHE_,
> +
> +  /* OpenACC clause: device_resident (variable_list).  */
> +  OMP_CLAUSE_DEVICE_RESIDENT,
> +
> +  /* OpenACC clause: use_device (variable_list).  */
> +  OMP_CLAUSE_USE_DEVICE,
> +
> +  /* OpenACC clause: gang [(gang-argument-list)].
> +     Where
> +      gang-argument-list: [gang-argument-list, ] gang-argument
> +      gang-argument: [num:] integer-expression
> +                   | static: size-expression
> +      size-expression: * | integer-expression.  */
> +  OMP_CLAUSE_GANG,
> +
> +  /* OpenACC clause: async [(integer-expression)].  */
> +  OMP_CLAUSE_ASYNC,
> +
> +  /* OpenACC clause: wait [(integer-expression-list)].  */
> +  OMP_CLAUSE_WAIT,
> +
>    /* Internal clause: temporary for combined loops expansion.  */
>    OMP_CLAUSE__LOOPTEMP_,
>
> -  /* OpenMP clause: if (scalar-expression).  */
> +  /* OpenACC/OpenMP clause: if (scalar-expression).  */
>    OMP_CLAUSE_IF,
>
>    /* OpenMP clause: num_threads (integer-expression).  */
> @@ -276,13 +305,15 @@ enum omp_clause_code {
>    /* OpenMP clause: nowait.  */
>    OMP_CLAUSE_NOWAIT,
>
> -  /* OpenMP clause: ordered.  */
> +  /* OpenACC clause: seq.
> +
> +     OpenMP clause: ordered.  */
>    OMP_CLAUSE_ORDERED,
>
>    /* OpenMP clause: default.  */
>    OMP_CLAUSE_DEFAULT,
>
> -  /* OpenMP clause: collapse (constant-integer-expression).  */
> +  /* OpenACC/OpenMP clause: collapse (constant-integer-expression).  */
>    OMP_CLAUSE_COLLAPSE,
>
>    /* OpenMP clause: untied.  */
> @@ -338,7 +369,25 @@ enum omp_clause_code {
>
>    /* Internally used only clause, holding _Cilk_for # of iterations
>       on OMP_PARALLEL.  */
> -  OMP_CLAUSE__CILK_FOR_COUNT_
> +  OMP_CLAUSE__CILK_FOR_COUNT_,
> +
> +  /* OpenACC clause: independent.  */
> +  OMP_CLAUSE_INDEPENDENT,
> +
> +  /* OpenACC clause: worker [( [num:] integer-expression)].  */
> +  OMP_CLAUSE_WORKER,
> +
> +  /* OpenACC clause: vector [( [length:] integer-expression)].  */
> +  OMP_CLAUSE_VECTOR,
> +
> +  /* OpenACC clause: num_gangs (integer-expression).  */
> +  OMP_CLAUSE_NUM_GANGS,
> +
> +  /* OpenACC clause: num_workers (integer-expression).  */
> +  OMP_CLAUSE_NUM_WORKERS,
> +
> +  /* OpenACC clause: vector_length (integer-expression).  */
> +  OMP_CLAUSE_VECTOR_LENGTH
>  };
>
>  #undef DEFTREESTRUCT
> @@ -1167,19 +1216,45 @@ enum omp_clause_depend_kind
>
>  enum omp_clause_map_kind
>  {
> -  OMP_CLAUSE_MAP_ALLOC,
> -  OMP_CLAUSE_MAP_TO,
> -  OMP_CLAUSE_MAP_FROM,
> -  OMP_CLAUSE_MAP_TOFROM,
> +  /* If not already present, allocate.  */
> +  OMP_CLAUSE_MAP_ALLOC = 0,
> +  /* ..., and copy to device.  */
> +  OMP_CLAUSE_MAP_TO = 1 << 0,
> +  /* ..., and copy from device.  */
> +  OMP_CLAUSE_MAP_FROM = 1 << 1,
> +  /* ..., and copy to and from device.  */
> +  OMP_CLAUSE_MAP_TOFROM = OMP_CLAUSE_MAP_TO | OMP_CLAUSE_MAP_FROM,
> +  /* Special map kinds.  */
> +  OMP_CLAUSE_MAP_SPECIAL = 1 << 2,
>    /* The following kind is an internal only map kind, used for pointer based
>       array sections.  OMP_CLAUSE_SIZE for these is not the pointer size,
>       which is implicitly POINTER_SIZE_UNITS, but the bias.  */
> -  OMP_CLAUSE_MAP_POINTER,
> +  OMP_CLAUSE_MAP_POINTER = OMP_CLAUSE_MAP_SPECIAL,
>    /* Also internal, behaves like OMP_CLAUS_MAP_TO, but additionally any
>       OMP_CLAUSE_MAP_POINTER records consecutive after it which have addresses
>       falling into that range will not be ignored if OMP_CLAUSE_MAP_TO_PSET
>       wasn't mapped already.  */
>    OMP_CLAUSE_MAP_TO_PSET,
> +  /* The following are only valid for OpenACC.  */
> +  /* Flag to force a specific behavior (or else, a run-time error).  */
> +  OMP_CLAUSE_MAP_FORCE = 1 << 3,
> +  /* Allocate.  */
> +  OMP_CLAUSE_MAP_FORCE_ALLOC = OMP_CLAUSE_MAP_FORCE | OMP_CLAUSE_MAP_ALLOC,
> +  /* ..., and copy to device.  */
> +  OMP_CLAUSE_MAP_FORCE_TO = OMP_CLAUSE_MAP_FORCE | OMP_CLAUSE_MAP_TO,
> +  /* ..., and copy from device.  */
> +  OMP_CLAUSE_MAP_FORCE_FROM = OMP_CLAUSE_MAP_FORCE | OMP_CLAUSE_MAP_FROM,
> +  /* ..., and copy to and from device.  */
> +  OMP_CLAUSE_MAP_FORCE_TOFROM = OMP_CLAUSE_MAP_FORCE | OMP_CLAUSE_MAP_TOFROM,
> +  /* Must already be present.  */
> +  OMP_CLAUSE_MAP_FORCE_PRESENT = OMP_CLAUSE_MAP_FORCE | OMP_CLAUSE_MAP_SPECIAL,
> +  /* Deallocate a mapping, without copying from device.  */
> +  OMP_CLAUSE_MAP_FORCE_DEALLOC,
> +  /* Is a device pointer.  OMP_CLAUSE_SIZE for these is unused; is implicitly
> +     POINTER_SIZE_UNITS.  */
> +  OMP_CLAUSE_MAP_FORCE_DEVICEPTR,
> +
> +  /* End marker.  */
>    OMP_CLAUSE_MAP_LAST
>  };
>
> diff --git gcc/tree-inline.c gcc/tree-inline.c
> index 2025b38..045e64e 100644
> --- gcc/tree-inline.c
> +++ gcc/tree-inline.c
> @@ -1371,6 +1371,10 @@ 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
> @@ -1393,6 +1397,7 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
>           break;
>
>         case GIMPLE_OMP_FOR:
> +         gcc_assert (!is_gimple_omp_oacc_specifically (stmt));
>           s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
>           s2 = remap_gimple_seq (gimple_omp_for_pre_body (stmt), id);
>           copy = gimple_build_omp_for (s1, gimple_omp_for_kind (stmt),
> @@ -1449,6 +1454,7 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
>           break;
>
>         case GIMPLE_OMP_TARGET:
> +         gcc_assert (!is_gimple_omp_oacc_specifically (stmt));
>           s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
>           copy = gimple_build_omp_target
>                    (s1, gimple_omp_target_kind (stmt),
> @@ -4000,6 +4006,8 @@ 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 68043f9..b5d6543 100644
> --- gcc/tree-nested.c
> +++ gcc/tree-nested.c
> @@ -627,6 +627,8 @@ walk_gimple_omp_for (gimple for_stmt,
>                      walk_stmt_fn callback_stmt, walk_tree_fn callback_op,
>                      struct nesting_info *info)
>  {
> +  gcc_assert (!is_gimple_omp_oacc_specifically (for_stmt));
> +
>    struct walk_stmt_info wi;
>    gimple_seq seq;
>    tree t;
> @@ -1323,6 +1325,10 @@ 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;
> @@ -1353,6 +1359,7 @@ convert_nonlocal_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
>        break;
>
>      case GIMPLE_OMP_FOR:
> +      gcc_assert (!is_gimple_omp_oacc_specifically (stmt));
>        save_suppress = info->suppress_expansion;
>        convert_nonlocal_omp_clauses (gimple_omp_for_clauses_ptr (stmt), wi);
>        walk_gimple_omp_for (stmt, convert_nonlocal_reference_stmt,
> @@ -1379,6 +1386,7 @@ convert_nonlocal_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
>        break;
>
>      case GIMPLE_OMP_TARGET:
> +      gcc_assert (!is_gimple_omp_oacc_specifically (stmt));
>        if (gimple_omp_target_kind (stmt) != GF_OMP_TARGET_KIND_REGION)
>         {
>           save_suppress = info->suppress_expansion;
> @@ -1890,6 +1898,10 @@ 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;
> @@ -1919,6 +1931,7 @@ convert_local_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
>        break;
>
>      case GIMPLE_OMP_FOR:
> +      gcc_assert (!is_gimple_omp_oacc_specifically (stmt));
>        save_suppress = info->suppress_expansion;
>        convert_local_omp_clauses (gimple_omp_for_clauses_ptr (stmt), wi);
>        walk_gimple_omp_for (stmt, convert_local_reference_stmt,
> @@ -1945,6 +1958,7 @@ convert_local_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
>        break;
>
>      case GIMPLE_OMP_TARGET:
> +      gcc_assert (!is_gimple_omp_oacc_specifically (stmt));
>        if (gimple_omp_target_kind (stmt) != GF_OMP_TARGET_KIND_REGION)
>         {
>           save_suppress = info->suppress_expansion;
> @@ -2275,7 +2289,12 @@ 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)
>         {
>           *handled_ops_p = false;
> @@ -2341,6 +2360,10 @@ 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;
> @@ -2374,6 +2397,7 @@ convert_gimple_call (gimple_stmt_iterator *gsi, bool *handled_ops_p,
>        break;
>
>      case GIMPLE_OMP_TARGET:
> +      gcc_assert (!is_gimple_omp_oacc_specifically (stmt));
>        if (gimple_omp_target_kind (stmt) != GF_OMP_TARGET_KIND_REGION)
>         {
>           walk_body (convert_gimple_call, NULL, info, gimple_omp_body_ptr (stmt));
> @@ -2410,6 +2434,7 @@ convert_gimple_call (gimple_stmt_iterator *gsi, bool *handled_ops_p,
>        break;
>
>      case GIMPLE_OMP_FOR:
> +      gcc_assert (!is_gimple_omp_oacc_specifically (stmt));
>        walk_body (convert_gimple_call, NULL, info,
>                  gimple_omp_for_pre_body_ptr (stmt));
>        /* FALLTHRU */
> @@ -2421,6 +2446,7 @@ convert_gimple_call (gimple_stmt_iterator *gsi, bool *handled_ops_p,
>      case GIMPLE_OMP_TASKGROUP:
>      case GIMPLE_OMP_ORDERED:
>      case GIMPLE_OMP_CRITICAL:
> +      gcc_assert (!is_gimple_omp_oacc_specifically (stmt));
>        walk_body (convert_gimple_call, NULL, info, gimple_omp_body_ptr (stmt));
>        break;
>
> diff --git gcc/tree-pass.h gcc/tree-pass.h
> index 3db1a08..730f458 100644
> --- gcc/tree-pass.h
> +++ gcc/tree-pass.h
> @@ -594,7 +594,7 @@ extern void pass_fini_dump_file (opt_pass *);
>  extern const char *get_current_pass_name (void);
>  extern void print_current_pass (FILE *);
>  extern void debug_pass (void);
> -extern void ipa_write_summaries (void);
> +extern void ipa_write_summaries (bool is_omp);
>  extern void ipa_write_optimization_summaries (struct lto_symtab_encoder_d *);
>  extern void ipa_read_summaries (void);
>  extern void ipa_read_optimization_summaries (void);
> diff --git gcc/tree-pretty-print.c gcc/tree-pretty-print.c
> index bafdc5c..1458913 100644
> --- gcc/tree-pretty-print.c
> +++ gcc/tree-pretty-print.c
> @@ -335,6 +335,12 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags)
>      case OMP_CLAUSE__LOOPTEMP_:
>        name = "_looptemp_";
>        goto print_remap;
> +    case OMP_CLAUSE_DEVICE_RESIDENT:
> +      name = "device_resident";
> +      goto print_remap;
> +    case OMP_CLAUSE_USE_DEVICE:
> +      name = "use_device";
> +      goto print_remap;
>    print_remap:
>        pp_string (buffer, name);
>        pp_left_paren (buffer);
> @@ -527,6 +533,27 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags)
>         case OMP_CLAUSE_MAP_TOFROM:
>           pp_string (buffer, "tofrom");
>           break;
> +       case OMP_CLAUSE_MAP_FORCE_ALLOC:
> +         pp_string (buffer, "force_alloc");
> +         break;
> +       case OMP_CLAUSE_MAP_FORCE_TO:
> +         pp_string (buffer, "force_to");
> +         break;
> +       case OMP_CLAUSE_MAP_FORCE_FROM:
> +         pp_string (buffer, "force_from");
> +         break;
> +       case OMP_CLAUSE_MAP_FORCE_TOFROM:
> +         pp_string (buffer, "force_tofrom");
> +         break;
> +       case OMP_CLAUSE_MAP_FORCE_PRESENT:
> +         pp_string (buffer, "force_present");
> +         break;
> +       case OMP_CLAUSE_MAP_FORCE_DEALLOC:
> +         pp_string (buffer, "force_dealloc");
> +         break;
> +       case OMP_CLAUSE_MAP_FORCE_DEVICEPTR:
> +         pp_string (buffer, "force_deviceptr");
> +         break;
>         default:
>           gcc_unreachable ();
>         }
> @@ -563,6 +590,12 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags)
>                          spc, flags, false);
>        goto print_clause_size;
>
> +    case OMP_CLAUSE__CACHE_:
> +      pp_string (buffer, "(");
> +      dump_generic_node (buffer, OMP_CLAUSE_DECL (clause),
> +                        spc, flags, false);
> +      goto print_clause_size;
> +
>      case OMP_CLAUSE_NUM_TEAMS:
>        pp_string (buffer, "num_teams(");
>        dump_generic_node (buffer, OMP_CLAUSE_NUM_TEAMS_EXPR (clause),
> @@ -636,6 +669,66 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags)
>        pp_right_paren (buffer);
>        break;
>
> +    case OMP_CLAUSE_GANG:
> +      pp_string (buffer, "gang(");
> +      dump_generic_node (buffer, OMP_CLAUSE_GANG_EXPR (clause),
> +                        spc, flags, false);
> +      pp_character(buffer, ')');
> +      break;
> +
> +    case OMP_CLAUSE_ASYNC:
> +      pp_string (buffer, "async");
> +      if (OMP_CLAUSE_ASYNC_EXPR (clause))
> +        {
> +          pp_character(buffer, '(');
> +          dump_generic_node (buffer, OMP_CLAUSE_ASYNC_EXPR (clause),
> +                             spc, flags, false);
> +          pp_character(buffer, ')');
> +        }
> +      break;
> +
> +    case OMP_CLAUSE_WAIT:
> +      pp_string (buffer, "wait(");
> +      dump_generic_node (buffer, OMP_CLAUSE_WAIT_EXPR (clause),
> +                        spc, flags, false);
> +      pp_character(buffer, ')');
> +      break;
> +
> +    case OMP_CLAUSE_WORKER:
> +      pp_string (buffer, "worker(");
> +      dump_generic_node (buffer, OMP_CLAUSE_WORKER_EXPR (clause),
> +                        spc, flags, false);
> +      pp_character(buffer, ')');
> +      break;
> +
> +    case OMP_CLAUSE_VECTOR:
> +      pp_string (buffer, "vector(");
> +      dump_generic_node (buffer, OMP_CLAUSE_VECTOR_EXPR (clause),
> +                        spc, flags, false);
> +      pp_character(buffer, ')');
> +      break;
> +
> +    case OMP_CLAUSE_NUM_GANGS:
> +      pp_string (buffer, "num_gangs(");
> +      dump_generic_node (buffer, OMP_CLAUSE_NUM_GANGS_EXPR (clause),
> +                         spc, flags, false);
> +      pp_character (buffer, ')');
> +      break;
> +
> +    case OMP_CLAUSE_NUM_WORKERS:
> +      pp_string (buffer, "num_workers(");
> +      dump_generic_node (buffer, OMP_CLAUSE_NUM_WORKERS_EXPR (clause),
> +                         spc, flags, false);
> +      pp_character (buffer, ')');
> +      break;
> +
> +    case OMP_CLAUSE_VECTOR_LENGTH:
> +      pp_string (buffer, "vector_length(");
> +      dump_generic_node (buffer, OMP_CLAUSE_VECTOR_LENGTH_EXPR (clause),
> +                         spc, flags, false);
> +      pp_character (buffer, ')');
> +      break;
> +
>      case OMP_CLAUSE_INBRANCH:
>        pp_string (buffer, "inbranch");
>        break;
> @@ -654,6 +747,9 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags)
>      case OMP_CLAUSE_TASKGROUP:
>        pp_string (buffer, "taskgroup");
>        break;
> +    case OMP_CLAUSE_INDEPENDENT:
> +      pp_string (buffer, "independent");
> +      break;
>
>      default:
>        /* Should never happen.  */
> @@ -2407,6 +2503,51 @@ 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 OACC_KERNELS:
> +      pp_string (buffer, "#pragma acc kernels");
> +      dump_omp_clauses (buffer, OACC_KERNELS_CLAUSES (node), spc, flags);
> +      goto dump_omp_body;
> +
> +    case OACC_DATA:
> +      pp_string (buffer, "#pragma acc data");
> +      dump_omp_clauses (buffer, OACC_DATA_CLAUSES (node), spc, flags);
> +      goto dump_omp_body;
> +
> +    case OACC_HOST_DATA:
> +      pp_string (buffer, "#pragma acc host_data");
> +      dump_omp_clauses (buffer, OACC_HOST_DATA_CLAUSES (node), spc, flags);
> +      goto dump_omp_body;
> +
> +    case OACC_DECLARE:
> +      pp_string (buffer, "#pragma acc declare");
> +      dump_omp_clauses (buffer, OACC_DECLARE_CLAUSES (node), spc, flags);
> +      break;
> +
> +    case OACC_UPDATE:
> +      pp_string (buffer, "#pragma acc update");
> +      dump_omp_clauses (buffer, OACC_UPDATE_CLAUSES (node), spc, flags);
> +      break;
> +
> +    case OACC_ENTER_DATA:
> +      pp_string (buffer, "#pragma acc enter data");
> +      dump_omp_clauses (buffer, OACC_ENTER_DATA_CLAUSES (node), spc, flags);
> +      break;
> +
> +    case OACC_EXIT_DATA:
> +      pp_string (buffer, "#pragma acc exit data");
> +      dump_omp_clauses (buffer, OACC_EXIT_DATA_CLAUSES (node), spc, flags);
> +      break;
> +
> +    case OACC_CACHE:
> +      pp_string (buffer, "#pragma acc cache");
> +      dump_omp_clauses (buffer, OACC_CACHE_CLAUSES (node), spc, flags);
> +      break;
> +
>      case OMP_PARALLEL:
>        pp_string (buffer, "#pragma omp parallel");
>        dump_omp_clauses (buffer, OMP_PARALLEL_CLAUSES (node), spc, flags);
> @@ -2451,6 +2592,10 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
>        pp_string (buffer, "#pragma omp distribute");
>        goto dump_omp_loop;
>
> +    case OACC_LOOP:
> +      pp_string (buffer, "#pragma acc loop");
> +      goto dump_omp_loop;
> +
>      case OMP_TEAMS:
>        pp_string (buffer, "#pragma omp teams");
>        dump_omp_clauses (buffer, OMP_TEAMS_CLAUSES (node), spc, flags);
> diff --git gcc/tree.c gcc/tree.c
> index 6e5c375..7318434 100644
> --- gcc/tree.c
> +++ gcc/tree.c
> @@ -270,6 +270,12 @@ unsigned const char omp_clause_num_ops[] =
>    2, /* OMP_CLAUSE_FROM  */
>    2, /* OMP_CLAUSE_TO  */
>    2, /* OMP_CLAUSE_MAP  */
> +  2, /* OMP_CLAUSE__CACHE_  */
> +  1, /* OMP_CLAUSE_DEVICE_RESIDENT  */
> +  1, /* OMP_CLAUSE_USE_DEVICE  */
> +  1, /* OMP_CLAUSE_GANG  */
> +  1, /* OMP_CLAUSE_ASYNC  */
> +  1, /* OMP_CLAUSE_WAIT  */
>    1, /* OMP_CLAUSE__LOOPTEMP_  */
>    1, /* OMP_CLAUSE_IF  */
>    1, /* OMP_CLAUSE_NUM_THREADS  */
> @@ -296,6 +302,12 @@ unsigned const char omp_clause_num_ops[] =
>    0, /* OMP_CLAUSE_TASKGROUP  */
>    1, /* OMP_CLAUSE__SIMDUID_  */
>    1, /* OMP_CLAUSE__CILK_FOR_COUNT_  */
> +  0, /* OMP_CLAUSE_INDEPENDENT  */
> +  1, /* OMP_CLAUSE_WORKER  */
> +  1, /* OMP_CLAUSE_VECTOR  */
> +  1, /* OMP_CLAUSE_NUM_GANGS  */
> +  1, /* OMP_CLAUSE_NUM_WORKERS  */
> +  1, /* OMP_CLAUSE_VECTOR_LENGTH  */
>  };
>
>  const char * const omp_clause_code_name[] =
> @@ -315,6 +327,12 @@ const char * const omp_clause_code_name[] =
>    "from",
>    "to",
>    "map",
> +  "_cache_",
> +  "device_resident",
> +  "use_device",
> +  "gang",
> +  "async",
> +  "wait",
>    "_looptemp_",
>    "if",
>    "num_threads",
> @@ -340,7 +358,13 @@ const char * const omp_clause_code_name[] =
>    "sections",
>    "taskgroup",
>    "_simduid_",
> -  "_Cilk_for_count_"
> +  "_Cilk_for_count_",
> +  "independent",
> +  "worker",
> +  "vector",
> +  "num_gangs",
> +  "num_workers",
> +  "vector_length"
>  };
>
>
> @@ -11092,6 +11116,16 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data,
>      case OMP_CLAUSE:
>        switch (OMP_CLAUSE_CODE (*tp))
>         {
> +       case OMP_CLAUSE_DEVICE_RESIDENT:
> +       case OMP_CLAUSE_USE_DEVICE:
> +       case OMP_CLAUSE_GANG:
> +       case OMP_CLAUSE_ASYNC:
> +       case OMP_CLAUSE_WAIT:
> +       case OMP_CLAUSE_WORKER:
> +       case OMP_CLAUSE_VECTOR:
> +       case OMP_CLAUSE_NUM_GANGS:
> +       case OMP_CLAUSE_NUM_WORKERS:
> +       case OMP_CLAUSE_VECTOR_LENGTH:
>         case OMP_CLAUSE_PRIVATE:
>         case OMP_CLAUSE_SHARED:
>         case OMP_CLAUSE_FIRSTPRIVATE:
> @@ -11115,6 +11149,7 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data,
>           WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, 0));
>           /* FALLTHRU */
>
> +       case OMP_CLAUSE_INDEPENDENT:
>         case OMP_CLAUSE_NOWAIT:
>         case OMP_CLAUSE_ORDERED:
>         case OMP_CLAUSE_DEFAULT:
> @@ -11152,6 +11187,7 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data,
>         case OMP_CLAUSE_FROM:
>         case OMP_CLAUSE_TO:
>         case OMP_CLAUSE_MAP:
> +       case OMP_CLAUSE__CACHE_:
>           WALK_SUBTREE (OMP_CLAUSE_DECL (*tp));
>           WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, 1));
>           WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp));
> diff --git gcc/tree.def gcc/tree.def
> index ff6be21..f44853a 100644
> --- gcc/tree.def
> +++ gcc/tree.def
> @@ -1021,8 +1021,33 @@ 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)
> +
> +/* OpenACC - #pragma acc kernels [clause1 ... clauseN]
> +   Operand 0: OACC_KERNELS_BODY: Sequence of kernels.
> +   Operand 1: OACC_KERNELS_CLAUSES: List of clauses.  */
> +
> +DEFTREECODE (OACC_KERNELS, "oacc_kernels", tcc_statement, 2)
> +
> +/* OpenACC - #pragma acc data [clause1 ... clauseN]
> +   Operand 0: OACC_DATA_BODY: Data construct body.
> +   Operand 1: OACC_DATA_CLAUSES: List of clauses.  */
> +
> +DEFTREECODE (OACC_DATA, "oacc_data", tcc_statement, 2)
> +
> +/* OpenACC - #pragma acc host_data [clause1 ... clauseN]
> +   Operand 0: OACC_HOST_DATA_BODY: Host_data construct body.
> +   Operand 1: OACC_HOST_DATA_CLAUSES: List of clauses.  */
> +
> +DEFTREECODE (OACC_HOST_DATA, "oacc_host_data", 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.  */
> @@ -1053,7 +1078,7 @@ DEFTREECODE (OMP_TASK, "omp_task", tcc_statement, 2)
>     private.  N1, N2 and INCR are required to be loop invariant integer
>     expressions that are evaluated without any synchronization.
>     The evaluation order, frequency of evaluation and side-effects are
> -   unspecified by the standard.  */
> +   unspecified by the standards.  */
>  DEFTREECODE (OMP_FOR, "omp_for", tcc_statement, 6)
>
>  /* OpenMP - #pragma omp simd [clause1 ... clauseN]
> @@ -1072,6 +1097,10 @@ DEFTREECODE (CILK_FOR, "cilk_for", tcc_statement, 6)
>     Operands like for OMP_FOR.  */
>  DEFTREECODE (OMP_DISTRIBUTE, "omp_distribute", tcc_statement, 6)
>
> +/* OpenMP - #pragma acc loop [clause1 ... clauseN]
> +   Operands like for OMP_FOR.  */
> +DEFTREECODE (OACC_LOOP, "oacc_loop", tcc_statement, 6)
> +
>  /* OpenMP - #pragma omp teams [clause1 ... clauseN]
>     Operand 0: OMP_TEAMS_BODY: Teams body.
>     Operand 1: OMP_TEAMS_CLAUSES: List of clauses.  */
> @@ -1118,6 +1147,27 @@ DEFTREECODE (OMP_ORDERED, "omp_ordered", tcc_statement, 1)
>     Operand 1: OMP_CRITICAL_NAME: Identifier for critical section.  */
>  DEFTREECODE (OMP_CRITICAL, "omp_critical", tcc_statement, 2)
>
> +/* OpenACC - #pragma acc declare [clause1 ... clauseN]
> +   Operand 0: OACC_DECLARE_CLAUSES: List of clauses.  */
> +DEFTREECODE (OACC_DECLARE, "oacc_declare", tcc_statement, 1)
> +
> +/* OpenACC - #pragma acc update [clause1 ... clauseN]
> +   Operand 0: OACC_UPDATE_CLAUSES: List of clauses.  */
> +DEFTREECODE (OACC_UPDATE, "oacc_update", tcc_statement, 1)
> +
> +/* OpenACC - #pragma acc enter data [clause1 ... clauseN]
> +   Operand 0: OACC_ENTER_DATA_CLAUSES: List of clauses.  */
> +DEFTREECODE (OACC_ENTER_DATA, "oacc_enter_data", tcc_statement, 1)
> +
> +/* OpenACC - #pragma acc exit data [clause1 ... clauseN]
> +   Operand 0: OACC_EXIT_DATA_CLAUSES: List of clauses.  */
> +DEFTREECODE (OACC_EXIT_DATA, "oacc_exit_data", tcc_statement, 1)
> +
> +/* OpenACC - #pragma acc cache (variable1 ... variableN)
> +   Operand 0: OACC_CACHE_CLAUSES: List of variables (transformed into
> +       OMP_CLAUSE__CACHE_ clauses).  */
> +DEFTREECODE (OACC_CACHE, "oacc_cache", tcc_statement, 1)
> +
>  /* OpenMP - #pragma omp target update [clause1 ... clauseN]
>     Operand 0: OMP_TARGET_UPDATE_CLAUSES: List of clauses.  */
>  DEFTREECODE (OMP_TARGET_UPDATE, "omp_target_update", tcc_statement, 1)
> diff --git gcc/tree.h gcc/tree.h
> index 1b661ca..e1adbab 100644
> --- gcc/tree.h
> +++ gcc/tree.h
> @@ -1160,12 +1160,47 @@ extern void protected_set_expr_location (tree, location_t);
>  #define TRANSACTION_EXPR_RELAXED(NODE) \
>    (TRANSACTION_EXPR_CHECK (NODE)->base.public_flag)
>
> -/* OpenMP directive and clause accessors.  */
> +/* OpenMP and OpenACC 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 OACC_KERNELS_BODY(NODE) \
> +  TREE_OPERAND (OACC_KERNELS_CHECK(NODE), 0)
> +#define OACC_KERNELS_CLAUSES(NODE) \
> +  TREE_OPERAND (OACC_KERNELS_CHECK(NODE), 1)
> +
> +#define OACC_DATA_BODY(NODE) \
> +  TREE_OPERAND (OACC_DATA_CHECK (NODE), 0)
> +#define OACC_DATA_CLAUSES(NODE) \
> +  TREE_OPERAND (OACC_DATA_CHECK (NODE), 1)
> +
> +#define OACC_HOST_DATA_BODY(NODE) \
> +  TREE_OPERAND (OACC_HOST_DATA_CHECK (NODE), 0)
> +#define OACC_HOST_DATA_CLAUSES(NODE) \
> +  TREE_OPERAND (OACC_HOST_DATA_CHECK (NODE), 1)
> +
> +#define OACC_DECLARE_CLAUSES(NODE) \
> +  TREE_OPERAND (OACC_DECLARE_CHECK (NODE), 0)
> +
> +#define OACC_ENTER_DATA_CLAUSES(NODE) \
> +  TREE_OPERAND (OACC_ENTER_DATA_CHECK (NODE), 0)
> +
> +#define OACC_EXIT_DATA_CLAUSES(NODE) \
> +  TREE_OPERAND (OACC_EXIT_DATA_CHECK (NODE), 0)
> +
> +#define OACC_UPDATE_CLAUSES(NODE) \
> +  TREE_OPERAND (OACC_UPDATE_CHECK (NODE), 0)
> +
> +#define OACC_CACHE_CLAUSES(NODE) \
> +  TREE_OPERAND (OACC_CACHE_CHECK (NODE), 0)
>
>  #define OMP_PARALLEL_BODY(NODE)    TREE_OPERAND (OMP_PARALLEL_CHECK (NODE), 0)
>  #define OMP_PARALLEL_CLAUSES(NODE) TREE_OPERAND (OMP_PARALLEL_CHECK (NODE), 1)
> @@ -1177,7 +1212,7 @@ extern void protected_set_expr_location (tree, location_t);
>  #define OMP_TASKREG_BODY(NODE)    TREE_OPERAND (OMP_TASKREG_CHECK (NODE), 0)
>  #define OMP_TASKREG_CLAUSES(NODE) TREE_OPERAND (OMP_TASKREG_CHECK (NODE), 1)
>
> -#define OMP_LOOP_CHECK(NODE) TREE_RANGE_CHECK (NODE, OMP_FOR, OMP_DISTRIBUTE)
> +#define OMP_LOOP_CHECK(NODE) TREE_RANGE_CHECK (NODE, OMP_FOR, OACC_LOOP)
>  #define OMP_FOR_BODY(NODE)        TREE_OPERAND (OMP_LOOP_CHECK (NODE), 0)
>  #define OMP_FOR_CLAUSES(NODE)     TREE_OPERAND (OMP_LOOP_CHECK (NODE), 1)
>  #define OMP_FOR_INIT(NODE)        TREE_OPERAND (OMP_LOOP_CHECK (NODE), 2)
> @@ -1219,7 +1254,7 @@ extern void protected_set_expr_location (tree, location_t);
>  #define OMP_CLAUSE_SIZE(NODE)                                          \
>    OMP_CLAUSE_OPERAND (OMP_CLAUSE_RANGE_CHECK (OMP_CLAUSE_CHECK (NODE), \
>                                               OMP_CLAUSE_FROM,          \
> -                                             OMP_CLAUSE_MAP), 1)
> +                                             OMP_CLAUSE__CACHE_), 1)
>
>  #define OMP_CLAUSE_CHAIN(NODE)     TREE_CHAIN (OMP_CLAUSE_CHECK (NODE))
>  #define OMP_CLAUSE_DECL(NODE)                                          \
> @@ -1236,6 +1271,15 @@ extern void protected_set_expr_location (tree, location_t);
>  #define OMP_SECTION_LAST(NODE) \
>    (OMP_SECTION_CHECK (NODE)->base.private_flag)
>
> +/* True on an OACC_KERNELS statement if is represents combined kernels loop
> +   directive.  */
> +#define OACC_KERNELS_COMBINED(NODE) \
> +  (OACC_KERNELS_CHECK (NODE)->base.private_flag)
> +
> +/* Like OACC_KERNELS_COMBINED, but for parallel loop directive.  */
> +#define OACC_PARALLEL_COMBINED(NODE) \
> +  (OACC_PARALLEL_CHECK (NODE)->base.private_flag)
> +
>  /* True on an OMP_PARALLEL statement if it represents an explicit
>     combined parallel work-sharing constructs.  */
>  #define OMP_PARALLEL_COMBINED(NODE) \
> @@ -1278,6 +1322,32 @@ extern void protected_set_expr_location (tree, location_t);
>  #define OMP_CLAUSE_SCHEDULE_CHUNK_EXPR(NODE) \
>    OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_SCHEDULE), 0)
>
> +/* OpenACC clause expressions  */
> +#define OMP_CLAUSE_GANG_EXPR(NODE) \
> +  OMP_CLAUSE_OPERAND ( \
> +    OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_GANG), 0)
> +#define OMP_CLAUSE_ASYNC_EXPR(NODE) \
> +  OMP_CLAUSE_OPERAND ( \
> +    OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_ASYNC), 0)
> +#define OMP_CLAUSE_WAIT_EXPR(NODE) \
> +  OMP_CLAUSE_OPERAND ( \
> +    OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_WAIT), 0)
> +#define OMP_CLAUSE_VECTOR_EXPR(NODE) \
> +  OMP_CLAUSE_OPERAND ( \
> +    OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_VECTOR), 0)
> +#define OMP_CLAUSE_WORKER_EXPR(NODE) \
> +  OMP_CLAUSE_OPERAND ( \
> +    OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_WORKER), 0)
> +#define OMP_CLAUSE_NUM_GANGS_EXPR(NODE) \
> +  OMP_CLAUSE_OPERAND ( \
> +    OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_NUM_GANGS), 0)
> +#define OMP_CLAUSE_NUM_WORKERS_EXPR(NODE) \
> +  OMP_CLAUSE_OPERAND ( \
> +    OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_NUM_WORKERS), 0)
> +#define OMP_CLAUSE_VECTOR_LENGTH_EXPR(NODE) \
> +  OMP_CLAUSE_OPERAND ( \
> +    OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_VECTOR_LENGTH), 0)
> +
>  #define OMP_CLAUSE_DEPEND_KIND(NODE) \
>    (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_DEPEND)->omp_clause.subcode.depend_kind)
>
> diff --git libgcc/Makefile.in libgcc/Makefile.in
> index 4008a85..c4eee71 100644
> --- libgcc/Makefile.in
> +++ libgcc/Makefile.in
> @@ -980,6 +980,12 @@ crtbegin$(objext): $(srcdir)/crtstuff.c
>  crtend$(objext): $(srcdir)/crtstuff.c
>         $(crt_compile) $(CRTSTUFF_T_CFLAGS) -c $< -DCRT_END
>
> +crtompbegin$(objext): $(srcdir)/ompstuff.c
> +       $(crt_compile) $(CRTSTUFF_T_CFLAGS) -c $< -DCRT_BEGIN
> +
> +crtompend$(objext): $(srcdir)/ompstuff.c
> +       $(crt_compile) $(CRTSTUFF_T_CFLAGS) -c $< -DCRT_END
> +
>  # These are versions of crtbegin and crtend for shared libraries.
>  crtbeginS$(objext): $(srcdir)/crtstuff.c
>         $(crt_compile) $(CRTSTUFF_T_CFLAGS_S) -c $< -DCRT_BEGIN -DCRTSTUFFS_O
> diff --git libgcc/configure.ac libgcc/configure.ac
> index 710f15a..4061b39 100644
> --- libgcc/configure.ac
> +++ libgcc/configure.ac
> @@ -346,6 +346,18 @@ esac
>  # Collect host-machine-specific information.
>  . ${srcdir}/config.host
>
> +AC_ARG_ENABLE(offload-targets,
> +[AS_HELP_STRING([--enable-offload-targets=LIST],
> + [enable offloading to devices from LIST])],
> +[
> +  if test x"$enable_offload_targets" = x; then
> +    AC_MSG_ERROR([no offload targets specified])
> +  fi
> +], [enable_offload_targets=])
> +if test x"$enable_offload_targets" != x; then
> +  extra_parts="${extra_parts} crtompbegin.o crtompend.o"
> +fi
> +
>  # Check if Solaris/x86 linker supports ZERO terminator unwind entries.
>  # This is after config.host so we can augment tmake_file.
>  # Link with -nostartfiles -nodefaultlibs since neither are present while
> diff --git libgcc/ompstuff.c libgcc/ompstuff.c
> new file mode 100644
> index 0000000..3e6c293
> --- /dev/null
> +++ libgcc/ompstuff.c
> @@ -0,0 +1,73 @@
> +/* Specialized bits of code needed for the OpenMP offloading tables.
> +   Copyright (C) 2014 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.
> +
> +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/>.  */
> +
> +/* Target machine header files require this define. */
> +#define IN_LIBGCC2
> +
> +/* FIXME: Including auto-host is incorrect, but until we have
> +   identified the set of defines that need to go into auto-target.h,
> +   this will have to do.  */
> +#include "auto-host.h"
> +#undef pid_t
> +#undef rlim_t
> +#undef ssize_t
> +#undef vfork
> +#include "tconfig.h"
> +#include "tsystem.h"
> +#include "coretypes.h"
> +#include "tm.h"
> +#include "libgcc_tm.h"
> +
> +#ifdef CRT_BEGIN
> +
> +#if defined(HAVE_GAS_HIDDEN) && defined(ENABLE_OFFLOADING)
> +void *_omp_func_table[0]
> +  __attribute__ ((__used__, visibility ("hidden"),
> +                 section ("__gnu_offload_funcs"))) = { };
> +void *_omp_var_table[0]
> +  __attribute__ ((__used__, visibility ("hidden"),
> +                 section ("__gnu_offload_vars"))) = { };
> +#endif
> +
> +#elif defined CRT_END
> +
> +#if defined(HAVE_GAS_HIDDEN) && defined(ENABLE_OFFLOADING)
> +void *_omp_funcs_end[0]
> +  __attribute__ ((__used__, visibility ("hidden"),
> +                 section ("__gnu_offload_funcs"))) = { };
> +void *_omp_vars_end[0]
> +  __attribute__ ((__used__, visibility ("hidden"),
> +                 section ("__gnu_offload_vars"))) = { };
> +extern void *_omp_func_table[];
> +extern void *_omp_var_table[];
> +void *__OPENMP_TARGET__[] __attribute__ ((__visibility__ ("hidden"))) =
> +{
> +  &_omp_func_table, &_omp_funcs_end,
> +  &_omp_var_table, &_omp_vars_end
> +};
> +#endif
> +
> +#else /* ! CRT_BEGIN && ! CRT_END */
> +#error "One of CRT_BEGIN or CRT_END must be defined."
> +#endif
>
>
> GrÃÃe,
>  Thomas


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]