diff mbox

Cilk Keywords (_Cilk_spawn and _Cilk_sync) for C (and C++)

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

Commit Message

Iyer, Balaji V Oct. 22, 2013, 4:22 p.m. UTC
Hi Jeff,
	I have attached 2 patches - 1 for C and 1 for C++ - along with the changelogs (ChangeLog.cilkplus for C and common changes, cp-ChangeLog.cilkplus for C++ specific files) with the changes you have requested.  Answers to your questions are given below also.

	It passes all its tests and doesn't affect any other existing tests (i.e. by affect I mean fail a passing test or pass a failing test).

Thanks,

Balaji V. Iyer.

> -----Original Message-----
> From: Jeff Law [mailto:law@redhat.com]
> Sent: Monday, October 21, 2013 2:53 PM
> To: Iyer, Balaji V; rth@redhat.com; Jason Merrill (jason@redhat.com); Aldy
> Hernandez (aldyh@redhat.com)
> Cc: gcc-patches@gcc.gnu.org
> Subject: Re: [PATCH] Cilk Keywords (_Cilk_spawn and _Cilk_sync) for C (and C++)
> 
> On 09/11/13 12:18, Iyer, Balaji V wrote:
> > Hello Everyone, Couple weeks back, I had submitted a patch for review
> > that will implement Cilk keywords (_Cilk_spawn and _Cilk_sync) into
> > the C compiler. I recently finished C++ implementation also. In this
> > email, I am attaching 2 patches: 1 for C (and the common parts for C
> > and C++) and 1 for C++. The C++ Changelog is labelled
> > cp-ChangeLog.cilkplus and the other one is just ChangeLog.cilkplus.
> > There isn't much changes in the C patch. Only noticeable changes would
> > be moving functions to the common parts so that C++ can use them.
> >
> > It passes all the tests and does not affect  (by affect I mean fail a
> > passing test or pass a failing one) any of the other tests in the
> > testsuite directory.
> >
> > Is this Ok for trunk?
> Here are my final notes from this pass over the changes.  If you could send an
> updated patch to the list, it would be appreciated.  I may have more comments
> now that I've looked over everything and have a slightly better understanding of
> the overall structure.
> 
> 
> I'm not a C++ guy, but are you going to have to do anything special with
> lambdas?  Such as in cilk_set_spawn_marker?
> 

Actually, if I am not mistaken (and Jason please feel free to correct me), by the time we hit the gimplify phase, a lambda function is sort of converted to a regular function. This is the precise reason for me to wait till gimplify phase to handle _Cilk_spawn and _Cilk_sync conversion. I have a test that will spawn a lambda function in the C++ patch.

The C++ patch pretty much just handles the front-end related stuff. It parses the keyword and then in pt.c, it recognizes the _Cilk_spawn and _Cilk_sync keyword and then passes them along to the next phase, which hits gimplify phase and then we gimplify it like we do it in C.

> I'm going to assume you don't need to do anything for the C++ specific decls in
> copy_decl_for_cilk.  Note I didn't look at any of the C++ specific files, so if
> you're handling it there, that's fine with me.
> 
> I didn't look at the tests closely.  How thorough are those tests, particularly for
> front-end issues?  The reason I ask is those tests will help ensure that folks don't
> break the cilk+ support as often as they might otherwise.  Basically they cover
> for the lack of knowledge about the cilk+ implementation by providing
> developers a heads-up that they broke something.  Are there any internal
> testsuites Intel could contribute to help beef up testing?
> 

I have made effort to make sure that the testsuite will test all the known ways that our customers use _Cilk_spawn and _Cilk_sync. Same goes for the flags in testsuite also. I have also made sure I step through all (if not almost all) the error calls. Also, in C++ I have tried to have cases where it will do operator overloading, lambda function spawning, templatized functions (and their hybrid flavors).

> Can you #undef the helper macros SUBTREE, MODIFIED, INITIALIZED that are
> defined in extract_free_variables?  A nit, but those kind of defines can certainly
> surprised folks.  Actually, unless there's a compelling reason, why not just go
> ahead and make the calls to extract_free_variables explicit and drop the macros
> completely?
> 
I tried to model it sort of like walk_tree routine. I have removed those #defines and have called the function explicitly.

> In all, I didn't see anything that made me say "wait, this is a huge issue we need
> to address".  Presumably you and Aldy worked through those before I got
> involved ;-)
> 

Yup. Aldy was great at catching a lot of issues :-).


> jeff

diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index 9bcea20..d4bb9ac 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -76,7 +76,7 @@ CXX_AND_OBJCXX_OBJS = cp/call.o cp/decl.o cp/expr.o cp/pt.o cp/typeck2.o \
  cp/typeck.o cp/cvt.o cp/except.o cp/friend.o cp/init.o cp/method.o \
  cp/search.o cp/semantics.o cp/tree.o cp/repo.o cp/dump.o cp/optimize.o \
  cp/mangle.o cp/cp-objcp-common.o cp/name-lookup.o cp/cxx-pretty-print.o \
- cp/cp-gimplify.o cp/cp-array-notation.o cp/lambda.o \
+ cp/cp-gimplify.o cp/cp-array-notation.o cp/lambda.o cp/cp-cilk.o \
  cp/vtable-class-hierarchy.o $(CXX_C_OBJS)
 
 # Language-specific object files for C++.
diff --git a/gcc/cp/cp-cilk.c b/gcc/cp/cp-cilk.c
new file mode 100644
index 0000000..0da95e8
--- /dev/null
+++ b/gcc/cp/cp-cilk.c
@@ -0,0 +1,118 @@
+/* Functions to handle Cilk keywords support in C++.
+   Copyright (C) 2011-2013  Free Software Foundation, Inc.
+   Contributed by Balaji V. Iyer <balaji.v.iyer@intel.com>,
+   Intel Corporation.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "cp-tree.h"
+#include "tree-iterator.h"
+#include "cilk.h"
+
+/* 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;
+}
+
+/* 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);
+  extern tree do_begin_catch (void);
+  extern tree do_end_catch (tree);
+  add_local_decl (cfun, frame);
+  
+  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 catch_list = alloc_stmt_list ();
+      tree except_flag = set_cilk_except_flag (frame);
+      tree except_data = set_cilk_except_data (frame);
+      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);
+      tree try_finally_expr = build_stmt (EXPR_LOCATION (body),
+					  TRY_FINALLY_EXPR,
+				     try_catch_expr, dtor);
+      append_to_statement_list (try_finally_expr, &list);
+    }
+  else
+    append_to_statement_list (build_stmt (EXPR_LOCATION (body),
+					  TRY_FINALLY_EXPR, body, dtor), &list);
+}
+
+/* Returns a local variable of type VAR_DECL to store LAMBDA_FN.  */
+
+tree
+cilk_create_lambda_fn_tmp_var (tree lambda_fn)
+{
+  tree return_var = build_decl (EXPR_LOCATION (lambda_fn), VAR_DECL, NULL_TREE, 
+				make_auto ());
+  TREE_USED (return_var) = 1;
+  TREE_ADDRESSABLE (return_var) = 1;
+  DECL_CONTEXT (return_var) = current_function_decl;
+  DECL_INITIAL (return_var) = NULL_TREE;
+  DECL_SEEN_IN_BIND_EXPR_P (return_var) = 1;
+  cp_finish_decl (return_var, lambda_fn, false, NULL_TREE, LOOKUP_NORMAL);
+  add_local_decl (cfun, return_var);
+  return return_var;
+}
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 b1347e2..914a99a 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6177,6 +6177,14 @@ extern void vtv_build_vtable_verify_fndecl      (void);
 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 *);
+
+/* In cp/cp-cilk.c */
+extern void cp_cilk_install_body_wframe_cleanup (tree, tree);
+extern tree cilk_create_lambda_fn_tmp_var       (tree);
 /* -- end of C++ */
 
 #endif /* ! GCC_CP_TREE_H */
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index fe8fe4e..cf93172 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -53,6 +53,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 {
@@ -13882,6 +13883,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 c76d944..8d8f985 100644
--- a/gcc/cp/except.c
+++ b/gcc/cp/except.c
@@ -35,9 +35,9 @@ along with GCC; see the file COPYING3.  If not see
 
 static void push_eh_cleanup (tree);
 static tree prepare_eh_type (tree);
-static tree do_begin_catch (void);
+tree do_begin_catch (void);
 static int dtor_nothrow (tree);
-static tree do_end_catch (tree);
+tree do_end_catch (tree);
 static bool decl_is_java_type (tree decl, int err);
 static void initialize_handler_parm (tree, tree);
 static tree do_allocate_exception (tree);
@@ -182,7 +182,7 @@ do_get_exception_ptr (void)
 /* Build up a call to __cxa_begin_catch, to tell the runtime that the
    exception has been handled.  */
 
-static tree
+tree
 do_begin_catch (void)
 {
   tree fn;
@@ -229,7 +229,7 @@ dtor_nothrow (tree type)
 /* Build up a call to __cxa_end_catch, to destroy the exception object
    for the current catch block if no others are currently using it.  */
 
-static tree
+tree
 do_end_catch (tree type)
 {
   tree fn, cleanup;
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 10a7b96..5b2b829 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -5598,6 +5598,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);
@@ -5742,6 +5743,67 @@ 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;
+	  }
+	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;
+	  }
+	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;
+	    cfun->calls_cilk_spawn = 1;
+	  }
+	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 75f327b..b424e0c 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -300,6 +300,7 @@ typedef struct GTY(()) cp_parser {
 #define IN_OMP_BLOCK		4
 #define IN_OMP_FOR		8
 #define IN_IF_STMT             16
+#define IN_CILK_SPAWN          32
   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 e04bdcc..189c408 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -13746,6 +13746,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 e56052d..4840a2a 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2105,6 +2105,14 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
 
   gcc_assert (!TYPE_P (fn));
 
+  /* When Cilk Plus is enabled, the lambda function need to be stored to
+     a variable because if the function is spawned, then we need some kind
+     of a handle.  */
+  if (flag_enable_cilkplus && cxx_dialect >= cxx0x
+      && TREE_CODE (fn) != VAR_DECL && TREE_CODE (fn) != OVERLOAD
+      && TREE_CODE (fn) != FUNCTION_DECL)
+    fn = cilk_create_lambda_fn_tmp_var (fn);
+
   orig_fn = fn;
 
   if (processing_template_decl)
@@ -10369,9 +10377,15 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
 	  return false;
       return true;
 
+    case CILK_SYNC_STMT:
     case ARRAY_NOTATION_REF:
       return false;
 
+    case CILK_SPAWN_STMT:
+      if (!potential_constant_expression_1 (CILK_SPAWN_FN (t), true, flags))
+	return false;
+      return true;
+
     case FMA_EXPR:
     case VEC_PERM_EXPR:
      for (i = 0; i < 3; ++i)
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index bcb8782..61eaf83 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/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..a358973
--- /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
+      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..aeceda1
--- /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)
+    return 1;
+  if (main2 () != 12)
+    return 2;
+  if (main3 () != 14)
+    return 3;
+  if (main4() != 14)
+    return 4;
+  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..39ed4ee
--- /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)
+    return 1;
+  
+  int t = 40, t_serial = 40;
+  t = fibonacci (t);
+  t_serial = fibonacci_serial (t_serial);
+  if (t != t_serial)
+    return 2;
+
+  short s = 20, s_serial = 20;
+  s = fibonacci (s);
+  s_serial = fibonacci_serial (s_serial);
+  if (s != s_serial)
+    return 3;
+
+#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..bf16f1e
--- /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 = 40;
+     int parallel_fib = fib<int>(z);
+     int serial_fib = sfib(40);
+    if (serial_fib != parallel_fib) 
+      return 1;
+    
+    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..818bca0
--- /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)
+    abort ();
+  if (array[0] != FIRST_NUMBER)
+    abort ();
+  if (array[1] != SECOND_NUMBER)
+    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)
+    abort ();
+  if (array[0] != FIRST_NUMBER)
+    abort ();
+  if (array[1] != SECOND_NUMBER)
+    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..17c0fa5
--- /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)
+    abort ();
+  if (array[0] != FIRST_NUMBER)
+    abort ();
+  if (array[1] != SECOND_NUMBER)
+    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)
+    abort ();
+  if (array[0] != FIRST_NUMBER)
+    abort ();
+  if (array[1] != SECOND_NUMBER)
+    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 7e0fda5..27d5fb7 100644
--- a/gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp
+++ b/gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp
@@ -23,6 +23,11 @@ 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"
+
 dg-init
 dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -fcilkplus" " "
 dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O0 -fcilkplus" " "
@@ -50,3 +55,29 @@ 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" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/CK/*.cc]] " -O0 -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/CK/*.cc]] " -O1 -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/CK/*.cc]] " -O2 -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/CK/*.cc]] " -O3 -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/CK/*.cc]] " -g -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/CK/*.cc]] " -g -O0 -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/CK/*.cc]] " -g -O1 -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/CK/*.cc]] " -g -O2 -ftree-vectorize -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/CK/*.cc]] " -g -O3 -fcilkplus" " "
+dg-finish
+
+dg-init
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -O0 -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -O1 -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -O2 -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -O3 -fcilkplus" " "
+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 -O0 -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -g -O1 -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -g -O2 -ftree-vectorize -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -g -O3 -fcilkplus" " "
+dg-finish

Comments

Jeff Law Oct. 28, 2013, 8:23 p.m. UTC | #1
On 10/22/13 10:22, Iyer, Balaji V wrote:
> Hi Jeff, I have attached 2 patches - 1 for C and 1 for C++ - along
> with the changelogs (ChangeLog.cilkplus for C and common changes,
> cp-ChangeLog.cilkplus for C++ specific files) with the changes you
> have requested.  Answers to your questions are given below also.
>
> It passes all its tests and doesn't affect any other existing tests
> (i.e. by affect I mean fail a passing test or pass a failing test).
>

A note.  cilk-common seems to be a mix of tree and rtl bits.  Those may 
need to be broken into separate files and/or moved around as part of the 
reorganization work that's occurring in GCC right now.  So if Andrew or 
someone else pings you, please respond appropriately.

The C (and shared) parts of this patch are OK.  Jason needs to review 
the C++ front-end changes.

If possible, I recommend installing the C (and shared) bits as well as 
the runtime component if they can build & work w/o the C++ front-end 
changes, then track the C++ front-end changes separately.

Jeff
Iyer, Balaji V Oct. 28, 2013, 9:01 p.m. UTC | #2
> -----Original Message-----
> From: gcc-patches-owner@gcc.gnu.org [mailto:gcc-patches-
> owner@gcc.gnu.org] On Behalf Of Jeff Law
> Sent: Monday, October 28, 2013 4:24 PM
> To: Iyer, Balaji V; rth@redhat.com; Jason Merrill (jason@redhat.com); Aldy
> Hernandez (aldyh@redhat.com)
> Cc: gcc-patches@gcc.gnu.org
> Subject: Re: [PATCH] Cilk Keywords (_Cilk_spawn and _Cilk_sync) for C (and C++)
> 
> On 10/22/13 10:22, Iyer, Balaji V wrote:
> > Hi Jeff, I have attached 2 patches - 1 for C and 1 for C++ - along
> > with the changelogs (ChangeLog.cilkplus for C and common changes,
> > cp-ChangeLog.cilkplus for C++ specific files) with the changes you
> > have requested.  Answers to your questions are given below also.
> >
> > It passes all its tests and doesn't affect any other existing tests
> > (i.e. by affect I mean fail a passing test or pass a failing test).
> >
> 
> A note.  cilk-common seems to be a mix of tree and rtl bits.  Those may need to
> be broken into separate files and/or moved around as part of the reorganization
> work that's occurring in GCC right now.  So if Andrew or someone else pings
> you, please respond appropriately.
> 
> The C (and shared) parts of this patch are OK.  Jason needs to review the C++
> front-end changes.
> 
> If possible, I recommend installing the C (and shared) bits as well as the runtime
> component if they can build & work w/o the C++ front-end changes, then track
> the C++ front-end changes separately.

Thanks! I will extract and check in the Cilk_spawn and _Cilk_sync for C work.

-Balaji V. Iyer.

> 
> Jeff
diff mbox

Patch

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index f0b8c5a..01c3e37 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -872,7 +872,7 @@  RTL_H = $(RTL_BASE_H) $(FLAGS_H) genrtl.h
 READ_MD_H = $(OBSTACK_H) $(HASHTAB_H) read-md.h
 PARAMS_H = params.h params.def
 BUILTINS_DEF = builtins.def sync-builtins.def omp-builtins.def \
-	gtm-builtins.def sanitizer.def cilkplus.def
+	gtm-builtins.def sanitizer.def cilkplus.def cilk-builtins.def
 INTERNAL_FN_DEF = internal-fn.def
 INTERNAL_FN_H = internal-fn.h $(INTERNAL_FN_DEF)
 TREE_CORE_H = tree-core.h coretypes.h all-tree.def tree.def \
@@ -1140,7 +1140,7 @@  C_COMMON_OBJS = c-family/c-common.o c-family/c-cppbuiltin.o c-family/c-dump.o \
   c-family/c-omp.o c-family/c-opts.o c-family/c-pch.o \
   c-family/c-ppoutput.o c-family/c-pragma.o c-family/c-pretty-print.o \
   c-family/c-semantics.o c-family/c-ada-spec.o tree-mudflap.o \
-  c-family/array-notation-common.o c-family/c-ubsan.o
+  c-family/array-notation-common.o c-family/cilk.o c-family/c-ubsan.o
 
 # Language-independent object files.
 # We put the insn-*.o files first so that a parallel make will build
@@ -1185,6 +1185,7 @@  OBJS = \
 	cgraphbuild.o \
 	cgraphunit.o \
 	cgraphclones.o \
+	cilk-common.o \
 	combine.o \
 	combine-stack-adj.o \
 	compare-elim.o \
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 5df5c54..586da1f 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -48,6 +48,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "diagnostic-core.h"
 #include "builtins.h"
 #include "ubsan.h"
+#include "cilk.h"
 
 
 static tree do_mpc_arg1 (tree, tree, int (*)(mpc_ptr, mpc_srcptr, mpc_rnd_t));
@@ -234,6 +235,10 @@  is_builtin_name (const char *name)
     return true;
   if (strncmp (name, "__atomic_", 9) == 0)
     return true;
+  if (flag_enable_cilkplus 
+      && (!strcmp (name, "__cilkrts_detach")   
+	  || !strcmp (name, "__cilkrts_pop_frame")))
+    return true;
   return false;
 }
 
@@ -6792,6 +6797,14 @@  expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
       expand_builtin_set_thread_pointer (exp);
       return const0_rtx;
 
+    case BUILT_IN_CILK_DETACH:
+      expand_builtin_cilk_detach (exp);
+      return const0_rtx;
+      
+    case BUILT_IN_CILK_POP_FRAME:
+      expand_builtin_cilk_pop_frame (exp);
+      return const0_rtx;
+
     default:	/* just do library call, if unknown builtin */
       break;
     }
