diff mbox

[gomp4] Accelerator constructs omp lowering and expansion

Message ID 20130904185447.GG23437@tucnak.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek Sept. 4, 2013, 6:54 p.m. UTC
Hi!

This patch implements #pragma omp {target{, data, update},teams} lowering
and expansion, and adds stub calls into libgomp, so that (for now
unconditionally) we can at least always fall back to host execution.

I still need to add testcases and test reference based array section
handling and look at mapping of VLAs.

Any issues you can spot in the patch?  If not, I'll commit it tomorrow, so
that I can continue poking in these areas without too much pending stuff.

Known issues that don't affect host fallback, but will be a problem
for offloading (Richard or others, any thoughts about that?):
1) right now we pass a host fn address and a function name string
   to GOMP_target.  For host execution we of course only need the fn
   address, for offloading I guess libgomp will need to dlinfo
   that fn address to find out what shared library (or binary) contains
   it and somehow look for the special data section in it.
   But, right now the *._omp_fn.N functions are always static, so there
   is nothing to look up by name for Intel MIC, and if we wanted to make
   the symbol global, we'd need to give it a shlib resp. binary unique
   name; but if the containing function is not global, how can we do that?
   Append get_file_function_name to the name?
2) much bigger problem seems to be global #pragma omp declare target
   variables.  Those are supposed to be mapped from the beginning,
   if they are just copied into the target LTO subset streaming, they will
   be emitted normally as data variables.  But, unfortunately the
   runtime must be aware of those mappings, because you can do stuff like:
#pragma omp declare target
int v = 1;
#pragma omp end declare target
void bar (int *p)
{
  #pragma omp target map(to:p[:1])
  *p++;
}
void foo () { bar (&v); }
   where the runtime should assign target's p copy the value of target's
   v variable.  Or even for say #pragma omp target update.
   So, on the host side, we need to prepare the triplets of host var
   address, var size and during linking somehow supply it info on how
   to create the target address, and have some function (one per
   shared library resp. binary) that would locate the data section
   within the shared library/binary for the requested accelerator
   and with another argument call some libgomp function to initialize
   the device data environment for the given shared library/binary
   and accelerator.  Perhaps we could pass the address of such (.hidden)
   function as yet another argument to GOMP_target call and
   --as-needed link it from some *.a library?

2013-09-04  Jakub Jelinek  <jakub@redhat.com>

	* tree-cfg.c (make_edges): For GIMPLE_OMP_TARGET
	with GF_OMP_TARGET_KIND_UPDATE, don't look for
	GIMPLE_OMP_RETURN and immediately restore previous
	region.
	* langhooks.c (lhd_omp_mappable_type): New function.
	* omp-low.c (scan_sharing_clauses): Ignore OMP_CLAUSE_SHARED
	in GIMPLE_OMP_TEAMS constructs.  Handle OMP_CLAUSE_NUM_TEAMS,
	OMP_CLAUSE_THREAD_LIMIT, OMP_CLAUSE_DEVICE, OMP_CLAUSE_MAP,
	OMP_CLAUSE_TO and OMP_CLAUSE_FROM.
	(create_omp_child_function): If current function has
	"omp declare target" attribute or if current region
	is OMP_TARGET or lexically nested in it, add that
	attribute to the omp child function.
	(scan_omp_target, scan_omp_teams): New functions.
	(check_omp_nesting_restrictions): Fix a typo in TEAMS nesting
	check.
	(scan_omp_1_stmt): Handle GIMPLE_OMP_TARGET and GIMPLE_OMP_TEAMS.
	(lower_rec_input_clauses): Ignore OMP_CLAUSE_SHARED
	in GIMPLE_OMP_TEAMS constructs.
	(expand_omp_synch): Handle GIMPLE_OMP_TEAMS.
	(expand_omp_target): New function.
	(expand_omp): Handle GIMPLE_OMP_TARGET and GIMPLE_OMP_TEAMS.
	(build_omp_regions_1): For GIMPLE_OMP_TARGET with
	GF_OMP_TARGET_KIND_UPDATE, don't look for GIMPLE_OMP_RETURN and
	immediately restore previous region.
	(lower_omp_single): Emit a CLOBBER stmt after GIMPLE_OMP_RETURN.
	(lower_omp_taskreg): Likewise.
	(lower_omp_target, lower_omp_teams): New functions.
	(lower_omp_1): Handle GIMPLE_OMP_TARGET and GIMPLE_OMP_TEAMS.
	* tree.h (enum omp_clause_map_kind): Improve description of
	OMP_CLAUSE_MAP_POINTER.
	(OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION): Define.
	* gimple.def (GIMPLE_OMP_TARGET): Use GSS_OMP_PARALLEL instead
	of GSS_OMP_SINGLE.
	* langhooks.h (struct lang_hooks_for_types): Add
	omp_mappable_type hook.
	* langhooks-def.h (lhd_omp_mappable_type): New prototype.
	(LANG_HOOKS_OMP_MAPPABLE_TYPE): Define.
	(LANG_HOOKS_FOR_TYPES_INITIALIZER): Use it.
	* gimple.h (gimple_omp_target_clauses, gimple_omp_target_clauses_ptr,
	gimple_omp_target_set_clauses): Use gimple_omp_parallel
	instead of gimple_omp_single.
	(gimple_omp_target_child_fn, gimple_omp_target_child_fn_ptr,
	gimple_omp_target_set_child_fn, gimple_omp_target_data_arg,
	gimple_omp_target_data_arg_ptr, gimple_omp_target_set_data_arg): New
	inlines.
	* omp-builtins.def (BUILT_IN_GOMP_TARGET, BUILT_IN_GOMP_TARGET_DATA,
	BUILT_IN_GOMP_TARGET_END_DATA, BUILT_IN_GOMP_TARGET_UPDATE,
	BUILT_IN_GOMP_TEAMS): New builtins.
	* gimple-pretty-print.c (dump_gimple_omp_target): Print child_fn
	for #pragma omp target.
	* gimplify.c (omp_notice_variable): Diagnose if implicitly mapped
	decl doesn't have mappable type.
	(gimplify_scan_omp_clauses): For OMP_CLAUSE_MAP don't clear
	notice_outer.
	(gimplify_adjust_omp_clauses_1): Add OMP_CLAUSE_MAP even if the same
	decl is already referenced in target data construct surrounding it.
	(gimplify_adjust_omp_clauses): Likewise.  Handle
	OMP_CLAUSE_THREAD_LIMIT.
	(gimplify_omp_workshare): Fix up gimplification of target or target
	data construct body.  For target data add GOMP_target_end_data
	call in a try/finally cleanup.
	* builtin-types.def (BT_FN_VOID_UINT_UINT,
	BT_FN_VOID_INT_SIZE_PTR_PTR_PTR,
	BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR): New.
c/
	* c-typeck.c (handle_omp_array_sections_1): Remove pointer_based_p
	argument.  Do c_save_expr on low bound unconditionally.
	(handle_omp_array_sections): Adjust caller.  Call c_fully_fold when
	needed.  Add OMP_CLAUSE_MAP_POINTER map clause even for array based
	array sections.
	(c_finish_omp_clauses): Don't complain about non-mappable types
	for OMP_CLAUSE_MAP_POINTER.  Check for duplicates even for map
	clauses.  Handle OMP_CLAUSE_NUM_TEAMS.
	* c-parser.c (c_parser_omp_target_data, c_parser_omp_target): Call
	keep_next_level ().
cp/
	* parser.c (cp_parser_omp_target_data, cp_parser_omp_target): Call
	keep_next_level (true).
	* cp-objcp-common.h (LANG_HOOKS_OMP_MAPPABLE_TYPE): Define.
	* semantics.c (handle_omp_array_sections_1): Remove pointer_based_p
	argument.  Do cp_save_expr on low bound unconditionally.
	(handle_omp_array_sections): Adjust caller.  Add OMP_CLAUSE_MAP_POINTER
	map clause even for array based array sections.
	(finish_omp_clauses): Don't complain about non-mappable types
	for OMP_CLAUSE_MAP_POINTER.  Check for duplicates even for map
	clauses.
fortran/
	* types.def (BT_FN_VOID_UINT_UINT, BT_FN_VOID_INT_SIZE_PTR_PTR_PTR,
	BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR): New.
testsuite/
	* c-c++-common/gomp/map-1.c (foo): Add dg-error for implicitly
	mapped non-mappable var.
libgomp/
	* libgomp.map (GOMP_4.0): Add GOMP_target, GOMP_target_data,
	GOMP_target_end_data, GOMP_target_update and GOMP_teams.
	* Makefile.am (libgomp_la_SOURCES): Add target.c.
	* Makefile.in: Regenerated.
	* target.c: New file.
	* libgomp_g.h (GOMP_target, GOMP_target_data,
	GOMP_target_end_data, GOMP_target_update, GOMP_teams): New prototypes.
	* testsuite/libgomp.c++/for-11.C (main): Uncomment
	#pragma omp target teams directive.
	* testsuite/libgomp.c/for-3.c (main): Likewise.
	* testsuite/libgomp.c++/target-1.C: New test.
	* testsuite/libgomp.c/target-1.c: New test.


	Jakub

Comments

Jakub Jelinek Sept. 5, 2013, 8:24 a.m. UTC | #1
On Wed, Sep 04, 2013 at 08:54:47PM +0200, Jakub Jelinek wrote:
> Any issues you can spot in the patch?  If not, I'll commit it tomorrow, so
> that I can continue poking in these areas without too much pending stuff.

Committed now.

> Known issues that don't affect host fallback, but will be a problem
> for offloading (Richard or others, any thoughts about that?):
> 1) right now we pass a host fn address and a function name string
>    to GOMP_target.  For host execution we of course only need the fn
>    address, for offloading I guess libgomp will need to dlinfo
>    that fn address to find out what shared library (or binary) contains
>    it and somehow look for the special data section in it.
>    But, right now the *._omp_fn.N functions are always static, so there
>    is nothing to look up by name for Intel MIC, and if we wanted to make
>    the symbol global, we'd need to give it a shlib resp. binary unique
>    name; but if the containing function is not global, how can we do that?
>    Append get_file_function_name to the name?
> 2) much bigger problem seems to be global #pragma omp declare target
>    variables.  Those are supposed to be mapped from the beginning,
>    if they are just copied into the target LTO subset streaming, they will
>    be emitted normally as data variables.  But, unfortunately the
>    runtime must be aware of those mappings, because you can do stuff like:
> #pragma omp declare target
> int v = 1;
> #pragma omp end declare target
> void bar (int *p)
> {
>   #pragma omp target map(to:p[:1])
>   *p++;
> }
> void foo () { bar (&v); }
>    where the runtime should assign target's p copy the value of target's
>    v variable.  Or even for say #pragma omp target update.
>    So, on the host side, we need to prepare the triplets of host var
>    address, var size and during linking somehow supply it info on how
>    to create the target address, and have some function (one per
>    shared library resp. binary) that would locate the data section
>    within the shared library/binary for the requested accelerator
>    and with another argument call some libgomp function to initialize
>    the device data environment for the given shared library/binary
>    and accelerator.  Perhaps we could pass the address of such (.hidden)
>    function as yet another argument to GOMP_target call and
>    --as-needed link it from some *.a library?

Perhaps both of the above could be solved by (though, dunno about the
feasibility of doing it in the linker plugin):

1) GCC passes
extern char __OPENMP_TARGET__[] __attribute__((visibility ("hidden"), weak));
   &__OPENMP_TARGET__[0]
as the 3rd argument of GOMP_target call, rather than the name of the
function (and NULL on targets that don't support weak symbols or named
sections or visibility).  NULL will mean always fall back to host execution,
no support for offloading.
2) GCC emits struct { void *addr; uintptr_t size; } pairs into
   .gnu.openmp_target
   section for any non-extern vars declared in the TU with "omp declare target"
   attribute and for any *.omp_fn* functions passed to GOMP_target calls
   (with size 0).  For TREE_PUBLIC vars, perhaps we should emit !TREE_PUBLIC
   aliases and store those into the section instead.
3) during .gnu.target_lto* streaming, either those .gnu.openmp_target
   additions would be streamed too as is, or modified (only the addresses,
   leaving out sizes, which don't make sense)
4) when compiling target code and linking it, it would be important not to
   reorder the individual .gnu.openmp_target section additions in any way,
   so there is a 1:1 correspondence between the host array and target array
5) the lto linker plugin, when special handling the .gnu.target_lto*
   sections would also create the __OPENMP_TARGET__ symbol at the start
   of some magic section, fill in the section header at that point
   (likely some version number, number of supported targets, and for each
   of them address of the data blob in memory (or filename if it can't be
   in memory?), blob size, and pointer to the array of target addresses
   (unrelocated or something), plus the host .gnu.openmp_target content
   as array)
Then GOMP_target, if it sees NULL, would just do host fallback execution,
if it sees non-NULL in that argument and the device doesn't have that
loaded yet, it would read the info there to see if the target is supported,
find out how to load it (COI dlopen from memory, compile and ??? for
HSAIL/PTX), and initialize the mapping data structure from the host address,
size pairs in that array plus target array (after relocation?).
Then, for the function address, GOMP_target would just look up the function
address passed to it in the target mapping data structure.

	Jakub
Richard Biener Sept. 5, 2013, 10:07 a.m. UTC | #2
On Wed, Sep 4, 2013 at 8:54 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> Hi!
>
> This patch implements #pragma omp {target{, data, update},teams} lowering
> and expansion, and adds stub calls into libgomp, so that (for now
> unconditionally) we can at least always fall back to host execution.
>
> I still need to add testcases and test reference based array section
> handling and look at mapping of VLAs.
>
> Any issues you can spot in the patch?  If not, I'll commit it tomorrow, so
> that I can continue poking in these areas without too much pending stuff.
>
> Known issues that don't affect host fallback, but will be a problem
> for offloading (Richard or others, any thoughts about that?):
> 1) right now we pass a host fn address and a function name string
>    to GOMP_target.  For host execution we of course only need the fn
>    address, for offloading I guess libgomp will need to dlinfo
>    that fn address to find out what shared library (or binary) contains
>    it and somehow look for the special data section in it.
>    But, right now the *._omp_fn.N functions are always static, so there
>    is nothing to look up by name for Intel MIC, and if we wanted to make
>    the symbol global, we'd need to give it a shlib resp. binary unique
>    name; but if the containing function is not global, how can we do that?
>    Append get_file_function_name to the name?

I'd say we should pass the address of a descriptor instead that we
name specially.  Like

struct gomp_descr {
   void (*host_fn) ();
   void (*target_fns[]) ();
} __gomp_descr_N;

with N simply incrementing and the descriptor being local to the TU.
We initialize that with a reference to the outlined host function that
binds locally and external references to some private name (randomized
like we do for anonymous namespaces?).  The linker plugin then
needs to look for the descriptor symbols and from the host_fn address
lookup the function section with the LTO data for it.  From the extern
references it will know the symbol names to be used for the target(s)
implementation.

The descriptor above of course lacks metadata to identify the target fn
architecture.

> 2) much bigger problem seems to be global #pragma omp declare target
>    variables.  Those are supposed to be mapped from the beginning,
>    if they are just copied into the target LTO subset streaming, they will
>    be emitted normally as data variables.  But, unfortunately the
>    runtime must be aware of those mappings, because you can do stuff like:
> #pragma omp declare target
> int v = 1;
> #pragma omp end declare target
> void bar (int *p)
> {
>   #pragma omp target map(to:p[:1])
>   *p++;
> }
> void foo () { bar (&v); }
>    where the runtime should assign target's p copy the value of target's
>    v variable.  Or even for say #pragma omp target update.
>    So, on the host side, we need to prepare the triplets of host var
>    address, var size and during linking somehow supply it info on how
>    to create the target address, and have some function (one per
>    shared library resp. binary) that would locate the data section
>    within the shared library/binary for the requested accelerator
>    and with another argument call some libgomp function to initialize
>    the device data environment for the given shared library/binary
>    and accelerator.

A similar scheme as proposed above with the descriptor should work, no?
We can of course drop the descriptor as real data object and just stream
the symbol association in a special section.

Richard.

