diff mbox

_Cilk_spawn and _Cilk_sync for C++

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

Commit Message

Iyer, Balaji V Nov. 28, 2013, 4:05 a.m. UTC
> -----Original Message-----
> From: Jason Merrill [mailto:jason@redhat.com]
> Sent: Wednesday, November 27, 2013 8:24 PM
> To: Iyer, Balaji V; gcc-patches@gcc.gnu.org
> Cc: Jeff Law
> Subject: Re: _Cilk_spawn and _Cilk_sync for C++
> 
> On 11/27/2013 05:59 PM, Iyer, Balaji V wrote:
> > Well, if I use copy_tree_body_r for C and C++, in lambda functions, it
> asserts in varasm.c. The main reason I see that, the copy_tree_body_r walks
> into the closure and then maps the variables from the lambda function from
> the spawner to the helper function.
> 
> It walks into the initializer for the closure object, yes.  And gets confused by
> the initializer in the
> 
>    _Cilk_spawn [=](int *Aa, int size){ foo1_c(A, size); }(B, 2);
> 
> case.  The initializer for the closure is a CONSTRUCTOR which contains a
> reference to A, and that is running into trouble because
> extract_free_variables doesn't walk into CONSTRUCTORs.  You probably
> want to switch a lot of your tree walking functions to use walk_tree directly
> rather than try to keep up with all the different kinds of expressions yourself.

Found the bug. I was not utilizing the stabilize_expr's output correctly. Here is the fixed patch. I have removed the function pointer and the lang_hooks addition. It now just uses copy_tree_body_r for C and C++. It passes all the tests for C and C++ on my x86_64 box.

Is this Ok for trunk?

Here are the ChangeLog entries:
gcc/c-family/ChangeLog
2013-11-27  Balaji V. Iyer  <balaji.v.iyer@intel.com>

        * cilk.c (cilk_outline): Made this function non-static.
        * c-common.h (cilk_outline): New prototype.
        (c_cilk_install_body_with_frame_cleanup): Added a new parameter.

gcc/ChangeLog
2013-11-27  Balaji V. Iyer  <balaji.v.iyer@intel.com>

        * langhooks.h
        (lang_hooks_for_cilkplus::install_body_with_frame_cleanup): Added new
        parameter.

gcc/cp/ChangeLog
2013-11-27  Balaji V. Iyer  <balaji.v.iyer@intel.com>

        * cp-tree.h (cilk_valid_spawn): New prototype.
        (gimplify_cilk_spawn): Likewise.
        (cp_cilk_install_body_wframe_cleanup): Likewise.
        (cilk_create_lambda_fn_tmp_var): Likewise.
        (create_try_catch_expr): Likewise.
        * decl.c (finish_function): Insert Cilk function-calls when a
        _Cilk_spawn is used in a function.
        * parser.c (cp_parser_postfix_expression): Added RID_CILK_SPAWN and
        RID_CILK_SYNC cases.
        * cp-cilkplus.c (set_cilk_except_flag): New function.
        (set_cilk_except_data): Likewise.
        (cp_cilk_install_body_wframe_cleanup): Likewise.
        (is_lambda_function): Likewise.
        * except.c (create_try_catch_expr): Likewise.
        * parser.h (IN_CILK_SPAWN): New #define.
        * cp-objcp-common.h (LANG_HOOKS_CILKPLUS_GIMPLIFY_SPAWN): Likewise.
        * cp-objcp-common.h (LANG_HOOKS_CILKPLUS_CILK_SPEC_COPY_BODY):
        Likewise.
        (LANG_HOOKS_CILKPLUS_DETECT_SPAWN_AND_UNWRAP): Likewise.
        (LANG_HOOKS_CILKPLUS_FRAME_CLEANUP): Likewise.
        * pt.c (tsubst_expr): Added CILK_SPAWN_STMT and CILK_SYNC_STMT cases.
        * semantics.c (potential_constant_expression_1): Likewise.
        * typeck.c (cp_build_compound_expr): Reject a spawned function in a
        compound expression.
        (check_return_expr): Reject a spawned function in a return expression.