diff --git a/gcc/builtins.def b/gcc/builtins.def
index 8ccf3ae..12c56be 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -147,6 +147,13 @@  along with GCC; see the file COPYING3.  If not see
                false, true, true, ATTRS, false, \
 	       (flag_openmp || flag_tree_parallelize_loops))
 
+/* Builtin used by implementation of Cilk Plus.  Most of these are decomposed
+   by the compiler but a few are implemented in libcilkrts.  */ 
+#undef DEF_CILK_BUILTIN_STUB
+#define DEF_CILK_BUILTIN_STUB(ENUM, NAME) \
+  DEF_BUILTIN (ENUM, NAME, BUILT_IN_NORMAL, BT_LAST, BT_LAST, false, false, \
+	       false, ATTR_LAST, false, false)
+
 /* Builtin used by the implementation of GNU TM.  These
    functions are mapped to the actual implementation of the STM library. */
 #undef DEF_TM_BUILTIN
@@ -846,6 +853,9 @@  DEF_GCC_BUILTIN (BUILT_IN_LINE, "LINE", BT_FN_INT, ATTR_NOTHROW_LEAF_LIST)
 /* OpenMP builtins.  */
 #include "omp-builtins.def"
 
+/* Cilk keywords builtins.  */
+#include "cilk-builtins.def"
+
 /* GTM builtins. */
 #include "gtm-builtins.def"
 
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index d830288..c2d958c 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -410,6 +410,8 @@  const struct c_common_resword c_common_reswords[] =
   { "_Alignof",		RID_ALIGNOF,   D_CONLY },
   { "_Bool",		RID_BOOL,      D_CONLY },
   { "_Complex",		RID_COMPLEX,	0 },
+  { "_Cilk_spawn",      RID_CILK_SPAWN, 0 },
+  { "_Cilk_sync",       RID_CILK_SYNC,  0 },
   { "_Imaginary",	RID_IMAGINARY, D_CONLY },
   { "_Decimal32",       RID_DFLOAT32,  D_CONLY | D_EXT },
   { "_Decimal64",       RID_DFLOAT64,  D_CONLY | D_EXT },
@@ -5223,6 +5225,9 @@  c_define_builtins (tree va_list_ref_type_node, tree va_list_arg_type_node)
 
   if (flag_mudflap)
     mudflap_init ();
+
+  if (flag_enable_cilkplus)
+    cilk_init_builtins ();
 }
 
 /* Like get_identifier, but avoid warnings about null arguments when
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 1f8333e..8dd40c8 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -148,6 +148,9 @@  enum rid
   /* C++11 */
   RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
 
+  /* Cilk Plus keywords.  */
+  RID_CILK_SPAWN, RID_CILK_SYNC,
+  
   /* Objective-C ("AT" reserved words - they are only keywords when
      they follow '@')  */
   RID_AT_ENCODE,   RID_AT_END,
@@ -1356,4 +1359,18 @@  extern void cilkplus_extract_an_triplets (vec<tree, va_gc> *, size_t, size_t,
 					  vec<vec<an_parts> > *);
 extern vec <tree, va_gc> *fix_sec_implicit_args
   (location_t, vec <tree, va_gc> *, vec<an_loop_parts>, size_t, tree);
+
+/* In cilk.c.  */
+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 bool cilk_detect_spawn_and_unwrap (tree *);
+extern bool cilk_set_spawn_marker (location_t, tree);
+extern tree build_cilk_sync (void);
+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);
+
 #endif /* ! GCC_C_COMMON_H */