>    Perhaps we could pass the address of such (.hidden)
>    function as yet another argument to GOMP_target call and
>    --as-needed link it from some *.a library?
>
> 2013-09-04  Jakub Jelinek  <jakub@redhat.com>
>
>         * tree-cfg.c (make_edges): For GIMPLE_OMP_TARGET
>         with GF_OMP_TARGET_KIND_UPDATE, don't look for
>         GIMPLE_OMP_RETURN and immediately restore previous
>         region.
>         * langhooks.c (lhd_omp_mappable_type): New function.
>         * omp-low.c (scan_sharing_clauses): Ignore OMP_CLAUSE_SHARED
>         in GIMPLE_OMP_TEAMS constructs.  Handle OMP_CLAUSE_NUM_TEAMS,
>         OMP_CLAUSE_THREAD_LIMIT, OMP_CLAUSE_DEVICE, OMP_CLAUSE_MAP,
>         OMP_CLAUSE_TO and OMP_CLAUSE_FROM.
>         (create_omp_child_function): If current function has
>         "omp declare target" attribute or if current region
>         is OMP_TARGET or lexically nested in it, add that
>         attribute to the omp child function.
>         (scan_omp_target, scan_omp_teams): New functions.
>         (check_omp_nesting_restrictions): Fix a typo in TEAMS nesting
>         check.
>         (scan_omp_1_stmt): Handle GIMPLE_OMP_TARGET and GIMPLE_OMP_TEAMS.
>         (lower_rec_input_clauses): Ignore OMP_CLAUSE_SHARED
>         in GIMPLE_OMP_TEAMS constructs.
>         (expand_omp_synch): Handle GIMPLE_OMP_TEAMS.
>         (expand_omp_target): New function.
>         (expand_omp): Handle GIMPLE_OMP_TARGET and GIMPLE_OMP_TEAMS.
>         (build_omp_regions_1): For GIMPLE_OMP_TARGET with
>         GF_OMP_TARGET_KIND_UPDATE, don't look for GIMPLE_OMP_RETURN and
>         immediately restore previous region.
>         (lower_omp_single): Emit a CLOBBER stmt after GIMPLE_OMP_RETURN.
>         (lower_omp_taskreg): Likewise.
>         (lower_omp_target, lower_omp_teams): New functions.
>         (lower_omp_1): Handle GIMPLE_OMP_TARGET and GIMPLE_OMP_TEAMS.
>         * tree.h (enum omp_clause_map_kind): Improve description of
>         OMP_CLAUSE_MAP_POINTER.
>         (OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION): Define.
>         * gimple.def (GIMPLE_OMP_TARGET): Use GSS_OMP_PARALLEL instead
>         of GSS_OMP_SINGLE.
>         * langhooks.h (struct lang_hooks_for_types): Add
>         omp_mappable_type hook.
>         * langhooks-def.h (lhd_omp_mappable_type): New prototype.
>         (LANG_HOOKS_OMP_MAPPABLE_TYPE): Define.
>         (LANG_HOOKS_FOR_TYPES_INITIALIZER): Use it.
>         * gimple.h (gimple_omp_target_clauses, gimple_omp_target_clauses_ptr,
>         gimple_omp_target_set_clauses): Use gimple_omp_parallel
>         instead of gimple_omp_single.
>         (gimple_omp_target_child_fn, gimple_omp_target_child_fn_ptr,
>         gimple_omp_target_set_child_fn, gimple_omp_target_data_arg,
>         gimple_omp_target_data_arg_ptr, gimple_omp_target_set_data_arg): New
>         inlines.
>         * omp-builtins.def (BUILT_IN_GOMP_TARGET, BUILT_IN_GOMP_TARGET_DATA,
>         BUILT_IN_GOMP_TARGET_END_DATA, BUILT_IN_GOMP_TARGET_UPDATE,
>         BUILT_IN_GOMP_TEAMS): New builtins.
>         * gimple-pretty-print.c (dump_gimple_omp_target): Print child_fn
>         for #pragma omp target.
>         * gimplify.c (omp_notice_variable): Diagnose if implicitly mapped
>         decl doesn't have mappable type.
>         (gimplify_scan_omp_clauses): For OMP_CLAUSE_MAP don't clear
>         notice_outer.
>         (gimplify_adjust_omp_clauses_1): Add OMP_CLAUSE_MAP even if the same
>         decl is already referenced in target data construct surrounding it.
>         (gimplify_adjust_omp_clauses): Likewise.  Handle
>         OMP_CLAUSE_THREAD_LIMIT.
>         (gimplify_omp_workshare): Fix up gimplification of target or target
>         data construct body.  For target data add GOMP_target_end_data
>         call in a try/finally cleanup.
>         * builtin-types.def (BT_FN_VOID_UINT_UINT,
>         BT_FN_VOID_INT_SIZE_PTR_PTR_PTR,
>         BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR): New.
> c/
>         * c-typeck.c (handle_omp_array_sections_1): Remove pointer_based_p
>         argument.  Do c_save_expr on low bound unconditionally.
>         (handle_omp_array_sections): Adjust caller.  Call c_fully_fold when
>         needed.  Add OMP_CLAUSE_MAP_POINTER map clause even for array based
>         array sections.
>         (c_finish_omp_clauses): Don't complain about non-mappable types
>         for OMP_CLAUSE_MAP_POINTER.  Check for duplicates even for map
>         clauses.  Handle OMP_CLAUSE_NUM_TEAMS.
>         * c-parser.c (c_parser_omp_target_data, c_parser_omp_target): Call
>         keep_next_level ().
> cp/
>         * parser.c (cp_parser_omp_target_data, cp_parser_omp_target): Call
>         keep_next_level (true).
>         * cp-objcp-common.h (LANG_HOOKS_OMP_MAPPABLE_TYPE): Define.
>         * semantics.c (handle_omp_array_sections_1): Remove pointer_based_p
>         argument.  Do cp_save_expr on low bound unconditionally.
>         (handle_omp_array_sections): Adjust caller.  Add OMP_CLAUSE_MAP_POINTER
>         map clause even for array based array sections.
>         (finish_omp_clauses): Don't complain about non-mappable types
>         for OMP_CLAUSE_MAP_POINTER.  Check for duplicates even for map
>         clauses.
> fortran/
>         * types.def (BT_FN_VOID_UINT_UINT, BT_FN_VOID_INT_SIZE_PTR_PTR_PTR,
>         BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR): New.
> testsuite/
>         * c-c++-common/gomp/map-1.c (foo): Add dg-error for implicitly
>         mapped non-mappable var.
> libgomp/
>         * libgomp.map (GOMP_4.0): Add GOMP_target, GOMP_target_data,
>         GOMP_target_end_data, GOMP_target_update and GOMP_teams.
>         * Makefile.am (libgomp_la_SOURCES): Add target.c.
>         * Makefile.in: Regenerated.
>         * target.c: New file.
>         * libgomp_g.h (GOMP_target, GOMP_target_data,
>         GOMP_target_end_data, GOMP_target_update, GOMP_teams): New prototypes.
>         * testsuite/libgomp.c++/for-11.C (main): Uncomment
>         #pragma omp target teams directive.
>         * testsuite/libgomp.c/for-3.c (main): Likewise.
>         * testsuite/libgomp.c++/target-1.C: New test.
>         * testsuite/libgomp.c/target-1.c: New test.
>
> --- gcc/tree-cfg.c.jj   2013-08-27 20:53:36.000000000 +0200
> +++ gcc/tree-cfg.c      2013-09-02 13:55:36.591737508 +0200
> @@ -610,7 +610,6 @@ make_edges (void)
>             case GIMPLE_OMP_TASK:
>             case GIMPLE_OMP_FOR:
>             case GIMPLE_OMP_SINGLE:
> -           case GIMPLE_OMP_TARGET:
>             case GIMPLE_OMP_TEAMS:
>             case GIMPLE_OMP_MASTER:
>             case GIMPLE_OMP_ORDERED:
> @@ -620,6 +619,13 @@ make_edges (void)
>               fallthru = true;
>               break;
>
> +           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)
> +               cur_region = cur_region->outer;
> +             break;
> +
>             case GIMPLE_OMP_SECTIONS:
>               cur_region = new_omp_region (bb, code, cur_region);
>               fallthru = true;
> --- gcc/langhooks.c.jj  2013-08-27 20:53:03.000000000 +0200
> +++ gcc/langhooks.c     2013-09-04 19:30:55.551423852 +0200
> @@ -523,6 +523,15 @@ lhd_omp_firstprivatize_type_sizes (struc
>  {
>  }
>
> +/* Return true if TYPE is an OpenMP mappable type.  By default return true
> +   if type is complete.  */
> +
> +bool
> +lhd_omp_mappable_type (tree type)
> +{
> +  return COMPLETE_TYPE_P (type);
> +}
> +
>  /* Common function for add_builtin_function and
>     add_builtin_function_ext_scope.  */
>  static tree
> --- gcc/omp-low.c.jj    2013-08-27 22:44:31.000000000 +0200
> +++ gcc/omp-low.c       2013-09-04 19:58:30.320019227 +0200
> @@ -1453,6 +1453,9 @@ scan_sharing_clauses (tree clauses, omp_
>           break;
>
>         case OMP_CLAUSE_SHARED:
> +         /* Ignore shared directives in teams construct.  */
> +         if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS)
> +           break;
>           gcc_assert (is_taskreg_ctx (ctx));
>           decl = OMP_CLAUSE_DECL (c);
>           gcc_assert (!COMPLETE_TYPE_P (TREE_TYPE (decl))
> @@ -1533,6 +1536,9 @@ scan_sharing_clauses (tree clauses, omp_
>         case OMP_CLAUSE_FINAL:
>         case OMP_CLAUSE_IF:
>         case OMP_CLAUSE_NUM_THREADS:
> +       case OMP_CLAUSE_NUM_TEAMS:
> +       case OMP_CLAUSE_THREAD_LIMIT:
> +       case OMP_CLAUSE_DEVICE:
>         case OMP_CLAUSE_SCHEDULE:
>         case OMP_CLAUSE_DIST_SCHEDULE:
>         case OMP_CLAUSE_DEPEND:
> @@ -1540,6 +1546,66 @@ scan_sharing_clauses (tree clauses, omp_
>             scan_omp_op (&OMP_CLAUSE_OPERAND (c, 0), ctx->outer);
>           break;
>
> +       case OMP_CLAUSE_TO:
> +       case OMP_CLAUSE_FROM:
> +       case OMP_CLAUSE_MAP:
> +         if (ctx->outer)
> +           scan_omp_op (&OMP_CLAUSE_SIZE (c), ctx->outer);
> +         decl = OMP_CLAUSE_DECL (c);
> +         /* Global variables with "omp declare target" attribute
> +            don't need to be copied, the receiver side will use them
> +            directly.  */
> +         if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
> +             && DECL_P (decl)
> +             && is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx))
> +             && lookup_attribute ("omp declare target",
> +                                  DECL_ATTRIBUTES (decl)))
> +           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
> +                those.  */
> +             if (gimple_omp_target_kind (ctx->stmt) == GF_OMP_TARGET_KIND_DATA
> +                 && !POINTER_TYPE_P (TREE_TYPE (decl)))
> +               break;
> +           }
> +         if (DECL_P (decl))
> +           {
> +             install_var_field (decl, true, 3, ctx);
> +             if (gimple_omp_target_kind (ctx->stmt)
> +                 == GF_OMP_TARGET_KIND_REGION)
> +               install_var_local (decl, ctx);
> +           }
> +         else
> +           {
> +             tree base = get_base_address (decl);
> +             tree nc = OMP_CLAUSE_CHAIN (c);
> +             if (DECL_P (base)
> +                 && nc != NULL_TREE
> +                 && OMP_CLAUSE_CODE (nc) == OMP_CLAUSE_MAP
> +                 && OMP_CLAUSE_DECL (nc) == base
> +                 && OMP_CLAUSE_MAP_KIND (nc) == OMP_CLAUSE_MAP_POINTER
> +                 && integer_zerop (OMP_CLAUSE_SIZE (nc)))
> +               {
> +                 OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c) = 1;
> +                 OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (nc) = 1;
> +               }
> +             else
> +               {
> +                 gcc_assert (!splay_tree_lookup (ctx->field_map,
> +                                                 (splay_tree_key) decl));
> +                 tree field
> +                   = build_decl (OMP_CLAUSE_LOCATION (c),
> +                                 FIELD_DECL, NULL_TREE, ptr_type_node);
> +                 insert_field_into_struct (ctx->record_type, field);
> +                 splay_tree_insert (ctx->field_map, (splay_tree_key) decl,
> +                                    (splay_tree_value) field);
> +               }
> +           }
> +         break;
> +
>         case OMP_CLAUSE_NOWAIT:
>         case OMP_CLAUSE_ORDERED:
>         case OMP_CLAUSE_COLLAPSE:
> @@ -1590,16 +1656,46 @@ scan_sharing_clauses (tree clauses, omp_
>           break;
>
>         case OMP_CLAUSE_SHARED:
> +         /* Ignore shared directives in teams construct.  */
> +         if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS)
> +           break;
>           decl = OMP_CLAUSE_DECL (c);
>           if (! is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx)))
>             fixup_remapped_decl (decl, ctx, false);
>           break;
>
> +       case OMP_CLAUSE_MAP:
> +         if (gimple_omp_target_kind (ctx->stmt) == GF_OMP_TARGET_KIND_DATA)
> +           break;
> +         decl = OMP_CLAUSE_DECL (c);
> +         if (DECL_P (decl)
> +             && is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx))
> +             && lookup_attribute ("omp declare target",
> +                                  DECL_ATTRIBUTES (decl)))
> +           break;
> +         if (DECL_P (decl))
> +           {
> +             if (OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER
> +                 && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
> +                 && !COMPLETE_TYPE_P (TREE_TYPE (decl)))
> +               {
> +                 tree new_decl = lookup_decl (decl, ctx);
> +                 TREE_TYPE (new_decl)
> +                   = remap_type (TREE_TYPE (decl), &ctx->cb);
> +               }
> +             else
> +               fixup_remapped_decl (decl, ctx, false);
> +           }
> +         break;
> +
>         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:
> +       case OMP_CLAUSE_DEVICE:
>         case OMP_CLAUSE_SCHEDULE:
>         case OMP_CLAUSE_DIST_SCHEDULE:
>         case OMP_CLAUSE_NOWAIT:
> @@ -1613,6 +1709,8 @@ scan_sharing_clauses (tree clauses, omp_
>         case OMP_CLAUSE_ALIGNED:
>         case OMP_CLAUSE_DEPEND:
>         case OMP_CLAUSE__LOOPTEMP_:
> +       case OMP_CLAUSE_TO:
> +       case OMP_CLAUSE_FROM:
>           break;
>
>         default:
> @@ -1677,6 +1775,26 @@ create_omp_child_function (omp_context *
>    DECL_EXTERNAL (decl) = 0;
>    DECL_CONTEXT (decl) = NULL_TREE;
>    DECL_INITIAL (decl) = make_node (BLOCK);
> +  bool target_p = false;
> +  if (lookup_attribute ("omp declare target",
> +                       DECL_ATTRIBUTES (current_function_decl)))
> +    target_p = true;
> +  else
> +    {
> +      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)
> +         {
> +           target_p = true;
> +           break;
> +         }
> +    }
> +  if (target_p)
> +    DECL_ATTRIBUTES (decl)
> +      = tree_cons (get_identifier ("omp declare target"),
> +                  NULL_TREE, DECL_ATTRIBUTES (decl));
>
>    t = build_decl (DECL_SOURCE_LOCATION (decl),
>                   RESULT_DECL, NULL_TREE, void_type_node);
> @@ -1975,6 +2093,53 @@ scan_omp_single (gimple stmt, omp_contex
>      layout_type (ctx->record_type);
>  }
>
> +/* Scan an OpenMP target{, data, update} directive.  */
> +
> +static void
> +scan_omp_target (gimple stmt, omp_context *outer_ctx)
> +{
> +  omp_context *ctx;
> +  tree name;
> +  int kind = gimple_omp_target_kind (stmt);
> +
> +  ctx = new_omp_context (stmt, outer_ctx);
> +  ctx->field_map = splay_tree_new (splay_tree_compare_pointers, 0, 0);
> +  ctx->default_kind = OMP_CLAUSE_DEFAULT_SHARED;
> +  ctx->record_type = lang_hooks.types.make_type (RECORD_TYPE);
> +  name = create_tmp_var_name (".omp_data_t");
> +  name = build_decl (gimple_location (stmt),
> +                    TYPE_DECL, name, ctx->record_type);
> +  DECL_ARTIFICIAL (name) = 1;
> +  DECL_NAMELESS (name) = 1;
> +  TYPE_NAME (ctx->record_type) = name;
> +  if (kind == GF_OMP_TARGET_KIND_REGION)
> +    {
> +      create_omp_child_function (ctx, false);
> +      gimple_omp_target_set_child_fn (stmt, ctx->cb.dst_fn);
> +    }
> +
> +  scan_sharing_clauses (gimple_omp_target_clauses (stmt), ctx);
> +  scan_omp (gimple_omp_body_ptr (stmt), ctx);
> +
> +  if (TYPE_FIELDS (ctx->record_type) == NULL)
> +    ctx->record_type = ctx->receiver_decl = NULL;
> +  else
> +    {
> +      layout_type (ctx->record_type);
> +      if (kind == GF_OMP_TARGET_KIND_REGION)
> +       fixup_child_record_type (ctx);
> +    }
> +}
> +
> +/* Scan an OpenMP teams directive.  */
> +
> +static void
> +scan_omp_teams (gimple stmt, omp_context *outer_ctx)
> +{
> +  omp_context *ctx = new_omp_context (stmt, outer_ctx);
> +  scan_sharing_clauses (gimple_omp_teams_clauses (stmt), ctx);
> +  scan_omp (gimple_omp_body_ptr (stmt), ctx);
> +}
>
>  /* Check OpenMP nesting restrictions.  */
>  static bool
> @@ -1992,7 +2157,7 @@ check_omp_nesting_restrictions (gimple s
>        else if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS)
>         {
>           if ((gimple_code (stmt) != GIMPLE_OMP_FOR
> -              || (gimple_omp_for_kind (ctx->stmt)
> +              || (gimple_omp_for_kind (stmt)
>                    != GF_OMP_FOR_KIND_DISTRIBUTE))
>               && gimple_code (stmt) != GIMPLE_OMP_PARALLEL)
>             {
> @@ -2345,6 +2510,14 @@ scan_omp_1_stmt (gimple_stmt_iterator *g
>        scan_omp (gimple_omp_body_ptr (stmt), ctx);
>        break;
>
> +    case GIMPLE_OMP_TARGET:
> +      scan_omp_target (stmt, ctx);
> +      break;
> +
> +    case GIMPLE_OMP_TEAMS:
> +      scan_omp_teams (stmt, ctx);
> +      break;
> +
>      case GIMPLE_BIND:
>        {
>         tree var;
> @@ -2731,6 +2904,9 @@ lower_rec_input_clauses (tree clauses, g
>                 continue;
>               break;
>             case OMP_CLAUSE_SHARED:
> +             /* Ignore shared directives in teams construct.  */
> +             if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS)
> +               continue;
>               if (maybe_lookup_decl (OMP_CLAUSE_DECL (c), ctx) == NULL)
>                 {
>                   gcc_assert (is_global_var (OMP_CLAUSE_DECL (c)));
> @@ -2889,6 +3065,9 @@ lower_rec_input_clauses (tree clauses, g
>           switch (OMP_CLAUSE_CODE (c))
>             {
>             case OMP_CLAUSE_SHARED:
> +             /* Ignore shared directives in teams construct.  */
> +             if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS)
> +               continue;
>               /* Shared global vars are just accessed directly.  */
>               if (is_global_var (new_var))
>                 break;
> @@ -6728,7 +6907,8 @@ expand_omp_synch (struct omp_region *reg
>    gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SINGLE
>               || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_MASTER
>               || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ORDERED
> -             || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_CRITICAL);
> +             || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_CRITICAL
> +             || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_TEAMS);
>    gsi_remove (&si, true);
>    single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
>
> @@ -7317,6 +7497,318 @@ expand_omp_atomic (struct omp_region *re
>  }
>
>
> +/* Expand the OpenMP target{, data, update} directive 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;
> +  gimple_stmt_iterator gsi;
> +  gimple entry_stmt, stmt;
> +  edge e;
> +
> +  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)
> +    {
> +      child_fn = gimple_omp_target_child_fn (entry_stmt);
> +      child_cfun = DECL_STRUCT_FUNCTION (child_fn);
> +    }
> +
> +  entry_bb = region->entry;
> +  exit_bb = region->exit;
> +
> +  if (kind == GF_OMP_TARGET_KIND_REGION)
> +    {
> +      unsigned srcidx, dstidx, num;
> +
> +      /* If the target region needs data sent from the parent
> +        function, then the very first statement (except possible
> +        tree profile counter updates) of the parallel body
> +        is a copy assignment .OMP_DATA_I = &.OMP_DATA_O.  Since
> +        &.OMP_DATA_O is passed as an argument to the child function,
> +        we need to replace it with the argument as seen by the child
> +        function.
> +
> +        In most cases, this will end up being the identity assignment
> +        .OMP_DATA_I = .OMP_DATA_I.  However, if the parallel body had
> +        a function call that has been inlined, the original PARM_DECL
> +        .OMP_DATA_I may have been converted into a different local
> +        variable.  In which case, we need to keep the assignment.  */
> +      if (gimple_omp_target_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);
> +
> +         for (gsi = gsi_start_bb (entry_succ_bb); ; gsi_next (&gsi))
> +           {
> +             gcc_assert (!gsi_end_p (gsi));
> +             stmt = gsi_stmt (gsi);
> +             if (gimple_code (stmt) != GIMPLE_ASSIGN)
> +               continue;
> +
> +             if (gimple_num_ops (stmt) == 2)
> +               {
> +                 tree arg = gimple_assign_rhs1 (stmt);
> +
> +                 /* We're ignoring the subcode because we're
> +                    effectively doing a STRIP_NOPS.  */
> +
> +                 if (TREE_CODE (arg) == ADDR_EXPR
> +                     && TREE_OPERAND (arg, 0) == sender)
> +                   {
> +                     tgtcopy_stmt = stmt;
> +                     break;
> +                   }
> +               }
> +           }
> +
> +         gcc_assert (tgtcopy_stmt != NULL);
> +         arg = DECL_ARGUMENTS (child_fn);
> +
> +         gcc_assert (gimple_assign_lhs (tgtcopy_stmt) == arg);
> +         gsi_remove (&gsi, true);
> +       }
> +
> +      /* Declare local variables needed in CHILD_CFUN.  */
> +      block = DECL_INITIAL (child_fn);
> +      BLOCK_VARS (block) = vec2chain (child_cfun->local_decls);
> +      /* The gimplifier could record temporaries in target block
> +        rather than in containing function's local_decls chain,
> +        which would mean cgraph missed finalizing them.  Do it now.  */
> +      for (t = BLOCK_VARS (block); t; t = DECL_CHAIN (t))
> +       if (TREE_CODE (t) == VAR_DECL
> +           && TREE_STATIC (t)
> +           && !DECL_EXTERNAL (t))
> +         varpool_finalize_decl (t);
> +      DECL_SAVED_TREE (child_fn) = NULL;
> +      /* We'll create a CFG for child_fn, so no gimple body is needed.  */
> +      gimple_set_body (child_fn, NULL);
> +      TREE_USED (block) = 1;
> +
> +      /* Reset DECL_CONTEXT on function arguments.  */
> +      for (t = DECL_ARGUMENTS (child_fn); t; t = DECL_CHAIN (t))
> +       DECL_CONTEXT (t) = child_fn;
> +
> +      /* Split ENTRY_BB at GIMPLE_OMP_TARGET,
> +        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);
> +      gsi_remove (&gsi, true);
> +      e = split_block (entry_bb, stmt);
> +      entry_bb = e->dest;
> +      single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
> +
> +      /* Convert GIMPLE_OMP_RETURN into a RETURN_EXPR.  */
> +      if (exit_bb)
> +       {
> +         gsi = gsi_last_bb (exit_bb);
> +         gcc_assert (!gsi_end_p (gsi)
> +                     && gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
> +         stmt = gimple_build_return (NULL);
> +         gsi_insert_after (&gsi, stmt, GSI_SAME_STMT);
> +         gsi_remove (&gsi, true);
> +       }
> +
> +      /* Move the target region into CHILD_CFUN.  */
> +
> +      block = gimple_block (entry_stmt);
> +
> +      new_bb = move_sese_region_to_fn (child_cfun, entry_bb, exit_bb, block);
> +      if (exit_bb)
> +       single_succ_edge (new_bb)->flags = EDGE_FALLTHRU;
> +      /* When the OMP expansion process cannot guarantee an up-to-date
> +        loop tree arrange for the child function to fixup loops.  */
> +      if (loops_state_satisfies_p (LOOPS_NEED_FIXUP))
> +       child_cfun->x_current_loops->state |= LOOPS_NEED_FIXUP;
> +
> +      /* Remove non-local VAR_DECLs from child_cfun->local_decls list.  */
> +      num = vec_safe_length (child_cfun->local_decls);
> +      for (srcidx = 0, dstidx = 0; srcidx < num; srcidx++)
> +       {
> +         t = (*child_cfun->local_decls)[srcidx];
> +         if (DECL_CONTEXT (t) == cfun->decl)
> +           continue;
> +         if (srcidx != dstidx)
> +           (*child_cfun->local_decls)[dstidx] = t;
> +         dstidx++;
> +       }
> +      if (dstidx != num)
> +       vec_safe_truncate (child_cfun->local_decls, dstidx);
> +
> +      /* Inform the callgraph about the new function.  */
> +      DECL_STRUCT_FUNCTION (child_fn)->curr_properties = cfun->curr_properties;
> +      cgraph_add_new_function (child_fn, true);
> +
> +      /* Fix the callgraph edges for child_cfun.  Those for cfun will be
> +        fixed in a following pass.  */
> +      push_cfun (child_cfun);
> +      rebuild_cgraph_edges ();
> +
> +      /* Some EH regions might become dead, see PR34608.  If
> +        pass_cleanup_cfg isn't the first pass to happen with the
> +        new child, these dead EH edges might cause problems.
> +        Clean them up now.  */
> +      if (flag_exceptions)
> +       {
> +         basic_block bb;
> +         bool changed = false;
> +
> +         FOR_EACH_BB (bb)
> +           changed |= gimple_purge_dead_eh_edges (bb);
> +         if (changed)
> +           cleanup_tree_cfg ();
> +       }
> +      pop_cfun ();
> +    }
> +
> +  /* Emit a library call to launch the target region, or do data
> +     transfers.  */
> +  tree t1, t2, t3, t4, device, cond, c, clauses;
> +  enum built_in_function start_ix;
> +  location_t clause_loc;
> +
> +  clauses = gimple_omp_target_clauses (entry_stmt);
> +
> +  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;
> +
> +  /* By default, the value of DEVICE is -1 (let runtime library choose)
> +     and there is no conditional.  */
> +  cond = NULL_TREE;
> +  device = build_int_cst (integer_type_node, -1);
> +
> +  c = find_omp_clause (clauses, OMP_CLAUSE_IF);
> +  if (c)
> +    cond = OMP_CLAUSE_IF_EXPR (c);
> +
> +  c = find_omp_clause (clauses, OMP_CLAUSE_DEVICE);
> +  if (c)
> +    {
> +      device = OMP_CLAUSE_DEVICE_ID (c);
> +      clause_loc = OMP_CLAUSE_LOCATION (c);
> +    }
> +  else
> +    clause_loc = gimple_location (entry_stmt);
> +
> +  /* Ensure 'device' is of the correct type.  */
> +  device = fold_convert_loc (clause_loc, integer_type_node, device);
> +
> +  /* If we found the clause 'if (cond)', build
> +     (cond ? device : -2).  */
> +  if (cond)
> +    {
> +      cond = gimple_boolify (cond);
> +
> +      basic_block cond_bb, then_bb, else_bb;
> +      edge e;
> +      tree tmp_var;
> +
> +      tmp_var = create_tmp_var (TREE_TYPE (device), NULL);
> +      e = split_block (entry_bb, NULL);
> +      cond_bb = e->src;
> +      entry_bb = e->dest;
> +      remove_edge (e);
> +
> +      then_bb = create_empty_bb (cond_bb);
> +      else_bb = create_empty_bb (then_bb);
> +      set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);
> +      set_immediate_dominator (CDI_DOMINATORS, else_bb, cond_bb);
> +
> +      stmt = gimple_build_cond_empty (cond);
> +      gsi = gsi_start_bb (cond_bb);
> +      gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
> +
> +      gsi = gsi_start_bb (then_bb);
> +      stmt = gimple_build_assign (tmp_var, device);
> +      gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
> +
> +      gsi = gsi_start_bb (else_bb);
> +      stmt = gimple_build_assign (tmp_var,
> +                                 build_int_cst (integer_type_node, -2));
> +      gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
> +
> +      make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE);
> +      make_edge (cond_bb, else_bb, EDGE_FALSE_VALUE);
> +      if (current_loops)
> +       {
> +         add_bb_to_loop (then_bb, cond_bb->loop_father);
> +         add_bb_to_loop (else_bb, cond_bb->loop_father);
> +       }
> +      make_edge (then_bb, entry_bb, EDGE_FALLTHRU);
> +      make_edge (else_bb, entry_bb, EDGE_FALLTHRU);
> +
> +      device = tmp_var;
> +    }
> +
> +  gsi = gsi_last_bb (new_bb);
> +  t = gimple_omp_target_data_arg (entry_stmt);
> +  if (t == NULL)
> +    {
> +      t1 = size_zero_node;
> +      t2 = build_zero_cst (ptr_type_node);
> +      t3 = t2;
> +      t4 = t2;
> +    }
> +  else
> +    {
> +      t1 = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (TREE_VEC_ELT (t, 1))));
> +      t1 = size_binop (PLUS_EXPR, t1, size_int (1));
> +      t2 = build_fold_addr_expr (TREE_VEC_ELT (t, 0));
> +      t3 = build_fold_addr_expr (TREE_VEC_ELT (t, 1));
> +      t4 = build_fold_addr_expr (TREE_VEC_ELT (t, 2));
> +    }
> +
> +  gimple g;
> +  if (kind == GF_OMP_TARGET_KIND_REGION)
> +    {
> +      tree fnaddr = build_fold_addr_expr (child_fn);
> +      unsigned fnnamelen = IDENTIFIER_LENGTH (DECL_NAME (child_fn));
> +      tree fnname = build_string (fnnamelen,
> +                                 IDENTIFIER_POINTER (DECL_NAME (child_fn)));
> +      TREE_TYPE (fnname) = build_array_type_nelts (char_type_node,
> +                                                  fnnamelen);
> +      TREE_READONLY (fnname) = 1;
> +      TREE_STATIC (fnname) = 1;
> +      fnname = build_fold_addr_expr (fnname);
> +      g = gimple_build_call (builtin_decl_explicit (start_ix), 7,
> +                            device, fnaddr, fnname, t1, t2, t3, t4);
> +    }
> +  else
> +    g = gimple_build_call (builtin_decl_explicit (start_ix), 5,
> +                          device, t1, t2, t3, t4);
> +  gimple_set_location (g, gimple_location (entry_stmt));
> +  gsi_insert_before (&gsi, g, GSI_SAME_STMT);
> +  if (kind != GF_OMP_TARGET_KIND_REGION)
> +    {
> +      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)
> +    {
> +      gsi = gsi_last_bb (region->exit);
> +      g = gsi_stmt (gsi);
> +      gcc_assert (g && gimple_code (g) == GIMPLE_OMP_RETURN);
> +      gsi_remove (&gsi, true);
> +    }
> +}
> +
> +
>  /* Expand the parallel region tree rooted at REGION.  Expansion
>     proceeds in depth-first order.  Innermost regions are expanded
>     first.  This way, parallel regions that require a new function to
> @@ -7374,6 +7866,7 @@ expand_omp (struct omp_region *region)
>         case GIMPLE_OMP_MASTER:
>         case GIMPLE_OMP_ORDERED:
>         case GIMPLE_OMP_CRITICAL:
> +       case GIMPLE_OMP_TEAMS:
>           expand_omp_synch (region);
>           break;
>
> @@ -7381,6 +7874,10 @@ expand_omp (struct omp_region *region)
>           expand_omp_atomic (region);
>           break;
>
> +       case GIMPLE_OMP_TARGET:
> +         expand_omp_target (region);
> +         break;
> +
>         default:
>           gcc_unreachable ();
>         }
> @@ -7445,6 +7942,9 @@ build_omp_regions_1 (basic_block bb, str
>              GIMPLE_OMP_SECTIONS, and we do nothing for it.  */
>           ;
>         }
> +      else if (code == GIMPLE_OMP_TARGET
> +              && gimple_omp_target_kind (stmt) == GF_OMP_TARGET_KIND_UPDATE)
> +       new_omp_region (bb, code, parent);
>        else
>         {
>           /* Otherwise, this directive becomes the parent for a new
> @@ -7825,7 +8325,7 @@ lower_omp_single (gimple_stmt_iterator *
>  {
>    tree block;
>    gimple t, bind, single_stmt = gsi_stmt (*gsi_p);
> -  gimple_seq bind_body, dlist;
> +  gimple_seq bind_body, bind_body_tail = NULL, dlist;
>    struct gimplify_ctx gctx;
>
>    push_gimplify_context (&gctx);
> @@ -7855,8 +8355,17 @@ lower_omp_single (gimple_stmt_iterator *
>    t = gimple_build_omp_return
>          (!!find_omp_clause (gimple_omp_single_clauses (single_stmt),
>                             OMP_CLAUSE_NOWAIT));
> -  gimple_seq_add_stmt (&bind_body, t);
> -  maybe_add_implicit_barrier_cancel (ctx, &bind_body);
> +  gimple_seq_add_stmt (&bind_body_tail, t);
> +  maybe_add_implicit_barrier_cancel (ctx, &bind_body_tail);
> +  if (ctx->record_type)
> +    {
> +      gimple_stmt_iterator gsi = gsi_start (bind_body_tail);
> +      tree clobber = build_constructor (ctx->record_type, NULL);
> +      TREE_THIS_VOLATILE (clobber) = 1;
> +      gsi_insert_after (&gsi, gimple_build_assign (ctx->sender_decl,
> +                                                  clobber), GSI_SAME_STMT);
> +    }
> +  gimple_seq_add_seq (&bind_body, bind_body_tail);
>    gimple_bind_set_body (bind, bind_body);
>
>    pop_gimplify_context (bind);
> @@ -8605,6 +9114,14 @@ lower_omp_taskreg (gimple_stmt_iterator
>    lower_send_clauses (clauses, &ilist, &olist, ctx);
>    lower_send_shared_vars (&ilist, &olist, ctx);
>
> +  if (ctx->record_type)
> +    {
> +      tree clobber = build_constructor (TREE_TYPE (ctx->sender_decl), NULL);
> +      TREE_THIS_VOLATILE (clobber) = 1;
> +      gimple_seq_add_stmt (&olist, gimple_build_assign (ctx->sender_decl,
> +                                                       clobber));
> +    }
> +
>    /* Once all the expansions are done, sequence all the different
>       fragments inside gimple_omp_body.  */
>
> @@ -8637,6 +9154,326 @@ lower_omp_taskreg (gimple_stmt_iterator
>    pop_gimplify_context (NULL);
>  }
>
> +/* Lower the OpenMP target directive in the current statement
> +   in GSI_P.  CTX holds context information for the directive.  */
> +
> +static void
> +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;
> +  struct gimplify_ctx gctx;
> +  location_t loc = gimple_location (stmt);
> +  int kind = gimple_omp_target_kind (stmt);
> +  unsigned int map_cnt = 0;
> +
> +  clauses = gimple_omp_target_clauses (stmt);
> +  if (kind == GF_OMP_TARGET_KIND_REGION)
> +    {
> +      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)
> +    tgt_body = gimple_omp_body (stmt);
> +  child_fn = ctx->cb.dst_fn;
> +
> +  push_gimplify_context (&gctx);
> +
> +  for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
> +    switch (OMP_CLAUSE_CODE (c))
> +      {
> +       tree var, x;
> +
> +      default:
> +       break;
> +      case OMP_CLAUSE_MAP:
> +      case OMP_CLAUSE_TO:
> +      case OMP_CLAUSE_FROM:
> +       var = OMP_CLAUSE_DECL (c);
> +       if (!DECL_P (var))
> +         {
> +           if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP
> +               || !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c))
> +             map_cnt++;
> +           continue;
> +         }
> +       if (!lookup_sfield (var, ctx))
> +         continue;
> +
> +       if (kind == GF_OMP_TARGET_KIND_REGION)
> +         {
> +           x = build_receiver_ref (var, true, ctx);
> +           tree new_var = lookup_decl (var, ctx);
> +           SET_DECL_VALUE_EXPR (new_var, x);
> +           DECL_HAS_VALUE_EXPR_P (new_var) = 1;
> +         }
> +       map_cnt++;
> +      }
> +
> +  if (kind != GF_OMP_TARGET_KIND_UPDATE)
> +    lower_omp (&tgt_body, ctx);
> +
> +  if (kind == GF_OMP_TARGET_KIND_REGION)
> +    {
> +      /* Declare all the variables created by mapping and the variables
> +        declared in the scope of the target body.  */
> +      record_vars_into (ctx->block_vars, child_fn);
> +      record_vars_into (gimple_bind_vars (tgt_bind), child_fn);
> +    }
> +
> +  olist = NULL;
> +  ilist = NULL;
> +  if (ctx->record_type)
> +    {
> +      ctx->sender_decl
> +       = create_tmp_var (ctx->record_type, ".omp_data_arr");
> +      DECL_NAMELESS (ctx->sender_decl) = 1;
> +      TREE_ADDRESSABLE (ctx->sender_decl) = 1;
> +      t = make_tree_vec (3);
> +      TREE_VEC_ELT (t, 0) = ctx->sender_decl;
> +      TREE_VEC_ELT (t, 1)
> +       = create_tmp_var (build_array_type_nelts (size_type_node, map_cnt),
> +                         ".omp_data_sizes");
> +      DECL_NAMELESS (TREE_VEC_ELT (t, 1)) = 1;
> +      TREE_ADDRESSABLE (TREE_VEC_ELT (t, 1)) = 1;
> +      TREE_STATIC (TREE_VEC_ELT (t, 1)) = 1;
> +      TREE_VEC_ELT (t, 2)
> +       = create_tmp_var (build_array_type_nelts (unsigned_char_type_node,
> +                                                 map_cnt),
> +                         ".omp_data_kinds");
> +      DECL_NAMELESS (TREE_VEC_ELT (t, 2)) = 1;
> +      TREE_ADDRESSABLE (TREE_VEC_ELT (t, 2)) = 1;
> +      TREE_STATIC (TREE_VEC_ELT (t, 2)) = 1;
> +      gimple_omp_target_set_data_arg (stmt, t);
> +
> +      vec<constructor_elt, va_gc> *vsize;
> +      vec<constructor_elt, va_gc> *vkind;
> +      vec_alloc (vsize, map_cnt);
> +      vec_alloc (vkind, map_cnt);
> +      unsigned int map_idx = 0;
> +
> +      for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
> +       switch (OMP_CLAUSE_CODE (c))
> +         {
> +           tree ovar, nc;
> +
> +         default:
> +           break;
> +         case OMP_CLAUSE_MAP:
> +         case OMP_CLAUSE_TO:
> +         case OMP_CLAUSE_FROM:
> +           nc = c;
> +           ovar = OMP_CLAUSE_DECL (c);
> +           if (!DECL_P (ovar))
> +             {
> +               if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
> +                   && OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c))
> +                 {
> +                   gcc_checking_assert (OMP_CLAUSE_DECL (OMP_CLAUSE_CHAIN (c))
> +                                        == get_base_address (ovar));
> +                   nc = OMP_CLAUSE_CHAIN (c);
> +                   ovar = OMP_CLAUSE_DECL (nc);
> +                 }
> +               else
> +                 {
> +                   tree x = build_sender_ref (ovar, ctx);
> +                   tree v
> +                     = build_fold_addr_expr_with_type (ovar, ptr_type_node);
> +                   gimplify_assign (x, v, &ilist);
> +                   nc = NULL_TREE;
> +                 }
> +             }
> +           else if (!lookup_sfield (ovar, ctx))
> +             continue;
> +
> +           if (nc)
> +             {
> +               tree var = lookup_decl_in_outer_ctx (ovar, ctx);
> +               tree x = build_sender_ref (ovar, ctx);
> +               if (is_gimple_reg (var))
> +                 {
> +                   gcc_assert (kind == GF_OMP_TARGET_KIND_REGION);
> +                   tree avar = create_tmp_var (TREE_TYPE (var), NULL);
> +                   mark_addressable (avar);
> +                   if (OMP_CLAUSE_MAP_KIND (c) != OMP_CLAUSE_MAP_ALLOC
> +                       && OMP_CLAUSE_MAP_KIND (c) != OMP_CLAUSE_MAP_FROM)
> +                     gimplify_assign (avar, var, &ilist);
> +                   avar = build_fold_addr_expr (avar);
> +                   gimplify_assign (x, avar, &ilist);
> +                   if ((OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_FROM
> +                        || OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_TOFROM)
> +                       && !TYPE_READONLY (TREE_TYPE (var)))
> +                     {
> +                       x = build_sender_ref (ovar, ctx);
> +                       x = build_simple_mem_ref (x);
> +                       gimplify_assign (var, x, &olist);
> +                     }
> +                 }
> +               else
> +                 {
> +                   var = build_fold_addr_expr (var);
> +                   gimplify_assign (x, var, &ilist);
> +                 }
> +             }
> +           tree s = OMP_CLAUSE_SIZE (c);
> +           if (s == NULL_TREE)
> +             s = TYPE_SIZE (TREE_TYPE (ovar));
> +           s = fold_convert (size_type_node, s);
> +           tree purpose = size_int (map_idx++);
> +           CONSTRUCTOR_APPEND_ELT (vsize, purpose, s);
> +           if (TREE_CODE (s) != INTEGER_CST)
> +             TREE_STATIC (TREE_VEC_ELT (t, 1)) = 0;
> +
> +           unsigned char tkind = 0;
> +           switch (OMP_CLAUSE_CODE (c))
> +             {
> +             case OMP_CLAUSE_MAP:
> +               tkind = OMP_CLAUSE_MAP_KIND (c);
> +               break;
> +             case OMP_CLAUSE_TO:
> +               tkind = OMP_CLAUSE_MAP_TO;
> +               break;
> +             case OMP_CLAUSE_FROM:
> +               tkind = OMP_CLAUSE_MAP_FROM;
> +               break;
> +             default:
> +               gcc_unreachable ();
> +             }
> +           CONSTRUCTOR_APPEND_ELT (vkind, purpose,
> +                                   build_int_cst (unsigned_char_type_node,
> +                                                  tkind));
> +           if (nc && nc != c)
> +             c = nc;
> +         }
> +
> +      gcc_assert (map_idx == map_cnt);
> +
> +      DECL_INITIAL (TREE_VEC_ELT (t, 1))
> +       = build_constructor (TREE_TYPE (TREE_VEC_ELT (t, 1)), vsize);
> +      DECL_INITIAL (TREE_VEC_ELT (t, 2))
> +       = build_constructor (TREE_TYPE (TREE_VEC_ELT (t, 2)), vkind);
> +      if (!TREE_STATIC (TREE_VEC_ELT (t, 1)))
> +       {
> +         gimple_seq initlist = NULL;
> +         force_gimple_operand (build1 (DECL_EXPR, void_type_node,
> +                                       TREE_VEC_ELT (t, 1)),
> +                               &initlist, true, NULL_TREE);
> +         gimple_seq_add_seq (&ilist, initlist);
> +       }
> +
> +      tree clobber = build_constructor (ctx->record_type, NULL);
> +      TREE_THIS_VOLATILE (clobber) = 1;
> +      gimple_seq_add_stmt (&olist, gimple_build_assign (ctx->sender_decl,
> +                                                       clobber));
> +    }
> +
> +  /* Once all the expansions are done, sequence all the different
> +     fragments inside gimple_omp_body.  */
> +
> +  new_body = NULL;
> +
> +  if (ctx->record_type && kind == GF_OMP_TARGET_KIND_REGION)
> +    {
> +      t = build_fold_addr_expr_loc (loc, ctx->sender_decl);
> +      /* fixup_child_record_type might have changed receiver_decl's type.  */
> +      t = fold_convert_loc (loc, TREE_TYPE (ctx->receiver_decl), t);
> +      gimple_seq_add_stmt (&new_body,
> +                          gimple_build_assign (ctx->receiver_decl, t));
> +    }
> +
> +  if (kind == GF_OMP_TARGET_KIND_REGION)
> +    {
> +      gimple_seq_add_seq (&new_body, tgt_body);
> +      new_body = maybe_catch_exception (new_body);
> +    }
> +  else if (kind == GF_OMP_TARGET_KIND_DATA)
> +    new_body = tgt_body;
> +  if (kind != GF_OMP_TARGET_KIND_UPDATE)
> +    {
> +      gimple_seq_add_stmt (&new_body, gimple_build_omp_return (false));
> +      gimple_omp_set_body (stmt, new_body);
> +    }
> +
> +  bind = gimple_build_bind (NULL, NULL,
> +                           tgt_bind ? gimple_bind_block (tgt_bind)
> +                                    : NULL_TREE);
> +  gsi_replace (gsi_p, bind, true);
> +  gimple_bind_add_seq (bind, ilist);
> +  gimple_bind_add_stmt (bind, stmt);
> +  gimple_bind_add_seq (bind, olist);
> +
> +  pop_gimplify_context (NULL);
> +}
> +
> +/* Expand code for an OpenMP teams directive.  */
> +
> +static void
> +lower_omp_teams (gimple_stmt_iterator *gsi_p, omp_context *ctx)
> +{
> +  gimple teams_stmt = gsi_stmt (*gsi_p);
> +  struct gimplify_ctx gctx;
> +  push_gimplify_context (&gctx);
> +
> +  tree block = make_node (BLOCK);
> +  gimple bind = gimple_build_bind (NULL, NULL, block);
> +  gsi_replace (gsi_p, bind, true);
> +  gimple_seq bind_body = NULL;
> +  gimple_seq dlist = NULL;
> +  gimple_seq olist = NULL;
> +
> +  tree num_teams = find_omp_clause (gimple_omp_teams_clauses (teams_stmt),
> +                                   OMP_CLAUSE_NUM_TEAMS);
> +  if (num_teams == NULL_TREE)
> +    num_teams = build_int_cst (unsigned_type_node, 0);
> +  else
> +    {
> +      num_teams = OMP_CLAUSE_NUM_TEAMS_EXPR (num_teams);
> +      num_teams = fold_convert (unsigned_type_node, num_teams);
> +      gimplify_expr (&num_teams, &bind_body, NULL, is_gimple_val, fb_rvalue);
> +    }
> +  tree thread_limit = find_omp_clause (gimple_omp_teams_clauses (teams_stmt),
> +                                      OMP_CLAUSE_THREAD_LIMIT);
> +  if (thread_limit == NULL_TREE)
> +    thread_limit = build_int_cst (unsigned_type_node, 0);
> +  else
> +    {
> +      thread_limit = OMP_CLAUSE_THREAD_LIMIT_EXPR (thread_limit);
> +      thread_limit = fold_convert (unsigned_type_node, thread_limit);
> +      gimplify_expr (&thread_limit, &bind_body, NULL, is_gimple_val,
> +                    fb_rvalue);
> +    }
> +
> +  lower_rec_input_clauses (gimple_omp_teams_clauses (teams_stmt),
> +                          &bind_body, &dlist, ctx, NULL);
> +  lower_omp (gimple_omp_body_ptr (teams_stmt), ctx);
> +  lower_reduction_clauses (gimple_omp_teams_clauses (teams_stmt), &olist, ctx);
> +  gimple_seq_add_stmt (&bind_body, teams_stmt);
> +
> +  location_t loc = gimple_location (teams_stmt);
> +  tree decl = builtin_decl_explicit (BUILT_IN_GOMP_TEAMS);
> +  gimple call = gimple_build_call (decl, 2, num_teams, thread_limit);
> +  gimple_set_location (call, loc);
> +  gimple_seq_add_stmt (&bind_body, call);
> +
> +  gimple_seq_add_seq (&bind_body, gimple_omp_body (teams_stmt));
> +  gimple_omp_set_body (teams_stmt, NULL);
> +  gimple_seq_add_seq (&bind_body, olist);
> +  gimple_seq_add_seq (&bind_body, dlist);
> +  gimple_seq_add_stmt (&bind_body, gimple_build_omp_return (true));
> +  gimple_bind_set_body (bind, bind_body);
> +
> +  pop_gimplify_context (bind);
> +
> +  gimple_bind_append_vars (bind, ctx->block_vars);
> +  BLOCK_VARS (block) = ctx->block_vars;
> +  if (BLOCK_VARS (block))
> +    TREE_USED (block) = 1;
> +}
> +
> +
>  /* Callback for lower_omp_1.  Return non-NULL if *tp needs to be
>     regimplified.  If DATA is non-NULL, lower_omp_1 is outside
>     of OpenMP context, but with task_shared_vars set.  */
> @@ -8760,6 +9597,16 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p
>                         lower_omp_regimplify_p, ctx ? NULL : &wi, NULL))
>         gimple_regimplify_operands (stmt, gsi_p);
>        break;
> +    case GIMPLE_OMP_TARGET:
> +      ctx = maybe_lookup_ctx (stmt);
> +      gcc_assert (ctx);
> +      lower_omp_target (gsi_p, ctx);
> +      break;
> +    case GIMPLE_OMP_TEAMS:
> +      ctx = maybe_lookup_ctx (stmt);
> +      gcc_assert (ctx);
> +      lower_omp_teams (gsi_p, ctx);
> +      break;
>      case GIMPLE_CALL:
>        tree fndecl;
>        fndecl = gimple_call_fndecl (stmt);
> --- gcc/c/c-typeck.c.jj 2013-08-27 20:49:05.000000000 +0200
> +++ gcc/c/c-typeck.c    2013-09-04 17:21:17.295112407 +0200
> @@ -10773,8 +10773,7 @@ c_finish_omp_cancellation_point (locatio
>
>  static tree
>  handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
> -                            bool &maybe_zero_len, unsigned int &first_non_one,
> -                            bool &pointer_based_p)
> +                            bool &maybe_zero_len, unsigned int &first_non_one)
>  {
>    tree ret, low_bound, length, type;
>    if (TREE_CODE (t) != TREE_LIST)
> @@ -10801,15 +10800,11 @@ handle_omp_array_sections_1 (tree c, tre
>                     omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
>           return error_mark_node;
>         }
> -      if (POINTER_TYPE_P (TREE_TYPE (t))
> -         && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP)
> -       pointer_based_p = true;
>        return t;
>      }
>
>    ret = handle_omp_array_sections_1 (c, TREE_CHAIN (t), types,
> -                                    maybe_zero_len, first_non_one,
> -                                    pointer_based_p);
> +                                    maybe_zero_len, first_non_one);
>    if (ret == error_mark_node || ret == NULL_TREE)
>      return ret;
>
> @@ -10989,16 +10984,12 @@ handle_omp_array_sections_1 (tree c, tre
>      }
>    if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND)
>      types.safe_push (TREE_TYPE (ret));
> -  /* For pointer based array sections we will need to evaluate lb more
> -     than once.  */
> -  if (pointer_based_p)
> +  /* We will need to evaluate lb more than once.  */
> +  tree lb = c_save_expr (low_bound);
> +  if (lb != low_bound)
>      {
> -      tree lb = c_save_expr (low_bound);
> -      if (lb != low_bound)
> -       {
> -         TREE_PURPOSE (t) = lb;
> -         low_bound = lb;
> -       }
> +      TREE_PURPOSE (t) = lb;
> +      low_bound = lb;
>      }
>    ret = build_array_ref (OMP_CLAUSE_LOCATION (c), ret, low_bound);
>    return ret;
> @@ -11010,12 +11001,10 @@ static bool
>  handle_omp_array_sections (tree c)
>  {
>    bool maybe_zero_len = false;
> -  bool pointer_based_p = false;
>    unsigned int first_non_one = 0;
>    vec<tree> types = vNULL;
>    tree first = handle_omp_array_sections_1 (c, OMP_CLAUSE_DECL (c), types,
> -                                           maybe_zero_len, first_non_one,
> -                                           pointer_based_p);
> +                                           maybe_zero_len, first_non_one);
>    if (first == error_mark_node)
>      {
>        types.release ();
> @@ -11047,6 +11036,7 @@ handle_omp_array_sections (tree c)
>         }
>        if (tem)
>         first = build2 (COMPOUND_EXPR, TREE_TYPE (first), tem, first);
> +      first = c_fully_fold (first, false, NULL);
>        OMP_CLAUSE_DECL (c) = first;
>      }
>    else
> @@ -11155,27 +11145,31 @@ handle_omp_array_sections (tree c)
>        types.release ();
>        if (side_effects)
>         size = build2 (COMPOUND_EXPR, sizetype, side_effects, size);
> +      first = c_fully_fold (first, false, NULL);
>        OMP_CLAUSE_DECL (c) = first;
> +      if (size)
> +       size = c_fully_fold (size, false, NULL);
>        OMP_CLAUSE_SIZE (c) = size;
> -      if (pointer_based_p)
> -       {
> -         tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP);
> -         OMP_CLAUSE_MAP_KIND (c2) = OMP_CLAUSE_MAP_POINTER;
> -         if (!c_mark_addressable (t))
> -           return false;
> -         OMP_CLAUSE_DECL (c2) = t;
> -         t = build_fold_addr_expr (first);
> -         t = fold_convert_loc (OMP_CLAUSE_LOCATION (c),
> -                               build_pointer_type (char_type_node), t);
> -         t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR,
> -                              ptrdiff_type_node, t,
> -                              fold_convert_loc (OMP_CLAUSE_LOCATION (c),
> -                                                TREE_TYPE (t),
> -                                                OMP_CLAUSE_DECL (c2)));
> -         OMP_CLAUSE_SIZE (c2) = t;
> -         OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c);
> -         OMP_CLAUSE_CHAIN (c) = c2;
> -       }
> +      if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP)
> +       return false;
> +      tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP);
> +      OMP_CLAUSE_MAP_KIND (c2) = OMP_CLAUSE_MAP_POINTER;
> +      if (!c_mark_addressable (t))
> +       return false;
> +      OMP_CLAUSE_DECL (c2) = t;
> +      t = build_fold_addr_expr (first);
> +      t = fold_convert_loc (OMP_CLAUSE_LOCATION (c), ptrdiff_type_node, t);
> +      tree ptr = OMP_CLAUSE_DECL (c2);
> +      if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
> +       ptr = build_fold_addr_expr (ptr);
> +      t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR,
> +                          ptrdiff_type_node, t,
> +                          fold_convert_loc (OMP_CLAUSE_LOCATION (c),
> +                                            ptrdiff_type_node, ptr));
> +      t = c_fully_fold (t, false, NULL);
> +      OMP_CLAUSE_SIZE (c2) = t;
> +      OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c);
> +      OMP_CLAUSE_CHAIN (c) = c2;
>      }
>    return false;
>  }
> @@ -11462,18 +11456,21 @@ c_finish_omp_clauses (tree clauses)
>             }
>           else if (!c_mark_addressable (t))
>             remove = true;
> -         else if (!COMPLETE_TYPE_P (TREE_TYPE (t)))
> +         else if (!COMPLETE_TYPE_P (TREE_TYPE (t))
> +                  && !(OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
> +                       && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER))
>             {
>               error_at (OMP_CLAUSE_LOCATION (c),
>                         "%qD does not have a mappable type in %qs clause", t,
>                         omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
>               remove = true;
>             }
> -         else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP)
> -           break;
>           else if (bitmap_bit_p (&generic_head, DECL_UID (t)))
>             {
> -             error ("%qD appears more than once in motion clauses", t);
> +             if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP)
> +               error ("%qD appears more than once in motion clauses", t);
> +             else
> +               error ("%qD appears more than once in map clauses", t);
>               remove = true;
>             }
>           else
> @@ -11509,6 +11506,7 @@ c_finish_omp_clauses (tree clauses)
>
>         case OMP_CLAUSE_IF:
>         case OMP_CLAUSE_NUM_THREADS:
> +       case OMP_CLAUSE_NUM_TEAMS:
>         case OMP_CLAUSE_THREAD_LIMIT:
>         case OMP_CLAUSE_SCHEDULE:
>         case OMP_CLAUSE_ORDERED:
> --- gcc/c/c-parser.c.jj 2013-08-27 20:49:04.000000000 +0200
> +++ gcc/c/c-parser.c    2013-09-02 11:41:51.023319550 +0200
> @@ -12068,7 +12068,10 @@ c_parser_omp_target_data (location_t loc
>    OMP_TARGET_DATA_CLAUSES (stmt)
>      = c_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK,
>                                 "#pragma omp target data");
> -  OMP_TARGET_DATA_BODY (stmt) = c_parser_omp_structured_block (parser);
> +  keep_next_level ();
> +  tree block = c_begin_compound_stmt (true);
> +  add_stmt (c_parser_omp_structured_block (parser));
> +  OMP_TARGET_DATA_BODY (stmt) = c_end_compound_stmt (loc, block, true);
>
>    SET_EXPR_LOCATION (stmt, loc);
>    return add_stmt (stmt);
> @@ -12161,6 +12164,7 @@ c_parser_omp_target (c_parser *parser, e
>
>           c_parser_consume_token (parser);
>           strcpy (p_name, "#pragma omp target");
> +         keep_next_level ();
>           tree block = c_begin_compound_stmt (true);
>           tree ret = c_parser_omp_teams (loc, parser, p_name,
>                                          OMP_TARGET_CLAUSE_MASK, cclauses);
> @@ -12182,7 +12186,10 @@ c_parser_omp_target (c_parser *parser, e
>    OMP_TARGET_CLAUSES (stmt)
>      = c_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK,
>                                 "#pragma omp target");
> -  OMP_TARGET_BODY (stmt) = c_parser_omp_structured_block (parser);
> +  keep_next_level ();
> +  tree block = c_begin_compound_stmt (true);
> +  add_stmt (c_parser_omp_structured_block (parser));
> +  OMP_TARGET_BODY (stmt) = c_end_compound_stmt (loc, block, true);
>
>    SET_EXPR_LOCATION (stmt, loc);
>    add_stmt (stmt);
> --- gcc/tree.h.jj       2013-08-27 22:05:43.000000000 +0200
> +++ gcc/tree.h  2013-09-03 14:35:36.350942556 +0200
> @@ -629,6 +629,9 @@ struct GTY(()) tree_base {
>         OMP_CLAUSE_LINEAR_NO_COPYIN in
>            OMP_CLAUSE_LINEAR
>
> +       OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION in
> +          OMP_CLAUSE_MAP
> +
>         TRANSACTION_EXPR_RELAXED in
>            TRANSACTION_EXPR
>
> @@ -2050,15 +2053,21 @@ enum omp_clause_map_kind
>    OMP_CLAUSE_MAP_TO,
>    OMP_CLAUSE_MAP_FROM,
>    OMP_CLAUSE_MAP_TOFROM,
> -  /* This following 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 / BITS_PER_UNIT, but the bias.  */
> +  /* 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 / BITS_PER_UNIT, but the bias.  */
>    OMP_CLAUSE_MAP_POINTER
>  };
>
>  #define OMP_CLAUSE_MAP_KIND(NODE) \
>    (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)->omp_clause.subcode.map_kind)
>
> +/* Nonzero if this map clause is for array (rather than pointer) based array
> +   section with zero bias.  Both the non-decl OMP_CLAUSE_MAP and
> +   correspoidng OMP_CLAUSE_MAP_POINTER clause are marked with this flag.  */
> +#define OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION(NODE) \
> +  (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)->base.public_flag)
> +
>  enum omp_clause_proc_bind_kind
>  {
>    /* Numbers should match omp_proc_bind_t enum in omp.h.  */
> --- gcc/gimple.def.jj   2013-08-19 12:07:51.000000000 +0200
> +++ gcc/gimple.def      2013-09-02 11:55:57.892684945 +0200
> @@ -349,12 +349,18 @@ DEFGSCODE(GIMPLE_OMP_SECTIONS_SWITCH, "g
>     CLAUSES is an OMP_CLAUSE chain holding the associated clauses.  */
>  DEFGSCODE(GIMPLE_OMP_SINGLE, "gimple_omp_single", GSS_OMP_SINGLE)
>
> -/* GIMPLE_OMP_TARGET <BODY, CLAUSES> represents
> +/* GIMPLE_OMP_TARGET <BODY, CLAUSES, CHILD_FN> represents
>     #pragma omp target {,data,update}
>     BODY is the sequence of statements inside the target construct
>     (NULL for target update).
> -   CLAUSES is an OMP_CLAUSE chain holding the associated clauses.  */
> -DEFGSCODE(GIMPLE_OMP_TARGET, "gimple_omp_target", GSS_OMP_SINGLE)
> +   CLAUSES is an OMP_CLAUSE chain holding the associated clauses.
> +   CHILD_FN is set when outlining the body of the target 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_OMP_TARGET, "gimple_omp_target", GSS_OMP_PARALLEL)
>
>  /* GIMPLE_OMP_TEAMS <BODY, CLAUSES> represents #pragma omp teams
>     BODY is the sequence of statements inside the single section.
> --- gcc/fortran/types.def.jj    2013-08-19 12:07:51.000000000 +0200
> +++ gcc/fortran/types.def       2013-09-04 20:19:40.880566458 +0200
> @@ -120,6 +120,7 @@ DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_VPTR_INT
>  DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_SIZE_CONST_VPTR, BT_BOOL, BT_SIZE,
>                      BT_CONST_VOLATILE_PTR)
>  DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_INT_BOOL, BT_BOOL, BT_INT, BT_BOOL)
> +DEF_FUNCTION_TYPE_2 (BT_FN_VOID_UINT_UINT, BT_VOID, BT_UINT, BT_UINT)
>
>  DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR)
>
> @@ -167,6 +168,8 @@ DEF_FUNCTION_TYPE_5 (BT_FN_BOOL_LONG_LON
>                      BT_PTR_LONG, BT_PTR_LONG)
>  DEF_FUNCTION_TYPE_5 (BT_FN_VOID_SIZE_VPTR_PTR_PTR_INT, BT_VOID, BT_SIZE,
>                      BT_VOLATILE_PTR, BT_PTR, BT_PTR, BT_INT)
> +DEF_FUNCTION_TYPE_5 (BT_FN_VOID_INT_SIZE_PTR_PTR_PTR,
> +                    BT_VOID, BT_INT, BT_SIZE, BT_PTR, BT_PTR, BT_PTR)
>
>  DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_LONG_LONG_LONG_LONG_LONGPTR_LONGPTR,
>                       BT_BOOL, BT_LONG, BT_LONG, BT_LONG, BT_LONG,
> @@ -203,6 +206,9 @@ DEF_FUNCTION_TYPE_7 (BT_FN_BOOL_BOOL_ULL
>                      BT_BOOL, BT_BOOL, BT_ULONGLONG, BT_ULONGLONG,
>                      BT_ULONGLONG, BT_ULONGLONG,
>                      BT_PTR_ULONGLONG, BT_PTR_ULONGLONG)
> +DEF_FUNCTION_TYPE_7 (BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR,
> +                    BT_VOID, BT_INT, BT_PTR_FN_VOID_PTR, BT_PTR, BT_SIZE,
> +                    BT_PTR, BT_PTR, BT_PTR)
>
>  DEF_FUNCTION_TYPE_8 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT,
>                      BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT,
> --- gcc/cp/parser.c.jj  2013-08-27 20:50:58.000000000 +0200
> +++ gcc/cp/parser.c     2013-09-04 17:37:20.511076432 +0200
> @@ -29451,6 +29451,7 @@ cp_parser_omp_target_data (cp_parser *pa
>    OMP_TARGET_DATA_CLAUSES (stmt)
>      = cp_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK,
>                                  "#pragma omp target data", pragma_tok);
> +  keep_next_level (true);
>    OMP_TARGET_DATA_BODY (stmt) = cp_parser_omp_structured_block (parser);
>
>    SET_EXPR_LOCATION (stmt, pragma_tok->location);
> @@ -29543,6 +29544,7 @@ cp_parser_omp_target (cp_parser *parser,
>
>           cp_lexer_consume_token (parser->lexer);
>           strcpy (p_name, "#pragma omp target");
> +         keep_next_level (true);
>           tree sb = begin_omp_structured_block ();
>           unsigned save = cp_parser_begin_omp_structured_block (parser);
>           tree ret = cp_parser_omp_teams (parser, pragma_tok, p_name,
> @@ -29566,6 +29568,7 @@ cp_parser_omp_target (cp_parser *parser,
>    OMP_TARGET_CLAUSES (stmt)
>      = cp_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK,
>                                  "#pragma omp target", pragma_tok);
> +  keep_next_level (true);
>    OMP_TARGET_BODY (stmt) = cp_parser_omp_structured_block (parser);
>
>    SET_EXPR_LOCATION (stmt, pragma_tok->location);
> --- gcc/cp/cp-objcp-common.h.jj 2013-03-20 10:07:19.000000000 +0100
> +++ gcc/cp/cp-objcp-common.h    2013-09-04 19:33:40.520583302 +0200
> @@ -145,6 +145,8 @@ extern void cp_common_init_ts (void);
>  #define LANG_HOOKS_OMP_FINISH_CLAUSE cxx_omp_finish_clause
>  #undef LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE
>  #define LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE cxx_omp_privatize_by_reference
> +#undef LANG_HOOKS_OMP_MAPPABLE_TYPE
> +#define LANG_HOOKS_OMP_MAPPABLE_TYPE cp_omp_mappable_type
>
>  #undef LANG_HOOKS_EH_USE_CXA_END_CLEANUP
>  #define LANG_HOOKS_EH_USE_CXA_END_CLEANUP true
> --- gcc/cp/semantics.c.jj       2013-08-27 20:50:56.000000000 +0200
> +++ gcc/cp/semantics.c  2013-09-04 17:21:48.507946784 +0200
> @@ -4101,8 +4101,7 @@ cxx_omp_create_clause_info (tree c, tree
>
>  static tree
>  handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
> -                            bool &maybe_zero_len, unsigned int &first_non_one,
> -                            bool &pointer_based_p)
> +                            bool &maybe_zero_len, unsigned int &first_non_one)
>  {
>    tree ret, low_bound, length, type;
>    if (TREE_CODE (t) != TREE_LIST)
> @@ -4134,16 +4133,11 @@ handle_omp_array_sections_1 (tree c, tre
>           return error_mark_node;
>         }
>        t = convert_from_reference (t);
> -      if (!processing_template_decl
> -         && POINTER_TYPE_P (TREE_TYPE (t))
> -         && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP)
> -       pointer_based_p = true;
>        return t;
>      }
>
>    ret = handle_omp_array_sections_1 (c, TREE_CHAIN (t), types,
> -                                    maybe_zero_len, first_non_one,
> -                                    pointer_based_p);
> +                                    maybe_zero_len, first_non_one);
>    if (ret == error_mark_node || ret == NULL_TREE)
>      return ret;
>
> @@ -4326,16 +4320,12 @@ handle_omp_array_sections_1 (tree c, tre
>      }
>    if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND)
>      types.safe_push (TREE_TYPE (ret));
> -  /* For pointer based array sections we will need to evaluate lb more
> -     than once.  */
> -  if (pointer_based_p)
> +  /* We will need to evaluate lb more than once.  */
> +  tree lb = cp_save_expr (low_bound);
> +  if (lb != low_bound)
>      {
> -      tree lb = cp_save_expr (low_bound);
> -      if (lb != low_bound)
> -       {
> -         TREE_PURPOSE (t) = lb;
> -         low_bound = lb;
> -       }
> +      TREE_PURPOSE (t) = lb;
> +      low_bound = lb;
>      }
>    ret = grok_array_decl (OMP_CLAUSE_LOCATION (c), ret, low_bound, false);
>    return ret;
> @@ -4347,12 +4337,10 @@ static bool
>  handle_omp_array_sections (tree c)
>  {
>    bool maybe_zero_len = false;
> -  bool pointer_based_p = false;
>    unsigned int first_non_one = 0;
>    vec<tree> types = vNULL;
>    tree first = handle_omp_array_sections_1 (c, OMP_CLAUSE_DECL (c), types,
> -                                           maybe_zero_len, first_non_one,
> -                                           pointer_based_p);
> +                                           maybe_zero_len, first_non_one);
>    if (first == error_mark_node)
>      {
>        types.release ();
> @@ -4506,26 +4494,27 @@ handle_omp_array_sections (tree c)
>             size = build2 (COMPOUND_EXPR, sizetype, side_effects, size);
>           OMP_CLAUSE_DECL (c) = first;
>           OMP_CLAUSE_SIZE (c) = size;
> -         if (pointer_based_p)
> -           {
> -             tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c),
> -                                         OMP_CLAUSE_MAP);
> -             OMP_CLAUSE_MAP_KIND (c2) = OMP_CLAUSE_MAP_POINTER;
> -             if (!cxx_mark_addressable (t))
> -               return false;
> -             OMP_CLAUSE_DECL (c2) = t;
> -             t = build_fold_addr_expr (first);
> -             t = fold_convert_loc (OMP_CLAUSE_LOCATION (c),
> -                                   build_pointer_type (char_type_node), t);
> -             t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR,
> -                                  ptrdiff_type_node, t,
> -                                  fold_convert_loc (OMP_CLAUSE_LOCATION (c),
> -                                                    TREE_TYPE (t),
> -                                                    OMP_CLAUSE_DECL (c2)));
> -             OMP_CLAUSE_SIZE (c2) = t;
> -             OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c);
> -             OMP_CLAUSE_CHAIN (c) = c2;
> -           }
> +         if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP)
> +           return false;
> +         tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c),
> +                                     OMP_CLAUSE_MAP);
> +         OMP_CLAUSE_MAP_KIND (c2) = OMP_CLAUSE_MAP_POINTER;
> +         if (!cxx_mark_addressable (t))
> +           return false;
> +         OMP_CLAUSE_DECL (c2) = t;
> +         t = build_fold_addr_expr (first);
> +         t = fold_convert_loc (OMP_CLAUSE_LOCATION (c),
> +                               ptrdiff_type_node, t);
> +         tree ptr = OMP_CLAUSE_DECL (c2);
> +         if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
> +           ptr = build_fold_addr_expr (ptr);
> +         t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR,
> +                              ptrdiff_type_node, t,
> +                              fold_convert_loc (OMP_CLAUSE_LOCATION (c),
> +                                                ptrdiff_type_node, ptr));
> +         OMP_CLAUSE_SIZE (c2) = t;
> +         OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c);
> +         OMP_CLAUSE_CHAIN (c) = c2;
>         }
>      }
>    return false;
> @@ -4972,21 +4961,24 @@ finish_omp_clauses (tree clauses)
>                    && TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE
>                    && !cxx_mark_addressable (t))
>             remove = true;
> -         else if (!cp_omp_mappable_type ((TREE_CODE (TREE_TYPE (t))
> -                                          == REFERENCE_TYPE)
> -                                         ? TREE_TYPE (TREE_TYPE (t))
> -                                         : TREE_TYPE (t)))
> +         else if (!(OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
> +                    && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER)
> +                  && !cp_omp_mappable_type ((TREE_CODE (TREE_TYPE (t))
> +                                             == REFERENCE_TYPE)
> +                                            ? TREE_TYPE (TREE_TYPE (t))
> +                                            : TREE_TYPE (t)))
>             {
>               error_at (OMP_CLAUSE_LOCATION (c),
>                         "%qD does not have a mappable type in %qs clause", t,
>                         omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
>               remove = true;
>             }
> -         else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP)
> -           break;
>           else if (bitmap_bit_p (&generic_head, DECL_UID (t)))
>             {
> -             error ("%qD appears more than once in motion clauses", t);
> +             if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP)
> +               error ("%qD appears more than once in motion clauses", t);
> +             else
> +               error ("%qD appears more than once in map clauses", t);
>               remove = true;
>             }
>           else
> --- gcc/langhooks.h.jj  2013-03-20 10:08:13.000000000 +0100
> +++ gcc/langhooks.h     2013-09-04 19:29:20.429909391 +0200
> @@ -111,6 +111,9 @@ struct lang_hooks_for_types
>       firstprivate variables.  */
>    void (*omp_firstprivatize_type_sizes) (struct gimplify_omp_ctx *, tree);
>
> +  /* Return true if TYPE is a mappable type.  */
> +  bool (*omp_mappable_type) (tree type);
> +
>    /* Return TRUE if TYPE1 and TYPE2 are identical for type hashing purposes.
>       Called only after doing all language independent checks.
>       At present, this function is only called when both TYPE1 and TYPE2 are
> --- gcc/langhooks-def.h.jj      2013-03-20 10:08:41.000000000 +0100
> +++ gcc/langhooks-def.h 2013-09-04 19:29:45.450781052 +0200
> @@ -77,6 +77,7 @@ extern tree lhd_omp_assignment (tree, tr
>  struct gimplify_omp_ctx;
>  extern void lhd_omp_firstprivatize_type_sizes (struct gimplify_omp_ctx *,
>                                                tree);
> +extern bool lhd_omp_mappable_type (tree);
>
>  #define LANG_HOOKS_NAME                        "GNU unknown"
>  #define LANG_HOOKS_IDENTIFIER_SIZE     sizeof (struct lang_identifier)
> @@ -166,6 +167,7 @@ extern tree lhd_make_node (enum tree_cod
>  #define LANG_HOOKS_TYPE_MAX_SIZE       lhd_return_null_const_tree
>  #define LANG_HOOKS_OMP_FIRSTPRIVATIZE_TYPE_SIZES \
>    lhd_omp_firstprivatize_type_sizes
> +#define LANG_HOOKS_OMP_MAPPABLE_TYPE   lhd_omp_mappable_type
>  #define LANG_HOOKS_TYPE_HASH_EQ                NULL
>  #define LANG_HOOKS_GET_ARRAY_DESCR_INFO        NULL
>  #define LANG_HOOKS_GET_SUBRANGE_BOUNDS NULL
> @@ -184,6 +186,7 @@ extern tree lhd_make_node (enum tree_cod
>    LANG_HOOKS_INCOMPLETE_TYPE_ERROR, \
>    LANG_HOOKS_TYPE_MAX_SIZE, \
>    LANG_HOOKS_OMP_FIRSTPRIVATIZE_TYPE_SIZES, \
> +  LANG_HOOKS_OMP_MAPPABLE_TYPE, \
>    LANG_HOOKS_TYPE_HASH_EQ, \
>    LANG_HOOKS_GET_ARRAY_DESCR_INFO, \
>    LANG_HOOKS_GET_SUBRANGE_BOUNDS, \
> --- gcc/gimple.h.jj     2013-08-27 21:55:11.000000000 +0200
> +++ gcc/gimple.h        2013-09-02 11:57:32.143164024 +0200
> @@ -4702,7 +4702,7 @@ static inline tree
>  gimple_omp_target_clauses (const_gimple gs)
>  {
>    GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
> -  return gs->gimple_omp_single.clauses;
> +  return gs->gimple_omp_parallel.clauses;
>  }
>
>
> @@ -4712,7 +4712,7 @@ static inline tree *
>  gimple_omp_target_clauses_ptr (gimple gs)
>  {
>    GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
> -  return &gs->gimple_omp_single.clauses;
> +  return &gs->gimple_omp_parallel.clauses;
>  }
>
>
> @@ -4722,7 +4722,7 @@ static inline void
>  gimple_omp_target_set_clauses (gimple gs, tree clauses)
>  {
>    GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
> -  gs->gimple_omp_single.clauses = clauses;
> +  gs->gimple_omp_parallel.clauses = clauses;
>  }
>
>
> @@ -4747,6 +4747,67 @@ gimple_omp_target_set_kind (gimple g, in
>  }
>
>
> +/* Return the child function used to hold the body of OMP_TARGET GS.  */
> +
> +static inline tree
> +gimple_omp_target_child_fn (const_gimple gs)
> +{
> +  GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
> +  return gs->gimple_omp_parallel.child_fn;
> +}
> +
> +/* Return a pointer to the child function used to hold the body of
> +   OMP_TARGET GS.  */
> +
> +static inline tree *
> +gimple_omp_target_child_fn_ptr (gimple gs)
> +{
> +  GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
> +  return &gs->gimple_omp_parallel.child_fn;
> +}
> +
> +
> +/* Set CHILD_FN to be the child function for OMP_TARGET GS.  */
> +
> +static inline void
> +gimple_omp_target_set_child_fn (gimple gs, tree child_fn)
> +{
> +  GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
> +  gs->gimple_omp_parallel.child_fn = child_fn;
> +}
> +
> +
> +/* Return the artificial argument used to send variables and values
> +   from the parent to the children threads in OMP_TARGET GS.  */
> +
> +static inline tree
> +gimple_omp_target_data_arg (const_gimple gs)
> +{
> +  GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
> +  return gs->gimple_omp_parallel.data_arg;
> +}
> +
> +
> +/* Return a pointer to the data argument for OMP_TARGET GS.  */
> +
> +static inline tree *
> +gimple_omp_target_data_arg_ptr (gimple gs)
> +{
> +  GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
> +  return &gs->gimple_omp_parallel.data_arg;
> +}
> +
> +
> +/* Set DATA_ARG to be the data argument for OMP_TARGET GS.  */
> +
> +static inline void
> +gimple_omp_target_set_data_arg (gimple gs, tree data_arg)
> +{
> +  GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
> +  gs->gimple_omp_parallel.data_arg = data_arg;
> +}
> +
> +
>  /* Return the clauses associated with OMP_TEAMS GS.  */
>
>  static inline tree
> --- gcc/omp-builtins.def.jj     2013-08-19 12:07:51.000000000 +0200
> +++ gcc/omp-builtins.def        2013-09-04 15:14:21.049713033 +0200
> @@ -225,3 +225,14 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SINGLE_C
>                   BT_FN_PTR, ATTR_NOTHROW_LEAF_LIST)
>  DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SINGLE_COPY_END, "GOMP_single_copy_end",
>                   BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
> +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TARGET, "GOMP_target",
> +                 BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR,
> +                 ATTR_NOTHROW_LIST)
> +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TARGET_DATA, "GOMP_target_data",
> +                 BT_FN_VOID_INT_SIZE_PTR_PTR_PTR, ATTR_NOTHROW_LIST)
> +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TARGET_END_DATA, "GOMP_target_end_data",
> +                 BT_FN_VOID, ATTR_NOTHROW_LIST)
> +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TARGET_UPDATE, "GOMP_target_update",
> +                 BT_FN_VOID_INT_SIZE_PTR_PTR_PTR, ATTR_NOTHROW_LIST)
> +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TEAMS, "GOMP_teams",
> +                 BT_FN_VOID_UINT_UINT, ATTR_NOTHROW_LIST)
> --- gcc/gimple-pretty-print.c.jj        2013-08-27 21:53:53.000000000 +0200
> +++ gcc/gimple-pretty-print.c   2013-08-30 17:53:14.201347484 +0200
> @@ -1277,6 +1277,13 @@ dump_gimple_omp_target (pretty_printer *
>        pp_string (buffer, "#pragma omp target");
>        pp_string (buffer, kind);
>        dump_omp_clauses (buffer, gimple_omp_target_clauses (gs), spc, flags);
> +      if (gimple_omp_target_child_fn (gs))
> +       {
> +         pp_string (buffer, " [child fn: ");
> +         dump_generic_node (buffer, gimple_omp_target_child_fn (gs),
> +                            spc, flags, false);
> +         pp_right_bracket (buffer);
> +       }
>        if (!gimple_seq_empty_p (gimple_omp_body (gs)))
>         {
>           newline_and_indent (buffer, spc + 2);
> --- gcc/gimplify.c.jj   2013-08-27 22:03:35.000000000 +0200
> +++ gcc/gimplify.c      2013-09-04 19:36:07.442834807 +0200
> @@ -5976,7 +5976,16 @@ omp_notice_variable (struct gimplify_omp
>    if (ctx->region_type == ORT_TARGET)
>      {
>        if (n == NULL)
> -       omp_add_variable (ctx, decl, GOVD_MAP | flags);
> +       {
> +         if (!lang_hooks.types.omp_mappable_type (TREE_TYPE (decl)))
> +           {
> +             error ("%qD referenced in target region does not have "
> +                    "a mappable type", decl);
> +             omp_add_variable (ctx, decl, GOVD_MAP | GOVD_EXPLICIT | flags);
> +           }
> +         else
> +           omp_add_variable (ctx, decl, GOVD_MAP | flags);
> +       }
>        else
>         n->value |= flags;
>        ret = lang_hooks.decls.omp_disregard_value_expr (decl, true);
> @@ -6283,7 +6292,6 @@ gimplify_scan_omp_clauses (tree *list_p,
>               break;
>             }
>           flags = GOVD_MAP | GOVD_EXPLICIT;
> -         notice_outer = false;
>           goto do_add;
>
>         case OMP_CLAUSE_DEPEND:
> @@ -6500,31 +6508,7 @@ gimplify_adjust_omp_clauses_1 (splay_tre
>    if (private_debug)
>      code = OMP_CLAUSE_PRIVATE;
>    else if (flags & GOVD_MAP)
> -    {
> -      /* If decl is already in the enclosing device data environment,
> -        the spec says that it should just be used and no init/assignment
> -        should be done.  If there was any privatization in between though,
> -        it means that original decl might be in the enclosing device data
> -        environment, but the privatized might not.  */
> -      struct gimplify_omp_ctx *ctx;
> -      for (ctx = gimplify_omp_ctxp->outer_context;
> -          ctx; ctx = ctx->outer_context)
> -       {
> -         n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl);
> -         if (n == NULL)
> -           continue;
> -         if (ctx->region_type == ORT_TARGET_DATA)
> -           {
> -             if ((n->value & GOVD_MAP) != 0)
> -               return 0;
> -           }
> -         else if ((n->value & (GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE
> -                               | GOVD_PRIVATE | GOVD_REDUCTION
> -                               | GOVD_LINEAR)) != 0)
> -           break;
> -       }
> -      code = OMP_CLAUSE_MAP;
> -    }
> +    code = OMP_CLAUSE_MAP;
>    else if (flags & GOVD_SHARED)
>      {
>        if (is_global_var (decl))
> @@ -6689,31 +6673,6 @@ gimplify_adjust_omp_clauses (tree *list_
>           n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl);
>           if (ctx->region_type == ORT_TARGET && !(n->value & GOVD_SEEN))
>             remove = true;
> -         else
> -           {
> -             /* If decl is already in the enclosing device data environment,
> -                the spec says that it should just be used and no init/assignment
> -                should be done.  If there was any privatization in between though,
> -                it means that original decl might be in the enclosing device data
> -                environment, but the privatized might not.  */
> -             struct gimplify_omp_ctx *octx;
> -             for (octx = ctx->outer_context; octx; octx = octx->outer_context)
> -               {
> -                 n = splay_tree_lookup (octx->variables,
> -                                        (splay_tree_key) decl);
> -                 if (n == NULL)
> -                   continue;
> -                 if (octx->region_type == ORT_TARGET_DATA)
> -                   {
> -                     if ((n->value & GOVD_MAP) != 0)
> -                       remove = true;
> -                   }
> -                 else if ((n->value & (GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE
> -                                       | GOVD_PRIVATE | GOVD_REDUCTION
> -                                       | GOVD_LINEAR)) != 0)
> -                   break;
> -               }
> -           }
>           break;
>
>         case OMP_CLAUSE_REDUCTION:
> @@ -6722,6 +6681,7 @@ gimplify_adjust_omp_clauses (tree *list_
>         case OMP_CLAUSE_IF:
>         case OMP_CLAUSE_NUM_THREADS:
>         case OMP_CLAUSE_NUM_TEAMS:
> +       case OMP_CLAUSE_THREAD_LIMIT:
>         case OMP_CLAUSE_DIST_SCHEDULE:
>         case OMP_CLAUSE_DEVICE:
>         case OMP_CLAUSE_SCHEDULE:
> @@ -7198,7 +7158,28 @@ gimplify_omp_workshare (tree *expr_p, gi
>        gcc_unreachable ();
>      }
>    gimplify_scan_omp_clauses (&OMP_CLAUSES (expr), pre_p, ort);
> -  gimplify_and_add (OMP_BODY (expr), &body);
> +  if (ort == ORT_TARGET || ort == ORT_TARGET_DATA)
> +    {
> +      struct gimplify_ctx gctx;
> +      push_gimplify_context (&gctx);
> +      gimple g = gimplify_and_return_first (OMP_BODY (expr), &body);
> +      if (gimple_code (g) == GIMPLE_BIND)
> +       pop_gimplify_context (g);
> +      else
> +       pop_gimplify_context (NULL);
> +      if (ort == ORT_TARGET_DATA)
> +       {
> +         gimple_seq cleanup = NULL;
> +         tree fn = builtin_decl_explicit (BUILT_IN_GOMP_TARGET_END_DATA);
> +         g = gimple_build_call (fn, 0);
> +         gimple_seq_add_stmt (&cleanup, g);
> +         g = gimple_build_try (body, cleanup, GIMPLE_TRY_FINALLY);
> +         body = NULL;
> +         gimple_seq_add_stmt (&body, g);
> +       }
> +    }
> +  else
> +    gimplify_and_add (OMP_BODY (expr), &body);
>    gimplify_adjust_omp_clauses (&OMP_CLAUSES (expr));
>
>    switch (TREE_CODE (expr))
> --- gcc/testsuite/c-c++-common/gomp/map-1.c.jj  2013-07-06 19:18:46.161478820 +0200
> +++ gcc/testsuite/c-c++-common/gomp/map-1.c     2013-09-04 17:00:51.174322082 +0200
> @@ -33,7 +33,7 @@ foo (int g[3][10], int h[4][8], int i[2]
>    #pragma omp target map(to: o[2:5]) /* { dg-error "does not have pointer or array type" } */
>      ;
>    #pragma omp target map(to: a[:][:]) /* { dg-error "array type length expression is not optional" } */
> -    bar (&a[0][0]);
> +    bar (&a[0][0]); /* { dg-error "referenced in target region does not have a mappable type" } */
>    #pragma omp target map(tofrom: b[-1:]) /* { dg-error "negative low bound in array section" } */
>      bar (b);
>    #pragma omp target map(tofrom: c[:-3][:]) /* { dg-error "negative length in array section" } */
> --- gcc/builtin-types.def.jj    2013-08-19 12:07:51.000000000 +0200
> +++ gcc/builtin-types.def       2013-09-03 08:58:48.902658867 +0200
> @@ -345,6 +345,7 @@ DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_VPTR_INT
>  DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_SIZE_CONST_VPTR, BT_BOOL, BT_SIZE,
>                      BT_CONST_VOLATILE_PTR)
>  DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_INT_BOOL, BT_BOOL, BT_INT, BT_BOOL)
> +DEF_FUNCTION_TYPE_2 (BT_FN_VOID_UINT_UINT, BT_VOID, BT_UINT, BT_UINT)
>
>  DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR)
>
> @@ -472,6 +473,8 @@ DEF_FUNCTION_TYPE_5 (BT_FN_BOOL_VPTR_PTR
>  DEF_FUNCTION_TYPE_5 (BT_FN_VOID_OMPFN_PTR_UINT_UINT_UINT,
>                      BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, BT_UINT,
>                      BT_UINT)
> +DEF_FUNCTION_TYPE_5 (BT_FN_VOID_INT_SIZE_PTR_PTR_PTR,
> +                    BT_VOID, BT_INT, BT_SIZE, BT_PTR, BT_PTR, BT_PTR)
>
>  DEF_FUNCTION_TYPE_6 (BT_FN_INT_STRING_SIZE_INT_SIZE_CONST_STRING_VALIST_ARG,
>                      BT_INT, BT_STRING, BT_SIZE, BT_INT, BT_SIZE,
> @@ -511,6 +514,9 @@ DEF_FUNCTION_TYPE_7 (BT_FN_BOOL_BOOL_ULL
>                      BT_BOOL, BT_BOOL, BT_ULONGLONG, BT_ULONGLONG,
>                      BT_ULONGLONG, BT_ULONGLONG,
>                      BT_PTR_ULONGLONG, BT_PTR_ULONGLONG)
> +DEF_FUNCTION_TYPE_7 (BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR,
> +                    BT_VOID, BT_INT, BT_PTR_FN_VOID_PTR, BT_PTR, BT_SIZE,
> +                    BT_PTR, BT_PTR, BT_PTR)
>
>  DEF_FUNCTION_TYPE_8 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT,
>                      BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT,
> --- libgomp/libgomp.map.jj      2013-06-12 14:24:42.000000000 +0200
> +++ libgomp/libgomp.map 2013-09-04 15:17:42.694659418 +0200
> @@ -218,4 +218,9 @@ GOMP_4.0 {
>         GOMP_parallel;
>         GOMP_taskgroup_start;
>         GOMP_taskgroup_end;
> +       GOMP_target;
> +       GOMP_target_data;
> +       GOMP_target_end_data;
> +       GOMP_target_update;
> +       GOMP_teams;
>  } GOMP_3.0;
> --- libgomp/Makefile.am.jj      2013-03-20 10:02:06.000000000 +0100
> +++ libgomp/Makefile.am 2013-09-04 14:59:19.475033836 +0200
> @@ -60,7 +60,7 @@ libgomp_la_LINK = $(LINK) $(libgomp_la_L
>  libgomp_la_SOURCES = alloc.c barrier.c critical.c env.c error.c iter.c \
>         iter_ull.c loop.c loop_ull.c ordered.c parallel.c sections.c single.c \
>         task.c team.c work.c lock.c mutex.c proc.c sem.c bar.c ptrlock.c \
> -       time.c fortran.c affinity.c
> +       time.c fortran.c affinity.c target.c
>
>  nodist_noinst_HEADERS = libgomp_f.h
>  nodist_libsubinclude_HEADERS = omp.h
> --- libgomp/Makefile.in.jj      2013-03-20 10:02:05.000000000 +0100
> +++ libgomp/Makefile.in 2013-09-04 14:59:52.243864494 +0200
> @@ -96,7 +96,7 @@ am_libgomp_la_OBJECTS = alloc.lo barrier
>         error.lo iter.lo iter_ull.lo loop.lo loop_ull.lo ordered.lo \
>         parallel.lo sections.lo single.lo task.lo team.lo work.lo \
>         lock.lo mutex.lo proc.lo sem.lo bar.lo ptrlock.lo time.lo \
> -       fortran.lo affinity.lo
> +       fortran.lo affinity.lo target.lo
>  libgomp_la_OBJECTS = $(am_libgomp_la_OBJECTS)
>  DEFAULT_INCLUDES = -I.@am__isrc@
>  depcomp = $(SHELL) $(top_srcdir)/../depcomp
> @@ -317,7 +317,7 @@ libgomp_la_LINK = $(LINK) $(libgomp_la_L
>  libgomp_la_SOURCES = alloc.c barrier.c critical.c env.c error.c iter.c \
>         iter_ull.c loop.c loop_ull.c ordered.c parallel.c sections.c single.c \
>         task.c team.c work.c lock.c mutex.c proc.c sem.c bar.c ptrlock.c \
> -       time.c fortran.c affinity.c
> +       time.c fortran.c affinity.c target.c
>
>  nodist_noinst_HEADERS = libgomp_f.h
>  nodist_libsubinclude_HEADERS = omp.h
> @@ -474,6 +474,7 @@ distclean-compile:
>  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sections.Plo@am__quote@
>  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sem.Plo@am__quote@
>  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/single.Plo@am__quote@
> +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/target.Plo@am__quote@
>  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/task.Plo@am__quote@
>  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/team.Plo@am__quote@
>  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/time.Plo@am__quote@
> --- libgomp/libgomp_g.h.jj      2013-04-05 18:15:57.000000000 +0200
> +++ libgomp/libgomp_g.h 2013-09-04 15:25:55.982080005 +0200
> @@ -199,4 +199,14 @@ extern bool GOMP_single_start (void);
>  extern void *GOMP_single_copy_start (void);
>  extern void GOMP_single_copy_end (void *);
>
> +/* target.c */
> +
> +extern void GOMP_target (int, void (*) (void *), const char *,
> +                        size_t, void **, size_t *, unsigned char *);
> +extern void GOMP_target_data (int, size_t, void **, size_t *, unsigned char *);
> +extern void GOMP_target_end_data (void);
> +extern void GOMP_target_update (int, size_t, void **, size_t *,
> +                               unsigned char *);
> +extern void GOMP_teams (unsigned int, unsigned int);
> +
>  #endif /* LIBGOMP_G_H */
> --- libgomp/testsuite/libgomp.c++/for-11.C.jj   2013-06-21 08:38:19.000000000 +0200
> +++ libgomp/testsuite/libgomp.c++/for-11.C      2013-09-04 15:28:21.542379101 +0200
> @@ -75,10 +75,7 @@ int
>  main ()
>  {
>    int err = 0;
> -// FIXME: distribute construct must be closely nested
> -// in teams region, but we don't handle target expansions
> -// yet.  Enable when it works.
> -// #pragma omp target teams reduction(|:err)
> +  #pragma omp target teams reduction(|:err)
>      {
>        err |= test_d_normal ();
>        err |= test_d_ds128_normal ();
> --- libgomp/testsuite/libgomp.c++/target-1.C.jj 2013-09-04 18:55:02.294387946 +0200
> +++ libgomp/testsuite/libgomp.c++/target-1.C    2013-09-04 18:54:56.430417616 +0200
> @@ -0,0 +1 @@
> +#include "../libgomp.c/target-1.c"
> --- libgomp/testsuite/libgomp.c/for-3.c.jj      2013-07-06 19:44:29.000000000 +0200
> +++ libgomp/testsuite/libgomp.c/for-3.c 2013-09-04 15:28:53.986223342 +0200
> @@ -77,10 +77,7 @@ int
>  main ()
>  {
>    int err = 0;
> -/* FIXME: distribute construct must be closely nested
> -   in teams region, but we don't handle target expansions
> -   yet.  Enable when it works.  */
> -/* #pragma omp target teams reduction(|:err) */
> +  #pragma omp target teams reduction(|:err)
>      {
>        err |= test_d_normal ();
>        err |= test_d_ds128_normal ();
> --- libgomp/testsuite/libgomp.c/target-1.c.jj   2013-09-04 18:54:18.520609855 +0200
> +++ libgomp/testsuite/libgomp.c/target-1.c      2013-09-04 18:54:10.000000000 +0200
> @@ -0,0 +1,90 @@
> +extern
> +#ifdef __cplusplus
> +"C"
> +#endif
> +void abort (void);
> +
> +void
> +fn1 (double *x, double *y, int z)
> +{
> +  int i;
> +  for (i = 0; i < z; i++)
> +    {
> +      x[i] = i & 31;
> +      y[i] = (i & 63) - 30;
> +    }
> +}
> +
> +#pragma omp declare target
> +int tgtv = 6;
> +int
> +tgt (void)
> +{
> +  #pragma omp atomic update
> +    tgtv++;
> +  return 0;
> +}
> +#pragma omp end declare target
> +
> +double
> +fn2 (int x, int y, int z)
> +{
> +  double b[1024], c[1024], s = 0;
> +  int i, j;
> +  fn1 (b, c, x);
> +  #pragma omp target data map(to: b)
> +  {
> +    #pragma omp target map(tofrom: c)
> +      #pragma omp teams num_teams(y) thread_limit(z) reduction(+:s) firstprivate(x)
> +       #pragma omp distribute dist_schedule(static, 4) collapse(1)
> +         for (j=0; j < x; j += y)
> +           #pragma omp parallel for reduction(+:s)
> +             for (i = j; i < j + y; i++)
> +               tgt (), s += b[i] * c[i];
> +    #pragma omp target update from(b, tgtv)
> +  }
> +  return s;
> +}
> +
> +double
> +fn3 (int x)
> +{
> +  double b[1024], c[1024], s = 0;
> +  int i;
> +  fn1 (b, c, x);
> +  #pragma omp target map(to: b, c)
> +    #pragma omp parallel for reduction(+:s)
> +      for (i = 0; i < x; i++)
> +       tgt (), s += b[i] * c[i];
> +  return s;
> +}
> +
> +double
> +fn4 (int x, double *p)
> +{
> +  double b[1024], c[1024], d[1024], s = 0;
> +  int i;
> +  fn1 (b, c, x);
> +  fn1 (d + x, p + x, x);
> +  #pragma omp target map(to: b, c[0:x], d[x:x]) map(to:p[x:64 + (x & 31)])
> +    #pragma omp parallel for reduction(+:s)
> +      for (i = 0; i < x; i++)
> +       s += b[i] * c[i] + d[x + i] + p[x + i];
> +  return s;
> +}
> +
> +int
> +main ()
> +{
> +  double a = fn2 (128, 4, 6);
> +  int b = tgtv;
> +  double c = fn3 (61);
> +  #pragma omp target update from(tgtv)
> +  int d = tgtv;
> +  double e[1024];
> +  double f = fn4 (64, e);
> +  if (a != 13888.0 || b != 6 + 128 || c != 4062.0 || d != 6 + 128 + 61
> +      || f != 8032.0)
> +    abort ();
> +  return 0;
> +}
> --- libgomp/target.c.jj 2013-09-04 14:58:30.488287438 +0200
> +++ libgomp/target.c    2013-09-04 15:18:31.363404929 +0200
> @@ -0,0 +1,83 @@
> +/* Copyright (C) 2013 Free Software Foundation, Inc.
> +   Contributed by Jakub Jelinek <jakub@redhat.com>.
> +
> +   This file is part of the GNU OpenMP Library (libgomp).
> +
> +   Libgomp is free software; you can redistribute it and/or modify it
> +   under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3, or (at your option)
> +   any later version.
> +
> +   Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
> +   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
> +   FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> +   more details.
> +
> +   Under Section 7 of GPL version 3, you are granted additional
> +   permissions described in the GCC Runtime Library Exception, version
> +   3.1, as published by the Free Software Foundation.
> +
> +   You should have received a copy of the GNU General Public License and
> +   a copy of the GCC Runtime Library Exception along with this program;
> +   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +/* This file handles the maintainence of threads in response to team
> +   creation and termination.  */
> +
> +#include "libgomp.h"
> +#include <stdlib.h>
> +#include <string.h>
> +
> +static int
> +resolve_device (int device)
> +{
> +  return -1;
> +}
> +
> +/* Called when encountering a target directive.  If DEVICE
> +   is -1, it means use device-var ICV.  If it is -2 (or any other value
> +   larger than last available hw device, use host fallback.
> +   FN is address of host code, FNNAME corresponding name to lookup
> +   in the target code.  HOSTADDRS, SIZES and KINDS are arrays
> +   with MAPNUM entries, with addresses of the host objects,
> +   sizes of the host objects (resp. for pointer kind pointer bias
> +   and assumed sizeof (void *) size) and kinds.  */
> +
> +void
> +GOMP_target (int device, void (*fn) (void *), const char *fnname,
> +            size_t mapnum, void **hostaddrs, size_t *sizes,
> +            unsigned char *kinds)
> +{
> +  if (resolve_device (device) == -1)
> +    {
> +      fn (hostaddrs);
> +      return;
> +    }
> +}
> +
> +void
> +GOMP_target_data (int device, size_t mapnum, void **hostaddrs, size_t *sizes,
> +                 unsigned char *kinds)
> +{
> +  if (resolve_device (device) == -1)
> +    return;
> +}
> +
> +void
> +GOMP_target_end_data (void)
> +{
> +}
> +
> +void
> +GOMP_target_update (int device, size_t mapnum, void **hostaddrs, size_t *sizes,
> +                   unsigned char *kinds)
> +{
> +  if (resolve_device (device) == -1)
> +    return;
> +}
> +
> +void
> +GOMP_teams (unsigned int num_teams, unsigned int thread_limit)
> +{
> +}
>
>         Jakub
diff mbox

Patch

--- gcc/tree-cfg.c.jj	2013-08-27 20:53:36.000000000 +0200
+++ gcc/tree-cfg.c	2013-09-02 13:55:36.591737508 +0200
@@ -610,7 +610,6 @@  make_edges (void)
 	    case GIMPLE_OMP_TASK:
 	    case GIMPLE_OMP_FOR:
 	    case GIMPLE_OMP_SINGLE:
-	    case GIMPLE_OMP_TARGET:
 	    case GIMPLE_OMP_TEAMS:
 	    case GIMPLE_OMP_MASTER:
 	    case GIMPLE_OMP_ORDERED:
@@ -620,6 +619,13 @@  make_edges (void)
 	      fallthru = true;
 	      break;
 
+	    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)
+		cur_region = cur_region->outer;
+	      break;
+
 	    case GIMPLE_OMP_SECTIONS:
 	      cur_region = new_omp_region (bb, code, cur_region);
 	      fallthru = true;
--- gcc/langhooks.c.jj	2013-08-27 20:53:03.000000000 +0200
+++ gcc/langhooks.c	2013-09-04 19:30:55.551423852 +0200
@@ -523,6 +523,15 @@  lhd_omp_firstprivatize_type_sizes (struc
 {
 }
 
+/* Return true if TYPE is an OpenMP mappable type.  By default return true
+   if type is complete.  */
+
+bool
+lhd_omp_mappable_type (tree type)
+{
+  return COMPLETE_TYPE_P (type);
+}
+
 /* Common function for add_builtin_function and
    add_builtin_function_ext_scope.  */
 static tree
--- gcc/omp-low.c.jj	2013-08-27 22:44:31.000000000 +0200
+++ gcc/omp-low.c	2013-09-04 19:58:30.320019227 +0200
@@ -1453,6 +1453,9 @@  scan_sharing_clauses (tree clauses, omp_
 	  break;
 
 	case OMP_CLAUSE_SHARED:
+	  /* Ignore shared directives in teams construct.  */
+	  if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS)
+	    break;
 	  gcc_assert (is_taskreg_ctx (ctx));
 	  decl = OMP_CLAUSE_DECL (c);
 	  gcc_assert (!COMPLETE_TYPE_P (TREE_TYPE (decl))
@@ -1533,6 +1536,9 @@  scan_sharing_clauses (tree clauses, omp_
 	case OMP_CLAUSE_FINAL:
 	case OMP_CLAUSE_IF:
 	case OMP_CLAUSE_NUM_THREADS:
+	case OMP_CLAUSE_NUM_TEAMS:
+	case OMP_CLAUSE_THREAD_LIMIT:
+	case OMP_CLAUSE_DEVICE:
 	case OMP_CLAUSE_SCHEDULE:
 	case OMP_CLAUSE_DIST_SCHEDULE:
 	case OMP_CLAUSE_DEPEND:
@@ -1540,6 +1546,66 @@  scan_sharing_clauses (tree clauses, omp_
 	    scan_omp_op (&OMP_CLAUSE_OPERAND (c, 0), ctx->outer);
 	  break;
 
+	case OMP_CLAUSE_TO:
+	case OMP_CLAUSE_FROM:
+	case OMP_CLAUSE_MAP:
+	  if (ctx->outer)
+	    scan_omp_op (&OMP_CLAUSE_SIZE (c), ctx->outer);
+	  decl = OMP_CLAUSE_DECL (c);
+	  /* Global variables with "omp declare target" attribute
+	     don't need to be copied, the receiver side will use them
+	     directly.  */
+	  if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+	      && DECL_P (decl)
+	      && is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx))
+	      && lookup_attribute ("omp declare target",
+				   DECL_ATTRIBUTES (decl)))
+	    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
+		 those.  */
+	      if (gimple_omp_target_kind (ctx->stmt) == GF_OMP_TARGET_KIND_DATA
+		  && !POINTER_TYPE_P (TREE_TYPE (decl)))
+		break;
+	    }
+	  if (DECL_P (decl))
+	    {
+	      install_var_field (decl, true, 3, ctx);
+	      if (gimple_omp_target_kind (ctx->stmt)
+		  == GF_OMP_TARGET_KIND_REGION)
+		install_var_local (decl, ctx);
+	    }
+	  else
+	    {
+	      tree base = get_base_address (decl);
+	      tree nc = OMP_CLAUSE_CHAIN (c);
+	      if (DECL_P (base)
+		  && nc != NULL_TREE
+		  && OMP_CLAUSE_CODE (nc) == OMP_CLAUSE_MAP
+		  && OMP_CLAUSE_DECL (nc) == base
+		  && OMP_CLAUSE_MAP_KIND (nc) == OMP_CLAUSE_MAP_POINTER
+		  && integer_zerop (OMP_CLAUSE_SIZE (nc)))
+		{
+		  OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c) = 1;
+		  OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (nc) = 1;
+		}
+	      else
+		{
+		  gcc_assert (!splay_tree_lookup (ctx->field_map,
+						  (splay_tree_key) decl));
+		  tree field
+		    = build_decl (OMP_CLAUSE_LOCATION (c),
+				  FIELD_DECL, NULL_TREE, ptr_type_node);
+		  insert_field_into_struct (ctx->record_type, field);
+		  splay_tree_insert (ctx->field_map, (splay_tree_key) decl,
+				     (splay_tree_value) field);
+		}
+	    }
+	  break;
+
 	case OMP_CLAUSE_NOWAIT:
 	case OMP_CLAUSE_ORDERED:
 	case OMP_CLAUSE_COLLAPSE:
@@ -1590,16 +1656,46 @@  scan_sharing_clauses (tree clauses, omp_
 	  break;
 
 	case OMP_CLAUSE_SHARED:
+	  /* Ignore shared directives in teams construct.  */
+	  if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS)
+	    break;
 	  decl = OMP_CLAUSE_DECL (c);
 	  if (! is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx)))
 	    fixup_remapped_decl (decl, ctx, false);
 	  break;
 
+	case OMP_CLAUSE_MAP:
+	  if (gimple_omp_target_kind (ctx->stmt) == GF_OMP_TARGET_KIND_DATA)
+	    break;
+	  decl = OMP_CLAUSE_DECL (c);
+	  if (DECL_P (decl)
+	      && is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx))
+	      && lookup_attribute ("omp declare target",
+				   DECL_ATTRIBUTES (decl)))
+	    break;
+	  if (DECL_P (decl))
+	    {
+	      if (OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER
+		  && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
+		  && !COMPLETE_TYPE_P (TREE_TYPE (decl)))
+		{
+		  tree new_decl = lookup_decl (decl, ctx);
+		  TREE_TYPE (new_decl)
+		    = remap_type (TREE_TYPE (decl), &ctx->cb);
+		}
+	      else
+		fixup_remapped_decl (decl, ctx, false);
+	    }
+	  break;
+
 	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:
+	case OMP_CLAUSE_DEVICE:
 	case OMP_CLAUSE_SCHEDULE:
 	case OMP_CLAUSE_DIST_SCHEDULE:
 	case OMP_CLAUSE_NOWAIT:
@@ -1613,6 +1709,8 @@  scan_sharing_clauses (tree clauses, omp_
 	case OMP_CLAUSE_ALIGNED:
 	case OMP_CLAUSE_DEPEND:
 	case OMP_CLAUSE__LOOPTEMP_:
+	case OMP_CLAUSE_TO:
+	case OMP_CLAUSE_FROM:
 	  break;
 
 	default:
@@ -1677,6 +1775,26 @@  create_omp_child_function (omp_context *
   DECL_EXTERNAL (decl) = 0;
   DECL_CONTEXT (decl) = NULL_TREE;
   DECL_INITIAL (decl) = make_node (BLOCK);
+  bool target_p = false;
+  if (lookup_attribute ("omp declare target",
+			DECL_ATTRIBUTES (current_function_decl)))
+    target_p = true;
+  else
+    {
+      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)
+	  {
+	    target_p = true;
+	    break;
+	  }
+    }
+  if (target_p)
+    DECL_ATTRIBUTES (decl)
+      = tree_cons (get_identifier ("omp declare target"),
+		   NULL_TREE, DECL_ATTRIBUTES (decl));
 
   t = build_decl (DECL_SOURCE_LOCATION (decl),
 		  RESULT_DECL, NULL_TREE, void_type_node);
@@ -1975,6 +2093,53 @@  scan_omp_single (gimple stmt, omp_contex
     layout_type (ctx->record_type);
 }
 
+/* Scan an OpenMP target{, data, update} directive.  */
+
+static void
+scan_omp_target (gimple stmt, omp_context *outer_ctx)
+{
+  omp_context *ctx;
+  tree name;
+  int kind = gimple_omp_target_kind (stmt);
+
+  ctx = new_omp_context (stmt, outer_ctx);
+  ctx->field_map = splay_tree_new (splay_tree_compare_pointers, 0, 0);
+  ctx->default_kind = OMP_CLAUSE_DEFAULT_SHARED;
+  ctx->record_type = lang_hooks.types.make_type (RECORD_TYPE);
+  name = create_tmp_var_name (".omp_data_t");
+  name = build_decl (gimple_location (stmt),
+		     TYPE_DECL, name, ctx->record_type);
+  DECL_ARTIFICIAL (name) = 1;
+  DECL_NAMELESS (name) = 1;
+  TYPE_NAME (ctx->record_type) = name;
+  if (kind == GF_OMP_TARGET_KIND_REGION)
+    {
+      create_omp_child_function (ctx, false);
+      gimple_omp_target_set_child_fn (stmt, ctx->cb.dst_fn);
+    }
+
+  scan_sharing_clauses (gimple_omp_target_clauses (stmt), ctx);
+  scan_omp (gimple_omp_body_ptr (stmt), ctx);
+
+  if (TYPE_FIELDS (ctx->record_type) == NULL)
+    ctx->record_type = ctx->receiver_decl = NULL;
+  else
+    {
+      layout_type (ctx->record_type);
+      if (kind == GF_OMP_TARGET_KIND_REGION)
+	fixup_child_record_type (ctx);
+    }
+}
+
+/* Scan an OpenMP teams directive.  */
+
+static void
+scan_omp_teams (gimple stmt, omp_context *outer_ctx)
+{
+  omp_context *ctx = new_omp_context (stmt, outer_ctx);
+  scan_sharing_clauses (gimple_omp_teams_clauses (stmt), ctx);
+  scan_omp (gimple_omp_body_ptr (stmt), ctx);
+}
 
 /* Check OpenMP nesting restrictions.  */
 static bool
@@ -1992,7 +2157,7 @@  check_omp_nesting_restrictions (gimple s
       else if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS)
 	{
 	  if ((gimple_code (stmt) != GIMPLE_OMP_FOR
-	       || (gimple_omp_for_kind (ctx->stmt)
+	       || (gimple_omp_for_kind (stmt)
 		   != GF_OMP_FOR_KIND_DISTRIBUTE))
 	      && gimple_code (stmt) != GIMPLE_OMP_PARALLEL)
 	    {
@@ -2345,6 +2510,14 @@  scan_omp_1_stmt (gimple_stmt_iterator *g
       scan_omp (gimple_omp_body_ptr (stmt), ctx);
       break;
 
+    case GIMPLE_OMP_TARGET:
+      scan_omp_target (stmt, ctx);
+      break;
+
+    case GIMPLE_OMP_TEAMS:
+      scan_omp_teams (stmt, ctx);
+      break;
+
     case GIMPLE_BIND:
       {
 	tree var;
@@ -2731,6 +2904,9 @@  lower_rec_input_clauses (tree clauses, g
 		continue;
 	      break;
 	    case OMP_CLAUSE_SHARED:
+	      /* Ignore shared directives in teams construct.  */
+	      if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS)
+		continue;
 	      if (maybe_lookup_decl (OMP_CLAUSE_DECL (c), ctx) == NULL)
 		{
 		  gcc_assert (is_global_var (OMP_CLAUSE_DECL (c)));
@@ -2889,6 +3065,9 @@  lower_rec_input_clauses (tree clauses, g
 	  switch (OMP_CLAUSE_CODE (c))
 	    {
 	    case OMP_CLAUSE_SHARED:
+	      /* Ignore shared directives in teams construct.  */
+	      if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS)
+		continue;
 	      /* Shared global vars are just accessed directly.  */
 	      if (is_global_var (new_var))
 		break;
@@ -6728,7 +6907,8 @@  expand_omp_synch (struct omp_region *reg
   gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SINGLE
 	      || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_MASTER
 	      || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ORDERED
-	      || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_CRITICAL);
+	      || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_CRITICAL
+	      || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_TEAMS);
   gsi_remove (&si, true);
   single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
 
@@ -7317,6 +7497,318 @@  expand_omp_atomic (struct omp_region *re
 }
 
 
+/* Expand the OpenMP target{, data, update} directive 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;
+  gimple_stmt_iterator gsi;
+  gimple entry_stmt, stmt;
+  edge e;
+
+  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)
+    {
+      child_fn = gimple_omp_target_child_fn (entry_stmt);
+      child_cfun = DECL_STRUCT_FUNCTION (child_fn);
+    }
+
+  entry_bb = region->entry;
+  exit_bb = region->exit;
+
+  if (kind == GF_OMP_TARGET_KIND_REGION)
+    {
+      unsigned srcidx, dstidx, num;
+
+      /* If the target region needs data sent from the parent
+	 function, then the very first statement (except possible
+	 tree profile counter updates) of the parallel body
+	 is a copy assignment .OMP_DATA_I = &.OMP_DATA_O.  Since
+	 &.OMP_DATA_O is passed as an argument to the child function,
+	 we need to replace it with the argument as seen by the child
+	 function.
+
+	 In most cases, this will end up being the identity assignment
+	 .OMP_DATA_I = .OMP_DATA_I.  However, if the parallel body had
+	 a function call that has been inlined, the original PARM_DECL
+	 .OMP_DATA_I may have been converted into a different local
+	 variable.  In which case, we need to keep the assignment.  */
+      if (gimple_omp_target_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);
+
+	  for (gsi = gsi_start_bb (entry_succ_bb); ; gsi_next (&gsi))
+	    {
+	      gcc_assert (!gsi_end_p (gsi));
+	      stmt = gsi_stmt (gsi);
+	      if (gimple_code (stmt) != GIMPLE_ASSIGN)
+		continue;
+
+	      if (gimple_num_ops (stmt) == 2)
+		{
+		  tree arg = gimple_assign_rhs1 (stmt);
+
+		  /* We're ignoring the subcode because we're
+		     effectively doing a STRIP_NOPS.  */
+
+		  if (TREE_CODE (arg) == ADDR_EXPR
+		      && TREE_OPERAND (arg, 0) == sender)
+		    {
+		      tgtcopy_stmt = stmt;
+		      break;
+		    }
+		}
+	    }
+
+	  gcc_assert (tgtcopy_stmt != NULL);
+	  arg = DECL_ARGUMENTS (child_fn);
+
+	  gcc_assert (gimple_assign_lhs (tgtcopy_stmt) == arg);
+	  gsi_remove (&gsi, true);
+	}
+
+      /* Declare local variables needed in CHILD_CFUN.  */
+      block = DECL_INITIAL (child_fn);
+      BLOCK_VARS (block) = vec2chain (child_cfun->local_decls);
+      /* The gimplifier could record temporaries in target block
+	 rather than in containing function's local_decls chain,
+	 which would mean cgraph missed finalizing them.  Do it now.  */
+      for (t = BLOCK_VARS (block); t; t = DECL_CHAIN (t))
+	if (TREE_CODE (t) == VAR_DECL
+	    && TREE_STATIC (t)
+	    && !DECL_EXTERNAL (t))
+	  varpool_finalize_decl (t);
+      DECL_SAVED_TREE (child_fn) = NULL;
+      /* We'll create a CFG for child_fn, so no gimple body is needed.  */
+      gimple_set_body (child_fn, NULL);
+      TREE_USED (block) = 1;
+
+      /* Reset DECL_CONTEXT on function arguments.  */
+      for (t = DECL_ARGUMENTS (child_fn); t; t = DECL_CHAIN (t))
+	DECL_CONTEXT (t) = child_fn;
+
+      /* Split ENTRY_BB at GIMPLE_OMP_TARGET,
+	 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);
+      gsi_remove (&gsi, true);
+      e = split_block (entry_bb, stmt);
+      entry_bb = e->dest;
+      single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
+
+      /* Convert GIMPLE_OMP_RETURN into a RETURN_EXPR.  */
+      if (exit_bb)
+	{
+	  gsi = gsi_last_bb (exit_bb);
+	  gcc_assert (!gsi_end_p (gsi)
+		      && gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
+	  stmt = gimple_build_return (NULL);
+	  gsi_insert_after (&gsi, stmt, GSI_SAME_STMT);
+	  gsi_remove (&gsi, true);
+	}
+
+      /* Move the target region into CHILD_CFUN.  */
+
+      block = gimple_block (entry_stmt);
+
+      new_bb = move_sese_region_to_fn (child_cfun, entry_bb, exit_bb, block);
+      if (exit_bb)
+	single_succ_edge (new_bb)->flags = EDGE_FALLTHRU;
+      /* When the OMP expansion process cannot guarantee an up-to-date
+	 loop tree arrange for the child function to fixup loops.  */
+      if (loops_state_satisfies_p (LOOPS_NEED_FIXUP))
+	child_cfun->x_current_loops->state |= LOOPS_NEED_FIXUP;
+
+      /* Remove non-local VAR_DECLs from child_cfun->local_decls list.  */
+      num = vec_safe_length (child_cfun->local_decls);
+      for (srcidx = 0, dstidx = 0; srcidx < num; srcidx++)
+	{
+	  t = (*child_cfun->local_decls)[srcidx];
+	  if (DECL_CONTEXT (t) == cfun->decl)
+	    continue;
+	  if (srcidx != dstidx)
+	    (*child_cfun->local_decls)[dstidx] = t;
+	  dstidx++;
+	}
+      if (dstidx != num)
+	vec_safe_truncate (child_cfun->local_decls, dstidx);
+
+      /* Inform the callgraph about the new function.  */
+      DECL_STRUCT_FUNCTION (child_fn)->curr_properties = cfun->curr_properties;
+      cgraph_add_new_function (child_fn, true);
+
+      /* Fix the callgraph edges for child_cfun.  Those for cfun will be
+	 fixed in a following pass.  */
+      push_cfun (child_cfun);
+      rebuild_cgraph_edges ();
+
+      /* Some EH regions might become dead, see PR34608.  If
+	 pass_cleanup_cfg isn't the first pass to happen with the
+	 new child, these dead EH edges might cause problems.
+	 Clean them up now.  */
+      if (flag_exceptions)
+	{
+	  basic_block bb;
+	  bool changed = false;
+
+	  FOR_EACH_BB (bb)
+	    changed |= gimple_purge_dead_eh_edges (bb);
+	  if (changed)
+	    cleanup_tree_cfg ();
+	}
+      pop_cfun ();
+    }
+
+  /* Emit a library call to launch the target region, or do data
+     transfers.  */
+  tree t1, t2, t3, t4, device, cond, c, clauses;
+  enum built_in_function start_ix;
+  location_t clause_loc;
+
+  clauses = gimple_omp_target_clauses (entry_stmt);
+
+  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;
+
+  /* By default, the value of DEVICE is -1 (let runtime library choose)
+     and there is no conditional.  */
+  cond = NULL_TREE;
+  device = build_int_cst (integer_type_node, -1);
+
+  c = find_omp_clause (clauses, OMP_CLAUSE_IF);
+  if (c)
+    cond = OMP_CLAUSE_IF_EXPR (c);
+
+  c = find_omp_clause (clauses, OMP_CLAUSE_DEVICE);
+  if (c)
+    {
+      device = OMP_CLAUSE_DEVICE_ID (c);
+      clause_loc = OMP_CLAUSE_LOCATION (c);
+    }
+  else
+    clause_loc = gimple_location (entry_stmt);
+
+  /* Ensure 'device' is of the correct type.  */
+  device = fold_convert_loc (clause_loc, integer_type_node, device);
+
+  /* If we found the clause 'if (cond)', build
+     (cond ? device : -2).  */
+  if (cond)
+    {
+      cond = gimple_boolify (cond);
+
+      basic_block cond_bb, then_bb, else_bb;
+      edge e;
+      tree tmp_var;
+
+      tmp_var = create_tmp_var (TREE_TYPE (device), NULL);
+      e = split_block (entry_bb, NULL);
+      cond_bb = e->src;
+      entry_bb = e->dest;
+      remove_edge (e);
+
+      then_bb = create_empty_bb (cond_bb);
+      else_bb = create_empty_bb (then_bb);
+      set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);
+      set_immediate_dominator (CDI_DOMINATORS, else_bb, cond_bb);
+
+      stmt = gimple_build_cond_empty (cond);
+      gsi = gsi_start_bb (cond_bb);
+      gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
+
+      gsi = gsi_start_bb (then_bb);
+      stmt = gimple_build_assign (tmp_var, device);
+      gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
+
+      gsi = gsi_start_bb (else_bb);
+      stmt = gimple_build_assign (tmp_var,
+				  build_int_cst (integer_type_node, -2));
+      gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
+
+      make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE);
+      make_edge (cond_bb, else_bb, EDGE_FALSE_VALUE);
+      if (current_loops)
+	{
+	  add_bb_to_loop (then_bb, cond_bb->loop_father);
+	  add_bb_to_loop (else_bb, cond_bb->loop_father);
+	}
+      make_edge (then_bb, entry_bb, EDGE_FALLTHRU);
+      make_edge (else_bb, entry_bb, EDGE_FALLTHRU);
+
+      device = tmp_var;
+    }
+
+  gsi = gsi_last_bb (new_bb);
+  t = gimple_omp_target_data_arg (entry_stmt);
+  if (t == NULL)
+    {
+      t1 = size_zero_node;
+      t2 = build_zero_cst (ptr_type_node);
+      t3 = t2;
+      t4 = t2;
+    }
+  else
+    {
+      t1 = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (TREE_VEC_ELT (t, 1))));
+      t1 = size_binop (PLUS_EXPR, t1, size_int (1));
+      t2 = build_fold_addr_expr (TREE_VEC_ELT (t, 0));
+      t3 = build_fold_addr_expr (TREE_VEC_ELT (t, 1));
+      t4 = build_fold_addr_expr (TREE_VEC_ELT (t, 2));
+    }
+
+  gimple g;
+  if (kind == GF_OMP_TARGET_KIND_REGION)
+    {
+      tree fnaddr = build_fold_addr_expr (child_fn);
+      unsigned fnnamelen = IDENTIFIER_LENGTH (DECL_NAME (child_fn));
+      tree fnname = build_string (fnnamelen,
+				  IDENTIFIER_POINTER (DECL_NAME (child_fn)));
+      TREE_TYPE (fnname) = build_array_type_nelts (char_type_node,
+						   fnnamelen);
+      TREE_READONLY (fnname) = 1;
+      TREE_STATIC (fnname) = 1;
+      fnname = build_fold_addr_expr (fnname);
+      g = gimple_build_call (builtin_decl_explicit (start_ix), 7,
+			     device, fnaddr, fnname, t1, t2, t3, t4);
+    }
+  else
+    g = gimple_build_call (builtin_decl_explicit (start_ix), 5,
+			   device, t1, t2, t3, t4);
+  gimple_set_location (g, gimple_location (entry_stmt));
+  gsi_insert_before (&gsi, g, GSI_SAME_STMT);
+  if (kind != GF_OMP_TARGET_KIND_REGION)
+    {
+      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)
+    {
+      gsi = gsi_last_bb (region->exit);
+      g = gsi_stmt (gsi);
+      gcc_assert (g && gimple_code (g) == GIMPLE_OMP_RETURN);
+      gsi_remove (&gsi, true);
+    }
+}
+
+
 /* Expand the parallel region tree rooted at REGION.  Expansion
    proceeds in depth-first order.  Innermost regions are expanded
    first.  This way, parallel regions that require a new function to
@@ -7374,6 +7866,7 @@  expand_omp (struct omp_region *region)
 	case GIMPLE_OMP_MASTER:
 	case GIMPLE_OMP_ORDERED:
 	case GIMPLE_OMP_CRITICAL:
+	case GIMPLE_OMP_TEAMS:
 	  expand_omp_synch (region);
 	  break;
 
@@ -7381,6 +7874,10 @@  expand_omp (struct omp_region *region)
 	  expand_omp_atomic (region);
 	  break;
 
+	case GIMPLE_OMP_TARGET:
+	  expand_omp_target (region);
+	  break;
+
 	default:
 	  gcc_unreachable ();
 	}
@@ -7445,6 +7942,9 @@  build_omp_regions_1 (basic_block bb, str
 	     GIMPLE_OMP_SECTIONS, and we do nothing for it.  */
 	  ;
 	}
+      else if (code == GIMPLE_OMP_TARGET
+	       && gimple_omp_target_kind (stmt) == GF_OMP_TARGET_KIND_UPDATE)
+	new_omp_region (bb, code, parent);
       else
 	{
 	  /* Otherwise, this directive becomes the parent for a new
@@ -7825,7 +8325,7 @@  lower_omp_single (gimple_stmt_iterator *
 {
   tree block;
   gimple t, bind, single_stmt = gsi_stmt (*gsi_p);
-  gimple_seq bind_body, dlist;
+  gimple_seq bind_body, bind_body_tail = NULL, dlist;
   struct gimplify_ctx gctx;
 
   push_gimplify_context (&gctx);
@@ -7855,8 +8355,17 @@  lower_omp_single (gimple_stmt_iterator *
   t = gimple_build_omp_return
         (!!find_omp_clause (gimple_omp_single_clauses (single_stmt),
 			    OMP_CLAUSE_NOWAIT));
-  gimple_seq_add_stmt (&bind_body, t);
-  maybe_add_implicit_barrier_cancel (ctx, &bind_body);
+  gimple_seq_add_stmt (&bind_body_tail, t);
+  maybe_add_implicit_barrier_cancel (ctx, &bind_body_tail);
+  if (ctx->record_type)
+    {
+      gimple_stmt_iterator gsi = gsi_start (bind_body_tail);
+      tree clobber = build_constructor (ctx->record_type, NULL);
+      TREE_THIS_VOLATILE (clobber) = 1;
+      gsi_insert_after (&gsi, gimple_build_assign (ctx->sender_decl,
+						   clobber), GSI_SAME_STMT);
+    }
+  gimple_seq_add_seq (&bind_body, bind_body_tail);
   gimple_bind_set_body (bind, bind_body);
 
   pop_gimplify_context (bind);
@@ -8605,6 +9114,14 @@  lower_omp_taskreg (gimple_stmt_iterator
   lower_send_clauses (clauses, &ilist, &olist, ctx);
   lower_send_shared_vars (&ilist, &olist, ctx);
 
+  if (ctx->record_type)
+    {
+      tree clobber = build_constructor (TREE_TYPE (ctx->sender_decl), NULL);
+      TREE_THIS_VOLATILE (clobber) = 1;
+      gimple_seq_add_stmt (&olist, gimple_build_assign (ctx->sender_decl,
+							clobber));
+    }
+
   /* Once all the expansions are done, sequence all the different
      fragments inside gimple_omp_body.  */
 
@@ -8637,6 +9154,326 @@  lower_omp_taskreg (gimple_stmt_iterator
   pop_gimplify_context (NULL);
 }
 
+/* Lower the OpenMP target directive in the current statement
+   in GSI_P.  CTX holds context information for the directive.  */
+
+static void
+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;
+  struct gimplify_ctx gctx;
+  location_t loc = gimple_location (stmt);
+  int kind = gimple_omp_target_kind (stmt);
+  unsigned int map_cnt = 0;
+
+  clauses = gimple_omp_target_clauses (stmt);
+  if (kind == GF_OMP_TARGET_KIND_REGION)
+    {
+      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)
+    tgt_body = gimple_omp_body (stmt);
+  child_fn = ctx->cb.dst_fn;
+
+  push_gimplify_context (&gctx);
+
+  for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+    switch (OMP_CLAUSE_CODE (c))
+      {
+	tree var, x;
+
+      default:
+	break;
+      case OMP_CLAUSE_MAP:
+      case OMP_CLAUSE_TO:
+      case OMP_CLAUSE_FROM:
+	var = OMP_CLAUSE_DECL (c);
+	if (!DECL_P (var))
+	  {
+	    if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP
+		|| !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c))
+	      map_cnt++;
+	    continue;
+	  }
+	if (!lookup_sfield (var, ctx))
+	  continue;
+
+	if (kind == GF_OMP_TARGET_KIND_REGION)
+	  {
+	    x = build_receiver_ref (var, true, ctx);
+	    tree new_var = lookup_decl (var, ctx);
+	    SET_DECL_VALUE_EXPR (new_var, x);
+	    DECL_HAS_VALUE_EXPR_P (new_var) = 1;
+	  }
+	map_cnt++;
+      }
+
+  if (kind != GF_OMP_TARGET_KIND_UPDATE)
+    lower_omp (&tgt_body, ctx);
+
+  if (kind == GF_OMP_TARGET_KIND_REGION)
+    {
+      /* Declare all the variables created by mapping and the variables
+	 declared in the scope of the target body.  */
+      record_vars_into (ctx->block_vars, child_fn);
+      record_vars_into (gimple_bind_vars (tgt_bind), child_fn);
+    }
+
+  olist = NULL;
+  ilist = NULL;
+  if (ctx->record_type)
+    {
+      ctx->sender_decl
+	= create_tmp_var (ctx->record_type, ".omp_data_arr");
+      DECL_NAMELESS (ctx->sender_decl) = 1;
+      TREE_ADDRESSABLE (ctx->sender_decl) = 1;
+      t = make_tree_vec (3);
+      TREE_VEC_ELT (t, 0) = ctx->sender_decl;
+      TREE_VEC_ELT (t, 1)
+	= create_tmp_var (build_array_type_nelts (size_type_node, map_cnt),
+			  ".omp_data_sizes");
+      DECL_NAMELESS (TREE_VEC_ELT (t, 1)) = 1;
+      TREE_ADDRESSABLE (TREE_VEC_ELT (t, 1)) = 1;
+      TREE_STATIC (TREE_VEC_ELT (t, 1)) = 1;
+      TREE_VEC_ELT (t, 2)
+	= create_tmp_var (build_array_type_nelts (unsigned_char_type_node,
+						  map_cnt),
+			  ".omp_data_kinds");
+      DECL_NAMELESS (TREE_VEC_ELT (t, 2)) = 1;
+      TREE_ADDRESSABLE (TREE_VEC_ELT (t, 2)) = 1;
+      TREE_STATIC (TREE_VEC_ELT (t, 2)) = 1;
+      gimple_omp_target_set_data_arg (stmt, t);
+
+      vec<constructor_elt, va_gc> *vsize;
+      vec<constructor_elt, va_gc> *vkind;
+      vec_alloc (vsize, map_cnt);
+      vec_alloc (vkind, map_cnt);
+      unsigned int map_idx = 0;
+
+      for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+	switch (OMP_CLAUSE_CODE (c))
+	  {
+	    tree ovar, nc;
+
+	  default:
+	    break;
+	  case OMP_CLAUSE_MAP:
+	  case OMP_CLAUSE_TO:
+	  case OMP_CLAUSE_FROM:
+	    nc = c;
+	    ovar = OMP_CLAUSE_DECL (c);
+	    if (!DECL_P (ovar))
+	      {
+		if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+		    && OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c))
+		  {
+		    gcc_checking_assert (OMP_CLAUSE_DECL (OMP_CLAUSE_CHAIN (c))
+					 == get_base_address (ovar));
+		    nc = OMP_CLAUSE_CHAIN (c);
+		    ovar = OMP_CLAUSE_DECL (nc);
+		  }
+		else
+		  {
+		    tree x = build_sender_ref (ovar, ctx);
+		    tree v
+		      = build_fold_addr_expr_with_type (ovar, ptr_type_node);
+		    gimplify_assign (x, v, &ilist);
+		    nc = NULL_TREE;
+		  }
+	      }
+	    else if (!lookup_sfield (ovar, ctx))
+	      continue;
+
+	    if (nc)
+	      {
+		tree var = lookup_decl_in_outer_ctx (ovar, ctx);
+		tree x = build_sender_ref (ovar, ctx);
+		if (is_gimple_reg (var))
+		  {
+		    gcc_assert (kind == GF_OMP_TARGET_KIND_REGION);
+		    tree avar = create_tmp_var (TREE_TYPE (var), NULL);
+		    mark_addressable (avar);
+		    if (OMP_CLAUSE_MAP_KIND (c) != OMP_CLAUSE_MAP_ALLOC
+			&& OMP_CLAUSE_MAP_KIND (c) != OMP_CLAUSE_MAP_FROM)
+		      gimplify_assign (avar, var, &ilist);
+		    avar = build_fold_addr_expr (avar);
+		    gimplify_assign (x, avar, &ilist);
+		    if ((OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_FROM
+			 || OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_TOFROM)
+			&& !TYPE_READONLY (TREE_TYPE (var)))
+		      {
+			x = build_sender_ref (ovar, ctx);
+			x = build_simple_mem_ref (x);
+			gimplify_assign (var, x, &olist);
+		      }
+		  }
+		else
+		  {
+		    var = build_fold_addr_expr (var);
+		    gimplify_assign (x, var, &ilist);
+		  }
+	      }
+	    tree s = OMP_CLAUSE_SIZE (c);
+	    if (s == NULL_TREE)
+	      s = TYPE_SIZE (TREE_TYPE (ovar));
+	    s = fold_convert (size_type_node, s);
+	    tree purpose = size_int (map_idx++);
+	    CONSTRUCTOR_APPEND_ELT (vsize, purpose, s);
+	    if (TREE_CODE (s) != INTEGER_CST)
+	      TREE_STATIC (TREE_VEC_ELT (t, 1)) = 0;
+
+	    unsigned char tkind = 0;
+	    switch (OMP_CLAUSE_CODE (c))
+	      {
+	      case OMP_CLAUSE_MAP:
+		tkind = OMP_CLAUSE_MAP_KIND (c);
+		break;
+	      case OMP_CLAUSE_TO:
+		tkind = OMP_CLAUSE_MAP_TO;
+		break;
+	      case OMP_CLAUSE_FROM:
+		tkind = OMP_CLAUSE_MAP_FROM;
+		break;
+	      default:
+		gcc_unreachable ();
+	      }
+	    CONSTRUCTOR_APPEND_ELT (vkind, purpose,
+				    build_int_cst (unsigned_char_type_node,
+						   tkind));
+	    if (nc && nc != c)
+	      c = nc;
+	  }
+
+      gcc_assert (map_idx == map_cnt);
+
+      DECL_INITIAL (TREE_VEC_ELT (t, 1))
+	= build_constructor (TREE_TYPE (TREE_VEC_ELT (t, 1)), vsize);
+      DECL_INITIAL (TREE_VEC_ELT (t, 2))
+	= build_constructor (TREE_TYPE (TREE_VEC_ELT (t, 2)), vkind);
+      if (!TREE_STATIC (TREE_VEC_ELT (t, 1)))
+	{
+	  gimple_seq initlist = NULL;
+	  force_gimple_operand (build1 (DECL_EXPR, void_type_node,
+					TREE_VEC_ELT (t, 1)),
+				&initlist, true, NULL_TREE);
+	  gimple_seq_add_seq (&ilist, initlist);
+	}
+
+      tree clobber = build_constructor (ctx->record_type, NULL);
+      TREE_THIS_VOLATILE (clobber) = 1;
+      gimple_seq_add_stmt (&olist, gimple_build_assign (ctx->sender_decl,
+							clobber));
+    }
+
+  /* Once all the expansions are done, sequence all the different
+     fragments inside gimple_omp_body.  */
+
+  new_body = NULL;
+
+  if (ctx->record_type && kind == GF_OMP_TARGET_KIND_REGION)
+    {
+      t = build_fold_addr_expr_loc (loc, ctx->sender_decl);
+      /* fixup_child_record_type might have changed receiver_decl's type.  */
+      t = fold_convert_loc (loc, TREE_TYPE (ctx->receiver_decl), t);
+      gimple_seq_add_stmt (&new_body,
+	  		   gimple_build_assign (ctx->receiver_decl, t));
+    }
+
+  if (kind == GF_OMP_TARGET_KIND_REGION)
+    {
+      gimple_seq_add_seq (&new_body, tgt_body);
+      new_body = maybe_catch_exception (new_body);
+    }
+  else if (kind == GF_OMP_TARGET_KIND_DATA)
+    new_body = tgt_body;
+  if (kind != GF_OMP_TARGET_KIND_UPDATE)
+    {
+      gimple_seq_add_stmt (&new_body, gimple_build_omp_return (false));
+      gimple_omp_set_body (stmt, new_body);
+    }
+
+  bind = gimple_build_bind (NULL, NULL,
+			    tgt_bind ? gimple_bind_block (tgt_bind)
+				     : NULL_TREE);
+  gsi_replace (gsi_p, bind, true);
+  gimple_bind_add_seq (bind, ilist);
+  gimple_bind_add_stmt (bind, stmt);
+  gimple_bind_add_seq (bind, olist);
+
+  pop_gimplify_context (NULL);
+}
+
+/* Expand code for an OpenMP teams directive.  */
+
+static void
+lower_omp_teams (gimple_stmt_iterator *gsi_p, omp_context *ctx)
+{
+  gimple teams_stmt = gsi_stmt (*gsi_p);
+  struct gimplify_ctx gctx;
+  push_gimplify_context (&gctx);
+
+  tree block = make_node (BLOCK);
+  gimple bind = gimple_build_bind (NULL, NULL, block);
+  gsi_replace (gsi_p, bind, true);
+  gimple_seq bind_body = NULL;
+  gimple_seq dlist = NULL;
+  gimple_seq olist = NULL;
+
+  tree num_teams = find_omp_clause (gimple_omp_teams_clauses (teams_stmt),
+				    OMP_CLAUSE_NUM_TEAMS);
+  if (num_teams == NULL_TREE)
+    num_teams = build_int_cst (unsigned_type_node, 0);
+  else
+    {
+      num_teams = OMP_CLAUSE_NUM_TEAMS_EXPR (num_teams);
+      num_teams = fold_convert (unsigned_type_node, num_teams);
+      gimplify_expr (&num_teams, &bind_body, NULL, is_gimple_val, fb_rvalue);
+    }
+  tree thread_limit = find_omp_clause (gimple_omp_teams_clauses (teams_stmt),
+				       OMP_CLAUSE_THREAD_LIMIT);
+  if (thread_limit == NULL_TREE)
+    thread_limit = build_int_cst (unsigned_type_node, 0);
+  else
+    {
+      thread_limit = OMP_CLAUSE_THREAD_LIMIT_EXPR (thread_limit);
+      thread_limit = fold_convert (unsigned_type_node, thread_limit);
+      gimplify_expr (&thread_limit, &bind_body, NULL, is_gimple_val,
+		     fb_rvalue);
+    }
+
+  lower_rec_input_clauses (gimple_omp_teams_clauses (teams_stmt),
+			   &bind_body, &dlist, ctx, NULL);
+  lower_omp (gimple_omp_body_ptr (teams_stmt), ctx);
+  lower_reduction_clauses (gimple_omp_teams_clauses (teams_stmt), &olist, ctx);
+  gimple_seq_add_stmt (&bind_body, teams_stmt);
+
+  location_t loc = gimple_location (teams_stmt);
+  tree decl = builtin_decl_explicit (BUILT_IN_GOMP_TEAMS);
+  gimple call = gimple_build_call (decl, 2, num_teams, thread_limit);
+  gimple_set_location (call, loc);
+  gimple_seq_add_stmt (&bind_body, call);
+
+  gimple_seq_add_seq (&bind_body, gimple_omp_body (teams_stmt));
+  gimple_omp_set_body (teams_stmt, NULL);
+  gimple_seq_add_seq (&bind_body, olist);
+  gimple_seq_add_seq (&bind_body, dlist);
+  gimple_seq_add_stmt (&bind_body, gimple_build_omp_return (true));
+  gimple_bind_set_body (bind, bind_body);
+
+  pop_gimplify_context (bind);
+
+  gimple_bind_append_vars (bind, ctx->block_vars);
+  BLOCK_VARS (block) = ctx->block_vars;
+  if (BLOCK_VARS (block))
+    TREE_USED (block) = 1;
+}
+
+
 /* Callback for lower_omp_1.  Return non-NULL if *tp needs to be
    regimplified.  If DATA is non-NULL, lower_omp_1 is outside
    of OpenMP context, but with task_shared_vars set.  */
@@ -8760,6 +9597,16 @@  lower_omp_1 (gimple_stmt_iterator *gsi_p
 			lower_omp_regimplify_p, ctx ? NULL : &wi, NULL))
 	gimple_regimplify_operands (stmt, gsi_p);
       break;
+    case GIMPLE_OMP_TARGET:
+      ctx = maybe_lookup_ctx (stmt);
+      gcc_assert (ctx);
+      lower_omp_target (gsi_p, ctx);
+      break;
+    case GIMPLE_OMP_TEAMS:
+      ctx = maybe_lookup_ctx (stmt);
+      gcc_assert (ctx);
+      lower_omp_teams (gsi_p, ctx);
+      break;
     case GIMPLE_CALL:
       tree fndecl;
       fndecl = gimple_call_fndecl (stmt);
--- gcc/c/c-typeck.c.jj	2013-08-27 20:49:05.000000000 +0200
+++ gcc/c/c-typeck.c	2013-09-04 17:21:17.295112407 +0200
@@ -10773,8 +10773,7 @@  c_finish_omp_cancellation_point (locatio
 
 static tree
 handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
-			     bool &maybe_zero_len, unsigned int &first_non_one,
-			     bool &pointer_based_p)
+			     bool &maybe_zero_len, unsigned int &first_non_one)
 {
   tree ret, low_bound, length, type;
   if (TREE_CODE (t) != TREE_LIST)
@@ -10801,15 +10800,11 @@  handle_omp_array_sections_1 (tree c, tre
 		    omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
 	  return error_mark_node;
 	}
-      if (POINTER_TYPE_P (TREE_TYPE (t))
-	  && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP)
-	pointer_based_p = true;
       return t;
     }
 
   ret = handle_omp_array_sections_1 (c, TREE_CHAIN (t), types,
-				     maybe_zero_len, first_non_one,
-				     pointer_based_p);
+				     maybe_zero_len, first_non_one);
   if (ret == error_mark_node || ret == NULL_TREE)
     return ret;
 
