This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: OpenACC middle end changes
- From: Richard Biener <richard dot guenther at gmail dot com>
- To: Thomas Schwinge <thomas at codesourcery dot com>
- Cc: Jakub Jelinek <jakub at redhat dot com>, GCC Patches <gcc-patches at gcc dot gnu dot org>
- Date: Fri, 14 Nov 2014 11:28:15 +0100
- Subject: Re: OpenACC middle end changes
- Authentication-results: sourceware.org; auth=none
- References: <87fvdnnijk dot fsf at schwinge dot name>
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