diff --git a/gcc/c-family/cilk.c b/gcc/c-family/cilk.c
new file mode 100644
index 0000000..91f10d5
--- /dev/null
+++ b/gcc/c-family/cilk.c
@@ -0,0 +1,1305 @@ 
+/* This file is part of the Intel(R) Cilk(TM) Plus support
+   This file contains the CilkPlus Intrinsics
+   Copyright (C) 2013 Free Software Foundation, Inc.
+   Contributed by Balaji V. Iyer <balaji.v.iyer@intel.com>,
+   Intel Corporation
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "langhooks.h"
+#include "gimple.h"
+#include "tree-iterator.h"
+#include "tree-inline.h"
+#include "c-family/c-common.h"
+#include "toplev.h" 
+#include "cgraph.h"
+#include "diagnostic.h"
+#include "cilk.h"
+
+enum add_variable_type {
+    /* Reference to previously-defined variable.  */
+    ADD_READ,
+    /* Definition of a new variable in inner-scope.  */
+    ADD_BIND,
+    /* Write to possibly previously-defined variable.  */
+    ADD_WRITE
+};
+
+enum cilk_block_type {
+    /* Indicates a _Cilk_spawn block.  30 was an arbitary number picked for 
+       ease of debugging.  */
+    CILK_BLOCK_SPAWN = 30,
+    /* Indicates _Cilk_for statement block.  */
+    CILK_BLOCK_FOR
+};
+
+struct wrapper_data
+{
+  /* Kind of function to be created.  */
+  enum cilk_block_type type;
+  /* Signature of helper function.  */
+  tree fntype;
+  /* Containing function.  */
+  tree context;
+  /* Disposition of all variables in the inner statement.  */
+  struct pointer_map_t *decl_map;
+  /* True if this function needs a static chain.  */
+  bool nested;
+  /* Arguments to be passed to wrapper function, currently a list.  */
+  tree arglist;
+  /* Argument types, a list.  */
+  tree argtypes;
+  /* Incoming parameters.  */
+  tree parms;
+  /* Outer BLOCK object.  */
+  tree block;
+};
+
+static void extract_free_variables (tree, struct wrapper_data *,
+				    enum add_variable_type);
+static HOST_WIDE_INT cilk_wrapper_count;
+
+/* Marks the CALL_EXPR or FUNCTION_DECL, FCALL, as a spawned function call
+   and the current function as a spawner.  Emit error if the function call
+   is outside a function or if a non function-call is spawned.  */
+
+inline bool
+cilk_set_spawn_marker (location_t loc, tree fcall)
+{
+  if (!current_function_decl)
+    {
+      error_at (loc, "%<_Cilk_spawn%> may only be used inside a function");
+      return false;
+    }
+  else if (fcall == error_mark_node)
+    /* Error reporting here is not necessary here since if FCALL is an
+       error_mark_node, the function marking it as error would have reported
+       it.  */
+    return false; 
+  else if (TREE_CODE (fcall) != CALL_EXPR
+	   && TREE_CODE (fcall) != FUNCTION_DECL
+	   /* In C++, TARGET_EXPR is generated when we have an overloaded
+	      '=' operator.  */
+	   && TREE_CODE (fcall) != TARGET_EXPR)
+    { 
+      error_at (loc, "only function calls can be spawned");
+      return false;
+    }
+  else
+    {
+      cfun->calls_cilk_spawn = true;
+      return true;
+    }
+}
+
+/* This function will output the exit conditions for a spawn call.  */
+
+tree
+create_cilk_function_exit (tree frame, bool detaches, bool needs_sync)
+{
+  tree epi = alloc_stmt_list ();
+
+  if (needs_sync) 
+    append_to_statement_list (build_cilk_sync (), &epi);
+  tree func_ptr = build1 (ADDR_EXPR, cilk_frame_ptr_type_decl, frame);
+  tree pop_frame = build_call_expr (cilk_pop_fndecl, 1, func_ptr);
+  tree worker = cilk_dot (frame, CILK_TI_FRAME_WORKER, 0);
+  tree current = cilk_arrow (worker, CILK_TI_WORKER_CUR, 0);
+  tree parent = cilk_dot (frame, CILK_TI_FRAME_PARENT, 0);
+  tree set_current = build2 (MODIFY_EXPR, void_type_node, current, parent);
+  append_to_statement_list (set_current, &epi);
+  append_to_statement_list (pop_frame, &epi);
+  tree call = build_call_expr (cilk_leave_fndecl, 1, func_ptr);
+  if (!detaches)
+    {
+      tree flags = cilk_dot (frame, CILK_TI_FRAME_FLAGS, false);
+      tree flags_cmp_expr = fold_build2 (NE_EXPR, TREE_TYPE (flags), flags, 
+					 build_int_cst (TREE_TYPE (flags), 
+							CILK_FRAME_VERSION));
+      call = fold_build3 (COND_EXPR, void_type_node, flags_cmp_expr,
+			  call, build_empty_stmt (EXPR_LOCATION (flags)));
+    }
+  append_to_statement_list (call, &epi);  
+  return epi;
+}
+
+/* Trying to get the correct cfun for the FUNCTION_DECL indicated by OUTER.  */
+
+static void
+pop_cfun_to (tree outer)
+{
+  pop_cfun ();
+  current_function_decl = outer;
+  gcc_assert (cfun == DECL_STRUCT_FUNCTION (current_function_decl));
+  gcc_assert (cfun->decl == current_function_decl);
+}
+
+/* This function does whatever is necessary to make the compiler emit a newly 
+   generated function, FNDECL.  */
+
+static void
+call_graph_add_fn (tree fndecl)
+{
+  const tree outer = current_function_decl;
+  struct function *f = DECL_STRUCT_FUNCTION (fndecl);
+  gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
+
+  f->is_cilk_function = 1;
+  f->curr_properties = cfun->curr_properties;
+  gcc_assert (cfun == DECL_STRUCT_FUNCTION (outer)); 
+  gcc_assert (cfun->decl == outer);
+
+  push_cfun (f);
+  cgraph_create_node (fndecl);
+  pop_cfun_to (outer);
+}
+
+/* Return true if this is a tree which is allowed to contain a spawn as 
+   operand 0.
+   A spawn call may be wrapped in a series of unary operations such
+   as conversions.  These conversions need not be "useless"
+   to be disregarded because they are retained in the spawned
+   statement.  They are bypassed only to look for a spawn
+   within.
+   A comparison to constant is simple enough to allow, and
+   is used to convert to bool.  */
+
+static bool
+cilk_ignorable_spawn_rhs_op (tree exp)
+{
+  enum tree_code code = TREE_CODE (exp);
+  switch (TREE_CODE_CLASS (code))
+    {
+    case tcc_expression:
+      return code == ADDR_EXPR;
+    case tcc_comparison:
+      /* We need the spawn as operand 0 for now.   That's where it
+	 appears in the only case we really care about, conversion
+	 to bool.  */
+      return (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST);
+    case tcc_unary:
+    case tcc_reference:
+      return true;
+    default:
+      return false;
+    }
+}
+
+/* Helper function for walk_tree.  If *TP is a CILK_SPAWN_STMT, then unwrap
+   this "wrapper."  The function returns NULL_TREE regardless.  */
+
+static tree
+unwrap_cilk_spawn_stmt (tree *tp, int *walk_subtrees, void *)
+{
+  if (TREE_CODE (*tp) == CILK_SPAWN_STMT)
+    {
+      *tp = CILK_SPAWN_FN (*tp);
+      *walk_subtrees = 0;
+    }
+  return NULL_TREE;
+}
+
+/* Returns true when EXP is a CALL_EXPR with _Cilk_spawn in front.  Unwraps
+   CILK_SPAWN_STMT wrapper from the CALL_EXPR in *EXP0 statement.  */
+
+static bool
+recognize_spawn (tree exp, tree *exp0)
+{
+  bool spawn_found = false;
+  if (TREE_CODE (exp) == CILK_SPAWN_STMT)
+    {
+      /* Remove the CALL_EXPR from CILK_SPAWN_STMT wrapper.  */
+      exp = CILK_SPAWN_FN (exp);
+      walk_tree (exp0, unwrap_cilk_spawn_stmt, NULL, NULL);
+      spawn_found = true;
+    }
+  return spawn_found;
+}
+
+/* Returns true if *EXP0 is a recognized form of spawn.  Recognized forms are,
+   after conversion to void, a call expression at outer level or an assignment
+   at outer level with the right hand side being a spawned call.
+   In addition to this, it also unwraps the CILK_SPAWN_STMT cover from the
+   CALL_EXPR that is being spawned.
+   Note that `=' in C++ may turn into a CALL_EXPR rather than a MODIFY_EXPR.  */
+
+bool
+cilk_detect_spawn_and_unwrap (tree *exp0)
+{
+  tree exp = *exp0;
+
+  if (!TREE_SIDE_EFFECTS (exp))
+    return false;
+
+  /* Strip off any conversion to void.  It does not affect whether spawn 
+     is supported here.  */
+  if (TREE_CODE (exp) == CONVERT_EXPR && VOID_TYPE_P (TREE_TYPE (exp)))
+    exp = TREE_OPERAND (exp, 0);
+
+  if (TREE_CODE (exp) == MODIFY_EXPR || TREE_CODE (exp) == INIT_EXPR)
+    exp = TREE_OPERAND (exp, 1);
+
+  while (cilk_ignorable_spawn_rhs_op (exp))
+    exp = TREE_OPERAND (exp, 0);
+
+  if (TREE_CODE (exp) == TARGET_EXPR)
+    if (TARGET_EXPR_INITIAL (exp)
+	&& TREE_CODE (TARGET_EXPR_INITIAL (exp)) != AGGR_INIT_EXPR)
+      exp = TARGET_EXPR_INITIAL (exp);
+
+  /* Happens with C++ TARGET_EXPR.  */
+  if (exp == NULL_TREE)
+    return false;
+
+  while (TREE_CODE (exp) == CLEANUP_POINT_EXPR || TREE_CODE (exp) == EXPR_STMT)
+    exp = TREE_OPERAND (exp, 0);
+  
+  /* Now we should have a CALL_EXPR with a CILK_SPAWN_STMT wrapper around 
+     it, or return false.  */
+  if (recognize_spawn (exp, exp0))
+    return true;
+  return false;
+}
+
+/* This function will build and return a FUNCTION_DECL using information 
+   from *WD.  */
+
+static tree
+create_cilk_helper_decl (struct wrapper_data *wd)
+{
+  char name[20];
+  if (wd->type == CILK_BLOCK_FOR)
+    sprintf (name, "_cilk_for_%ld", cilk_wrapper_count++);
+  else if (wd->type == CILK_BLOCK_SPAWN)
+    sprintf (name, "_cilk_spn_%ld", cilk_wrapper_count++);
+  else
+    gcc_unreachable (); 
+  
+  clean_symbol_name (name);
+  tree fndecl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL, 
+			    get_identifier (name), wd->fntype);
+
+  TREE_PUBLIC (fndecl) = 0;
+  TREE_STATIC (fndecl) = 1;
+  TREE_USED (fndecl) = 1;
+  DECL_ARTIFICIAL (fndecl) = 0;
+  DECL_IGNORED_P (fndecl) = 0;
+  DECL_EXTERNAL (fndecl) = 0;
+
+  DECL_CONTEXT (fndecl) = wd->context; 
+  tree block = make_node (BLOCK);
+  DECL_INITIAL (fndecl) = block;
+  TREE_USED (block) = 1;
+  gcc_assert (!DECL_SAVED_TREE (fndecl));
+
+  /* Inlining would defeat the purpose of this wrapper.
+     Either it secretly switches stack frames or it allocates
+     a stable stack frame to hold function arguments even if
+     the parent stack frame is stolen.  */
+  DECL_UNINLINABLE (fndecl) = 1;
+
+  tree result_decl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, 
+				 void_type_node);
+  DECL_ARTIFICIAL (result_decl) = 0;
+  DECL_IGNORED_P (result_decl) = 1;
+  DECL_CONTEXT (result_decl) = fndecl;
+  DECL_RESULT (fndecl) = result_decl;
+  
+  return fndecl;
+}
+
+/* A function used by walk tree to find wrapper parms.  */
+
+static bool
+wrapper_parm_cb (const void *key0, void **val0, void *data)
+{
+  struct wrapper_data *wd = (struct wrapper_data *) data;
+  tree arg = * (tree *)&key0;
+  tree val = (tree)*val0;
+  tree parm;
+
+  if (val == error_mark_node || val == arg)
+    return true;
+
+  if (TREE_CODE (val) == PAREN_EXPR)
+    {
+      /* We should not reach here with a register receiver.
+	 We may see a register variable modified in the
+	 argument list.  Because register variables are
+	 worker-local we don't need to work hard to support
+	 them in code that spawns.  */
+      if ((TREE_CODE (arg) == VAR_DECL) && DECL_HARD_REGISTER (arg))
+	{
+	  error_at (EXPR_LOCATION (arg),
+		    "explicit register variable %qD may not be modified in "
+		    "spawn", arg);
+	  arg = null_pointer_node;
+	}
+      else
+	arg = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (arg)), arg);
+	
+      val = TREE_OPERAND (val, 0);
+      *val0 = val;
+      gcc_assert (TREE_CODE (val) == INDIRECT_REF);
+      parm = TREE_OPERAND (val, 0);
+      STRIP_NOPS (parm);
+    }
+  else
+    parm = val;
+  TREE_CHAIN (parm) = wd->parms;
+  wd->parms = parm;
+  wd->argtypes = tree_cons (NULL_TREE, TREE_TYPE (parm), wd->argtypes); 
+  wd->arglist = tree_cons (NULL_TREE, arg, wd->arglist); 
+  return true;
+}
+
+/* This function is used to build a wrapper of a certain type.  */
+
+static void
+build_wrapper_type (struct wrapper_data *wd)
+{
+  wd->arglist = NULL_TREE;
+  wd->parms = NULL_TREE;
+  wd->argtypes = void_list_node;
+
+  pointer_map_traverse (wd->decl_map, wrapper_parm_cb, wd);
+  gcc_assert (wd->type != CILK_BLOCK_FOR);
+
+  /* Now build a function.
+     Its return type is void (all side effects are via explicit parameters).
+     Its parameters are WRAPPER_PARMS with type WRAPPER_TYPES.
+     Actual arguments in the caller are WRAPPER_ARGS.  */
+  wd->fntype = build_function_type (void_type_node, wd->argtypes);
+}
+
+/* This function checks all the CALL_EXPRs in *TP found by cilk_outline.  */
+
+static tree
+check_outlined_calls (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, 
+		      void *data)
+{
+  bool *throws = (bool *) data;
+  tree t = *tp;
+  int flags;
+
+  if (TREE_CODE (t) != CALL_EXPR)
+    return 0;
+  flags = call_expr_flags (t);
+
+  if (!(flags & ECF_NOTHROW) && flag_exceptions)
+    *throws = true;
+  if (flags & ECF_RETURNS_TWICE)
+    error_at (EXPR_LOCATION (t), 
+	      "cannot spawn call to function that returns twice");
+  return 0;
+}
+
+/* Each DECL in the source code (spawned statement) is passed to this function
+   once.  Each instance of the DECL is replaced with the result of this 
+   function.
+
+   The parameters of the wrapper should have been entered into the map already.
+   This function only deals with variables with scope limited to the 
+   spawned expression.  */
+
+static tree
+copy_decl_for_cilk (tree decl, copy_body_data *id)
+{
+  switch (TREE_CODE (decl))
+    {
+    case VAR_DECL:
+      return copy_decl_no_change (decl, id);
+
+    case LABEL_DECL:
+      error_at (EXPR_LOCATION (decl), "invalid use of label %q+D in "
+		"%<_Cilk_spawn%>", 
+		decl);
+      return error_mark_node;
+
+    case RESULT_DECL:
+    case PARM_DECL:
+      /* RESULT_DECL and PARM_DECL has already been entered into the map.  */
+    default:
+      gcc_unreachable ();
+      return error_mark_node;
+    }
+}
+
+/* Copy all local variables.  */
+
+static bool
+for_local_cb (const void *k_v, void **vp, void *p)
+{
+  tree k = *(tree *) &k_v;
+  tree v = (tree) *vp;
+
+  if (v == error_mark_node)
+    *vp = copy_decl_no_change (k, (copy_body_data *) p);
+  return true;
+}
+
+/* Copy all local declarations from a _Cilk_spawned function's body.  */
+
+static bool
+wrapper_local_cb (const void *k_v, void **vp, void *data)
+{
+  copy_body_data *id = (copy_body_data *) data;
+  tree key = *(tree *) &k_v;
+  tree val = (tree) *vp;
+
+  if (val == error_mark_node)
+    *vp = copy_decl_for_cilk (key, id);
+
+  return true;
+}
+
+/* Alter a tree STMT from OUTER_FN to form the body of INNER_FN.  */
+
+static void
+cilk_outline (tree inner_fn, tree *stmt_p, struct wrapper_data *wd)
+{
+  const tree outer_fn = wd->context;	      
+  const bool nested = (wd->type == CILK_BLOCK_FOR);
+  copy_body_data id;
+  bool throws;
+
+  DECL_STATIC_CHAIN (outer_fn) = 1;
+
+  memset (&id, 0, sizeof (id));
+  /* Copy from the function containing the spawn...  */
+  id.src_fn = outer_fn;
+
+  /* ...to the wrapper.  */
+  id.dst_fn = inner_fn; 
+  id.src_cfun = DECL_STRUCT_FUNCTION (outer_fn);
+
+  /* There shall be no RETURN in spawn helper.  */
+  id.retvar = 0; 
+  id.decl_map = wd->decl_map;
+  id.copy_decl = nested ? copy_decl_no_change : copy_decl_for_cilk;
+  id.block = DECL_INITIAL (inner_fn);
+  id.transform_lang_insert_block = NULL;
+
+  id.transform_new_cfg = true;
+  id.transform_call_graph_edges = CB_CGE_MOVE;
+  id.remap_var_for_cilk = true;
+  id.regimplify = true; /* unused? */
+
+  insert_decl_map (&id, wd->block, DECL_INITIAL (inner_fn));
+
+  /* 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);
+
+  /* See if this function can throw or calls something that should
+     not be spawned.  The exception part is only necessary if
+     flag_exceptions && !flag_non_call_exceptions.  */
+  throws = false ;
+  (void) walk_tree_without_duplicates (stmt_p, check_outlined_calls, &throws);
+}
+
+/* Generate the body of a wrapper function that assigns the
+   result of the expression RHS into RECEIVER.  RECEIVER must
+   be NULL if this is not a spawn -- the wrapper will return
+   a value.  If this is a spawn, the wrapper will return void.  */
+
+static tree
+create_cilk_wrapper_body (tree stmt, struct wrapper_data *wd)
+{
+  const tree outer = current_function_decl;
+  tree fndecl;
+  tree p;
+
+   /* Build the type of the wrapper and its argument list from the
+     variables that it requires.  */
+  build_wrapper_type (wd);
+
+  /* Emit a function that takes WRAPPER_PARMS incoming and applies ARGS 
+     (modified) to the wrapped function.  Return the wrapper and modified ARGS 
+     to the caller to generate a function call.  */
+  fndecl = create_cilk_helper_decl (wd);
+  push_struct_function (fndecl);
+  if (wd->nested && (wd->type == CILK_BLOCK_FOR))
+    {
+      gcc_assert (TREE_VALUE (wd->arglist) == NULL_TREE);
+      TREE_VALUE (wd->arglist) = build2 (FDESC_EXPR, ptr_type_node,
+					 fndecl, integer_one_node);
+    }
+  DECL_ARGUMENTS (fndecl) = wd->parms;
+
+  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);
+  gcc_assert (DECL_SAVED_TREE (fndecl));
+
+  pop_cfun_to (outer);
+
+  /* Recognize the new function.  */
+  call_graph_add_fn (fndecl);
+  return fndecl;
+}
+
+/* Initializes the wrapper data structure.  */
+
+static void
+init_wd (struct wrapper_data *wd, enum cilk_block_type type)
+{
+  wd->type = type;
+  wd->fntype = NULL_TREE;
+  wd->context = current_function_decl;
+  wd->decl_map = pointer_map_create ();
+  /* _Cilk_for bodies are always nested.  Others start off as 
+     normal functions.  */
+  wd->nested = (type == CILK_BLOCK_FOR);
+  wd->arglist = NULL_TREE;
+  wd->argtypes = NULL_TREE;
+  wd->block = NULL_TREE;
+}
+
+/* Clears the wrapper data structure.  */
+
+static void
+free_wd (struct wrapper_data *wd)
+{
+  pointer_map_destroy (wd->decl_map);
+  wd->nested = false;
+  wd->arglist = NULL_TREE;
+  wd->argtypes = NULL_TREE;
+  wd->parms = NULL_TREE;
+}
+
+
+ /* Given a variable in an expression to be extracted into
+   a helper function, declare the helper function parameter
+   to receive it.
+
+   On entry the value of the (key, value) pair may be
+
+   (*, error_mark_node) -- Variable is private to helper function,
+   do nothing.
+
+   (var, var) -- Reference to outer scope (function or global scope).
+
+   (var, integer 0) -- Capture by value, save newly-declared PARM_DECL
+   for value in value slot.
+
+   (var, integer 1) -- Capture by reference, declare pointer to type
+   as new PARM_DECL and store (spawn_stmt (indirect_ref (parm)).
+   
+   (var, ???) -- Pure output argument, handled similarly to above.
+*/
+
+static bool
+declare_one_free_variable (const void *var0, void **map0,
+			   void *data ATTRIBUTE_UNUSED)
+{
+  const_tree var = (const_tree) var0;
+  tree map = (tree)*map0;
+  tree var_type = TREE_TYPE (var), arg_type;
+  bool by_reference;
+  tree parm;
+
+  gcc_assert (DECL_P (var));
+
+  /* Ignore truly local variables.  */
+  if (map == error_mark_node)
+    return true;
+  /* Ignore references to the parent function.  */
+  if (map == var)
+    return true;
+
+  gcc_assert (TREE_CODE (map) == INTEGER_CST);
+
+  /* A value is passed by reference if:
+
+     1. It is addressable, so that a copy may not be made.
+     2. It is modified in the spawned statement.
+     In the future this function may want to arrange
+     a warning if the spawned statement is a loop body
+     because an output argument would indicate a race.
+     Note: Earlier passes must have marked the variable addressable.
+     3. It is expensive to copy.  */
+  by_reference =
+    (TREE_ADDRESSABLE (var_type)
+     /* Arrays must be passed by reference.  This is required for C
+	semantics -- arrays are not first class objects.  Other
+	aggregate types can and should be passed by reference if
+	they are not passed to the spawned function.  We aren't yet
+	distinguishing safe uses in argument calculation from unsafe
+	uses as outgoing function arguments, so we make a copy to
+	stabilize the value.  */
+     || TREE_CODE (var_type) == ARRAY_TYPE
+     || (tree) map == integer_one_node);
+
+  if (by_reference)
+    var_type = build_qualified_type (build_pointer_type (var_type),
+				     TYPE_QUAL_RESTRICT);
+  gcc_assert (!TREE_ADDRESSABLE (var_type));
+
+  /* Maybe promote to int.  */
+  if (INTEGRAL_TYPE_P (var_type) && COMPLETE_TYPE_P (var_type)
+      && INT_CST_LT_UNSIGNED (TYPE_SIZE (var_type),
+			      TYPE_SIZE (integer_type_node)))
+    arg_type = integer_type_node;
+  else
+    arg_type = var_type;
+
+  parm = build_decl (UNKNOWN_LOCATION, PARM_DECL, NULL_TREE, var_type);
+  DECL_ARG_TYPE (parm) = arg_type;
+  DECL_ARTIFICIAL (parm) = 0;
+  TREE_READONLY (parm) = 1;
+  
+  if (by_reference)
+    {
+      parm = build1 (INDIRECT_REF, TREE_TYPE (var_type), parm);
+      parm = build1 (PAREN_EXPR, void_type_node, parm);
+    }
+  *map0 = parm;
+  return true;
+}
+ 
+/* Returns a wrapper function for a _Cilk_spawn.  */
+
+static tree
+create_cilk_wrapper (tree exp, tree *args_out)
+{
+  struct wrapper_data wd;
+  tree fndecl;
+
+  init_wd (&wd, CILK_BLOCK_SPAWN);
+
+  if (TREE_CODE (exp) == CONVERT_EXPR)
+    exp = TREE_OPERAND (exp, 0);
+  
+  /* Special handling for top level INIT_EXPR.  Usually INIT_EXPR means the 
+     variable is defined in the spawned expression and can be private to the 
+     spawn helper.  A top level INIT_EXPR defines a variable to be initialized 
+     by spawn and the variable must remain in the outer function.  */
+  if (TREE_CODE (exp) == INIT_EXPR)
+    {
+      extract_free_variables (TREE_OPERAND (exp, 0), &wd, ADD_WRITE);
+      extract_free_variables (TREE_OPERAND (exp, 1), &wd, ADD_READ);
+      /* TREE_TYPE should be void.  Be defensive.  */
+      if (TREE_TYPE (exp) != void_type_node)
+	extract_free_variables (TREE_TYPE (exp), &wd, ADD_READ);
+    }
+  else
+    extract_free_variables (exp, &wd, ADD_READ);
+  pointer_map_traverse (wd.decl_map, declare_one_free_variable, &wd);
+  wd.block = TREE_BLOCK (exp);
+  if (!wd.block)
+    wd.block = DECL_INITIAL (current_function_decl);
+
+  /* Now fvars maps the old variable to incoming variable.  Update
+     the expression and arguments to refer to the new names.  */
+  fndecl = create_cilk_wrapper_body (exp, &wd);
+  *args_out = wd.arglist;
+  
+  free_wd (&wd);
+
+  return fndecl;
+}
+
+/* Transform *SPAWN_P, a spawned CALL_EXPR, to gimple.  *SPAWN_P can be a
+   CALL_EXPR, INIT_EXPR or MODIFY_EXPR.  Returns GS_OK if everything is fine,
+   and GS_UNHANDLED, otherwise.  */
+
+int
+gimplify_cilk_spawn (tree *spawn_p, gimple_seq *before ATTRIBUTE_UNUSED,
+		     gimple_seq *after ATTRIBUTE_UNUSED)
+{
+  tree expr = *spawn_p;
+  tree function, call1, call2, new_args;
+  tree ii_args = NULL_TREE;
+  int total_args = 0, ii = 0;
+  tree *arg_array;
+  tree setjmp_cond_expr = NULL_TREE;
+  tree setjmp_expr, spawn_expr, setjmp_value = NULL_TREE;
+
+  cfun->calls_cilk_spawn = 1;
+  cfun->is_cilk_function = 1;
+
+  /* Remove CLEANUP_POINT_EXPR and EXPR_STMT from *spawn_p.  */
+  while (TREE_CODE (expr) == CLEANUP_POINT_EXPR
+	 || TREE_CODE (expr) == EXPR_STMT)
+    expr = TREE_OPERAND (expr, 0);
+  
+  new_args = NULL;
+  function = create_cilk_wrapper (expr, &new_args);
+
+  /* This should give the number of parameters.  */
+  total_args = list_length (new_args);
+  arg_array = XNEWVEC (tree, total_args);
+
+  ii_args = new_args;
+  for (ii = 0; ii < total_args; ii++)
+    {
+      arg_array[ii] = TREE_VALUE (ii_args);
+      ii_args = TREE_CHAIN (ii_args);
+    }
+  
+  TREE_USED (function) = 1;
+  rest_of_decl_compilation (function, 0, 0);
+
+  call1 = cilk_call_setjmp (cfun->cilk_frame_decl);
+
+  if (*arg_array == NULL_TREE)
+    call2 = build_call_expr (function, 0);
+  else 
+    call2 = build_call_expr_loc_array (EXPR_LOCATION (*spawn_p), function, 
+					 total_args, arg_array);
+  *spawn_p = alloc_stmt_list ();
+  tree f_ptr_type = build_pointer_type (TREE_TYPE (cfun->cilk_frame_decl));
+  tree frame_ptr = build1 (ADDR_EXPR, f_ptr_type, cfun->cilk_frame_decl);
+  tree save_fp = build_call_expr (cilk_save_fp_fndecl, 1, frame_ptr);
+  append_to_statement_list (save_fp, spawn_p);		  
+  setjmp_value = create_tmp_var (TREE_TYPE (call1), NULL);
+  setjmp_expr = fold_build2 (MODIFY_EXPR, void_type_node, setjmp_value, call1);
+
+  append_to_statement_list_force (setjmp_expr, spawn_p);
+  
+  setjmp_cond_expr = fold_build2 (EQ_EXPR, TREE_TYPE (call1), setjmp_value,
+				  build_int_cst (TREE_TYPE (call1), 0));
+  spawn_expr = fold_build3 (COND_EXPR, void_type_node, setjmp_cond_expr,
+			    call2, build_empty_stmt (EXPR_LOCATION (call1)));
+  append_to_statement_list (spawn_expr, spawn_p);
+
+  return GS_OK;
+}
+
+/* Make the frames necessary for a spawn call.  */
+
+tree
+make_cilk_frame (tree fn)
+{
+  struct function *f = DECL_STRUCT_FUNCTION (fn);
+  tree decl;
+
+  if (f->cilk_frame_decl)
+    return f->cilk_frame_decl;
+
+  decl = build_decl (EXPR_LOCATION (fn), VAR_DECL, NULL_TREE, 
+		     cilk_frame_type_decl);
+  DECL_CONTEXT (decl) = fn;
+  DECL_SEEN_IN_BIND_EXPR_P (decl) = 1;
+  f->cilk_frame_decl = decl;
+  return decl;
+}
+
+/* Returns a STATEMENT_LIST with all the pedigree operations required for
+   install body with frame cleanup functions.  FRAME_PTR is the pointer to
+   __cilkrts_stack_frame created by make_cilk_frame.  */
+
+tree
+cilk_install_body_pedigree_operations (tree frame_ptr)
+{
+  tree body_list = alloc_stmt_list ();
+  tree enter_frame = build_call_expr (cilk_enter_fast_fndecl, 1, frame_ptr); 
+  append_to_statement_list (enter_frame, &body_list);
+  
+  tree parent = cilk_arrow (frame_ptr, CILK_TI_FRAME_PARENT, 0);
+  tree worker = cilk_arrow (frame_ptr, CILK_TI_FRAME_WORKER, 0);
+
+  tree pedigree = cilk_arrow (frame_ptr, CILK_TI_FRAME_PEDIGREE, 0);
+  tree pedigree_rank = cilk_dot (pedigree, CILK_TI_PEDIGREE_RANK, 0);
+  tree parent_pedigree = cilk_dot (pedigree, CILK_TI_PEDIGREE_PARENT, 0);
+  tree pedigree_parent = cilk_arrow (parent, CILK_TI_FRAME_PEDIGREE, 0);
+  tree pedigree_parent_rank = cilk_dot (pedigree_parent, 
+					CILK_TI_PEDIGREE_RANK, 0);
+  tree pedigree_parent_parent = cilk_dot (pedigree_parent, 
+				     CILK_TI_PEDIGREE_PARENT, 0);
+  tree worker_pedigree = cilk_arrow (worker, CILK_TI_WORKER_PEDIGREE, 1);
+  tree w_pedigree_rank = cilk_dot (worker_pedigree, CILK_TI_PEDIGREE_RANK, 0);
+  tree w_pedigree_parent = cilk_dot (worker_pedigree, 
+				     CILK_TI_PEDIGREE_PARENT, 0);
+
+  /* sf.pedigree.rank = worker->pedigree.rank.  */
+  tree exp1 = build2 (MODIFY_EXPR, void_type_node, pedigree_rank,
+		     w_pedigree_rank);
+  append_to_statement_list (exp1, &body_list);
+
+  /* sf.pedigree.parent = worker->pedigree.parent.  */
+  exp1 = build2 (MODIFY_EXPR, void_type_node, parent_pedigree,
+		 w_pedigree_parent);
+  append_to_statement_list (exp1, &body_list);
+
+  /* sf.call_parent->pedigree.rank = worker->pedigree.rank.  */
+  exp1 = build2 (MODIFY_EXPR, void_type_node, pedigree_parent_rank,
+		 w_pedigree_rank);
+  append_to_statement_list (exp1, &body_list);
+
+  /* sf.call_parent->pedigree.parent = worker->pedigree.parent.  */
+  exp1 = build2 (MODIFY_EXPR, void_type_node, pedigree_parent_parent,
+		 w_pedigree_parent);
+  append_to_statement_list (exp1, &body_list);
+
+  /* sf->worker.pedigree.rank = 0.  */
+  exp1 = build2 (MODIFY_EXPR, void_type_node, w_pedigree_rank, 
+		 build_zero_cst (uint64_type_node));
+  append_to_statement_list (exp1, &body_list);
+
+  /* sf->pedigree.parent = &sf->pedigree.  */
+  exp1 = build2 (MODIFY_EXPR, void_type_node, w_pedigree_parent,
+		 build1 (ADDR_EXPR,
+			 build_pointer_type (cilk_pedigree_type_decl),
+			 pedigree));
+  append_to_statement_list (exp1, &body_list);
+  return body_list;
+}
+
+/* Inserts "cleanup" functions after the function-body of FNDECL.  FNDECL is a 
+   spawn-helper and BODY is the newly created body for FNDECL.  */
+
+void
+c_cilk_install_body_w_frame_cleanup (tree fndecl, tree body)
+{
+  tree list = alloc_stmt_list ();
+  tree frame = make_cilk_frame (fndecl);
+  tree dtor = create_cilk_function_exit (frame, false, true);
+  add_local_decl (cfun, frame);
+  
+  DECL_SAVED_TREE (fndecl) = list;
+  tree frame_ptr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (frame)), 
+			   frame);
+  tree body_list = cilk_install_body_pedigree_operations (frame_ptr);
+  gcc_assert (TREE_CODE (body_list) == STATEMENT_LIST);
+  
+  tree detach_expr = build_call_expr (cilk_detach_fndecl, 1, frame_ptr); 
+  append_to_statement_list (detach_expr, &body_list);
+  append_to_statement_list (body, &body_list);
+  append_to_statement_list (build_stmt (EXPR_LOCATION (body), TRY_FINALLY_EXPR,
+				       	body_list, dtor), &list);
+}
+
+/* Add a new variable, VAR to a variable list in WD->DECL_MAP.  HOW indicates
+   whether the variable is previously defined, currently defined, or a variable 
+   that is being written to.  */
+
+static void
+add_variable (struct wrapper_data *wd, tree var, enum add_variable_type how)
+{
+  void **valp;
+  
+  valp = pointer_map_contains (wd->decl_map, (void *) var);
+  if (valp)
+    {
+      tree val = (tree) *valp;
+      /* If the variable is local, do nothing.  */
+      if (val == error_mark_node)
+	return;
+      /* If the variable was entered with itself as value,
+	 meaning it belongs to an outer scope, do not alter
+	 the value.  */
+      if (val == var) 
+	return;
+      /* A statement expression may cause a variable to be
+	 bound twice, once in BIND_EXPR and again in a
+	 DECL_EXPR.  That case caused a return in the 
+	 test above.  Any other duplicate definition is
+	 an error.  */
+      gcc_assert (how != ADD_BIND);
+      if (how != ADD_WRITE)
+	return;
+      /* This variable might have been entered as read but is now written.  */
+      *valp = (void *) var;
+      wd->nested = true;
+      return;
+    }
+  else
+    {
+      tree val = NULL_TREE;
+
+      /* Nested function rewriting silently discards hard register
+	 assignments for function scope variables, and they wouldn't
+	 work anyway.  Warn here.  This misses one case: if the
+	 register variable is used as the loop bound or increment it
+	 has already been added to the map.  */
+      if ((how != ADD_BIND) && (TREE_CODE (var) == VAR_DECL)
+	  && !DECL_EXTERNAL (var) && DECL_HARD_REGISTER (var))
+	warning (0, "register assignment ignored for %qD used in Cilk block",
+		 var);
+
+      switch (how)
+	{
+	  /* ADD_BIND means always make a fresh new variable.  */
+	case ADD_BIND:
+	  val = error_mark_node;
+	  break;
+	  /* ADD_READ means
+	     1. For cilk_for, refer to the outer scope definition as-is
+	     2. For a spawned block, take a scalar in an rgument
+	     and otherwise refer to the outer scope definition as-is.
+	     3. For a spawned call, take a scalar in an argument.  */
+	case ADD_READ:
+	  switch (wd->type)
+	    {
+	    case CILK_BLOCK_FOR:
+	      val = var;
+	      break;
+	    case CILK_BLOCK_SPAWN:
+	      if (TREE_ADDRESSABLE (var))
+		{
+		  val = var;
+		  wd->nested = true;
+		  break;
+		}
+	      val = integer_zero_node;
+	      break;
+	    }
+	  break;
+	case ADD_WRITE:
+	  switch (wd->type)
+	    {
+	    case CILK_BLOCK_FOR:
+	      val = var;
+	      wd->nested = true;
+	      break;
+	    case CILK_BLOCK_SPAWN:
+	      if (TREE_ADDRESSABLE (var))
+		val = integer_one_node;
+	      else
+		{
+		  val = var;
+		  wd->nested = true;
+		}
+	      break;
+	    }
+	}
+      *pointer_map_insert (wd->decl_map, (void *) var) = val;
+    }
+}
+
+/* Find the variables referenced in an expression T.  This does not avoid 
+   duplicates because a variable may be read in one context and written in 
+   another.  HOW describes the context in which the reference is seen.  If 
+   NESTED is true a nested function is being generated and variables in the 
+   original context should not be remapped.  */
+
+static void
+extract_free_variables (tree t, struct wrapper_data *wd,
+			enum add_variable_type how)
+{  
+  if (t == NULL_TREE)
+    return;
+
+  enum tree_code code = TREE_CODE (t);
+  bool is_expr = IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code));
+
+  if (is_expr)
+    extract_free_variables (TREE_TYPE (t), wd, ADD_READ);
+
+  switch (code)
+    {
+    case ERROR_MARK:
+    case IDENTIFIER_NODE:
+    case INTEGER_CST:
+    case REAL_CST:
+    case FIXED_CST:
+    case STRING_CST:
+    case BLOCK:
+    case PLACEHOLDER_EXPR:
+    case FIELD_DECL:
+    case VOID_TYPE:
+    case REAL_TYPE:
+      /* These do not contain variable references.  */
+      return;
+
+    case SSA_NAME:
+      /* Currently we don't see SSA_NAME.  */
+      extract_free_variables (SSA_NAME_VAR (t), wd, how);
+      return;
+
+    case LABEL_DECL:
+      /* This might be a reference to a label outside the Cilk block,
+	 which is an error, or a reference to a label in the Cilk block
+	 that we haven't seen yet.  We can't tell.  Ignore it.  An
+	 invalid use will cause an error later in copy_decl_for_cilk.  */
+      return;
+
+    case RESULT_DECL:
+      if (wd->type != CILK_BLOCK_SPAWN)
+	TREE_ADDRESSABLE (t) = 1;
+    case VAR_DECL:
+    case PARM_DECL:
+      if (!TREE_STATIC (t) && !DECL_EXTERNAL (t))
+	add_variable (wd, t, how);
+      return;
+
+    case NON_LVALUE_EXPR:
+    case CONVERT_EXPR:
+    case NOP_EXPR:
+      extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_READ);
+      return;
+
+    case INIT_EXPR:
+      extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_BIND);
+      extract_free_variables (TREE_OPERAND (t, 1), wd, ADD_READ);
+      return;
+
+    case MODIFY_EXPR:
+    case PREDECREMENT_EXPR:
+    case PREINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+      /* These write their result.  */
+      extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_WRITE);
+      extract_free_variables (TREE_OPERAND (t, 1), wd, ADD_READ);
+      return;
+
+    case ADDR_EXPR:
+      /* This might modify its argument, and the value needs to be
+	 passed by reference in any case to preserve identity and
+	 type if is a promoting type.  In the case of a nested loop
+	 just notice that we touch the variable.  It will already
+	 be addressable, and marking it modified will cause a spurious
+	 warning about writing the control variable.  */
+      if (wd->type != CILK_BLOCK_SPAWN)
+	extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_READ);
+      else 
+	extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_WRITE);
+      return;
+
+    case ARRAY_REF:
+      /* Treating ARRAY_REF and BIT_FIELD_REF identically may
+	 mark the array as written but the end result is correct
+	 because the array is passed by pointer anyway.  */
+    case BIT_FIELD_REF:
+      /* Propagate the access type to the object part of which
+	 is being accessed here.  As for ADDR_EXPR, don't do this
+	 in a nested loop, unless the access is to a fixed index.  */
+      if (wd->type != CILK_BLOCK_FOR || TREE_CONSTANT (TREE_OPERAND (t, 1)))
+	extract_free_variables (TREE_OPERAND (t, 0), wd, how);
+      else
+	extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_READ);
+      extract_free_variables (TREE_OPERAND (t, 1), wd, ADD_READ);
+      extract_free_variables (TREE_OPERAND (t, 2), wd, ADD_READ);
+      return;
+
+    case TREE_LIST:
+      extract_free_variables (TREE_PURPOSE (t), wd, ADD_READ);
+      extract_free_variables (TREE_VALUE (t), wd, ADD_READ);
+      extract_free_variables (TREE_CHAIN (t), wd, ADD_READ);
+      return;
+
+    case TREE_VEC:
+      {
+	int len = TREE_VEC_LENGTH (t);
+	int i;
+	for (i = 0; i < len; i++)
+	  extract_free_variables (TREE_VEC_ELT (t, i), wd, ADD_READ);
+	return;
+      }
+
+    case VECTOR_CST:
+      {
+	unsigned ii = 0;
+	for (ii = 0; ii < VECTOR_CST_NELTS (t); ii++)
+	  extract_free_variables (VECTOR_CST_ELT (t, ii), wd, ADD_READ); 
+	break;
+      }
+
+    case COMPLEX_CST:
+      extract_free_variables (TREE_REALPART (t), wd, ADD_READ);
+      extract_free_variables (TREE_IMAGPART (t), wd, ADD_READ);
+      return;
+
+    case BIND_EXPR:
+      {
+	tree decl;
+	for (decl = BIND_EXPR_VARS (t); decl; decl = TREE_CHAIN (decl))
+	  {
+	    add_variable (wd, decl, ADD_BIND);
+	    /* A self-referential initialization is no problem because
+	       we already entered the variable into the map as local.  */
+	    extract_free_variables (DECL_INITIAL (decl), wd, ADD_READ);
+	    extract_free_variables (DECL_SIZE (decl), wd, ADD_READ);
+	    extract_free_variables (DECL_SIZE_UNIT (decl), wd, ADD_READ);
+	  }
+	extract_free_variables (BIND_EXPR_BODY (t), wd, ADD_READ);
+	return;
+      }
+
+    case STATEMENT_LIST:
+      {
+	tree_stmt_iterator i;
+	for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
+	  extract_free_variables (*tsi_stmt_ptr (i), wd, ADD_READ);
+	return;
+      }
+
+    case TARGET_EXPR:
+      {
+	extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_BIND);
+	extract_free_variables (TREE_OPERAND (t, 1), wd, ADD_READ);
+	extract_free_variables (TREE_OPERAND (t, 2), wd, ADD_READ);
+	if (TREE_OPERAND (t, 3) != TREE_OPERAND (t, 1))
+	  extract_free_variables (TREE_OPERAND (t, 3), wd, ADD_READ);
+	return;
+      }
+
+    case RETURN_EXPR:
+      if (TREE_NO_WARNING (t))
+	{
+	  gcc_assert (errorcount);
+	  return;
+	}
+      return;
+
+    case DECL_EXPR:
+      if (TREE_CODE (DECL_EXPR_DECL (t)) != TYPE_DECL)
+	extract_free_variables (DECL_EXPR_DECL (t), wd, ADD_BIND);
+      return;
+
+    case INTEGER_TYPE:
+    case ENUMERAL_TYPE:
+    case BOOLEAN_TYPE:
+      extract_free_variables (TYPE_MIN_VALUE (t), wd, ADD_READ);
+      extract_free_variables (TYPE_MAX_VALUE (t), wd, ADD_READ);
+      return;
+
+    case POINTER_TYPE:
+      extract_free_variables (TREE_TYPE (t), wd, ADD_READ);
+      break;
+
+    case ARRAY_TYPE:
+      extract_free_variables (TREE_TYPE (t), wd, ADD_READ);
+      extract_free_variables (TYPE_DOMAIN (t), wd, ADD_READ);
+      return;
+
+    case RECORD_TYPE:
+      extract_free_variables (TYPE_FIELDS (t), wd, ADD_READ);
+      return;
+    
+    case METHOD_TYPE:
+      extract_free_variables (TYPE_ARG_TYPES (t), wd, ADD_READ);
+      extract_free_variables (TYPE_METHOD_BASETYPE (t), wd, ADD_READ);
+      return;
+
+    case AGGR_INIT_EXPR:
+    case CALL_EXPR:
+      {
+	int len = 0;
+	int ii = 0;
+	if (TREE_CODE (TREE_OPERAND (t, 0)) == INTEGER_CST)
+	  {
+	    len = TREE_INT_CST_LOW (TREE_OPERAND (t, 0));
+
+	    for (ii = 0; ii < len; ii++)
+	      extract_free_variables (TREE_OPERAND (t, ii), wd, ADD_READ);
+	    extract_free_variables (TREE_TYPE (t), wd, ADD_READ);
+	  }
+	break;
+      }
+
+    default:
+      if (is_expr)
+	{
+	  int i, len;
+
+	  /* Walk over all the sub-trees of this operand.  */
+	  len = TREE_CODE_LENGTH (code);
+
+	  /* Go through the subtrees.  We need to do this in forward order so
+	     that the scope of a FOR_EXPR is handled properly.  */
+	  for (i = 0; i < len; ++i)
+	    extract_free_variables (TREE_OPERAND (t, i), wd, ADD_READ);
+	}
+    }
+}
+
+
+/* Add appropriate frames needed for a Cilk spawned function call, FNDECL. 
+   Returns the __cilkrts_stack_frame * variable.  */
+
+tree
+insert_cilk_frame (tree fndecl)
+{
+  tree addr, body, enter, out, orig_body;
+  location_t loc = EXPR_LOCATION (fndecl);
+
+  if (!cfun || cfun->decl != fndecl)
+    push_cfun (DECL_STRUCT_FUNCTION (fndecl)); 
+
+  tree decl = cfun->cilk_frame_decl;
+  if (!decl)
+    {
+      tree *saved_tree = &DECL_SAVED_TREE (fndecl);
+      decl = make_cilk_frame (fndecl);
+      add_local_decl (cfun, decl);
+
+      addr = build1 (ADDR_EXPR, cilk_frame_ptr_type_decl, decl);
+      enter = build_call_expr (cilk_enter_fndecl, 1, addr);
+      out = create_cilk_function_exit (cfun->cilk_frame_decl, false, true);
+
+      /* The new body will be:
+	 __cilkrts_enter_frame_1 (&sf);
+	 try {
+	    orig_body;
+	 } 
+	 finally {
+	     __cilkrts_pop_frame (&sf);
+	     __cilkrts_leave_frame (&sf);
+         }  */
+
+      body = alloc_stmt_list ();
+      orig_body = *saved_tree;
+
+      if (TREE_CODE (orig_body) == BIND_EXPR)
+	orig_body = BIND_EXPR_BODY (orig_body);
+ 
+      append_to_statement_list (enter, &body);
+      append_to_statement_list (build_stmt (loc, TRY_FINALLY_EXPR, orig_body, 
+					    out), &body);
+      if (TREE_CODE (*saved_tree) == BIND_EXPR)
+	BIND_EXPR_BODY (*saved_tree) = body;
+      else
+	*saved_tree = body;
+    }
+  return decl;
+}
+
+/* Wraps CALL, a CALL_EXPR, into a CILK_SPAWN_STMT tree and returns it.  */
+
+tree
+build_cilk_spawn (location_t loc, tree call)
+{
+  if (!cilk_set_spawn_marker (loc, call))
+    return error_mark_node;
+  tree spawn_stmt = build1 (CILK_SPAWN_STMT, TREE_TYPE (call), call);
+  TREE_SIDE_EFFECTS (spawn_stmt) = 1;
+  return spawn_stmt;
+}
+
+/* Returns a tree of type CILK_SYNC_STMT.  */
+
+tree
+build_cilk_sync (void)
+{
+  tree sync = build0 (CILK_SYNC_STMT, void_type_node);
+  TREE_SIDE_EFFECTS (sync) = 1;
+  return sync;
+}
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index 0554e72..64718c5 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -56,6 +56,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "pointer-set.h"
 #include "plugin.h"
 #include "c-family/c-ada-spec.h"
