[omp4/cilkplus] jumps in/out-of #pragma simd for
diff mbox

Message ID 51C44438.1040003@redhat.com
State New
Headers show

Commit Message

Aldy Hernandez June 21, 2013, 12:16 p.m. UTC
[list copied]

On 06/20/13 11:20, Jakub Jelinek wrote:
> On Wed, Jun 19, 2013 at 05:08:38PM -0500, Aldy Hernandez wrote:
>> On 06/19/13 16:43, Jakub Jelinek wrote:
>>> On Wed, Jun 19, 2013 at 04:39:52PM -0500, Aldy Hernandez wrote:
>>>> Jumps are disallowed into or out of the body of the for loop
>>>> associated with a #pragma simd.

> I guess my preference would be CILK_SIMD tree (handled the same
> as OMP_SIMD during genericization/instantiation), and let
> gimplification turn that into (note CILKSIMD added, and everything
> reordered):
> GF_OMP_FOR_KIND_FOR		0 << 0	#pragma omp for
> GF_OMP_FOR_KIND_DISTRIBUTE	1 << 0	#pragma omp distribute
> GF_OMP_FOR_KIND_SIMD		2 << 0	#pragma omp simd
> GF_OMP_FOR_KIND_CILKSIMD	3 << 0	#pragma simd
>
> This way, when testing for whether it is any kind of simd
> we can use gimple_omp_for_kind (stmt) & GF_OMP_FOR_KIND_SIMD
> instead of the current gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_SIMD
> test, and the equality can be tested where we expect differences
> (say, in the diagnostics - provide different wording), or in nesting
> restrictions/combined constructs etc.

I have done as suggested, and cleaned things up along the way.

I believe this is the last remaining TODO on my Cilk Plus pragma simd 
list.  Everything else is dependent on OMP4.

Is this what you had in mind?

If you'd like, I can submit the OMP changes separately so we can put 
them on the OMP4 branch.  However, my plan is to start pushing the OMP4 
supporting bits (from gomp-4_0-branch) and the Cilk Plus #pragma simd 
support (from aldyh/cilk-in-gomp) next week, so perhaps everything will 
fall into place shortly.  As you wish...

Aldy
commit 0d0061a495d9adec95d67eafa0baac2b77396392
Author: Aldy Hernandez <aldyh@redhat.com>
Date:   Thu Jun 20 19:26:12 2013 -0500

    Implement a new CILK_SIMD tree code and gimplify it into GIMPLE_OMP_FOR with
    an appropriate annotation.

Comments

Jakub Jelinek June 21, 2013, 12:59 p.m. UTC | #1
On Fri, Jun 21, 2013 at 07:16:56AM -0500, Aldy Hernandez wrote:
> I have done as suggested, and cleaned things up along the way.
> 
> I believe this is the last remaining TODO on my Cilk Plus pragma
> simd list.  Everything else is dependent on OMP4.
> 
> Is this what you had in mind?

Roughly, yes.

You don't handle CILK_SIMD in pt.c (but perhaps this is for C FE only so
far).

> --- a/gcc/gimplify.c
> +++ b/gcc/gimplify.c
> @@ -6838,6 +6839,8 @@ find_combined_omp_for (tree *tp, int *walk_subtrees, void *)
>        *walk_subtrees = 1;
>        /* FALLTHRU */
>      case OMP_SIMD:
> +    case CILK_SIMD:
> +      /* ?? Hmmm, is this the right way to handle CILK_SIMD?  */
>        if (OMP_FOR_INIT (*tp) != NULL_TREE)

CILK_SIMD can't be ever combined with #pragma omp for or #pragma omp
distribute, so no, the above is wrong, just don't list CILK_SIMD there.
>  	return *tp;
>        break;
> @@ -6868,9 +6871,11 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
>  
>    orig_for_stmt = for_stmt = *expr_p;
>  
> -  simd = TREE_CODE (for_stmt) == OMP_SIMD;
> +  simd = TREE_CODE (for_stmt) == OMP_SIMD
> +    || TREE_CODE (for_stmt) == CILK_SIMD;
>    gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p,
> -			     TREE_CODE (for_stmt) == OMP_SIMD
> +			     (TREE_CODE (for_stmt) == OMP_SIMD
> +			      || TREE_CODE (for_stmt) == CILK_SIMD)

