--- gcc/gimple-pretty-print.c.jj	2013-05-27 09:22:21.000000000 +0200
+++ gcc/gimple-pretty-print.c	2013-06-14 12:09:18.273391612 +0200
@@ -1110,9 +1110,6 @@ dump_gimple_omp_for (pretty_printer *buf
 	case GF_OMP_FOR_KIND_SIMD:
 	  kind = " simd";
 	  break;
-	case GF_OMP_FOR_KIND_FOR_SIMD:
-	  kind = " for simd";
-	  break;
 	case GF_OMP_FOR_KIND_DISTRIBUTE:
 	  kind = " distribute";
 	  break;
@@ -1144,9 +1141,6 @@ dump_gimple_omp_for (pretty_printer *buf
 	case GF_OMP_FOR_KIND_SIMD:
 	  pp_string (buffer, "#pragma omp simd");
 	  break;
-	case GF_OMP_FOR_KIND_FOR_SIMD:
-	  pp_string (buffer, "#pragma omp for simd");
-	  break;
 	case GF_OMP_FOR_KIND_DISTRIBUTE:
 	  pp_string (buffer, "#pragma omp distribute");
 	  break;
--- gcc/c/c-parser.c.jj	2013-05-13 16:36:52.000000000 +0200
+++ gcc/c/c-parser.c	2013-06-14 12:09:18.276392262 +0200
@@ -11044,7 +11044,7 @@ c_parser_omp_for (location_t loc, c_pars
       if (strcmp (p, "simd") == 0)
 	{
 	  c_parser_consume_token (parser);
-	  code = OMP_FOR_SIMD;
+	  /* code = OMP_FOR_SIMD; */
 	  mask |= OMP_SIMD_CLAUSE_MASK;
 	  p_name = "#pragma omp for simd";
 	}
@@ -11234,6 +11234,7 @@ c_parser_omp_parallel (location_t loc, c
   const char *p_name = "#pragma omp parallel";
   tree stmt, clauses, par_clause, ws_clause, block;
   omp_clause_mask mask = OMP_PARALLEL_CLAUSE_MASK;
+  tree cclauses[C_OMP_CLAUSE_SPLIT_COUNT];
 
   if (c_parser_next_token_is_keyword (parser, RID_FOR))
     {
@@ -11280,7 +11281,9 @@ c_parser_omp_parallel (location_t loc, c
 
     case PRAGMA_OMP_PARALLEL_FOR:
       block = c_begin_omp_parallel ();
-      c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause);
+      c_omp_split_clauses (loc, OMP_FOR, mask, clauses, cclauses);
+      par_clause = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL];
+      ws_clause = cclauses[C_OMP_CLAUSE_SPLIT_FOR];
       c_parser_omp_for_loop (loc, parser, OMP_FOR, ws_clause, &par_clause);
       stmt = c_finish_omp_parallel (loc, par_clause, block);
       OMP_PARALLEL_COMBINED (stmt) = 1;
@@ -11288,8 +11291,10 @@ c_parser_omp_parallel (location_t loc, c
 
     case PRAGMA_OMP_PARALLEL_FOR_SIMD:
       block = c_begin_omp_parallel ();
-      c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause);
-      c_parser_omp_for_loop (loc, parser, OMP_FOR_SIMD, ws_clause,
+      c_omp_split_clauses (loc, OMP_FOR, mask, clauses, cclauses);
+      par_clause = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL];
+      ws_clause = cclauses[C_OMP_CLAUSE_SPLIT_FOR];
+      c_parser_omp_for_loop (loc, parser, OMP_FOR /*_SIMD*/, ws_clause,
 			     &par_clause);
       stmt = c_finish_omp_parallel (loc, par_clause, block);
       OMP_PARALLEL_COMBINED (stmt) = 1;
@@ -11297,7 +11302,9 @@ c_parser_omp_parallel (location_t loc, c
 
     case PRAGMA_OMP_PARALLEL_SECTIONS:
       block = c_begin_omp_parallel ();
-      c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause);
+      c_omp_split_clauses (loc, OMP_SECTIONS, mask, clauses, cclauses);
+      par_clause = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL];
+      ws_clause = cclauses[C_OMP_CLAUSE_SPLIT_SECTIONS];
       stmt = c_parser_omp_sections_scope (loc, parser);
       if (stmt)
 	OMP_SECTIONS_CLAUSES (stmt) = ws_clause;
--- gcc/cp/parser.c.jj	2013-06-12 15:00:11.000000000 +0200
+++ gcc/cp/parser.c	2013-06-14 13:22:11.291742674 +0200
@@ -27299,7 +27299,8 @@ cp_parser_omp_clause_proc_bind (cp_parse
 
 static tree
 cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask,
-			   const char *where, cp_token *pragma_tok)
+			   const char *where, cp_token *pragma_tok,
+			   bool finish_p = true)
 {
   tree clauses = NULL;
   bool first = true;
@@ -27526,9 +27527,9 @@ cp_parser_omp_all_clauses (cp_parser *pa
     }
  saw_error:
   cp_parser_skip_to_pragma_eol (parser, pragma_tok);
-  if (parser->omp_declare_simd_clauses)
-    return clauses;
-  return finish_omp_clauses (clauses);
+  if (finish_p)
+    return finish_omp_clauses (clauses);
+  return clauses;
 }
 
 /* OpenMP 2.5:
@@ -28202,7 +28203,7 @@ cp_parser_omp_for_incr (cp_parser *parse
 
 static tree
 cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses,
-			tree *par_clauses)
+			tree *cclauses)
 {
   tree init, cond, incr, body, decl, pre_body = NULL_TREE, ret;
   tree real_decl, initv, condv, incrv, declv;
@@ -28412,10 +28413,12 @@ cp_parser_omp_for_loop (cp_parser *parse
 
       if (decl)
 	real_decl = decl;
-      if (par_clauses != NULL && real_decl != NULL_TREE)
+      if (cclauses != NULL
+	  && cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] != NULL
+	  && real_decl != NULL_TREE)
 	{
 	  tree *c;
-	  for (c = par_clauses; *c ; )
+	  for (c = &cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; *c ; )
 	    if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_FIRSTPRIVATE
 		&& OMP_CLAUSE_DECL (*c) == real_decl)
 	      {
@@ -28594,6 +28597,20 @@ cp_parser_omp_for_loop (cp_parser *parse
   return ret;
 }
 
+/* Helper function for OpenMP parsing, split clauses and call
+   finish_omp_clauses on each of the set of clauses afterwards.  */
+
+static void
+cp_omp_split_clauses (location_t loc, enum tree_code code,
+		      omp_clause_mask mask, tree clauses, tree *cclauses)
+{
+  int i;
+  c_omp_split_clauses (loc, code, mask, clauses, cclauses);
+  for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++)
+    if (cclauses[i])
+      cclauses[i] = finish_omp_clauses (cclauses[i]);
+}
+
 /* OpenMP 4.0:
    #pragma omp simd simd-clause[optseq] new-line
      for-loop  */
@@ -28608,18 +28625,29 @@ cp_parser_omp_for_loop (cp_parser *parse
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE))
 
 static tree
-cp_parser_omp_simd (cp_parser *parser, cp_token *pragma_tok)
+cp_parser_omp_simd (cp_parser *parser, cp_token *pragma_tok,
+		    char *p_name, omp_clause_mask mask, tree *cclauses)
 {
   tree clauses, sb, ret;
   unsigned int save;
+  location_t loc = cp_lexer_peek_token (parser->lexer)->location;
 
-  clauses = cp_parser_omp_all_clauses (parser, OMP_SIMD_CLAUSE_MASK,
-				       "#pragma omp simd", pragma_tok);
+  strcat (p_name, " simd");
+  mask |= OMP_SIMD_CLAUSE_MASK;
+  mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED);
+
+  clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok,
+				       cclauses == NULL);
+  if (cclauses)
+    {
+      cp_omp_split_clauses (loc, OMP_SIMD, mask, clauses, cclauses);
+      clauses = cclauses[C_OMP_CLAUSE_SPLIT_SIMD];
+    }
 
   sb = begin_omp_structured_block ();
   save = cp_parser_begin_omp_structured_block (parser);
 
-  ret = cp_parser_omp_for_loop (parser, OMP_SIMD, clauses, NULL);
+  ret = cp_parser_omp_for_loop (parser, OMP_SIMD, clauses, cclauses);
 
   cp_parser_end_omp_structured_block (parser, save);
   add_stmt (finish_omp_structured_block (sb));
@@ -28646,13 +28674,17 @@ cp_parser_omp_simd (cp_parser *parser, c
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE))
 
 static tree