@@ -10989,16 +10984,12 @@  handle_omp_array_sections_1 (tree c, tre
     }
   if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND)
     types.safe_push (TREE_TYPE (ret));
-  /* For pointer based array sections we will need to evaluate lb more
-     than once.  */
-  if (pointer_based_p)
+  /* We will need to evaluate lb more than once.  */
+  tree lb = c_save_expr (low_bound);
+  if (lb != low_bound)
     {
-      tree lb = c_save_expr (low_bound);
-      if (lb != low_bound)
-	{
-	  TREE_PURPOSE (t) = lb;
-	  low_bound = lb;
-	}
+      TREE_PURPOSE (t) = lb;
+      low_bound = lb;
     }
   ret = build_array_ref (OMP_CLAUSE_LOCATION (c), ret, low_bound);
   return ret;
@@ -11010,12 +11001,10 @@  static bool
 handle_omp_array_sections (tree c)
 {
   bool maybe_zero_len = false;
-  bool pointer_based_p = false;
   unsigned int first_non_one = 0;
   vec<tree> types = vNULL;
   tree first = handle_omp_array_sections_1 (c, OMP_CLAUSE_DECL (c), types,
-					    maybe_zero_len, first_non_one,
-					    pointer_based_p);
+					    maybe_zero_len, first_non_one);
   if (first == error_mark_node)
     {
       types.release ();
@@ -11047,6 +11036,7 @@  handle_omp_array_sections (tree c)
 	}
       if (tem)
 	first = build2 (COMPOUND_EXPR, TREE_TYPE (first), tem, first);