I guess this should be just "simd ? ORT_SIMD : ORT_WORKSHARE);" then.

>  			     ? ORT_SIMD : ORT_WORKSHARE);

>  	case NE_EXPR:
> -	  if (!flag_enable_cilk)
> +	  /* NE_EXPR is only allowed for Cilk Plus loops.  */
> +	  if (flag_enable_cilk

Very weird name of a flag.  Should have been flag_cilk or flag_cilkplus
IMHO.

>    if (copyin_by_ref || lastprivate_firstprivate)
>      {
> -      /* Don't add any barrier for #pragma omp simd.  */
> +      /* Don't add any barrier for #pragma omp simd or #pragma simd.  */
>        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_SIMD))
>  	gimplify_and_add (build_omp_barrier (), ilist);

This one will clash with a change I'm working on right now (we don't
want a barrier for distribute either, so this is now
|| gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_FOR

	Jakub
Richard Henderson June 21, 2013, 3:37 p.m. UTC | #2
>  	case NE_EXPR:
> -	  if (!flag_enable_cilk)
> +	  /* NE_EXPR is only allowed for Cilk Plus loops.  */
> +	  if (flag_enable_cilk
> +	      && gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_CILKSIMD)
> +	    break;
> +	  else
>  	    gcc_unreachable ();
> -	  /* NE_EXPR is technically not allowed in OpenMP, but it is
> -	     allowed in Cilk Plus, which generates OMP_SIMD constructs.  */
> -	  break;

Something I'm going to bring up wrt the main cilk+ patches, but checking
flag_enable_cilk is useless.  One can only get KIND_CILKSIMD if cilk is
enabled, and the test itself is very inexpensive.

Better as

  if (gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_CILKSIMD)
    {
      // if you really thing we need to check it...
      gcc_checking_assert (flag_enable_cilk);
      break;
    }
  gcc_unreachable ();

Or, best as

  gcc_checking_assert (flag_enable_cilk);
  gcc_assert (gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_CILKSIMD);
  break;

since I believe the front end should have already checked this grammar.

> +  bool cilkplus_block = false;
> +  if (flag_enable_cilk)
> +    {
> +      if ((branch_ctx
> +	   && gimple_code (branch_ctx) == GIMPLE_OMP_FOR
> +	   && gimple_omp_for_kind (branch_ctx) & GF_OMP_FOR_KIND_CILKSIMD)
> +	  || (gimple_code (label_ctx) == GIMPLE_OMP_FOR
> +	      && gimple_omp_for_kind (label_ctx) & GF_OMP_FOR_KIND_CILKSIMD))
> +	cilkplus_block = true;
> +    }

The & tests here aren't right.  Recall that CILKSIMD == 3 << 3, so that covers
DISTRIBUTE and normal SIMD as well.  The only & tests should have been for SIMD
when one wants both SIMD and CILKSIMD.


r~

Patch
diff mbox

diff --git a/gcc/ChangeLog.cilkplus b/gcc/ChangeLog.cilkplus
index 6a48ada..4ca0c67 100644
--- a/gcc/ChangeLog.cilkplus
+++ b/gcc/ChangeLog.cilkplus
@@ -1,9 +1,23 @@ 
-2013-05-13  Aldy Hernandez  <aldyh@redhat.com>
+2013-06-20  Aldy Hernandez  <aldyh@redhat.com>
 	    Balaji V. Iyer  <balaji.v.iyer@intel.com>
 
 	* Makefile.in (C_COMMON_OBJS): Depend on c-family/c-cilkplus.o.
 	(c-cilkplus.o): New dependency.
 	* omp-low.c (extract_omp_for_data): Add case for NE_EXPR.