-cp_parser_omp_for (cp_parser *parser, cp_token *pragma_tok)
+cp_parser_omp_for (cp_parser *parser, cp_token *pragma_tok,
+		   char *p_name, omp_clause_mask mask, tree *cclauses)
 {
   tree clauses, sb, ret;
   unsigned int save;
-  enum tree_code code = OMP_FOR;
-  omp_clause_mask mask = OMP_FOR_CLAUSE_MASK;
-  const char *p_name = "#pragma omp for";
+  location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+
+  strcat (p_name, " for");
+  mask |= OMP_FOR_CLAUSE_MASK;
+  if (cclauses)
+    mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT);
 
   if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
     {
@@ -28661,19 +28693,41 @@ cp_parser_omp_for (cp_parser *parser, cp
 
       if (strcmp (p, "simd") == 0)
 	{
+	  tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+	  if (cclauses == NULL)
+	    cclauses = cclauses_buf;
+
 	  cp_lexer_consume_token (parser->lexer);
-	  code = OMP_FOR_SIMD;
-	  mask |= OMP_SIMD_CLAUSE_MASK;
-	  p_name = "#pragma omp for simd";
+	  sb = begin_omp_structured_block ();
+	  save = cp_parser_begin_omp_structured_block (parser);
+	  ret = cp_parser_omp_simd (parser, pragma_tok, p_name, mask,
+				    cclauses);
+	  cp_parser_end_omp_structured_block (parser, save);
+	  tree body = finish_omp_structured_block (sb);
+	  if (ret == NULL)
+	    return ret;
+	  ret = make_node (OMP_FOR);
+	  TREE_TYPE (ret) = void_type_node;
+	  OMP_FOR_BODY (ret) = body;
+	  OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_FOR];
+	  SET_EXPR_LOCATION (ret, loc);
+	  add_stmt (ret);
+	  return ret;
 	}
     }
 
-  clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok);
+  clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok,
+				       cclauses == NULL);
+  if (cclauses)
+    {
+      cp_omp_split_clauses (loc, OMP_FOR, mask, clauses, cclauses);
+      clauses = cclauses[C_OMP_CLAUSE_SPLIT_FOR];
+    }
 
   sb = begin_omp_structured_block ();
   save = cp_parser_begin_omp_structured_block (parser);
 
-  ret = cp_parser_omp_for_loop (parser, code, clauses, NULL);
+  ret = cp_parser_omp_for_loop (parser, OMP_FOR, clauses, cclauses);
 
   cp_parser_end_omp_structured_block (parser, save);
   add_stmt (finish_omp_structured_block (sb));
@@ -28800,12 +28854,24 @@ cp_parser_omp_sections_scope (cp_parser
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
 
 static tree
-cp_parser_omp_sections (cp_parser *parser, cp_token *pragma_tok)
+cp_parser_omp_sections (cp_parser *parser, cp_token *pragma_tok,
+			char *p_name, omp_clause_mask mask, tree *cclauses)
 {
   tree clauses, ret;
+  location_t loc = cp_lexer_peek_token (parser->lexer)->location;
 
-  clauses = cp_parser_omp_all_clauses (parser, OMP_SECTIONS_CLAUSE_MASK,
-				       "#pragma omp sections", pragma_tok);
+  strcat (p_name, " sections");
+  mask |= OMP_SECTIONS_CLAUSE_MASK;
+  if (cclauses)
+    mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT);
+
+  clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok,
+				       cclauses == NULL);
+  if (cclauses)
+    {
+      cp_omp_split_clauses (loc, OMP_SECTIONS, mask, clauses, cclauses);
+      clauses = cclauses[C_OMP_CLAUSE_SPLIT_SECTIONS];
+    }
 
   ret = cp_parser_omp_sections_scope (parser);
   if (ret)
@@ -28834,35 +28900,37 @@ cp_parser_omp_sections (cp_parser *parse
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PROC_BIND))
 
 static tree
-cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok)
+cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok,
+			char *p_name, omp_clause_mask mask, tree *cclauses)
 {
-  enum pragma_kind p_kind = PRAGMA_OMP_PARALLEL;
-  const char *p_name = "#pragma omp parallel";
-  tree stmt, clauses, par_clause, ws_clause, block;
-  omp_clause_mask mask = OMP_PARALLEL_CLAUSE_MASK;
+  tree stmt, clauses, block;
   unsigned int save;
   location_t loc = cp_lexer_peek_token (parser->lexer)->location;
 
+  strcat (p_name, " parallel");
+  mask |= OMP_PARALLEL_CLAUSE_MASK;
+
   if (cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR))
     {
-      cp_lexer_consume_token (parser->lexer);
-      p_kind = PRAGMA_OMP_PARALLEL_FOR;
-      p_name = "#pragma omp parallel for";
-      mask |= OMP_FOR_CLAUSE_MASK;
-      mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT);
-      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);
+      tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+      if (cclauses == NULL)
+	cclauses = cclauses_buf;
 
-	  if (strcmp (p, "simd") == 0)
-	    {
-	      cp_lexer_consume_token (parser->lexer);
-	      p_kind = PRAGMA_OMP_PARALLEL_FOR_SIMD;
-	      p_name = "#pragma omp parallel for simd";
-	      mask |= OMP_SIMD_CLAUSE_MASK;
-	    }
-	}
+      cp_lexer_consume_token (parser->lexer);
+      block = begin_omp_parallel ();
+      save = cp_parser_begin_omp_structured_block (parser);
+      cp_parser_omp_for (parser, pragma_tok, p_name, mask, cclauses);
+      cp_parser_end_omp_structured_block (parser, save);
+      stmt = finish_omp_parallel (cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL],
+				  block);
+      OMP_PARALLEL_COMBINED (stmt) = 1;
+      return stmt;
+    }
+  else if (cclauses)
+    {
+      error_at (loc, "expected %<for%> after %qs", p_name);
+      cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+      return NULL_TREE;
     }
   else if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
     {
@@ -28870,50 +28938,28 @@ cp_parser_omp_parallel (cp_parser *parse
       const char *p = IDENTIFIER_POINTER (id);
       if (strcmp (p, "sections") == 0)
 	{
+	  tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+	  cclauses = cclauses_buf;
+
 	  cp_lexer_consume_token (parser->lexer);
-	  p_kind = PRAGMA_OMP_PARALLEL_SECTIONS;
-	  p_name = "#pragma omp parallel sections";
-	  mask |= OMP_SECTIONS_CLAUSE_MASK;
-	  mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT);
+	  block = begin_omp_parallel ();
+	  save = cp_parser_begin_omp_structured_block (parser);
+	  cp_parser_omp_sections (parser, pragma_tok, p_name, mask, cclauses);
+	  cp_parser_end_omp_structured_block (parser, save);
+	  stmt = finish_omp_parallel (cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL],
+				      block);
+	  OMP_PARALLEL_COMBINED (stmt) = 1;
+	  return stmt;
 	}
     }
 
   clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok);
+
   block = begin_omp_parallel ();
   save = cp_parser_begin_omp_structured_block (parser);
-
-  switch (p_kind)
-    {
-    case PRAGMA_OMP_PARALLEL:
-      cp_parser_statement (parser, NULL_TREE, false, NULL);
-      par_clause = clauses;
-      break;
-
-    case PRAGMA_OMP_PARALLEL_FOR:
-      c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause);
-      cp_parser_omp_for_loop (parser, OMP_FOR, ws_clause, &par_clause);
-      break;
-
-    case PRAGMA_OMP_PARALLEL_FOR_SIMD:
-      c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause);
-      cp_parser_omp_for_loop (parser, OMP_FOR_SIMD, ws_clause, &par_clause);
-      break;
-
-    case PRAGMA_OMP_PARALLEL_SECTIONS:
-      c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause);
-      stmt = cp_parser_omp_sections_scope (parser);
-      if (stmt)
-	OMP_SECTIONS_CLAUSES (stmt) = ws_clause;
-      break;
-
-    default:
-      gcc_unreachable ();
-    }
-
+  cp_parser_statement (parser, NULL_TREE, false, NULL);
   cp_parser_end_omp_structured_block (parser, save);
-  stmt = finish_omp_parallel (par_clause, block);
-  if (p_kind != PRAGMA_OMP_PARALLEL)
-    OMP_PARALLEL_COMBINED (stmt) = 1;
+  stmt = finish_omp_parallel (clauses, block);
   return stmt;
 }
 
@@ -29088,6 +29134,92 @@ cp_parser_omp_cancellation_point (cp_par
 }
 
 /* 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,
+			  char *p_name, omp_clause_mask mask, tree *cclauses)
+{
+  tree clauses, sb, ret;
+  unsigned int save;
+  location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+
+  strcat (p_name, " distribute");
+  mask |= OMP_DISTRIBUTE_CLAUSE_MASK;
+
+  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);
+      bool simd = false;
+      bool parallel = false;
+
+      if (strcmp (p, "simd") == 0)
+	{
+	  simd = true;
+	  if (cclauses)
+	    {
+	      error_at (loc, "%<simd%> not expected after %qs", p_name);
+	      cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+	      return NULL_TREE;
+	    }
+	}
+      else
+	parallel = strcmp (p, "parallel") == 0;
+      if (parallel || simd)
+	{
+	  tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+	  if (cclauses == NULL)
+	    cclauses = cclauses_buf;
+	  sb = begin_omp_structured_block ();
+	  save = cp_parser_begin_omp_structured_block (parser);
+	  if (simd)
+	    ret = cp_parser_omp_simd (parser, pragma_tok, p_name, mask,
+				      cclauses);
+	  else
+	    ret = cp_parser_omp_parallel (parser, pragma_tok, p_name, mask,
+					  cclauses);
+	  cp_parser_end_omp_structured_block (parser, save);
+	  tree body = finish_omp_structured_block (sb);
+	  if (ret == NULL)
+	    return ret;
+	  ret = make_node (OMP_DISTRIBUTE);
+	  TREE_TYPE (ret) = void_type_node;
+	  OMP_FOR_BODY (ret) = body;
+	  OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE];
+	  SET_EXPR_LOCATION (ret, loc);
+	  add_stmt (ret);
+	  return ret;
+	}
+    }
+
+  clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok,
+				       cclauses == NULL);
+  if (cclauses)
+    {
+      cp_omp_split_clauses (loc, OMP_DISTRIBUTE, mask, clauses, cclauses);
+      clauses = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE];
+    }
+
+  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 teams teams-clause[optseq] new-line
      structured-block  */
 
