+2013-10-29 Balaji V. Iyer <balaji.v.iyer@intel.com>
+
+ * builtins.c (is_builtin_name): Added a check for __cilkrts_detach and
+ __cilkrts_pop_frame. If matched, then return true for built-in
+ function name.
+ (expand_builtin): Added BUILT_IN_CILK_DETACH and
+ BUILT_IN_CILK_POP_FRAME case.
+ * langhooks-def.h (lhd_install_body_with_frame_cleanup): New prototype.
+ (lhs_cilk_detect_spawn): Likewise.
+ (LANG_HOOKS_DECLS): Added LANG_HOOKS_CILKPLUS.
+ (LANG_HOOKS_CILKPLUS_DETECT_SPAWN_AND_UNWRAP): New #define.
+ (LANG_HOOKS_CILKPLUS_FRAME_CLEANUP): Likewise.
+ (LANG_HOOKS_CILKPLUS_GIMPLIFY_SPAWN): Likewise.
+ (LANG_HOOKS_CILKPLUS): Likewise.
+ * tree.h (CILK_SPAWN_FN): Likewise.
+ * builtin.def (DEF_CILK_BUILTIN_STUB): Likewise.
+ * Makefile.in (C_COMMON_OBJS): Added c-family/cilk.o.
+ (OBJS): Added cilk-common.o.
+ (BUILTINS_DEF): Added cilk-builtins.def.
+ * langhooks.c (lhd_install_body_with_frame_cleanup): New function.
+ (lhd_cilk_detect_spawn): Likewise.
+ * langhooks.h (lang_hooks_for_cilkplus): New struct.
+ (struct lang_hooks): Added new field called "cilkplus."
+ * cilk-common.c: New file.
+ * cilk.h: Likewise.
+ * cilk-builtins.def: Likewise.
+ * cppbuiltin.c (define_builtin_macros_for_compilation_flags): Added
+ "__cilk" macro and set it to 200.
+ * function.h (struct function::cilk_frame_decl): New field.
+ (struct function::is_cilk_function): Likewise.
+ (struct function::calls_cilk_spawn): Likewise.
+ * gimplify.c (gimplify_call_expr): Added a check if the function call
+ being gimplified is a spawn detach point. If so, then add pop_frame
+ and detach function calls.
+ (gimplify_expr): Added a CILK_SPAWN_STMT and CILK_SYNC_STMT case
+ for gimplifying _Cilk_spawn and _Cilk_sync statements.
+ (gimplify_return_expr): Added a check for _Cilk_spawn usage in
+ function. If so, added a _Cilk_sync and gimplified it.
+ (gimplify_modify_expr): Added a check for _Cilk_spawn in MODIFY and
+ INIT_EXPRs. If so, then call gimplify_cilk_spawn.
+ * ipa-inline-analysis (initialize_inline_failed): Prevent inlining of
+ spawner function.
+ (can_inline_edge_p): Prevent inling of spawnee function.
+ * ira.c (ira_setup_eliminable_regset): Force usage of frame pointer
+ for functions that use Cilk keywords.
+ * tree-inline.h (struct copy_body_data::remap_var_for_cilk): New field.
+ * tree-pretty-print.c (dump_generic_node): Added CILK_SPAWN_STMT and
+ CILK_SYNC_STMT cases.
+ * tree.def (DEFTREECODE): Added CILK_SPAWN_STMT and CILK_SYNC_STMT
+ trees.
+ * generic.texi (CILK_SPAWN_STMT): Added documentation for _Cilk_spawn.
+ (CILK_SYNC_STMT): Added documentation for _Cilk_sync.
+ * passes.texi (Cilk Keywords): New section that describes the compiler
+ code changes for handling Cilk Keywords.
+
2013-10-29 David Malcolm <dmalcolm@redhat.com>
Patch autogenerated by refactor_symtab.py from
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 \
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 \
- 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
cgraphbuild.o \
cgraphunit.o \
cgraphclones.o \
+ cilk-common.o \
combine.o \
combine-stack-adj.o \
compare-elim.o \
#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));
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;
}
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;
}
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
/* OpenMP builtins. */
#include "omp-builtins.def"
+/* Cilk keywords builtins. */
+#include "cilk-builtins.def"
+
/* GTM builtins. */
#include "gtm-builtins.def"
+2013-10-29 Balaji V. Iyer <balaji.v.iyer@intel.com>
+
+ * c-common.c (c_common_reswords[]): Added _Cilk_spawn and _Cilk_sync
+ fields.
+ (c_define_builtins): Called cilk_init_builtins if Cilk Plus is
+ enabled.
+ * c-common.h (enum rid): Added RID_CILK_SPAWN and RID_CILK_SYNC.
+ (insert_cilk_frame): New prototype.
+ (cilk_init_builtins): Likewise.
+ (gimplify_cilk_spawn): Likewise.
+ (c_cilk_install_body_w_frame_cleanup): Likewise.
+ (cilk_detect_spawn_and_unwrap): Likewise.
+ (cilk_set_spawn_marker): Likewise.
+ (build_cilk_sync): Likewise.
+ (build_cilk_spawn): Likewise.
+ * cilk.c: New file.
+
2013-10-29 David Malcolm <dmalcolm@redhat.com>
Patch autogenerated by refactor_symtab.py from
{ "_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 },
targetm.init_builtins ();
build_common_builtin_nodes ();
+
+ if (flag_enable_cilkplus)
+ cilk_init_builtins ();
}
/* Like get_identifier, but avoid warnings about null arguments when
/* 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,
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 */
--- /dev/null
+/* 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;
+}
+2013-10-29 Balaji V. Iyer <balaji.v.iyer@intel.com>
+
+ * c-decl.c (finish_function): Added a call for insert_cilk_frame when
+ a spawning function is found.
+ * c-objc-common.h (LANG_HOOKS_CILKPLUS_GIMPLIFY_SPAWN): New #define.
+ (LANG_HOOKS_CILKPLUS_FRAME_CLEANUP): Likewise.
+ (LANG_HOOKS_CILKPLUS_DETECT_SPAWN_AND_UNWRAP): Likewise.
+ * c-parser.c (c_parser_statement_after_labels): Added RID_CILK_SYNC
+ case.
+ (c_parser_postfix_expression): Added RID_CILK_SPAWN case.
+ * c-typeck.c (build_compound_expr): Reject _Cilk_spawn in a comma
+ expr.
+ (c_finish_return): Added a check to reject _Cilk_spawn in return
+ expression.
+ (build_cilk_spawn): New function.
+ (build_cilk_sync): Likewise.
+ * Makefile.in (c-decl.o): Added cilk.h in dependency list.
+
2013-10-27 Tobias Burnus <burnus@net-b.de>
PR other/33426
#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
/* 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. */
#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 */
case RID_FOR:
c_parser_for_statement (parser, false);
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))
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;
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);
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;
--- /dev/null
+/* 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")
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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
cpp_define_formatted (pfile, "__FINITE_MATH_ONLY__=%d",
flag_finite_math_only);
+ if (flag_enable_cilkplus)
+ cpp_define (pfile, "__cilk=200");
}
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
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
/* 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. */
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;
#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 */
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)
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
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. */
}
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);
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)))
{
#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
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;
}
#include "ipa-inline.h"
#include "ipa-utils.h"
#include "sreal.h"
+#include "cilk.h"
/* Statistics we collect about inlining algorithm. */
static int overall_size;
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;
|| (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)
#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, \
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, \
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;
+}
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
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
+2013-10-29 Balaji V. Iyer <balaji.v.iyer@intel.com>
+
+ * Make-lang.in (lto/lto-lang.o): Added cilk.h in dependency list.
+ * lto-lang.c (lto_init): Added a call to cilk_init_builtins if Cilk
+ Plus is enabled.
+
2013-10-29 David Malcolm <dmalcolm@redhat.com>
Patch autogenerated by refactor_symtab.py from
#include "diagnostic-core.h"
#include "toplev.h"
#include "lto-streamer.h"
+#include "cilk.h"
static tree lto_type_for_size (unsigned, int);
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 ();
+2013-10-29 Balaji V. Iyer <balaji.v.iyer@intel.com>
+
+ * c-c++-common/cilk-plus/CK/compound_cilk_spawn.c: New test.
+ * c-c++-common/cilk-plus/CK/concec_cilk_spawn.c: Likewise.
+ * c-c++-common/cilk-plus/CK/fib.c: Likewise.
+ * c-c++-common/cilk-plus/CK/no_args_error.c: Likewise.
+ * c-c++-common/cilk-plus/CK/spawnee_inline.c: Likewise.
+ * c-c++-common/cilk-plus/CK/spawner_inline.c: Likewise.
+ * c-c++-common/cilk-plus/CK/spawning_arg.c: Likewise.
+ * c-c++-common/cilk-plus/CK/steal_check.c: Likewise.
+ * c-c++-common/cilk-plus/CK/test__cilk.c: Likewise.
+ * c-c++-common/cilk-plus/CK/varargs_test.c: Likewise.
+ * c-c++-common/cilk-plus/CK/sync_wo_spawn.c: Likewise.
+ * c-c++-common/cilk-plus/CK/invalid_spawn.c: Likewise.
+ * c-c++-common/cilk-plus/CK/spawn_in_return.c: Likewise.
+ * c-c++-common/cilk-plus/CK/fib_init_expr_xy.c: Likewise.
+ * c-c++-common/cilk-plus/CK/fib_no_sync.c: Likewise.
+ * c-c++-common/cilk-plus/CK/fib_no_return.c: Likewise.
+ * gcc.dg/cilk-plus/cilk-plus.exp: Added support to run Cilk Keywords
+ test stored in c-c++-common. Also, added the Cilk runtime's library
+ to the ld_library_path.
+
2013-10-29 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/58888
--- /dev/null
+/* { 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;
+}
--- /dev/null
+/* { 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;
+}
--- /dev/null
+/* { dg-options "-fcilkplus" } */
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fcilkplus -lcilkrts" { target { i?86-*-* x86_64-*-* } } } */
+
+#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);
+ }
+}
--- /dev/null
+/* { dg-options "-fcilkplus" } */
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fcilkplus -lcilkrts" { target { i?86-*-* x86_64-*-* } } } */
+
+#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);
+ }
+}
--- /dev/null
+/* { dg-options "-fcilkplus" } */
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fcilkplus -lcilkrts" { target { i?86-*-* x86_64-*-* } } } */
+
+#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);
+}
--- /dev/null
+/* { dg-options "-fcilkplus" } */
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fcilkplus -lcilkrts" { target { i?86-*-* x86_64-*-* } } } */
+
+#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);
+ }
+}
--- /dev/null
+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;
+}
--- /dev/null
+/* { 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" } */
+}
+
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-fcilkplus" } */
+
+int main (void)
+{
+ extern int foo ();
+ return _Cilk_spawn foo (); /* { dg-error "return statement is not allowed" } */
+}
--- /dev/null
+/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */
+/* { dg-options "-fcilkplus -w" } */
+/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */
+
+#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;
+}
+
--- /dev/null
+/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */
+/* { dg-options "-fcilkplus" } */
+/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */
+
+#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;
+}
+
--- /dev/null
+/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */
+/* { dg-options "-fcilkplus" } */
+/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */
+
+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;
+}
--- /dev/null
+/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */
+/* { dg-options "-fcilkplus" } */
+/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */
+
+// #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)
+ {
+ ;
+ }
+}
+
+
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-fcilkplus" } */
+
+int main (void)
+{
+ _Cilk_sync; /* { dg-error "expected '_Cilk_spawn' before '_Cilk_sync'" } */
+ return 0;
+}
+
--- /dev/null
+/* { dg-do compile } */
+/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */
+/* { dg-options "-fcilkplus" } */
+
+int main (void)
+{
+ if (__cilk == 200)
+ return 0;
+ return 1;
+}
--- /dev/null
+/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */
+/* { dg-options "-fcilkplus" } */
+/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */
+
+#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;
+}
+
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 "${library_var}/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" " "
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
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. */
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;
}
Operand 1 is the annotation id. */
DEFTREECODE (ANNOTATE_EXPR, "annotate_expr", tcc_expression, 2)
+/* 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:
#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). */