diff mbox

_Cilk_spawn and _Cilk_sync for C++

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

Commit Message

Iyer, Balaji V Nov. 25, 2013, 3:50 p.m. UTC
Hi Jason,
    Please see my responses below

> -----Original Message-----
> From: Jason Merrill [mailto:jason@redhat.com]
> Sent: Friday, November 22, 2013 10:51 AM
> To: Iyer, Balaji V; gcc-patches@gcc.gnu.org
> Cc: Jeff Law
> Subject: Re: _Cilk_spawn and _Cilk_sync for C++
> 
> On 11/21/2013 05:40 PM, Iyer, Balaji V wrote:
> > +/* Returns a TRY_CATCH_EXPR that will encapsulate BODY, EXCEPT_DATA
> and
> > +   EXCEPT_FLAG.  */
> > +
> > +tree
> > +create_cilk_try_catch (tree except_flag, tree except_data, tree body)
> > +{
> > +  tree catch_list = alloc_stmt_list ();
> > +  append_to_statement_list (except_flag, &catch_list);
> > +  append_to_statement_list (except_data, &catch_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 (EXPR_LOCATION (body),
> 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 (EXPR_LOCATION (body),
> TRY_CATCH_EXPR,
> > +				    body, catch_list);
> > +  return try_catch_expr;
> > +}
> 
> I had in mind something less cilk-specific: a function that takes two tree
> operands, one for the body and one for the throwing path.
> Basically, make catch_list a parameter and move the first two appends back
> into the calling function.
> 

This is fixed as you suggested.


> > The reason is that, when you have something like this:
> >
> > _Cilk_spawn [=]  { <body> } ();
> >
> > I need to capture the function call (which in this case is the whole function)
> and throw it into a nested function.  The nested function implementation is
> shared with C. If the function is stored in a variable then I can just send that
> out to the nested function. I have added another constraint to make sure the
> function is a spawning function, this way we can reduce more cases were
> they are stored to a variable. The reason why I added this check in
> finish_call_expr is that it seemed to be most straight-forward for me and
> only place where I could do with least disruption (code-changes).
> 
> It looks like you're transforming any
> 
> [...] {...} (...);
> 
> into
> 
> auto lambda = [...]{...};
> lambda(...);
> 
> which has significantly different semantics, particularly in terms of the
> lifetime of the lambda object.  In some of the Cilk online documentation, I
> see:
> 
> > When spawning named lambda functions, be careful that the lifespan of
> the lambda extends at least until the next sync, or else the destructor for the
> lambda will race with the spawned call. For example:
> > double i = g();
> > if (some condition) {
> >    // named lambda with value capture of i
> >    auto f = [=i]() { double d = sin(i); f(d); };
> >    cilk_spawn f();
> > } // Ouch! destructor for f is in parallel with spawned call.
> 
> This would seem to apply even more to unnamed lambda functions, since
> normally they would be destroyed at the end of the full-expression, which
> must always be before the sync.  Does the Intel compiler implicitly extend
> the lifetime of a lambda called by cilk spawn?  In any case, we really don't
> want to do this for all calls to unnamed lambdas just because we turned on
> cilk mode.
> 

I have fixed this issue.  My function to map the variable's context from the spawner to the spawn helper function was going into the lambda function. I made it stop by adding a language specific copy_tree_body (basically stop going into the lambda function's body for C++ and for the rest of the times just use copy_tree_body_r, no code duplicating  is done between the two) that and it works fine now.

The fixed patch is attached and here are the fixed ChangeLogs:

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

        * cilk.c (cilk_outline): Replaced a call to copy_tree_body_r with the
        language specific one.

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

        * c-objc-common.h (LANG_HOOKS_CILKPLUS_CILK_SPEC_COPY_BODY): New
        define.

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

        * langhooks.h (lang_hooks_for_cilkplus::cilk_specific_copy_tree_body):
        New field.
        * langhooks-def.h
        (LANG_HOOKS_CILKPLUS::LANG_HOOKS_CILKPLUS_CILK_SPEC_COPY_BODY):
        Likewise.
        (LANG_HOOKS_CILKPLUS_CILK_SPEC_COPY_BODY): New #define.

gcc/cp/ChangeLog
2013-11-25  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.
        (cp_cilk_copy_tree_body_r): 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-25  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.


So, is this patch Ok to install?

Thanks,

Balaji V. Iyer.


> Jason

Comments

Jason Merrill Nov. 27, 2013, 5:42 p.m. UTC | #1
On 11/25/2013 10:50 AM, Iyer, Balaji V wrote:
> I have fixed this issue.  My function to map the variable's context from the spawner to the spawn helper function was going into the lambda function. I made it stop by adding a language specific copy_tree_body (basically stop going into the lambda function's body for C++ and for the rest of the times just use copy_tree_body_r, no code duplicating  is done between the two) that and it works fine now.