@@ -29101,14 +29233,55 @@ cp_parser_omp_cancellation_point (cp_par
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT))
 
 static tree
-cp_parser_omp_teams (cp_parser *parser, cp_token *pragma_tok)
+cp_parser_omp_teams (cp_parser *parser, cp_token *pragma_tok,
+		     char *p_name, omp_clause_mask mask, tree *cclauses)
 {
+  tree clauses, sb, ret;
+  unsigned int save;
+  location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+
+  strcat (p_name, " teams");
+  mask |= OMP_TEAMS_CLAUSE_MASK;
+
+  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, "distribute") == 0)
+	{
+	  tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+	  if (cclauses == NULL)
+	    cclauses = cclauses_buf;
+
+	  cp_lexer_consume_token (parser->lexer);
+	  sb = begin_omp_structured_block ();
+	  save = cp_parser_begin_omp_structured_block (parser);
+	  ret = cp_parser_omp_distribute (parser, pragma_tok, p_name, mask,
+					  cclauses);
+	  cp_parser_end_omp_structured_block (parser, save);
+	  tree body = finish_omp_structured_block (sb);
+	  if (ret == NULL)
+	    return ret;
+	  clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS];
+	  ret = make_node (OMP_TEAMS);
+	  TREE_TYPE (ret) = void_type_node;
+	  OMP_TEAMS_CLAUSES (ret) = clauses;
+	  OMP_TEAMS_BODY (ret) = body;
+	  return add_stmt (ret);
+	}
+    }
+
+  clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok,
+				       cclauses == NULL);
+  if (cclauses)
+    {
+      cp_omp_split_clauses (loc, OMP_TEAMS, mask, clauses, cclauses);
+      clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS];
+    }
+
   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_CLAUSES (stmt) = clauses;
   OMP_TEAMS_BODY (stmt) = cp_parser_omp_structured_block (parser);
 
   return add_stmt (stmt);
@@ -29216,6 +29389,29 @@ cp_parser_omp_target (cp_parser *parser,
 	  cp_lexer_consume_token (parser->lexer);
 	  return cp_parser_omp_target_update (parser, pragma_tok, context);
 	}
+      else if (strcmp (p, "teams") == 0)
+	{
+	  tree cclauses[C_OMP_CLAUSE_SPLIT_COUNT];
+	  char p_name[sizeof ("#pragma omp target teams distribute "
+			      "parallel for simd")];
+
+	  cp_lexer_consume_token (parser->lexer);
+	  strcpy (p_name, "#pragma omp target");
+	  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,
+					  OMP_TARGET_CLAUSE_MASK, cclauses);
+	  cp_parser_end_omp_structured_block (parser, save);
+	  tree body = finish_omp_structured_block (sb);
+	  if (ret == NULL)
+	    return ret;
+	  tree stmt = make_node (OMP_TARGET);
+	  TREE_TYPE (stmt) = void_type_node;
+	  OMP_TARGET_CLAUSES (stmt) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET];
+	  OMP_TARGET_BODY (stmt) = body;
+	  add_stmt (stmt);
+	  return true;
+	}
     }
 
   tree stmt = make_node (OMP_TARGET);
@@ -29232,36 +29428,6 @@ cp_parser_omp_target (cp_parser *parser,
 }
 
 /* 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				\
@@ -29281,7 +29447,8 @@ cp_parser_omp_declare_simd (cp_parser *p
   vec_safe_push (parser->omp_declare_simd_clauses, NULL_TREE);
   tree clauses
     = cp_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK,
-				 "#pragma omp declare simd", pragma_tok);
+				 "#pragma omp declare simd", pragma_tok,
+				 false);
   parser->omp_declare_simd_clauses->last () = clauses;
   if (first_p)
     {
@@ -29382,6 +29549,8 @@ static void
 cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok)
 {
   tree stmt;
+  char p_name[sizeof "#pragma omp teams distribute parallel for simd"];
+  omp_clause_mask mask (0);
 
   switch (pragma_tok->pragma_kind)
     {
@@ -29392,10 +29561,12 @@ cp_parser_omp_construct (cp_parser *pars
       stmt = cp_parser_omp_critical (parser, pragma_tok);
       break;
     case PRAGMA_OMP_DISTRIBUTE:
-      stmt = cp_parser_omp_distribute (parser, pragma_tok);
+      strcpy (p_name, "#pragma omp");
+      stmt = cp_parser_omp_distribute (parser, pragma_tok, p_name, mask, NULL);
       break;
     case PRAGMA_OMP_FOR:
-      stmt = cp_parser_omp_for (parser, pragma_tok);
+      strcpy (p_name, "#pragma omp");
+      stmt = cp_parser_omp_for (parser, pragma_tok, p_name, mask, NULL);
       break;
     case PRAGMA_OMP_MASTER:
       stmt = cp_parser_omp_master (parser, pragma_tok);
@@ -29404,13 +29575,16 @@ cp_parser_omp_construct (cp_parser *pars
       stmt = cp_parser_omp_ordered (parser, pragma_tok);
       break;
     case PRAGMA_OMP_PARALLEL:
-      stmt = cp_parser_omp_parallel (parser, pragma_tok);
+      strcpy (p_name, "#pragma omp");
+      stmt = cp_parser_omp_parallel (parser, pragma_tok, p_name, mask, NULL);
       break;
     case PRAGMA_OMP_SECTIONS:
-      stmt = cp_parser_omp_sections (parser, pragma_tok);
+      strcpy (p_name, "#pragma omp");
+      stmt = cp_parser_omp_sections (parser, pragma_tok, p_name, mask, NULL);
       break;
     case PRAGMA_OMP_SIMD:
-      stmt = cp_parser_omp_simd (parser, pragma_tok);
+      strcpy (p_name, "#pragma omp");
+      stmt = cp_parser_omp_simd (parser, pragma_tok, p_name, mask, NULL);
       break;
     case PRAGMA_OMP_SINGLE:
       stmt = cp_parser_omp_single (parser, pragma_tok);
@@ -29422,7 +29596,8 @@ cp_parser_omp_construct (cp_parser *pars
       cp_parser_omp_taskgroup (parser, pragma_tok);
       return;
     case PRAGMA_OMP_TEAMS:
-      stmt = cp_parser_omp_teams (parser, pragma_tok);
+      strcpy (p_name, "#pragma omp");
+      stmt = cp_parser_omp_teams (parser, pragma_tok, p_name, mask, NULL);
       break;
     default:
       gcc_unreachable ();
--- gcc/cp/pt.c.jj	2013-06-12 14:59:07.000000000 +0200
+++ gcc/cp/pt.c	2013-06-14 17:45:22.066675980 +0200
@@ -13293,19 +13293,22 @@ tsubst_expr (tree t, tree args, tsubst_f
 
     case OMP_FOR:
     case OMP_SIMD:
-    case OMP_FOR_SIMD:
     case OMP_DISTRIBUTE:
       {
 	tree clauses, body, pre_body;
-	tree declv, initv, condv, incrv;
+	tree declv = NULL_TREE, initv = NULL_TREE, condv = NULL_TREE;
+	tree incrv = NULL_TREE;
 	int i;
 
 	clauses = tsubst_omp_clauses (OMP_FOR_CLAUSES (t), false,
 				      args, complain, in_decl);
-	declv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t)));
-	initv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t)));
-	condv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t)));
-	incrv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t)));
+	if (OMP_FOR_INIT (t) != NULL_TREE)
+	  {
+	    declv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t)));
+	    initv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t)));
+	    condv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t)));
+	    incrv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t)));
+	  }
 
 	stmt = begin_omp_structured_block ();
 
@@ -13313,17 +13316,29 @@ tsubst_expr (tree t, tree args, tsubst_f
 	RECUR (OMP_FOR_PRE_BODY (t));
 	pre_body = pop_stmt_list (pre_body);
 
-	for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (t)); i++)
-	  tsubst_omp_for_iterator (t, i, declv, initv, condv, incrv,
-				   &clauses, args, complain, in_decl,
-				   integral_constant_expression_p);
+	if (OMP_FOR_INIT (t) != NULL_TREE)
+	  for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (t)); i++)
+	    tsubst_omp_for_iterator (t, i, declv, initv, condv, incrv,
+				     &clauses, args, complain, in_decl,
+				     integral_constant_expression_p);
 
 	body = push_stmt_list ();
 	RECUR (OMP_FOR_BODY (t));
 	body = pop_stmt_list (body);
 
-	t = finish_omp_for (EXPR_LOCATION (t), TREE_CODE (t), declv, initv,
-			    condv, incrv, body, pre_body, clauses);
+	if (OMP_FOR_INIT (t) != NULL_TREE)
+	  t = finish_omp_for (EXPR_LOCATION (t), TREE_CODE (t), declv, initv,
+			      condv, incrv, body, pre_body, clauses);
+	else
+	  {
+	    t = make_node (TREE_CODE (t));
+	    TREE_TYPE (t) = void_type_node;
+	    OMP_FOR_BODY (t) = body;
+	    OMP_FOR_PRE_BODY (t) = pre_body;
+	    OMP_FOR_CLAUSES (t) = clauses;
+	    SET_EXPR_LOCATION (t, EXPR_LOCATION (t));
+	    add_stmt (t);
+	  }
 
 	add_stmt (finish_omp_structured_block (stmt));
       }
--- gcc/cp/semantics.c.jj	2013-06-12 15:00:11.000000000 +0200
+++ gcc/cp/semantics.c	2013-06-14 12:09:18.287394537 +0200
@@ -5760,11 +5782,10 @@ finish_omp_for (location_t locus, enum t
 
       if (CLASS_TYPE_P (TREE_TYPE (decl)))
 	{
-	  if (code == OMP_SIMD || code == OMP_FOR_SIMD)
+	  if (code == OMP_SIMD)
 	    {
-	      error_at (elocus, "%<#pragma omp%s simd%> used with class "
-				"iteration variable %qE",
-			code == OMP_FOR_SIMD ? " for" : "", decl);
+	      error_at (elocus, "%<#pragma omp simd%> used with class "
+				"iteration variable %qE", decl);
 	      return NULL;
 	    }
 	  if (handle_omp_for_class_iterator (i, locus, declv, initv, condv,
--- gcc/cp/cp-tree.h.jj	2013-05-29 10:05:42.000000000 +0200
+++ gcc/cp/cp-tree.h	2013-06-13 12:26:37.480571572 +0200
@@ -60,8 +60,7 @@ c-common.h, not after.
       STMT_EXPR_NO_SCOPE (in STMT_EXPR)
       BIND_EXPR_TRY_BLOCK (in BIND_EXPR)
       TYPENAME_IS_ENUM_P (in TYPENAME_TYPE)
-      OMP_FOR_GIMPLIFYING_P (in OMP_FOR, OMP_SIMD, OMP_FOR_SIMD
-			     and OMP_DISTRIBUTE)
+      OMP_FOR_GIMPLIFYING_P (in OMP_FOR, OMP_SIMD and OMP_DISTRIBUTE)
       BASELINK_QUALIFIED_P (in BASELINK)
       TARGET_EXPR_IMPLICIT_P (in TARGET_EXPR)
       TEMPLATE_PARM_PARAMETER_PACK (in TEMPLATE_PARM_INDEX)
--- gcc/cp/cp-gimplify.c.jj	2013-05-13 16:38:25.000000000 +0200
+++ gcc/cp/cp-gimplify.c	2013-06-14 12:09:18.290395129 +0200
@@ -670,7 +670,6 @@ cp_gimplify_expr (tree *expr_p, gimple_s
 
     case OMP_FOR:
     case OMP_SIMD:
-    case OMP_FOR_SIMD:
     case OMP_DISTRIBUTE:
       ret = cp_gimplify_omp_for (expr_p, pre_p);
       break;
@@ -1121,7 +1120,6 @@ cp_genericize_r (tree *stmt_p, int *walk
     genericize_break_stmt (stmt_p);
   else if (TREE_CODE (stmt) == OMP_FOR
 	   || TREE_CODE (stmt) == OMP_SIMD
-	   || TREE_CODE (stmt) == OMP_FOR_SIMD
 	   || TREE_CODE (stmt) == OMP_DISTRIBUTE)
     genericize_omp_for_stmt (stmt_p, walk_subtrees, data);
   else if (TREE_CODE (stmt) == SIZEOF_EXPR)
--- gcc/gimple.h.jj	2013-05-27 09:22:21.000000000 +0200
+++ gcc/gimple.h	2013-06-14 16:27:40.920798468 +0200
@@ -113,8 +113,8 @@ enum gf_mask {
     GF_OMP_FOR_KIND_MASK	= 3 << 0,
     GF_OMP_FOR_KIND_FOR		= 0 << 0,
     GF_OMP_FOR_KIND_SIMD	= 1 << 0,
-    GF_OMP_FOR_KIND_FOR_SIMD	= 2 << 0,
-    GF_OMP_FOR_KIND_DISTRIBUTE	= 3 << 0,
+    GF_OMP_FOR_KIND_DISTRIBUTE	= 2 << 0,
+    GF_OMP_FOR_COMBINED		= 4 << 0,
     GF_OMP_TARGET_KIND_MASK	= 3 << 0,
     GF_OMP_TARGET_KIND_REGION	= 0 << 0,
     GF_OMP_TARGET_KIND_DATA	= 1 << 0,
@@ -4003,6 +4003,31 @@ gimple_omp_for_set_kind (gimple g, int k
 }
 
 
+/* Return true if OMP for statement G has the
+   GF_OMP_FOR_COMBINED flag set.  */
+
+static inline bool
+gimple_omp_for_combined_p (const_gimple g)
+{
+  GIMPLE_CHECK (g, GIMPLE_OMP_FOR);
+  return (gimple_omp_subcode (g) & GF_OMP_FOR_COMBINED) != 0;
+}
+
+
+/* Set the GF_OMP_FOR_COMBINED field in G depending on the boolean
+   value of COMBINED_P.  */
+
+static inline void
+gimple_omp_for_set_combined_p (gimple g, bool combined_p)
+{
+  GIMPLE_CHECK (g, GIMPLE_OMP_FOR);
+  if (combined_p)
+    g->gsbase.subcode |= GF_OMP_FOR_COMBINED;
+  else
+    g->gsbase.subcode &= ~GF_OMP_FOR_COMBINED;
+}
+
+
 /* Return the clauses associated with OMP_FOR GS.  */
 
 static inline tree
