Patchwork [gomp4] Initial support for accelerator support parsing

login
register
mail settings
Submitter Jakub Jelinek
Date May 24, 2013, 1:07 p.m.
Message ID <20130524130756.GR1377@tucnak.redhat.com>
Download mbox | patch
Permalink /patch/246139/
State New
Headers show

Comments

Jakub Jelinek - May 24, 2013, 1:07 p.m.
Hi!

This patch contains C++ parser changes etc. to handle
#pragma omp {teams,target {,data,update},distribute} parsing
all the way through till omp lowering (it bombs badly in omp expansion,
but already omp lowering will need to be tought out).
Things not handled yet are #pragma omp declare target/#pragma omp end
declare target (I assume we can handle it by automatically adding
"omp target" attribute to vars/functions in there) and there is no support
for array sections yet (also relevant for OMP_CLAUSE_DEPEND).

Say:

void baz (float *, float *, int);

float
foo (int x)
{
  float b[1024], c[1024], s = 0;
  int i;
  baz (b, c, x);        
  #pragma omp target map(to: b, c)
    #pragma omp parallel for reduction(+:s)
      for (i = 0; i < x; i++)
        s += b[i] * c[i];
  return s;
}

float
bar (int x, int y, int z)
{
  float b[1024], c[1024], s = 0;
  int i, j;
  baz (b, c, x);
  #pragma omp target data map(to: b)
  {
    #pragma omp target map(to: c)
      #pragma omp teams num_teams(y) num_threads(z) reduction(+:s)
        #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++)
                s += b[i] * c[i];
    #pragma omp target update from(b, c)
  }
  return s;
}

now parses with g++ -S -fopenmp -fdump-tree-all and shows dump up to
*.cfg (crash during ompexp).

Comments on this before I commit it to gomp-4_0-branch?

2013-05-24  Jakub Jelinek  <jakub@redhat.com>

	* tree.def (OMP_TEAMS, OMP_TARGET_DATA, OMP_TARGET,
	OMP_TARGET_UPDATE): New tree codes.
	* tree-cfg.c (make_edges): Handle GIMPLE_OMP_TARGET
	and GIMPLE_OMP_TEAMS.
	* omp-low.c (scan_sharing_clauses): Handle OMP_CLAUSE_DIST_SCHEDULE.
	* gimple-low.c (lower_stmt): Handle GIMPLE_OMP_TARGET
	and GIMPLE_OMP_TEAMS.
	* tree.h (OMP_TEAMS_BODY, OMP_TEAMS_CLAUSES, OMP_TARGET_DATA_BODY,
	OMP_TARGET_DATA_CLAUSES, OMP_TARGET_BODY, OMP_TARGET_CLAUSES,
	OMP_TARGET_UPDATE_CLAUSES): Define.
 	* tree-nested.c (convert_nonlocal_reference_stmt,
	convert_local_reference_stmt, convert_gimple_call): Handle
	GIMPLE_OMP_TARGET and GIMPLE_OMP_TEAMS.
	* tree-inline.c (estimate_num_insns): Likewise.
	(remap_gimple_stmt): Likewise.  Adjust gimple_build_omp_for
	caller.
	* gimple.def: Adjust comments describing OMP_CLAUSEs.
	(GIMPLE_OMP_TARGET, GIMPLE_OMP_TEAMS): New GIMPLE stmts.
	* tree-parloops.c (create_parallel_loop): Adjust gimple_build_omp_for
	caller.
	* tree-pretty-print.c (dump_generic_node): Handle OMP_TEAMS,
	OMP_TARGET, OMP_TARGET_DATA and OMP_TARGET_UPDATE.
	* gimple.h (GF_OMP_TARGET_KIND_MASK, GF_OMP_TARGET_KIND_REGION,
	GF_OMP_TARGET_KIND_DATA, GF_OMP_TARGET_KIND_UPDATE): New.
	(gimple_build_omp_for): Add kind argument to prototype.
	(gimple_build_omp_target, gimple_build_omp_teams): New prototypes.
	(gimple_has_substatements): Handle GIMPLE_OMP_TARGET and
	GIMPLE_OMP_TEAMS.
	(gimple_omp_subcode): Change GIMPLE_OMP_SINGLE to GIMPLE_OMP_TEAMS.
	(gimple_omp_target_clauses, gimple_omp_target_clauses_ptr,
	gimple_omp_target_set_clauses, gimple_omp_target_kind,
	gimple_omp_target_set_kind, gimple_omp_teams_clauses,
	gimple_omp_teams_clauses_ptr, gimple_omp_teams_set_clauses): New
	inline functions.
	(gimple_return_set_retval): Handle GIMPLE_OMP_TARGET and
	GIMPLE_OMP_TEAMS.
	* gimple.c (gimple_build_omp_for): Add kind argument, call
	gimple_omp_for_set_kind.
	(gimple_build_omp_target, gimple_build_omp_teams): New functions.
	(walk_gimple_op, walk_gimple_stmt, gimple_copy): Handle
	GIMPLE_OMP_TARGET and GIMPLE_OMP_TEAMS.
	* gimple-pretty-print.c (dump_gimple_omp_target,
	dump_gimple_omp_teams): New functions.
	(pp_gimple_stmt_1): Handle GIMPLE_OMP_TARGET and GIMPLE_OMP_TEAMS.
	* gimplify.c (enum gimplify_omp_var_data): Add GOVD_MAP.
	(enum omp_region_type): Add ORT_TEAMS, ORT_TARGET and ORT_TARGET_DATA.
	(omp_add_variable): Add temporary assertions.
	(omp_notice_threadprivate_variable): Complain if threadprivate vars
	appear in target region.
	(omp_notice_variable): ORT_TARGET, ORT_TARGET_DATA and ORT_TEAMS
	handling.
	(omp_check_private): Ignore ORT_TARGET and ORT_TARGET_DATA regions.
	(gimplify_scan_omp_clauses): Handle OMP_CLAUSE_MAP, OMP_CLAUSE_TO,
	OMP_CLAUSE_FROM, OMP_CLAUSE_NUM_TEAMS, OMP_CLAUSE_DIST_SCHEDULE
	and OMP_CLAUSE_DEVICE.
	(gimplify_adjust_omp_clauses): Likewise.
	(gimplify_adjust_omp_clauses_1): Handle GOVD_MAP.  Fix up
	check for privatization by also testing for GOVD_LINEAR.
	(gimplify_omp_for): Adjust gimple_build_omp_for caller.
	Clear *expr_p.
	(gimplify_omp_workshare): Handle also OMP_TARGET, OMP_TARGET_DATA
	and OMP_TEAMS.  Clear *expr_p.
	(gimplify_omp_target_update): New function.
	(gimplify_expr): Handle OMP_TARGET, OMP_TARGET_DATA, OMP_TARGET_UPDATE
	and OMP_TEAMS.
cp/
	* parser.c (cp_parser_omp_clause_cancelkind): Remove diagnostics.
	(cp_parser_omp_all_clauses): Require that OMP_CLAUSE_{TO,FROM}
	and OMP_CLAUSE_{PARALLEL,FOR,SECTIONS,TASKGROUP} must be first in
	the list of clauses.
	(OMP_TEAMS_CLAUSE_MASK, OMP_TARGET_CLAUSE_MASK,
	OMP_TARGET_DATA_CLAUSE_MASK, OMP_TARGET_UPDATE_CLAUSE_MASK,
	OMP_DISTRIBUTE_CLAUSE_MASK): Define.
	(cp_parser_omp_teams, cp_parser_omp_target, cp_parser_omp_target_data,
	cp_parser_omp_target_update, cp_parser_omp_distribute): New functions.
	(cp_parser_omp_construct): Handle PRAGMA_OMP_DISTRIBUTE and
	PRAGMA_OMP_TEAMS.
	(cp_parser_pragma): Handle PRAGMA_OMP_DISTRIBUTE, PRAGMA_OMP_TEAMS
	and PRAGMA_OMP_TARGET.
	* pt.c (tsubst_expr): Handle OMP_TEAMS, OMP_TARGET, OMP_TARGET_DATA
	and OMP_TARGET_UPDATE.


	Jakub

Patch