I doubt it was walking from the enclosing function into the body of the 
lambda function.  Looking at the patch, it seems that what you're 
avoiding is walking into the closure object itself, and adding an entire 
new langhook seems like overkill for that.

I think a better approach would be to add a cp_build_cilk_spawn that 
uses stabilize_call to pre-evaluate the arguments of the call.

Jason
Iyer, Balaji V Nov. 27, 2013, 6:25 p.m. UTC | #2
> -----Original Message-----
> From: Jason Merrill [mailto:jason@redhat.com]
> Sent: Wednesday, November 27, 2013 12:43 PM
> To: Iyer, Balaji V; gcc-patches@gcc.gnu.org
> Cc: Jeff Law
> Subject: Re: _Cilk_spawn and _Cilk_sync for C++
> 
> On 11/25/2013 10:50 AM, Iyer, Balaji V wrote:
> > I have fixed this issue.  My function to map the variable's context from the
> spawner to the spawn helper function was going into the lambda function. I
> made it stop by adding a language specific copy_tree_body (basically stop
> going into the lambda function's body for C++ and for the rest of the times
> just use copy_tree_body_r, no code duplicating  is done between the two)
> that and it works fine now.
> 
> I doubt it was walking from the enclosing function into the body of the
> lambda function.  Looking at the patch, it seems that what you're avoiding is
> walking into the closure object itself, and adding an entire new langhook
> seems like overkill for that.
> 
> I think a better approach would be to add a cp_build_cilk_spawn that uses
> stabilize_call to pre-evaluate the arguments of the call.

I really can't pre-evaluate the calls before I move into the nested function because all those parts must be in the nested function.

Adding another hook seem to be straightforward for me. One advantage I can think of having a separate node for that when new features get added in, we have a place to separately evaluate them and copy them as necessary. If it is not too much of a hazzle, I would like to keep them. I don't add anything more in the structure, just 1 more for _Cilk_for.

Or, another thing I could do is to pass a function pointer and pass the copy_tree_body function into it. Is that acceptable by you?

> 
> Jason
Jason Merrill Nov. 27, 2013, 6:57 p.m. UTC | #3
On 11/27/2013 01:25 PM, Iyer, Balaji V wrote:
>> I think a better approach would be to add a cp_build_cilk_spawn that uses
>> stabilize_call to pre-evaluate the arguments of the call.
>
> I really can't pre-evaluate the calls before I move into the nested function because all those parts must be in the nested function.

OK, then use stabilize_expr to pre-evaluate just the function, to get 
the effect of your earlier cilk_create_lambda_fn_tmp_var without the 
undesirable lifetime effects.

> Adding another hook seem to be straightforward for me.

It's straightforward but undesirable; we want to minimize the number of 
hooks, and this one is unnecessary.

Jason
diff mbox

Patch

diff --git a/gcc/c-family/cilk.c b/gcc/c-family/cilk.c
index 165348f..925a2c1 100644
--- a/gcc/c-family/cilk.c
+++ b/gcc/c-family/cilk.c
@@ -510,7 +510,16 @@  cilk_outline (tree inner_fn, tree *stmt_p, struct wrapper_data *wd)
   pointer_map_traverse (wd->decl_map, nested ? for_local_cb : wrapper_local_cb,
 			&id);
 