+      first = c_fully_fold (first, false, NULL);
       OMP_CLAUSE_DECL (c) = first;
     }
   else
@@ -11155,27 +11145,31 @@  handle_omp_array_sections (tree c)
       types.release ();
       if (side_effects)
 	size = build2 (COMPOUND_EXPR, sizetype, side_effects, size);
+      first = c_fully_fold (first, false, NULL);
       OMP_CLAUSE_DECL (c) = first;
+      if (size)
+	size = c_fully_fold (size, false, NULL);
       OMP_CLAUSE_SIZE (c) = size;
-      if (pointer_based_p)
-	{
-	  tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP);
-	  OMP_CLAUSE_MAP_KIND (c2) = OMP_CLAUSE_MAP_POINTER;
-	  if (!c_mark_addressable (t))
-	    return false;
-	  OMP_CLAUSE_DECL (c2) = t;
-	  t = build_fold_addr_expr (first);
-	  t = fold_convert_loc (OMP_CLAUSE_LOCATION (c),
-				build_pointer_type (char_type_node), t);
-	  t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR,
-			       ptrdiff_type_node, t,
-			       fold_convert_loc (OMP_CLAUSE_LOCATION (c),
-						 TREE_TYPE (t),
-						 OMP_CLAUSE_DECL (c2)));
-	  OMP_CLAUSE_SIZE (c2) = t;
-	  OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c);
-	  OMP_CLAUSE_CHAIN (c) = c2;
-	}
+      if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP)
+	return false;
+      tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP);
+      OMP_CLAUSE_MAP_KIND (c2) = OMP_CLAUSE_MAP_POINTER;
+      if (!c_mark_addressable (t))
+	return false;
+      OMP_CLAUSE_DECL (c2) = t;
+      t = build_fold_addr_expr (first);
+      t = fold_convert_loc (OMP_CLAUSE_LOCATION (c), ptrdiff_type_node, t);
+      tree ptr = OMP_CLAUSE_DECL (c2);
+      if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
+	ptr = build_fold_addr_expr (ptr);
+      t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR,
+			   ptrdiff_type_node, t,
+			   fold_convert_loc (OMP_CLAUSE_LOCATION (c),
+					     ptrdiff_type_node, ptr));
+      t = c_fully_fold (t, false, NULL);
+      OMP_CLAUSE_SIZE (c2) = t;
+      OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c);
+      OMP_CLAUSE_CHAIN (c) = c2;
     }
   return false;
 }