+#include "cilk.h"
 
 /* In grokdeclarator, distinguish syntactic contexts of declarators.  */
 enum decl_context
@@ -8447,6 +8448,12 @@  finish_function (void)
   /* Tie off the statement tree for this function.  */
   DECL_SAVED_TREE (fndecl) = pop_stmt_list (DECL_SAVED_TREE (fndecl));
 
+  /* If the function has _Cilk_spawn in front of a function call inside it
+     i.e. it is a spawning function, then add the appropriate Cilk plus
+     functions inside.  */
+  if (fn_contains_cilk_spawn_p (cfun))
+    cfun->cilk_frame_decl = insert_cilk_frame (fndecl);
+
   finish_fname_decls ();
 
   /* Complain if there's just no return statement.  */
diff --git a/gcc/c/c-objc-common.h b/gcc/c/c-objc-common.h
index e144824..6ae7b3e 100644
--- a/gcc/c/c-objc-common.h
+++ b/gcc/c/c-objc-common.h
@@ -105,4 +105,13 @@  along with GCC; see the file COPYING3.  If not see
 #undef LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P
 #define LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P c_vla_unspec_p
 
+#undef  LANG_HOOKS_CILKPLUS_GIMPLIFY_SPAWN
+#define LANG_HOOKS_CILKPLUS_GIMPLIFY_SPAWN gimplify_cilk_spawn
+
+#undef  LANG_HOOKS_CILKPLUS_FRAME_CLEANUP
+#define LANG_HOOKS_CILKPLUS_FRAME_CLEANUP c_cilk_install_body_w_frame_cleanup
+
+#undef  LANG_HOOKS_CILKPLUS_DETECT_SPAWN_AND_UNWRAP
+#define LANG_HOOKS_CILKPLUS_DETECT_SPAWN_AND_UNWRAP  \
+  cilk_detect_spawn_and_unwrap
 #endif /* GCC_C_OBJC_COMMON */
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 9b6abe0..5bcd623 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -4582,6 +4582,14 @@  c_parser_statement_after_labels (c_parser *parser)
 	case RID_FOR:
 	  c_parser_for_statement (parser);
 	  break;