--- gcc/gimplify.c.jj	2013-06-12 14:59:07.000000000 +0200
+++ gcc/gimplify.c	2013-06-14 16:33:31.877024772 +0200
@@ -4716,7 +4716,6 @@ is_gimple_stmt (tree t)
     case OMP_PARALLEL:
     case OMP_FOR:
     case OMP_SIMD:
-    case OMP_FOR_SIMD:
     case OMP_DISTRIBUTE:
     case OMP_SECTIONS:
     case OMP_SECTION:
@@ -6826,12 +6825,39 @@ gimplify_omp_task (tree *expr_p, gimple_
   *expr_p = NULL_TREE;
 }
 
+/* Helper function of gimplify_omp_for, find OMP_FOR resp. OMP_SIMD
+   with non-NULL OMP_FOR_INIT.  */
+
+static tree
+find_combined_omp_for (tree *tp, int *walk_subtrees, void *)
+{
+  *walk_subtrees = 0;
+  switch (TREE_CODE (*tp))
+    {
+    case OMP_FOR:
+      *walk_subtrees = 1;
+      /* FALLTHRU */
+    case OMP_SIMD:
+      if (OMP_FOR_INIT (*tp) != NULL_TREE)
+	return *tp;
+      break;
+    case BIND_EXPR:
+    case STATEMENT_LIST:
+    case OMP_PARALLEL:
+      *walk_subtrees = 1;
+      break;
+    default:
+      break;
+    }
+  return NULL_TREE;
+}
+
 /* Gimplify the gross structure of an OMP_FOR statement.  */
 
 static enum gimplify_status
 gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
 {
-  tree for_stmt, decl, var, t;
+  tree for_stmt, orig_for_stmt, decl, var, t;
   enum gimplify_status ret = GS_ALL_DONE;
   enum gimplify_status tret;
   gimple gfor;
@@ -6840,10 +6866,9 @@ gimplify_omp_for (tree *expr_p, gimple_s
   bool simd;
   bitmap has_decl_expr = NULL;
 
-  for_stmt = *expr_p;
+  orig_for_stmt = for_stmt = *expr_p;
 
-  simd = TREE_CODE (for_stmt) == OMP_SIMD
-	 || TREE_CODE (for_stmt) == OMP_FOR_SIMD;
+  simd = TREE_CODE (for_stmt) == OMP_SIMD;
   gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p,
 			     TREE_CODE (for_stmt) == OMP_SIMD
 			     ? ORT_SIMD : ORT_WORKSHARE);
@@ -6876,6 +6901,13 @@ gimplify_omp_for (tree *expr_p, gimple_s
   gimplify_and_add (OMP_FOR_PRE_BODY (for_stmt), &for_pre_body);
   OMP_FOR_PRE_BODY (for_stmt) = NULL_TREE;
 
+  if (OMP_FOR_INIT (for_stmt) == NULL_TREE)
+    {
+      for_stmt = walk_tree (&OMP_FOR_BODY (for_stmt), find_combined_omp_for,
+			    NULL, NULL);
+      gcc_assert (for_stmt != NULL_TREE);
+    }
+
   for_body = NULL;
   gcc_assert (TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt))
 	      == TREE_VEC_LENGTH (OMP_FOR_COND (for_stmt)));
@@ -6891,12 +6923,14 @@ gimplify_omp_for (tree *expr_p, gimple_s
 		  || POINTER_TYPE_P (TREE_TYPE (decl)));
 
       /* Make sure the iteration variable is private.  */
-      bool is_private = omp_is_private (gimplify_omp_ctxp, decl, simd);
       tree c = NULL_TREE;
-      if (simd)
+      if (orig_for_stmt != for_stmt)
+	/* Do this only on innermost construct for combined ones.  */;
+      else if (simd)
 	{
 	  splay_tree_node n = splay_tree_lookup (gimplify_omp_ctxp->variables,
 						 (splay_tree_key)decl);
+	  omp_is_private (gimplify_omp_ctxp, decl, simd);
 	  if (n != NULL && (n->value & GOVD_DATA_SHARE_CLASS) != 0)
 	    omp_notice_variable (gimplify_omp_ctxp, decl, true);
 	  else
@@ -6913,7 +6947,7 @@ gimplify_omp_for (tree *expr_p, gimple_s
 				GOVD_LINEAR | GOVD_EXPLICIT | GOVD_SEEN);
 	    }
 	}