@@ -11462,18 +11456,21 @@  c_finish_omp_clauses (tree clauses)
 	    }
 	  else if (!c_mark_addressable (t))
 	    remove = true;
-	  else if (!COMPLETE_TYPE_P (TREE_TYPE (t)))
+	  else if (!COMPLETE_TYPE_P (TREE_TYPE (t))
+		   && !(OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+			&& OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER))
 	    {
 	      error_at (OMP_CLAUSE_LOCATION (c),
 			"%qD does not have a mappable type in %qs clause", t,
 			omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
 	      remove = true;
 	    }
-	  else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP)
-	    break;
 	  else if (bitmap_bit_p (&generic_head, DECL_UID (t)))
 	    {
-	      error ("%qD appears more than once in motion clauses", t);
+	      if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP)
+		error ("%qD appears more than once in motion clauses", t);
+	      else
+		error ("%qD appears more than once in map clauses", t);
 	      remove = true;
 	    }
 	  else
@@ -11509,6 +11506,7 @@  c_finish_omp_clauses (tree clauses)
 
 	case OMP_CLAUSE_IF:
 	case OMP_CLAUSE_NUM_THREADS:
+	case OMP_CLAUSE_NUM_TEAMS:
 	case OMP_CLAUSE_THREAD_LIMIT:
 	case OMP_CLAUSE_SCHEDULE:
 	case OMP_CLAUSE_ORDERED:
--- gcc/c/c-parser.c.jj	2013-08-27 20:49:04.000000000 +0200
+++ gcc/c/c-parser.c	2013-09-02 11:41:51.023319550 +0200
@@ -12068,7 +12068,10 @@  c_parser_omp_target_data (location_t loc
   OMP_TARGET_DATA_CLAUSES (stmt)
     = c_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK,
 				"#pragma omp target data");
-  OMP_TARGET_DATA_BODY (stmt) = c_parser_omp_structured_block (parser);
+  keep_next_level ();
+  tree block = c_begin_compound_stmt (true);
+  add_stmt (c_parser_omp_structured_block (parser));
+  OMP_TARGET_DATA_BODY (stmt) = c_end_compound_stmt (loc, block, true);
 
   SET_EXPR_LOCATION (stmt, loc);
   return add_stmt (stmt);
@@ -12161,6 +12164,7 @@  c_parser_omp_target (c_parser *parser, e
 
 	  c_parser_consume_token (parser);
 	  strcpy (p_name, "#pragma omp target");
+	  keep_next_level ();
 	  tree block = c_begin_compound_stmt (true);
 	  tree ret = c_parser_omp_teams (loc, parser, p_name,
 					 OMP_TARGET_CLAUSE_MASK, cclauses);
@@ -12182,7 +12186,10 @@  c_parser_omp_target (c_parser *parser, e
   OMP_TARGET_CLAUSES (stmt)
     = c_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK,
 				"#pragma omp target");
-  OMP_TARGET_BODY (stmt) = c_parser_omp_structured_block (parser);
+  keep_next_level ();
+  tree block = c_begin_compound_stmt (true);
+  add_stmt (c_parser_omp_structured_block (parser));
+  OMP_TARGET_BODY (stmt) = c_end_compound_stmt (loc, block, true);
 
   SET_EXPR_LOCATION (stmt, loc);
   add_stmt (stmt);
--- gcc/tree.h.jj	2013-08-27 22:05:43.000000000 +0200
+++ gcc/tree.h	2013-09-03 14:35:36.350942556 +0200
@@ -629,6 +629,9 @@  struct GTY(()) tree_base {
        OMP_CLAUSE_LINEAR_NO_COPYIN in
 	   OMP_CLAUSE_LINEAR
 
+       OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION in
+	   OMP_CLAUSE_MAP
+
        TRANSACTION_EXPR_RELAXED in
 	   TRANSACTION_EXPR
 
@@ -2050,15 +2053,21 @@  enum omp_clause_map_kind
   OMP_CLAUSE_MAP_TO,
   OMP_CLAUSE_MAP_FROM,
   OMP_CLAUSE_MAP_TOFROM,
-  /* This following 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 / BITS_PER_UNIT, but the bias.  */
+  /* 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 / BITS_PER_UNIT, but the bias.  */
   OMP_CLAUSE_MAP_POINTER
 };
 
 #define OMP_CLAUSE_MAP_KIND(NODE) \
   (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)->omp_clause.subcode.map_kind)
 