-  walk_tree (stmt_p, copy_tree_body_r, &id, NULL);
+  /* When you are walking through all the trees and copying them, there is no
+     reason to copy the lambda function body that is spawned in C++.
+     For everything else (_Cilk_for body for C/C++), just do the normal copying,
+     i.e. call copy_tree_body_r.  In C, the cilk_specific_copy_tree_body is
+     defined to copy_tree_body_r in c-objc-common.h file.  */
+  if (wd->type == CILK_BLOCK_FOR)
+    walk_tree (stmt_p, copy_tree_body_r, (void *) &id, NULL);
+  else
+    walk_tree (stmt_p, lang_hooks.cilkplus.cilk_specific_copy_tree_body,
+	       (void *) &id, NULL);
 
   /* See if this function can throw or calls something that should
      not be spawned.  The exception part is only necessary if
diff --git a/gcc/c/c-objc-common.h b/gcc/c/c-objc-common.h
index 6ae7b3e..adab71b 100644
--- a/gcc/c/c-objc-common.h
+++ b/gcc/c/c-objc-common.h
@@ -108,6 +108,9 @@  along with GCC; see the file COPYING3.  If not see
 #undef  LANG_HOOKS_CILKPLUS_GIMPLIFY_SPAWN
 #define LANG_HOOKS_CILKPLUS_GIMPLIFY_SPAWN gimplify_cilk_spawn
 
+#undef  LANG_HOOKS_CILKPLUS_CILK_SPEC_COPY_BODY
+#define LANG_HOOKS_CILKPLUS_CILK_SPEC_COPY_BODY copy_tree_body_r
+
 #undef  LANG_HOOKS_CILKPLUS_FRAME_CLEANUP
 #define LANG_HOOKS_CILKPLUS_FRAME_CLEANUP c_cilk_install_body_w_frame_cleanup
 
diff --git a/gcc/cp/cp-cilkplus.c b/gcc/cp/cp-cilkplus.c
index 5c1090a..414f71e 100644
--- 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,105 @@  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)
+{
+  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;
+}
+
+/* Helper function for walk_tree.  This function will call copy_tree_body_r
+   for all the sub_trees except the first parameter of a lambda function.  */
+
+tree
+cp_cilk_copy_tree_body_r (tree *tp, int *walk_subtrees, void *data)
+{
+  if (TREE_CODE (*tp) == CALL_EXPR)
+    {
+      int nargs = call_expr_nargs (*tp);
+      int start = 0;
+      if (cxx_dialect >= cxx0x && is_lambda_fn_p (*tp))
+	start = 1;
+      for (int ii = start; ii < nargs; ii++)
+	walk_tree (&CALL_EXPR_ARG ((*tp), ii), copy_tree_body_r, data, NULL);
+      /* No need to visit *TP's subtrees since we have done the necessary
+	 ones above.  */
+      *walk_subtrees = 0;
+    }
+  else
+    walk_tree (tp, copy_tree_body_r, data, NULL);
+  return NULL_TREE;
+}
+
+/* Installs BODY into function FNDECL with appropriate exception handling
+   code.  */
+
+void
+cp_cilk_install_body_wframe_cleanup (tree fndecl, tree orig_body)
+{
+  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);
+  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..eb81cb2 100644
--- a/gcc/cp/cp-objcp-common.h
+++ b/gcc/cp/cp-objcp-common.h
@@ -154,4 +154,17 @@  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_CILK_SPEC_COPY_BODY
+#define LANG_HOOKS_CILKPLUS_CILK_SPEC_COPY_BODY cp_cilk_copy_tree_body_r
+
+#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 4e26bd5..9d9f4be 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5355,6 +5355,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);
@@ -6179,11 +6180,19 @@  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);
+extern tree cp_cilk_copy_tree_body_r            (tree *, int *, 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 7d9d5df..64c09d1 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -54,6 +54,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 {
@@ -13866,6 +13867,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 ac2128d..e8e6383 100644
--- a/gcc/cp/except.c
+++ b/gcc/cp/except.c
@@ -1339,4 +1339,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 27f1054..0f9b29b 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -5622,6 +5622,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);
@@ -5766,6 +5767,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 3bc8ccb..1b34434 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -13758,6 +13758,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 81394fa..a07b0ef 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -10415,6 +10415,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 bff7f17..f42ea63 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -6159,6 +6159,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
@@ -8283,6 +8294,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..ca24f06 100644
--- a/gcc/langhooks-def.h
+++ b/gcc/langhooks-def.h
@@ -220,8 +220,13 @@  extern bool lhd_cilk_detect_spawn (tree *);
 #define LANG_HOOKS_CILKPLUS_FRAME_CLEANUP lhd_install_body_with_frame_cleanup
 #define LANG_HOOKS_CILKPLUS_GIMPLIFY_SPAWN lhd_gimplify_expr
 
+/* We do not need a empty function for the cilk-specific becuase they will
+   automatically checked for NULL before calling.  */
+#define LANG_HOOKS_CILKPLUS_CILK_SPEC_COPY_BODY NULL
+
 #define LANG_HOOKS_CILKPLUS {			\
   LANG_HOOKS_CILKPLUS_DETECT_SPAWN_AND_UNWRAP,	\
+  LANG_HOOKS_CILKPLUS_CILK_SPEC_COPY_BODY,      \
   LANG_HOOKS_CILKPLUS_FRAME_CLEANUP,		\
   LANG_HOOKS_CILKPLUS_GIMPLIFY_SPAWN            \
 }
diff --git a/gcc/langhooks.h b/gcc/langhooks.h
index 9539e7d..56b52be 100644
--- a/gcc/langhooks.h
+++ b/gcc/langhooks.h
@@ -146,6 +146,10 @@  struct lang_hooks_for_cilkplus
   /* Returns true if the expression passed in has a spawned function call.  */
   bool (*cilk_detect_spawn_and_unwrap) (tree *);
 
+  /* Cilk specific copy tree body used by C++ because we need a way to bypass
+     the first argument of a lambda function for a _Cilk_spawn.  */
+  tree (*cilk_specific_copy_tree_body) (tree *, int *, void *);
+
   /* 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);
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 fa9246c..90faca4 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]] ""
@@ -56,3 +64,23 @@  dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/AN/*.cc]] " -g -O2
 dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/AN/*.cc]] " -g -O3 -fcilkplus" " "
 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