-      else if (is_private)
+      else if (omp_is_private (gimplify_omp_ctxp, decl, simd))
 	omp_notice_variable (gimplify_omp_ctxp, decl, true);
       else
 	omp_add_variable (gimplify_omp_ctxp, decl, GOVD_PRIVATE | GOVD_SEEN);
@@ -6921,7 +6955,9 @@ gimplify_omp_for (tree *expr_p, gimple_s
       /* If DECL is not a gimple register, create a temporary variable to act
 	 as an iteration counter.  This is valid, since DECL cannot be
 	 modified in the body of the loop.  */
-      if (!is_gimple_reg (decl))
+      if (orig_for_stmt != for_stmt)
+	var = decl;
+      else if (!is_gimple_reg (decl))
 	{
 	  var = create_tmp_var (TREE_TYPE (decl), get_name (decl));
 	  TREE_OPERAND (t, 0) = var;
@@ -6954,6 +6990,8 @@ gimplify_omp_for (tree *expr_p, gimple_s
 	{
 	case PREINCREMENT_EXPR:
 	case POSTINCREMENT_EXPR:
+	  if (orig_for_stmt != for_stmt)
+	    break;
 	  t = build_int_cst (TREE_TYPE (decl), 1);
 	  if (c)
 	    OMP_CLAUSE_LINEAR_STEP (c) = t;
@@ -6964,6 +7002,8 @@ gimplify_omp_for (tree *expr_p, gimple_s
 
 	case PREDECREMENT_EXPR:
 	case POSTDECREMENT_EXPR:
+	  if (orig_for_stmt != for_stmt)
+	    break;
 	  t = build_int_cst (TREE_TYPE (decl), -1);
 	  if (c)
 	    OMP_CLAUSE_LINEAR_STEP (c) = t;
@@ -7020,7 +7060,8 @@ gimplify_omp_for (tree *expr_p, gimple_s
 	  gcc_unreachable ();
 	}
 
-      if (var != decl || TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) > 1)
+      if ((var != decl || TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) > 1)
+	  && orig_for_stmt == for_stmt)
 	{
 	  for (c = OMP_FOR_CLAUSES (for_stmt); c ; c = OMP_CLAUSE_CHAIN (c))
 	    if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
@@ -7045,23 +7086,37 @@ gimplify_omp_for (tree *expr_p, gimple_s
 
   BITMAP_FREE (has_decl_expr);
 
-  gimplify_and_add (OMP_FOR_BODY (for_stmt), &for_body);
+  gimplify_and_add (OMP_FOR_BODY (orig_for_stmt), &for_body);
+
+  if (orig_for_stmt != for_stmt)
+    for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++)
+      {
+	t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i);
+	decl = TREE_OPERAND (t, 0);
+	var = create_tmp_var (TREE_TYPE (decl), get_name (decl));
+	omp_add_variable (gimplify_omp_ctxp, var, GOVD_PRIVATE | GOVD_SEEN);
+	TREE_OPERAND (t, 0) = var;
+	t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i);
+	TREE_OPERAND (t, 1) = copy_node (TREE_OPERAND (t, 1));
+	TREE_OPERAND (TREE_OPERAND (t, 1), 0) = var;
+      }
 
-  gimplify_adjust_omp_clauses (&OMP_FOR_CLAUSES (for_stmt));
+  gimplify_adjust_omp_clauses (&OMP_FOR_CLAUSES (orig_for_stmt));
 
   int kind;
-  switch (TREE_CODE (for_stmt))
+  switch (TREE_CODE (orig_for_stmt))
     {
     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),
+  gfor = gimple_build_omp_for (for_body, kind, OMP_FOR_CLAUSES (orig_for_stmt),
 			       TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)),
 			       for_pre_body);