+	case RID_CILK_SYNC:
+	  c_parser_consume_token (parser);
+	  c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+	  if (!flag_enable_cilkplus) 
+	    error_at (loc, "-fcilkplus must be enabled to use %<_Cilk_sync%>");
+	  else 
+	    add_stmt (build_cilk_sync ());
+	  break;
 	case RID_GOTO:
 	  c_parser_consume_token (parser);
 	  if (c_parser_next_token_is (parser, CPP_NAME))
@@ -7148,6 +7156,30 @@  c_parser_postfix_expression (c_parser *parser)
 	case RID_GENERIC:
 	  expr = c_parser_generic_selection (parser);
 	  break;
+	case RID_CILK_SPAWN:
+	  c_parser_consume_token (parser);
+	  if (!flag_enable_cilkplus)
+	    {
+	      error_at (loc, "-fcilkplus must be enabled to use "
+			"%<_Cilk_spawn%>");
+	      expr = c_parser_postfix_expression (parser);
+	      expr.value = error_mark_node;	      
+	    }
+	  if (c_parser_peek_token (parser)->keyword == RID_CILK_SPAWN)
+	    {
+	      error_at (loc, "consecutive %<_Cilk_spawn%> keywords "
+			"are not permitted");
+	      /* Now flush out all the _Cilk_spawns.  */
+	      while (c_parser_peek_token (parser)->keyword == RID_CILK_SPAWN)
+		c_parser_consume_token (parser);
+	      expr = c_parser_postfix_expression (parser);
+	    }
+	  else
+	    {
+	      expr = c_parser_postfix_expression (parser);
+	      expr.value = build_cilk_spawn (loc, expr.value);
+	    }
+	  break; 
 	default:
 	  c_parser_error (parser, "expected expression");
 	  expr.value = error_mark_node;
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 1d83137..1034cee 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -4387,6 +4387,14 @@  build_compound_expr (location_t loc, tree expr1, tree expr2)
   tree eptype = NULL_TREE;
   tree ret;
 
+  if (flag_enable_cilkplus
+      && (TREE_CODE (expr1) == CILK_SPAWN_STMT
+	  || TREE_CODE (expr2) == CILK_SPAWN_STMT))
+    {
+      error_at (loc,
+		"spawned function call cannot be part of a comma expression");
+      return error_mark_node;
+    }
   expr1_int_operands = EXPR_INT_CONST_OPERANDS (expr1);
   if (expr1_int_operands)
     expr1 = remove_c_maybe_const_expr (expr1);
@@ -8694,6 +8702,12 @@  c_finish_return (location_t loc, tree retval, tree origtype)
 	  return error_mark_node;
 	}
     }