+/* Nonzero if this map clause is for array (rather than pointer) based array
+   section with zero bias.  Both the non-decl OMP_CLAUSE_MAP and
+   correspoidng OMP_CLAUSE_MAP_POINTER clause are marked with this flag.  */
+#define OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION(NODE) \
+  (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)->base.public_flag)
+
 enum omp_clause_proc_bind_kind
 {
   /* Numbers should match omp_proc_bind_t enum in omp.h.  */
--- gcc/gimple.def.jj	2013-08-19 12:07:51.000000000 +0200
+++ gcc/gimple.def	2013-09-02 11:55:57.892684945 +0200
@@ -349,12 +349,18 @@  DEFGSCODE(GIMPLE_OMP_SECTIONS_SWITCH, "g
    CLAUSES is an OMP_CLAUSE chain holding the associated clauses.  */
 DEFGSCODE(GIMPLE_OMP_SINGLE, "gimple_omp_single", GSS_OMP_SINGLE)
 
-/* GIMPLE_OMP_TARGET <BODY, CLAUSES> represents
+/* GIMPLE_OMP_TARGET <BODY, CLAUSES, CHILD_FN> represents
    #pragma omp target {,data,update}
    BODY is the sequence of statements inside the target construct
    (NULL for target update).
-   CLAUSES is an OMP_CLAUSE chain holding the associated clauses.  */
-DEFGSCODE(GIMPLE_OMP_TARGET, "gimple_omp_target", GSS_OMP_SINGLE)
+   CLAUSES is an OMP_CLAUSE chain holding the associated clauses.
+   CHILD_FN is set when outlining the body of the target 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_OMP_TARGET, "gimple_omp_target", GSS_OMP_PARALLEL)
 
 /* GIMPLE_OMP_TEAMS <BODY, CLAUSES> represents #pragma omp teams
    BODY is the sequence of statements inside the single section.
--- gcc/fortran/types.def.jj	2013-08-19 12:07:51.000000000 +0200
+++ gcc/fortran/types.def	2013-09-04 20:19:40.880566458 +0200
@@ -120,6 +120,7 @@  DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_VPTR_INT
 DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_SIZE_CONST_VPTR, BT_BOOL, BT_SIZE,
 		     BT_CONST_VOLATILE_PTR)
 DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_INT_BOOL, BT_BOOL, BT_INT, BT_BOOL)
+DEF_FUNCTION_TYPE_2 (BT_FN_VOID_UINT_UINT, BT_VOID, BT_UINT, BT_UINT)
 
 DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR)
 
@@ -167,6 +168,8 @@  DEF_FUNCTION_TYPE_5 (BT_FN_BOOL_LONG_LON
 		     BT_PTR_LONG, BT_PTR_LONG)
 DEF_FUNCTION_TYPE_5 (BT_FN_VOID_SIZE_VPTR_PTR_PTR_INT, BT_VOID, BT_SIZE,
 		     BT_VOLATILE_PTR, BT_PTR, BT_PTR, BT_INT)
+DEF_FUNCTION_TYPE_5 (BT_FN_VOID_INT_SIZE_PTR_PTR_PTR,
+		     BT_VOID, BT_INT, BT_SIZE, BT_PTR, BT_PTR, BT_PTR)
 
 DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_LONG_LONG_LONG_LONG_LONGPTR_LONGPTR,
                      BT_BOOL, BT_LONG, BT_LONG, BT_LONG, BT_LONG,
@@ -203,6 +206,9 @@  DEF_FUNCTION_TYPE_7 (BT_FN_BOOL_BOOL_ULL
 		     BT_BOOL, BT_BOOL, BT_ULONGLONG, BT_ULONGLONG,
 		     BT_ULONGLONG, BT_ULONGLONG,
 		     BT_PTR_ULONGLONG, BT_PTR_ULONGLONG)
+DEF_FUNCTION_TYPE_7 (BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR,
+		     BT_VOID, BT_INT, BT_PTR_FN_VOID_PTR, BT_PTR, BT_SIZE,
+		     BT_PTR, BT_PTR, BT_PTR)
 
 DEF_FUNCTION_TYPE_8 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT,
 		     BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT,
--- gcc/cp/parser.c.jj	2013-08-27 20:50:58.000000000 +0200
+++ gcc/cp/parser.c	2013-09-04 17:37:20.511076432 +0200
@@ -29451,6 +29451,7 @@  cp_parser_omp_target_data (cp_parser *pa
   OMP_TARGET_DATA_CLAUSES (stmt)
     = cp_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK,
 				 "#pragma omp target data", pragma_tok);
+  keep_next_level (true);
   OMP_TARGET_DATA_BODY (stmt) = cp_parser_omp_structured_block (parser);
 
   SET_EXPR_LOCATION (stmt, pragma_tok->location);
@@ -29543,6 +29544,7 @@  cp_parser_omp_target (cp_parser *parser,
 
 	  cp_lexer_consume_token (parser->lexer);
 	  strcpy (p_name, "#pragma omp target");
+	  keep_next_level (true);
 	  tree sb = begin_omp_structured_block ();
 	  unsigned save = cp_parser_begin_omp_structured_block (parser);
 	  tree ret = cp_parser_omp_teams (parser, pragma_tok, p_name,
@@ -29566,6 +29568,7 @@  cp_parser_omp_target (cp_parser *parser,
   OMP_TARGET_CLAUSES (stmt)
     = cp_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK,
 				 "#pragma omp target", pragma_tok);
+  keep_next_level (true);
   OMP_TARGET_BODY (stmt) = cp_parser_omp_structured_block (parser);
 
   SET_EXPR_LOCATION (stmt, pragma_tok->location);
--- gcc/cp/cp-objcp-common.h.jj	2013-03-20 10:07:19.000000000 +0100
+++ gcc/cp/cp-objcp-common.h	2013-09-04 19:33:40.520583302 +0200
@@ -145,6 +145,8 @@  extern void cp_common_init_ts (void);
 #define LANG_HOOKS_OMP_FINISH_CLAUSE cxx_omp_finish_clause
 #undef LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE
 #define LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE cxx_omp_privatize_by_reference
+#undef LANG_HOOKS_OMP_MAPPABLE_TYPE
+#define LANG_HOOKS_OMP_MAPPABLE_TYPE cp_omp_mappable_type
 
 #undef LANG_HOOKS_EH_USE_CXA_END_CLEANUP
 #define LANG_HOOKS_EH_USE_CXA_END_CLEANUP true
--- gcc/cp/semantics.c.jj	2013-08-27 20:50:56.000000000 +0200
+++ gcc/cp/semantics.c	2013-09-04 17:21:48.507946784 +0200
@@ -4101,8 +4101,7 @@  cxx_omp_create_clause_info (tree c, tree
 
 static tree
 handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
-			     bool &maybe_zero_len, unsigned int &first_non_one,
-			     bool &pointer_based_p)
+			     bool &maybe_zero_len, unsigned int &first_non_one)
 {
   tree ret, low_bound, length, type;
   if (TREE_CODE (t) != TREE_LIST)
@@ -4134,16 +4133,11 @@  handle_omp_array_sections_1 (tree c, tre
 	  return error_mark_node;
 	}
       t = convert_from_reference (t);
-      if (!processing_template_decl
-	  && POINTER_TYPE_P (TREE_TYPE (t))
-	  && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP)
-	pointer_based_p = true;
       return t;
     }
 
   ret = handle_omp_array_sections_1 (c, TREE_CHAIN (t), types,
-				     maybe_zero_len, first_non_one,
-				     pointer_based_p);
+				     maybe_zero_len, first_non_one);
   if (ret == error_mark_node || ret == NULL_TREE)
     return ret;
 
@@ -4326,16 +4320,12 @@  handle_omp_array_sections_1 (tree c, tre
     }
   if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND)
     types.safe_push (TREE_TYPE (ret));
-  /* For pointer based array sections we will need to evaluate lb more
-     than once.  */
-  if (pointer_based_p)
+  /* We will need to evaluate lb more than once.  */
+  tree lb = cp_save_expr (low_bound);
+  if (lb != low_bound)
     {
-      tree lb = cp_save_expr (low_bound);
-      if (lb != low_bound)
-	{
-	  TREE_PURPOSE (t) = lb;
-	  low_bound = lb;
-	}
+      TREE_PURPOSE (t) = lb;
+      low_bound = lb;
     }
   ret = grok_array_decl (OMP_CLAUSE_LOCATION (c), ret, low_bound, false);
   return ret;
@@ -4347,12 +4337,10 @@  static bool
 handle_omp_array_sections (tree c)
 {
   bool maybe_zero_len = false;
-  bool pointer_based_p = false;
   unsigned int first_non_one = 0;
   vec<tree> types = vNULL;
   tree first = handle_omp_array_sections_1 (c, OMP_CLAUSE_DECL (c), types,
-					    maybe_zero_len, first_non_one,
-					    pointer_based_p);
+					    maybe_zero_len, first_non_one);
   if (first == error_mark_node)
     {
       types.release ();
@@ -4506,26 +4494,27 @@  handle_omp_array_sections (tree c)
 	    size = build2 (COMPOUND_EXPR, sizetype, side_effects, size);
 	  OMP_CLAUSE_DECL (c) = first;
 	  OMP_CLAUSE_SIZE (c) = size;
-	  if (pointer_based_p)
-	    {
-	      tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c),
-					  OMP_CLAUSE_MAP);
-	      OMP_CLAUSE_MAP_KIND (c2) = OMP_CLAUSE_MAP_POINTER;
-	      if (!cxx_mark_addressable (t))
-		return false;
-	      OMP_CLAUSE_DECL (c2) = t;
-	      t = build_fold_addr_expr (first);
-	      t = fold_convert_loc (OMP_CLAUSE_LOCATION (c),
-				    build_pointer_type (char_type_node), t);
-	      t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR,
-				   ptrdiff_type_node, t,
-				   fold_convert_loc (OMP_CLAUSE_LOCATION (c),
-						     TREE_TYPE (t),
-						     OMP_CLAUSE_DECL (c2)));
-	      OMP_CLAUSE_SIZE (c2) = t;
-	      OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c);
-	      OMP_CLAUSE_CHAIN (c) = c2;
-	    }
+	  if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP)
+	    return false;
+	  tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c),
+				      OMP_CLAUSE_MAP);
+	  OMP_CLAUSE_MAP_KIND (c2) = OMP_CLAUSE_MAP_POINTER;
+	  if (!cxx_mark_addressable (t))
+	    return false;
+	  OMP_CLAUSE_DECL (c2) = t;
+	  t = build_fold_addr_expr (first);
+	  t = fold_convert_loc (OMP_CLAUSE_LOCATION (c),
+				ptrdiff_type_node, t);
+	  tree ptr = OMP_CLAUSE_DECL (c2);
+	  if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
+	    ptr = build_fold_addr_expr (ptr);
+	  t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR,
+			       ptrdiff_type_node, t,
+			       fold_convert_loc (OMP_CLAUSE_LOCATION (c),
+						 ptrdiff_type_node, ptr));
+	  OMP_CLAUSE_SIZE (c2) = t;
+	  OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c);
+	  OMP_CLAUSE_CHAIN (c) = c2;
 	}
     }
   return false;
@@ -4972,21 +4961,24 @@  finish_omp_clauses (tree clauses)
 		   && TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE
 		   && !cxx_mark_addressable (t))
 	    remove = true;
-	  else if (!cp_omp_mappable_type ((TREE_CODE (TREE_TYPE (t))
-					   == REFERENCE_TYPE)
-					  ? TREE_TYPE (TREE_TYPE (t))
-					  : TREE_TYPE (t)))
+	  else if (!(OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+		     && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER)
+		   && !cp_omp_mappable_type ((TREE_CODE (TREE_TYPE (t))
+					      == REFERENCE_TYPE)
+					     ? TREE_TYPE (TREE_TYPE (t))
+					     : TREE_TYPE (t)))
 	    {
 	      error_at (OMP_CLAUSE_LOCATION (c),
 			"%qD does not have a mappable type in %qs clause", t,
 			omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
 	      remove = true;
 	    }
-	  else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP)
-	    break;
 	  else if (bitmap_bit_p (&generic_head, DECL_UID (t)))
 	    {
-	      error ("%qD appears more than once in motion clauses", t);
+	      if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP)
+		error ("%qD appears more than once in motion clauses", t);
+	      else
+		error ("%qD appears more than once in map clauses", t);
 	      remove = true;
 	    }
 	  else
