diff mbox

_Cilk_spawn and _Cilk_sync for C++

Message ID BF230D13CA30DD48930C31D4099330003A4AE578@FMSMSX101.amr.corp.intel.com
State New
Headers show

Commit Message

Iyer, Balaji V Dec. 3, 2013, 7:48 p.m. UTC
Hi Jason,
	I am attaching a fixed patch with answers to your questions below. The patch passes all the tests for C and C++ on my x86_64 SUSE box.

Thanks,

Balaji V. Iyer.

> -----Original Message-----
> From: Jason Merrill [mailto:jason@redhat.com]
> Sent: Monday, December 2, 2013 5:19 PM
> To: Iyer, Balaji V; gcc-patches@gcc.gnu.org
> Cc: Jeff Law
> Subject: Re: _Cilk_spawn and _Cilk_sync for C++
> 
> On 11/28/2013 11:40 AM, Iyer, Balaji V wrote:
> > Consider the following test case. I took this from the lambda_spawns.cc
> line #203.
> >
> > as you can tell, it is clobbering the lambda closure at the end of the lambda
> calling and then it is catching value of A from main2 as it is supposed to.
> 
> Yep, your patch gives a fine result for this testcase.
> 
> > What am I misunderstanding?
> 
> It just gets there for the wrong reason: remapping exactly nothing in the
> closure object happens to give the desired semantics, treating the
> temporaries in the CONSTRUCTOR as local to the spawned function and
> referring to variables from the spawning context via the nested function
> static chain.  But presumably you have all that remapping machinery there
> because doing nothing doesn't always give the desired result.  Right?
> 
> When you add CONSTRUCTOR handling to extract_free_variables, you get
> the crash in gimplify_var_or_parm_decl because you don't specifically handle
> VEC_INIT_EXPR, which needs to be handled a lot like TARGET_EXPR, and end
> up trying to pass the address of its temporary object into the spawned
> function, which doesn't work because, like a TARGET_EXPR, the temporary
> doesn't exist outside of the VEC_INIT_EXPR.  This doesn't mean that handling
> CONSTRUCTOR is wrong; leaving it out means that you aren't going to handle
> aggregate temporaries properly either.
> 
> I think it might be better for gimplify_cilk_spawn to gimplify the call
> expression first, and then do your transformation on the gimple, so you don't
> have to worry about language-specific magic.
> 
> Now, after all that I must admit that cilk_spawn could only ever see
> VEC_INIT_EXPR in the context of a lambda closure initialization, and the
> default behavior should always be correct for a lambda closure initialization,
> so I guess I'm willing to allow the magic lambda handling with a comment
> about it being a workaround.

Thanks for this! Where should I put this comment?

> 
> > +is_lambda_fn_p (tree call_exp)
> > +{
> > +  if (TREE_CODE (call_exp) != CALL_EXPR)
> > +    return false;
> > +  tree call_fn = CALL_EXPR_FN (call_exp);
> > +  if (TREE_CODE (call_fn) == ADDR_EXPR)
> > +    call_fn = TREE_OPERAND (call_fn, 0);
> 
> Use get_callee_fndecl to get the FUNCTION_DECL.  And change the name of
> the function, since it isn't testing whether the argument is itself a lambda
> function; perhaps call_to_lambda_fn_p?
> 

This is fixed.

> >         case CILK_SPAWN_STMT:
> >           gcc_assert
> >             (fn_contains_cilk_spawn_p (cfun)
> >              && lang_hooks.cilkplus.cilk_detect_spawn_and_unwrap (expr_p));
> >           if (!seen_error ())
> >             {
> >               ret = (enum gimplify_status)
> >                 lang_hooks.cilkplus.gimplify_cilk_spawn (expr_p, pre_p,
> >                                                          post_p);
> >               break;
> >             }
> >           /* If errors are seen, then just process it as a CALL_EXPR.
> > */
> 
> Please remove these langhooks and instead add handling of
> CILK_SPAWN_STMT to c_gimplify_expr and cp_gimplify_expr.

I mentioned this in a previous thread (http://gcc.gnu.org/ml/gcc-patches/2013-12/msg00244.html). 

> 
> >   lang_hooks.cilkplus.install_body_with_frame_cleanup (fndecl, stmt,
> >                                                        (void *) wd);
> 
> And instead of this langhook, declare a function in c-common.h that is
> defined by all C family front ends.
> 
> > +    stabilize_expr (orig_body, &pre_body);
> 
> Here you're pre-evaluating the entire call, rather than just the lambda
> closure object, which means none of the arguments to the call will be
> remapped.  I think you want
> 

I stabilize the call here, and then I call cilk_outline on the pre_body which will do the outlining of the arguments. Also, I don't need a specialized copy_tree_body_r for C++ to handle the lambda functions.

> CALL_EXPR_ARG (orig_body, 0)
>    = stabilize_expr (CALL_EXPR_ARG (orig_body, 0), &pre_body);
> append_to_statement_list (orig_body, &pre_body);
> 
> instead.
> 
> > +  gcc_assert (TREE_CODE (catch_list) == STATEMENT_LIST);
> 
> You don't need this, append_to_statement_list handles the list not yet being
> a list fine.

This is fixed.

> 
> > +       /* We set this here so that finish_call_expr can set lambda to a var.
> > +          if it is not done so.  */
> 
> This comment is obsolete.
> 

Fixed.

> > +       error_at (input_location, "_Cilk_sync cannot be used without enabling
> "
> > +                 "Cilk Plus");
> > +      cp_lexer_consume_token (parser->lexer);
> > +      if (parser->in_statement & IN_CILK_SPAWN)
> > +       parser->in_statement = parser->in_statement & ~IN_CILK_SPAWN;
> 
> Why are you messing with in_statement in the cilk_spawn code?
> 
This needed to catch cases like this:

_Cilk_spawn _Cilk_spawn foo () 

There could be other things between those two _Cilk_spawns   eg. '('.

But the comment above is misleading and I fixed that. Also, it should not be  = IN_CILK_SPAWN, but |= IN_CILK_SPAWN. I fixed that also.

Thanks,

Balaji V. Iyer.

> Jason

Comments

Jason Merrill Dec. 4, 2013, 7:45 p.m. UTC | #1
On 12/03/2013 02:48 PM, Iyer, Balaji V wrote:
>> Now, after all that I must admit that cilk_spawn could only ever see
>> VEC_INIT_EXPR in the context of a lambda closure initialization, and the
>> default behavior should always be correct for a lambda closure initialization,
>> so I guess I'm willing to allow the magic lambda handling with a comment
>> about it being a workaround.
>
> Thanks for this! Where should I put this comment?

In cp_cilk_install_body_wframe_cleanup, before the lambda handling.

>> Here you're pre-evaluating the entire call, rather than just the lambda
>> closure object, which means none of the arguments to the call will be
>> remapped.  I think you want
>
> I stabilize the call here, and then I call cilk_outline on the pre_body which will do the outlining of the arguments.

Ah, I see.  Then the stabilization isn't actually making a difference, 
as you're just shuffling things around rather than actually hiding them. 
  And indeed removing the special lambda handling doesn't prevent the 
tests from passing.  What's actually different about this patch is that 
you pass pre_body to cilk_outline and then ignore any changes 
cilk_outline made to it: the rest of the function goes back to looking 
at orig_body.  If I change the later references to use pre_body, we 
still get the crash.

>>> +       error_at (input_location, "_Cilk_sync cannot be used without enabling"
>>> +                 "Cilk Plus");
>>> +      cp_lexer_consume_token (parser->lexer);
>>> +      if (parser->in_statement & IN_CILK_SPAWN)
>>> +       parser->in_statement = parser->in_statement & ~IN_CILK_SPAWN;
>>
>> Why are you messing with in_statement in the cilk_spawn code?
>>
> This needed to catch cases like this:
>
> _Cilk_spawn _Cilk_spawn foo ()

Oops, I meant to say "in the cilk_sync code".  Why does finding a 
_Cilk_sync end the _Cilk_spawn context?

Jason
Jason Merrill Dec. 5, 2013, 9 p.m. UTC | #2
On 12/04/2013 02:45 PM, Jason Merrill wrote:
>>>> +       error_at (input_location, "_Cilk_sync cannot be used without
>>>> enabling"
>>>> +                 "Cilk Plus");
>>>> +      cp_lexer_consume_token (parser->lexer);
>>>> +      if (parser->in_statement & IN_CILK_SPAWN)
>>>> +       parser->in_statement = parser->in_statement & ~IN_CILK_SPAWN;
>>>
>>> Why are you messing with in_statement in the cilk_spawn code?
>>>
>> This needed to catch cases like this:
>>
>> _Cilk_spawn _Cilk_spawn foo ()
>
> Oops, I meant to say "in the cilk_sync code".  Why does finding a
> _Cilk_sync end the _Cilk_spawn context?

Ping, I think this question got lost in the discussion of the copy_body 
function.

Jason
Iyer, Balaji V Dec. 5, 2013, 9:24 p.m. UTC | #3
> -----Original Message-----
> From: Jason Merrill [mailto:jason@redhat.com]
> Sent: Thursday, December 5, 2013 4:00 PM
> To: Iyer, Balaji V; gcc-patches@gcc.gnu.org
> Cc: Jeff Law
> Subject: Re: _Cilk_spawn and _Cilk_sync for C++
> 
> On 12/04/2013 02:45 PM, Jason Merrill wrote:
> >>>> +       error_at (input_location, "_Cilk_sync cannot be used
> >>>> + without
> >>>> enabling"
> >>>> +                 "Cilk Plus");
> >>>> +      cp_lexer_consume_token (parser->lexer);
> >>>> +      if (parser->in_statement & IN_CILK_SPAWN)
> >>>> +       parser->in_statement = parser->in_statement &
> >>>> + ~IN_CILK_SPAWN;
> >>>
> >>> Why are you messing with in_statement in the cilk_spawn code?
> >>>
> >> This needed to catch cases like this:
> >>
> >> _Cilk_spawn _Cilk_spawn foo ()
> >
> > Oops, I meant to say "in the cilk_sync code".  Why does finding a
> > _Cilk_sync end the _Cilk_spawn context?
> 
> Ping, I think this question got lost in the discussion of the copy_body
> function.
> 

It doesn't. I just have an if statement to clear out IN_CILK_SPAWN if it is was still enabled (more like a safety measure). I have removed it.

> Jason
>
diff mbox

Patch

diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 664e928..f46008f 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1379,7 +1379,7 @@  extern vec <tree, va_gc> *fix_sec_implicit_args
 extern tree insert_cilk_frame (tree);
 extern void cilk_init_builtins (void);
 extern int gimplify_cilk_spawn (tree *, gimple_seq *, gimple_seq *);
-extern void c_cilk_install_body_w_frame_cleanup (tree, tree);
+extern void c_cilk_install_body_w_frame_cleanup (tree, tree, void *);
 extern bool cilk_detect_spawn_and_unwrap (tree *);
 extern bool cilk_set_spawn_marker (location_t, tree);
 extern tree build_cilk_sync (void);
@@ -1387,5 +1387,5 @@  extern tree build_cilk_spawn (location_t, tree);
 extern tree make_cilk_frame (tree);
 extern tree create_cilk_function_exit (tree, bool, bool);
 extern tree cilk_install_body_pedigree_operations (tree);
-
+extern void cilk_outline (tree, tree *, struct wrapper_data *);
 #endif /* ! GCC_C_COMMON_H */
diff --git a/gcc/c-family/cilk.c b/gcc/c-family/cilk.c
index c85b5f2..537a07b 100644
--- a/gcc/c-family/cilk.c
+++ b/gcc/c-family/cilk.c
@@ -477,7 +477,7 @@  wrapper_local_cb (const void *k_v, void **vp, void *data)
 
 /* Alter a tree STMT from OUTER_FN to form the body of INNER_FN.  */
 
-static void
+void
 cilk_outline (tree inner_fn, tree *stmt_p, struct wrapper_data *wd)
 {
   const tree outer_fn = wd->context;	      
@@ -512,8 +512,8 @@  cilk_outline (tree inner_fn, tree *stmt_p, struct wrapper_data *wd)
   /* We don't want the private variables any more.  */
   pointer_map_traverse (wd->decl_map, nested ? for_local_cb : wrapper_local_cb,
 			&id);
-
-  walk_tree (stmt_p, copy_tree_body_r, &id, NULL);
+  
+  walk_tree (stmt_p, copy_tree_body_r, (void *) &id, NULL);
 
   /* See if this function can throw or calls something that should
      not be spawned.  The exception part is only necessary if
@@ -554,10 +554,9 @@  create_cilk_wrapper_body (tree stmt, struct wrapper_data *wd)
   for (p = wd->parms; p; p = TREE_CHAIN (p))
     DECL_CONTEXT (p) = fndecl;
 
-  cilk_outline (fndecl, &stmt, wd);
-  stmt = fold_build_cleanup_point_expr (void_type_node, stmt);
   gcc_assert (!DECL_SAVED_TREE (fndecl));
-  lang_hooks.cilkplus.install_body_with_frame_cleanup (fndecl, stmt);
+  lang_hooks.cilkplus.install_body_with_frame_cleanup (fndecl, stmt, 
+						       (void *) wd);
   gcc_assert (DECL_SAVED_TREE (fndecl));
 
   pop_cfun_to (outer);
@@ -879,7 +878,7 @@  cilk_install_body_pedigree_operations (tree frame_ptr)
    spawn-helper and BODY is the newly created body for FNDECL.  */
 
 void
-c_cilk_install_body_w_frame_cleanup (tree fndecl, tree body)
+c_cilk_install_body_w_frame_cleanup (tree fndecl, tree body, void *wd)
 {
   tree list = alloc_stmt_list ();
   tree frame = make_cilk_frame (fndecl);
@@ -894,6 +893,10 @@  c_cilk_install_body_w_frame_cleanup (tree fndecl, tree body)
   
   tree detach_expr = build_call_expr (cilk_detach_fndecl, 1, frame_ptr); 
   append_to_statement_list (detach_expr, &body_list);
+ 
+  cilk_outline (fndecl, &body, (struct wrapper_data *) wd);
+  body = fold_build_cleanup_point_expr (void_type_node, body);
+
   append_to_statement_list (body, &body_list);
   append_to_statement_list (build_stmt (EXPR_LOCATION (body), TRY_FINALLY_EXPR,
 				       	body_list, dtor), &list);
diff --git a/gcc/cp/cp-cilkplus.c b/gcc/cp/cp-cilkplus.c
index 5c1090a..d65def6
--- a/gcc/cp/cp-cilkplus.c
+++ b/gcc/cp/cp-cilkplus.c
@@ -25,7 +25,10 @@ 
 #include "coretypes.h"
 #include "cp-tree.h"
 #include "diagnostic-core.h"
-
+#include "tree-iterator.h"
+#include "tree-inline.h"  /* for copy_tree_body_r.  */
+#include "ggc.h"
+#include "cilk.h"
 
 /* Callback for cp_walk_tree to validate the body of a pragma simd loop
    or _cilk_for loop.
@@ -75,3 +78,88 @@  cpp_validate_cilk_plus_loop (tree body)
 		(void *) &valid, NULL);
   return valid;
 }
+
+/* Sets the EXCEPTION bit (0x10) in the FRAME.flags field.  */
+
+static tree
+set_cilk_except_flag (tree frame)
+{
+  tree flags = cilk_dot (frame, CILK_TI_FRAME_FLAGS, 0);
+
+  flags = build2 (MODIFY_EXPR, void_type_node, flags,
+		  build2 (BIT_IOR_EXPR, TREE_TYPE (flags), flags,
+			  build_int_cst (TREE_TYPE (flags),
+					 CILK_FRAME_EXCEPTING)));
+  return flags;
+}
+
+/* Sets the frame.EXCEPT_DATA field to the head of the exception pointer.  */
+
+static tree
+set_cilk_except_data (tree frame)
+{
+  tree except_data = cilk_dot (frame, CILK_TI_FRAME_EXCEPTION, 0);
+  tree uresume_fn = builtin_decl_implicit (BUILT_IN_EH_POINTER);
+  tree ret_expr;
+  uresume_fn  = build_call_expr (uresume_fn, 1,
+				 build_int_cst (integer_type_node, 0));
+  ret_expr = build2 (MODIFY_EXPR, void_type_node, except_data, uresume_fn);
+  return ret_expr;
+}
+
+/* Returns true if the FUNCTION_DECL in call_exp, A CALL_EXPR tree is a
+   lambda function.  */
+
+static bool
+call_to_lambda_fn_p (tree call_exp)
+{
+  if (TREE_CODE (call_exp) != CALL_EXPR)
+    return false;
+  tree call_fn = get_callee_fndecl (call_exp);
+  if (call_fn && LAMBDA_FUNCTION_P (call_fn))
+    return true;
+  return false;
+}
+
+/* Installs BODY into function FNDECL with appropriate exception handling
+   code.  WD holds information of wrapper function used to pass into the
+   outlining function, cilk_outline.  */
+
+void
+cp_cilk_install_body_wframe_cleanup (tree fndecl, tree orig_body, void *wd)
+{
+  tree frame = make_cilk_frame (fndecl);
+  tree dtor = create_cilk_function_exit (frame, false, false);
+  add_local_decl (cfun, frame);
+
+  cfun->language = ggc_alloc_cleared_language_function ();
+  
+  location_t loc = EXPR_LOCATION (orig_body);
+  tree list = alloc_stmt_list ();
+  DECL_SAVED_TREE (fndecl) = list;
+  tree fptr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (frame)), frame);
+  tree body = cilk_install_body_pedigree_operations (fptr);
+  gcc_assert (TREE_CODE (body) == STATEMENT_LIST);
+  tree detach_expr = build_call_expr (cilk_detach_fndecl, 1, fptr);
+  append_to_statement_list (detach_expr, &body);
+  tree pre_body = NULL_TREE;
+  if (call_to_lambda_fn_p (orig_body))
+    stabilize_expr (orig_body, &pre_body);
+  else
+    pre_body = orig_body;
+  cilk_outline (fndecl, &pre_body, (struct wrapper_data *) wd);
+  orig_body = fold_build_cleanup_point_expr (void_type_node, orig_body);
+  append_to_statement_list (orig_body, &body);
+  if (flag_exceptions)
+    {
+      tree except_flag = set_cilk_except_flag (frame);
+      tree except_data = set_cilk_except_data (frame);
+      tree catch_list = alloc_stmt_list ();
+      append_to_statement_list (except_flag, &catch_list);
+      append_to_statement_list (except_data, &catch_list);
+      body = create_try_catch_expr (body, catch_list);
+    }
+  append_to_statement_list (build_stmt (loc, TRY_FINALLY_EXPR, body, dtor),
+			    &list);
+}
+
diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h
index ee22423..77a66c3 100644
--- a/gcc/cp/cp-objcp-common.h
+++ b/gcc/cp/cp-objcp-common.h
@@ -154,4 +154,14 @@  extern void cp_common_init_ts (void);
 #undef LANG_HOOKS_EH_PROTECT_CLEANUP_ACTIONS
 #define LANG_HOOKS_EH_PROTECT_CLEANUP_ACTIONS cp_protect_cleanup_actions
 
+#undef  LANG_HOOKS_CILKPLUS_GIMPLIFY_SPAWN
+#define LANG_HOOKS_CILKPLUS_GIMPLIFY_SPAWN gimplify_cilk_spawn
+
+#undef  LANG_HOOKS_CILKPLUS_DETECT_SPAWN_AND_UNWRAP
+#define LANG_HOOKS_CILKPLUS_DETECT_SPAWN_AND_UNWRAP  \
+    cilk_detect_spawn_and_unwrap
+
+#undef  LANG_HOOKS_CILKPLUS_FRAME_CLEANUP
+#define LANG_HOOKS_CILKPLUS_FRAME_CLEANUP cp_cilk_install_body_wframe_cleanup
+
 #endif /* GCC_CP_OBJCP_COMMON */
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 1fc4b59..109110b 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5356,6 +5356,7 @@  extern tree begin_eh_spec_block			(void);
 extern void finish_eh_spec_block		(tree, tree);
 extern tree build_eh_type_type			(tree);
 extern tree cp_protect_cleanup_actions		(void);
+extern tree create_try_catch_expr               (tree, tree);
 
 /* in expr.c */
 extern tree cplus_expand_constant		(tree);
@@ -6180,11 +6181,17 @@  extern void vtv_build_vtable_verify_fndecl      (void);
 
 /* In cp-cilkplus.c.  */
 extern bool cpp_validate_cilk_plus_loop		(tree);
+extern void cp_cilk_install_body_wframe_cleanup (tree, tree, void *);
 
 /* In cp/cp-array-notations.c */
 extern tree expand_array_notation_exprs         (tree);
 bool cilkplus_an_triplet_types_ok_p             (location_t, tree, tree, tree,
 						 tree);
+/* In c-family/cilk.c */
+extern bool cilk_valid_spawn                    (tree);
+extern int gimplify_cilk_spawn                  (tree *, gimple_seq *,
+						 gimple_seq *);
+
 /* -- end of C++ */
 
 #endif /* ! GCC_CP_TREE_H */
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 9508131..5e3c301 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -59,6 +59,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "splay-tree.h"
 #include "plugin.h"
 #include "cgraph.h"
+#include "cilk.h"
 
 /* Possible cases of bad specifiers type used by bad_specifiers. */
 enum bad_spec_place {
@@ -13883,6 +13884,9 @@  finish_function (int flags)
   /* If we're saving up tree structure, tie off the function now.  */
   DECL_SAVED_TREE (fndecl) = pop_stmt_list (DECL_SAVED_TREE (fndecl));
 
+  if (fn_contains_cilk_spawn_p (cfun) && !processing_template_decl)
+    cfun->cilk_frame_decl = insert_cilk_frame (fndecl);
+
   finish_fname_decls ();
 
   /* If this function can't throw any exceptions, remember that.  */
diff --git a/gcc/cp/except.c b/gcc/cp/except.c
index d7d009b..be487cd 100644
--- a/gcc/cp/except.c
+++ b/gcc/cp/except.c
@@ -1342,4 +1342,22 @@  build_noexcept_spec (tree expr, int complain)
     }
 }
 
+/* Returns a TRY_CATCH_EXPR that will put TRY_LIST and CATCH_LIST in the
+   TRY and CATCH locations.  CATCH_LIST must be a STATEMENT_LIST */
+
+tree
+create_try_catch_expr (tree try_expr, tree catch_list)
+{
+  location_t loc = EXPR_LOCATION (try_expr);
+ 
+  append_to_statement_list (do_begin_catch (), &catch_list);
+  append_to_statement_list (build_throw (NULL_TREE), &catch_list);
+  tree catch_tf_expr = build_stmt (loc, TRY_FINALLY_EXPR, catch_list, 
+				   do_end_catch (NULL_TREE));
+  catch_list = build2 (CATCH_EXPR, void_type_node, NULL_TREE,
+		       catch_tf_expr);
+  tree try_catch_expr = build_stmt (loc, TRY_CATCH_EXPR, try_expr, catch_list);
+  return try_catch_expr;
+}
+
 #include "gt-cp-except.h"
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index d7092cc..4b0d757 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -5627,6 +5627,7 @@  cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
   cp_id_kind idk = CP_ID_KIND_NONE;
   tree postfix_expression = NULL_TREE;
   bool is_member_access = false;
+  int saved_in_statement = -1;
 
   /* Peek at the next token.  */
   token = cp_lexer_peek_token (parser->lexer);
@@ -5771,6 +5772,68 @@  cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
       }
       break;
 
+    case RID_CILK_SPAWN:
+      {
+	cp_lexer_consume_token (parser->lexer);
+	token = cp_lexer_peek_token (parser->lexer);
+	if (token->type == CPP_SEMICOLON)
+	  {
+	    error_at (token->location, "%<_Cilk_spawn%> must be followed by "
+		      "an expression");
+	    postfix_expression = error_mark_node;
+	    break;
+	  }
+	else if (!current_function_decl)
+	  {
+	    error_at (token->location, "%<_Cilk_spawn%> may only be used "
+		      "inside a function");
+	    postfix_expression = error_mark_node;
+	    break;
+	  }
+	else
+	  {
+	    /* Consecutive _Cilk_spawns are not allowed in a statement.  */
+	    saved_in_statement = parser->in_statement;
+	    parser->in_statement |= IN_CILK_SPAWN;
+	  }
+	cfun->calls_cilk_spawn = 1;
+	postfix_expression = 
+	  cp_parser_postfix_expression (parser, false, false, 
+					false, false, &idk);
+	if (saved_in_statement & IN_CILK_SPAWN)
+	  {
+	    error_at (token->location, "consecutive %<_Cilk_spawn%> keywords "
+		      "are not permitted");
+	    postfix_expression = error_mark_node;
+	    cfun->calls_cilk_spawn = 0; 
+	  }
+	else
+	  {
+	    postfix_expression = build_cilk_spawn (token->location, 
+						   postfix_expression);
+	    if (postfix_expression != error_mark_node) 
+	      SET_EXPR_LOCATION (postfix_expression, input_location);
+	    parser->in_statement = parser->in_statement & ~IN_CILK_SPAWN;
+	  }
+	break;
+      }
+      
+    case RID_CILK_SYNC:
+      if (flag_enable_cilkplus)
+	{ 
+	  tree sync_expr = build_cilk_sync ();
+	  SET_EXPR_LOCATION (sync_expr, 
+			     cp_lexer_peek_token (parser->lexer)->location);
+	  finish_expr_stmt (sync_expr);
+	}
+      else
+	error_at (input_location, "_Cilk_sync cannot be used without enabling "
+		  "Cilk Plus");
+      cp_lexer_consume_token (parser->lexer);
+      if (parser->in_statement & IN_CILK_SPAWN)
+	parser->in_statement = parser->in_statement & ~IN_CILK_SPAWN;
+      break;
+
     case RID_BUILTIN_SHUFFLE:
       {
 	vec<tree, va_gc> *vec;
diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index edd4e6e..e26e350 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -301,6 +301,7 @@  typedef struct GTY(()) cp_parser {
 #define IN_OMP_FOR		8
 #define IN_IF_STMT             16
 #define IN_CILK_SIMD_FOR       32
+#define IN_CILK_SPAWN          64
   unsigned char in_statement;
 
   /* TRUE if we are presently parsing the body of a switch statement.
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index b58c755..8672129 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -13762,6 +13762,13 @@  tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
       error ("use %<...%> to expand argument pack");
       RETURN (error_mark_node);
 
+    case CILK_SPAWN_STMT:
+      cfun->calls_cilk_spawn = 1;
+      RETURN (build_cilk_spawn (EXPR_LOCATION (t), RECUR (CILK_SPAWN_FN (t))));
+
+    case CILK_SYNC_STMT:
+      RETURN (build_cilk_sync ());
+
     case COMPOUND_EXPR:
       tmp = RECUR (TREE_OPERAND (t, 0));
       if (tmp == NULL_TREE)
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index d871c4d..4f637fb 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -10417,6 +10417,8 @@  potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
 	  return false;
       return true;
 
+    case CILK_SYNC_STMT:
+    case CILK_SPAWN_STMT:
     case ARRAY_NOTATION_REF:
       return false;
 
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index a4da037..fd8eac1 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -6164,6 +6164,17 @@  cp_build_compound_expr (tree lhs, tree rhs, tsubst_flags_t complain)
   if (lhs == error_mark_node || rhs == error_mark_node)
     return error_mark_node;
 
+  if (flag_enable_cilkplus
+      && (TREE_CODE (lhs) == CILK_SPAWN_STMT
+	  || TREE_CODE (rhs) == CILK_SPAWN_STMT))
+    {
+      location_t loc = (EXPR_HAS_LOCATION (lhs) ? EXPR_LOCATION (lhs)
+			: EXPR_LOCATION (rhs));
+      error_at (loc,
+		"spawned function call cannot be part of a comma expression");
+      return error_mark_node;
+    }
+
   if (TREE_CODE (rhs) == TARGET_EXPR)
     {
       /* If the rhs is a TARGET_EXPR, then build the compound
@@ -8288,6 +8299,13 @@  check_return_expr (tree retval, bool *no_warning)
 
   *no_warning = false;
 
+  if (flag_enable_cilkplus && retval && TREE_CODE (retval) == CILK_SPAWN_STMT)
+    {
+      error_at (EXPR_LOCATION (retval), "use of %<_Cilk_spawn%> in a return "
+		"statement is not allowed");
+      return NULL_TREE;
+    }
+
   /* A `volatile' function is one that isn't supposed to return, ever.
      (This is a G++ extension, used to get better code for functions
      that call the `volatile' function.)  */
diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h
index 411cf74..e3c34d9 100644
--- a/gcc/langhooks-def.h
+++ b/gcc/langhooks-def.h
@@ -214,7 +214,7 @@  extern tree lhd_make_node (enum tree_code);
 #define LANG_HOOKS_OMP_CLAUSE_DTOR hook_tree_tree_tree_null
 #define LANG_HOOKS_OMP_FINISH_CLAUSE hook_void_tree
 
-extern void lhd_install_body_with_frame_cleanup (tree, tree);
+extern void lhd_install_body_with_frame_cleanup (tree, tree, void *);
 extern bool lhd_cilk_detect_spawn (tree *);
 #define LANG_HOOKS_CILKPLUS_DETECT_SPAWN_AND_UNWRAP lhd_cilk_detect_spawn
 #define LANG_HOOKS_CILKPLUS_FRAME_CLEANUP lhd_install_body_with_frame_cleanup
diff --git a/gcc/langhooks.c b/gcc/langhooks.c
index 7fe349d..ef6d82d 100644
--- a/gcc/langhooks.c
+++ b/gcc/langhooks.c
@@ -681,7 +681,7 @@  lhd_end_section (void)
    frame cleanup function for _Cilk_spawn.  */
 
 void
-lhd_install_body_with_frame_cleanup (tree, tree)
+lhd_install_body_with_frame_cleanup (tree, tree, void *)
 {
 }
 
diff --git a/gcc/langhooks.h b/gcc/langhooks.h
index 9539e7d..80bfa66 100644
--- a/gcc/langhooks.h
+++ b/gcc/langhooks.h
@@ -148,7 +148,7 @@  struct lang_hooks_for_cilkplus
 
   /* Function to add the clean up functions after spawn.  The reason why it is
      language dependent is because in C++, it must handle exceptions.  */
-  void (*install_body_with_frame_cleanup) (tree, tree);
+  void (*install_body_with_frame_cleanup) (tree, tree, void *);
 
   /* Function to gimplify a spawned function call.  Returns enum gimplify
      status, but as mentioned in a previous comment, we can't see that type 
diff --git a/gcc/testsuite/g++.dg/cilk-plus/CK/catch_exc.cc b/gcc/testsuite/g++.dg/cilk-plus/CK/catch_exc.cc
new file mode 100644
index 0000000..0633d19
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cilk-plus/CK/catch_exc.cc
@@ -0,0 +1,67 @@ 
+/* { dg-options "-fcilkplus" } */
+/* { dg-do run { target i?86-*-* x86_64-*-* arm*-*-* } } */
+/* { dg-options "-fcilkplus -lcilkrts" { target { i?86-*-* x86_64-*-* arm*-*-* } } } */
+
+#include <assert.h>
+#include <unistd.h>
+#if HAVE_IO
+#include <cstdio>
+#include <cilk/cilk_api.h>
+#endif
+#include <cstdlib>
+
+
+void func(int volatile* steal_me) 
+{
+  while (! (*steal_me)) 
+    {
+      usleep(2000);
+    }
+#if HAVE_IO
+  printf("Foo executing on %d\n", __cilkrts_get_worker_number());
+#endif
+  throw 5;
+}
+
+void my_test() 
+{
+  volatile int steal_me = 0;
+
+  try 
+    {
+      _Cilk_spawn func(&steal_me);
+#if HAVE_IO
+      printf("Continuation executing on %d\n",
+	     __cilkrts_get_worker_number());
+#endif
+      steal_me = 1;
+      _Cilk_sync;
+      goto bad;
+    }
+
+  catch (int x) 
+    {
+#if HAVE_IO
+      printf("We caught x = %d\n", x);
+#endif
+      assert(x == 5);
+    }
+  if (0) 
+    {
+    bad:
+#if HAVE_IO
+      printf("We should not be here!\n");
+#endif
+      __builtin_abort ();
+    }
+}
+
+
+int main() 
+{
+  my_test();
+#if HAVE_IO
+  printf("PASSED\n");
+#endif
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cilk-plus/CK/const_spawn.cc b/gcc/testsuite/g++.dg/cilk-plus/CK/const_spawn.cc
new file mode 100644
index 0000000..1ea473f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cilk-plus/CK/const_spawn.cc
@@ -0,0 +1,78 @@ 
+/* { dg-options "-fcilkplus" } */
+/* { dg-do run { target i?86-*-* x86_64-*-* arm*-*-* } } */
+/* { dg-options "-fcilkplus -lcilkrts" { target { i?86-*-* x86_64-*-* arm*-*-* } } } */
+
+class Rectangle
+{
+  int area_val, h, w;
+  public:
+    Rectangle (int, int);
+    Rectangle (int, int, int);
+    ~Rectangle ();
+    int area ();
+};
+Rectangle::~Rectangle ()
+{
+  h = 0;
+  w = 0;
+  area_val = 0;
+}
+Rectangle::Rectangle (int height, int width)
+{
+  h = height;
+  w = width;
+  area_val = 0;
+}
+
+Rectangle::Rectangle (int height, int width, int area_orig)
+{
+  h = height;
+  w = width;
+  area_val = area_orig;
+}
+
+int Rectangle::area()
+{
+  return (area_val += (h*w));
+}
+
+/* Spawning constructor.  */
+int main1 (void)
+{
+  Rectangle r = _Cilk_spawn Rectangle (4, 3);
+  return r.area();
+}
+ 
+/* Spawning constructor 2.  */
+int main2 (void)
+{
+  Rectangle r (_Cilk_spawn Rectangle (4, 3));
+  return r.area();
+}
+
+/* Spawning copy constructor.  */
+int main3 (void)
+{
+  Rectangle r = _Cilk_spawn Rectangle (4, 3, 2);
+  return r.area ();
+}
+
+/* Spawning copy constructor 2.  */
+int main4 (void)
+{
+  Rectangle r ( _Cilk_spawn Rectangle (4, 3, 2));
+  return r.area();
+}
+
+int main (void)
+{
+  if (main1 () != 12)
+    __builtin_abort ();
+  if (main2 () != 12)
+    __builtin_abort ();
+  if (main3 () != 14)
+    __builtin_abort ();
+  if (main4() != 14)
+    __builtin_abort ();
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cilk-plus/CK/fib-opr-overload.cc b/gcc/testsuite/g++.dg/cilk-plus/CK/fib-opr-overload.cc
new file mode 100644
index 0000000..6af4a36
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cilk-plus/CK/fib-opr-overload.cc
@@ -0,0 +1,94 @@ 
+/* { dg-options "-fcilkplus" } */
+/* { dg-do run { target i?86-*-* x86_64-*-* arm*-*-* } } */
+/* { dg-options "-fcilkplus -lcilkrts" { target { i?86-*-* x86_64-*-* arm*-*-* } } } */
+
+#if HAVE_IO
+#include <iostream>
+#endif
+
+class Some_Struct
+{
+  int calculated_value;
+  short some_unused_value;
+public:
+  Some_Struct () {
+      this->calculated_value = 0;
+  }
+  Some_Struct (int value) {
+      this->calculated_value = value;
+  }
+  Some_Struct operator=(Some_Struct f) {
+      this->calculated_value = f.calculated_value;
+      return *this;
+  }
+  bool operator!=(Some_Struct f) {
+      return (this->calculated_value != f.calculated_value);
+  }
+  Some_Struct operator+(Some_Struct &f) {
+    Some_Struct z;
+    z.calculated_value = this->calculated_value + f.calculated_value;
+      return z;
+  }
+  Some_Struct operator-(int x) {
+    Some_Struct z;
+    z.calculated_value = this->calculated_value - x;
+    return z;
+  }
+  bool operator<(int x) {
+      return (this->calculated_value < x);
+  }
+  int get_calculated_value () {
+      return this->calculated_value;
+  }
+};
+
+
+template <class T>
+T fibonacci_serial (T f)
+{
+  if (f < 2)
+    return f;
+  T a = fibonacci_serial (f-1);
+  T b = fibonacci_serial (f-2);
+  return (a+b);
+}
+
+template <class T>
+T fibonacci (T f)
+{
+  if (f < 2)
+    return f;
+  T a = _Cilk_spawn fibonacci (f-1);
+  T b = fibonacci (f-2);
+  _Cilk_sync; 
+  return (a+b);
+}
+
+int main (void)
+{
+  Some_Struct f (40), f_serial(40);
+  f = fibonacci (f);
+  f_serial = fibonacci_serial (f_serial);
+  
+  if (f != f_serial)
+    __builtin_abort ();
+  
+  int t = 40, t_serial = 40;
+  t = fibonacci (t);
+  t_serial = fibonacci_serial (t_serial);
+  if (t != t_serial)
+    __builtin_abort ();
+
+  short s = 20, s_serial = 20;
+  s = fibonacci (s);
+  s_serial = fibonacci_serial (s_serial);
+  if (s != s_serial)
+    __builtin_abort ();
+
+#if HAVE_IO
+  std::cout << "Fib_Parallel (40) = " << f.get_calculated_value() << std::endl;
+  std::cout << "Fib_Serial   (40) = " << f_serial.get_calculated_value() 
+    << std::endl;
+#endif
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cilk-plus/CK/fib-tplt.cc b/gcc/testsuite/g++.dg/cilk-plus/CK/fib-tplt.cc
new file mode 100644
index 0000000..dbc2da8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cilk-plus/CK/fib-tplt.cc
@@ -0,0 +1,53 @@ 
+/* { dg-options "-fcilkplus" } */
+/* { dg-do run { target i?86-*-* x86_64-*-* arm*-*-* } } */
+/* { dg-options "-fcilkplus -lcilkrts" { target { i?86-*-* x86_64-*-* arm*-*-*-* } } } */
+
+struct fib_struct
+{
+  int x;
+  int *y;
+  int z[3];
+  struct fib_struct *ptr_next;
+  struct fib_struct operator+(struct fib_struct &other) {
+    struct fib_struct z ;
+     z.x = (*this).x + (other.x);
+    return z; 
+  }
+  struct fib_struct operator-(int other) {
+    struct fib_struct z ;
+    z.x = this->x - other;
+    return z;
+  }
+  bool operator<(int number) {
+   return (this->x < number);
+  }
+    
+};
+
+template <typename T>
+T fib (T z) {
+    if (z < 2) return z;
+    T a = _Cilk_spawn fib<T>(z - 1);
+    T b = fib<T>(z - 2);
+    T c = a + b;
+    return (a+b);
+}
+
+
+int sfib(int x)
+{
+  if (x < 2) return x;
+  int a = sfib(x-1);
+  int b = sfib(x-2);
+  return (a+b);
+}
+
+int main () {
+     int z = 30;
+     int parallel_fib = fib<int>(z);
+     int serial_fib = sfib(z);
+    if (serial_fib != parallel_fib) 
+      __builtin_abort ();
+    
+    return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cilk-plus/CK/lambda_spawns.cc b/gcc/testsuite/g++.dg/cilk-plus/CK/lambda_spawns.cc
new file mode 100644
index 0000000..7448d1a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cilk-plus/CK/lambda_spawns.cc
@@ -0,0 +1,236 @@ 
+/* { dg-options "-fcilkplus" } */
+/* { dg-do run { target i?86-*-* x86_64-*-* arm*-*-* } } */
+/* { dg-options "-std=c++11 -fcilkplus -lcilkrts" { target { i?86-*-* x86_64-*-* arm*-*-* } } } */
+#define FIRST_NUMBER 5
+#define SECOND_NUMBER 3
+#define HAVE_IO 0
+#if HAVE_IO
+#include <stdio.h>
+#endif
+
+#include <stdlib.h>
+
+int global_var;
+
+void foo1(int *array, int size)
+{
+#if HAVE_IO
+  for (int ii = 0; ii < size; ii++) 
+    printf("%2d\t", array[ii]);
+  printf("\n");
+  fflush (stdout);
+#else
+  if (size != 2)
+    __builtin_abort ();
+  if (array[0] != FIRST_NUMBER)
+    __builtin_abort ();
+  if (array[1] != SECOND_NUMBER)
+    __builtin_abort ();
+#endif
+  global_var++;
+}
+void foo1_c(const int *array, int size)
+{
+#if HAVE_IO
+  for (int ii = 0; ii < size; ii++) 
+    printf("%2d\t", array[ii]);
+  printf("\n");
+  fflush (stdout);
+#else
+  if (size != 2)
+    __builtin_abort ();
+  if (array[0] != FIRST_NUMBER)
+    __builtin_abort ();
+  if (array[1] != SECOND_NUMBER)
+    __builtin_abort ();
+#endif
+  global_var++;
+}
+
+
+int main2 (int argc) {
+  int A[2] = {FIRST_NUMBER, SECOND_NUMBER};
+  int B[2] = {FIRST_NUMBER, SECOND_NUMBER};
+  int main_size = argc+1; /* We know argc is 1, and so 1+1 = 2.  */
+  int q = 0;
+
+  global_var = 0;
+  auto func0 = [=](){ foo1_c(A, 2); };
+  _Cilk_spawn func0();
+  foo1 (A, 2);
+  _Cilk_sync;
+  if (global_var != 2)
+    return (++q);
+
+  global_var = 0;
+  auto func1 = [=](int *Aa){ foo1(Aa, 2); };
+  _Cilk_spawn func1 (A);
+  foo1 (A, 2);
+  _Cilk_sync;
+  if (global_var != 2)
+    return (++q);
+
+  global_var = 0;
+  auto func2 = [=](int *Aa, int size){ foo1(Aa, size); };
+  _Cilk_spawn func2 (A, 2);
+  foo1 (A, 2);
+  _Cilk_sync;
+  if (global_var != 2)
+    return (++q);
+
+  global_var = 0;
+  auto func3 = [=](int *Aa, int size){ int new_size = (size % 2 + 2); 
+				       foo1(Aa, size); };
+  _Cilk_spawn func3 (A, 2);
+  foo1 (A, 2);
+  _Cilk_sync;
+  if (global_var != 2)
+    return (++q);
+
+  global_var = 0;
+  auto func4 = [](int *Aa){ foo1(Aa, 2); };
+  _Cilk_spawn func4 (A);
+  foo1 (A, 2);
+  _Cilk_sync;
+  if (global_var != 2)
+    return (++q);
+
+  global_var = 0;
+  auto func5 = [](int *Aa, int size){ foo1(Aa, size); };
+  _Cilk_spawn func5 (A, 2);
+  foo1 (A, 2);
+  _Cilk_sync;
+  if (global_var != 2)
+    return (++q);
+
+  global_var = 0;
+  auto func6 = [&](int *Aa){ foo1(Aa, 2); };
+  _Cilk_spawn func6 (A);
+  foo1 (A, 2);
+  _Cilk_sync;
+  if (global_var != 2)
+    return (++q);
+
+  global_var = 0;
+  auto func7 = [&](int *Aa, int size){ foo1(Aa, size); };
+  _Cilk_spawn func7 (A, 2);
+  foo1 (A, 2);
+  _Cilk_sync;
+  if (global_var != 2)
+    return (++q);
+
+  global_var = 0;
+  auto func8 = [&](){ foo1(A, 2); };
+  _Cilk_spawn func8 ();
+  foo1 (A, 2);
+  _Cilk_sync;
+  if (global_var != 2)
+    return (++q);
+
+  global_var = 0;
+  /* We ignore the first param here and pass in A from the outer fn.  */
+  auto func9 = [&](int *Aa, int size){ foo1(A, size); };
+  _Cilk_spawn func9 (A, 2);
+  foo1 (A, 2);
+  _Cilk_sync;
+  if (global_var != 2)
+    return (++q);
+
+  global_var = 0;
+  auto func10 = [=](){ foo1_c(A, main_size); };
+  _Cilk_spawn func10 ();
+  foo1 (A, 2);
+  _Cilk_sync;
+  if (global_var != 2)
+    return (++q);
+
+  global_var = 0;
+  auto func11 = [&](){ foo1(A, main_size); };
+  _Cilk_spawn func11 ();
+  foo1 (A, 2);
+  _Cilk_sync;
+  if (global_var != 2)
+    return (++q);
+
+  global_var = 0;
+  /* We ignore the first & second param here and pass in A from the 
+     outer fn.  */
+  auto func12 = [&](int *Aa, int size){ foo1(A, main_size); };
+  _Cilk_spawn func12 (A, 2);
+  foo1 (A, 2);
+  _Cilk_sync;
+  if (global_var != 2)
+    return (++q);
+
+  global_var = 0;
+  _Cilk_spawn [&](int *Aa){ foo1(Aa, 2); }(A);
+  foo1 (A, 2);
+  _Cilk_sync;
+  if (global_var != 2)
+    return (++q);
+
+  global_var = 0;
+  _Cilk_spawn [&](int *Aa, int size){ foo1(Aa, size); }(A, 2);
+  foo1 (A, 2);
+  _Cilk_sync;
+  if (global_var != 2)
+    return (++q);
+
+  global_var = 0;
+  _Cilk_spawn [=](int *Aa){ foo1(Aa, 2); }(A);
+  foo1 (A, 2);
+  _Cilk_sync;
+  if (global_var != 2)
+    return (++q);
+
+  global_var = 0;
+  _Cilk_spawn [=](int *Aa, int size){ foo1(Aa, size); }(A, 2);
+  foo1 (A, 2);
+  _Cilk_sync;
+  if (global_var != 2)
+    return (++q);
+
+  global_var = 0;
+  /* We ignore the first param here.  */
+  _Cilk_spawn [=](int *Aa, int size){ foo1_c(A, size); }(A, 2);
+  foo1 (A, 2);
+  _Cilk_sync;
+  if (global_var != 2)
+    return (++q);
+
+  global_var = 0;
+  /* We ignore the first and second param here.  */
+  _Cilk_spawn [=](int *Aa, int size){ foo1_c(A, size); }(B, 2);
+  foo1 (A, 2);
+  _Cilk_sync;
+  if (global_var != 2)
+    return (++q);
+
+  global_var = 0;
+  _Cilk_spawn [&](){ foo1(A, 2); }();
+  [&](){ foo1(A, 2); }();
+  _Cilk_sync;
+  if (global_var != 2)
+    return (++q);
+
+  global_var = 0;
+  _Cilk_spawn [=](){ foo1_c (A, main_size); }();
+  foo1 (A, 2);
+  _Cilk_sync;
+  if (global_var != 2)
+    return (++q);
+
+  global_var = 0;
+  _Cilk_spawn [&](){ foo1(A, main_size); }();
+  [&](){ foo1(A, 2); }();
+  _Cilk_sync;
+  if (global_var != 2)
+    return (++q);
+
+  return q;
+}
+
+int main (void)
+{
+  return main2 (1);
+}
diff --git a/gcc/testsuite/g++.dg/cilk-plus/CK/lambda_spawns_tplt.cc b/gcc/testsuite/g++.dg/cilk-plus/CK/lambda_spawns_tplt.cc
new file mode 100644
index 0000000..2667f5a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cilk-plus/CK/lambda_spawns_tplt.cc
@@ -0,0 +1,173 @@ 
+/* { dg-options "-fcilkplus" } */
+/* { dg-do run { target i?86-*-* x86_64-*-* arm*-*-* } } */
+/* { dg-options "-std=c++11 -fcilkplus -lcilkrts" { target { i?86-*-* x86_64-*-* arm*-*-* } } } */
+
+#define FIRST_NUMBER 5
+#define SECOND_NUMBER 3
+#define HAVE_IO 0
+#if HAVE_IO
+#include <stdio.h>
+#endif
+
+#include <stdlib.h>
+
+template <class T>
+void foo1(T *array, int size)
+{
+#if HAVE_IO
+  for (int ii = 0; ii < size; ii++) 
+    printf("%2d\t", (int)array[ii]);
+  printf("\n");
+  fflush (stdout);
+#else
+  if (size != 2)
+    __builtin_abort ();
+  if (array[0] != FIRST_NUMBER)
+    __builtin_abort ();
+  if (array[1] != SECOND_NUMBER)
+    __builtin_abort ();
+#endif
+}
+template <class T>
+void foo1_c(const T *array, int size)
+{
+#if HAVE_IO
+  for (int ii = 0; ii < size; ii++) 
+    printf("%2d\t", (int)array[ii]);
+  printf("\n");
+  fflush (stdout);
+#else
+  if (size != 2)
+    __builtin_abort ();
+  if (array[0] != FIRST_NUMBER)
+    __builtin_abort ();
+  if (array[1] != SECOND_NUMBER)
+    __builtin_abort ();
+#endif
+}
+template <class T>
+int main2 (int argc, char **argv) {
+  T A[2] = {FIRST_NUMBER, SECOND_NUMBER};
+  int main_size = argc+1; /* We know argc is 1, and so 1+1 = 2.  */
+  auto func0 = [=](){ foo1_c(A, 2); };
+  _Cilk_spawn func0();
+  foo1 (A, 2);
+  _Cilk_sync;
+
+  auto func1 = [=](T *Aa){ foo1(Aa, 2); };
+  _Cilk_spawn func1 (A);
+  foo1 (A, 2);
+  _Cilk_sync;
+
+  auto func2 = [=](T *Aa, int size){ foo1(Aa, size); };
+  _Cilk_spawn func2 (A, 2);
+  foo1 (A, 2);
+  _Cilk_sync;
+
+  auto func3 = [=](T *Aa, int size){ int new_size = (size % 2 + 2); 
+				       foo1(Aa, size); };
+  _Cilk_spawn func3 (A, 2);
+  foo1 (A, 2);
+  _Cilk_sync;
+
+  auto func4 = [](T *Aa){ foo1(Aa, 2); };
+  _Cilk_spawn func4 (A);
+  foo1 (A, 2);
+  _Cilk_sync;
+
+  auto func5 = [](T *Aa, int size){ foo1(Aa, size); };
+  _Cilk_spawn func5 (A, 2);
+  foo1 (A, 2);
+  _Cilk_sync;
+
+  auto func6 = [&](T *Aa){ foo1(Aa, 2); };
+  _Cilk_spawn func6 (A);
+  foo1 (A, 2);
+  _Cilk_sync;
+
+  auto func7 = [&](T *Aa, int size){ foo1(Aa, size); };
+  _Cilk_spawn func7 (A, 2);
+  foo1 (A, 2);
+  _Cilk_sync;
+
+  auto func8 = [&](){ foo1(A, 2); };
+  _Cilk_spawn func8 ();
+  foo1 (A, 2);
+  _Cilk_sync;
+
+  /* We ignore the first param here and pass in A from the outer fn.  */
+  auto func9 = [&](T *Aa, int size){ foo1(A, size); };
+  _Cilk_spawn func9 (A, 2);
+  foo1 (A, 2);
+  _Cilk_sync;
+
+  auto func10 = [=](){ foo1_c(A, main_size); };
+  _Cilk_spawn func10 ();
+  foo1 (A, 2);
+  _Cilk_sync;
+
+  auto func11 = [&](){ foo1(A, main_size); };
+  _Cilk_spawn func11 ();
+  foo1 (A, 2);
+  _Cilk_sync;
+
+  /* We ignore the first & second param here and pass in A from the 
+     outer fn.  */
+  auto func12 = [&](T *Aa, int size){ foo1(A, main_size); };
+  _Cilk_spawn func12 (A, 2);
+  foo1 (A, 2);
+  _Cilk_sync;
+
+  _Cilk_spawn [&](T *Aa){ foo1(Aa, 2); }(A);
+  foo1 (A, 2);
+  _Cilk_sync;
+
+  _Cilk_spawn [&](T *Aa, int size){ foo1(Aa, size); }(A, 2);
+  foo1 (A, 2);
+  _Cilk_sync;
+
+  _Cilk_spawn [=](T *Aa){ foo1(Aa, 2); }(A);
+  foo1 (A, 2);
+  _Cilk_sync;
+
+  _Cilk_spawn [=](T *Aa, int size){ foo1(Aa, size); }(A, 2);
+  foo1 (A, 2);
+  _Cilk_sync;
+
+  /* We ignore the first param here.  */
+  _Cilk_spawn [=](T *Aa, int size){ foo1_c(A, size); }(A, 2);
+  foo1 (A, 2);
+  _Cilk_sync;
+
+  /* We ignore the first and second param here.  */
+  _Cilk_spawn [=](T *Aa, int size){ foo1_c(A, main_size); }(A, 2);
+  foo1 (A, 2);
+  _Cilk_sync;
+
+  _Cilk_spawn [&](){ foo1(A, 2); }();
+  [&](){ foo1(A, 2); }();
+  _Cilk_sync;
+
+  _Cilk_spawn [=](){ foo1_c(A, main_size); }();
+  foo1 (A, 2);
+  _Cilk_sync;
+	
+  _Cilk_spawn [&](){ foo1(A, main_size); }();
+  [&](){ foo1(A, 2); }();
+  _Cilk_sync;
+
+  return 0;
+}
+
+int main (void)
+{
+  int argc = 1;
+  char **argv = NULL;
+  int x = 1, y = 1, z = 1, q = 1, p = 1;
+  x = main2<char>(argc,argv);
+  y = main2<short>(argc,argv);
+  z = main2<int>(argc,argv);
+  p = main2<long>(argc,argv);
+  q = main2<long long>(argc,argv);
+  return (x+y+z+p+q);
+}
diff --git a/gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp b/gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp
index a66ec44..a4328d0 100644
--- a/gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp
+++ b/gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp
@@ -22,6 +22,14 @@  if { ![check_effective_target_cilkplus] } {
     return;
 }
 
+verbose "$tool $libdir" 1
+set library_var "[get_multilibs]"
+# Pointing the ld_library_path to the Cilk Runtime library binaries.
+set ld_library_path "$[get_multilibs]/libcilkrts/.libs"
+
+set ALWAYS_CFLAGS ""
+lappend ALWAYS_CFLAGS "-L${library_var}/libcilkrts/.libs"
+
 dg-init
 # Run the tests that are shared with C.
 g++-dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/PS/*.c]] ""
@@ -62,4 +70,23 @@  dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/AN/*.cc]] " -g -O3
 dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/AN/*.cc]] " -O3 -ftree-vectorize -fcilkplus -g" " "
 dg-finish
 
+dg-init
+dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/CK/*.cc]] " -fcilkplus $ALWAYS_CFLAGS" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/CK/*.cc]] " -O1 -fcilkplus $ALWAYS_CFLAGS" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/CK/*.cc]] " -O2 -fcilkplus $ALWAYS_CFLAGS" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/CK/*.cc]] " -O3 -fcilkplus $ALWAYS_CFLAGS" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/CK/*.cc]] " -g -fcilkplus $ALWAYS_CFLAGS" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/CK/*.cc]] " -g -O2 -fcilkplus $ALWAYS_CFLAGS" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/CK/*.cc]] " -g -O3 -fcilkplus $ALWAYS_CFLAGS" " "
+dg-finish
+
+dg-init
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -fcilkplus $ALWAYS_CFLAGS" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -O1 -fcilkplus $ALWAYS_CFLAGS" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -O2 -fcilkplus $ALWAYS_CFLAGS" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -O3 -fcilkplus $ALWAYS_CFLAGS" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -g -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -g -O2 -fcilkplus $ALWAYS_CFLAGS" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -g -O3 -fcilkplus $ALWAYS_CFLAGS" " "
+dg-finish
 unset TEST_EXTRA_LIBS