+  if (flag_enable_cilkplus && retval && TREE_CODE (retval) == CILK_SPAWN_STMT)
+    {
+      error_at (loc, "use of %<_Cilk_spawn%> in a return statement is not "
+		"allowed");
+      return error_mark_node;
+    }
   if (retval)
     {
       tree semantic_type = NULL_TREE;
diff --git a/gcc/cilk-builtins.def b/gcc/cilk-builtins.def
new file mode 100644
index 0000000..8634194
--- /dev/null
+++ b/gcc/cilk-builtins.def
@@ -0,0 +1,33 @@ 
+/* This file contains the definitions and documentation for the
+   Cilk Plus builtins used in the GNU compiler.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+
+   Contributed by Balaji V. Iyer <balaji.v.iyer@intel.com>
+   	          Intel Corporation.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+DEF_CILK_BUILTIN_STUB (BUILT_IN_CILK_ENTER_FRAME, "__cilkrts_enter_frame_1")
+DEF_CILK_BUILTIN_STUB (BUILT_IN_CILK_ENTER_FRAME_FAST, 
+		       "__cilkrts_enter_frame_fast_1")
+DEF_CILK_BUILTIN_STUB (BUILT_IN_CILK_DETACH, "__cilkrts_detach")
+DEF_CILK_BUILTIN_STUB (BUILT_IN_CILK_RETHROW, "__cilkrts_rethrow")
+DEF_CILK_BUILTIN_STUB (BUILT_IN_CILK_SYNCHED, "__cilkrts_synched")
+DEF_CILK_BUILTIN_STUB (BUILT_IN_CILK_SYNC, "__cilkrts_sync")
+DEF_CILK_BUILTIN_STUB (BUILT_IN_CILK_LEAVE_FRAME, "__cilkrts_leave_frame")
+DEF_CILK_BUILTIN_STUB (BUILT_IN_CILK_POP_FRAME, "__cilkrts_pop_frame")
+DEF_CILK_BUILTIN_STUB (BUILT_IN_CILK_SAVE_FP, "__cilkrts_save_fp_ctrl_state")
diff --git a/gcc/cilk-common.c b/gcc/cilk-common.c
new file mode 100644
index 0000000..ca178c0
--- /dev/null
+++ b/gcc/cilk-common.c
@@ -0,0 +1,484 @@ 
+/* This file is part of the Intel(R) Cilk(TM) Plus support
+   This file contains the CilkPlus Intrinsics
+   Copyright (C) 2013 Free Software Foundation, Inc.
+   Contributed by Balaji V. Iyer <balaji.v.iyer@intel.com>,
+   Intel Corporation
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "langhooks.h"
+#include "expr.h"
+#include "optabs.h"
+#include "recog.h"
+#include "tree-iterator.h"
+#include "gimple.h"
+#include "cilk.h"
+
+/* This structure holds all the important fields of the internal structures,
+   internal built-in functions, and Cilk-specific data types.  Explanation of 
+   all the these fielsd are given in cilk.h.  */
+tree cilk_trees[(int) CILK_TI_MAX];
+
+/* Returns the value in structure FRAME pointed by the FIELD_NUMBER
+   (e.g. X.y).  
+   FIELD_NUMBER is an index to the structure FRAME_PTR.  For details
+   about these fields, refer to cilk_trees structure in cilk.h and
+   cilk_init_builtins function  in this file.  Returns a TREE that is the type 
+   of the field represented by FIELD_NUMBER.  If VOLATIL parameter is set
+   to true then the returning field is set as volatile.  */
+
+tree
+cilk_dot (tree frame, int field_number, bool volatil)
+{
+  tree field = cilk_trees[field_number];
+  field = fold_build3 (COMPONENT_REF, TREE_TYPE (field), frame, field, 
+		       NULL_TREE);
+  TREE_THIS_VOLATILE (field) = volatil;
+  return field;
+}
+
+/* Returns the address of a field in FRAME_PTR, pointed by FIELD_NUMBER.  
+   (e.g. (&X)->y).   Please see cilk_dot function for explanation of the 
+   FIELD_NUMBER.  Returns a tree that is the type of the field represented 
+   by FIELD_NUMBER. If VOLATIL parameter is set to true then the returning
+   field is set as volatile.  */
+
+tree
+cilk_arrow (tree frame_ptr, int field_number, bool volatil)
+{
+  return cilk_dot (fold_build1 (INDIRECT_REF, 
+				TREE_TYPE (TREE_TYPE (frame_ptr)), frame_ptr), 
+		   field_number, volatil);
+}
+
+
+/* This function will add FIELD of type TYPE to a defined built-in 
+   structure.  *NAME is the name of the field to be added.  */
+
+static tree
+add_field (const char *name, tree type, tree fields)
+{
+  tree t = get_identifier (name);
+  tree field = build_decl (BUILTINS_LOCATION, FIELD_DECL, t, type);
+  TREE_CHAIN (field) = fields;
+  return field;
+}
+
+/* This function will define a built-in function of NAME, of type FNTYPE and
+   register it under the built-in function code CODE.  If PUBLISH is set then
+   the declaration is pushed into the declaration list.  CODE is the index
+   to the cilk_trees array.  *NAME is the name of the function to be added.  */
+
+static tree
+install_builtin (const char *name, tree fntype, enum built_in_function code,
+                 bool publish)
+{
+  tree fndecl = build_fn_decl (name, fntype);
+  DECL_BUILT_IN_CLASS (fndecl) = BUILT_IN_NORMAL;
+  DECL_FUNCTION_CODE (fndecl) = code;
+  if (publish)
+    {
+      tree t = lang_hooks.decls.pushdecl (fndecl);
+      if (t)
+        fndecl = t;
+    }
+  set_builtin_decl (code, fndecl, true);
+  return fndecl;
+}
+
+/* Creates and initializes all the built-in Cilk keywords functions and three
+   structures: __cilkrts_stack_frame, __cilkrts_pedigree and __cilkrts_worker.
+   Detailed information about __cilkrts_stack_frame and
+   __cilkrts_worker structures are given in libcilkrts/include/internal/abi.h.
+   __cilkrts_pedigree is described in libcilkrts/include/cilk/common.h.  */
+
+void
+cilk_init_builtins (void)
+{
+  /* Now build the following __cilkrts_pedigree struct:
+     struct __cilkrts_pedigree {
+        uint64_t rank;
+        struct __cilkrts_pedigree *parent;
+      }  */
+       
+  tree pedigree_type = lang_hooks.types.make_type (RECORD_TYPE);
+  tree pedigree_ptr  = build_pointer_type (pedigree_type);
+  tree field = add_field ("rank", uint64_type_node, NULL_TREE);
+  cilk_trees[CILK_TI_PEDIGREE_RANK] = field;
+  field = add_field ("parent", pedigree_ptr, field);
+  cilk_trees[CILK_TI_PEDIGREE_PARENT] = field;
+  finish_builtin_struct (pedigree_type, "__cilkrts_pedigree_GCC", field,
+			 NULL_TREE);
+  lang_hooks.types.register_builtin_type (pedigree_type,
+					  "__cilkrts_pedigree_t");
+  cilk_pedigree_type_decl = pedigree_type; 
+  
+  /* Build the Cilk Stack Frame:
+     struct __cilkrts_stack_frame {
+       uint32_t flags;
+       uint32_t size;
+       struct __cilkrts_stack_frame *call_parent;
+       __cilkrts_worker *worker;
+       void *except_data;
+       void *ctx[4];
+       uint32_t mxcsr;
+       uint16_t fpcsr;
+       uint16_t reserved;
+       __cilkrts_pedigree pedigree;
+     };  */
+
+  tree frame = lang_hooks.types.make_type (RECORD_TYPE);
+  tree frame_ptr = build_pointer_type (frame);
+  tree worker_type = lang_hooks.types.make_type (RECORD_TYPE);
+  tree worker_ptr = build_pointer_type (worker_type);
+  tree s_type_node = build_int_cst (size_type_node, 4);
+
+  tree flags = add_field ("flags", uint32_type_node, NULL_TREE);
+  tree size = add_field ("size", uint32_type_node, flags);
+  tree parent = add_field ("call_parent", frame_ptr, size);
+  tree worker = add_field ("worker", worker_ptr, parent);
+  tree except = add_field ("except_data", frame_ptr, worker);
+  tree context = add_field ("ctx",
+			    build_array_type (ptr_type_node,
+					      build_index_type (s_type_node)),
+			    except);
+  tree mxcsr = add_field ("mxcsr", uint32_type_node, context);
+  tree fpcsr = add_field ("fpcsr", uint16_type_node, mxcsr);
+  tree reserved = add_field ("reserved", uint16_type_node, fpcsr);
+  tree pedigree = add_field ("pedigree", pedigree_type, reserved);
+  
+  /* Now add them to a common structure whose fields are #defined to something
+     that is used at a later stage.  */
+  cilk_trees[CILK_TI_FRAME_FLAGS] = flags;
+  cilk_trees[CILK_TI_FRAME_PARENT] = parent;
+  cilk_trees[CILK_TI_FRAME_WORKER] = worker;
+  cilk_trees[CILK_TI_FRAME_EXCEPTION] = except;
+  cilk_trees[CILK_TI_FRAME_CONTEXT] = context;
+  /* We don't care about reserved, so no need to store it in cilk_trees.  */
+  cilk_trees[CILK_TI_FRAME_PEDIGREE] = pedigree;
+  TREE_ADDRESSABLE (frame) = 1;
+
+  finish_builtin_struct (frame, "__cilkrts_st_frame_GCC", pedigree, NULL_TREE);
+  cilk_frame_type_decl = frame;
+  lang_hooks.types.register_builtin_type (frame, "__cilkrts_frame_t");
+
+  cilk_frame_ptr_type_decl = build_qualified_type (frame_ptr,
+						   TYPE_QUAL_VOLATILE);
+  /* Now let's do the following worker struct:
+
+     struct __cilkrts_worker {
+       __cilkrts_stack_frame *volatile *volatile tail;
+       __cilkrts_stack_frame *volatile *volatile head;
+       __cilkrts_stack_frame *volatile *volatile exc;
+       __cilkrts_stack_frame *volatile *volatile protected_tail;
+       __cilkrts_stack_frame *volatile *ltq_limit;
+       int32_t self;
+       global_state_t *g;
+       local_state *l;
+       cilkred_map *reducer_map;
+       __cilkrts_stack_frame *current_stack_frame;
+       void *reserved;
+       __cilkrts_worker_sysdep_state *sysdep;
+       __cilkrts_pedigree pedigree;
+    }   */
+
+  tree fptr_volatil_type = build_qualified_type (frame_ptr, TYPE_QUAL_VOLATILE);
+  tree fptr_volatile_ptr = build_pointer_type (fptr_volatil_type);
+  tree fptr_vol_ptr_vol = build_qualified_type (fptr_volatile_ptr,
+						TYPE_QUAL_VOLATILE);
+  tree g = lang_hooks.types.make_type (RECORD_TYPE);
+  finish_builtin_struct (g, "__cilkrts_global_state", NULL_TREE, NULL_TREE);
+  tree l = lang_hooks.types.make_type (RECORD_TYPE);
+  finish_builtin_struct (l, "__cilkrts_local_state", NULL_TREE, NULL_TREE);
+  tree sysdep_t = lang_hooks.types.make_type (RECORD_TYPE);
+  finish_builtin_struct (sysdep_t, "__cilkrts_worker_sysdep_state", NULL_TREE,
+			 NULL_TREE);
+  
+  field = add_field ("tail", fptr_vol_ptr_vol, NULL_TREE);
+  cilk_trees[CILK_TI_WORKER_TAIL] = field;
+  field = add_field ("head", fptr_vol_ptr_vol, field);
+  field  = add_field ("exc", fptr_vol_ptr_vol, field);
+  field = add_field ("protected_tail", fptr_vol_ptr_vol, field);
+  field = add_field ("ltq_limit", fptr_volatile_ptr, field);
+  field = add_field ("self", integer_type_node, field);
+  field = add_field ("g", build_pointer_type (g), field);
+  field = add_field ("l", build_pointer_type (g), field);
+  field = add_field ("reducer_map", ptr_type_node, field);
+  field = add_field ("current_stack_frame", frame_ptr, field);
+  cilk_trees[CILK_TI_WORKER_CUR] = field;
+  field = add_field ("saved_protected_tail", fptr_volatile_ptr, field);
+  field = add_field ("sysdep", build_pointer_type (sysdep_t), field);
+  field = add_field ("pedigree", pedigree_type, field);
+  cilk_trees[CILK_TI_WORKER_PEDIGREE] = field;
+  finish_builtin_struct (worker_type, "__cilkrts_worker_GCC", field,
+			 NULL_TREE);
+
+  tree fptr_arglist = tree_cons (NULL_TREE, frame_ptr, void_list_node);
+  tree fptr_fun = build_function_type (void_type_node, fptr_arglist);
+  
+  /* void __cilkrts_enter_frame_1 (__cilkrts_stack_frame *);  */
+  cilk_enter_fndecl = install_builtin ("__cilkrts_enter_frame_1", fptr_fun,
+				       BUILT_IN_CILK_ENTER_FRAME, false);
+
+  /* void __cilkrts_enter_frame_fast_1 (__cilkrts_stack_frame *);  */
+  cilk_enter_fast_fndecl = 
+    install_builtin ("__cilkrts_enter_frame_fast_1", fptr_fun, 
+		     BUILT_IN_CILK_ENTER_FRAME_FAST, false);
+  
+  /* void __cilkrts_pop_frame (__cilkrts_stack_frame *);  */
+  cilk_pop_fndecl = install_builtin ("__cilkrts_pop_frame", fptr_fun,
+				     BUILT_IN_CILK_POP_FRAME, false);
+
+  /* void __cilkrts_leave_frame (__cilkrts_stack_frame *);  */
+  cilk_leave_fndecl = install_builtin ("__cilkrts_leave_frame", fptr_fun,
+				       BUILT_IN_CILK_LEAVE_FRAME, false);
+
+  /* void __cilkrts_sync (__cilkrts_stack_frame *);  */
+  cilk_sync_fndecl = install_builtin ("__cilkrts_sync", fptr_fun,
+				      BUILT_IN_CILK_SYNC, false);
+
+  /* void __cilkrts_detach (__cilkrts_stack_frame *);  */
+  cilk_detach_fndecl = install_builtin ("__cilkrts_detach", fptr_fun,
+					BUILT_IN_CILK_DETACH, false);
+
+  /* __cilkrts_rethrow (struct stack_frame *);  */
+  cilk_rethrow_fndecl = install_builtin ("__cilkrts_rethrow", fptr_fun, 
+					 BUILT_IN_CILK_RETHROW, false);
+
+  /* __cilkrts_save_fp_ctrl_state (__cilkrts_stack_frame *);  */
+  cilk_save_fp_fndecl = install_builtin ("__cilkrts_save_fp_ctrl_state", 
+					 fptr_fun, BUILT_IN_CILK_SAVE_FP,
+					 false);
+}
+
+/* Get the appropriate frame arguments for CALL that is of type CALL_EXPR.  */
+
+static tree
+get_frame_arg (tree call)
+{
+  tree arg, argtype;
+
+  gcc_assert (call_expr_nargs (call) >= 1);
+    
+  arg = CALL_EXPR_ARG (call, 0);
+  argtype = TREE_TYPE (arg);
+  gcc_assert (TREE_CODE (argtype) == POINTER_TYPE);
+
+  argtype = TREE_TYPE (argtype);
+  
+  gcc_assert (!lang_hooks.types_compatible_p
+	      || lang_hooks.types_compatible_p (argtype, cilk_frame_type_decl));
+
+  /* If it is passed in as an address, then just use the value directly 
+     since the function is inlined.  */
+  if (TREE_CODE (arg) == INDIRECT_REF || TREE_CODE (arg) == ADDR_EXPR)
+    return TREE_OPERAND (arg, 0);
+  return arg;
+}
+
+/* Expands the __cilkrts_pop_frame function call stored in EXP.  */
+
+void
+expand_builtin_cilk_pop_frame (tree exp)
+{
+  tree frame = get_frame_arg (exp);
+  tree parent = cilk_dot (frame, CILK_TI_FRAME_PARENT, 0);
+
+  tree clear_parent = build2 (MODIFY_EXPR, void_type_node, parent,
+			      build_int_cst (TREE_TYPE (parent), 0));
+  expand_expr (clear_parent, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+  /* During LTO, the is_cilk_function flag gets cleared.
+     If __cilkrts_pop_frame is called, then this definitely must be a
+     cilk function.  */
+  if (cfun)
+    cfun->is_cilk_function = 1;
+}
+
+/* Expands the cilk_detach function call stored in EXP.  */
+
+void
+expand_builtin_cilk_detach (tree exp)
+{
+  rtx insn;
+  tree fptr = get_frame_arg (exp);
+
+  if (fptr == NULL_TREE)
+    return;
+
+  tree parent = cilk_dot (fptr, CILK_TI_FRAME_PARENT, 0);
+  tree worker = cilk_dot (fptr, CILK_TI_FRAME_WORKER, 0);
+  tree tail = cilk_dot (worker, CILK_TI_WORKER_TAIL, 1);
+
+  rtx wreg = expand_expr (worker, NULL_RTX, Pmode, EXPAND_NORMAL);
+  if (GET_CODE (wreg) != REG)
+    wreg = copy_to_reg (wreg);
+  rtx preg = expand_expr (parent, NULL_RTX, Pmode, EXPAND_NORMAL);
+
+  /* TMP <- WORKER.TAIL
+    *TMP <- PARENT
+     TMP <- TMP + 1
+     WORKER.TAIL <- TMP   */
+
+  HOST_WIDE_INT worker_tail_offset =
+    tree_low_cst (DECL_FIELD_OFFSET (cilk_trees[CILK_TI_WORKER_TAIL]), 0) +
+    tree_low_cst (DECL_FIELD_BIT_OFFSET (cilk_trees[CILK_TI_WORKER_TAIL]), 0) /
+    BITS_PER_UNIT;
+  rtx tmem0 = gen_rtx_MEM (Pmode,
+			   plus_constant (Pmode, wreg, worker_tail_offset));
+  set_mem_attributes (tmem0, tail, 0);
+  MEM_NOTRAP_P (tmem0) = 1;
+  gcc_assert (MEM_VOLATILE_P (tmem0));
+  rtx treg = copy_to_mode_reg (Pmode, tmem0);
+  rtx tmem1 = gen_rtx_MEM (Pmode, treg);
+  set_mem_attributes (tmem1, TREE_TYPE (TREE_TYPE (tail)), 0);
+  MEM_NOTRAP_P (tmem1) = 1;
+  emit_move_insn (tmem1, preg);
+  emit_move_insn (treg, plus_constant (Pmode, treg, GET_MODE_SIZE (Pmode)));
+
+  /* There is a release barrier (st8.rel, membar #StoreStore,
+     sfence, lwsync, etc.) between the two stores.  On x86
+     normal volatile stores have proper semantics; the sfence
+     would only be needed for nontemporal stores (which we
+     could generate using the storent optab, for no benefit
+     in this case).
+
+     The predicate may return false even for a REG if this is
+     the limited release operation that only stores 0.  */
+  enum insn_code icode = direct_optab_handler (sync_lock_release_optab, Pmode); 
+  if (icode != CODE_FOR_nothing
+      && insn_data[icode].operand[1].predicate (treg, Pmode)
+      && (insn = GEN_FCN (icode) (tmem0, treg)) != NULL_RTX)
+    emit_insn (insn);
+  else
+    emit_move_insn (tmem0, treg);
+
+  /* The memory barrier inserted above should not prevent
+     the load of flags from being moved before the stores,
+     but in practice it does because it is implemented with
+     unspec_volatile.  In-order RISC machines should
+     explicitly load flags earlier.  */
+
+  tree flags = cilk_dot (fptr, CILK_TI_FRAME_FLAGS, 0);
+  expand_expr (build2 (MODIFY_EXPR, void_type_node, flags,
+		       build2 (BIT_IOR_EXPR, TREE_TYPE (flags), flags,
+			       build_int_cst (TREE_TYPE (flags),
+					      CILK_FRAME_DETACHED))),
+	       const0_rtx, VOIDmode, EXPAND_NORMAL);
+}
+
+/* Returns a setjmp CALL_EXPR with FRAME->context as its parameter.  */
+
+tree
+cilk_call_setjmp (tree frame)
+{
+  tree c = cilk_dot (frame, CILK_TI_FRAME_CONTEXT, false);
+  c = build1 (ADDR_EXPR, build_pointer_type (ptr_type_node), c);
+  return build_call_expr (builtin_decl_implicit (BUILT_IN_SETJMP), 1, c);
+}
+
+/* This function will expand the _Cilk_sync keyword.  */
+
+static tree
+expand_cilk_sync (void)
+{
+  tree frame = cfun->cilk_frame_decl;
+
+  /* Cilk_sync is converted to the following code:
+
+     sf.pedigree = sf.worker->pedigree;
+     if (frame.flags & CILK_FRAME_UNSYNCHED)
+     {
+        __cilkrts_save_fp_state (&sf);
+        if (!builtin_setjmp (sf.ctx) 
+	    __cilkrts_sync (&sf); 
+	else 
+	   if (sf.flags & CILK_FRAME_EXCEPTING) 
+	     __cilkrts_rethrow (&sf); 
+      }
+      sf.worker->pedigree.rank = sf.worker->pedigree.rank + 1;  */
+
+  tree flags = cilk_dot (frame, CILK_TI_FRAME_FLAGS, false);
+  
+  tree unsynched = fold_build2 (BIT_AND_EXPR, TREE_TYPE (flags), flags,
+				build_int_cst (TREE_TYPE (flags),
+					       CILK_FRAME_UNSYNCHED));
+
+  unsynched = fold_build2 (NE_EXPR, TREE_TYPE (unsynched), unsynched,
+			   build_int_cst (TREE_TYPE (unsynched), 0));
+
+  tree frame_addr = build1 (ADDR_EXPR, cilk_frame_ptr_type_decl, frame);
+
+  /* Check if exception (0x10) bit is set in the sf->flags.  */
+  tree except_flag = fold_build2 (BIT_AND_EXPR, TREE_TYPE (flags), flags,
+				  build_int_cst (TREE_TYPE (flags),
+						 CILK_FRAME_EXCEPTING));
+  except_flag = fold_build2 (NE_EXPR, TREE_TYPE (except_flag), except_flag,
+			     build_int_cst (TREE_TYPE (except_flag), 0));
+
+  /* If the exception flag is set then call the __cilkrts_rethrow (&sf).  */
+  tree except_cond = fold_build3 (COND_EXPR, void_type_node, except_flag,
+				  build_call_expr (cilk_rethrow_fndecl, 1,
+						   frame_addr),
+				  build_empty_stmt (EXPR_LOCATION (unsynched)));
+  
+  tree sync_expr = build_call_expr (cilk_sync_fndecl, 1, frame_addr);
+  tree setjmp_expr = cilk_call_setjmp (frame);
+  setjmp_expr = fold_build2 (EQ_EXPR, TREE_TYPE (setjmp_expr), setjmp_expr,
+			     build_int_cst (TREE_TYPE (setjmp_expr), 0));
+  
+  setjmp_expr = fold_build3 (COND_EXPR, void_type_node, setjmp_expr,
+			     sync_expr, except_cond);
+  tree sync_list = alloc_stmt_list ();
+  append_to_statement_list (build_call_expr (cilk_save_fp_fndecl, 1,
+					     frame_addr), &sync_list);
+  append_to_statement_list (setjmp_expr, &sync_list);
+  tree sync = fold_build3 (COND_EXPR, void_type_node, unsynched, sync_list,
+			   build_empty_stmt (EXPR_LOCATION (unsynched)));
+  tree parent_pedigree = cilk_dot (frame, CILK_TI_FRAME_PEDIGREE, false);
+  tree worker = cilk_dot (frame, CILK_TI_FRAME_WORKER, false);
+  tree worker_pedigree = cilk_arrow (worker, CILK_TI_WORKER_PEDIGREE, false);
+  tree assign_pedigree = fold_build2 (MODIFY_EXPR, void_type_node,
+				      parent_pedigree, worker_pedigree);
+  tree w_ped_rank = cilk_dot (unshare_expr (worker_pedigree), 
+			      CILK_TI_PEDIGREE_RANK, false);
+  tree incr_ped_rank = fold_build2 (PLUS_EXPR, TREE_TYPE (w_ped_rank),
+				    w_ped_rank,
+				    build_one_cst (TREE_TYPE (w_ped_rank)));
+  incr_ped_rank = fold_build2 (MODIFY_EXPR, void_type_node, w_ped_rank,
+			       incr_ped_rank);
+  tree ret_sync_exp = alloc_stmt_list ();
+  append_to_statement_list (assign_pedigree, &ret_sync_exp);
+  append_to_statement_list (sync, &ret_sync_exp);
+  append_to_statement_list (incr_ped_rank, &ret_sync_exp);
+  return ret_sync_exp;
+}
+
+/* Gimplifies the cilk_sync expression passed in *EXPR_P.  Returns GS_ALL_DONE 
+   when finished.  */
+
+void
+gimplify_cilk_sync (tree *expr_p, gimple_seq *pre_p)
+{
+  tree sync_expr = expand_cilk_sync ();
+  *expr_p = NULL_TREE;
+  gimplify_and_add (sync_expr, pre_p);
+}
diff --git a/gcc/cilk.h b/gcc/cilk.h
new file mode 100644
index 0000000..99b4d78
--- /dev/null
+++ b/gcc/cilk.h
@@ -0,0 +1,102 @@ 
+/* This file is part of the Intel(R) Cilk(TM) Plus support
+   This file contains Cilk Support files.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+   Contributed by Balaji V. Iyer <balaji.v.iyer@intel.com>,
+                  Intel Corporation
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_CILK_H
+#define GCC_CILK_H
+
+/* Frame status bits known to compiler.  */
+#define CILK_FRAME_UNSYNCHED 0x02
+#define CILK_FRAME_DETACHED  0x04
+#define CILK_FRAME_EXCEPTING 0x10
+#define CILK_FRAME_VERSION   (1 << 24)
+
+enum cilk_tree_index  {
+/* All the built-in functions for Cilk keywords.  */
+  CILK_TI_F_WORKER = 0,               /* __cilkrts_get_worker ().  */
+  CILK_TI_F_SYNC,                     /* __cilkrts_sync ().  */
+  CILK_TI_F_DETACH,                   /* __cilkrts_detach (...).   */
+  CILK_TI_F_ENTER,                    /* __cilkrts_enter_frame (...).  */
+  CILK_TI_F_ENTER_FAST,               /* __cilkrts_enter_frame_fast (.).  */
+  CILK_TI_F_LEAVE,                    /* __cilkrts_leave_frame (...).  */
+  CILK_TI_F_POP,                      /* __cilkrts_pop_frame (...).  */
+  CILK_TI_F_RETHROW,                  /* __cilkrts_rethrow (...).  */
+  CILK_TI_F_SAVE_FP,                  /* __cilkrts_save_fp_ctrl_state (...).  */
+  /* __cilkrts_stack_frame struct fields.  */
+  CILK_TI_FRAME_FLAGS,                /* stack_frame->flags.  */
+  CILK_TI_FRAME_PARENT,               /* stack_frame->parent.  */
+  CILK_TI_FRAME_WORKER,               /* stack_frame->worker.  */
+  CILK_TI_FRAME_EXCEPTION,            /* stack_frame->except_data.  */
+  CILK_TI_FRAME_CONTEXT,              /* stack_frame->context[4].  */
+  CILK_TI_FRAME_PEDIGREE,             /* stack_frame->pedigree.  */
+
+  /* __cilkrts_worker struct fields.  */
+  CILK_TI_WORKER_CUR,                 /* worker->current_stack_frame.  */
+  CILK_TI_WORKER_TAIL,                /* worker->tail.  */
+  CILK_TI_WORKER_PEDIGREE,            /* worker->pedigree.  */
+
+  /* __cilkrts_pedigree struct fields.  */
+  CILK_TI_PEDIGREE_RANK,              /* pedigree->rank.  */
+  CILK_TI_PEDIGREE_PARENT,            /* pedigree->parent.  */
+  
+  /* Types.  */
+  CILK_TI_FRAME_TYPE,                 /* struct __cilkrts_stack_frame.  */
+  CILK_TI_FRAME_PTR,                  /* __cilkrts_stack_frame *.  */
+  CILK_TI_WORKER_TYPE,                /* struct __cilkrts_worker.  */
+  CILK_TI_PEDIGREE_TYPE,              /* struct __cilkrts_pedigree.  */
+  CILK_TI_MAX
+};
+
+extern GTY (()) tree cilk_trees[CILK_TI_MAX];
+
+#define cilk_worker_fndecl            cilk_trees[CILK_TI_F_WORKER]
+#define cilk_sync_fndecl              cilk_trees[CILK_TI_F_SYNC]
+#define cilk_synched_fndecl           cilk_trees[CILK_TI_F_SYNCED]
+#define cilk_detach_fndecl            cilk_trees[CILK_TI_F_DETACH]
+#define cilk_enter_fndecl             cilk_trees[CILK_TI_F_ENTER]
+#define cilk_enter_fast_fndecl        cilk_trees[CILK_TI_F_ENTER_FAST]
+#define cilk_leave_fndecl             cilk_trees[CILK_TI_F_LEAVE]
+#define cilk_rethrow_fndecl           cilk_trees[CILK_TI_F_RETHROW]
+#define cilk_pop_fndecl               cilk_trees[CILK_TI_F_POP]
+#define cilk_save_fp_fndecl           cilk_trees[CILK_TI_F_SAVE_FP]
+
+#define cilk_worker_type_fndecl       cilk_trees[CILK_TI_WORKER_TYPE]
+#define cilk_frame_type_decl          cilk_trees[CILK_TI_FRAME_TYPE]
+#define cilk_frame_ptr_type_decl      cilk_trees[CILK_TI_FRAME_PTR]
+#define cilk_pedigree_type_decl       cilk_trees[CILK_TI_PEDIGREE_TYPE]
+
+extern void expand_builtin_cilk_detach (tree);
+extern void expand_builtin_cilk_pop_frame (tree);
+extern tree cilk_arrow (tree, int, bool);
+extern tree cilk_dot (tree, int, bool);
+extern void cilk_init_builtins (void);
+extern void gimplify_cilk_sync (tree *, gimple_seq *);
+extern tree cilk_call_setjmp (tree);
+/* Returns true if Cilk Plus is enabled and if F->cilk_frame_decl is not
+   NULL_TREE.  */
+
+inline bool
+fn_contains_cilk_spawn_p (function *f)
+{
+  return (flag_enable_cilkplus 
+	  && (f->calls_cilk_spawn || f->cilk_frame_decl != NULL_TREE));
+}
+#endif
diff --git a/gcc/cppbuiltin.c b/gcc/cppbuiltin.c
index 2ceccdc..cd74e23 100644
--- a/gcc/cppbuiltin.c
+++ b/gcc/cppbuiltin.c
@@ -105,6 +105,8 @@  define_builtin_macros_for_compilation_flags (cpp_reader *pfile)
 
   cpp_define_formatted (pfile, "__FINITE_MATH_ONLY__=%d",
 			flag_finite_math_only);
+  if (flag_enable_cilkplus)
+    cpp_define (pfile, "__cilk=200");
 }
 
 
diff --git a/gcc/doc/generic.texi b/gcc/doc/generic.texi
index ccecd6e..415d2b7 100644
--- a/gcc/doc/generic.texi
+++ b/gcc/doc/generic.texi
@@ -3160,6 +3160,30 @@  several statements chained together.
 Used to represent a @code{break} statement.  There are no additional
 fields.
 
+@item CILK_SPAWN_STMT
+
+Used to represent a spawning function in the Cilk Plus language extension.  
+This tree has one field that holds the name of the spawning function.
+@code{_Cilk_spawn} can be written in C in the following way:
+
+@smallexample
+@code{_Cilk_spawn} <function_name> (<parameters>);
+@end smallexample
+
+Detailed description for usage and functionality of @code{_Cilk_spawn} can be 
+found at http://www.cilkplus.org
+
+@item CILK_SYNC_STMT
+
+This statement is part of the Cilk Plus language extension.  It indicates that
+the current function cannot continue in parallel with its spawned children.  
+There are no additional fields.  @code{_Cilk_sync} can be written in C in the 
+following way:
+
+@smallexample
+@code{_Cilk_sync};
+@end smallexample
+
 @item CLEANUP_STMT
 
 Used to represent an action that should take place upon exit from the
diff --git a/gcc/doc/passes.texi b/gcc/doc/passes.texi
index 045f964..97f7d93 100644
--- a/gcc/doc/passes.texi
+++ b/gcc/doc/passes.texi
@@ -124,13 +124,45 @@  true, then we expand them using either @code{expand_array_notation_exprs} or
 inside conditions, they are transformed using the function 
 @code{fix_conditional_array_notations}.  The C language-specific routines are 
 located in @file{c/c-array-notation.c} and the equivalent C++ routines are in 
-file @file{cp/cp-array-notation.c}.  Common routines such as functions to 
-initialize builtin functions are stored in @file{array-notation-common.c}.
+the file @file{cp/cp-array-notation.c}.  Common routines such as functions to 
+initialize built-in functions are stored in @file{array-notation-common.c}.
+
+@item Cilk keywords:
+@itemize @bullet 
+@item @code{_Cilk_spawn}:
+The @code{_Cilk_spawn} keyword is parsed and the function it contains is marked 
+as a spawning function.  The spawning function is called the spawner.  At 
+the end of the parsing phase, appropriate built-in functions are 
+added to the spawner that are defined in the Cilk runtime.  The appropriate 
+locations of these functions, and the internal structures are detailed in 
+@code{cilk_init_builtins} in the file @file{cilk-common.c}.  The pointers to 
+Cilk functions and fields of internal structures are described 
+in @file{cilk.h}.  The built-in functions are described in 
+@file{cilk-builtins.def}.
+
+During gimplification, a new "spawn-helper" function is created.  
+The spawned function is replaced with a spawn helper function in the spawner.  
+The spawned function-call is moved into the spawn helper.  The main function
+that does these transformations is @code{gimplify_cilk_spawn} in
+@file{c-family/cilk.c}.  In the spawn-helper, the gimplification function 
+@code{gimplify_call_expr}, inserts a function call @code{__cilkrts_detach}.
+This function is expanded by @code{builtin_expand_cilk_detach} located in
+@file{c-family/cilk.c}.
+
+@item @code{_Cilk_sync}:
+@code{_Cilk_sync} is parsed like a keyword.  During gimplification, 
+the function @code{gimplify_cilk_sync} in @file{c-family/cilk.c}, will replace
+this keyword with a set of functions that are stored in the Cilk runtime.  
+One of the internal functions inserted during gimplification, 
+@code{__cilkrts_pop_frame} must be expanded by the compiler and is 
+done by @code{builtin_expand_cilk_pop_frame} in @file{cilk-common.c}.
+
+@end itemize
 @end itemize
 
-Detailed information about Cilk Plus and language specification is provided in 
-@w{@uref{http://www.cilkplus.org/}}.  It is worth mentioning that the current 
-implementation follows ABI 0.9.
+Documentation about Cilk Plus and language specification is provided under the
+"Learn" section in @w{@uref{http://www.cilkplus.org/}}.  It is worth mentioning
+that the current implementation follows ABI 1.1.
 
 @node Gimplification pass
 @section Gimplification pass
diff --git a/gcc/function.h b/gcc/function.h
index d1f4ffc..9bb6ff0 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -552,6 +552,9 @@  struct GTY(()) function {
   /* Vector of function local variables, functions, types and constants.  */
   vec<tree, va_gc> *local_decls;
 
+  /* In a Cilk function, the VAR_DECL for the frame descriptor. */
+  tree cilk_frame_decl;
+
   /* For md files.  */
 
   /* tm.h can use this to store whatever it likes.  */
@@ -607,6 +610,12 @@  struct GTY(()) function {
      either as a subroutine or builtin.  */
   unsigned int calls_alloca : 1;
 
+  /* This will indicate whether a function is a cilk function */
+  unsigned int is_cilk_function : 1;
+
+  /* Nonzero if this is a Cilk function that spawns. */
+  unsigned int calls_cilk_spawn : 1;
+  
   /* Nonzero if function being compiled receives nonlocal gotos
      from nested functions.  */
   unsigned int has_nonlocal_label : 1;
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 193e017..c1eab77 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -44,6 +44,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "vec.h"
 #include "omp-low.h"
 #include "gimple-low.h"
+#include "cilk.h"
 
 #include "langhooks-def.h"	/* FIXME: for lhd_set_decl_assembler_name */
 #include "tree-pass.h"		/* FIXME: only for PROP_gimple_any */
@@ -1307,6 +1308,15 @@  gimplify_return_expr (tree stmt, gimple_seq *pre_p)
   if (ret_expr == error_mark_node)
     return GS_ERROR;
 
+  /* Implicit _Cilk_sync must be inserted right before any return statement 
+     if there is a _Cilk_spawn in the function.  If the user has provided a 
+     _Cilk_sync, the optimizer should remove this duplicate one.  */
+  if (fn_contains_cilk_spawn_p (cfun))
+    {
+      tree impl_sync = build0 (CILK_SYNC_STMT, void_type_node);
+      gimplify_and_add (impl_sync, pre_p);
+    }
+
   if (!ret_expr
       || TREE_CODE (ret_expr) == RESULT_DECL
       || ret_expr == error_mark_node)
@@ -2497,6 +2507,12 @@  gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value)
   if (! EXPR_HAS_LOCATION (*expr_p))
     SET_EXPR_LOCATION (*expr_p, input_location);
 
+  if (fn_contains_cilk_spawn_p (cfun)
+      && lang_hooks.cilkplus.cilk_detect_spawn_and_unwrap (expr_p) 
+      && !seen_error ())
+    return (enum gimplify_status) 
+      lang_hooks.cilkplus.gimplify_cilk_spawn (expr_p, pre_p, NULL);
+
   /* This may be a call to a builtin function.
 
      Builtin function calls may be transformed into different
@@ -4702,6 +4718,12 @@  gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
 
   gcc_assert (TREE_CODE (*expr_p) == MODIFY_EXPR
 	      || TREE_CODE (*expr_p) == INIT_EXPR);
+  
+  if (fn_contains_cilk_spawn_p (cfun)
+      && lang_hooks.cilkplus.cilk_detect_spawn_and_unwrap (expr_p) 
+      && !seen_error ())
+    return (enum gimplify_status) 
+      lang_hooks.cilkplus.gimplify_cilk_spawn (expr_p, pre_p, post_p);
 
   /* Trying to simplify a clobber using normal logic doesn't work,
      so handle it here.  */
@@ -7648,6 +7670,19 @@  gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
 	    }
 	  break;
 
+	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.  */
+
 	case CALL_EXPR:
 	  ret = gimplify_call_expr (expr_p, pre_p, fallback != fb_none);
 
@@ -8268,6 +8303,22 @@  gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
 	    break;
 	  }
 
+	case CILK_SYNC_STMT:
+	  {
+	    if (!fn_contains_cilk_spawn_p (cfun))
+	      {
+		error_at (EXPR_LOCATION (*expr_p),
+			  "expected %<_Cilk_spawn%> before %<_Cilk_sync%>");
+		ret = GS_ERROR;
+	      }
+	    else
+	      {
+		gimplify_cilk_sync (expr_p, pre_p);
+		ret = GS_ALL_DONE;
+	      }
+	    break;
+	  }
+	
 	default:
 	  switch (TREE_CODE_CLASS (TREE_CODE (*expr_p)))
 	    {
diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c
index 304f9f5..0080956 100644
--- a/gcc/ipa-inline-analysis.c
+++ b/gcc/ipa-inline-analysis.c
@@ -89,6 +89,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "cfgloop.h"
 #include "tree-scalar-evolution.h"
 #include "ipa-utils.h"
+#include "cilk.h"
 
 /* Estimate runtime of function can easilly run into huge numbers with many
    nested loops.  Be sure we can compute time * INLINE_SIZE_SCALE * 2 in an
@@ -1434,6 +1435,9 @@  initialize_inline_failed (struct cgraph_edge *e)
     e->inline_failed = CIF_REDEFINED_EXTERN_INLINE;
   else if (e->call_stmt_cannot_inline_p)
     e->inline_failed = CIF_MISMATCHED_ARGUMENTS;
+  else if (cfun && fn_contains_cilk_spawn_p (cfun))
+    /* We can't inline if the function is spawing a function.  */
+    e->inline_failed = CIF_FUNCTION_NOT_INLINABLE;
   else
     e->inline_failed = CIF_FUNCTION_NOT_CONSIDERED;
 }
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index 26c410b..f6da9e8 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -114,6 +114,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "ipa-inline.h"
 #include "ipa-utils.h"
 #include "sreal.h"
+#include "cilk.h"
 
 /* Statistics we collect about inlining algorithm.  */
 static int overall_size;
@@ -263,7 +264,8 @@  can_inline_edge_p (struct cgraph_edge *e, bool report,
       e->inline_failed = CIF_BODY_NOT_AVAILABLE;
       inlinable = false;
     }
-  else if (!inline_summary (callee)->inlinable)
+  else if (!inline_summary (callee)->inlinable 
+	   || (caller_cfun && fn_contains_cilk_spawn_p (caller_cfun)))
     {
       e->inline_failed = CIF_FUNCTION_NOT_INLINABLE;
       inlinable = false;
diff --git a/gcc/ira.c b/gcc/ira.c
index d959109..628fd03 100644
--- a/gcc/ira.c
+++ b/gcc/ira.c
@@ -1874,6 +1874,9 @@  ira_setup_eliminable_regset (bool from_ira_p)
        || (flag_stack_check && STACK_CHECK_MOVING_SP)
        || crtl->accesses_prior_frames
        || crtl->stack_realign_needed
+       /* We need a frame pointer for all Cilk Plus functions that use
+	  Cilk keywords.  */
+       || (flag_enable_cilkplus && cfun->is_cilk_function)
        || targetm.frame_pointer_required ());
 
   if (from_ira_p && ira_use_lra_p)
diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h
index b7be472..411cf74 100644
--- a/gcc/langhooks-def.h
+++ b/gcc/langhooks-def.h
@@ -214,6 +214,18 @@  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 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
+#define LANG_HOOKS_CILKPLUS_GIMPLIFY_SPAWN lhd_gimplify_expr
+
+#define LANG_HOOKS_CILKPLUS {			\
+  LANG_HOOKS_CILKPLUS_DETECT_SPAWN_AND_UNWRAP,	\
+  LANG_HOOKS_CILKPLUS_FRAME_CLEANUP,		\
+  LANG_HOOKS_CILKPLUS_GIMPLIFY_SPAWN            \
+}
+
 #define LANG_HOOKS_DECLS { \
   LANG_HOOKS_GLOBAL_BINDINGS_P, \
   LANG_HOOKS_PUSHDECL, \
@@ -291,6 +303,7 @@  extern void lhd_end_section (void);
   LANG_HOOKS_TREE_DUMP_INITIALIZER, \
   LANG_HOOKS_DECLS, \
   LANG_HOOKS_FOR_TYPES_INITIALIZER, \
+  LANG_HOOKS_CILKPLUS, \
   LANG_HOOKS_LTO, \
   LANG_HOOKS_GET_INNERMOST_GENERIC_PARMS, \
   LANG_HOOKS_GET_INNERMOST_GENERIC_ARGS, \
diff --git a/gcc/langhooks.c b/gcc/langhooks.c
index 559d5c1..5d1457b 100644
--- a/gcc/langhooks.c
+++ b/gcc/langhooks.c
@@ -675,3 +675,18 @@  lhd_end_section (void)
       saved_section = NULL;
     }
 }
+
+/* Empty function that is replaced with appropriate language dependent
+   frame cleanup function for _Cilk_spawn.  */
+
+void
+lhd_install_body_with_frame_cleanup (tree, tree)
+{
+}
+
+/* Empty function to handle cilk_valid_spawn.  */
+bool
+lhd_cilk_detect_spawn (tree *)
+{
+  return false;
+}
diff --git a/gcc/langhooks.h b/gcc/langhooks.h
index a83bf7b..9539e7d 100644
--- a/gcc/langhooks.h
+++ b/gcc/langhooks.h
@@ -139,6 +139,23 @@  struct lang_hooks_for_types
   tree (*reconstruct_complex_type) (tree, tree);
 };
 