+  if (orig_for_stmt != for_stmt)
+    gimple_omp_for_set_combined_p (gfor, true);
 
   for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++)
     {
@@ -8057,7 +8112,6 @@ gimplify_expr (tree *expr_p, gimple_seq
 
 	case OMP_FOR:
 	case OMP_SIMD:
-	case OMP_FOR_SIMD:
 	case OMP_DISTRIBUTE:
 	  ret = gimplify_omp_for (expr_p, pre_p);
 	  break;
--- gcc/Makefile.in.jj	2013-06-12 11:53:15.000000000 +0200
+++ gcc/Makefile.in	2013-06-12 11:53:15.000000000 +0200
@@ -1976,7 +1976,7 @@ c-family/c-lex.o : c-family/c-lex.c $(CO
 	$(CPPLIB_H) $(TARGET_H) $(TIMEVAR_H)
 
 c-family/c-omp.o : c-family/c-omp.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
-	$(TREE_H) $(C_COMMON_H) $(GIMPLE_H) langhooks.h
+	$(TREE_H) $(C_COMMON_H) $(C_PRAGMA_H) $(GIMPLE_H) langhooks.h
 
 CFLAGS-c-family/c-opts.o += @TARGET_SYSTEM_ROOT_DEFINE@
 c-family/c-opts.o : c-family/c-opts.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
--- gcc/omp-low.c.jj	2013-06-12 11:53:14.000000000 +0200
+++ gcc/omp-low.c	2013-06-14 16:19:10.595129024 +0200
@@ -938,17 +938,25 @@ build_outer_var_ref (tree var, omp_conte
       bool by_ref = use_pointer_for_field (var, NULL);
       x = build_receiver_ref (var, by_ref, ctx);
     }
+  else if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR
+	   && gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD)
+    {
+      /* #pragma omp simd isn't a worksharing construct, and can reference even
+	 private vars in its linear etc. clauses.  */
+      x = NULL_TREE;
+      if (ctx->outer && is_taskreg_ctx (ctx))
+	x = lookup_decl (var, ctx->outer);
+      else if (ctx->outer)
+	x = maybe_lookup_decl (var, ctx->outer);
+      if (x == NULL_TREE)
+	x = var;
+    }
   else if (ctx->outer)
     x = lookup_decl (var, ctx->outer);
   else if (is_reference (var))
     /* This can happen with orphaned constructs.  If var is reference, it is
        possible it is shared and as such valid.  */
     x = var;
-  else if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR
-	   && gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD)
-    /* #pragma omp simd isn't a worksharing construct, and can reference even
-       private vars in its linear etc. clauses.  */
-    x = var;
   else
     gcc_unreachable ();
 
@@ -1877,8 +1885,7 @@ check_omp_nesting_restrictions (gimple s
   if (ctx != NULL)
     {
       if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR
-	  && (gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD
-	      || gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_FOR_SIMD))
+	  && gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD)
 	{
 	  error_at (gimple_location (stmt),
 		    "OpenMP constructs may not be nested inside simd region");
--- gcc/tree.def.jj	2013-05-27 09:22:21.000000000 +0200
+++ gcc/tree.def	2013-06-13 11:55:43.242627832 +0200
@@ -1034,10 +1034,6 @@ DEFTREECODE (OMP_FOR, "omp_for", tcc_sta
    Operands like for OMP_FOR.  */
 DEFTREECODE (OMP_SIMD, "omp_simd", tcc_statement, 6)
 
-/* OpenMP - #pragma omp for simd [clause1 ... clauseN]
-   Operands like for OMP_FOR.  */
-DEFTREECODE (OMP_FOR_SIMD, "omp_for_simd", tcc_statement, 6)
-
 /* OpenMP - #pragma omp distribute [clause1 ... clauseN]
    Operands like for OMP_FOR.  */
 DEFTREECODE (OMP_DISTRIBUTE, "omp_distribute", tcc_statement, 6)
--- gcc/tree-pretty-print.c.jj	2013-06-12 14:59:07.000000000 +0200
+++ gcc/tree-pretty-print.c	2013-06-14 13:31:19.236871998 +0200
@@ -2364,10 +2364,6 @@ dump_generic_node (pretty_printer *buffe
       pp_string (buffer, "#pragma omp simd");
       goto dump_omp_loop;
 
-    case OMP_FOR_SIMD:
-      pp_string (buffer, "#pragma omp for simd");
-      goto dump_omp_loop;
-
     case OMP_DISTRIBUTE:
       pp_string (buffer, "#pragma omp distribute");
       goto dump_omp_loop;
@@ -2409,21 +2405,27 @@ dump_generic_node (pretty_printer *buffe
 	      dump_generic_node (buffer, OMP_FOR_PRE_BODY (node),
 		  spc, flags, false);
 	    }
-	  spc -= 2;
-	  for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (node)); i++)
+	  if (OMP_FOR_INIT (node))
 	    {
-	      spc += 2;
-	      newline_and_indent (buffer, spc);
-	      pp_string (buffer, "for (");
-	      dump_generic_node (buffer, TREE_VEC_ELT (OMP_FOR_INIT (node), i),
-				 spc, flags, false);
-	      pp_string (buffer, "; ");
-	      dump_generic_node (buffer, TREE_VEC_ELT (OMP_FOR_COND (node), i),
-				 spc, flags, false);
-	      pp_string (buffer, "; ");
-	      dump_generic_node (buffer, TREE_VEC_ELT (OMP_FOR_INCR (node), i),
-				 spc, flags, false);
-	      pp_string (buffer, ")");
+	      spc -= 2;
+	      for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (node)); i++)
+		{
+		  spc += 2;
+		  newline_and_indent (buffer, spc);
+		  pp_string (buffer, "for (");
+		  dump_generic_node (buffer,
+				     TREE_VEC_ELT (OMP_FOR_INIT (node), i),
+				     spc, flags, false);
+		  pp_string (buffer, "; ");
+		  dump_generic_node (buffer,
+				     TREE_VEC_ELT (OMP_FOR_COND (node), i),
+				     spc, flags, false);
+		  pp_string (buffer, "; ");
+		  dump_generic_node (buffer,
+				     TREE_VEC_ELT (OMP_FOR_INCR (node), i),
+				     spc, flags, false);
+		  pp_string (buffer, ")");
+		}
 	    }
 	  if (OMP_FOR_BODY (node))
 	    {
@@ -2435,7 +2437,8 @@ dump_generic_node (pretty_printer *buffe
 	      newline_and_indent (buffer, spc + 2);
 	      pp_character (buffer, '}');
 	    }
-	  spc -= 2 * TREE_VEC_LENGTH (OMP_FOR_INIT (node)) - 2;
+	  if (OMP_FOR_INIT (node))
+	    spc -= 2 * TREE_VEC_LENGTH (OMP_FOR_INIT (node)) - 2;
 	  if (OMP_FOR_PRE_BODY (node))
 	    {
 	      spc -= 4;
--- gcc/c-family/c-common.h.jj	2013-05-09 17:06:21.000000000 +0200
+++ gcc/c-family/c-common.h	2013-06-13 18:07:18.388364356 +0200
@@ -1030,112 +1030,6 @@ extern void pp_dir_change (cpp_reader *,
 extern bool check_missing_format_attribute (tree, tree);
 
 /* In c-omp.c  */
-extern tree c_finish_omp_master (location_t, tree);
-extern tree c_finish_omp_critical (location_t, tree, tree);
-extern tree c_finish_omp_ordered (location_t, tree);
-extern void c_finish_omp_barrier (location_t);
-extern tree c_finish_omp_atomic (location_t, enum tree_code, enum tree_code,
-				 tree, tree, tree, tree, tree, bool, bool);
-extern void c_finish_omp_flush (location_t);
-extern void c_finish_omp_taskwait (location_t);
-extern void c_finish_omp_taskyield (location_t);
-extern tree c_finish_omp_for (location_t, enum tree_code, tree, tree, tree,
-			      tree, tree, tree);
-extern void c_split_parallel_clauses (location_t, tree, tree *, tree *);
-extern tree c_omp_declare_simd_clauses_to_numbers (tree, tree);
-extern void c_omp_declare_simd_clauses_to_decls (tree, tree);
-extern enum omp_clause_default_kind c_omp_predetermined_sharing (tree);
-
-/* Not in c-omp.c; provided by the front end.  */
-extern bool c_omp_sharing_predetermined (tree);
-extern tree c_omp_remap_decl (tree, bool);
-extern void record_types_used_by_current_var_decl (tree);
-
-/* Return next tree in the chain for chain_next walking of tree nodes.  */
-static inline tree
-c_tree_chain_next (tree t)
-{
-  /* TREE_CHAIN of a type is TYPE_STUB_DECL, which is different
-     kind of object, never a long chain of nodes.  Prefer
-     TYPE_NEXT_VARIANT for types.  */
-  if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_TYPE_COMMON))
-    return TYPE_NEXT_VARIANT (t);
-  /* Otherwise, if there is TREE_CHAIN, return it.  */
-  if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_COMMON))
-    return TREE_CHAIN (t);
-  return NULL;
-}
-
-/* Mask used by tm_stmt_attr.  */
-#define TM_STMT_ATTR_OUTER	2
-#define TM_STMT_ATTR_ATOMIC	4
-#define TM_STMT_ATTR_RELAXED	8
-
-extern int parse_tm_stmt_attr (tree, int);
-
-/* Mask used by tm_attr_to_mask and tm_mask_to_attr.  Note that these
-   are ordered specifically such that more restrictive attributes are
-   at lower bit positions.  This fact is known by the C++ tm attribute
-   inheritance code such that least bit extraction (mask & -mask) results
-   in the most restrictive attribute.  */
-#define TM_ATTR_SAFE			1
-#define TM_ATTR_CALLABLE		2
-#define TM_ATTR_PURE			4
-#define TM_ATTR_IRREVOCABLE		8
-#define TM_ATTR_MAY_CANCEL_OUTER	16
-
-extern int tm_attr_to_mask (tree);
-extern tree tm_mask_to_attr (int);
-extern tree find_tm_attribute (tree);
-
-/* A suffix-identifier value doublet that represents user-defined literals
-   for C++-0x.  */
-enum overflow_type {
-  OT_UNDERFLOW = -1,
-  OT_NONE,
-  OT_OVERFLOW
-};
-
-struct GTY(()) tree_userdef_literal {
-  struct tree_base base;
-  tree suffix_id;
-  tree value;
-  tree num_string;
-  enum overflow_type overflow;
-};
-
-#define USERDEF_LITERAL_SUFFIX_ID(NODE) \
-  (((struct tree_userdef_literal *)USERDEF_LITERAL_CHECK (NODE))->suffix_id)
-
-#define USERDEF_LITERAL_VALUE(NODE) \
-  (((struct tree_userdef_literal *)USERDEF_LITERAL_CHECK (NODE))->value)
-
-#define USERDEF_LITERAL_OVERFLOW(NODE) \
-  (((struct tree_userdef_literal *)USERDEF_LITERAL_CHECK (NODE))->overflow)
-
-#define USERDEF_LITERAL_NUM_STRING(NODE) \
-  (((struct tree_userdef_literal *)USERDEF_LITERAL_CHECK (NODE))->num_string)
-
-#define USERDEF_LITERAL_TYPE(NODE) \
-  (TREE_TYPE (USERDEF_LITERAL_VALUE (NODE)))
-
-extern tree build_userdef_literal (tree suffix_id, tree value,
-				   enum overflow_type overflow,
-				   tree num_string);
-
-extern void convert_vector_to_pointer_for_subscript (location_t, tree*, tree);
-
-/* Possibe cases of scalar_to_vector conversion.  */
-enum stv_conv {
-  stv_error,        /* Error occured.  */
-  stv_nothing,      /* Nothing happened.  */
-  stv_firstarg,     /* First argument must be expanded.  */
-  stv_secondarg     /* Second argument must be expanded.  */
-};
-
-extern enum stv_conv scalar_to_vector (location_t loc, enum tree_code code,
-				       tree op0, tree op1, bool);
-
 #if HOST_BITS_PER_WIDE_INT >= 64
 typedef unsigned HOST_WIDE_INT omp_clause_mask;
 # define OMP_CLAUSE_MASK_1 ((omp_clause_mask) 1)
