Patchwork [gomp4] C++ parsing of combined constructs

login
register
mail settings
Submitter Jakub Jelinek
Date June 14, 2013, 5:08 p.m.
Message ID <20130614170846.GN2336@tucnak.redhat.com>
Download mbox | patch
Permalink /patch/251474/
State New
Headers show

Comments

Jakub Jelinek - June 14, 2013, 5:08 p.m.
Hi!

As OpenMP 4.0 is going to have far more combined constructs
than we initially thought (beyond the OpenMP 2.5 parallel {for,sections}
and OpenMP 4.0 rc2 {,parallel }for simd another 10-12,
the initial approach I had in mind for for simd isn't really workable,
so this patch revamps the parsing of combined constructs (so far in C++,
C is only minimally tweaked so that OpenMP 3.1 tests keep working fine),
there is a much larger function to do clause splitting, and gimplifier
has been tweaked to handle those.  What is left to do is handle the
gimple_omp_for_combined_p constructs in omp-low.c during ompexp.
The way I want it to work say for for simd is that say
expand_omp_for_generic will in the usual:
        more = GOMP_loop_foo_start (N1, N2, STEP, CHUNK, &istart0, &iend0);
        if (more) goto L0; else goto L3;
    L0:
        V = istart0;
        iend = iend0;
    L1:
        BODY;
        V += STEP;
        if (V cond iend) goto L1; else goto L2;
    L2:
        if (GOMP_loop_foo_next (&istart0, &iend0)) goto L0; else goto L3;
    L3:
sequence for collapse(1) leave the V += STEP; if (V cond iend) goto L1; else goto L2;
stmts out and tweak the SIMD loop that it will start with V and end with iend.
For collapsed loops we need to pass down to the expand_omp_for_simd not just
start and end, but also count{2,...N}.  And for distribute parallel for{, simd}
we'll need a way to pass down the istart/iend and count{2,...N} for
collapse>1 through parallel, thus most likely we'll want to create
the decls already during gimplification and stick them somewhere, plus
add them as firstprivate clauses on the parallel.

Anyway, the patch grew already quite big, and this passes gomp.exp and
libgomp testing and is able to compile say:
int a[1024], b, c, d;

void
foo ()
{
  int i;
  #pragma omp for simd schedule(dynamic, 32)
  for (i = 0; i < 1024; i++)
    a[i] += 2;
}
without crashing (though, it will actually iterate 1024*1024 times
right now).  Thus committed to gomp-4_0-branch what I have and will continue
next week.

2013-06-14  Jakub Jelinek  <jakub@redhat.com>

	* gimple-pretty-print.c (dump_gimple_omp_for): Don't handle
	GF_OMP_FOR_KIND_FOR_SIMD.
	* gimple.h (GF_OMP_FOR_KIND_FOR_SIMD): Remove.
	(GF_OMP_FOR_COMBINED): New.
	(gimple_omp_for_combined_p, gimple_omp_for_set_combined_p): New
	inline functions.
	* gimplify.c (is_gimple_stmt): Don't handle OMP_FOR_SIMD.
	(find_combined_omp_for): New function.
	(gimplify_omp_for): Handle combined OMP_DISTRIBUTE and OMP_FOR
	loops.
	* Makefile.in (c-family/c-omp.o): Depend on $(C_PRAGMA_H).
	* omp-low.c (build_outer_var_ref): Fix up simd handling.
	(check_omp_nesting_restrictions): Don't handle
	GF_OMP_FOR_KIND_FOR_SIMD.
	* tree.def (OMP_FOR_SIMD): Remove.
	* tree-pretty-print.c (dump_generic_node): Don't handle OMP_FOR_SIMD.
	Handle NULL OMP_FOR_INIT.
c/
	* c-parser.c (c_parser_omp_for): Comment out OMP_FOR_SIMD uses.
	(c_parser_omp_parallel): Call c_omp_split_clauses instead of
	c_split_parallel_clauses, adjust the code for different API
	of the new function.
cp/
	* parser.c (cp_parser_omp_all_clauses): Add defaulted finish_p
	argument.  Don't call finish_omp_clauses if it is false.
	(cp_parser_omp_for_loop): Change last argument to cclauses,
	and adjust uses to grab parallel clauses from the array of all
	the split clauses.
	(cp_omp_split_clauses): New function.
	(cp_parser_omp_simd): Add p_name, mask and cclauses arguments.
	Allow the function to be called also when parsing combined constructs.
	(cp_parser_omp_sections): Likewise.
	(cp_parser_omp_for): Add p_name, mask and cclauses arguments.
	Allow the function to be called also when parsing combined constructs,
	and call cp_parser_omp_simd when parsing for simd.
	(cp_parser_omp_parallel): Likewise.
	(cp_parser_omp_distribute): Likewise.
	(cp_parser_omp_teams): Likewise.
	(cp_parser_omp_target): If next token is teams, call
	cp_parser_omp_teams and parse it as combined construct.
	(cp_parser_omp_declare_simd): Pass false as last argument to
	cp_parser_omp_all_clauses.
	(cp_parser_omp_construct): Adjust callers of cp_parser_omp_simd,
	cp_parser_omp_sections, cp_parser_omp_for, cp_parser_omp_parallel,
	cp_parser_omp_distribute and cp_parser_omp_teams.
	* pt.c (tsubst_expr): Don't handle OMP_FOR_SIMD.  Handle NULL
	OMP_FOR_INIT.
	* semantics.c (finish_omp_for): Don't handle OMP_FOR_SIMD.
	* cp-tree.h (OMP_FOR_GIMPLIFYING_P): Adjust comment.
	* cp-gimplify.c (cp_gimplify_expr, cp_genericize_r): Don't handle
	OMP_FOR_SIMD.
c-family/
	* c-common.h: Move omp_clause_mask code earlier in the file.
	(c_omp_split_clauses): New prototype.
	(c_split_parallel_clauses): Removed.
	* c-pragma.h (enum pragma_kind): Add
	PRAGMA_OMP_DISTRIBUTE_PARALLEL_FOR,
	PRAGMA_OMP_DISTRIBUTE_PARALLEL_FOR_SIMD,
	PRAGMA_OMP_DISTRIBUTE_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,
	PRAGMA_OMP_TEAMS_DISTRIBUTE,
	PRAGMA_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR,
	and PRAGMA_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD.
	* c-omp.c: Include c-pragma.h.
	(c_omp_split_clauses): New function.
	(c_split_parallel_clauses): Remove.



	Jakub

Patch

--- 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