gcc/testsuite/ChangeLog
2013-11-27  Balaji V. Iyer  <balaji.v.iyer@intel.com>

        * g++.dg/cilk-plus/CK/catch_exc.cc: New test case.
        * g++.dg/cilk-plus/CK/const_spawn.cc: Likewise.
        * g++.dg/cilk-plus/CK/fib-opr-overload.cc: Likewise.
        * g++.dg/cilk-plus/CK/fib-tplt.cc: Likewise.
        * g++.dg/cilk-plus/CK/lambda_spawns.cc: Likewise.
        * g++.dg/cilk-plus/CK/lambda_spawns_tplt.cc: Likewise.
        * g++.dg/cilk-plus/cilk-plus.exp: Added support to run Cilk Keywords
        test stored in c-c++-common.  Also, added the Cilk runtime's library
        to the ld_library_path.

Thanks,

Balaji V. Iyer.

Comments

Jason Merrill Nov. 28, 2013, 2:10 p.m. UTC | #1
On 11/27/2013 11:05 PM, Iyer, Balaji V wrote:
> Found the bug. I was not utilizing the stabilize_expr's output correctly.

Unfortunately, I think I was misleading you with talk of stabilize; like 
you said, you want to evaluate the whole expression in the spawned 
function rather than in the caller, so that any temporaries (including 
the lambda closure) live until the _Cilk_sync.  Using stabilize_expr 
this way (the way I was suggesting) forces the lambda closure to be 
evaluated in the caller, and then destroyed at the end of the enclosing 
statement, which is likely to erase any data that the spawned function 
needs to do its work, if anything captured by copy has a destructor.

As I said in my last mail, I think the right fix is to make sure that A 
gets remapped properly during copy_body so that its use in the 
initializer for the closure doesn't confuse later passes.

Jason
Iyer, Balaji V Nov. 28, 2013, 4:40 p.m. UTC | #2
> -----Original Message-----
> From: Jason Merrill [mailto:jason@redhat.com]
> Sent: Thursday, November 28, 2013 9:11 AM
> To: Iyer, Balaji V; gcc-patches@gcc.gnu.org
> Cc: Jeff Law
> Subject: Re: _Cilk_spawn and _Cilk_sync for C++
> 
> On 11/27/2013 11:05 PM, Iyer, Balaji V wrote:
> > Found the bug. I was not utilizing the stabilize_expr's output correctly.
> 
> Unfortunately, I think I was misleading you with talk of stabilize; like you said,
> you want to evaluate the whole expression in the spawned function rather
> than in the caller, so that any temporaries (including the lambda closure) live
> until the _Cilk_sync.  Using stabilize_expr this way (the way I was suggesting)
> forces the lambda closure to be evaluated in the caller, and then destroyed
> at the end of the enclosing statement, which is likely to erase any data that
> the spawned function needs to do its work, if anything captured by copy has
> a destructor.
> 

> As I said in my last mail, I think the right fix is to make sure that A gets
> remapped properly during copy_body so that its use in the initializer for the
> closure doesn't confuse later passes.

Consider the following test case. I took this from the lambda_spawns.cc line #203.


  global_var = 0;
  _Cilk_spawn [=](int *Aa, int size){ foo1_c(A, size); }(B, 2);
  foo1 (A, 2);
  _Cilk_sync;
  if (global_var != 2)
    return (++q);


... and here is its gimple output:

{
  struct  * D.2349;
  unsigned long D.2350;
  struct  * D.2351;
  struct  * D.2352;
  struct  * D.2353;
  struct  * D.2354;
  unsigned long D.2355;
  struct  * D.2356;
  struct  * D.2357;
  struct  * D.2358;
  struct  * D.2359;
  struct  * D.2360;
  struct __lambda0 D.2219;
  unsigned int D.2361;
  unsigned int D.2362;
  void * D.2363;
  void * D.2364;
  struct  * D.2365;
  struct  * D.2366;
  unsigned int D.2367;

  try
    {
      try
        {
          __cilkrts_enter_frame_fast_1 (&D.2258);
          D.2349 = D.2258.worker;
          D.2350 = D.2349->pedigree.rank;
          D.2258.pedigree.rank = D.2350;
          D.2351 = D.2258.worker;
          D.2352 = D.2351->pedigree.parent;
          D.2258.pedigree.parent = D.2352;
          D.2353 = D.2258.call_parent;
          D.2354 = D.2258.worker;
          D.2355 = D.2354->pedigree.rank;
          D.2353->pedigree.rank = D.2355;
          D.2356 = D.2258.call_parent;
          D.2357 = D.2258.worker;
          D.2358 = D.2357->pedigree.parent;
          D.2356->pedigree.parent = D.2358;
          D.2359 = D.2258.worker;
          D.2359->pedigree.rank = 0;
          D.2360 = D.2258.worker;
          D.2360->pedigree.parent = &D.2258.pedigree;
          __cilkrts_detach (&D.2258);
          D.2219.__A = CHAIN.6->A;
          try
            {
              main2(int)::<lambda(int*, int)>::operator() (&D.2219, D.2255, 2);
            }        
         finally
            {
              D.2219 = {CLOBBER};                           <===============================
            }
        }
      catch
        {
          catch (NULL)
            {
              try
                {
                  D.2361 = D.2258.flags;
                  D.2362 = D.2361 | 16;
                  D.2258.flags = D.2362;
                  D.2363 = __builtin_eh_pointer (0);
                  D.2258.except_data = D.2363;
                  D.2364 = __builtin_eh_pointer (0);
                  __cxa_begin_catch (D.2364);
                  __cxa_rethrow ();
                }
              finally
                {
                  __cxa_end_catch ();
                }
            }
        }
          finally

as you can tell, it is clobbering the lambda closure at the end of the lambda calling (in the finally expr, I marked with <=========  ) and then it is catching value of A from main2 as it is supposed to. 

What am I misunderstanding?


> 
> Jason
Jason Merrill Dec. 2, 2013, 10:19 p.m. UTC | #3
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.

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

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

>   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

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.

> +       /* 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.

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

Jason
Iyer, Balaji V Dec. 3, 2013, 3:22 p.m. UTC | #4
> 
> >         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.
> 
Hi Jason,
	I really cannot do this because if the spawned function returns a value, the whole expression must be pushed into the spawn helper. Thus, this lang_hooks function is called in the gimplify_modify_expr and a couple other places.

E.g.  In:

x = _Cilk_spawn func ()

The spawn helper should contain:

x = func ();

Thanks,

Balaji V. Iyer.
Jason Merrill Dec. 3, 2013, 10:12 p.m. UTC | #5
On 12/03/2013 10:22 AM, Iyer, Balaji V wrote:
>> Please remove these langhooks and instead add handling of
>> CILK_SPAWN_STMT to c_gimplify_expr and cp_gimplify_expr.

> 	I really cannot do this because if the spawned function returns a value, the whole expression must be pushed into the spawn helper. Thus, this lang_hooks function is called in the gimplify_modify_expr and a couple other places.

Then c/cp_gimplify_expr can check for that in MODIFY_EXPR and CALL_EXPR 
nodes as well.

Jason
diff mbox

Patch

diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 664e928..f46008f
--- 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..480823d
--- 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,90 @@  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
+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);
+  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 (is_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..8ecac62 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);
+  gcc_assert (TREE_CODE (catch_list) == STATEMENT_LIST);
+  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..2069e4c 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,70 @@  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
+	  {
+	    /* Break or continue statements within this primary expression
+	       is not allowed.  */
+	    saved_in_statement = parser->in_statement;
+	    parser->in_statement = IN_CILK_SPAWN;
+	  }
+	/* We set this here so that finish_call_expr can set lambda to a var.
+	   if it is not done so.  */
+	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