@@ -1261,4 +1155,123 @@ omp_clause_mask::operator == (omp_clause
 # define OMP_CLAUSE_MASK_1 omp_clause_mask (1)
 #endif
 
+enum c_omp_clause_split
+{
+  C_OMP_CLAUSE_SPLIT_TARGET = 0,
+  C_OMP_CLAUSE_SPLIT_TEAMS,
+  C_OMP_CLAUSE_SPLIT_DISTRIBUTE,
+  C_OMP_CLAUSE_SPLIT_PARALLEL,
+  C_OMP_CLAUSE_SPLIT_FOR,
+  C_OMP_CLAUSE_SPLIT_SIMD,
+  C_OMP_CLAUSE_SPLIT_COUNT,
+  C_OMP_CLAUSE_SPLIT_SECTIONS = C_OMP_CLAUSE_SPLIT_FOR
+};
+
+extern tree c_finish_omp_master (location_t, tree);
+extern tree c_finish_omp_critical (location_t, tree, tree);
+extern tree c_finish_omp_ordered (location_t, tree);
+extern void c_finish_omp_barrier (location_t);
+extern tree c_finish_omp_atomic (location_t, enum tree_code, enum tree_code,
+				 tree, tree, tree, tree, tree, bool, bool);
+extern void c_finish_omp_flush (location_t);
+extern void c_finish_omp_taskwait (location_t);
+extern void c_finish_omp_taskyield (location_t);
+extern tree c_finish_omp_for (location_t, enum tree_code, tree, tree, tree,
+			      tree, tree, tree);
+extern void c_omp_split_clauses (location_t, enum tree_code, omp_clause_mask,
+				 tree, tree *);
+extern tree c_omp_declare_simd_clauses_to_numbers (tree, tree);
+extern void c_omp_declare_simd_clauses_to_decls (tree, tree);
+extern enum omp_clause_default_kind c_omp_predetermined_sharing (tree);
+
+/* Not in c-omp.c; provided by the front end.  */
+extern bool c_omp_sharing_predetermined (tree);
+extern tree c_omp_remap_decl (tree, bool);
+extern void record_types_used_by_current_var_decl (tree);
+
+/* Return next tree in the chain for chain_next walking of tree nodes.  */
+static inline tree
+c_tree_chain_next (tree t)
+{
+  /* TREE_CHAIN of a type is TYPE_STUB_DECL, which is different
+     kind of object, never a long chain of nodes.  Prefer
+     TYPE_NEXT_VARIANT for types.  */
+  if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_TYPE_COMMON))
+    return TYPE_NEXT_VARIANT (t);
+  /* Otherwise, if there is TREE_CHAIN, return it.  */
+  if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_COMMON))
+    return TREE_CHAIN (t);
+  return NULL;
+}
+
+/* Mask used by tm_stmt_attr.  */
+#define TM_STMT_ATTR_OUTER	2
+#define TM_STMT_ATTR_ATOMIC	4
+#define TM_STMT_ATTR_RELAXED	8
+
+extern int parse_tm_stmt_attr (tree, int);
+
+/* Mask used by tm_attr_to_mask and tm_mask_to_attr.  Note that these
+   are ordered specifically such that more restrictive attributes are
+   at lower bit positions.  This fact is known by the C++ tm attribute
+   inheritance code such that least bit extraction (mask & -mask) results
+   in the most restrictive attribute.  */
+#define TM_ATTR_SAFE			1
+#define TM_ATTR_CALLABLE		2
+#define TM_ATTR_PURE			4
+#define TM_ATTR_IRREVOCABLE		8
+#define TM_ATTR_MAY_CANCEL_OUTER	16
+
+extern int tm_attr_to_mask (tree);
+extern tree tm_mask_to_attr (int);
+extern tree find_tm_attribute (tree);
+
+/* A suffix-identifier value doublet that represents user-defined literals
+   for C++-0x.  */
+enum overflow_type {
+  OT_UNDERFLOW = -1,
+  OT_NONE,
+  OT_OVERFLOW
+};
+
+struct GTY(()) tree_userdef_literal {
+  struct tree_base base;
+  tree suffix_id;
+  tree value;
+  tree num_string;
+  enum overflow_type overflow;
+};
+
+#define USERDEF_LITERAL_SUFFIX_ID(NODE) \
+  (((struct tree_userdef_literal *)USERDEF_LITERAL_CHECK (NODE))->suffix_id)
+
+#define USERDEF_LITERAL_VALUE(NODE) \
+  (((struct tree_userdef_literal *)USERDEF_LITERAL_CHECK (NODE))->value)
+
+#define USERDEF_LITERAL_OVERFLOW(NODE) \
+  (((struct tree_userdef_literal *)USERDEF_LITERAL_CHECK (NODE))->overflow)
+
+#define USERDEF_LITERAL_NUM_STRING(NODE) \
+  (((struct tree_userdef_literal *)USERDEF_LITERAL_CHECK (NODE))->num_string)
+
+#define USERDEF_LITERAL_TYPE(NODE) \
+  (TREE_TYPE (USERDEF_LITERAL_VALUE (NODE)))
+
+extern tree build_userdef_literal (tree suffix_id, tree value,
+				   enum overflow_type overflow,
+				   tree num_string);
+
+extern void convert_vector_to_pointer_for_subscript (location_t, tree*, tree);
+
+/* Possibe cases of scalar_to_vector conversion.  */
+enum stv_conv {
+  stv_error,        /* Error occured.  */
+  stv_nothing,      /* Nothing happened.  */
+  stv_firstarg,     /* First argument must be expanded.  */
+  stv_secondarg     /* Second argument must be expanded.  */
+};
+
+extern enum stv_conv scalar_to_vector (location_t loc, enum tree_code code,
+				       tree op0, tree op1, bool);
+
 #endif /* ! GCC_C_COMMON_H */