--- gcc/langhooks.h.jj	2013-03-20 10:08:13.000000000 +0100
+++ gcc/langhooks.h	2013-09-04 19:29:20.429909391 +0200
@@ -111,6 +111,9 @@  struct lang_hooks_for_types
      firstprivate variables.  */
   void (*omp_firstprivatize_type_sizes) (struct gimplify_omp_ctx *, tree);
 
+  /* Return true if TYPE is a mappable type.  */
+  bool (*omp_mappable_type) (tree type);
+
   /* Return TRUE if TYPE1 and TYPE2 are identical for type hashing purposes.
      Called only after doing all language independent checks.
      At present, this function is only called when both TYPE1 and TYPE2 are
--- gcc/langhooks-def.h.jj	2013-03-20 10:08:41.000000000 +0100
+++ gcc/langhooks-def.h	2013-09-04 19:29:45.450781052 +0200
@@ -77,6 +77,7 @@  extern tree lhd_omp_assignment (tree, tr
 struct gimplify_omp_ctx;
 extern void lhd_omp_firstprivatize_type_sizes (struct gimplify_omp_ctx *,
 					       tree);
+extern bool lhd_omp_mappable_type (tree);
 
 #define LANG_HOOKS_NAME			"GNU unknown"
 #define LANG_HOOKS_IDENTIFIER_SIZE	sizeof (struct lang_identifier)
@@ -166,6 +167,7 @@  extern tree lhd_make_node (enum tree_cod
 #define LANG_HOOKS_TYPE_MAX_SIZE	lhd_return_null_const_tree
 #define LANG_HOOKS_OMP_FIRSTPRIVATIZE_TYPE_SIZES \
   lhd_omp_firstprivatize_type_sizes
+#define LANG_HOOKS_OMP_MAPPABLE_TYPE	lhd_omp_mappable_type
 #define LANG_HOOKS_TYPE_HASH_EQ		NULL
 #define LANG_HOOKS_GET_ARRAY_DESCR_INFO	NULL
 #define LANG_HOOKS_GET_SUBRANGE_BOUNDS	NULL
@@ -184,6 +186,7 @@  extern tree lhd_make_node (enum tree_cod
   LANG_HOOKS_INCOMPLETE_TYPE_ERROR, \
   LANG_HOOKS_TYPE_MAX_SIZE, \
   LANG_HOOKS_OMP_FIRSTPRIVATIZE_TYPE_SIZES, \
+  LANG_HOOKS_OMP_MAPPABLE_TYPE, \
   LANG_HOOKS_TYPE_HASH_EQ, \
   LANG_HOOKS_GET_ARRAY_DESCR_INFO, \
   LANG_HOOKS_GET_SUBRANGE_BOUNDS, \
--- gcc/gimple.h.jj	2013-08-27 21:55:11.000000000 +0200
+++ gcc/gimple.h	2013-09-02 11:57:32.143164024 +0200
@@ -4702,7 +4702,7 @@  static inline tree
 gimple_omp_target_clauses (const_gimple gs)
 {
   GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
-  return gs->gimple_omp_single.clauses;
+  return gs->gimple_omp_parallel.clauses;
 }
 
 
@@ -4712,7 +4712,7 @@  static inline tree *
 gimple_omp_target_clauses_ptr (gimple gs)
 {
   GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
-  return &gs->gimple_omp_single.clauses;
+  return &gs->gimple_omp_parallel.clauses;
 }
 
 
@@ -4722,7 +4722,7 @@  static inline void
 gimple_omp_target_set_clauses (gimple gs, tree clauses)
 {
   GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
-  gs->gimple_omp_single.clauses = clauses;
+  gs->gimple_omp_parallel.clauses = clauses;
 }
 
 
@@ -4747,6 +4747,67 @@  gimple_omp_target_set_kind (gimple g, in
 }
 
 
+/* Return the child function used to hold the body of OMP_TARGET GS.  */
+
+static inline tree
+gimple_omp_target_child_fn (const_gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
+  return gs->gimple_omp_parallel.child_fn;
+}
+
+/* Return a pointer to the child function used to hold the body of
+   OMP_TARGET GS.  */
+
+static inline tree *
+gimple_omp_target_child_fn_ptr (gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
+  return &gs->gimple_omp_parallel.child_fn;
+}
+
+
+/* Set CHILD_FN to be the child function for OMP_TARGET GS.  */
+
+static inline void
+gimple_omp_target_set_child_fn (gimple gs, tree child_fn)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
+  gs->gimple_omp_parallel.child_fn = child_fn;
+}
+
+
+/* Return the artificial argument used to send variables and values
+   from the parent to the children threads in OMP_TARGET GS.  */
+
+static inline tree
+gimple_omp_target_data_arg (const_gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
+  return gs->gimple_omp_parallel.data_arg;
+}
+
+
+/* Return a pointer to the data argument for OMP_TARGET GS.  */
+
+static inline tree *
+gimple_omp_target_data_arg_ptr (gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
+  return &gs->gimple_omp_parallel.data_arg;
+}
+
+
+/* Set DATA_ARG to be the data argument for OMP_TARGET GS.  */
+
+static inline void
+gimple_omp_target_set_data_arg (gimple gs, tree data_arg)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
+  gs->gimple_omp_parallel.data_arg = data_arg;
+}
+
+
 /* Return the clauses associated with OMP_TEAMS GS.  */
 
 static inline tree
--- gcc/omp-builtins.def.jj	2013-08-19 12:07:51.000000000 +0200
+++ gcc/omp-builtins.def	2013-09-04 15:14:21.049713033 +0200
@@ -225,3 +225,14 @@  DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SINGLE_C
 		  BT_FN_PTR, ATTR_NOTHROW_LEAF_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SINGLE_COPY_END, "GOMP_single_copy_end",
 		  BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TARGET, "GOMP_target",
+		  BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR,
+		  ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TARGET_DATA, "GOMP_target_data",
+		  BT_FN_VOID_INT_SIZE_PTR_PTR_PTR, ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TARGET_END_DATA, "GOMP_target_end_data",
+		  BT_FN_VOID, ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TARGET_UPDATE, "GOMP_target_update",
+		  BT_FN_VOID_INT_SIZE_PTR_PTR_PTR, ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TEAMS, "GOMP_teams",
+		  BT_FN_VOID_UINT_UINT, ATTR_NOTHROW_LIST)
--- gcc/gimple-pretty-print.c.jj	2013-08-27 21:53:53.000000000 +0200
+++ gcc/gimple-pretty-print.c	2013-08-30 17:53:14.201347484 +0200
@@ -1277,6 +1277,13 @@  dump_gimple_omp_target (pretty_printer *
       pp_string (buffer, "#pragma omp target");
       pp_string (buffer, kind);
       dump_omp_clauses (buffer, gimple_omp_target_clauses (gs), spc, flags);
+      if (gimple_omp_target_child_fn (gs))
+	{
+	  pp_string (buffer, " [child fn: ");
+	  dump_generic_node (buffer, gimple_omp_target_child_fn (gs),
+			     spc, flags, false);
+	  pp_right_bracket (buffer);
+	}
       if (!gimple_seq_empty_p (gimple_omp_body (gs)))
 	{
 	  newline_and_indent (buffer, spc + 2);
--- gcc/gimplify.c.jj	2013-08-27 22:03:35.000000000 +0200
+++ gcc/gimplify.c	2013-09-04 19:36:07.442834807 +0200
@@ -5976,7 +5976,16 @@  omp_notice_variable (struct gimplify_omp
   if (ctx->region_type == ORT_TARGET)
     {
       if (n == NULL)
-	omp_add_variable (ctx, decl, GOVD_MAP | flags);
+	{
+	  if (!lang_hooks.types.omp_mappable_type (TREE_TYPE (decl)))
+	    {
+	      error ("%qD referenced in target region does not have "
+		     "a mappable type", decl);
+	      omp_add_variable (ctx, decl, GOVD_MAP | GOVD_EXPLICIT | flags);
+	    }
+	  else
+	    omp_add_variable (ctx, decl, GOVD_MAP | flags);
+	}
       else
 	n->value |= flags;
       ret = lang_hooks.decls.omp_disregard_value_expr (decl, true);
@@ -6283,7 +6292,6 @@  gimplify_scan_omp_clauses (tree *list_p,
 	      break;
 	    }
 	  flags = GOVD_MAP | GOVD_EXPLICIT;
-	  notice_outer = false;
 	  goto do_add;
 
 	case OMP_CLAUSE_DEPEND:
@@ -6500,31 +6508,7 @@  gimplify_adjust_omp_clauses_1 (splay_tre
   if (private_debug)
     code = OMP_CLAUSE_PRIVATE;
   else if (flags & GOVD_MAP)
-    {
-      /* If decl is already in the enclosing device data environment,
-	 the spec says that it should just be used and no init/assignment
-	 should be done.  If there was any privatization in between though,
-	 it means that original decl might be in the enclosing device data
-	 environment, but the privatized might not.  */
-      struct gimplify_omp_ctx *ctx;
-      for (ctx = gimplify_omp_ctxp->outer_context;
-	   ctx; ctx = ctx->outer_context)
-	{
-	  n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl);
-	  if (n == NULL)
-	    continue;
-	  if (ctx->region_type == ORT_TARGET_DATA)
-	    {
-	      if ((n->value & GOVD_MAP) != 0)
-		return 0;
-	    }
-	  else if ((n->value & (GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE
-				| GOVD_PRIVATE | GOVD_REDUCTION
-				| GOVD_LINEAR)) != 0)
-	    break;
-	}
-      code = OMP_CLAUSE_MAP;
-    }
+    code = OMP_CLAUSE_MAP;
   else if (flags & GOVD_SHARED)
     {
       if (is_global_var (decl))
@@ -6689,31 +6673,6 @@  gimplify_adjust_omp_clauses (tree *list_
 	  n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl);
 	  if (ctx->region_type == ORT_TARGET && !(n->value & GOVD_SEEN))
 	    remove = true;
-	  else
-	    {
-	      /* If decl is already in the enclosing device data environment,
-		 the spec says that it should just be used and no init/assignment
-		 should be done.  If there was any privatization in between though,
-		 it means that original decl might be in the enclosing device data
-		 environment, but the privatized might not.  */
-	      struct gimplify_omp_ctx *octx;
-	      for (octx = ctx->outer_context; octx; octx = octx->outer_context)
-		{
-		  n = splay_tree_lookup (octx->variables,
-					 (splay_tree_key) decl);
-		  if (n == NULL)
-		    continue;
-		  if (octx->region_type == ORT_TARGET_DATA)
-		    {
-		      if ((n->value & GOVD_MAP) != 0)
-			remove = true;
-		    }
-		  else if ((n->value & (GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE
-					| GOVD_PRIVATE | GOVD_REDUCTION
-					| GOVD_LINEAR)) != 0)
-		    break;
-		}
-	    }
 	  break;
 
 	case OMP_CLAUSE_REDUCTION:
@@ -6722,6 +6681,7 @@  gimplify_adjust_omp_clauses (tree *list_
 	case OMP_CLAUSE_IF:
 	case OMP_CLAUSE_NUM_THREADS:
 	case OMP_CLAUSE_NUM_TEAMS:
+	case OMP_CLAUSE_THREAD_LIMIT:
 	case OMP_CLAUSE_DIST_SCHEDULE:
 	case OMP_CLAUSE_DEVICE:
 	case OMP_CLAUSE_SCHEDULE:
@@ -7198,7 +7158,28 @@  gimplify_omp_workshare (tree *expr_p, gi
       gcc_unreachable ();
     }
   gimplify_scan_omp_clauses (&OMP_CLAUSES (expr), pre_p, ort);
-  gimplify_and_add (OMP_BODY (expr), &body);
+  if (ort == ORT_TARGET || ort == ORT_TARGET_DATA)
+    {
+      struct gimplify_ctx gctx;
+      push_gimplify_context (&gctx);
+      gimple g = gimplify_and_return_first (OMP_BODY (expr), &body);
+      if (gimple_code (g) == GIMPLE_BIND)
+	pop_gimplify_context (g);
+      else
+	pop_gimplify_context (NULL);
+      if (ort == ORT_TARGET_DATA)
+	{
+	  gimple_seq cleanup = NULL;
+	  tree fn = builtin_decl_explicit (BUILT_IN_GOMP_TARGET_END_DATA);
+	  g = gimple_build_call (fn, 0);
+	  gimple_seq_add_stmt (&cleanup, g);
+	  g = gimple_build_try (body, cleanup, GIMPLE_TRY_FINALLY);
+	  body = NULL;
+	  gimple_seq_add_stmt (&body, g);
+	}
+    }
+  else
+    gimplify_and_add (OMP_BODY (expr), &body);
   gimplify_adjust_omp_clauses (&OMP_CLAUSES (expr));
 
   switch (TREE_CODE (expr))
--- gcc/testsuite/c-c++-common/gomp/map-1.c.jj	2013-07-06 19:18:46.161478820 +0200
+++ gcc/testsuite/c-c++-common/gomp/map-1.c	2013-09-04 17:00:51.174322082 +0200
@@ -33,7 +33,7 @@  foo (int g[3][10], int h[4][8], int i[2]
   #pragma omp target map(to: o[2:5]) /* { dg-error "does not have pointer or array type" } */
     ;
   #pragma omp target map(to: a[:][:]) /* { dg-error "array type length expression is not optional" } */
-    bar (&a[0][0]);
+    bar (&a[0][0]); /* { dg-error "referenced in target region does not have a mappable type" } */
   #pragma omp target map(tofrom: b[-1:]) /* { dg-error "negative low bound in array section" } */
     bar (b);
   #pragma omp target map(tofrom: c[:-3][:]) /* { dg-error "negative length in array section" } */
--- gcc/builtin-types.def.jj	2013-08-19 12:07:51.000000000 +0200
+++ gcc/builtin-types.def	2013-09-03 08:58:48.902658867 +0200
@@ -345,6 +345,7 @@  DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_VPTR_INT
 DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_SIZE_CONST_VPTR, BT_BOOL, BT_SIZE,
 		     BT_CONST_VOLATILE_PTR)
 DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_INT_BOOL, BT_BOOL, BT_INT, BT_BOOL)
+DEF_FUNCTION_TYPE_2 (BT_FN_VOID_UINT_UINT, BT_VOID, BT_UINT, BT_UINT)
 
 DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR)
 
@@ -472,6 +473,8 @@  DEF_FUNCTION_TYPE_5 (BT_FN_BOOL_VPTR_PTR
 DEF_FUNCTION_TYPE_5 (BT_FN_VOID_OMPFN_PTR_UINT_UINT_UINT,
 		     BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, BT_UINT,
 		     BT_UINT)
+DEF_FUNCTION_TYPE_5 (BT_FN_VOID_INT_SIZE_PTR_PTR_PTR,
+		     BT_VOID, BT_INT, BT_SIZE, BT_PTR, BT_PTR, BT_PTR)
 
 DEF_FUNCTION_TYPE_6 (BT_FN_INT_STRING_SIZE_INT_SIZE_CONST_STRING_VALIST_ARG,
 		     BT_INT, BT_STRING, BT_SIZE, BT_INT, BT_SIZE,
@@ -511,6 +514,9 @@  DEF_FUNCTION_TYPE_7 (BT_FN_BOOL_BOOL_ULL
 		     BT_BOOL, BT_BOOL, BT_ULONGLONG, BT_ULONGLONG,
 		     BT_ULONGLONG, BT_ULONGLONG,
 		     BT_PTR_ULONGLONG, BT_PTR_ULONGLONG)
+DEF_FUNCTION_TYPE_7 (BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR,
+		     BT_VOID, BT_INT, BT_PTR_FN_VOID_PTR, BT_PTR, BT_SIZE,
+		     BT_PTR, BT_PTR, BT_PTR)
 
 DEF_FUNCTION_TYPE_8 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT,
 		     BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT,
--- libgomp/libgomp.map.jj	2013-06-12 14:24:42.000000000 +0200
+++ libgomp/libgomp.map	2013-09-04 15:17:42.694659418 +0200
@@ -218,4 +218,9 @@  GOMP_4.0 {
 	GOMP_parallel;
 	GOMP_taskgroup_start;
 	GOMP_taskgroup_end;
+	GOMP_target;
+	GOMP_target_data;
+	GOMP_target_end_data;
+	GOMP_target_update;
+	GOMP_teams;
 } GOMP_3.0;
--- libgomp/Makefile.am.jj	2013-03-20 10:02:06.000000000 +0100
+++ libgomp/Makefile.am	2013-09-04 14:59:19.475033836 +0200
@@ -60,7 +60,7 @@  libgomp_la_LINK = $(LINK) $(libgomp_la_L
 libgomp_la_SOURCES = alloc.c barrier.c critical.c env.c error.c iter.c \
 	iter_ull.c loop.c loop_ull.c ordered.c parallel.c sections.c single.c \
 	task.c team.c work.c lock.c mutex.c proc.c sem.c bar.c ptrlock.c \
-	time.c fortran.c affinity.c
+	time.c fortran.c affinity.c target.c
 
 nodist_noinst_HEADERS = libgomp_f.h
 nodist_libsubinclude_HEADERS = omp.h
--- libgomp/Makefile.in.jj	2013-03-20 10:02:05.000000000 +0100
+++ libgomp/Makefile.in	2013-09-04 14:59:52.243864494 +0200
@@ -96,7 +96,7 @@  am_libgomp_la_OBJECTS = alloc.lo barrier
 	error.lo iter.lo iter_ull.lo loop.lo loop_ull.lo ordered.lo \
 	parallel.lo sections.lo single.lo task.lo team.lo work.lo \
 	lock.lo mutex.lo proc.lo sem.lo bar.lo ptrlock.lo time.lo \
-	fortran.lo affinity.lo
+	fortran.lo affinity.lo target.lo
 libgomp_la_OBJECTS = $(am_libgomp_la_OBJECTS)
 DEFAULT_INCLUDES = -I.@am__isrc@
 depcomp = $(SHELL) $(top_srcdir)/../depcomp
@@ -317,7 +317,7 @@  libgomp_la_LINK = $(LINK) $(libgomp_la_L
 libgomp_la_SOURCES = alloc.c barrier.c critical.c env.c error.c iter.c \
 	iter_ull.c loop.c loop_ull.c ordered.c parallel.c sections.c single.c \
 	task.c team.c work.c lock.c mutex.c proc.c sem.c bar.c ptrlock.c \
-	time.c fortran.c affinity.c
+	time.c fortran.c affinity.c target.c
 
 nodist_noinst_HEADERS = libgomp_f.h
 nodist_libsubinclude_HEADERS = omp.h
@@ -474,6 +474,7 @@  distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sections.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sem.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/single.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/target.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/task.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/team.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/time.Plo@am__quote@
--- libgomp/libgomp_g.h.jj	2013-04-05 18:15:57.000000000 +0200
+++ libgomp/libgomp_g.h	2013-09-04 15:25:55.982080005 +0200
@@ -199,4 +199,14 @@  extern bool GOMP_single_start (void);
 extern void *GOMP_single_copy_start (void);
 extern void GOMP_single_copy_end (void *);
 
+/* target.c */
+
+extern void GOMP_target (int, void (*) (void *), const char *,
+			 size_t, void **, size_t *, unsigned char *);
+extern void GOMP_target_data (int, size_t, void **, size_t *, unsigned char *);
+extern void GOMP_target_end_data (void);
+extern void GOMP_target_update (int, size_t, void **, size_t *,
+				unsigned char *);
+extern void GOMP_teams (unsigned int, unsigned int);
+
 #endif /* LIBGOMP_G_H */
--- libgomp/testsuite/libgomp.c++/for-11.C.jj	2013-06-21 08:38:19.000000000 +0200
+++ libgomp/testsuite/libgomp.c++/for-11.C	2013-09-04 15:28:21.542379101 +0200
@@ -75,10 +75,7 @@  int
 main ()
 {
   int err = 0;
-// FIXME: distribute construct must be closely nested
-// in teams region, but we don't handle target expansions
-// yet.  Enable when it works.
-// #pragma omp target teams reduction(|:err)
+  #pragma omp target teams reduction(|:err)
     {
       err |= test_d_normal ();
       err |= test_d_ds128_normal ();
--- libgomp/testsuite/libgomp.c++/target-1.C.jj	2013-09-04 18:55:02.294387946 +0200
+++ libgomp/testsuite/libgomp.c++/target-1.C	2013-09-04 18:54:56.430417616 +0200
@@ -0,0 +1 @@ 
+#include "../libgomp.c/target-1.c"
--- libgomp/testsuite/libgomp.c/for-3.c.jj	2013-07-06 19:44:29.000000000 +0200
+++ libgomp/testsuite/libgomp.c/for-3.c	2013-09-04 15:28:53.986223342 +0200
@@ -77,10 +77,7 @@  int
 main ()
 {
   int err = 0;
-/* FIXME: distribute construct must be closely nested
-   in teams region, but we don't handle target expansions
-   yet.  Enable when it works.  */
-/* #pragma omp target teams reduction(|:err) */
+  #pragma omp target teams reduction(|:err)
     {
       err |= test_d_normal ();
       err |= test_d_ds128_normal ();
--- libgomp/testsuite/libgomp.c/target-1.c.jj	2013-09-04 18:54:18.520609855 +0200
+++ libgomp/testsuite/libgomp.c/target-1.c	2013-09-04 18:54:10.000000000 +0200
@@ -0,0 +1,90 @@ 
+extern
+#ifdef __cplusplus
+"C"
+#endif
+void abort (void);
+
+void
+fn1 (double *x, double *y, int z)
+{
+  int i;
+  for (i = 0; i < z; i++)
+    {
+      x[i] = i & 31;
+      y[i] = (i & 63) - 30;
+    }
+}
+
+#pragma omp declare target
+int tgtv = 6;
+int
+tgt (void)
+{
+  #pragma omp atomic update
+    tgtv++;
+  return 0;
+}
+#pragma omp end declare target
+
+double
+fn2 (int x, int y, int z)
+{
+  double b[1024], c[1024], s = 0;
+  int i, j;
+  fn1 (b, c, x);
+  #pragma omp target data map(to: b)
+  {
+    #pragma omp target map(tofrom: c)
+      #pragma omp teams num_teams(y) thread_limit(z) reduction(+:s) firstprivate(x)
+	#pragma omp distribute dist_schedule(static, 4) collapse(1)
+	  for (j=0; j < x; j += y)
+	    #pragma omp parallel for reduction(+:s)
+	      for (i = j; i < j + y; i++)
+		tgt (), s += b[i] * c[i];
+    #pragma omp target update from(b, tgtv)
+  }
+  return s;
+}
+
+double
+fn3 (int x)
+{
+  double b[1024], c[1024], s = 0;
+  int i;
+  fn1 (b, c, x);
+  #pragma omp target map(to: b, c)
+    #pragma omp parallel for reduction(+:s)
+      for (i = 0; i < x; i++)
+	tgt (), s += b[i] * c[i];
+  return s;
+}
+
+double
+fn4 (int x, double *p)
+{
+  double b[1024], c[1024], d[1024], s = 0;
+  int i;
+  fn1 (b, c, x);
+  fn1 (d + x, p + x, x);
+  #pragma omp target map(to: b, c[0:x], d[x:x]) map(to:p[x:64 + (x & 31)])
+    #pragma omp parallel for reduction(+:s)
+      for (i = 0; i < x; i++)
+	s += b[i] * c[i] + d[x + i] + p[x + i];
+  return s;
+}
+
+int
+main ()
+{
+  double a = fn2 (128, 4, 6);
+  int b = tgtv;
+  double c = fn3 (61);
+  #pragma omp target update from(tgtv)
+  int d = tgtv;
+  double e[1024];
+  double f = fn4 (64, e);
+  if (a != 13888.0 || b != 6 + 128 || c != 4062.0 || d != 6 + 128 + 61
+      || f != 8032.0)
+    abort ();
+  return 0;
+}
--- libgomp/target.c.jj	2013-09-04 14:58:30.488287438 +0200
+++ libgomp/target.c	2013-09-04 15:18:31.363404929 +0200
@@ -0,0 +1,83 @@ 
+/* Copyright (C) 2013 Free Software Foundation, Inc.
+   Contributed by Jakub Jelinek <jakub@redhat.com>.
+
+   This file is part of the GNU OpenMP Library (libgomp).
+
+   Libgomp is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+   FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* This file handles the maintainence of threads in response to team
+   creation and termination.  */
+
+#include "libgomp.h"
+#include <stdlib.h>
+#include <string.h>
+
+static int
+resolve_device (int device)
+{
+  return -1;
+}
+
+/* Called when encountering a target directive.  If DEVICE
+   is -1, it means use device-var ICV.  If it is -2 (or any other value
+   larger than last available hw device, use host fallback.
+   FN is address of host code, FNNAME corresponding name to lookup
+   in the target code.  HOSTADDRS, SIZES and KINDS are arrays
+   with MAPNUM entries, with addresses of the host objects,
+   sizes of the host objects (resp. for pointer kind pointer bias
+   and assumed sizeof (void *) size) and kinds.  */
+
+void
+GOMP_target (int device, void (*fn) (void *), const char *fnname,
+	     size_t mapnum, void **hostaddrs, size_t *sizes,
+	     unsigned char *kinds)
+{
+  if (resolve_device (device) == -1)
+    {
+      fn (hostaddrs);
+      return;
+    }
+}
+
+void
+GOMP_target_data (int device, size_t mapnum, void **hostaddrs, size_t *sizes,
+		  unsigned char *kinds)
+{
+  if (resolve_device (device) == -1)
+    return;
+}
+
+void
+GOMP_target_end_data (void)
+{
+}
+
+void
+GOMP_target_update (int device, size_t mapnum, void **hostaddrs, size_t *sizes,
+		    unsigned char *kinds)
+{
+  if (resolve_device (device) == -1)
+    return;
+}
+
+void
+GOMP_teams (unsigned int num_teams, unsigned int thread_limit)
+{
+}