+	(build_outer_var_ref): Check for GF_OMP_FOR_KIND_SIMD bitwise.
+	(check_omp_nesting_restrictions): Same.
+	(lower_rec_input_clauses): Same.
+	(expand_omp_for): Same.
+	(lower_omp_for): Same.
+	(diagnose_sb_0): Adjust for Cilk Plus for loops.
+	* tree.def (CILK_SIMD): New entry.
+	* tree-pretty-print.c (dump_generic_node): Add case for CILK_SIMD.
+	* gimple-pretty-print.c (dump_gimple_omp_for): Add case for
+	GF_OMP_FOR_KIND_CILKSIMD.
+	* gimplify.c (gimplify_omp_for): Add case for CILK_SIMD.
+	(gimplify_expr): Same.
+	(is_gimple_stmt): Same.
+	(find_combined_omp_for): Same.
 
 c-family/
 	* c-cilkplus.c: New.
diff --git a/gcc/c-family/c-cilkplus.c b/gcc/c-family/c-cilkplus.c
index 12097e0..861bcbc 100644
--- a/gcc/c-family/c-cilkplus.c
+++ b/gcc/c-family/c-cilkplus.c
@@ -120,24 +120,8 @@  c_validate_cilk_plus_loop (tree *tp, int *walk_subtrees, void *data)
 
   bool *valid = (bool *) data;
 
-  /* 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);
@@ -358,23 +342,11 @@  c_finish_cilk_simd_loop (location_t loc,
   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 t = make_node (CILK_SIMD);
   TREE_TYPE (t) = void_type_node;
   OMP_FOR_INIT (t) = initv;
-
-  /* ?? 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."  Perhaps the RHS of the
-     condition and increment could be wrapped in a SAVE_EXPR to
-     evaluate only once.  */
   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);
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 3793bd9..c20d91c 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -12123,11 +12123,6 @@  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);
 }
 
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index bced6c3..a4ef585 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -30420,10 +30420,6 @@  cp_parser_cilk_simd_construct (cp_parser *parser, cp_token *pragma_token)
       return;
     }
 
-  /* #pragma simd is built on top of OpenMP 4.0's OMP_SIMD trees.  */
-  if (!flag_openmp)
-    flag_openmp = true;
-
   tree sb = begin_omp_structured_block ();
   int save = cp_parser_begin_omp_structured_block (parser);
   cp_parser_cilk_for (parser, RID_FOR, clauses);
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index ba7993a..8c92b5b 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -1110,6 +1110,9 @@  dump_gimple_omp_for (pretty_printer *buffer, gimple gs, int spc, int flags)
 	case GF_OMP_FOR_KIND_SIMD:
 	  kind = " simd";
 	  break;
+	case GF_OMP_FOR_KIND_CILKSIMD:
+	  kind = " cilksimd";
+	  break;
 	case GF_OMP_FOR_KIND_DISTRIBUTE:
 	  kind = " distribute";
 	  break;
@@ -1141,6 +1144,9 @@  dump_gimple_omp_for (pretty_printer *buffer, gimple gs, int spc, int flags)
 	case GF_OMP_FOR_KIND_SIMD:
 	  pp_string (buffer, "#pragma omp simd");
 	  break;
+	case GF_OMP_FOR_KIND_CILKSIMD:
+	  pp_string (buffer, "#pragma simd");
+	  break;
 	case GF_OMP_FOR_KIND_DISTRIBUTE:
 	  pp_string (buffer, "#pragma omp distribute");
 	  break;
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 08dacc5..6987df5 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -111,9 +111,10 @@  enum gf_mask {
     GF_CALL_INTERNAL		= 1 << 6,
     GF_OMP_PARALLEL_COMBINED	= 1 << 0,
     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_DISTRIBUTE	= 2 << 0,
+    GF_OMP_FOR_KIND_FOR		= 0 << 0, /* #pragma omp for */
+    GF_OMP_FOR_KIND_DISTRIBUTE	= 1 << 0, /* #pragma omp distribute */
+    GF_OMP_FOR_KIND_SIMD	= 2 << 0, /* #pragma omp simd */
+    GF_OMP_FOR_KIND_CILKSIMD	= 3 << 0, /* (Cilk Plus) #pragma simd */
     GF_OMP_FOR_COMBINED		= 4 << 0,
     GF_OMP_TARGET_KIND_MASK	= 3 << 0,
     GF_OMP_TARGET_KIND_REGION	= 0 << 0,
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 78ba9da..3d2f385 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -4716,6 +4716,7 @@  is_gimple_stmt (tree t)
     case OMP_PARALLEL:
     case OMP_FOR:
     case OMP_SIMD:
+    case CILK_SIMD:
     case OMP_DISTRIBUTE:
     case OMP_SECTIONS:
     case OMP_SECTION:
@@ -6838,6 +6839,8 @@  find_combined_omp_for (tree *tp, int *walk_subtrees, void *)
       *walk_subtrees = 1;
       /* FALLTHRU */
     case OMP_SIMD:
+    case CILK_SIMD:
+      /* ?? Hmmm, is this the right way to handle CILK_SIMD?  */
       if (OMP_FOR_INIT (*tp) != NULL_TREE)
 	return *tp;
       break;
@@ -6868,9 +6871,11 @@  gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
 
   orig_for_stmt = for_stmt = *expr_p;
 
-  simd = TREE_CODE (for_stmt) == OMP_SIMD;
+  simd = TREE_CODE (for_stmt) == OMP_SIMD
+    || TREE_CODE (for_stmt) == CILK_SIMD;
   gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p,
-			     TREE_CODE (for_stmt) == OMP_SIMD
+			     (TREE_CODE (for_stmt) == OMP_SIMD
+			      || TREE_CODE (for_stmt) == CILK_SIMD)
 			     ? ORT_SIMD : ORT_WORKSHARE);
 
   /* Handle OMP_FOR_INIT.  */
@@ -7108,6 +7113,7 @@  gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
     {
     case OMP_FOR: kind = GF_OMP_FOR_KIND_FOR; break;
     case OMP_SIMD: kind = GF_OMP_FOR_KIND_SIMD; break;
+    case CILK_SIMD: kind = GF_OMP_FOR_KIND_CILKSIMD; break;
     case OMP_DISTRIBUTE: kind = GF_OMP_FOR_KIND_DISTRIBUTE; break;
     default:
       gcc_unreachable ();
@@ -8110,6 +8116,14 @@  gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
 	  ret = GS_ALL_DONE;
 	  break;
 
+	case CILK_SIMD:
+	  /* For <#pragma simd> we will be generating GIMPLE_OMP_FOR
+	     with GF_OMP_FOR_KIND_CILKSIMD and let the OpenMP
+	     mechanism handle everything.  */
+	  if (!flag_openmp)
+	    flag_openmp = true;
+	  /* FALLTHRU */
+
 	case OMP_FOR:
 	case OMP_SIMD:
 	case OMP_DISTRIBUTE:
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index 0065443..3b88906 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -223,7 +223,7 @@  extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd,
   int i;
   struct omp_for_data_loop dummy_loop;
   location_t loc = gimple_location (for_stmt);
-  bool non_ws = gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_SIMD;
+  bool non_ws = gimple_omp_for_kind (for_stmt) & GF_OMP_FOR_KIND_SIMD;
   bool distribute = gimple_omp_for_kind (for_stmt)
 		    == GF_OMP_FOR_KIND_DISTRIBUTE;
 
@@ -317,11 +317,12 @@  extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd,
 	case GT_EXPR:
 	  break;
 	case NE_EXPR:
-	  if (!flag_enable_cilk)
+	  /* NE_EXPR is only allowed for Cilk Plus loops.  */
+	  if (flag_enable_cilk
+	      && gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_CILKSIMD)
+	    break;
+	  else
 	    gcc_unreachable ();
-	  /* NE_EXPR is technically not allowed in OpenMP, but it is
-	     allowed in Cilk Plus, which generates OMP_SIMD constructs.  */
-	  break;
 	case LE_EXPR:
 	  if (POINTER_TYPE_P (TREE_TYPE (loop->n2)))
 	    loop->n2 = fold_build_pointer_plus_hwi_loc (loc, loop->n2, 1);
@@ -945,7 +946,7 @@  build_outer_var_ref (tree var, omp_context *ctx)
       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)
+	   && 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.  */
@@ -1891,7 +1892,7 @@  check_omp_nesting_restrictions (gimple stmt, omp_context *ctx)
   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_SIMD)
 	{
 	  error_at (gimple_location (stmt),
 		    "OpenMP constructs may not be nested inside simd region");
@@ -1922,7 +1923,7 @@  check_omp_nesting_restrictions (gimple stmt, omp_context *ctx)
   switch (gimple_code (stmt))
     {
     case GIMPLE_OMP_FOR:
-      if (gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_SIMD)
+      if (gimple_omp_for_kind (stmt) & GF_OMP_FOR_KIND_SIMD)
 	return true;
       if (gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_DISTRIBUTE)
 	{
@@ -2763,9 +2764,9 @@  lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
      happens after firstprivate copying in all threads.  */
   if (copyin_by_ref || lastprivate_firstprivate)
     {
-      /* Don't add any barrier for #pragma omp simd.  */
+      /* Don't add any barrier for #pragma omp simd or #pragma simd.  */
       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_SIMD))
 	gimplify_and_add (build_omp_barrier (), ilist);
     }
 }
@@ -5511,7 +5512,7 @@  expand_omp_for (struct omp_region *region)
        original loops from being detected.  Fix that up.  */
     loops_state_set (LOOPS_NEED_FIXUP);
 
-  if (gimple_omp_for_kind (fd.for_stmt) == GF_OMP_FOR_KIND_SIMD)
+  if (gimple_omp_for_kind (fd.for_stmt) & GF_OMP_FOR_KIND_SIMD)
     expand_omp_simd (region, &fd);
   else if (fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC
 	   && !fd.have_ordered
@@ -7203,7 +7204,7 @@  lower_omp_for (gimple_stmt_iterator *gsi_p, omp_context *ctx)
   /* Once lowered, extract the bounds and clauses.  */
   extract_omp_for_data (stmt, &fd, NULL);
 
-  if (gimple_omp_for_kind (fd.for_stmt) != GF_OMP_FOR_KIND_SIMD)
+  if (!(gimple_omp_for_kind (fd.for_stmt) & GF_OMP_FOR_KIND_SIMD))
     lower_omp_for_lastprivate (&fd, &body, &dlist, ctx);
 
   gimple_seq_add_stmt (&body, stmt);
@@ -7220,7 +7221,7 @@  lower_omp_for (gimple_stmt_iterator *gsi_p, omp_context *ctx)
 
   /* Region exit marker goes at the end of the loop body.  */
   gimple_seq_add_stmt (&body, gimple_build_omp_return (fd.have_nowait));
-  if (gimple_omp_for_kind (fd.for_stmt) == GF_OMP_FOR_KIND_SIMD)
+  if (gimple_omp_for_kind (fd.for_stmt) & GF_OMP_FOR_KIND_SIMD)
     {
       dlist = NULL;
       lower_lastprivate_clauses (gimple_omp_for_clauses (fd.for_stmt),
@@ -7888,12 +7889,33 @@  diagnose_sb_0 (gimple_stmt_iterator *gsi_p,
     error ("invalid entry to OpenMP structured block");
 #endif
 
+  bool cilkplus_block = false;
+  if (flag_enable_cilk)
+    {
+      if ((branch_ctx
+	   && gimple_code (branch_ctx) == GIMPLE_OMP_FOR
+	   && gimple_omp_for_kind (branch_ctx) & GF_OMP_FOR_KIND_CILKSIMD)
+	  || (gimple_code (label_ctx) == GIMPLE_OMP_FOR
+	      && gimple_omp_for_kind (label_ctx) & GF_OMP_FOR_KIND_CILKSIMD))
+	cilkplus_block = true;
+    }
+
   /* If it's obvious we have an invalid entry, be specific about the error.  */
   if (branch_ctx == NULL)
-    error ("invalid entry to OpenMP structured block");
+    {
+      if (cilkplus_block)
+	error ("invalid entry to Cilk Plus structured block");
+      else
+	error ("invalid entry to OpenMP structured block");
+    }
   else
-    /* Otherwise, be vague and lazy, but efficient.  */
-    error ("invalid branch to/from an OpenMP structured block");
+    {
+      /* Otherwise, be vague and lazy, but efficient.  */
+      if (cilkplus_block)
+	error ("invalid branch to/from a Cilk Plus structured block");
+      else
+	error ("invalid branch to/from an OpenMP structured block");
+    }
 
   gsi_replace (gsi_p, gimple_build_nop (), false);
   return true;
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/body.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/body.c
index fe8b630..e8e2066 100644
--- a/gcc/testsuite/c-c++-common/cilk-plus/PS/body.c
+++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/body.c
@@ -11,8 +11,6 @@  void foo()
 #pragma simd
   for (int i=0; i < 1000; ++i)
     {
-      if (c == 5)
-	return;	 /* { dg-error "\(return statments are not allowed\|invalid exit\)" } */
       if (c == 6)
 	__builtin_setjmp (jmpbuf); /* { dg-error "calls to setjmp are not allowed" } */
       a[i] = b[i];
diff --git a/gcc/testsuite/gcc.dg/cilk-plus/jump.c b/gcc/testsuite/gcc.dg/cilk-plus/jump.c
new file mode 100644
index 0000000..9ec3293
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cilk-plus/jump.c
@@ -0,0 +1,27 @@ 
+/* { dg-do compile } */
+/* { dg-options "-fcilkplus" } */
+
+int *a, *b, c;
+
+void foo()
+{
+#pragma simd
+  for (int i=0; i < 1000; ++i)
+    {
+      a[i] = b[i];
+      if (c == 5)
+	return;	 /* { dg-error "invalid branch to.from a Cilk" } */
+    }
+}
+
+void bar()
+{
+#pragma simd
+  for (int i=0; i < 1000; ++i)
+    {
+    lab:
+      a[i] = b[i];
+    }
+  if (c == 6)
+    goto lab; /* { dg-error "invalid entry to Cilk Plus" } */
+}
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index 9c3d15e..9c29a5b 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -2364,6 +2364,10 @@  dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
       pp_string (buffer, "#pragma omp simd");
       goto dump_omp_loop;
 
+    case CILK_SIMD:
+      pp_string (buffer, "#pragma simd");
+      goto dump_omp_loop;
+
     case OMP_DISTRIBUTE:
       pp_string (buffer, "#pragma omp distribute");
       goto dump_omp_loop;
diff --git a/gcc/tree.def b/gcc/tree.def
index a23d5bf..75b4d8a 100644
--- a/gcc/tree.def
+++ b/gcc/tree.def
@@ -1034,6 +1034,13 @@  DEFTREECODE (OMP_FOR, "omp_for", tcc_statement, 6)
    Operands like for OMP_FOR.  */
 DEFTREECODE (OMP_SIMD, "omp_simd", tcc_statement, 6)
 
+/* Cilk Plus - #pragma simd [clause1 ... clauseN]
+   Operands like for OMP_FOR.
+
+   NOTE: This must go between OMP_FOR and OMP_DISTRIBUTE, so
+   OMP_LOOP_CHECK works as expected.  */
+DEFTREECODE (CILK_SIMD, "cilk_simd", tcc_statement, 6)
+
 /* OpenMP - #pragma omp distribute [clause1 ... clauseN]
    Operands like for OMP_FOR.  */
 DEFTREECODE (OMP_DISTRIBUTE, "omp_distribute", tcc_statement, 6)