+/* Language hooks related to Cilk Plus.  */
+
+struct lang_hooks_for_cilkplus
+{
+  /* Returns true if the expression passed in has a spawned function call.  */
+  bool (*cilk_detect_spawn_and_unwrap) (tree *);
+
+  /* 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);
+
+  /* Function to gimplify a spawned function call.  Returns enum gimplify
+     status, but as mentioned in a previous comment, we can't see that type 
+     here, so just return an int.  */
+  int (*gimplify_cilk_spawn) (tree *, gimple_seq *, gimple_seq *);
+};
+
 /* Language hooks related to decls and the symbol table.  */
 
 struct lang_hooks_for_decls
@@ -408,6 +425,8 @@  struct lang_hooks
 
   struct lang_hooks_for_types types;
 
+  struct lang_hooks_for_cilkplus cilkplus;
+  
   struct lang_hooks_for_lto lto;
 
   /* Returns a TREE_VEC of the generic parameters of an instantiation of
diff --git a/gcc/lto/lto-lang.c b/gcc/lto/lto-lang.c
index 0fa0fc9..b56c22b 100644
--- a/gcc/lto/lto-lang.c
+++ b/gcc/lto/lto-lang.c
@@ -35,6 +35,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "diagnostic-core.h"
 #include "toplev.h"
 #include "lto-streamer.h"
+#include "cilk.h"
 
 static tree lto_type_for_size (unsigned, int);
 
@@ -1174,6 +1175,9 @@  lto_init (void)
       lto_define_builtins (va_list_type_node,
 			   build_reference_type (va_list_type_node));
     }
+  
+  if (flag_enable_cilkplus)
+    cilk_init_builtins ();
 
   targetm.init_builtins ();
   build_common_builtin_nodes ();
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/CK/compound_cilk_spawn.c b/gcc/testsuite/c-c++-common/cilk-plus/CK/compound_cilk_spawn.c
new file mode 100644
index 0000000..5e687bd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cilk-plus/CK/compound_cilk_spawn.c
@@ -0,0 +1,26 @@ 
+/* { dg-do compile } */
+/* { dg-options "-fcilkplus" } */
+
+/* <feature>
+   A program is considered ill formed if the _Cilk_spawn form of this
+    expression appears other than in one of the following contexts:
+    as the entire body of an expression statement,
+    as the entire right hand side of an assignment expression that is the entire
+    body of an expression statement, or as the entire initializer-clause in a 
+    simple declaration.
+   </feature>
+*/
+
+int spawn_func (int arg)
+{
+  return arg + 1;
+}
+
+int check()
+{
+  int z;
+  z = 23, _Cilk_spawn spawn_func (3), 3424; /* { dg-error "spawned function call cannot be part of a comma expression" } */
+  23, spawn_func (5), _Cilk_spawn spawn_func (3); /* { dg-error "spawned function call cannot be part of a comma expression" } */
+  _Cilk_spawn spawn_func (0), _Cilk_spawn spawn_func (3), 3, spawn_func (0); /* { dg-error "spawned function call cannot be part of a comma expression" } */
+  return 23;
+}
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/CK/concec_cilk_spawn.c b/gcc/testsuite/c-c++-common/cilk-plus/CK/concec_cilk_spawn.c
new file mode 100644
index 0000000..b93c962
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cilk-plus/CK/concec_cilk_spawn.c
@@ -0,0 +1,20 @@ 
+/* { dg-do compile } */
+/* { dg-options "-fcilkplus" } */
+
+/* <feature> Consecutive _Cilk_spawn tokens are not permitted
+   </feature>
+*/
+
+int spawn_func (int arg)
+{
+  return arg + 1;
+}
+
+void func ()
+{
+  int a;
+  a = _Cilk_spawn _Cilk_spawn spawn_func (4); /* { dg-error "consecutive" } */
+  a = _Cilk_spawn _Cilk_spawn _Cilk_spawn spawn_func (4); /* { dg-error "consecutive" } */
+  a = _Cilk_spawn _Cilk_spawn _Cilk_spawn _Cilk_spawn spawn_func (4); /* { dg-error "consecutive" } */
+  return;
+}
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/CK/fib.c b/gcc/testsuite/c-c++-common/cilk-plus/CK/fib.c
new file mode 100644
index 0000000..94da12c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cilk-plus/CK/fib.c
@@ -0,0 +1,61 @@ 
+/* { 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 <stdio.h>
+#endif
+
+int fib        (int);
+int fib_serial (int);
+
+int main(void)
+{
+  int ii = 0, error = 0;
+  int fib_result[41], fib_serial_result[41];
+#if HAVE_IO
+
+  for (ii = 0; ii <= 40; ii++)
+    printf("fib (%2d) = %10d\n", ii, fib (ii));
+#else
+  for (ii = 0; ii <= 40; ii++)
+    {
+      fib_result[ii]        = fib (ii);
+      fib_serial_result[ii] = fib_serial (ii);
+    }
+
+  for (ii = 0; ii <= 40; ii++)
+    {
+      if (fib_result[ii] != fib_serial_result[ii])
+	error = 1;
+    }
+#endif
+  return error;
+}
+
+int fib_serial (int n)
+{
+  int x = 0, y = 0;
+  if (n < 2)
+    return n;
+  else
+    {
+      x = fib (n-1);
+      y = fib (n-2);
+      return (x+y);
+    }
+}
+
+int fib(int n)
+{
+  int x = 0, y = 0;
+  if (n < 2) 
+    return n;
+  else
+  {
+    x = _Cilk_spawn fib(n-1);
+    y = fib(n-2);
+    _Cilk_sync;
+    return (x+y);
+  }
+}
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/CK/fib_init_expr_xy.c b/gcc/testsuite/c-c++-common/cilk-plus/CK/fib_init_expr_xy.c
new file mode 100644
index 0000000..af94ac3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cilk-plus/CK/fib_init_expr_xy.c
@@ -0,0 +1,60 @@ 
+/* { 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 <stdio.h>
+#endif
+
+int fib        (int);
+int fib_serial (int);
+
+int main(void)
+{
+  int ii = 0, error = 0;
+  int fib_result[41], fib_serial_result[41];
+#if HAVE_IO
+
+  for (ii = 0; ii <= 40; ii++)
+    printf("fib (%2d) = %10d\n", ii, fib (ii));
+#else
+  for (ii = 0; ii <= 40; ii++)
+    {
+      fib_result[ii]        = fib (ii);
+      fib_serial_result[ii] = fib_serial (ii);
+    }
+
+  for (ii = 0; ii <= 40; ii++)
+    {
+      if (fib_result[ii] != fib_serial_result[ii])
+	error = 1;
+    }
+#endif
+  return error;
+}
+
+int fib_serial (int n)
+{
+  int x = 0, y = 0;
+  if (n < 2)
+    return n;
+  else
+    {
+      x = fib (n-1);
+      y = fib (n-2);
+      return (x+y);
+    }
+}
+
+int fib(int n)
+{
+  if (n < 2) 
+    return n;
+  else
+  {
+    int x = _Cilk_spawn fib(n-1);
+    int y = fib(n-2);
+    _Cilk_sync;
+    return (x+y);
+  }
+}
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/CK/fib_no_return.c b/gcc/testsuite/c-c++-common/cilk-plus/CK/fib_no_return.c
new file mode 100644
index 0000000..2b066ea
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cilk-plus/CK/fib_no_return.c
@@ -0,0 +1,65 @@ 
+/* { 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 <stdio.h>
+#endif
+
+void fib        (int *, int);
+int fib_serial (int);
+
+int main(void)
+{
+  int ii = 0, error = 0;
+  int fib_result[41], fib_serial_result[41];
+
+#if HAVE_IO
+  for (ii = 0; ii <= 40; ii++)
+    {
+      int result = 0;
+      fib (&result, ii); 
+      printf("fib (%2d) = %10d\n", ii, result);
+    }
+#else
+  for (ii = 0; ii <= 40; ii++)
+    {
+      fib (&fib_result[ii], ii);
+      fib_serial_result[ii] = fib_serial (ii);
+    }
+
+  for (ii = 0; ii <= 40; ii++)
+    {
+      if (fib_result[ii] != fib_serial_result[ii])
+	error = 1;
+    }
+#endif
+  return error;
+}
+
+int fib_serial (int n)
+{
+  int x = 0, y = 0;
+  if (n < 2)
+    return n;
+  else
+    {
+      fib (&x, n-1);
+      fib (&y, n-2);
+      return (x+y);
+    }
+}
+
+void fib(int *result, int n)
+{
+  int x = 0, y = 0;
+  if (n < 2) 
+    x = n;
+  else
+  {
+    _Cilk_spawn fib(&x, n-1);
+    fib(&y, n-2);
+    _Cilk_sync;
+  } 
+ *result = (x+y);
+}
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/CK/fib_no_sync.c b/gcc/testsuite/c-c++-common/cilk-plus/CK/fib_no_sync.c
new file mode 100644
index 0000000..f39cba0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cilk-plus/CK/fib_no_sync.c
@@ -0,0 +1,59 @@ 
+/* { 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 <stdio.h>
+#endif
+
+int fib        (int);
+int fib_serial (int);
+
+int main(void)
+{
+  int ii = 0, error = 0;
+  int fib_result[41], fib_serial_result[41];
+#if HAVE_IO
+
+  for (ii = 0; ii <= 40; ii++)
+    printf("fib (%2d) = %10d\n", ii, fib (ii));
+#else
+  for (ii = 0; ii <= 40; ii++)
+    {
+      fib_result[ii]        = fib (ii);
+      fib_serial_result[ii] = fib_serial (ii);
+    }
+
+  for (ii = 0; ii <= 40; ii++)
+    {
+      if (fib_result[ii] != fib_serial_result[ii])
+	error = 1;
+    }
+#endif
+  return error;
+}
+
+int fib_serial (int n)
+{
+  int x = 0, y = 0;
+  if (n < 2)
+    return n;
+  else
+    {
+      x = fib (n-1);
+      y = fib (n-2);
+      return (x+y);
+    }
+}
+
+int fib(int n)
+{
+  if (n < 2) 
+    return n;
+  else
+  {
+    int x = _Cilk_spawn fib(n-1);
+    int y = fib(n-2);
+    return (x+y);
+  }
+}
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/CK/invalid_spawns.c b/gcc/testsuite/c-c++-common/cilk-plus/CK/invalid_spawns.c
new file mode 100644
index 0000000..90dd5c1
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cilk-plus/CK/invalid_spawns.c
@@ -0,0 +1,11 @@ 
+extern int foo ();
+int bar = _Cilk_spawn foo (); /* { dg-error "may only be used inside a function" } */
+
+
+int main (void)
+{
+  int x; 
+
+  _Cilk_spawn x; /* { dg-error "only function calls can be spawned" } */
+  return x;
+}
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/CK/no_args_error.c b/gcc/testsuite/c-c++-common/cilk-plus/CK/no_args_error.c
new file mode 100644
index 0000000..593732e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cilk-plus/CK/no_args_error.c
@@ -0,0 +1,11 @@ 
+/* { dg-do compile } */
+/* { dg-options "-fcilkplus" } */
+
+int spawn_1 ();
+typedef int(*func) (int);
+
+void check () {
+      func var = spawn_1; /* { dg-error "invalid conversion from" "" { target c++ } 8 } */
+        _Cilk_spawn var (); /* { dg-error "too few arguments to function" } */ 
+}
+
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/CK/spawn_in_return.c b/gcc/testsuite/c-c++-common/cilk-plus/CK/spawn_in_return.c
new file mode 100644
index 0000000..14b7eef
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cilk-plus/CK/spawn_in_return.c
@@ -0,0 +1,8 @@ 
+/* { dg-do compile } */
+/* { dg-options "-fcilkplus" } */
+
+int main (void)
+{
+  extern int foo ();
+  return _Cilk_spawn foo (); /* { dg-error "return statement is not allowed" } */
+}
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/CK/spawnee_inline.c b/gcc/testsuite/c-c++-common/cilk-plus/CK/spawnee_inline.c
new file mode 100644
index 0000000..4a2a4a4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cilk-plus/CK/spawnee_inline.c
@@ -0,0 +1,80 @@ 
+/* { dg-do run  { target { i?86-*-* x86_64-*-* arm*-*-* } } } */
+/* { dg-options "-fcilkplus -w" } */
+/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* arm*-*-* } } } */
+
+#include <stdio.h>
+#include <stdlib.h>
+#define DEFAULT_VALUE "30"
+
+int fib (char *n_char)
+{
+  int n;
+  char n_char_minus_one[20], n_char_minus_two[20];
+  if (n_char)
+    n = atoi (n_char);
+  else
+    n = atoi(DEFAULT_VALUE);
+  
+  if (n < 2)
+    return n;
+  else
+    {	   
+      int x, y;
+      sprintf (n_char_minus_one,"%d", n-1); 
+      sprintf (n_char_minus_two,"%d", n-2); 
+      x = _Cilk_spawn fib (n_char_minus_one);
+      y = _Cilk_spawn fib (n_char_minus_two);
+      _Cilk_sync;
+      return (x+y);
+    }
+}
+
+int fib_serial (int n)
+{
+  int x, y;
+  if (n < 2)
+    return n;
+  else
+    {
+      x = fib_serial (n-1);
+      y = fib_serial (n-2);
+      return (x+y);
+    }
+  return 0;
+}
+
+int main2_parallel (int argc, char *argv[])
+{
+  int n, result_parallel = 0;
+
+  if (argc == 2)
+    {
+      result_parallel = _Cilk_spawn fib (argv[1]);
+      _Cilk_sync; 
+    }
+  else
+    {
+      result_parallel = _Cilk_spawn fib((char *)"30");
+      _Cilk_sync; 
+    }
+  return result_parallel;
+}
+
+int main2_serial (int argc, char *argv[])
+{
+  int n, result_serial = 0;
+  if (argc == 2) 
+    result_serial = fib_serial (atoi (argv[1]));
+  else
+    result_serial = fib_serial (atoi (DEFAULT_VALUE));
+
+  return result_serial;
+}
+
+int main (void)
+{
+  if (main2_serial (1, 0) != main2_parallel (1,0))
+    return 1;
+  return 0;
+}
+
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/CK/spawner_inline.c b/gcc/testsuite/c-c++-common/cilk-plus/CK/spawner_inline.c
new file mode 100644
index 0000000..9d07d97
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cilk-plus/CK/spawner_inline.c
@@ -0,0 +1,67 @@ 
+/* { dg-do run  { target { i?86-*-* x86_64-*-* arm*-*-* } } } */
+/* { dg-options "-fcilkplus" } */
+/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* arm*-*-* } } } */
+
+#include <stdlib.h>
+#define DEFAULT_VALUE 30
+int fib (int n)
+{
+  if (n<2)
+    return n;
+  else
+    {
+      int x, y;
+      x = _Cilk_spawn fib (n-1);
+      y = _Cilk_spawn fib (n-2);
+      _Cilk_sync;
+      return (x+y);
+      return 5;
+    }
+}
+
+int main_parallel (int argc, char *argv[])
+{
+  int n, result;
+  if (argc == 2)
+    n = atoi(argv[1]);
+  else
+    n = DEFAULT_VALUE;
+  result = _Cilk_spawn fib(n);
+  _Cilk_sync; 
+  return result;
+}
+
+int fib_serial (int n)
+{
+  int x, y;
+  if (n < 2)
+    return n;
+  else
+    {
+      x = fib (n-1);
+      y = fib (n-2);
+      return (x+y);
+    }
+}
+  
+int main_serial (int argc, char *argv[])
+{
+  int n, result;
+
+  if (argc == 2)
+    n = atoi (argv[1]);
+  else
+    n = DEFAULT_VALUE;
+  result = fib_serial (n);
+
+  return result;
+}
+
+int main (void)
+{
+  if (main_serial (1, 0) != main_parallel (1,0))
+    return 1;
+  else 
+    return 0;
+}
+
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/CK/spawning_arg.c b/gcc/testsuite/c-c++-common/cilk-plus/CK/spawning_arg.c
new file mode 100644
index 0000000..51a7bd2
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cilk-plus/CK/spawning_arg.c
@@ -0,0 +1,37 @@ 
+/* { dg-do run  { target { i?86-*-* x86_64-*-* arm*-*-* } } } */
+/* { dg-options "-fcilkplus" } */
+/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* arm*-*-* } } } */
+
+void f0(volatile int *steal_flag)
+{ 
+  int i = 0;
+  /* Wait for steal_flag to be set */
+  while (!*steal_flag) 
+    ;
+}
+
+int f1()
+{
+
+  volatile int steal_flag = 0;
+  _Cilk_spawn f0(&steal_flag);
+  steal_flag = 1;  // Indicate stolen
+  _Cilk_sync; 
+  return 0;
+}
+
+void f2(int q)
+{
+  q = 5;
+}
+
+void f3()
+{
+   _Cilk_spawn f2(f1());
+}
+
+int main()
+{
+  f3();
+  return 0;
+}
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/CK/steal_check.c b/gcc/testsuite/c-c++-common/cilk-plus/CK/steal_check.c
new file mode 100644
index 0000000..8aa9cdb
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cilk-plus/CK/steal_check.c
@@ -0,0 +1,43 @@ 
+/* { dg-do run  { target { i?86-*-* x86_64-*-* arm*-*-* } } } */
+/* { dg-options "-fcilkplus" } */
+/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* arm*-*-* } } } */
+
+// #include <cilk/cilk_api.h>
+extern void __cilkrts_set_param (char *, char *);
+
+void foo(volatile int *);
+
+void main2(void);
+
+int main(void)
+{
+ //  __cilkrts_set_param ((char *)"nworkers", (char *)"2");
+  main2();
+  return 0;
+}
+
+
+void main2(void)
+{
+  int some_var = 0;
+
+  _Cilk_spawn foo(&some_var);
+
+  some_var=1;
+  some_var=5;
+  some_var=3;
+  some_var=4;
+
+  _Cilk_sync; 
+  return;
+}
+
+void foo(volatile int *some_other_var)
+{
+  while (*some_other_var == 0)
+  {
+   ;
+  }
+}
+
+
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/CK/sync_wo_spawn.c b/gcc/testsuite/c-c++-common/cilk-plus/CK/sync_wo_spawn.c
new file mode 100644
index 0000000..51be796
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cilk-plus/CK/sync_wo_spawn.c
@@ -0,0 +1,9 @@ 
+/* { dg-do compile } */
+/* { dg-options "-fcilkplus" } */
+
+int main (void)
+{
+  _Cilk_sync; /* { dg-error "expected '_Cilk_spawn' before '_Cilk_sync'" } */
+  return 0;
+}
+
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/CK/test__cilk.c b/gcc/testsuite/c-c++-common/cilk-plus/CK/test__cilk.c
new file mode 100644
index 0000000..69197fc
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cilk-plus/CK/test__cilk.c
@@ -0,0 +1,10 @@ 
+/* { dg-do compile } */
+/* { dg-do run  { target { i?86-*-* x86_64-*-* arm*-*-* } } } */
+/* { dg-options "-fcilkplus" } */
+
+int main (void)
+{
+  if (__cilk == 200)
+   return 0; 
+  return 1;
+}
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/CK/varargs_test.c b/gcc/testsuite/c-c++-common/cilk-plus/CK/varargs_test.c
new file mode 100644
index 0000000..c8982d2
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cilk-plus/CK/varargs_test.c
@@ -0,0 +1,47 @@ 
+/* { dg-do run  { target { i?86-*-* x86_64-*-* arm*-*-* } } } */
+/* { dg-options "-fcilkplus" } */
+/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* arm*-*-* } } } */
+
+#include <stdarg.h>
+#include <stdlib.h>
+
+
+double compute_total (int no_elements, ...);
+
+int main(void)
+{
+  double array[5] = {5.0, 4.0, 9.0, 3.0, 4.0};
+  double array2[5] = {5.0, 6.0, 8.0, 6.0};
+  double yy=0, xx=0, xx_serial, yy_serial;
+
+  yy = _Cilk_spawn compute_total(5,array[0],array[1],array[2],
+                                 array[3], array[4]);
+  xx= compute_total(4,array2[0],array2[1],array2[2], array2[3]);
+  
+  _Cilk_sync;
+
+  yy_serial = compute_total(5,array[0],array[1],array[2], array[3], array[4]);
+  xx_serial = compute_total(4,array2[0],array2[1],array2[2], array2[3]);
+
+  if ((xx + yy) != (xx_serial + yy_serial)) 
+    return 1;
+  return 0;
+  
+}
+
+
+double compute_total (int no_elements, ...)
+{
+  double total = 0;
+  va_list args;
+  va_start(args, no_elements);
+  int ii = 0;
+  for (ii = 0; ii < no_elements; ii++)
+  {
+    total += va_arg(args,double);
+  }
+  va_end(args);
+
+  return total;
+}
+
diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp b/gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp
index 2533feb..7aa1839 100644
--- a/gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp
+++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp
@@ -23,6 +23,11 @@  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"
+
 dg-init
 dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -fcilkplus" " "
 dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O0 -fcilkplus" " "
