Patchwork [gomp4] #pragma omp declare simd C parsing

login
register
mail settings
Submitter Jakub Jelinek
Date May 13, 2013, 1:01 p.m.
Message ID <20130513130129.GW1377@tucnak.redhat.com>
Download mbox | patch
Permalink /patch/243399/
State New
Headers show

Comments

Jakub Jelinek - May 13, 2013, 1:01 p.m.
Hi!

As expected, the C FE in this case was easier than C++, for
#pragma omp declare reduction it will be the other way around, C
will be much harder.

Committed to gomp-4_0-branch.

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

	* c-tree.h (c_finish_omp_declare_simd): New prototype.
	* c-typeck.c (c_finish_omp_clauses): Handle OMP_CLAUSE_LINEAR_STEP
	adjustments for pointer-types here.  Diagnose inbranch notinbranch
	being used together.
	(c_finish_omp_declare_simd): New function.
	* c-parser.c (enum pragma_context): Add pragma_struct and
	pragma_param.
	(c_parser_declaration_or_fndef): Add omp_declare_simd_clauses
	argument.  Call c_finish_omp_declare_simd if needed.
	(c_parser_external_declaration, c_parser_compound_statement_nostart,
	c_parser_label, c_parser_for_statement, c_parser_objc_methodprotolist,
	c_parser_omp_for_loop): Adjust c_parser_declaration_or_fndef callers.
	(c_parser_struct_or_union_specifier): Use pragma_struct instead of
	pragma_external.
	(c_parser_parameter_declaration): Use pragma_param instead of
	pragma_external.
	(c_parser_pragma): Handle PRAGMA_OMP_DECLARE_REDUCTION.
	Replace == pragma_external with != pragma_stmt && != pragma_compound
	test.
	(c_parser_omp_variable_list): Add declare_simd argument.  Don't lookup
	vars if it is true, just store identifiers.
	(c_parser_omp_var_list_parens, c_parser_omp_clause_depend,
	c_parser_omp_clause_map): Adjust callers.
	(c_parser_omp_clause_reduction, c_parser_omp_clause_aligned): Add
	declare_simd argument, pass it through to c_parser_omp_variable_list.
	(c_parser_omp_clause_linear): Likewise.  Don't handle
	OMP_CLAUSE_LINEAR_STEP adjustements for pointer-types here.
	(c_parser_omp_clause_uniform): Call c_parser_omp_variable_list
	instead of c_parser_omp_var_list_parens to pass true as declare_simd.
	(c_parser_omp_all_clauses): Add declare_simd argument, pass it through
	clause parsing routines as needed.  Don't call c_finish_omp_clauses if
	set.
	(c_parser_omp_simd, c_parser_omp_for, c_parser_omp_sections,
	c_parser_omp_parallel, c_parser_omp_single, c_parser_omp_task,
	c_parser_omp_cancel, c_parser_omp_cancellation_point): Adjust callers.
	(OMP_DECLARE_SIMD_CLAUSE_MASK): Define.
	(c_parser_omp_declare_simd, c_parser_omp_declare): New functions.

	* gcc.dg/gomp/declare-simd-1.c: New test.
	* gcc.dg/gomp/declare-simd-2.c: New test.


	Jakub

Patch

--- gcc/c/c-tree.h.jj	2013-04-24 16:53:21.000000000 +0200
+++ gcc/c/c-tree.h	2013-05-13 12:50:51.536759893 +0200
@@ -642,6 +642,7 @@  extern void c_finish_omp_taskgroup (loca
 extern void c_finish_omp_cancel (location_t, tree);
 extern void c_finish_omp_cancellation_point (location_t, tree);
 extern tree c_finish_omp_clauses (tree);
+extern void c_finish_omp_declare_simd (tree, tree, vec<tree>);
 extern tree c_build_va_arg (location_t, tree, tree);
 extern tree c_finish_transaction (location_t, tree, int);
 extern bool c_tree_equal (tree, tree);
--- gcc/c/c-typeck.c.jj	2013-04-24 17:51:21.000000000 +0200
+++ gcc/c/c-typeck.c	2013-05-13 13:59:23.654460967 +0200
@@ -10670,6 +10670,7 @@  c_finish_omp_clauses (tree clauses)
   bitmap_head aligned_head;
   tree c, t, *pc = &clauses;
   const char *name;
+  bool branch_seen = false;
 
   bitmap_obstack_initialize (NULL);
   bitmap_initialize (&generic_head, &bitmap_default_obstack);
@@ -10774,6 +10775,17 @@  c_finish_omp_clauses (tree clauses)
 	      remove = true;
 	      break;
 	    }
+	  if (TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c))) == POINTER_TYPE)
+	    {
+	      tree s = OMP_CLAUSE_LINEAR_STEP (c);
+	      s = pointer_int_sum (OMP_CLAUSE_LOCATION (c), PLUS_EXPR,
+				   OMP_CLAUSE_DECL (c), s);
+	      s = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR,
+				   sizetype, s, OMP_CLAUSE_DECL (c));
+	      if (s == error_mark_node)
+		s = size_one_node;
+	      OMP_CLAUSE_LINEAR_STEP (c) = s;
+	    }
 	  goto check_dup_generic;
 
 	check_dup_generic:
@@ -10919,8 +10931,6 @@  c_finish_omp_clauses (tree clauses)
 	case OMP_CLAUSE_SIMDLEN:
 	case OMP_CLAUSE_DEVICE:
 	case OMP_CLAUSE_DIST_SCHEDULE:
-	case OMP_CLAUSE_INBRANCH:
-	case OMP_CLAUSE_NOTINBRANCH:
 	case OMP_CLAUSE_PARALLEL:
 	case OMP_CLAUSE_FOR:
 	case OMP_CLAUSE_SECTIONS:
@@ -10929,6 +10939,20 @@  c_finish_omp_clauses (tree clauses)
 	  pc = &OMP_CLAUSE_CHAIN (c);
 	  continue;
 
+	case OMP_CLAUSE_INBRANCH:
+	case OMP_CLAUSE_NOTINBRANCH:
+	  if (branch_seen)
+	    {
+	      error_at (OMP_CLAUSE_LOCATION (c),
+			"%<inbranch%> clause is incompatible with "
+			"%<notinbranch%>");
+	      remove = true;
+	      break;
+	    }
+	  branch_seen = true;
+	  pc = &OMP_CLAUSE_CHAIN (c);
+	  continue;
+
 	default:
 	  gcc_unreachable ();
 	}
@@ -10987,6 +11011,93 @@  c_finish_omp_clauses (tree clauses)
   return clauses;
 }
 
+/* Finalize #pragma omp declare simd clauses after FNDECL has been parsed,
+   and put that into "omp declare simd" attribute.  */
+
+void
+c_finish_omp_declare_simd (tree fndecl, tree parms, vec<tree> clauses)
+{
+  tree cl;
+  int i;
+
+  if (clauses[0] == error_mark_node)
+    return;
+  if (fndecl == NULL_TREE || TREE_CODE (fndecl) != FUNCTION_DECL)
+    {
+      error ("%<#pragma omp declare simd%> not immediately followed by "
+	     "a function declaration or definition");
+      clauses[0] = error_mark_node;
+      return;
+    }
+  if (clauses[0] == integer_zero_node)
+    {
+      error_at (DECL_SOURCE_LOCATION (fndecl),
+		"%<#pragma omp declare simd%> not immediately followed by "
+		"a single function declaration or definition");
+      clauses[0] = error_mark_node;
+      return;
+    }
+
+  if (parms == NULL_TREE)
+    parms = DECL_ARGUMENTS (fndecl);
+
+  FOR_EACH_VEC_ELT (clauses, i, cl)
+    {
+      tree c, *pc, decl, name;
+      for (pc = &cl, c = cl; c; c = *pc)
+	{
+	  bool remove = false;
+	  switch (OMP_CLAUSE_CODE (c))
+	    {
+	    case OMP_CLAUSE_UNIFORM:
+	    case OMP_CLAUSE_LINEAR:
+	    case OMP_CLAUSE_ALIGNED:
+	    case OMP_CLAUSE_REDUCTION:
+	      name = OMP_CLAUSE_DECL (c);
+	      if (name == error_mark_node)
+		remove = true;
+	      else
+		{
+		  for (decl = parms; decl; decl = TREE_CHAIN (decl))
+		    if (DECL_NAME (decl) == name)
+		      break;
+		  if (decl == NULL_TREE)
+		    {
+		      error_at (OMP_CLAUSE_LOCATION (c),
+				"%qE is not a function parameter", name);
+		      remove = true;
+		    }
+		  else
+		    OMP_CLAUSE_DECL (c) = decl;
+		}
+	      break;
+	    default:
+	      break;
+	    }
+	  if (remove)
+	    *pc = OMP_CLAUSE_CHAIN (c);
+	  else
+	    pc = &OMP_CLAUSE_CHAIN (c);
+	}
+      cl = c_finish_omp_clauses (cl);
+      tree saved_arguments = DECL_ARGUMENTS (fndecl);
+      DECL_ARGUMENTS (fndecl) = parms;
+      cl = c_omp_declare_simd_clauses_to_numbers (fndecl, cl);
+      DECL_ARGUMENTS (fndecl) = saved_arguments;
+      for (c = lookup_attribute ("omp declare simd", DECL_ATTRIBUTES (fndecl));
+	   c; c = lookup_attribute ("omp declare simd", TREE_CHAIN (c)))
+	if (omp_declare_simd_clauses_equal (TREE_VALUE (c), cl))
+	  break;
+      if (c)
+	continue;
+      c = build_tree_list (get_identifier ("omp declare simd"), cl);
+      TREE_CHAIN (c) = DECL_ATTRIBUTES (fndecl);
+      DECL_ATTRIBUTES (fndecl) = c;
+    }
+
+  clauses[0] = integer_zero_node;
+}
+
 /* Create a transaction node.  */
 
 tree
--- gcc/c/c-parser.c.jj	2013-05-09 17:04:26.436047147 +0200
+++ gcc/c/c-parser.c	2013-05-13 13:05:56.063771052 +0200
@@ -1112,7 +1112,7 @@  enum c_parser_prec {
 static void c_parser_external_declaration (c_parser *);
 static void c_parser_asm_definition (c_parser *);
 static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool,
-					   bool, bool, tree *);
+					   bool, bool, tree *, vec<tree>);
 static void c_parser_static_assert_declaration_no_semi (c_parser *);
 static void c_parser_static_assert_declaration (c_parser *);
 static void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool,
@@ -1189,8 +1189,10 @@  static void c_parser_omp_taskyield (c_pa
 static void c_parser_omp_cancel (c_parser *);
 static void c_parser_omp_cancellation_point (c_parser *);
 
-enum pragma_context { pragma_external, pragma_stmt, pragma_compound };
+enum pragma_context { pragma_external, pragma_struct, pragma_param,
+		      pragma_stmt, pragma_compound };
 static bool c_parser_pragma (c_parser *, enum pragma_context);
+static void c_parser_omp_declare (c_parser *, enum pragma_context);
 
 /* These Objective-C parser functions are only ever called when
    compiling Objective-C.  */
@@ -1361,7 +1363,8 @@  c_parser_external_declaration (c_parser
 	 an @interface or @protocol with prefix attributes).  We can
 	 only tell which after parsing the declaration specifiers, if
 	 any, and the first declarator.  */
-      c_parser_declaration_or_fndef (parser, true, true, true, false, true, NULL);
+      c_parser_declaration_or_fndef (parser, true, true, true, false, true,
+				     NULL, vNULL);
       break;
     }
 }
@@ -1441,7 +1444,8 @@  static void
 c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 			       bool static_assert_ok, bool empty_ok,
 			       bool nested, bool start_attr_ok,
-			       tree *objc_foreach_object_declaration)
+			       tree *objc_foreach_object_declaration,
+			       vec<tree> omp_declare_simd_clauses)
 {
   struct c_declspecs *specs;
   tree prefix_attrs;
@@ -1611,6 +1616,9 @@  c_parser_declaration_or_fndef (c_parser
 					C_DTR_NORMAL, &dummy);
       if (declarator == NULL)
 	{
+	  if (omp_declare_simd_clauses.exists ())
+	    c_finish_omp_declare_simd (NULL_TREE, NULL_TREE,
+				       omp_declare_simd_clauses);
 	  c_parser_skip_to_end_of_block_or_statement (parser);
 	  return;
 	}
@@ -1647,6 +1655,9 @@  c_parser_declaration_or_fndef (c_parser
 			      chainon (postfix_attrs, all_prefix_attrs));
 	      if (!d)
 		d = error_mark_node;
+	      if (omp_declare_simd_clauses.exists ())
+		c_finish_omp_declare_simd (d, NULL_TREE,
+					   omp_declare_simd_clauses);
 	      start_init (d, asm_name, global_bindings_p ());
 	      init_loc = c_parser_peek_token (parser)->location;
 	      init = c_parser_initializer (parser);
@@ -1663,6 +1674,24 @@  c_parser_declaration_or_fndef (c_parser
 	      tree d = start_decl (declarator, specs, false,
 				   chainon (postfix_attrs,
 					    all_prefix_attrs));
+	      if (omp_declare_simd_clauses.exists ())
+		{
+		  tree parms = NULL_TREE;
+		  if (d && TREE_CODE (d) == FUNCTION_DECL)
+		    {
+		      struct c_declarator *ce = declarator;
+			while (ce != NULL)
+			  if (ce->kind == cdk_function)
+			    {
+			      parms = ce->u.arg_info->parms;
+			      break;
+			    }
+			  else
+			    ce = ce->declarator;
+		    }
+		  c_finish_omp_declare_simd (d, parms,
+					     omp_declare_simd_clauses);
+		}
 	      if (d)
 		finish_decl (d, UNKNOWN_LOCATION, NULL_TREE,
 			     NULL_TREE, asm_name);
@@ -1752,8 +1781,11 @@  c_parser_declaration_or_fndef (c_parser
       while (c_parser_next_token_is_not (parser, CPP_EOF)
 	     && c_parser_next_token_is_not (parser, CPP_OPEN_BRACE))
 	c_parser_declaration_or_fndef (parser, false, false, false,
-				       true, false, NULL);
+				       true, false, NULL, vNULL);
       store_parm_decls ();
+      if (omp_declare_simd_clauses.exists ())
+	c_finish_omp_declare_simd (current_function_decl, NULL_TREE,
+				   omp_declare_simd_clauses);
       DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
 	= c_parser_peek_token (parser)->location;
       fnbody = c_parser_compound_statement (parser);
@@ -2480,7 +2512,7 @@  c_parser_struct_or_union_specifier (c_pa
 	  /* Accept #pragmas at struct scope.  */
 	  if (c_parser_next_token_is (parser, CPP_PRAGMA))
 	    {
-	      c_parser_pragma (parser, pragma_external);
+	      c_parser_pragma (parser, pragma_struct);
 	      continue;
 	    }
 	  /* Parse some comma-separated declarations, but not the
@@ -3311,7 +3343,7 @@  c_parser_parameter_declaration (c_parser
 
   /* Accept #pragmas between parameter declarations.  */
   while (c_parser_next_token_is (parser, CPP_PRAGMA))
-    c_parser_pragma (parser, pragma_external);
+    c_parser_pragma (parser, pragma_param);
 
   if (!c_parser_next_token_starts_declspecs (parser))
     {
@@ -4161,7 +4193,8 @@  c_parser_compound_statement_nostart (c_p
 	{
 	  last_label = false;
 	  mark_valid_location_for_stdc_pragma (false);
-	  c_parser_declaration_or_fndef (parser, true, true, true, true, true, NULL);
+	  c_parser_declaration_or_fndef (parser, true, true, true, true,
+					 true, NULL, vNULL);
 	  if (last_stmt)
 	    pedwarn_c90 (loc,
 			 (pedantic && !flag_isoc99)
@@ -4189,7 +4222,7 @@  c_parser_compound_statement_nostart (c_p
 	      last_label = false;
 	      mark_valid_location_for_stdc_pragma (false);
 	      c_parser_declaration_or_fndef (parser, true, true, true, true,
-					     true, NULL);
+					     true, NULL, vNULL);
 	      /* Following the old parser, __extension__ does not
 		 disable this diagnostic.  */
 	      restore_extension_diagnostics (ext);
@@ -4327,7 +4360,8 @@  c_parser_label (c_parser *parser)
 	  c_parser_declaration_or_fndef (parser, /*fndef_ok*/ false,
 					 /*static_assert_ok*/ true,
 					 /*empty_ok*/ true, /*nested*/ true,
-					 /*start_attr_ok*/ true, NULL);
+					 /*start_attr_ok*/ true, NULL,
+					 vNULL);
 	}
     }
 }
@@ -4947,7 +4981,7 @@  c_parser_for_statement (c_parser *parser
       else if (c_parser_next_tokens_start_declaration (parser))
 	{
 	  c_parser_declaration_or_fndef (parser, true, true, true, true, true, 
-					 &object_expression);
+					 &object_expression, vNULL);
 	  parser->objc_could_be_foreach_context = false;
 	  
 	  if (c_parser_next_token_is_keyword (parser, RID_IN))
@@ -4976,7 +5010,7 @@  c_parser_for_statement (c_parser *parser
 	      ext = disable_extension_diagnostics ();
 	      c_parser_consume_token (parser);
 	      c_parser_declaration_or_fndef (parser, true, true, true, true,
-					     true, &object_expression);
+					     true, &object_expression, vNULL);
 	      parser->objc_could_be_foreach_context = false;
 	      
 	      restore_extension_diagnostics (ext);
@@ -7643,7 +7677,7 @@  c_parser_objc_methodprotolist (c_parser
 	    }
 	  else
 	    c_parser_declaration_or_fndef (parser, false, false, true,
-					   false, true, NULL);
+					   false, true, NULL, vNULL);
 	  break;
 	}
     }
@@ -8657,6 +8691,10 @@  c_parser_pragma (c_parser *parser, enum
       c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
       return false;
 
+    case PRAGMA_OMP_DECLARE_REDUCTION:
+      c_parser_omp_declare (parser, context);
+      return false;
+
     case PRAGMA_GCC_PCH_PREPROCESS:
       c_parser_error (parser, "%<#pragma GCC pch_preprocess%> must be first");
       c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
@@ -8665,7 +8703,7 @@  c_parser_pragma (c_parser *parser, enum
     default:
       if (id < PRAGMA_FIRST_EXTERNAL)
 	{
-	  if (context == pragma_external)
+	  if (context != pragma_stmt && context != pragma_compound)
 	    {
 	    bad_stmt:
 	      c_parser_error (parser, "expected declaration specifiers");
@@ -8890,7 +8928,7 @@  static tree
 c_parser_omp_variable_list (c_parser *parser,
 			    location_t clause_loc,
 			    enum omp_clause_code kind,
-                            tree list)
+			    tree list, bool declare_simd)
 {
   if (c_parser_next_token_is_not (parser, CPP_NAME)
       || c_parser_peek_token (parser)->id_kind != C_ID_ID)
@@ -8899,7 +8937,12 @@  c_parser_omp_variable_list (c_parser *pa
   while (c_parser_next_token_is (parser, CPP_NAME)
 	 && c_parser_peek_token (parser)->id_kind == C_ID_ID)
     {
-      tree t = lookup_name (c_parser_peek_token (parser)->value);
+      tree t;
+
+      if (declare_simd)
+	t = c_parser_peek_token (parser)->value;
+      else
+	t = lookup_name (c_parser_peek_token (parser)->value);
 
       if (t == NULL_TREE)
 	undeclared_variable (c_parser_peek_token (parser)->location,
@@ -8939,7 +8982,7 @@  c_parser_omp_var_list_parens (c_parser *
 
   if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
     {
-      list = c_parser_omp_variable_list (parser, loc, kind, list);
+      list = c_parser_omp_variable_list (parser, loc, kind, list, false);
       c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
     }
   return list;
@@ -9239,7 +9282,7 @@  c_parser_omp_clause_private (c_parser *p
      One of: + * - & ^ | && || max min  */
 
 static tree
-c_parser_omp_clause_reduction (c_parser *parser, tree list)
+c_parser_omp_clause_reduction (c_parser *parser, tree list, bool declare_simd)
 {
   location_t clause_loc = c_parser_peek_token (parser)->location;
   if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
@@ -9301,7 +9344,8 @@  c_parser_omp_clause_reduction (c_parser
 	  tree nl, c;
 
 	  nl = c_parser_omp_variable_list (parser, clause_loc,
-					   OMP_CLAUSE_REDUCTION, list);
+					   OMP_CLAUSE_REDUCTION, list,
+					   declare_simd);
 	  for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
 	    OMP_CLAUSE_REDUCTION_CODE (c) = code;
 
@@ -9531,7 +9575,7 @@  c_parser_omp_clause_num_teams (c_parser
    aligned ( variable-list : constant-expression ) */
 
 static tree
-c_parser_omp_clause_aligned (c_parser *parser, tree list)
+c_parser_omp_clause_aligned (c_parser *parser, tree list, bool declare_simd)
 {
   location_t clause_loc = c_parser_peek_token (parser)->location;
   tree nl, c;
@@ -9540,7 +9584,7 @@  c_parser_omp_clause_aligned (c_parser *p
     return list;
 
   nl = c_parser_omp_variable_list (parser, clause_loc,
-				   OMP_CLAUSE_ALIGNED, list);
+				   OMP_CLAUSE_ALIGNED, list, declare_simd);
 
   if (c_parser_next_token_is (parser, CPP_COLON))
     {
@@ -9570,7 +9614,7 @@  c_parser_omp_clause_aligned (c_parser *p
    linear ( variable-list : expression ) */
 
 static tree
-c_parser_omp_clause_linear (c_parser *parser, tree list)
+c_parser_omp_clause_linear (c_parser *parser, tree list, bool declare_simd)
 {
   location_t clause_loc = c_parser_peek_token (parser)->location;
   tree nl, c, step;
@@ -9579,7 +9623,7 @@  c_parser_omp_clause_linear (c_parser *pa
     return list;
 
   nl = c_parser_omp_variable_list (parser, clause_loc,
-				   OMP_CLAUSE_LINEAR, list);
+				   OMP_CLAUSE_LINEAR, list, declare_simd);
 
   if (c_parser_next_token_is (parser, CPP_COLON))
     {
@@ -9600,16 +9644,7 @@  c_parser_omp_clause_linear (c_parser *pa
 
   for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
     {
-      tree s = step;
-      if (TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c))) == POINTER_TYPE)
-	{
-	  s = pointer_int_sum (clause_loc, PLUS_EXPR, OMP_CLAUSE_DECL (c), s);
-	  s = fold_build2_loc (clause_loc, MINUS_EXPR, sizetype, s,
-			       OMP_CLAUSE_DECL (c));
-	  if (s == error_mark_node)
-	    s = size_one_node;
-	}
-      OMP_CLAUSE_LINEAR_STEP (c) = s;
+      OMP_CLAUSE_LINEAR_STEP (c) = step;
     }
 
   c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
@@ -9724,7 +9759,7 @@  c_parser_omp_clause_depend (c_parser *pa
     goto resync_fail;
 
   nl = c_parser_omp_variable_list (parser, clause_loc,
-				   OMP_CLAUSE_DEPEND, list);
+				   OMP_CLAUSE_DEPEND, list, false);
 
   for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
     OMP_CLAUSE_DEPEND_KIND (c) = kind;
@@ -9780,7 +9815,7 @@  c_parser_omp_clause_map (c_parser *parse
     }
 
   nl = c_parser_omp_variable_list (parser, clause_loc,
-				   OMP_CLAUSE_MAP, list);
+				   OMP_CLAUSE_MAP, list, false);
 
   for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
     OMP_CLAUSE_MAP_KIND (c) = kind;
@@ -9934,7 +9969,16 @@  c_parser_omp_clause_from (c_parser *pars
 static tree
 c_parser_omp_clause_uniform (c_parser *parser, tree list)
 {
-  return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_UNIFORM, list);
+  /* The clauses location.  */
+  location_t loc = c_parser_peek_token (parser)->location;
+
+  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    {
+      list = c_parser_omp_variable_list (parser, loc, OMP_CLAUSE_UNIFORM,
+					 list, true);
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+    }
+  return list;
 }
 
 /* Parse all OpenMP clauses.  The set clauses allowed by the directive
@@ -9943,7 +9987,7 @@  c_parser_omp_clause_uniform (c_parser *p
 
 static tree
 c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask,
-			  const char *where)
+			  const char *where, bool declare_simd)
 {
   tree clauses = NULL;
   bool first = true;
@@ -10017,7 +10061,8 @@  c_parser_omp_all_clauses (c_parser *pars
 	  c_name = "private";
 	  break;
 	case PRAGMA_OMP_CLAUSE_REDUCTION:
-	  clauses = c_parser_omp_clause_reduction (parser, clauses);
+	  clauses = c_parser_omp_clause_reduction (parser, clauses,
+						   declare_simd);
 	  c_name = "reduction";
 	  break;
 	case PRAGMA_OMP_CLAUSE_SCHEDULE:
@@ -10083,11 +10128,12 @@  c_parser_omp_all_clauses (c_parser *pars
 	  c_name = "num_teams";
 	  break;
 	case PRAGMA_OMP_CLAUSE_ALIGNED:
-	  clauses = c_parser_omp_clause_aligned (parser, clauses);
+	  clauses = c_parser_omp_clause_aligned (parser, clauses,
+						 declare_simd);
 	  c_name = "aligned";
 	  break;
 	case PRAGMA_OMP_CLAUSE_LINEAR:
-	  clauses = c_parser_omp_clause_linear (parser, clauses);
+	  clauses = c_parser_omp_clause_linear (parser, clauses, declare_simd);
 	  c_name = "linear";
 	  break;
 	case PRAGMA_OMP_CLAUSE_DEPEND:
@@ -10135,6 +10181,9 @@  c_parser_omp_all_clauses (c_parser *pars
  saw_error:
   c_parser_skip_to_pragma_eol (parser);
 
+  if (declare_simd)
+    return clauses;
+
   return c_finish_omp_clauses (clauses);
 }
 
@@ -10677,7 +10726,8 @@  c_parser_omp_for_loop (location_t loc, c
 	{
 	  if (i > 0)
 	    vec_safe_push (for_block, c_begin_compound_stmt (true));
-	  c_parser_declaration_or_fndef (parser, true, true, true, true, true, NULL);
+	  c_parser_declaration_or_fndef (parser, true, true, true, true, true,
+					 NULL, vNULL);
 	  decl = check_for_loop_decls (for_loc, flag_isoc99);
 	  if (decl == NULL)
 	    goto error_init;
@@ -10942,7 +10992,7 @@  c_parser_omp_simd (location_t loc, c_par
   tree block, clauses, ret;
 
   clauses = c_parser_omp_all_clauses (parser, OMP_SIMD_CLAUSE_MASK,
-				      "#pragma omp simd");
+				      "#pragma omp simd", false);
 
   block = c_begin_compound_stmt (true);
   ret = c_parser_omp_for_loop (loc, parser, OMP_SIMD, clauses, NULL);
@@ -10994,7 +11044,7 @@  c_parser_omp_for (location_t loc, c_pars
 	}
     }
 
-  clauses = c_parser_omp_all_clauses (parser, mask, p_name);
+  clauses = c_parser_omp_all_clauses (parser, mask, p_name, false);
 
   block = c_begin_compound_stmt (true);
   ret = c_parser_omp_for_loop (loc, parser, code, clauses, NULL);
@@ -11140,7 +11190,7 @@  c_parser_omp_sections (location_t loc, c
   tree block, clauses, ret;
 
   clauses = c_parser_omp_all_clauses (parser, OMP_SECTIONS_CLAUSE_MASK,
-				      "#pragma omp sections");
+				      "#pragma omp sections", false);
 
   block = c_begin_compound_stmt (true);
   ret = c_parser_omp_sections_scope (loc, parser);
@@ -11212,7 +11262,7 @@  c_parser_omp_parallel (location_t loc, c
 	}
     }
 
-  clauses = c_parser_omp_all_clauses (parser, mask, p_name);
+  clauses = c_parser_omp_all_clauses (parser, mask, p_name, false);
 
   switch (p_kind)
     {
@@ -11278,7 +11328,7 @@  c_parser_omp_single (location_t loc, c_p
 
   OMP_SINGLE_CLAUSES (stmt)
     = c_parser_omp_all_clauses (parser, OMP_SINGLE_CLAUSE_MASK,
-				"#pragma omp single");
+				"#pragma omp single", false);
   OMP_SINGLE_BODY (stmt) = c_parser_omp_structured_block (parser);
 
   return add_stmt (stmt);
@@ -11307,7 +11357,7 @@  c_parser_omp_task (location_t loc, c_par
   tree clauses, block;
 
   clauses = c_parser_omp_all_clauses (parser, OMP_TASK_CLAUSE_MASK,
-				      "#pragma omp task");
+				      "#pragma omp task", false);
 
   block = c_begin_omp_task ();
   c_parser_statement (parser);
@@ -11377,7 +11427,7 @@  c_parser_omp_cancel (c_parser *parser)
 
   c_parser_consume_pragma (parser);
   tree clauses = c_parser_omp_all_clauses (parser, OMP_CANCEL_CLAUSE_MASK,
-					   "#pragma omp cancel");
+					   "#pragma omp cancel", false);
 
   c_finish_omp_cancel (loc, clauses);
 }
@@ -11420,11 +11470,142 @@  c_parser_omp_cancellation_point (c_parse
 
   clauses
     = c_parser_omp_all_clauses (parser, OMP_CANCELLATION_POINT_CLAUSE_MASK,
-				"#pragma omp cancellation point");
+				"#pragma omp cancellation point", false);
 
   c_finish_omp_cancellation_point (loc, clauses);
 }
 
+/* OpenMP 4.0:
+   # pragma omp declare simd declare-simd-clauses[optseq] new-line  */
+
+#define OMP_DECLARE_SIMD_CLAUSE_MASK				\
+	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMDLEN)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNIFORM)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_INBRANCH)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOTINBRANCH))
+
+static void
+c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
+{
+  vec<tree> clauses = vNULL;
+  tree cl = c_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK,
+				      "#pragma omp declare simd", true);
+  clauses.safe_push (cl);
+
+  while (c_parser_next_token_is (parser, CPP_PRAGMA))
+    {
+      if (c_parser_peek_token (parser)->pragma_kind
+	  != PRAGMA_OMP_DECLARE_REDUCTION
+	  || c_parser_peek_2nd_token (parser)->type != CPP_NAME
+	  || strcmp (IDENTIFIER_POINTER
+				(c_parser_peek_2nd_token (parser)->value),
+		     "simd") != 0)
+	{
+	  c_parser_error (parser,
+			  "%<#pragma omp declare simd%> must be followed by "
+			  "function declaration or definition or another "
+			  "%<#pragma omp declare simd%>");
+	  clauses.release ();
+	  return;
+	}
+      c_parser_consume_pragma (parser);
+      c_parser_consume_token (parser);
+      cl = c_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK,
+				     "#pragma omp declare simd", true);
+      clauses.safe_push (cl);
+    }
+
+  switch (context)
+    {
+    case pragma_external:
+      if (c_parser_next_token_is (parser, CPP_KEYWORD)
+	  && c_parser_peek_token (parser)->keyword == RID_EXTENSION)
+	{
+	  int ext = disable_extension_diagnostics ();
+	  do
+	    c_parser_consume_token (parser);
+	  while (c_parser_next_token_is (parser, CPP_KEYWORD)
+		 && c_parser_peek_token (parser)->keyword == RID_EXTENSION);
+	  c_parser_declaration_or_fndef (parser, true, true, true, false, true,
+					 NULL, clauses);
+	  restore_extension_diagnostics (ext);
+	}
+      else
+	c_parser_declaration_or_fndef (parser, true, true, true, false, true,
+				       NULL, clauses);
+      break;
+    case pragma_struct:
+    case pragma_param:
+      c_parser_error (parser, "%<#pragma omp declare simd%> must be followed by "
+			      "function declaration or definition");
+      break;
+    case pragma_compound:
+    case pragma_stmt:
+      if (c_parser_next_token_is (parser, CPP_KEYWORD)
+	  && c_parser_peek_token (parser)->keyword == RID_EXTENSION)
+	{
+	  int ext = disable_extension_diagnostics ();
+	  do
+	    c_parser_consume_token (parser);
+	  while (c_parser_next_token_is (parser, CPP_KEYWORD)
+		 && c_parser_peek_token (parser)->keyword == RID_EXTENSION);
+	  if (c_parser_next_tokens_start_declaration (parser))
+	    {
+	      c_parser_declaration_or_fndef (parser, true, true, true, true,
+					     true, NULL, clauses);
+	      restore_extension_diagnostics (ext);
+	      break;
+	    }
+	  restore_extension_diagnostics (ext);
+	}
+      else if (c_parser_next_tokens_start_declaration (parser))
+	{
+	  c_parser_declaration_or_fndef (parser, true, true, true, true, true,
+					 NULL, clauses);
+	  break;
+	}
+      c_parser_error (parser, "%<#pragma omp declare simd%> must be followed by "
+			      "function declaration or definition");
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  clauses.release ();
+}
+
+/* OpenMP 4.0
+   #pragma omp declare simd declare-simd-clauses[optseq] new-line
+   #pragma omp declare reduction (reduction-id : typename-list : expression) \
+      identity-clause[opt] new-line */
+
+static void
+c_parser_omp_declare (c_parser *parser, enum pragma_context context)
+{
+  c_parser_consume_pragma (parser);
+  if (c_parser_next_token_is (parser, CPP_NAME))
+    {
+      const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+      if (strcmp (p, "simd") == 0)
+	{
+	  c_parser_consume_token (parser);
+	  c_parser_omp_declare_simd (parser, context);
+	  return;
+	}
+/*    if (strcmp (p, "reduction") == 0)
+	{
+	  c_parser_consume_token (parser);
+	  c_parser_omp_declare_reduction (parser);
+	  return;
+	}  */
+    }
+
+  c_parser_error (parser, "expected %<simd%> or %<reduction%>");
+  c_parser_skip_to_pragma_eol (parser);
+}
+
 /* Main entry point to parsing most OpenMP pragmas.  */
 
 static void
--- gcc/testsuite/gcc.dg/gomp/declare-simd-1.c.jj	2013-05-13 13:25:37.054132804 +0200
+++ gcc/testsuite/gcc.dg/gomp/declare-simd-1.c	2013-05-13 13:22:43.000000000 +0200
@@ -0,0 +1,82 @@ 
+/* Test parsing of #pragma omp declare simd */
+/* { dg-do compile } */
+
+#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) \
+	    linear (c : 4) simdlen (8) notinbranch
+#pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a \
+									    : 4) simdlen (4) inbranch
+int f1 (int a, int *b, int c);
+
+#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8)
+int f2 (int a, int *b, int c)
+{
+  return a + *b + c;
+}
+
+#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (long long)) linear (c : 4) simdlen (8)
+__extension__
+long long f3 (long long a, long long *b, long long c);
+
+int
+f4 (int x)
+{
+  #pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int))
+  __extension__ __extension__ __extension__
+  extern int f5 (int a, int *b, int c);
+  {
+    x++;
+    #pragma omp declare simd simdlen (4) linear (c)
+    extern int f6 (int a, int *b, int c);
+  }
+  return x;
+}
+
+#pragma omp declare simd simdlen (16)
+int
+f7 (int x)
+{
+  #pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int))
+  extern int f8 (int a, int *b, int c);
+  return x;
+}
+
+int
+f9 (int x)
+{
+  if (x)
+    #pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int))
+    extern int f10 (int a, int *b, int c);
+  while (x < 10)
+    #pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int))
+    extern int f11 (int a, int *b, int c);
+  return x;
+}
+
+#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8)
+int f12 (int c; int *b; int a; int a, int *b, int c);
+
+#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8)
+int
+f13 (int c; int *b; int a; int a, int *b, int c)
+{
+  return a + *b + c;
+}
+
+#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8)
+int
+f14 (a, b, c)
+     int a, c;
+     int *b;
+{
+  return a + *b + c;
+}
+
+#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8)
+int
+f15 (int a, int *b, int c)
+{
+  return a + *b + c;
+}
+
+#pragma omp declare simd uniform (d) aligned (e : 8 * sizeof (int)) linear (f : 4) simdlen (8)
+int f15 (int d, int *e, int f);
--- gcc/testsuite/gcc.dg/gomp/declare-simd-2.c.jj	2013-05-13 13:25:39.876116620 +0200
+++ gcc/testsuite/gcc.dg/gomp/declare-simd-2.c	2013-05-13 14:00:42.113675965 +0200
@@ -0,0 +1,24 @@ 
+/* Test parsing of #pragma omp declare simd */
+/* { dg-do compile } */
+
+#pragma omp declare simd
+int a;	/* { dg-error "not immediately followed by a function declaration or definition" } */
+
+#pragma omp declare simd
+int fn1 (int a), fn2 (int a);	/* { dg-error "not immediately followed by a single function declaration or definition" } */
+
+#pragma omp declare simd
+int b, fn3 (int a);	/* { dg-error "not immediately followed by a function declaration or definition" } */
+
+#pragma omp declare simd linear (a)
+int fn4 (int a), c;	/* { dg-error "not immediately followed by a function declaration or definition" } */
+
+int t;
+
+#pragma omp declare simd
+#pragma omp declare simd
+#pragma omp threadprivate(t)	/* { dg-error "must be followed by function declaration or definition or another" } */
+int fn5 (int a);
+
+#pragma omp declare simd inbranch notinbranch /* { dg-error "clause is incompatible with" } */
+int fn6 (int);