--- gcc/tree.def.jj	2013-04-30 18:03:33.000000000 +0200
+++ gcc/tree.def	2013-05-22 15:22:45.143759788 +0200
@@ -1042,6 +1042,21 @@  DEFTREECODE (OMP_FOR_SIMD, "omp_for_simd
    Operands like for OMP_FOR.  */
 DEFTREECODE (OMP_DISTRIBUTE, "omp_distribute", tcc_statement, 6)
 
+/* OpenMP - #pragma omp teams [clause1 ... clauseN]
+   Operand 0: OMP_TEAMS_BODY: Teams body.
+   Operand 1: OMP_TEAMS_CLAUSES: List of clauses.  */
+DEFTREECODE (OMP_TEAMS, "omp_teams", tcc_statement, 2)
+
+/* OpenMP - #pragma omp target data [clause1 ... clauseN]
+   Operand 0: OMP_TARGET_DATA_BODY: Target data construct body.
+   Operand 1: OMP_TARGET_DATA_CLAUSES: List of clauses.  */
+DEFTREECODE (OMP_TARGET_DATA, "omp_target_data", tcc_statement, 2)
+
+/* OpenMP - #pragma omp target [clause1 ... clauseN]
+   Operand 0: OMP_TARGET_BODY: Target construct body.
+   Operand 1: OMP_TARGET_CLAUSES: List of clauses.  */
+DEFTREECODE (OMP_TARGET, "omp_target", tcc_statement, 2)
+
 /* OpenMP - #pragma omp sections [clause1 ... clauseN]
    Operand 0: OMP_SECTIONS_BODY: Sections body.
    Operand 1: OMP_SECTIONS_CLAUSES: List of clauses.  */
@@ -1069,6 +1084,10 @@  DEFTREECODE (OMP_ORDERED, "omp_ordered",
    Operand 1: OMP_CRITICAL_NAME: Identifier for critical section.  */
 DEFTREECODE (OMP_CRITICAL, "omp_critical", tcc_statement, 2)
 
+/* OpenMP - #pragma omp target update [clause1 ... clauseN]
+   Operand 0: OMP_TARGET_UPDATE_CLAUSES: List of clauses.  */
+DEFTREECODE (OMP_TARGET_UPDATE, "omp_target_update", tcc_statement, 1)
+
 /* OMP_ATOMIC through OMP_ATOMIC_CAPTURE_NEW must be consecutive,
    or OMP_ATOMIC_SEQ_CST needs adjusting.  */
 
--- gcc/tree-cfg.c.jj	2013-05-20 13:21:43.000000000 +0200
+++ gcc/tree-cfg.c	2013-05-24 13:36:50.784061934 +0200
@@ -592,6 +592,8 @@  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:
 	    case GIMPLE_OMP_CRITICAL:
--- gcc/omp-low.c.jj	2013-05-20 15:07:59.000000000 +0200
+++ gcc/omp-low.c	2013-05-24 13:47:32.465024619 +0200
@@ -1483,6 +1483,7 @@  scan_sharing_clauses (tree clauses, omp_
 	case OMP_CLAUSE_IF:
 	case OMP_CLAUSE_NUM_THREADS:
 	case OMP_CLAUSE_SCHEDULE:
+	case OMP_CLAUSE_DIST_SCHEDULE:
 	  if (ctx->outer)
 	    scan_omp_op (&OMP_CLAUSE_OPERAND (c, 0), ctx->outer);
 	  break;
@@ -1548,6 +1549,7 @@  scan_sharing_clauses (tree clauses, omp_
 	case OMP_CLAUSE_IF:
 	case OMP_CLAUSE_NUM_THREADS:
 	case OMP_CLAUSE_SCHEDULE:
+	case OMP_CLAUSE_DIST_SCHEDULE:
 	case OMP_CLAUSE_NOWAIT:
 	case OMP_CLAUSE_ORDERED:
 	case OMP_CLAUSE_COLLAPSE:
--- gcc/gimple-low.c.jj	2013-03-20 10:07:24.000000000 +0100
+++ gcc/gimple-low.c	2013-05-24 13:40:19.382080371 +0200
@@ -444,6 +444,8 @@  lower_stmt (gimple_stmt_iterator *gsi, s
 
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
+    case GIMPLE_OMP_TARGET:
+    case GIMPLE_OMP_TEAMS:
       data->cannot_fallthru = false;
       lower_omp_directive (gsi, data);
       data->cannot_fallthru = false;
--- gcc/tree.h.jj	2013-05-20 13:18:33.000000000 +0200
+++ gcc/tree.h	2013-05-22 15:07:13.696048592 +0200
@@ -1863,6 +1863,20 @@  extern void protected_set_expr_location
 #define OMP_CRITICAL_BODY(NODE)    TREE_OPERAND (OMP_CRITICAL_CHECK (NODE), 0)
 #define OMP_CRITICAL_NAME(NODE)    TREE_OPERAND (OMP_CRITICAL_CHECK (NODE), 1)
 
+#define OMP_TEAMS_BODY(NODE)	   TREE_OPERAND (OMP_TEAMS_CHECK (NODE), 0)
+#define OMP_TEAMS_CLAUSES(NODE)	   TREE_OPERAND (OMP_TEAMS_CHECK (NODE), 1)
+
+#define OMP_TARGET_DATA_BODY(NODE) \
+  TREE_OPERAND (OMP_TARGET_DATA_CHECK (NODE), 0)
+#define OMP_TARGET_DATA_CLAUSES(NODE)\
+  TREE_OPERAND (OMP_TARGET_DATA_CHECK (NODE), 1)
+
+#define OMP_TARGET_BODY(NODE)	   TREE_OPERAND (OMP_TARGET_CHECK (NODE), 0)
+#define OMP_TARGET_CLAUSES(NODE)   TREE_OPERAND (OMP_TARGET_CHECK (NODE), 1)
+
+#define OMP_TARGET_UPDATE_CLAUSES(NODE)\
+  TREE_OPERAND (OMP_TARGET_UPDATE_CHECK (NODE), 0)
+
 #define OMP_CLAUSE_CHAIN(NODE)     TREE_CHAIN (OMP_CLAUSE_CHECK (NODE))
 #define OMP_CLAUSE_DECL(NODE)      					\
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_RANGE_CHECK (OMP_CLAUSE_CHECK (NODE),	\
--- gcc/tree-nested.c.jj	2013-03-20 10:08:27.000000000 +0100
+++ gcc/tree-nested.c	2013-05-23 13:23:48.785572843 +0200
@@ -1291,6 +1291,22 @@  convert_nonlocal_reference_stmt (gimple_
       info->suppress_expansion = save_suppress;
       break;
 
+    case GIMPLE_OMP_TARGET:
+      save_suppress = info->suppress_expansion;
+      convert_nonlocal_omp_clauses (gimple_omp_target_clauses_ptr (stmt), wi);
+      walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op,
+		 info, gimple_omp_body_ptr (stmt));
+      info->suppress_expansion = save_suppress;
+      break;
+
+    case GIMPLE_OMP_TEAMS:
+      save_suppress = info->suppress_expansion;
+      convert_nonlocal_omp_clauses (gimple_omp_teams_clauses_ptr (stmt), wi);
+      walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op,
+		 info, gimple_omp_body_ptr (stmt));
+      info->suppress_expansion = save_suppress;
+      break;
+
     case GIMPLE_OMP_SECTION:
     case GIMPLE_OMP_MASTER:
     case GIMPLE_OMP_ORDERED:
@@ -1714,6 +1730,22 @@  convert_local_reference_stmt (gimple_stm
       info->suppress_expansion = save_suppress;
       break;
 
+    case GIMPLE_OMP_TARGET:
+      save_suppress = info->suppress_expansion;
+      convert_local_omp_clauses (gimple_omp_target_clauses_ptr (stmt), wi);
+      walk_body (convert_local_reference_stmt, convert_local_reference_op,
+		 info, gimple_omp_body_ptr (stmt));
+      info->suppress_expansion = save_suppress;
+      break;
+
+    case GIMPLE_OMP_TEAMS:
+      save_suppress = info->suppress_expansion;
+      convert_local_omp_clauses (gimple_omp_teams_clauses_ptr (stmt), wi);
+      walk_body (convert_local_reference_stmt, convert_local_reference_op,
+		 info, gimple_omp_body_ptr (stmt));
+      info->suppress_expansion = save_suppress;
+      break;
+
     case GIMPLE_OMP_SECTION:
     case GIMPLE_OMP_MASTER:
     case GIMPLE_OMP_ORDERED:
@@ -2071,6 +2103,8 @@  convert_gimple_call (gimple_stmt_iterato
     case GIMPLE_OMP_SECTIONS:
     case GIMPLE_OMP_SECTION:
     case GIMPLE_OMP_SINGLE:
+    case GIMPLE_OMP_TARGET:
+    case GIMPLE_OMP_TEAMS:
     case GIMPLE_OMP_MASTER:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_CRITICAL:
--- gcc/tree-inline.c.jj	2013-05-13 16:49:40.000000000 +0200
+++ gcc/tree-inline.c	2013-05-23 13:53:52.258166517 +0200
@@ -1298,7 +1298,8 @@  remap_gimple_stmt (gimple stmt, copy_bod
 	case GIMPLE_OMP_FOR:
 	  s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
 	  s2 = remap_gimple_seq (gimple_omp_for_pre_body (stmt), id);
-	  copy = gimple_build_omp_for (s1, gimple_omp_for_clauses (stmt),
+	  copy = gimple_build_omp_for (s1, gimple_omp_for_kind (stmt),
+				       gimple_omp_for_clauses (stmt),
 				       gimple_omp_for_collapse (stmt), s2);
 	  {
 	    size_t i;
@@ -1345,6 +1346,19 @@  remap_gimple_stmt (gimple stmt, copy_bod
 	           (s1, gimple_omp_single_clauses (stmt));
 	  break;
 
+	case GIMPLE_OMP_TARGET:
+	  s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
+	  copy = gimple_build_omp_target
+		   (s1, gimple_omp_target_kind (stmt),
+		    gimple_omp_target_clauses (stmt));
+	  break;
+
+	case GIMPLE_OMP_TEAMS:
+	  s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
+	  copy = gimple_build_omp_teams
+		   (s1, gimple_omp_teams_clauses (stmt));
+	  break;
+
 	case GIMPLE_OMP_CRITICAL:
 	  s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
 	  copy
@@ -3716,6 +3730,8 @@  estimate_num_insns (gimple stmt, eni_wei
     case GIMPLE_OMP_SECTION:
     case GIMPLE_OMP_SECTIONS:
     case GIMPLE_OMP_SINGLE:
+    case GIMPLE_OMP_TARGET:
+    case GIMPLE_OMP_TEAMS:
       return (weights->omp_cost
               + estimate_num_insns_seq (gimple_omp_body (stmt), weights));
 
--- gcc/gimple.def.jj	2013-03-20 10:05:01.000000000 +0100
+++ gcc/gimple.def	2013-05-23 12:45:29.902586194 +0200
@@ -287,7 +287,7 @@  DEFGSCODE(GIMPLE_OMP_ORDERED, "gimple_om
 
    BODY is a the sequence of statements to be executed by all threads.
 
-   CLAUSES is a TREE_LIST node with all the clauses.
+   CLAUSES is an OMP_CLAUSE chain with all the clauses.
 
    CHILD_FN is set when outlining the body of the parallel region.
    All the statements in BODY are moved into this newly created
@@ -306,7 +306,7 @@  DEFGSCODE(GIMPLE_OMP_PARALLEL, "gimple_o
 
    BODY is a the sequence of statements to be executed by all threads.
 
-   CLAUSES is a TREE_LIST node with all the clauses.
+   CLAUSES is an OMP_CLAUSE chain with all the clauses.
 
    CHILD_FN is set when outlining the body of the explicit task region.
    All the statements in BODY are moved into this newly created
@@ -334,7 +334,7 @@  DEFGSCODE(GIMPLE_OMP_SECTION, "gimple_om
 /* OMP_SECTIONS <BODY, CLAUSES, CONTROL> represents #pragma omp sections.
 
    BODY is the sequence of statements in the sections body.
-   CLAUSES is a TREE_LIST node holding the list of associated clauses.
+   CLAUSES is an OMP_CLAUSE chain holding the list of associated clauses.
    CONTROL is a VAR_DECL used for deciding which of the sections
    to execute.  */
 DEFGSCODE(GIMPLE_OMP_SECTIONS, "gimple_omp_sections", GSS_OMP_SECTIONS)
@@ -346,9 +346,21 @@  DEFGSCODE(GIMPLE_OMP_SECTIONS_SWITCH, "g
 
 /* GIMPLE_OMP_SINGLE <BODY, CLAUSES> represents #pragma omp single
    BODY is the sequence of statements inside the single section.
-   CLAUSES is a TREE_LIST node holding the associated clauses.  */
+   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
+   #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)
+
+/* GIMPLE_OMP_TEAMS <BODY, CLAUSES> represents #pragma omp teams
+   BODY is the sequence of statements inside the single section.
+   CLAUSES is an OMP_CLAUSE chain holding the associated clauses.  */
+DEFGSCODE(GIMPLE_OMP_TEAMS, "gimple_omp_teams", GSS_OMP_SINGLE)
+
 /* GIMPLE_PREDICT <PREDICT, OUTCOME> specifies a hint for branch prediction.
 
    PREDICT is one of the predictors from predict.def.
--- gcc/cp/parser.c.jj	2013-05-20 13:21:27.000000000 +0200
+++ gcc/cp/parser.c	2013-05-22 19:12:25.523182096 +0200
@@ -26823,22 +26823,7 @@  cp_parser_omp_clause_cancelkind (cp_pars
 				 enum omp_clause_code code,
 				 tree list, location_t location)
 {
-  tree c;
-
-  for (c = list; c; c = OMP_CLAUSE_CHAIN (c))
-    switch (OMP_CLAUSE_CODE (c))
-      {
-      case OMP_CLAUSE_PARALLEL:
-      case OMP_CLAUSE_FOR:
-      case OMP_CLAUSE_SECTIONS:
-      case OMP_CLAUSE_TASKGROUP:
-	error_at (location, "only one of %<parallel%>, %<for%>, %<sections%> "
-			    "and %<taskgroup%> clauses can be specified");
-	break;
-      default:
-	break;
-      }
-  c = build_omp_clause (location, code);
+  tree c = build_omp_clause (location, code);
   OMP_CLAUSE_CHAIN (c) = list;
   return c;
 }
@@ -27260,7 +27245,6 @@  cp_parser_omp_all_clauses (cp_parser *pa
 
       token = cp_lexer_peek_token (parser->lexer);
       c_kind = cp_parser_omp_clause_name (parser);
-      first = false;
 
       switch (c_kind)
 	{
@@ -27359,31 +27343,48 @@  cp_parser_omp_all_clauses (cp_parser *pa
 	  clauses = cp_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_PARALLEL,
 						     clauses, token->location);
 	  c_name = "parallel";
+	  if (!first)
+	    {
+	     clause_not_first:
+	      error_at (token->location, "%qs must be the first clause of %qs",
+			c_name, where);
+	      clauses = prev;
+	    }
 	  break;
 	case PRAGMA_OMP_CLAUSE_FOR:
 	  clauses = cp_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_FOR,
 						     clauses, token->location);
 	  c_name = "for";
+	  if (!first)
+	    goto clause_not_first;
 	  break;
 	case PRAGMA_OMP_CLAUSE_SECTIONS:
 	  clauses = cp_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_SECTIONS,
 						     clauses, token->location);
 	  c_name = "sections";
+	  if (!first)
+	    goto clause_not_first;
 	  break;
 	case PRAGMA_OMP_CLAUSE_TASKGROUP:
 	  clauses = cp_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_TASKGROUP,
 						     clauses, token->location);
 	  c_name = "taskgroup";
+	  if (!first)
+	    goto clause_not_first;
 	  break;
 	case PRAGMA_OMP_CLAUSE_TO:
 	  clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_TO,
 					    clauses);
 	  c_name = "to";
+	  if (!first)
+	    goto clause_not_first;
 	  break;
 	case PRAGMA_OMP_CLAUSE_FROM:
 	  clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FROM,
 					    clauses);
 	  c_name = "from";
+	  if (!first)
+	    goto clause_not_first;
 	  break;
 	case PRAGMA_OMP_CLAUSE_UNIFORM:
 	  clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_UNIFORM,
@@ -27441,6 +27442,8 @@  cp_parser_omp_all_clauses (cp_parser *pa
 	  goto saw_error;
 	}
 
+      first = false;
+
       if (((mask >> c_kind) & 1) == 0)
 	{
 	  /* Remove the invalid clause(s) from the list to avoid
@@ -29013,6 +29016,180 @@  cp_parser_omp_cancellation_point (cp_par
 }
 
 /* OpenMP 4.0:
+   # pragma omp teams teams-clause[optseq] new-line
+     structured-block  */
+
+#define OMP_TEAMS_CLAUSE_MASK					\
+	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT))
+
+static tree
+cp_parser_omp_teams (cp_parser *parser, cp_token *pragma_tok)
+{
+  tree stmt = make_node (OMP_TEAMS);
+  TREE_TYPE (stmt) = void_type_node;
+
+  OMP_TEAMS_CLAUSES (stmt)
+    = cp_parser_omp_all_clauses (parser, OMP_TEAMS_CLAUSE_MASK,
+				 "#pragma omp teams", pragma_tok);
+  OMP_TEAMS_BODY (stmt) = cp_parser_omp_structured_block (parser);
+
+  return add_stmt (stmt);
+}
+
+/* OpenMP 4.0:
+   # pragma omp target data target-data-clause[optseq] new-line
+     structured-block  */
+
+#define OMP_TARGET_DATA_CLAUSE_MASK				\
+	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)		\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF))
+
+static tree
+cp_parser_omp_target_data (cp_parser *parser, cp_token *pragma_tok)
+{
+  tree stmt = make_node (OMP_TARGET_DATA);
+  TREE_TYPE (stmt) = void_type_node;
+
+  OMP_TARGET_DATA_CLAUSES (stmt)
+    = cp_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK,
+				 "#pragma omp target data", pragma_tok);
+  OMP_TARGET_DATA_BODY (stmt) = cp_parser_omp_structured_block (parser);
+
+  SET_EXPR_LOCATION (stmt, pragma_tok->location);
+  return add_stmt (stmt);
+}
+
+/* OpenMP 4.0:
+   # pragma omp target update target-update-clause[optseq] new-line */
+
+#define OMP_TARGET_UPDATE_CLAUSE_MASK				\
+	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FROM)		\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TO)		\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF))
+
+static bool
+cp_parser_omp_target_update (cp_parser *parser, cp_token *pragma_tok,
+			     enum pragma_context context)
+{
+  if (context == pragma_stmt)
+    {
+      error_at (pragma_tok->location,
+		"%<#pragma omp target update%> may only be "
+		"used in compound statements");
+      cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+      return false;
+    }
+
+  tree clauses
+    = cp_parser_omp_all_clauses (parser, OMP_TARGET_UPDATE_CLAUSE_MASK,
+				 "#pragma omp target update", pragma_tok);
+  if (find_omp_clause (clauses, OMP_CLAUSE_TO) == NULL_TREE
+      && find_omp_clause (clauses, OMP_CLAUSE_FROM) == NULL_TREE)
+    {
+      error_at (pragma_tok->location,
+		"%<#pragma omp target update must contain either "
+		"%<from%> or %<to%> clauses");
+      return false;
+    }
+
+  tree stmt = make_node (OMP_TARGET_UPDATE);
+  TREE_TYPE (stmt) = void_type_node;
+  OMP_TARGET_UPDATE_CLAUSES (stmt) = clauses;
+  SET_EXPR_LOCATION (stmt, pragma_tok->location);
+  add_stmt (stmt);
+  return false;
+}
+
+/* OpenMP 4.0:
+   # pragma omp target target-clause[optseq] new-line
+     structured-block  */
+
+#define OMP_TARGET_CLAUSE_MASK					\
+	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)		\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF))
+
+static bool
+cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok,
+		      enum pragma_context context)
+{
+  if (context != pragma_stmt && context != pragma_compound)
+    {
+      cp_parser_error (parser, "expected declaration specifiers");
+      cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+      return false;
+    }
+
+  if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+    {
+      tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+      const char *p = IDENTIFIER_POINTER (id);
+
+      if (strcmp (p, "data") == 0)
+	{
+	  cp_lexer_consume_token (parser->lexer);
+	  cp_parser_omp_target_data (parser, pragma_tok);
+	  return true;
+	}
+      else if (strcmp (p, "update") == 0)
+	{
+	  cp_lexer_consume_token (parser->lexer);
+	  return cp_parser_omp_target_update (parser, pragma_tok, context);
+	}
+    }
+
+  tree stmt = make_node (OMP_TARGET);
+  TREE_TYPE (stmt) = void_type_node;
+
+  OMP_TARGET_CLAUSES (stmt)
+    = cp_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK,
+				 "#pragma omp target", pragma_tok);
+  OMP_TARGET_BODY (stmt) = cp_parser_omp_structured_block (parser);
+
+  SET_EXPR_LOCATION (stmt, pragma_tok->location);
+  add_stmt (stmt);
+  return true;
+}
+
+/* OpenMP 4.0:
+   #pragma omp distribute distribute-clause[optseq] new-line
+     for-loop  */
+
+#define OMP_DISTRIBUTE_CLAUSE_MASK				\
+	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE))
+
+static tree
+cp_parser_omp_distribute (cp_parser *parser, cp_token *pragma_tok)
+{
+  tree clauses, sb, ret;
+  unsigned int save;
+
+  clauses = cp_parser_omp_all_clauses (parser, OMP_DISTRIBUTE_CLAUSE_MASK,
+				       "#pragma omp distribute", pragma_tok);
+
+  sb = begin_omp_structured_block ();
+  save = cp_parser_begin_omp_structured_block (parser);
+
+  ret = cp_parser_omp_for_loop (parser, OMP_DISTRIBUTE, clauses, NULL);
+
+  cp_parser_end_omp_structured_block (parser, save);
+  add_stmt (finish_omp_structured_block (sb));
+
+  return ret;
+}
+
+/* OpenMP 4.0:
    # pragma omp declare simd declare-simd-clauses[optseq] new-line  */
 
 #define OMP_DECLARE_SIMD_CLAUSE_MASK				\