--- gcc/c-family/c-pragma.h.jj	2013-06-12 14:59:07.000000000 +0200
+++ gcc/c-family/c-pragma.h	2013-06-13 12:06:51.105442359 +0200
@@ -36,6 +36,9 @@ typedef enum pragma_kind {
   PRAGMA_OMP_DECLARE_SIMD,
   PRAGMA_OMP_DECLARE_TARGET,
   PRAGMA_OMP_DISTRIBUTE,
+  PRAGMA_OMP_DISTRIBUTE_PARALLEL_FOR,
+  PRAGMA_OMP_DISTRIBUTE_PARALLEL_FOR_SIMD,
+  PRAGMA_OMP_DISTRIBUTE_SIMD,
   PRAGMA_OMP_END_DECLARE_TARGET,
   PRAGMA_OMP_FLUSH,
   PRAGMA_OMP_FOR,
@@ -52,6 +55,10 @@ typedef enum pragma_kind {
   PRAGMA_OMP_SINGLE,
   PRAGMA_OMP_TARGET,
   PRAGMA_OMP_TARGET_DATA,
+  PRAGMA_OMP_TARGET_TEAMS,
+  PRAGMA_OMP_TARGET_TEAMS_DISTRIBUTE,
+  PRAGMA_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR,
+  PRAGMA_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD,
   PRAGMA_OMP_TARGET_UPDATE,
   PRAGMA_OMP_TASK,
   PRAGMA_OMP_TASKGROUP,
@@ -59,6 +66,9 @@ typedef enum pragma_kind {
   PRAGMA_OMP_TASKYIELD,
   PRAGMA_OMP_THREADPRIVATE,
   PRAGMA_OMP_TEAMS,
+  PRAGMA_OMP_TEAMS_DISTRIBUTE,
+  PRAGMA_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR,
+  PRAGMA_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD,
 
   PRAGMA_GCC_PCH_PREPROCESS,
 
--- gcc/c-family/c-omp.c.jj	2013-05-09 17:06:21.000000000 +0200
+++ gcc/c-family/c-omp.c	2013-06-14 12:43:47.381336138 +0200
@@ -26,6 +26,7 @@ along with GCC; see the file COPYING3.
 #include "coretypes.h"
 #include "tree.h"
 #include "c-common.h"
+#include "c-pragma.h"
 #include "gimple.h"		/* For create_tmp_var_raw.  */
 #include "langhooks.h"
 
@@ -585,21 +586,55 @@ c_finish_omp_for (location_t locus, enum
     }
 }
 
-
-/* Divide CLAUSES into two lists: those that apply to a parallel
-   construct, and those that apply to a work-sharing construct.  Place
-   the results in *PAR_CLAUSES and *WS_CLAUSES respectively.  In
-   addition, add a nowait clause to the work-sharing list.  LOC is the
-   location of the OMP_PARALLEL*.  */
+/* Right now we have 14 different combined constructs, this
+   function attempts to split or duplicate clauses for combined
+   constructs.  CODE is the innermost construct in the combined construct,
+   and MASK allows to determine which constructs are combined together,
+   as every construct has at least one clause that no other construct
+   has (except for OMP_SECTIONS, but that can be only combined with parallel).
+   Combined constructs are:
+   #pragma omp parallel for
+   #pragma omp parallel sections
+   #pragma omp parallel for simd
+   #pragma omp for simd
+   #pragma omp distribute simd
+   #pragma omp distribute parallel for
+   #pragma omp distribute parallel for simd
+   #pragma omp teams distribute
+   #pragma omp teams distribute parallel for
+   #pragma omp teams distribute parallel for simd
+   #pragma omp target teams
+   #pragma omp target teams distribute
+   #pragma omp target teams distribute parallel for
+   #pragma omp target teams distribute parallel for simd  */
 
 void
-c_split_parallel_clauses (location_t loc, tree clauses,
-			  tree *par_clauses, tree *ws_clauses)
+c_omp_split_clauses (location_t loc, enum tree_code code,
+		     omp_clause_mask mask, tree clauses, tree *cclauses)
 {
-  tree next;
+  tree next, c;
+  enum c_omp_clause_split s;
+  int i;
 
-  *par_clauses = NULL;
-  *ws_clauses = build_omp_clause (loc, OMP_CLAUSE_NOWAIT);
+  for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++)
+    cclauses[i] = NULL;
+  /* Add implicit nowait clause on
+     #pragma omp parallel {for,for simd,sections}.  */
+  if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS))
+    switch (code)
+      {
+      case OMP_FOR:
+      case OMP_SIMD:
+        cclauses[C_OMP_CLAUSE_SPLIT_FOR]
+	  = build_omp_clause (loc, OMP_CLAUSE_NOWAIT);
+	break;
+      case OMP_SECTIONS:
+	cclauses[C_OMP_CLAUSE_SPLIT_SECTIONS]
+	  = build_omp_clause (loc, OMP_CLAUSE_NOWAIT);
+	break;
+      default:
+	break;
+      }
 
   for (; clauses ; clauses = next)
     {
@@ -607,36 +642,228 @@ c_split_parallel_clauses (location_t loc
 
       switch (OMP_CLAUSE_CODE (clauses))
 	{
-	case OMP_CLAUSE_PRIVATE:
-	case OMP_CLAUSE_SHARED:
-	case OMP_CLAUSE_FIRSTPRIVATE:
-	case OMP_CLAUSE_LASTPRIVATE:
-	case OMP_CLAUSE_REDUCTION:
+	/* First the clauses that are unique to some constructs.  */
+	case OMP_CLAUSE_DEVICE:
+	case OMP_CLAUSE_MAP:
+	  s = C_OMP_CLAUSE_SPLIT_TARGET;
+	  break;
+	case OMP_CLAUSE_NUM_TEAMS:
+	case OMP_CLAUSE_THREAD_LIMIT:
+	  s = C_OMP_CLAUSE_SPLIT_TEAMS;
+	  break;
+	case OMP_CLAUSE_DIST_SCHEDULE:
+	  s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE;
+	  break;
 	case OMP_CLAUSE_COPYIN:
-	case OMP_CLAUSE_IF:
 	case OMP_CLAUSE_NUM_THREADS:
-	case OMP_CLAUSE_DEFAULT:
 	case OMP_CLAUSE_PROC_BIND:
-	  OMP_CLAUSE_CHAIN (clauses) = *par_clauses;
-	  *par_clauses = clauses;
+	  s = C_OMP_CLAUSE_SPLIT_PARALLEL;
 	  break;
-
-	case OMP_CLAUSE_SCHEDULE:
 	case OMP_CLAUSE_ORDERED:
-	case OMP_CLAUSE_COLLAPSE:
+	case OMP_CLAUSE_SCHEDULE:
+	case OMP_CLAUSE_NOWAIT:
+	  s = C_OMP_CLAUSE_SPLIT_FOR;
+	  break;
 	case OMP_CLAUSE_SAFELEN:
-	case OMP_CLAUSE_ALIGNED:
 	case OMP_CLAUSE_LINEAR:
-	  OMP_CLAUSE_CHAIN (clauses) = *ws_clauses;
-	  *ws_clauses = clauses;
+	case OMP_CLAUSE_ALIGNED:
+	  s = C_OMP_CLAUSE_SPLIT_SIMD;
+	  break;
+	/* Duplicate this to all of distribute, for and simd.  */
+	case OMP_CLAUSE_COLLAPSE:
+	  if (code == OMP_SIMD)
+	    {
+	      c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses),
+				    OMP_CLAUSE_COLLAPSE);
+	      OMP_CLAUSE_COLLAPSE_EXPR (c)
+		= OMP_CLAUSE_COLLAPSE_EXPR (clauses);
+	      OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_SIMD];
+	      cclauses[C_OMP_CLAUSE_SPLIT_SIMD] = c;
+	    }
+	  if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS))
+	    {
+	      if (mask & (OMP_CLAUSE_MASK_1
+			  << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE))
+		{
+		  c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses),
+					OMP_CLAUSE_COLLAPSE);
+		  OMP_CLAUSE_COLLAPSE_EXPR (c)
+		    = OMP_CLAUSE_COLLAPSE_EXPR (clauses);
+		  OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_FOR];
+		  cclauses[C_OMP_CLAUSE_SPLIT_FOR] = c;
+		  s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE;
+		}
+	      else
+		s = C_OMP_CLAUSE_SPLIT_FOR;
+	    }
+	  else
+	    s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE;
+	  break;
+	/* Private clause is supported on all constructs but target,
+	   it is enough to put it on the innermost one.  For
+	   #pragma omp {for,sections} put it on parallel though,
+	   as that's what we did for OpenMP 3.1.  */
+	case OMP_CLAUSE_PRIVATE:
+	  switch (code)
+	    {
+	    case OMP_SIMD: s = C_OMP_CLAUSE_SPLIT_SIMD; break;
+	    case OMP_FOR: case OMP_SECTIONS:
+	    case OMP_PARALLEL: s = C_OMP_CLAUSE_SPLIT_PARALLEL; break;
+	    case OMP_DISTRIBUTE: s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE; break;
+	    case OMP_TEAMS: s = C_OMP_CLAUSE_SPLIT_TEAMS; break;
+	    default: gcc_unreachable ();
+	    }
+	  break;
+	/* Firstprivate clause is supported on all constructs but
+	   target and simd.  Put it on the outermost of those and
+	   duplicate on parallel.  */
+	case OMP_CLAUSE_FIRSTPRIVATE:
+	  if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS))
+	    {
+	      if (mask & ((OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS)
+			  | (OMP_CLAUSE_MASK_1
+			     << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)))
+		{
+		  c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses),
+					OMP_CLAUSE_FIRSTPRIVATE);
+		  OMP_CLAUSE_DECL (c) = OMP_CLAUSE_DECL (clauses);
+		  OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL];
+		  cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] = c;
+		  if (mask & (OMP_CLAUSE_MASK_1
+			      << PRAGMA_OMP_CLAUSE_NUM_TEAMS))
+		    s = C_OMP_CLAUSE_SPLIT_TEAMS;
+		  else
+		    s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE;
+		}
+	      else
+		/* This must be
+		   #pragma omp parallel{, for{, simd}, sections}.  */
+		s = C_OMP_CLAUSE_SPLIT_PARALLEL;
+	    }
+	  else if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS))
+	    {
+	      /* This must be #pragma omp {,target }teams distribute.  */
+	      gcc_assert (code == OMP_DISTRIBUTE);
+	      s = C_OMP_CLAUSE_SPLIT_TEAMS;
+	    }
+	  else if (mask & (OMP_CLAUSE_MASK_1
+			   << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE))
+	    {
+	      /* This must be #pragma omp distribute simd.  */
+	      gcc_assert (code == OMP_SIMD);
+	      s = C_OMP_CLAUSE_SPLIT_TEAMS;
+	    }
+	  else
+	    {
+	      /* This must be #pragma omp for simd.  */
+	      gcc_assert (code == OMP_SIMD);
+	      s = C_OMP_CLAUSE_SPLIT_FOR;
+	    }
+	  break;
+	/* Lastprivate is allowed on for, sections and simd.  In
+	   parallel {for{, simd},sections} we actually want to put it on
+	   parallel rather than for or sections.  */
+	case OMP_CLAUSE_LASTPRIVATE:
+	  if (code == OMP_FOR || code == OMP_SECTIONS)
+	    {
+	      if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS))
+		s = C_OMP_CLAUSE_SPLIT_PARALLEL;
+	      else
+		s = C_OMP_CLAUSE_SPLIT_FOR;
+	      break;
+	    }
+	  gcc_assert (code == OMP_SIMD);
+	  if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE))
+	    {
+	      c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses),
+				    OMP_CLAUSE_LASTPRIVATE);
+	      OMP_CLAUSE_DECL (c) = OMP_CLAUSE_DECL (clauses);
+	      if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS))
+		s = C_OMP_CLAUSE_SPLIT_PARALLEL;
+	      else
+		s = C_OMP_CLAUSE_SPLIT_FOR;
+	      OMP_CLAUSE_CHAIN (c) = cclauses[s];
+	      cclauses[s] = c;
+	    }
+	  s = C_OMP_CLAUSE_SPLIT_SIMD;
+	  break;
+	/* Shared and default clauses are allowed on private and teams.  */
+	case OMP_CLAUSE_SHARED:
+	case OMP_CLAUSE_DEFAULT:
+	  if (code == OMP_TEAMS)
+	    {
+	      s = C_OMP_CLAUSE_SPLIT_TEAMS;
+	      break;
+	    }
+	  if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS))
+	    {
+	      c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses),
+				    OMP_CLAUSE_CODE (clauses));
+	      if (OMP_CLAUSE_CODE (clauses) == OMP_CLAUSE_SHARED)
+		OMP_CLAUSE_DECL (c) = OMP_CLAUSE_DECL (clauses);
+	      else
+		OMP_CLAUSE_DEFAULT_KIND (c)
+		  = OMP_CLAUSE_DEFAULT_KIND (clauses);
+	      OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS];
+	      cclauses[C_OMP_CLAUSE_SPLIT_TEAMS] = c;
+	      
+	    }
+	  s = C_OMP_CLAUSE_SPLIT_PARALLEL;
+	  break;
+	/* Reduction is allowed on simd, for, parallel, sections and teams.
+	   Duplicate it on all of them, but omit on for or sections if
+	   parallel is present.  */
+	case OMP_CLAUSE_REDUCTION:
+	  if (code == OMP_SIMD)
+	    {
+	      c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses),
+				    OMP_CLAUSE_REDUCTION);
+	      OMP_CLAUSE_DECL (c) = OMP_CLAUSE_DECL (clauses);
+	      OMP_CLAUSE_REDUCTION_CODE (c)
+		= OMP_CLAUSE_REDUCTION_CODE (clauses);
+	      OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_SIMD];
+	      cclauses[C_OMP_CLAUSE_SPLIT_SIMD] = c;
+	    }
+	  if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE))
+	    {
+	      if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS))
+		{
+		  c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses),
+					OMP_CLAUSE_REDUCTION);
+		  OMP_CLAUSE_DECL (c) = OMP_CLAUSE_DECL (clauses);
+		  OMP_CLAUSE_REDUCTION_CODE (c)
+		    = OMP_CLAUSE_REDUCTION_CODE (clauses);
+		  OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL];
+		  cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] = c;
+		  s = C_OMP_CLAUSE_SPLIT_TEAMS;
+		}
+	      else if (mask & (OMP_CLAUSE_MASK_1
+			       << PRAGMA_OMP_CLAUSE_NUM_THREADS))
+		s = C_OMP_CLAUSE_SPLIT_PARALLEL;
+	      else
+		s = C_OMP_CLAUSE_SPLIT_FOR;
+	    }
+	  else if (code == OMP_SECTIONS)
+	    s = C_OMP_CLAUSE_SPLIT_PARALLEL;
+	  else
+	    s = C_OMP_CLAUSE_SPLIT_TEAMS;
+	  break;
+	case OMP_CLAUSE_IF:
+	  /* FIXME: This is currently being discussed.  */
+	  if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS))
+	    s = C_OMP_CLAUSE_SPLIT_PARALLEL;
+	  else
+	    s = C_OMP_CLAUSE_SPLIT_TARGET;
 	  break;
-
 	default:
 	  gcc_unreachable ();
 	}
+      OMP_CLAUSE_CHAIN (clauses) = cclauses[s];
+      cclauses[s] = clauses;
     }
 }
 
+
 /* qsort callback to compare #pragma omp declare simd clauses.  */
 
 static int