@@ -46,4 +51,31 @@  dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -f
 dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -fcilkplus -g -O2 -ftree-vectorize -std=c99" " "
 dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -fcilkplus -g -O3 -std=c99" " "
 dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O3 -ftree-vectorize -std=c99 -g -fcilkplus" " "
+
+
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -O0 -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -O1 -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -O2 -ftree-vectorize -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -O3 -fcilkplus" " "
+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 -O0 -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -g -O1 -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -g -O2 -ftree-vectorize -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -g -O3 -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -O3 -ftree-vectorize -fcilkplus -g" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -fcilkplus -std=c99" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -fcilkplus -O0 -std=c99" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -fcilkplus -O1 -std=c99" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -fcilkplus -O2 -ftree-vectorize -std=c99" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -fcilkplus -O3 -std=c99" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -fcilkplus -g -std=c99" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -fcilkplus -g -O0 -std=c99" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -fcilkplus -g -O1 -std=c99" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -fcilkplus -g -O2 -ftree-vectorize -std=c99" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -fcilkplus -g -O3 -std=c99" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -O3 -ftree-vectorize -std=c99 -g -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -O0 -flto -g -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -O2 -flto -g -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -O3  -flto -g -fcilkplus" " "
 dg-finish
diff --git a/gcc/tree-inline.h b/gcc/tree-inline.h
index a78e4b6..cd32715 100644
--- a/gcc/tree-inline.h
+++ b/gcc/tree-inline.h
@@ -131,6 +131,10 @@  typedef struct copy_body_data
      the originals have been mapped to a value rather than to a
      variable.  */
   struct pointer_map_t *debug_map;
+ 
+  /* Cilk keywords currently need to replace some variables that
+     ordinary nested functions do not.  */ 
+  bool remap_var_for_cilk;
 } copy_body_data;
 
 /* Weights of constructions for estimate_num_insns.  */
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index f8a0342..4d499bf 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -2630,6 +2630,15 @@  dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
       dump_block_node (buffer, node, spc, flags);
       break;
 
+    case CILK_SPAWN_STMT:
+      pp_string (buffer, "_Cilk_spawn ");
+      dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
+      break;
+
+    case CILK_SYNC_STMT:
+      pp_string (buffer, "_Cilk_sync");
+      break;
+
     default:
       NIY;
     }
diff --git a/gcc/tree.def b/gcc/tree.def
index 88c850a..735347c 100644
--- a/gcc/tree.def
+++ b/gcc/tree.def
@@ -1261,6 +1261,13 @@  DEFTREECODE (OPTIMIZATION_NODE, "optimization_node", tcc_exceptional, 0)
 /* TARGET_OPTION_NODE.  Node to store the target specific options.  */
 DEFTREECODE (TARGET_OPTION_NODE, "target_option_node", tcc_exceptional, 0)
 
+/* Cilk spawn statement
+   Operand 0 is the CALL_EXPR.  */
+DEFTREECODE (CILK_SPAWN_STMT, "cilk_spawn_stmt", tcc_statement, 1)
+
+/* Cilk Sync statement: Does not have any operands.  */
+DEFTREECODE (CILK_SYNC_STMT, "cilk_sync_stmt", tcc_statement, 0)
+
 /*
 Local variables:
 mode:c
diff --git a/gcc/tree.h b/gcc/tree.h
index 2f4514d..c650cba 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -786,6 +786,9 @@  extern void omp_clause_range_check_failed (const_tree, const char *, int,
 #define CALL_EXPR_RETURN_SLOT_OPT(NODE) \
   (CALL_EXPR_CHECK (NODE)->base.private_flag)
 
+/* Cilk keywords accessors.  */
+#define CILK_SPAWN_FN(NODE) TREE_OPERAND (CILK_SPAWN_STMT_CHECK (NODE), 0)
+
 /* In a RESULT_DECL, PARM_DECL and VAR_DECL, means that it is
    passed by invisible reference (and the TREE_TYPE is a pointer to the true
    type).  */