@@ -29112,6 +29289,9 @@  cp_parser_omp_construct (cp_parser *pars
     case PRAGMA_OMP_CRITICAL:
       stmt = cp_parser_omp_critical (parser, pragma_tok);
       break;
+    case PRAGMA_OMP_DISTRIBUTE:
+      stmt = cp_parser_omp_distribute (parser, pragma_tok);
+      break;
     case PRAGMA_OMP_FOR:
       stmt = cp_parser_omp_for (parser, pragma_tok);
       break;
@@ -29139,6 +29319,9 @@  cp_parser_omp_construct (cp_parser *pars
     case PRAGMA_OMP_TASKGROUP:
       cp_parser_omp_taskgroup (parser, pragma_tok);
       return;
+    case PRAGMA_OMP_TEAMS:
+      stmt = cp_parser_omp_teams (parser, pragma_tok);
+      break;
     default:
       gcc_unreachable ();
     }
@@ -29609,6 +29792,7 @@  cp_parser_pragma (cp_parser *parser, enu
 
     case PRAGMA_OMP_ATOMIC:
     case PRAGMA_OMP_CRITICAL:
+    case PRAGMA_OMP_DISTRIBUTE:
     case PRAGMA_OMP_FOR:
     case PRAGMA_OMP_MASTER:
     case PRAGMA_OMP_ORDERED:
@@ -29618,11 +29802,15 @@  cp_parser_pragma (cp_parser *parser, enu
     case PRAGMA_OMP_SINGLE:
     case PRAGMA_OMP_TASK:
     case PRAGMA_OMP_TASKGROUP:
+    case PRAGMA_OMP_TEAMS:
       if (context != pragma_stmt && context != pragma_compound)
 	goto bad_stmt;
       cp_parser_omp_construct (parser, pragma_tok);
       return true;
 
+    case PRAGMA_OMP_TARGET:
+      return cp_parser_omp_target (parser, pragma_tok, context);
+
     case PRAGMA_OMP_SECTION:
       error_at (pragma_tok->location, 
 		"%<#pragma omp section%> may only be used in "
--- gcc/cp/pt.c.jj	2013-05-20 13:21:25.000000000 +0200
+++ gcc/cp/pt.c	2013-05-22 18:44:31.959390265 +0200
@@ -13330,6 +13330,9 @@  tsubst_expr (tree t, tree args, tsubst_f
 
     case OMP_SECTIONS:
     case OMP_SINGLE:
+    case OMP_TEAMS:
+    case OMP_TARGET_DATA:
+    case OMP_TARGET:
       tmp = tsubst_omp_clauses (OMP_CLAUSES (t), false,
 				args, complain, in_decl);
       stmt = push_stmt_list ();
@@ -13341,6 +13344,14 @@  tsubst_expr (tree t, tree args, tsubst_f
       OMP_CLAUSES (t) = tmp;
       add_stmt (t);
       break;
+
+    case OMP_TARGET_UPDATE:
+      tmp = tsubst_omp_clauses (OMP_TARGET_UPDATE_CLAUSES (t), false,
+				args, complain, in_decl);
+      t = copy_node (t);
+      OMP_CLAUSES (t) = tmp;
+      add_stmt (t);
+      break;
 
     case OMP_SECTION:
     case OMP_CRITICAL:
--- gcc/tree-parloops.c.jj	2013-05-13 16:46:37.000000000 +0200
+++ gcc/tree-parloops.c	2013-05-23 13:54:21.854439781 +0200
@@ -1686,7 +1686,7 @@  create_parallel_loop (struct loop *loop,
   t = build_omp_clause (loc, OMP_CLAUSE_SCHEDULE);
   OMP_CLAUSE_SCHEDULE_KIND (t) = OMP_CLAUSE_SCHEDULE_STATIC;
 
-  for_stmt = gimple_build_omp_for (NULL, t, 1, NULL);
+  for_stmt = gimple_build_omp_for (NULL, GF_OMP_FOR_KIND_FOR, t, 1, NULL);
   gimple_set_location (for_stmt, loc);
   gimple_omp_for_set_index (for_stmt, 0, initvar);
   gimple_omp_for_set_initial (for_stmt, 0, cvar_init);
--- gcc/tree-pretty-print.c.jj	2013-05-20 13:18:24.000000000 +0200
+++ gcc/tree-pretty-print.c	2013-05-22 19:00:26.349842964 +0200
@@ -2347,6 +2347,27 @@  dump_generic_node (pretty_printer *buffe
       pp_string (buffer, "#pragma omp distribute");
       goto dump_omp_loop;
 
+    case OMP_TEAMS:
+      pp_string (buffer, "#pragma omp teams");
+      dump_omp_clauses (buffer, OMP_TEAMS_CLAUSES (node), spc, flags);
+      goto dump_omp_body;
+
+    case OMP_TARGET_DATA:
+      pp_string (buffer, "#pragma omp target data");
+      dump_omp_clauses (buffer, OMP_TARGET_DATA_CLAUSES (node), spc, flags);
+      goto dump_omp_body;
+
+    case OMP_TARGET:
+      pp_string (buffer, "#pragma omp target");
+      dump_omp_clauses (buffer, OMP_TARGET_CLAUSES (node), spc, flags);
+      goto dump_omp_body;
+
+    case OMP_TARGET_UPDATE:
+      pp_string (buffer, "#pragma omp target update");
+      dump_omp_clauses (buffer, OMP_TARGET_UPDATE_CLAUSES (node), spc, flags);
+      is_expr = false;
+      break;
+
     dump_omp_loop:
       dump_omp_clauses (buffer, OMP_FOR_CLAUSES (node), spc, flags);
 
--- gcc/gimple.h.jj	2013-05-13 16:49:47.000000000 +0200
+++ gcc/gimple.h	2013-05-23 14:06:41.729631141 +0200
@@ -115,6 +115,10 @@  enum gf_mask {
     GF_OMP_FOR_KIND_SIMD	= 1 << 0,
     GF_OMP_FOR_KIND_FOR_SIMD	= 2 << 0,
     GF_OMP_FOR_KIND_DISTRIBUTE	= 3 << 0,
+    GF_OMP_TARGET_KIND_MASK	= 3 << 0,
+    GF_OMP_TARGET_KIND_REGION	= 0 << 0,
+    GF_OMP_TARGET_KIND_DATA	= 1 << 0,
+    GF_OMP_TARGET_KIND_UPDATE	= 2 << 0,
 
     /* True on an GIMPLE_OMP_RETURN statement if the return does not require
        a thread synchronization via some sort of barrier.  The exact barrier
@@ -618,7 +622,7 @@  struct GTY(()) gimple_statement_omp_cont
   tree control_use;
 };
 
-/* GIMPLE_OMP_SINGLE */
+/* GIMPLE_OMP_SINGLE, GIMPLE_OMP_TARGET, GIMPLE_OMP_TEAMS */
 
 struct GTY(()) gimple_statement_omp_single {
   /* [ WORD 1-7 ]  */
@@ -805,7 +809,7 @@  gimple gimple_build_switch_nlabels (unsi
 gimple gimple_build_switch (tree, tree, vec<tree> );
 gimple gimple_build_omp_parallel (gimple_seq, tree, tree, tree);
 gimple gimple_build_omp_task (gimple_seq, tree, tree, tree, tree, tree, tree);
-gimple gimple_build_omp_for (gimple_seq, tree, size_t, gimple_seq);
+gimple gimple_build_omp_for (gimple_seq, int, tree, size_t, gimple_seq);
 gimple gimple_build_omp_critical (gimple_seq, tree);
 gimple gimple_build_omp_section (gimple_seq);
 gimple gimple_build_omp_continue (tree, tree);
@@ -815,6 +819,8 @@  gimple gimple_build_omp_ordered (gimple_
 gimple gimple_build_omp_sections (gimple_seq, tree);
 gimple gimple_build_omp_sections_switch (void);
 gimple gimple_build_omp_single (gimple_seq, tree);
+gimple gimple_build_omp_target (gimple_seq, int, tree);
+gimple gimple_build_omp_teams (gimple_seq, tree);
 gimple gimple_build_cdt (tree, tree);
 gimple gimple_build_omp_atomic_load (tree, tree);
 gimple gimple_build_omp_atomic_store (tree);
@@ -1264,6 +1270,8 @@  gimple_has_substatements (gimple g)
     case GIMPLE_OMP_TASK:
     case GIMPLE_OMP_SECTIONS:
     case GIMPLE_OMP_SINGLE:
+    case GIMPLE_OMP_TARGET:
+    case GIMPLE_OMP_TEAMS:
     case GIMPLE_OMP_CRITICAL:
     case GIMPLE_WITH_CLEANUP_EXPR:
     case GIMPLE_TRANSACTION:
@@ -1691,7 +1699,7 @@  static inline unsigned
 gimple_omp_subcode (const_gimple s)
 {
   gcc_gimple_checking_assert (gimple_code (s) >= GIMPLE_OMP_ATOMIC_LOAD
-	      && gimple_code (s) <= GIMPLE_OMP_SINGLE);
+	      && gimple_code (s) <= GIMPLE_OMP_TEAMS);
   return s->gsbase.subcode;
 }
 
@@ -4604,6 +4612,87 @@  gimple_omp_single_set_clauses (gimple gs
 }
 
 
+/* Return the clauses associated with OMP_TARGET GS.  */
+
+static inline tree
+gimple_omp_target_clauses (const_gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
+  return gs->gimple_omp_single.clauses;
+}
+
+
+/* Return a pointer to the clauses associated with OMP_TARGET GS.  */
+
+static inline tree *
+gimple_omp_target_clauses_ptr (gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
+  return &gs->gimple_omp_single.clauses;
+}
+
+
+/* Set CLAUSES to be the clauses associated with OMP_TARGET GS.  */
+
+static inline void
+gimple_omp_target_set_clauses (gimple gs, tree clauses)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
+  gs->gimple_omp_single.clauses = clauses;
+}
+
+
+/* Return the kind of OMP target statemement.  */
+
+static inline int
+gimple_omp_target_kind (const_gimple g)
+{
+  GIMPLE_CHECK (g, GIMPLE_OMP_TARGET);
+  return (gimple_omp_subcode (g) & GF_OMP_TARGET_KIND_MASK);
+}
+
+
+/* Set the OMP target kind.  */
+
+static inline void
+gimple_omp_target_set_kind (gimple g, int kind)
+{
+  GIMPLE_CHECK (g, GIMPLE_OMP_TARGET);
+  g->gsbase.subcode = (g->gsbase.subcode & ~GF_OMP_TARGET_KIND_MASK)
+		      | (kind & GF_OMP_TARGET_KIND_MASK);
+}
+
+
+/* Return the clauses associated with OMP_TEAMS GS.  */
+
+static inline tree
+gimple_omp_teams_clauses (const_gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_TEAMS);
+  return gs->gimple_omp_single.clauses;
+}
+
+
+/* Return a pointer to the clauses associated with OMP_TEAMS GS.  */
+
+static inline tree *
+gimple_omp_teams_clauses_ptr (gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_TEAMS);
+  return &gs->gimple_omp_single.clauses;
+}
+
+
+/* Set CLAUSES to be the clauses associated with OMP_TEAMS GS.  */
+
+static inline void
+gimple_omp_teams_set_clauses (gimple gs, tree clauses)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_TEAMS);
+  gs->gimple_omp_single.clauses = clauses;
+}
+
+
 /* Return the clauses associated with OMP_SECTIONS GS.  */
 
 static inline tree
@@ -4946,6 +5035,8 @@  gimple_return_set_retval (gimple gs, tre
     case GIMPLE_OMP_SECTIONS:			\
     case GIMPLE_OMP_SECTIONS_SWITCH:		\
     case GIMPLE_OMP_SINGLE:			\
+    case GIMPLE_OMP_TARGET:			\
+    case GIMPLE_OMP_TEAMS:			\
     case GIMPLE_OMP_SECTION:			\
     case GIMPLE_OMP_MASTER:			\
     case GIMPLE_OMP_ORDERED:			\
--- gcc/gimple.c.jj	2013-05-13 16:49:46.000000000 +0200
+++ gcc/gimple.c	2013-05-23 13:40:12.487789257 +0200
@@ -908,13 +908,14 @@  gimple_build_omp_critical (gimple_seq bo
    PRE_BODY is the sequence of statements that are loop invariant.  */
 
 gimple
-gimple_build_omp_for (gimple_seq body, tree clauses, size_t collapse,
+gimple_build_omp_for (gimple_seq body, int kind, tree clauses, size_t collapse,
 		      gimple_seq pre_body)
 {
   gimple p = gimple_alloc (GIMPLE_OMP_FOR, 0);
   if (body)
     gimple_omp_set_body (p, body);
   gimple_omp_for_set_clauses (p, clauses);
+  gimple_omp_for_set_kind (p, kind);
   p->gimple_omp_for.collapse = collapse;
   p->gimple_omp_for.iter
       = ggc_alloc_cleared_vec_gimple_omp_for_iter (collapse);
@@ -1094,6 +1095,41 @@  gimple_build_omp_single (gimple_seq body
 }
 
 
+/* Build a GIMPLE_OMP_TARGET statement.
+
+   BODY is the sequence of statements that will be executed.
+   CLAUSES are any of the OMP target construct's clauses.  */
+
+gimple
+gimple_build_omp_target (gimple_seq body, int kind, tree clauses)
+{
+  gimple p = gimple_alloc (GIMPLE_OMP_TARGET, 0);
+  if (body)
+    gimple_omp_set_body (p, body);
+  gimple_omp_target_set_clauses (p, clauses);
+  gimple_omp_target_set_kind (p, kind);
+
+  return p;
+}
+
+
+/* Build a GIMPLE_OMP_TEAMS statement.
+
+   BODY is the sequence of statements that will be executed.
+   CLAUSES are any of the OMP teams construct's clauses.  */
+
+gimple
+gimple_build_omp_teams (gimple_seq body, tree clauses)
+{
+  gimple p = gimple_alloc (GIMPLE_OMP_TEAMS, 0);
+  if (body)
+    gimple_omp_set_body (p, body);
+  gimple_omp_teams_set_clauses (p, clauses);
+
+  return p;
+}
+
+
 /* Build a GIMPLE_OMP_ATOMIC_LOAD statement.  */
 
 gimple
@@ -1610,6 +1646,20 @@  walk_gimple_op (gimple stmt, walk_tree_f
 	return ret;
       break;
 
+    case GIMPLE_OMP_TARGET:
+      ret = walk_tree (gimple_omp_target_clauses_ptr (stmt), callback_op, wi,
+		       pset);
+      if (ret)
+	return ret;
+      break;
+
+    case GIMPLE_OMP_TEAMS:
+      ret = walk_tree (gimple_omp_teams_clauses_ptr (stmt), callback_op, wi,
+		       pset);
+      if (ret)
+	return ret;
+      break;
+
     case GIMPLE_OMP_ATOMIC_LOAD:
       ret = walk_tree (gimple_omp_atomic_load_lhs_ptr (stmt), callback_op, wi,
 		       pset);
@@ -1786,6 +1836,8 @@  walk_gimple_stmt (gimple_stmt_iterator *
     case GIMPLE_OMP_TASK:
     case GIMPLE_OMP_SECTIONS:
     case GIMPLE_OMP_SINGLE:
+    case GIMPLE_OMP_TARGET:
+    case GIMPLE_OMP_TEAMS:
       ret = walk_gimple_seq_mod (gimple_omp_body_ptr (stmt), callback_stmt,
 			     callback_op, wi);
       if (ret)
@@ -2308,6 +2360,8 @@  gimple_copy (gimple stmt)
 	  /* FALLTHRU  */
 
 	case GIMPLE_OMP_SINGLE:
+	case GIMPLE_OMP_TARGET:
+	case GIMPLE_OMP_TEAMS:
 	case GIMPLE_OMP_SECTION:
 	case GIMPLE_OMP_MASTER:
 	case GIMPLE_OMP_ORDERED:
--- gcc/gimple-pretty-print.c.jj	2013-05-13 16:49:01.000000000 +0200
+++ gcc/gimple-pretty-print.c	2013-05-23 13:17:37.589649980 +0200
@@ -1264,6 +1264,78 @@  dump_gimple_omp_single (pretty_printer *
     }
 }
 
+/* Dump a GIMPLE_OMP_TARGET tuple on the pretty_printer BUFFER.  */
+
+static void
+dump_gimple_omp_target (pretty_printer *buffer, gimple gs, int spc, int flags)
+{
+  const char *kind;
+  switch (gimple_omp_target_kind (gs))
+    {
+    case GF_OMP_TARGET_KIND_REGION:
+      kind = "";
+      break;
+    case GF_OMP_TARGET_KIND_DATA:
+      kind = " data";
+      break;
+    case GF_OMP_TARGET_KIND_UPDATE:
+      kind = " update";
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  if (flags & TDF_RAW)
+    {
+      dump_gimple_fmt (buffer, spc, flags, "%G%s <%+BODY <%S>%nCLAUSES <", gs,
+		       kind, gimple_omp_body (gs));
+      dump_omp_clauses (buffer, gimple_omp_target_clauses (gs), spc, flags);
+      dump_gimple_fmt (buffer, spc, flags, " >");
+    }
+  else
+    {
+      pp_string (buffer, "#pragma omp target");
+      pp_string (buffer, kind);
+      dump_omp_clauses (buffer, gimple_omp_target_clauses (gs), spc, flags);
+      if (!gimple_seq_empty_p (gimple_omp_body (gs)))
+	{
+	  newline_and_indent (buffer, spc + 2);
+	  pp_character (buffer, '{');
+	  pp_newline (buffer);
+	  dump_gimple_seq (buffer, gimple_omp_body (gs), spc + 4, flags);
+	  newline_and_indent (buffer, spc + 2);
+	  pp_character (buffer, '}');
+	}
+    }
+}
+
+/* Dump a GIMPLE_OMP_TEAMS tuple on the pretty_printer BUFFER.  */
+
+static void
+dump_gimple_omp_teams (pretty_printer *buffer, gimple gs, int spc, int flags)
+{
+  if (flags & TDF_RAW)
+    {
+      dump_gimple_fmt (buffer, spc, flags, "%G <%+BODY <%S>%nCLAUSES <", gs,
+		       gimple_omp_body (gs));
+      dump_omp_clauses (buffer, gimple_omp_teams_clauses (gs), spc, flags);
+      dump_gimple_fmt (buffer, spc, flags, " >");
+    }
+  else
+    {
+      pp_string (buffer, "#pragma omp teams");
+      dump_omp_clauses (buffer, gimple_omp_teams_clauses (gs), spc, flags);
+      if (!gimple_seq_empty_p (gimple_omp_body (gs)))
+	{
+	  newline_and_indent (buffer, spc + 2);
+	  pp_character (buffer, '{');
+	  pp_newline (buffer);
+	  dump_gimple_seq (buffer, gimple_omp_body (gs), spc + 4, flags);
+	  newline_and_indent (buffer, spc + 2);
+	  pp_character (buffer, '}');
+	}
+    }
+}
+
 /* Dump a GIMPLE_OMP_SECTIONS tuple on the pretty_printer BUFFER.  */
 
 static void
@@ -2038,6 +2110,14 @@  pp_gimple_stmt_1 (pretty_printer *buffer
       dump_gimple_omp_single (buffer, gs, spc, flags);
       break;
 
+    case GIMPLE_OMP_TARGET:
+      dump_gimple_omp_target (buffer, gs, spc, flags);
+      break;
+
+    case GIMPLE_OMP_TEAMS:
+      dump_gimple_omp_teams (buffer, gs, spc, flags);
+      break;
+
     case GIMPLE_OMP_RETURN:
       dump_gimple_omp_return (buffer, gs, spc, flags);
       break;
--- gcc/gimplify.c.jj	2013-05-13 16:49:10.000000000 +0200
+++ gcc/gimplify.c	2013-05-24 14:04:01.534225316 +0200
@@ -57,10 +57,11 @@  enum gimplify_omp_var_data
   GOVD_LASTPRIVATE = 32,
   GOVD_REDUCTION = 64,
   GOVD_LOCAL = 128,
-  GOVD_DEBUG_PRIVATE = 256,
-  GOVD_PRIVATE_OUTER_REF = 512,
-  GOVD_LINEAR = 1024,
-  GOVD_ALIGNED = 2048,
+  GOVD_MAP = 256,
+  GOVD_DEBUG_PRIVATE = 512,
+  GOVD_PRIVATE_OUTER_REF = 1024,
+  GOVD_LINEAR = 2048,
+  GOVD_ALIGNED = 4096,
   GOVD_DATA_SHARE_CLASS = (GOVD_SHARED | GOVD_PRIVATE | GOVD_FIRSTPRIVATE
 			   | GOVD_LASTPRIVATE | GOVD_REDUCTION | GOVD_LINEAR
 			   | GOVD_LOCAL)
@@ -74,7 +75,10 @@  enum omp_region_type
   ORT_PARALLEL = 2,
   ORT_COMBINED_PARALLEL = 3,
   ORT_TASK = 4,
-  ORT_UNTIED_TASK = 5
+  ORT_UNTIED_TASK = 5,
+  ORT_TEAMS = 8,
+  ORT_TARGET_DATA = 16,
+  ORT_TARGET = 32
 };
 
 struct gimplify_omp_ctx
@@ -5829,6 +5833,9 @@  omp_add_variable (struct gimplify_omp_ct
      the parameters of the type.  */
   if (DECL_SIZE (decl) && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
     {
+      /* To be handled later.  */
+      gcc_assert ((flags & GOVD_MAP) == 0);
+
       /* Add the pointer replacement variable as PRIVATE if the variable
 	 replacement is private, else FIRSTPRIVATE since we'll need the
 	 address of the original variable either for SHARED, or for the
@@ -5870,6 +5877,9 @@  omp_add_variable (struct gimplify_omp_ct
     }
   else if (lang_hooks.decls.omp_privatize_by_reference (decl))
     {
+      /* To be handled later.  */
+      gcc_assert ((flags & GOVD_MAP) == 0);
+
       gcc_assert ((flags & GOVD_LOCAL) == 0);
       omp_firstprivatize_type_sizes (ctx, TREE_TYPE (decl));
 
@@ -5896,6 +5906,22 @@  omp_notice_threadprivate_variable (struc
 				   tree decl2)
 {
   splay_tree_node n;
+  struct gimplify_omp_ctx *octx;
+
+  for (octx = ctx; octx; octx = octx->outer_context)
+    if (octx->region_type == ORT_TARGET)
+      {
+	n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl);
+	if (n == NULL)
+	  {
+	    error ("threadprivate variable %qE used in target region",
+		   DECL_NAME (decl));
+	    error_at (octx->location, "enclosing target region");
+	    splay_tree_insert (octx->variables, (splay_tree_key)decl, 0);
+	  }
+	if (decl2)
+	  splay_tree_insert (octx->variables, (splay_tree_key)decl2, 0);
+      }
 
   if (ctx->region_type != ORT_UNTIED_TASK)
     return false;
@@ -5944,13 +5970,24 @@  omp_notice_variable (struct gimplify_omp
     }
 
   n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl);
+  if (ctx->region_type == ORT_TARGET)
+    {
+      if (n == NULL)
+	omp_add_variable (ctx, decl, GOVD_MAP | flags);
+      else
+	n->value |= flags;
+      ret = lang_hooks.decls.omp_disregard_value_expr (decl, true);
+      goto do_outer;
+    }
+
   if (n == NULL)
     {
       enum omp_clause_default_kind default_kind, kind;
       struct gimplify_omp_ctx *octx;
 
       if (ctx->region_type == ORT_WORKSHARE
-	  || ctx->region_type == ORT_SIMD)
+	  || ctx->region_type == ORT_SIMD
+	  || ctx->region_type == ORT_TARGET_DATA)
 	goto do_outer;
 
       /* ??? Some compiler-generated variables (like SAVE_EXPRs) could be
@@ -5964,12 +6001,24 @@  omp_notice_variable (struct gimplify_omp
       switch (default_kind)
 	{
 	case OMP_CLAUSE_DEFAULT_NONE:
-	  error ("%qE not specified in enclosing parallel",
-		 DECL_NAME (lang_hooks.decls.omp_report_decl (decl)));
 	  if ((ctx->region_type & ORT_TASK) != 0)
-	    error_at (ctx->location, "enclosing task");
+	    {
+	      error ("%qE not specified in enclosing task",
+		     DECL_NAME (lang_hooks.decls.omp_report_decl (decl)));
+	      error_at (ctx->location, "enclosing task");
+	    }
+	  else if (ctx->region_type == ORT_TEAMS)
+	    {
+	      error ("%qE not specified in enclosing teams construct",
+		     DECL_NAME (lang_hooks.decls.omp_report_decl (decl)));
+	      error_at (ctx->location, "enclosing teams construct");
+	    }
 	  else
-	    error_at (ctx->location, "enclosing parallel");
+	    {
+	      error ("%qE not specified in enclosing parallel",
+		     DECL_NAME (lang_hooks.decls.omp_report_decl (decl)));
+	      error_at (ctx->location, "enclosing parallel");
+	    }
 	  /* FALLTHRU */
 	case OMP_CLAUSE_DEFAULT_SHARED:
 	  flags |= GOVD_SHARED;
@@ -5989,13 +6038,15 @@  omp_notice_variable (struct gimplify_omp
 	    {
 	      splay_tree_node n2;
 
+	      if ((octx->region_type & (ORT_TARGET_DATA | ORT_TARGET)) != 0)
+		continue;
 	      n2 = splay_tree_lookup (octx->variables, (splay_tree_key) decl);
 	      if (n2 && (n2->value & GOVD_DATA_SHARE_CLASS) != GOVD_SHARED)
 		{
 		  flags |= GOVD_FIRSTPRIVATE;
 		  break;
 		}
-	      if ((octx->region_type & ORT_PARALLEL) != 0)
+	      if ((octx->region_type & (ORT_PARALLEL | ORT_TEAMS)) != 0)
 		break;
 	    }
 	  if (flags & GOVD_FIRSTPRIVATE)
@@ -6137,6 +6188,9 @@  omp_check_private (struct gimplify_omp_c
 		 /* References might be private, but might be shared too.  */
 		 || lang_hooks.decls.omp_privatize_by_reference (decl));
 
+      if ((ctx->region_type & (ORT_TARGET | ORT_TARGET_DATA)) != 0)
+	continue;
+
       n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl);
       if (n != NULL)
 	return (n->value & GOVD_SHARED) == 0;
@@ -6204,6 +6258,20 @@  gimplify_scan_omp_clauses (tree *list_p,
 	    }
 	  flags = GOVD_LINEAR | GOVD_EXPLICIT;
 	  goto do_add;
+	case OMP_CLAUSE_MAP:
+	  flags = GOVD_MAP | GOVD_EXPLICIT;
+	  notice_outer = false;
+	  goto do_add;
+
+	case OMP_CLAUSE_TO:
+	case OMP_CLAUSE_FROM:
+	  decl = OMP_CLAUSE_DECL (c);
+	  if (error_operand_p (decl))
+	    {
+	      remove = true;
+	      break;
+	    }
+	  goto do_notice;
 
 	do_add:
 	  decl = OMP_CLAUSE_DECL (c);
@@ -6292,6 +6360,9 @@  gimplify_scan_omp_clauses (tree *list_p,
 
 	case OMP_CLAUSE_SCHEDULE:
 	case OMP_CLAUSE_NUM_THREADS:
+	case OMP_CLAUSE_NUM_TEAMS:
+	case OMP_CLAUSE_DIST_SCHEDULE:
+	case OMP_CLAUSE_DEVICE:
 	  if (gimplify_expr (&OMP_CLAUSE_OPERAND (c, 0), pre_p, NULL,
 			     is_gimple_val, fb_rvalue) == GS_ERROR)
 	    remove = true;
@@ -6357,12 +6428,40 @@  gimplify_adjust_omp_clauses_1 (splay_tre
       gcc_assert ((flags & GOVD_DATA_SHARE_CLASS) == GOVD_PRIVATE);
       private_debug = true;
     }
+  else if (flags & GOVD_MAP)
+    private_debug = false;
   else
     private_debug
       = lang_hooks.decls.omp_private_debug_clause (decl,
 						   !!(flags & GOVD_SHARED));
   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;
+    }
   else if (flags & GOVD_SHARED)
     {
       if (is_global_var (decl))
@@ -6373,7 +6472,8 @@  gimplify_adjust_omp_clauses_1 (splay_tre
 	      splay_tree_node on
 		= splay_tree_lookup (ctx->variables, (splay_tree_key) decl);
 	      if (on && (on->value & (GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE
-				      | GOVD_PRIVATE | GOVD_REDUCTION)) != 0)
+				      | GOVD_PRIVATE | GOVD_REDUCTION
+				      | GOVD_LINEAR)) != 0)
 		break;
 	      ctx = ctx->outer_context;
 	    }
@@ -6400,6 +6500,8 @@  gimplify_adjust_omp_clauses_1 (splay_tre
     OMP_CLAUSE_PRIVATE_DEBUG (clause) = 1;
   else if (code == OMP_CLAUSE_PRIVATE && (flags & GOVD_PRIVATE_OUTER_REF))
     OMP_CLAUSE_PRIVATE_OUTER_REF (clause) = 1;
+  else if (code == OMP_CLAUSE_MAP)
+    OMP_CLAUSE_MAP_KIND (clause) = OMP_CLAUSE_MAP_TOFROM;
   *list_p = clause;
   lang_hooks.decls.omp_finish_clause (clause);
 
@@ -6517,11 +6619,47 @@  gimplify_adjust_omp_clauses (tree *list_
 	    }
 	  break;
 
+	case OMP_CLAUSE_MAP:
+	  decl = OMP_CLAUSE_DECL (c);
+	  n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl);
+	  remove = false;
+	  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:
 	case OMP_CLAUSE_COPYIN:
 	case OMP_CLAUSE_COPYPRIVATE:
 	case OMP_CLAUSE_IF:
 	case OMP_CLAUSE_NUM_THREADS:
+	case OMP_CLAUSE_NUM_TEAMS:
+	case OMP_CLAUSE_DIST_SCHEDULE:
+	case OMP_CLAUSE_DEVICE:
 	case OMP_CLAUSE_SCHEDULE:
 	case OMP_CLAUSE_NOWAIT:
 	case OMP_CLAUSE_ORDERED:
@@ -6532,6 +6670,8 @@  gimplify_adjust_omp_clauses (tree *list_
 	case OMP_CLAUSE_MERGEABLE:
 	case OMP_CLAUSE_PROC_BIND:
 	case OMP_CLAUSE_SAFELEN:
+	case OMP_CLAUSE_TO:
+	case OMP_CLAUSE_FROM:
 	  break;
 
 	default:
@@ -6847,25 +6987,19 @@  gimplify_omp_for (tree *expr_p, gimple_s
 
   gimplify_adjust_omp_clauses (&OMP_FOR_CLAUSES (for_stmt));
 
-  gfor = gimple_build_omp_for (for_body, OMP_FOR_CLAUSES (for_stmt),
-			       TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)),
-			       for_pre_body);
+  int kind;
   switch (TREE_CODE (for_stmt))
     {
-    case OMP_FOR:
-      break;
-    case OMP_SIMD:
-      gimple_omp_for_set_kind (gfor, GF_OMP_FOR_KIND_SIMD);
-      break;
-    case OMP_FOR_SIMD:
-      gimple_omp_for_set_kind (gfor, GF_OMP_FOR_KIND_FOR_SIMD);
-      break;
-    case OMP_DISTRIBUTE:
-      gimple_omp_for_set_kind (gfor, GF_OMP_FOR_KIND_DISTRIBUTE);
-      break;
+    case OMP_FOR: kind = GF_OMP_FOR_KIND_FOR; break;
+    case OMP_SIMD: kind = GF_OMP_FOR_KIND_SIMD; break;
+    case OMP_FOR_SIMD: kind = GF_OMP_FOR_KIND_FOR_SIMD; break;
+    case OMP_DISTRIBUTE: kind = GF_OMP_FOR_KIND_DISTRIBUTE; break;
     default:
       gcc_unreachable ();
     }
+  gfor = gimple_build_omp_for (for_body, kind, OMP_FOR_CLAUSES (for_stmt),
+			       TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)),
+			       for_pre_body);
 
   for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++)
     {
@@ -6880,11 +7014,15 @@  gimplify_omp_for (tree *expr_p, gimple_s
     }
 
   gimplify_seq_add_stmt (pre_p, gfor);
-  return ret == GS_ALL_DONE ? GS_ALL_DONE : GS_ERROR;
+  if (ret != GS_ALL_DONE)
+    return GS_ERROR;
+  *expr_p = NULL_TREE;
+  return GS_ALL_DONE;
 }
 
-/* Gimplify the gross structure of other OpenMP worksharing constructs.
-   In particular, OMP_SECTIONS and OMP_SINGLE.  */
+/* Gimplify the gross structure of other OpenMP constructs.
+   In particular, OMP_SECTIONS, OMP_SINGLE, OMP_TARGET, OMP_TARGET_DATA
+   and OMP_TEAMS.  */
 
 static void
 gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p)
@@ -6892,19 +7030,72 @@  gimplify_omp_workshare (tree *expr_p, gi
   tree expr = *expr_p;
   gimple stmt;
   gimple_seq body = NULL;
+  enum omp_region_type ort = ORT_WORKSHARE;
 
-  gimplify_scan_omp_clauses (&OMP_CLAUSES (expr), pre_p, ORT_WORKSHARE);
+  switch (TREE_CODE (expr))
+    {
+    case OMP_SECTIONS:
+    case OMP_SINGLE:
+      break;
+    case OMP_TARGET:
+      ort = ORT_TARGET;
+      break;
+    case OMP_TARGET_DATA:
+      ort = ORT_TARGET_DATA;
+      break;
+    case OMP_TEAMS:
+      ort = ORT_TEAMS;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  gimplify_scan_omp_clauses (&OMP_CLAUSES (expr), pre_p, ort);
   gimplify_and_add (OMP_BODY (expr), &body);
   gimplify_adjust_omp_clauses (&OMP_CLAUSES (expr));
 
-  if (TREE_CODE (expr) == OMP_SECTIONS)
-    stmt = gimple_build_omp_sections (body, OMP_CLAUSES (expr));
-  else if (TREE_CODE (expr) == OMP_SINGLE)
-    stmt = gimple_build_omp_single (body, OMP_CLAUSES (expr));
-  else
-    gcc_unreachable ();
+  switch (TREE_CODE (expr))
+    {
+    case OMP_SECTIONS:
+      stmt = gimple_build_omp_sections (body, OMP_CLAUSES (expr));
+      break;
+    case OMP_SINGLE:
+      stmt = gimple_build_omp_single (body, OMP_CLAUSES (expr));
+      break;
+    case OMP_TARGET:
+      stmt = gimple_build_omp_target (body, GF_OMP_TARGET_KIND_REGION,
+				      OMP_CLAUSES (expr));
+      break;
+    case OMP_TARGET_DATA:
+      stmt = gimple_build_omp_target (body, GF_OMP_TARGET_KIND_DATA,
+				      OMP_CLAUSES (expr));
+      break;
+    case OMP_TEAMS:
+      stmt = gimple_build_omp_teams (body, OMP_CLAUSES (expr));
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  gimplify_seq_add_stmt (pre_p, stmt);
+  *expr_p = NULL_TREE;
+}
+
+/* Gimplify the gross structure of OpenMP target update construct.  */
+
+static void
+gimplify_omp_target_update (tree *expr_p, gimple_seq *pre_p)
+{
+  tree expr = *expr_p;
+  gimple stmt;
+
+  gimplify_scan_omp_clauses (&OMP_TARGET_UPDATE_CLAUSES (expr), pre_p,
+			     ORT_WORKSHARE);
+  gimplify_adjust_omp_clauses (&OMP_TARGET_UPDATE_CLAUSES (expr));
+  stmt = gimple_build_omp_target (NULL, GF_OMP_TARGET_KIND_UPDATE,
+				  OMP_TARGET_UPDATE_CLAUSES (expr));
 
   gimplify_seq_add_stmt (pre_p, stmt);
+  *expr_p = NULL_TREE;
 }
 
 /* A subroutine of gimplify_omp_atomic.  The front end is supposed to have
@@ -7811,10 +8002,18 @@  gimplify_expr (tree *expr_p, gimple_seq
 
 	case OMP_SECTIONS:
 	case OMP_SINGLE:
+	case OMP_TARGET:
+	case OMP_TARGET_DATA:
+	case OMP_TEAMS:
 	  gimplify_omp_workshare (expr_p, pre_p);
 	  ret = GS_ALL_DONE;
 	  break;
 
+	case OMP_TARGET_UPDATE:
+	  gimplify_omp_target_update (expr_p, pre_p);
+	  ret = GS_ALL_DONE;
+	  break;
+
 	case OMP_SECTION:
 	case OMP_MASTER:
 	case OMP_ORDERED: