Patchwork [gomp4/cilkplus] C parsing for Cilk Plus <#pragma simd>

login
register
mail settings
Submitter Aldy Hernandez
Date May 14, 2013, 12:16 a.m.
Message ID <5191825E.5060307@redhat.com>
Download mbox | patch
Permalink /patch/243549/
State New
Headers show

Comments

Aldy Hernandez - May 14, 2013, 12:16 a.m.
Hi Jakub.  Hi folks.

Attached is a patch against the gomp4 branch implementing Cilk's 
<#pragma simd> construct with the gomp4 infrastructure.  I emit OMP_SIMD 
as previously mentioned, and let omp-low.c do the rest.

The reason for this, is that Cilk Plus and OMP4 behave pretty much the 
same way, so there's no need to implement differing trees.  If in the 
future they diverge too much, I guess we could add different tree family 
opcodes for Cilk Plus and gimplify them to a common representation.  For 
now, they're pretty much identical.

I am working on a private branch in aldyh/cilk-in-gomp, but I thought 
I'd post what I've done so far, since it's pretty much complete, and 
Balaji is about to start the C++ parsing bits based on this work.

Let me know if you see anything obviously wrong, or would like things in 
any way different.

Aldy

Patch

diff --git a/gcc/ChangeLog.cilkplus b/gcc/ChangeLog.cilkplus
new file mode 100644
index 0000000..5e9fb79
--- /dev/null
+++ b/gcc/ChangeLog.cilkplus
@@ -0,0 +1,27 @@ 
+2013-05-13  Aldy Hernandez  <aldyh@redhat.com>
+
+	* Makefile.in (C_COMMON_OBJS): Depend on c-family/c-cilkplus.o.
+	(c-cilkplus.o): New dependency.
+
+c-family/
+	* c-cilkplus.c: New.
+	* c-pragma.c (init_pragma): Register "simd" pragma.
+	* c-pragma.h (enum pragma_kind): Add PRAGMA_CILK_SIMD enum.
+	(enum pragma_cilk_clause): New.
+	* c.opt (fcilkplus): New flag.
+
+c/
+	* c-parser.c (c_parser_pragma): Add case for PRAGMA_CILK_SIMD.
+	(c_parser_cilk_verify_simd): New.
+	(c_parser_cilk_clause_vectorlength): New.
+	(c_parser_cilk_clause_linear): New.
+	(c_parser_cilk_clause_name): New.
+	(c_parser_cilk_all_clauses): New.
+	(c_parser_cilk_for_statement): New.
+	(c_parser_cilk_simd_construct): New.
+	* c-tree.h (c_finish_cilk_simd_loop): Protoize.
+	(c_finish_cilk_clauses): Same.
+	* c-typeck.c (c_finish_bc_stmt): Add case for _Cilk_for loops.
+
+testsuite/
+	* gcc.dg/cilk-plus: New directory and associated infrastructure.
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 7be55ae..6a75f30 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1142,6 +1142,7 @@  C_COMMON_OBJS = c-family/c-common.o c-family/c-cppbuiltin.o c-family/c-dump.o \
   c-family/c-format.o c-family/c-gimplify.o c-family/c-lex.o \
   c-family/c-omp.o c-family/c-opts.o c-family/c-pch.o \
   c-family/c-ppoutput.o c-family/c-pragma.o c-family/c-pretty-print.o \
+  c-family/c-cilkplus.o \
   c-family/c-semantics.o c-family/c-ada-spec.o tree-mudflap.o
 
 # Language-independent object files.
@@ -1971,6 +1972,9 @@  c-family/c-lex.o : c-family/c-lex.c $(CONFIG_H) $(SYSTEM_H) coretypes.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
 
+c-family/c-cilkplus.o : c-family/c-cilkplus.c $(CONFIG_H) $(SYSTEM_H) \
+	coretypes.h $(TREE_H) $(C_COMMON_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 \
         $(TREE_H) $(C_PRAGMA_H) $(FLAGS_H) toplev.h langhooks.h \
diff --git a/gcc/c-family/c-cilkplus.c b/gcc/c-family/c-cilkplus.c
new file mode 100644
index 0000000..40284fe
--- /dev/null
+++ b/gcc/c-family/c-cilkplus.c
@@ -0,0 +1,442 @@ 
+/* This file contains routines to construct and validate Cilk Plus
+   constructs within the C and C++ front ends.
+
+   Copyright (C) 2011-2013  Free Software Foundation, Inc.
+   Contributed by Balaji V. Iyer <balaji.v.iyer@intel.com>,
+		  Aldy Hernandez <aldyh@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "c-common.h"
+
+/* Helper function for c_check_cilk_loop.
+
+   Validate the increment in a _Cilk_for construct or a <#pragma simd>
+   for loop.
+
+   LOC is the location of the `for' keyword.  DECL is the induction
+   variable.  INCR is the original increment expression.
+
+   Returns the canonicalized increment expression for an OMP_FOR_INCR.
+   If there is a validation error, returns error_mark_node.  */
+
+static tree
+c_check_cilk_loop_incr (location_t loc, tree decl, tree incr)
+{
+  if (EXPR_HAS_LOCATION (incr))
+    loc = EXPR_LOCATION (incr);
+
+  if (!incr)
+    {
+      error_at (loc, "missing increment");
+      return error_mark_node;
+    }
+
+  switch (TREE_CODE (incr))
+    {
+    case POSTINCREMENT_EXPR:
+    case PREINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+    case PREDECREMENT_EXPR:
+      if (TREE_OPERAND (incr, 0) != decl)
+	break;
+
+      // Bah... canonicalize into whatever OMP_FOR_INCR needs.
+      if (POINTER_TYPE_P (TREE_TYPE (decl))
+	  && TREE_OPERAND (incr, 1))
+	{
+	  tree t = fold_convert_loc (loc,
+				     sizetype, TREE_OPERAND (incr, 1));
+
+	  if (TREE_CODE (incr) == POSTDECREMENT_EXPR
+	      || TREE_CODE (incr) == PREDECREMENT_EXPR)
+	    t = fold_build1_loc (loc, NEGATE_EXPR, sizetype, t);
+	  t = fold_build_pointer_plus (decl, t);
+	  incr = build2 (MODIFY_EXPR, void_type_node, decl, t);
+	}
+      return incr;
+
+    case MODIFY_EXPR:
+      {
+	tree rhs;
+
+	if (TREE_OPERAND (incr, 0) != decl)
+	  break;
+
+	rhs = TREE_OPERAND (incr, 1);
+	if (TREE_CODE (rhs) == PLUS_EXPR
+	    && (TREE_OPERAND (rhs, 0) == decl
+		|| TREE_OPERAND (rhs, 1) == decl)
+	    && INTEGRAL_TYPE_P (TREE_TYPE (rhs)))
+	  return incr;
+	else if (TREE_CODE (rhs) == MINUS_EXPR
+		 && TREE_OPERAND (rhs, 0) == decl
+		 && INTEGRAL_TYPE_P (TREE_TYPE (rhs)))
+	  return incr;
+	// Otherwise fail because only PLUS_EXPR and MINUS_EXPR are
+	// allowed.
+	break;
+      }
+
+    default:
+      break;
+    }
+
+  error_at (loc, "invalid increment expression");
+  return error_mark_node;
+}
+
+/* Callback for walk_tree.
+
+   This function is passed in as a function pointer to walk_tree.  *TP is
+   the current tree pointer, *WALK_SUBTREES is set to 0 by this function if
+   recursing into TP's subtrees is unnecessary. *DATA is a bool variable that
+   is set to false if an error has occured.  */
+
+static tree
+find_invalid_stmts_in_loops (tree *tp, int *walk_subtrees, void *data)
+{
+  if (!tp || !*tp)
+    return NULL_TREE;
+
+  bool *valid = (bool *) data;
+
+  // FIXME: Disallow the following constructs within a SIMD loop:
+  //
+  // _Cilk_spawn
+  // _Cilk_for
+  // try
+
+  /* FIXME: Jumps are disallowed into or out of the body of a
+     _Cilk_for.  We can't just check for GOTO_EXPR here, since
+     GOTO_EXPR's can also be generated by switches and loops.
+
+     We should check for this case after we have built the CFG,
+     possibly at OMP expansion (ompexp).  However, since by then we
+     have expanded the _Cilk_for into an OMP_FOR, we should probably
+     set a tree bit in OMP_FOR differentiating it from the Cilk SIMD
+     construct and handle it appropriately.  */
+
+  switch (TREE_CODE (*tp))
+    {
+    case RETURN_EXPR:
+      error_at (EXPR_LOCATION (*tp), "return statments are not allowed "
+		"within loops annotated with #pragma simd");
+      *valid = false;
+      *walk_subtrees = 0;
+      break;
+    case CALL_EXPR:
+      {
+	tree fndecl = CALL_EXPR_FN (*tp);
+
+	if (TREE_CODE (fndecl) == ADDR_EXPR)
+	  fndecl = TREE_OPERAND (fndecl, 0);
+	if (TREE_CODE (fndecl) == FUNCTION_DECL)
+	  {
+	    if (setjmp_call_p (fndecl))
+	      {
+		error_at (EXPR_LOCATION (*tp),
+			  "calls to setjmp are not allowed within loops "
+			  "annotated with #pragma simd");
+		*valid = false;
+		*walk_subtrees = 0;
+	      }
+	  }
+	break;
+      }
+
+      /* FIXME: Perhaps we could do without these OMP tests and defer
+	 to the OMP type checking, since OMP_SIMD cannot have OpenMP
+	 constructs either.  From OpenMP 4.0rc2: "No OpenMP construct
+	 can appear in the simd region".  Similarly for the call to
+	 setjmp above.  */
+    case OMP_PARALLEL:
+    case OMP_TASK:
+    case OMP_FOR:
+    case OMP_SIMD:
+    case OMP_FOR_SIMD:
+    case OMP_DISTRIBUTE:
+    case OMP_SECTIONS:
+    case OMP_SINGLE:
+    case OMP_SECTION:
+    case OMP_MASTER:
+    case OMP_ORDERED:
+    case OMP_CRITICAL:
+    case OMP_ATOMIC:
+    case OMP_ATOMIC_READ:
+    case OMP_ATOMIC_CAPTURE_OLD:
+    case OMP_ATOMIC_CAPTURE_NEW:
+      error_at (EXPR_LOCATION (*tp), "OpenMP statements are not allowed "
+		"within loops annotated with #pragma simd");
+      *valid = false;
+      *walk_subtrees = 0;
+      break;
+
+    default:
+      break;
+    }
+  return NULL_TREE;
+}  
+
+/* Validate the body of a _Cilk_for construct or a <#pragma simd> for
+   loop.
+
+   Returns true if there were no errors, false otherwise.  */
+
+static bool
+c_check_cilk_loop_body (tree body)
+{
+  bool valid = true;
+  walk_tree (&body, find_invalid_stmts_in_loops, (void *) &valid, NULL);
+  return valid;
+}
+
+/* Validate a _Cilk_for construct (or a #pragma simd for loop, which
+   has the same syntactic restrictions).  Returns TRUE if there were
+   no errors, FALSE otherwise.  LOC is the location of the for.  DECL
+   is the controlling variable.  COND is the condition.  INCR is the
+   increment expression.  BODY is the body of the LOOP.  */
+
+static bool
+c_check_cilk_loop (location_t loc, tree decl, tree cond, tree incr, tree body)
+{
+  if (decl == error_mark_node
+      || cond == error_mark_node 
+      || incr == error_mark_node
+      || body == error_mark_node)
+    return false;
+
+  /* Validate the initialization.  */
+  gcc_assert (decl != NULL);
+  if (TREE_THIS_VOLATILE (decl))
+    {
+      error_at (loc, "induction variable cannot be volatile");
+      return false;
+    }
+  if (DECL_EXTERNAL (decl))
+    {
+      error_at (loc, "induction variable cannot be extern");
+      return false;
+    }
+  if (TREE_STATIC (decl))
+    {
+      error_at (loc, "induction variable cannot be static");
+      return false;
+    }
+  if (DECL_REGISTER (decl))
+    {
+      error_at (loc, "induction variable cannot be declared register");
+      return false;
+    }
+  if (!INTEGRAL_TYPE_P (TREE_TYPE (decl))
+      && !POINTER_TYPE_P (TREE_TYPE (decl)))
+    {
+      error_at (loc, "initialization variable must be of integral "
+		"or pointer type");
+      return false;
+    }
+
+  /* Validate the condition.  */
+  if (!cond)
+    {
+      error_at (loc, "missing condition");
+      return false;
+    }
+  bool cond_ok = false;
+  if (TREE_CODE (cond) == NE_EXPR
+      || TREE_CODE (cond) == LT_EXPR
+      || TREE_CODE (cond) == LE_EXPR
+      || TREE_CODE (cond) == GT_EXPR
+      || TREE_CODE (cond) == GE_EXPR)
+    {
+      /* Comparison must either be:
+	   DECL <comparison_operator> EXPR
+	   EXPR <comparison_operator> DECL
+      */
+      if (decl == TREE_OPERAND (cond, 0))
+	cond_ok = true;
+      else if (decl == TREE_OPERAND (cond, 1))
+	{
+	  /* Canonicalize the comparison so the DECL is on the LHS.  */
+	  TREE_SET_CODE (cond,
+			 swap_tree_comparison (TREE_CODE (cond)));
+	  TREE_OPERAND (cond, 1) = TREE_OPERAND (cond, 0);
+	  TREE_OPERAND (cond, 0) = decl;
+	  cond_ok = true;
+	}
+    }
+  if (!cond_ok)
+    {
+      error_at (loc, "invalid controlling predicate");
+      return false;
+    }
+
+  /* Validate the increment.  */
+  incr = c_check_cilk_loop_incr (loc, decl, incr);
+  if (incr == error_mark_node)
+    return false;
+
+  if (!c_check_cilk_loop_body (body))
+    return false;
+
+  return true;
+}
+
+/* Adjust any clauses to match the requirements for OpenMP.  */
+
+static tree
+adjust_clauses_for_omp (tree clauses)
+{
+  return clauses;
+}
+
+/* Validate and emit code for the FOR loop following a #<pragma simd>
+   construct.
+
+   LOC is the location of the location of the FOR.
+   DECL is the iteration variable.
+   INIT is the initialization expression.
+   COND is the controlling predicate.
+   INCR is the increment expression.
+   BODY is the body of the loop.
+   CLAUSES are the clauses associated with the pragma simd loop.
+
+   Returns the generated statement.  */
+
+tree
+c_finish_cilk_simd_loop (location_t loc,
+			 tree decl,
+			 tree init, tree cond, tree incr,
+			 tree body,
+			 tree clauses)
+{
+  location_t rhs_loc;
+
+  if (!c_check_cilk_loop (loc, decl, cond, incr, body))
+    return NULL;
+
+  /* In the case of "for (int i = 0...)", init will be a decl.  It should
+     have a DECL_INITIAL that we can turn into an assignment.  */
+  if (init == decl)
+    {
+      rhs_loc = DECL_SOURCE_LOCATION (decl);
+
+      init = DECL_INITIAL (decl);
+      if (init == NULL)
+	{
+	  error_at (rhs_loc, "%qE is not initialized", decl);
+	  init = integer_zero_node;
+	  return NULL;
+	}
+
+      init = build_modify_expr (loc, decl, NULL_TREE, NOP_EXPR, rhs_loc,
+				init, NULL_TREE);
+    }
+  gcc_assert (TREE_CODE (init) == MODIFY_EXPR);
+  gcc_assert (TREE_OPERAND (init, 0) == decl);
+
+  tree initv = make_tree_vec (1);
+  tree condv = make_tree_vec (1);
+  tree incrv = make_tree_vec (1);
+  TREE_VEC_ELT (initv, 0) = init;
+  TREE_VEC_ELT (condv, 0) = cond;
+  TREE_VEC_ELT (incrv, 0) = incr;
+
+  /* The OpenMP <#pragma omp simd> construct is exactly the same as
+     the Cilk Plus one, with the exception of the vectorlength()
+     clause in Cilk Plus.  Emitting an OMP_SIMD simlifies
+     everything.  */
+  tree t = make_node (OMP_SIMD);
+  TREE_TYPE (t) = void_type_node;
+  OMP_FOR_INIT (t) = initv;
+
+  /* FIXME: The spec says "The increment and limit expressions may be
+     evaluated fewer times than in the serialization.  If different
+     evaluations of the same expression yield different values, the
+     behavior of the program is undefined."  This means that the RHS
+     of the condition and increment could be wrapped in a
+     SAVE_EXPR.  */
+  OMP_FOR_COND (t) = condv;
+  OMP_FOR_INCR (t) = incrv;
+
+  OMP_FOR_BODY (t) = body;
+  OMP_FOR_PRE_BODY (t) = NULL;
+  OMP_FOR_CLAUSES (t) = adjust_clauses_for_omp (clauses);
+
+  SET_EXPR_LOCATION (t, loc);
+  return add_stmt (t);
+}
+
+/* Validate and emit code for <#pragma simd> clauses.  */
+
+tree
+c_finish_cilk_clauses (tree clauses)
+{
+  /* FIXME: Should we do some minimal type checking of the clauses
+     here, or at the minimum gcc_asserts?  */
+
+  /* FIXME: Must validate reduction clauses too.  Right now we're
+     ignoring them.  */
+  for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
+    {
+      tree prev = clauses;
+
+      /* If a variable appears in a linear clause it cannot appear in
+	 any other OMP clause.  */
+      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR)
+	for (tree c2 = clauses; c2; c2 = OMP_CLAUSE_CHAIN (c2))
+	  {
+	    if (c == c2)
+	      continue;
+	    enum omp_clause_code code = OMP_CLAUSE_CODE (c2);
+
+	    switch (code)
+	      {
+	      case OMP_CLAUSE_LINEAR:
+	      case OMP_CLAUSE_PRIVATE:
+	      case OMP_CLAUSE_FIRSTPRIVATE:
+	      case OMP_CLAUSE_LASTPRIVATE:
+	      case OMP_CLAUSE_REDUCTION:
+		break;
+
+	      case OMP_CLAUSE_SAFELEN:
+		goto next;
+
+	      default:
+		gcc_unreachable ();
+	      }
+
+	    if (OMP_CLAUSE_DECL (c) == OMP_CLAUSE_DECL (c2))
+	      {
+		error_at (OMP_CLAUSE_LOCATION (c2),
+			  "variable appears in more than one clause");
+		inform (OMP_CLAUSE_LOCATION (c),
+			"multiple clause defined here");
+		// Remove problematic clauses.
+		OMP_CLAUSE_CHAIN (prev) = OMP_CLAUSE_CHAIN (c2);
+	      }
+	  next:
+	    prev = c2;
+	  }
+    }
+
+  return clauses;
+}
diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c
index d46bfbb..80f98d4 100644
--- a/gcc/c-family/c-pragma.c
+++ b/gcc/c-family/c-pragma.c
@@ -1353,6 +1353,12 @@  init_pragma (void)
 				      omp_pragmas[i].id, true, true);
     }
 
+  if (flag_enable_cilk && !flag_preprocess_only)
+    {
+      cpp_register_deferred_pragma (parse_in, NULL, "simd", 
+				    PRAGMA_CILK_SIMD, true, false);
+    }
+
   if (!flag_preprocess_only)
     cpp_register_deferred_pragma (parse_in, "GCC", "pch_preprocess",
 				  PRAGMA_GCC_PCH_PREPROCESS, false, false);
diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h
index cd121d4..1f84a78 100644
--- a/gcc/c-family/c-pragma.h
+++ b/gcc/c-family/c-pragma.h
@@ -60,6 +60,9 @@  typedef enum pragma_kind {
   PRAGMA_OMP_THREADPRIVATE,
   PRAGMA_OMP_TEAMS,
 
+  /* Top level clause to handle all Cilk Plus pragma simd clauses.  */
+  PRAGMA_CILK_SIMD,
+
   PRAGMA_GCC_PCH_PREPROCESS,
 
   PRAGMA_FIRST_EXTERNAL
@@ -109,6 +112,17 @@  typedef enum pragma_omp_clause {
   PRAGMA_OMP_CLAUSE_UNTIED
 } pragma_omp_clause;
 
+/* All Cilk Plus #pragma omp clauses.  */
+typedef enum pragma_cilk_clause {
+  PRAGMA_CILK_CLAUSE_NONE = 0,
+  PRAGMA_CILK_CLAUSE_VECTORLENGTH,
+  PRAGMA_CILK_CLAUSE_LINEAR,
+  PRAGMA_CILK_CLAUSE_PRIVATE,
+  PRAGMA_CILK_CLAUSE_FIRSTPRIVATE,
+  PRAGMA_CILK_CLAUSE_LASTPRIVATE,
+  PRAGMA_CILK_CLAUSE_REDUCTION
+} pragma_cilk_clause;
+
 extern struct cpp_reader* parse_in;
 
 /* It's safe to always leave visibility pragma enabled as if
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 124c139..d4e0c1e 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -839,6 +839,10 @@  Recognize built-in functions
 fbuiltin-
 C ObjC C++ ObjC++ Joined
 
+fcilkplus
+C ObjC C++ ObjC++ LTO Report Var(flag_enable_cilk) Init(0)
+Enable Cilk
+
 fcanonical-system-headers
 C ObjC C++ ObjC++
 Where shorter, use canonicalized paths to systems headers.
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index dbfaf13..8ddddac 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1221,6 +1221,11 @@  static void c_parser_objc_at_dynamic_declaration (c_parser *);
 static bool c_parser_objc_diagnose_bad_element_prefix
   (c_parser *, struct c_declspecs *);
 
+/* Cilk Plus supporting routines.  */
+static void c_parser_cilk_for_statement (c_parser *, enum rid, tree);
+static void c_parser_cilk_simd_construct (c_parser *);
+static bool c_parser_cilk_verify_simd (c_parser *, enum pragma_context);
+
 /* Parse a translation unit (C90 6.7, C99 6.9).
 
    translation-unit:
@@ -8706,6 +8711,13 @@  c_parser_pragma (c_parser *parser, enum pragma_context context)
       c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
       return false;
 
+    case PRAGMA_CILK_SIMD:
+      if (!c_parser_cilk_verify_simd (parser, context))
+	return false;
+      c_parser_consume_pragma (parser);
+      c_parser_cilk_simd_construct (parser);
+      return false;
+
     default:
       if (id < PRAGMA_FIRST_EXTERNAL)
 	{
@@ -11722,7 +11734,407 @@  c_parser_omp_threadprivate (c_parser *parser)
 
   c_parser_skip_to_pragma_eol (parser);
 }
+
+/* Cilk Plus <#pragma simd> parsing routines.  */
+
+/* Helper function for c_parser_pragma.  Perform some sanity checking
+   for <#pragma simd> constructs.  Returns FALSE if there was a
+   problem.  */
+
+static bool
+c_parser_cilk_verify_simd (c_parser *parser,
+				  enum pragma_context context)
+{
+  if (!flag_enable_cilk)
+    {
+      warning (0, "pragma simd ignored because -fcilkplus is not enabled");
+      c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
+      return false;
+    }
+  if (!flag_tree_vectorize)
+    {
+      warning (0, "pragma simd is useless without -ftree-vectorize");
+      c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
+      return false;
+    }
+  if (context == pragma_external)
+    {
+      c_parser_error (parser,"pragma simd must be inside a function");
+      c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
+      return false;
+    }
+  return true;
+}
+
+/* Cilk Plus:
+   vectorlength ( constant-expression ) */
+
+static tree
+c_parser_cilk_clause_vectorlength (c_parser *parser, tree clauses)
+{
+  /* The vectorlength clause behaves exactly like OpenMP's safelen
+     clause.  Represent it in OpenMP terms.  */
+  check_no_duplicate_clause (clauses, OMP_CLAUSE_SAFELEN, "vectorlength");
+
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    return clauses;
+
+  location_t loc = c_parser_peek_token (parser)->location;
+  tree expr = c_parser_expr_no_commas (parser, NULL).value;
+  expr = c_fully_fold (expr, false, NULL);
+
+  if (!TREE_TYPE (expr)
+      || !TREE_CONSTANT (expr)
+      || !INTEGRAL_TYPE_P (TREE_TYPE (expr)))
+    error_at (loc, "vectorlength must be an integer constant");
+  else if (exact_log2 (TREE_INT_CST_LOW (expr)) == -1)
+    error_at (loc, "vectorlength must be a power of 2");
+  else
+    {
+      tree u = build_omp_clause (loc, OMP_CLAUSE_SAFELEN);
+      OMP_CLAUSE_SAFELEN_EXPR (u) = expr;
+      OMP_CLAUSE_CHAIN (u) = clauses;
+      clauses = u;
+    }
+
+  c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+  return clauses;
+}
+
+/* Cilk Plus:
+   linear ( simd-linear-variable-list )
+
+   simd-linear-variable-list:
+     simd-linear-variable
+     simd-linear-variable-list , simd-linear-variable
+
+   simd-linear-variable:
+     id-expression
+     id-expression : simd-linear-step
+
+   simd-linear-step:
+   conditional-expression */
+
+static tree
+c_parser_cilk_clause_linear (c_parser *parser, tree clauses)
+{
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    return clauses;
+
+  location_t loc = c_parser_peek_token (parser)->location;
+
+  if (c_parser_next_token_is_not (parser, CPP_NAME)
+      || c_parser_peek_token (parser)->id_kind != C_ID_ID)
+    c_parser_error (parser, "expected identifier");
+
+  while (c_parser_next_token_is (parser, CPP_NAME)
+	 && c_parser_peek_token (parser)->id_kind == C_ID_ID)
+    {
+      tree var = lookup_name (c_parser_peek_token (parser)->value);
+
+      if (var == NULL)
+	{
+	  undeclared_variable (c_parser_peek_token (parser)->location,
+			       c_parser_peek_token (parser)->value);
+	c_parser_consume_token (parser);
+	}
+      else if (var == error_mark_node)
+	c_parser_consume_token (parser);
+      else
+	{
+	  tree step = integer_one_node;
+
+	  /* Parse the linear step if present.  */
+	  if (c_parser_peek_2nd_token (parser)->type == CPP_COLON)
+	    {
+	      c_parser_consume_token (parser);
+	      c_parser_consume_token (parser);
+
+	      tree expr = c_parser_expr_no_commas (parser, NULL).value;
+	      expr = c_fully_fold (expr, false, NULL);
+
+	      if (!TREE_TYPE (expr)
+		  || !TREE_CONSTANT (expr)
+		  || !INTEGRAL_TYPE_P (TREE_TYPE (expr)))
+		c_parser_error (parser,
+				"step size must be an integer constant");
+	      else
+		step = expr;
+	    }
+	  else
+	    c_parser_consume_token (parser);
+
+	  /* Use OMP_CLAUSE_LINEAR, which has the same semantics.  */
+	  tree u = build_omp_clause (loc, OMP_CLAUSE_LINEAR);
+	  OMP_CLAUSE_DECL (u) = var;
+	  OMP_CLAUSE_LINEAR_STEP (u) = step;
+	  OMP_CLAUSE_CHAIN (u) = clauses;
+	  clauses = u;
+	}
+
+      if (c_parser_next_token_is_not (parser, CPP_COMMA))
+	break;
+
+      c_parser_consume_token (parser);
+    }
+
+  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+  return clauses;
+}
+
+/* Returns the name of the next clause.  If the clause is not
+   recognized SIMD_OMP_CLAUSE_NONE is returned and the next token is
+   not consumed.  Otherwise, the appropriate pragma_simd_clause is
+   returned and the token is consumed.  */
 
+static pragma_cilk_clause
+c_parser_cilk_clause_name (c_parser *parser)
+{
+  pragma_cilk_clause result;
+  c_token *token = c_parser_peek_token (parser);
+
+  if (!token->value || token->type != CPP_NAME)
+    return PRAGMA_CILK_CLAUSE_NONE;
+
+  const char *p = IDENTIFIER_POINTER (token->value);
+
+  if (!strcmp (p, "vectorlength"))
+    result = PRAGMA_CILK_CLAUSE_VECTORLENGTH;
+  else if (!strcmp (p, "linear"))
+    result = PRAGMA_CILK_CLAUSE_LINEAR;
+  else if (!strcmp (p, "private"))
+    result = PRAGMA_CILK_CLAUSE_PRIVATE;
+  else if (!strcmp (p, "firstprivate"))
+    result = PRAGMA_CILK_CLAUSE_FIRSTPRIVATE;
+  else if (!strcmp (p, "lastprivate"))
+    result = PRAGMA_CILK_CLAUSE_LASTPRIVATE;
+  else if (!strcmp (p, "reduction"))
+    result = PRAGMA_CILK_CLAUSE_REDUCTION;
+  else
+    return PRAGMA_CILK_CLAUSE_NONE;
+
+  c_parser_consume_token (parser);
+  return result;
+}
+
+/* Parse all #<pragma simd> clauses.  Return the list of clauses
+   found.  */
+
+static tree
+c_parser_cilk_all_clauses (c_parser *parser)
+{
+  tree clauses = NULL;
+
+  while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+    {
+      pragma_cilk_clause c_kind;
+
+      c_kind = c_parser_cilk_clause_name (parser);
+
+      switch (c_kind)
+	{
+	case PRAGMA_CILK_CLAUSE_VECTORLENGTH:
+	  clauses = c_parser_cilk_clause_vectorlength (parser, clauses);
+	  break;
+	case PRAGMA_CILK_CLAUSE_LINEAR:
+	  clauses = c_parser_cilk_clause_linear (parser, clauses);
+	  break;
+	case PRAGMA_CILK_CLAUSE_PRIVATE:
+	  /* Use the OpenMP counterpart.  */
+	  clauses = c_parser_omp_clause_private (parser, clauses);
+	  break;
+	case PRAGMA_CILK_CLAUSE_FIRSTPRIVATE:
+	  /* Use the OpenMP counterpart.  */
+	  /* FIXME: Note from the Cilk Plus forum: "For the time
+	     being, assume that firstprivate refers to the vector
+	     lane. (This is what is implemented in the icc compiler.)
+	     As we update the spec, we will harmonize these
+	     definitions with OpenMP 4, possibly deprecating
+	     firstprivate."  */
+	  clauses = c_parser_omp_clause_firstprivate (parser, clauses);
+	  break;
+	case PRAGMA_CILK_CLAUSE_LASTPRIVATE:
+	  /* Use the OpenMP counterpart.  */
+	  clauses = c_parser_omp_clause_lastprivate (parser, clauses);
+	  break;
+	case PRAGMA_CILK_CLAUSE_REDUCTION:
+	  /* Use the OpenMP counterpart.  */
+	  clauses = c_parser_omp_clause_reduction (parser, clauses);
+	  break;
+	default:
+	  c_parser_error (parser, "expected %<#pragma simd%> clause");
+	  goto saw_error;
+	}
+    }
+
+ saw_error:
+  c_parser_skip_to_pragma_eol (parser);
+  return c_finish_cilk_clauses (clauses);
+}
+
+/* Parse the restriction form of the for statement allowed by
+   Cilk Plus.  This function parses both the _CILK_FOR construct as
+   well as the for loop following a <#pragma simd> construct, both of
+   which have the same syntactic restrictions.
+
+   FOR_KEYWORD can be either RID_CILK_FOR or RID_FOR, for parsing
+   _cilk_for or the <#pragma simd> for loop construct respectively.
+
+   (NOTE: For now, only RID_FOR is handled).
+
+   For a <#pragma simd>, CLAUSES are the clauses that should have been
+   previously parsed.  If there are none, or if we are parsing a
+   _Cilk_for instead, this will be NULL.  */
+   
+static void
+c_parser_cilk_for_statement (c_parser *parser, enum rid for_keyword,
+			     tree clauses)
+{
+  tree init, decl,  cond, stmt;
+  tree block, incr, save_break, save_cont, body;
+  location_t loc;
+  bool fail = false;
+
+  gcc_assert (/*for_keyword == RID_CILK_FOR || */for_keyword == RID_FOR);
+
+  if (!c_parser_next_token_is_keyword (parser, for_keyword))
+    {
+      if (for_keyword == RID_FOR)
+	c_parser_error (parser, "for statement expected");
+      else
+	c_parser_error (parser, "_Cilk_for statement expected");
+      return;
+    }
+
+  loc = c_parser_peek_token (parser)->location;
+  c_parser_consume_token (parser);
+
+  block = c_begin_compound_stmt (true);
+
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    {
+      add_stmt (c_end_compound_stmt (loc, block, true));
+      return;
+    }
+
+  /* Parse the initialization declaration.  */
+  if (c_parser_next_tokens_start_declaration (parser))
+    {
+      c_parser_declaration_or_fndef (parser, true, false, false,
+				     false, false, NULL);
+      decl = check_for_loop_decls (loc, flag_isoc99);
+      if (decl == NULL)
+	goto error_init;
+      if (DECL_INITIAL (decl) == error_mark_node)
+	decl = error_mark_node;
+      init = decl;
+    }
+  else if (c_parser_next_token_is (parser, CPP_NAME)
+	   && c_parser_peek_2nd_token (parser)->type == CPP_EQ)
+    {
+      struct c_expr decl_exp;
+      struct c_expr init_exp;
+      location_t init_loc;
+
+      decl_exp = c_parser_postfix_expression (parser);
+      decl = decl_exp.value;
+
+      c_parser_require (parser, CPP_EQ, "expected %<=%>");
+
+      init_loc = c_parser_peek_token (parser)->location;
+      init_exp = c_parser_expr_no_commas (parser, NULL);
+      init_exp = default_function_array_read_conversion (init_loc,
+							 init_exp);
+      init = build_modify_expr (init_loc, decl, decl_exp.original_type,
+				NOP_EXPR, init_loc, init_exp.value,
+				init_exp.original_type);
+      init = c_process_expr_stmt (init_loc, init);
+
+      c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+    }
+  else
+    {
+    error_init:
+      c_parser_error (parser,
+		      "expected iteration declaration or initialization");
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+				 "expected %<)%>");
+      return;
+    }
+
+  /* Parse the loop condition.  */
+  cond = NULL_TREE;
+  if (c_parser_next_token_is_not (parser, CPP_SEMICOLON))
+    {
+      location_t cond_loc = c_parser_peek_token (parser)->location;
+      struct c_expr cond_expr = c_parser_binary_expression (parser, NULL,
+							    NULL);
+
+      cond = cond_expr.value;
+      cond = c_objc_common_truthvalue_conversion (cond_loc, cond);
+      cond = c_fully_fold (cond, false, NULL);
+    }
+  c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+
+  /* Parse the increment expression.  */
+  incr = NULL_TREE;
+  if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN))
+    {
+      location_t incr_loc = c_parser_peek_token (parser)->location;
+      incr = c_process_expr_stmt (incr_loc,
+				  c_parser_expression (parser).value);
+    }
+  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+  if (decl == NULL || decl == error_mark_node || init == error_mark_node)
+    fail = true;
+
+  save_break = c_break_label;
+  /* Magic number to inform c_finish_bc_stmt() that we are within a
+     Cilk for construct.  */
+  c_break_label = build_int_cst (size_type_node, 2);
+
+  save_cont = c_cont_label;
+  c_cont_label = NULL_TREE;
+  body = c_parser_c99_block_statement (parser);
+  c_break_label = save_break;
+  c_cont_label = save_cont;
+
+  if (!fail)
+    {
+      /*
+      // FIXME: Uncomment when RID_CILK_FOR is implemented.
+      if (for_keyword == RID_CILK_FOR)
+	c_finish_cilk_loop (loc, decl, cond, incr, body, grain);
+      else
+      */
+	c_finish_cilk_simd_loop (loc, decl, init, cond, incr, body, clauses);
+    }
+
+  stmt = c_end_compound_stmt (loc, block, true);
+  add_stmt (stmt);
+  c_break_label = save_break;
+  c_cont_label = save_cont;
+}
+
+/* Main entry point for parsing Cilk Plus <#pragma simd> for
+   loops.  */
+
+static void
+c_parser_cilk_simd_construct (c_parser *parser)
+{
+  tree clauses = c_parser_cilk_all_clauses (parser);
+
+  /* For <#pragma simd> we will be generating OMP_SIMD's and let the
+     OpenMP mechanism handle everything.  */
+  if (!flag_openmp)
+    flag_openmp = true;
+
+  c_parser_cilk_for_statement (parser, RID_FOR, clauses);
+}
+
 /* Parse a transaction attribute (GCC Extension).
 
    transaction-attribute:
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 93516da..84471db 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -647,6 +647,11 @@  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);
 
+/* In c-cilkplus.c */
+extern tree c_finish_cilk_simd_loop (location_t, tree, tree, tree, tree,
+				     tree, tree);
+extern tree c_finish_cilk_clauses (tree);
+
 /* Set to 0 at beginning of a function definition, set to 1 if
    a return statement that specifies a return value is seen.  */
 
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index a7a822e..78e7144 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -9093,6 +9093,13 @@  c_finish_bc_stmt (location_t loc, tree *label_p, bool is_break)
       error_at (loc, "break statement used with OpenMP for loop");
       return NULL_TREE;
 
+    case 2:
+      if (is_break) 
+	error ("break statement within _Cilk_for loop");
+      else 
+	error ("continue statement within _Cilk_for loop");
+      return NULL_TREE;
+
     default:
       gcc_unreachable ();
     }
@@ -10852,7 +10859,8 @@  c_finish_omp_clauses (tree clauses)
 	    bitmap_set_bit (&lastprivate_head, DECL_UID (t));
 	  break;
 
-	case OMP_CLAUSE_ALIGNED:
+	case OMP_CLAUSE_ALIGNED: 
+	  name = "aligned";
 	  t = OMP_CLAUSE_DECL (c);
 	  if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
 	    {
@@ -10872,6 +10880,7 @@  c_finish_omp_clauses (tree clauses)
 	  break;
 
 	case OMP_CLAUSE_DEPEND:
+	  name = "depend";
 	  t = OMP_CLAUSE_DECL (c);
 	  /* FIXME: depend clause argument may be also array section.  */
 	  if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
@@ -10883,8 +10892,11 @@  c_finish_omp_clauses (tree clauses)
 	  break;
 
 	case OMP_CLAUSE_MAP:
+	  name = "map";
 	case OMP_CLAUSE_TO:
+	  name = "to";
 	case OMP_CLAUSE_FROM:
+	  name = "from";
 	  t = OMP_CLAUSE_DECL (c);
 	  /* FIXME: map clause argument may be also array section.  */
 	  if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
@@ -10904,6 +10916,7 @@  c_finish_omp_clauses (tree clauses)
 	  break;
 
 	case OMP_CLAUSE_UNIFORM:
+	  name = "uniform";
 	  t = OMP_CLAUSE_DECL (c);
 	  if (TREE_CODE (t) != PARM_DECL)
 	    {
@@ -10918,24 +10931,87 @@  c_finish_omp_clauses (tree clauses)
 	  break;
 
 	case OMP_CLAUSE_IF:
+	  name = "if";
+	  pc = &OMP_CLAUSE_CHAIN (c);
+	  continue;
 	case OMP_CLAUSE_NUM_THREADS:
+	  name = "num_threads";
+	  pc = &OMP_CLAUSE_CHAIN (c);
+	  continue;
 	case OMP_CLAUSE_SCHEDULE:
+	  name = "schedule";
+	  pc = &OMP_CLAUSE_CHAIN (c);
+	  continue;
 	case OMP_CLAUSE_NOWAIT:
+	  name = "nowait"; 
+	  pc = &OMP_CLAUSE_CHAIN (c);
+	  continue;
 	case OMP_CLAUSE_ORDERED:
+	  name = "ordered";
+	  pc = &OMP_CLAUSE_CHAIN (c);
+	  continue;
 	case OMP_CLAUSE_DEFAULT:
+	  name = "default";
+	  pc = &OMP_CLAUSE_CHAIN (c);
+	  continue;
 	case OMP_CLAUSE_UNTIED:
+	  name = "untied";
+	  pc = &OMP_CLAUSE_CHAIN (c);
+	  continue;
 	case OMP_CLAUSE_COLLAPSE:
+	  name = "collapse";
+	  pc = &OMP_CLAUSE_CHAIN (c);
+	  continue;
 	case OMP_CLAUSE_FINAL:
+	  name = "final";
+	  pc = &OMP_CLAUSE_CHAIN (c);
+	  continue;
 	case OMP_CLAUSE_MERGEABLE:
+	  name = "mergeable";
+	  pc = &OMP_CLAUSE_CHAIN (c);
+	  continue;
 	case OMP_CLAUSE_SAFELEN:
+	  name = "safelen";
+	  pc = &OMP_CLAUSE_CHAIN (c);
+	  continue;
 	case OMP_CLAUSE_SIMDLEN:
+	  name = "simdlen";
+	  pc = &OMP_CLAUSE_CHAIN (c);
+	  continue;
 	case OMP_CLAUSE_DEVICE:
+	  name = "device";
+	  pc = &OMP_CLAUSE_CHAIN (c);
+	  continue;
 	case OMP_CLAUSE_DIST_SCHEDULE:
+	  name = "dist_schedule";
+	  pc = &OMP_CLAUSE_CHAIN (c);
+	  continue;
+	case OMP_CLAUSE_INBRANCH:
+	  name = "inbranch";
+	  pc = &OMP_CLAUSE_CHAIN (c);
+	  continue;
+	case OMP_CLAUSE_NOTINBRANCH:
+	  name = "notinbranch";
+	  pc = &OMP_CLAUSE_CHAIN (c);
+	  continue;
 	case OMP_CLAUSE_PARALLEL:
+	  name = "parallel"; 
+	  pc = &OMP_CLAUSE_CHAIN (c);
+	  continue;
 	case OMP_CLAUSE_FOR:
+	  name = "for";
+	  pc = &OMP_CLAUSE_CHAIN (c);
+	  continue;
 	case OMP_CLAUSE_SECTIONS:
+	  name = "sections";
+	  pc = &OMP_CLAUSE_CHAIN (c);
+	  continue;
 	case OMP_CLAUSE_TASKGROUP:
+	  name = "taskgroup";
+	  pc = &OMP_CLAUSE_CHAIN (c);
+	  continue;
 	case OMP_CLAUSE_PROC_BIND:
+	  name = "proc_bind";
 	  pc = &OMP_CLAUSE_CHAIN (c);
 	  continue;
 
diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/body.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/body.c
new file mode 100644
index 0000000..50b3ab1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/body.c
@@ -0,0 +1,35 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O3 -fcilkplus -fopenmp" } */
+
+int *a, *b, c;
+void *jmpbuf[10];
+
+void foo()
+{
+  int i, j;
+
+#pragma simd
+  for (i=0; i < 1000; ++i)
+    {
+      if (c == 5)
+	return;	 /* { dg-error "return statments are not allowed" } */
+      if (c == 6)
+	__builtin_setjmp (jmpbuf); /* { dg-error "calls to setjmp are not allowed" } */
+      a[i] = b[i];
+    }
+
+#pragma simd
+  for (i=0; i < 1000; ++i)
+    {
+      if (c==5)
+	break; /* { dg-error "break statement within" } */
+    }
+
+#pragma simd
+  for (i=0; i < 1000; ++i)
+    {
+#pragma omp for /* { dg-error "OpenMP statements are not allowed" } */
+      for (j=0; j < 1000; ++j)
+	a[i] = b[i];
+    }
+}
diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/cilk-simd-compile.exp b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/cilk-simd-compile.exp
new file mode 100644
index 0000000..154bb8c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/cilk-simd-compile.exp
@@ -0,0 +1,23 @@ 
+#   Copyright (C) 2013 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+load_lib gcc-dg.exp
+
+set OPTS "-fcilkplus -c -ftree-vectorize"
+
+dg-init
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] " $OPTS" " "
+dg-finish
diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses1.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses1.c
new file mode 100644
index 0000000..d0a2f79
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses1.c
@@ -0,0 +1,76 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O3 -std=c99 -fcilkplus -Werror -Wunknown-pragmas" } */
+
+volatile int *a, *b;
+
+void foo()
+{
+  int i, j, k;
+
+#pragma simd assert /* { dg-error "expected '#pragma simd' clause" } */
+  for (i=0; i < 100; ++i)
+    a[i] = b[i];
+
+#pragma simd vectorlength /* { dg-error "expected '\\('" } */
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd vectorlength /* { dg-error "expected '\\('" } */
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd vectorlength(sizeof (a) == sizeof (float) ? 4 : 8)
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd vectorlength(4,8) /* { dg-error "expected '\\)'" } */
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd vectorlength(i) /* { dg-error "vectorlength must be an integer" } */
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd linear(35) /* { dg-error "expected identifier" } */
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd linear(blah) /* { dg-error "'blah' undeclared" } */
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd linear(j, 36, k) /* { dg-error "expected '\\)'" } */
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd linear(i, j)
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd linear(i)
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd linear(i : 4)
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd linear(i : 2, j : 4, k)
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd linear(j : sizeof (a) == sizeof (float) ? 4 : 8)
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+  // And now everyone in unison!
+#pragma simd linear(j : 4) vectorlength(4)
+  for (i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd linear(blah2, 36)
+  /* { dg-error "'blah2' undeclared" "undeclared" { target *-*-* } 71 } */
+  /* { dg-error "expected '\\)'" "expected" { target *-*-* } 71 } */
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+}
diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses2.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses2.c
new file mode 100644
index 0000000..ca99ca8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses2.c
@@ -0,0 +1,18 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O3 -std=c99 -fcilkplus -fdump-tree-original" } */
+
+volatile int *a, *b;
+
+void foo()
+{
+  int i, j, k;
+
+#pragma simd linear(j : 4, k) vectorlength(4)
+  for (i=0; i < 1000; ++i)
+    a[i] = b[j];
+}
+
+/* { dg-final { scan-tree-dump-times "linear\\(j:4\\)" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "linear\\(k:1\\)" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "safelen\\(4\\)" 1 "original" } } */
+/* { dg-final { cleanup-tree-dump "original" } } */
diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses3.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses3.c
new file mode 100644
index 0000000..5536884
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses3.c
@@ -0,0 +1,41 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O3 -std=c99 -fcilkplus" } */
+
+#define N 1000
+
+int A[N], B[N], C[N];
+int main (void)
+{
+  int ii = 0;
+
+#pragma simd private (B) linear(B:1) /* { dg-error "more than one clause" } */
+  for (ii = 0; ii < N; ii++)
+    {
+      A[ii] = B[ii] + C[ii];
+    }
+
+#pragma simd private (B, C) linear(B:1) /* { dg-error "more than one clause" } */
+  for (ii = 0; ii < N; ii++)
+    {
+      A[ii] = B[ii] + C[ii];
+    }
+
+#pragma simd private (B) linear(C:2, B:1) /* { dg-error "more than one clause" } */
+  for (ii = 0; ii < N; ii++)
+    {
+      A[ii] = B[ii] + C[ii];
+    }
+
+#pragma simd reduction (+:B) linear(B:1) /* { dg-error "more than one clause" } */
+  for (ii = 0; ii < N; ii++)
+    {
+      A[ii] = B[ii] + C[ii];
+    }
+
+#pragma simd reduction (+:B) linear(B) /* { dg-error "more than one clause" } */
+  for (ii = 0; ii < N; ii++)
+    {
+      A[ii] = B[ii] + C[ii];
+    }
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for1.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for1.c
new file mode 100644
index 0000000..f8cc558
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for1.c
@@ -0,0 +1,144 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O3 -std=c99 -fcilkplus" } */
+
+int *a, *b, *c;
+int something;
+
+void foo()
+{
+  int i, j;
+
+  // The initialization shall declare or initialize a *SINGLE* variable.
+#pragma simd
+  for (i=0, j=5; i < 1000; i++) // { dg-error "expected ';' before ','" }
+    a[i] = b[j];
+
+  // Declaration and initialization is allowed.
+#pragma simd
+  for (int i=0; i < 1000; i++)
+    a[i] = b[j];
+
+  // Empty initialization is not allowed.
+#pragma simd
+  for (; i < 5; ++i)		// { dg-error "expected iteration decl" }
+    a[i] = i;
+
+  // Empty condition is not allowed.
+#pragma simd
+  for (i=0; ; ++i)		/* { dg-error "missing condition" } */
+    a[i] = i;
+
+  // Empty increment is not allowed.
+#pragma simd
+  for (i=0; i < 1234; )		/* { dg-error "missing increment" } */
+    a[i] = i*2;
+
+#pragma simd
+  i = 5; /* { dg-error "for statement expected" } */
+
+  // Initialization variables must be either integral or pointer types.
+  struct S {
+    int i;
+  };
+#pragma simd
+  for (struct S ss = { 0 }; ss.i <= 1000; ++ss.i) /* { dg-error "initialization variable must be of integral or pointer type" } */
+    a[ss.i] = b[ss.i];
+
+  #pragma simd
+  for (float f=0.0; f < 15.0; ++f) /* { dg-error "must be of integral" } */
+    a[(int)f] = (int) f;
+
+  // Pointers are OK.
+  #pragma simd
+  for (int *i=c; i < &c[100]; ++i)
+    *a = '5';
+
+  // Condition of '==' is not allowed.
+#pragma simd
+  for (i=j; i == 5; ++i) /* { dg-error "invalid controlling predicate" } */
+    a[i] = b[i];
+
+  // The LHS or RHS of the condition must be the initialization variable.
+#pragma simd
+  for (i=0; i+j < 1234; ++i) /* { dg-error "invalid controlling predicate" } */
+    a[i] = b[i];  
+
+  // Likewise.
+#pragma simd
+  for (i=0; 1234 < i + j; ++i) /* { dg-error "invalid controlling predicate" } */
+    a[i] = b[i];  
+
+  // Likewise, this is ok.
+#pragma simd
+  for (i=0; 1234 + j < i; ++i)
+    a[i] = b[i];
+
+  // According to the CilkPlus forum, casts are not allowed, even if
+  // they are no-ops.
+#pragma simd
+  for (i=0; (char)i < 1234; ++i) /* { dg-error "invalid controlling predicate" } */
+    a[i] = b[i];
+
+#pragma simd
+  for (i=255; i != something; --i)
+    a[i] = b[i];
+
+  // This condition gets folded into "i != 0" by
+  // c_parser_cilk_for_statement().  This is allowed as per the "!="
+  // allowance above.
+#pragma simd
+  for (i=100; i; --i)
+    a[i] = b[i];
+
+#pragma simd
+  for (i=100; i != 5; i += something)
+    a[i] = b[i];
+
+  // Increment must be on the induction variable.
+#pragma simd
+  for (i=0; i < 100; j++) /* { dg-error "invalid increment expression" } */
+    a[i] = b[i];
+
+  // Likewise.
+#pragma simd
+  for (i=0; i < 100; j = i + 1) /* { dg-error "invalid increment expression" } */
+    a[i] = b[i];
+
+  // Likewise.
+#pragma simd
+  for (i=0; i < 100; i = j + 1) /* { dg-error "invalid increment expression" } */
+    a[i] = b[i];
+
+#pragma simd
+  for (i=0; i < 100; i = i + 5)
+    a[i] = b[i];
+
+  // Only PLUS and MINUS increments are allowed.
+#pragma simd
+  for (i=0; i < 100; i *= 5) /* { dg-error "invalid increment expression" } */
+    a[i] = b[i];
+
+#pragma simd
+  for (i=0; i < 100; i -= j)
+    a[i] = b[i];
+
+#pragma simd
+  for (i=0; i < 100; i = i + j)
+    a[i] = b[i];
+
+#pragma simd
+  for (i=0; i < 100; i = j + i)
+    a[i] = b[i];
+
+#pragma simd
+  for (i=0; i < 100; ++i, ++j) /* { dg-error "invalid increment expression" } */
+    a[i] = b[i];
+
+#pragma simd
+  for (int *point=0; point < b; ++point)
+    *point = 555;
+
+#pragma simd
+  for (int *point=0; point > b; --point)
+    *point = 555;
+}
diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for2.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for2.c
new file mode 100644
index 0000000..2d09ae8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for2.c
@@ -0,0 +1,66 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O3 -std=c99 -fcilkplus" } */
+
+// Test storage classes in the initialization of a <#pragma simd> for
+// loop.
+
+int *a, *b;
+
+void foo()
+{
+#pragma simd
+  for (static int foo=5; foo < 10; ++foo)
+    a[foo] = b[foo];
+  /* { dg-error "declaration of static variable" "storage class1" { target *-*-* } 12 } */
+  /* { dg-error "induction variable cannot be static" "storage class2" { target *-*-* } 12 } */
+
+  static int bar;
+#pragma simd
+  for (bar=0; bar < 1000; ++bar) /* { dg-error "induction variable cannot be static" } */
+    a[bar] = bar;
+
+#pragma simd
+  for (extern int var=0; var < 1000; ++var)
+    a[var] = var;
+  /* { dg-error "has both 'extern' and initializer" "extern" { target *-*-* } 23 } */
+  /* { dg-error "declaration of static variable" "" { target *-*-* } 23 } */
+  /* { dg-error "induction variable cannot be static" "" { target *-*-* } 23 } */
+
+  extern int extvar;
+#pragma simd
+  for (extvar = 0; extvar < 1000; ++extvar) /* { dg-error "induction variable cannot be extern" } */
+    b[extvar] = a[extvar];
+
+  // This seems like it should be ok.
+  // Must check with standards people.
+#pragma simd
+  for (auto int autoi = 0; autoi < 1000; ++autoi)
+    b[autoi] = a[autoi] * 2;
+  // Similarly here.
+  auto int autoj;
+#pragma simd
+  for (auto int autoj = 0; autoj < 1000; ++autoj)
+    b[autoj] = a[autoj] * 2;
+
+  register int regi;
+#pragma simd
+  for (regi = 0; regi < 1000; ++regi) /* { dg-error "induction variable cannot be declared register" } */
+    b[regi] = a[regi] * 2;
+
+#pragma simd
+  for (register int regj = 0; regj < 1000; ++regj) /* { dg-error "induction variable cannot be declared register" } */
+    b[regj] = a[regj] * 2;
+
+  volatile int vi;
+#pragma simd
+  for (vi=0; vi<1000; ++vi) /* { dg-error "induction variable cannot be volatile" } */
+    a[vi] = b[vi];
+
+#pragma simd
+  for (volatile int vj=0; vj<1000; ++vj) /* { dg-error "induction variable cannot be volatile" } */
+    a[vj] = b[vj];
+
+#pragma simd
+  for (const int ci=0; ci<1000; ++ci) /* { dg-error "increment of read-only var" } */
+    a[ci] = b[ci];
+}
diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for3.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for3.c
new file mode 100644
index 0000000..8660627
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for3.c
@@ -0,0 +1,8 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O3 -fcilkplus" } */
+
+#pragma simd		/* { dg-error "must be inside a function" } */
+
+void foo()
+{
+}
diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/safelen.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/safelen.c
new file mode 100644
index 0000000..430aa41
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/safelen.c
@@ -0,0 +1,15 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O3 -fcilkplus -fdump-tree-gimple" } */
+
+int *a, *b;
+
+void foo()
+{
+  int i;
+#pragma simd vectorlength(8)
+  for (i=0; i < 1000; ++i)
+    a[i] = b[i];
+}
+
+/* { dg-final { scan-tree-dump-times "safelen\\(8\\)" 1 "gimple" } } */
+/* { dg-final { cleanup-tree-dump "gimple" } } */
diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/vectorlength.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/vectorlength.c
new file mode 100644
index 0000000..4bff17d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/vectorlength.c
@@ -0,0 +1,22 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O3 -fcilkplus" } */
+
+volatile int *a, *b, N;
+typedef int tint;
+struct someclass {
+  int a;
+  char b;
+  int *p;
+};
+
+void foo()
+{
+  int i;
+#pragma simd vectorlength(4) vectorlength(8) /* { dg-error "too many 'vectorlength' clauses" } */
+  for (i=0; i < N; ++i)
+    a[i] = b[i];
+
+#pragma simd vectorlength(3) /* { dg-error "must be a power of 2" } */
+  for (i=0; i < N; ++i)
+    a[i] = b[i];
+}