@@ -26,8 +26,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree.h"
#include "c-common.h"
-/* Validate the body of a _Cilk_for construct or a <#pragma simd> for
- loop.
+/* Validate the body of a <#pragma simd> for loop.
Returns true if there were no errors, false otherwise. */
@@ -91,3 +90,401 @@ c_finish_cilk_clauses (tree clauses)
}
return clauses;
}
+
+/* Helper function for c_check_cilk_for_loop.
+
+ Validate the increment in a _Cilk_for construct or a <#pragma simd>
+ for loop.
+
+ LOC is the location of the `for' keyword. DECL is the induction
+ variable. INCR is the original increment expression.
+
+ Returns the canonicalized increment expression for an OMP_FOR_INCR.
+ If there is a validation error, returns error_mark_node. */
+
+static tree
+c_check_cilk_loop_incr (location_t loc, tree decl, tree incr)
+{
+ tree orig_incr = incr;
+ if (!incr)
+ {
+ error_at (loc, "missing increment");
+ return error_mark_node;
+ }
+
+ if (EXPR_HAS_LOCATION (incr))
+ loc = EXPR_LOCATION (incr);
+
+ /* We hit this if-statement if we have an overloaded operand like
+ this: *my_class::operator+= (&ii, 1). For example, see the testscase
+ plus-equal-test.cc. */
+ if (TREE_CODE (incr) == INDIRECT_REF
+ || TREE_CODE (incr) == CLEANUP_POINT_EXPR)
+ incr = TREE_OPERAND (incr, 0);
+
+ if (TREE_CODE (incr) == TARGET_EXPR)
+ incr = TARGET_EXPR_INITIAL (incr);
+
+ switch (TREE_CODE (incr))
+ {
+ case POSTINCREMENT_EXPR:
+ case PREINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ case PREDECREMENT_EXPR:
+ if (TREE_OPERAND (incr, 0) != decl)
+ break;
+
+ return incr;
+
+ case MODIFY_EXPR:
+ {
+ tree rhs;
+
+ if (TREE_OPERAND (incr, 0) != decl)
+ break;
+
+ rhs = TREE_OPERAND (incr, 1);
+ if ((TREE_CODE (rhs) == PLUS_EXPR
+ || TREE_CODE (rhs) == POINTER_PLUS_EXPR)
+ && (TREE_OPERAND (rhs, 0) == decl
+ || TREE_OPERAND (rhs, 1) == decl)
+ && (INTEGRAL_TYPE_P (TREE_TYPE (rhs))
+ || POINTER_TYPE_P (TREE_TYPE (rhs))))
+ return incr;
+ else if (TREE_CODE (rhs) == MINUS_EXPR
+ && TREE_OPERAND (rhs, 0) == decl
+ && INTEGRAL_TYPE_P (TREE_TYPE (rhs)))
+ return incr;
+ // Otherwise fail because only PLUS_EXPR and MINUS_EXPR are
+ // allowed.
+ break;
+ }
+
+ /* We encounter CALL_EXPR in C++ when we have a case like this:
+ operator+= (&ii, 1); */
+ case CALL_EXPR:
+ {
+ enum tree_code code = cilk_find_code_from_call (CALL_EXPR_FN (incr));
+ if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR
+ || code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
+ {
+ tree val = CALL_EXPR_ARG (incr, 0);
+ if (TREE_CODE (val) == ADDR_EXPR
+ || TREE_CODE (val) == INDIRECT_REF)
+ val = TREE_OPERAND (val, 0);
+ if (val != decl)
+ break;
+ return incr;
+ }
+ for (int ii = 0; ii < call_expr_nargs (incr); ii++)
+ {
+ tree val = CALL_EXPR_ARG (incr, ii);
+ if (TREE_CODE (val) == ADDR_EXPR)
+ val = TREE_OPERAND (val, 0);
+ if (val == decl)
+ continue;
+ else
+ {
+ tree rhs = val;
+ if (TREE_CODE (rhs) == INTEGER_CST)
+ return orig_incr;
+ if ((TREE_CODE (rhs) == PLUS_EXPR
+ || TREE_CODE (rhs) == POINTER_PLUS_EXPR)
+ && (TREE_OPERAND (rhs, 0) == decl
+ || TREE_OPERAND (rhs, 1) == decl)
+ && (INTEGRAL_TYPE_P (TREE_TYPE (rhs))
+ || POINTER_TYPE_P (TREE_TYPE (rhs))))
+ return orig_incr;
+ else if (TREE_CODE (rhs) == MINUS_EXPR
+ && TREE_OPERAND (rhs, 0) == decl
+ && INTEGRAL_TYPE_P (TREE_TYPE (rhs)))
+ return orig_incr;
+ }
+ }
+ }
+
+ default:
+ break;
+ }
+
+ error_at (loc, "invalid increment expression");
+ return error_mark_node;
+}
+
+/* Callback for walk_tree to validate the body of a pragma simd loop
+ or _cilk_for loop.
+
+ This function is passed in as a function pointer to walk_tree. *TP is
+ the current tree pointer, *WALK_SUBTREES is set to 0 by this function if
+ recursing into TP's subtrees is unnecessary. *DATA is a bool variable that
+ is set to false if an error has occured. */
+
+tree
+c_validate_cilk_plus_loop (tree *tp, int *walk_subtrees, void *data)
+{
+ if (!tp || !*tp)
+ return NULL_TREE;
+
+ bool *valid = (bool *) data;
+
+ switch (TREE_CODE (*tp))
+ {
+ case CALL_EXPR:
+ {
+ tree fndecl = CALL_EXPR_FN (*tp);
+
+ if (TREE_CODE (fndecl) == ADDR_EXPR)
+ fndecl = TREE_OPERAND (fndecl, 0);
+ if (TREE_CODE (fndecl) == FUNCTION_DECL)
+ {
+ if (setjmp_call_p (fndecl))
+ {
+ error_at (EXPR_LOCATION (*tp),
+ "calls to setjmp are not allowed within loops "
+ "annotated with #pragma simd or _Cilk_for loops");
+ *valid = false;
+ *walk_subtrees = 0;
+ }
+ }
+ break;
+ }
+
+ case OMP_PARALLEL:
+ case OMP_TASK:
+ case OMP_FOR:
+ case OMP_SIMD:
+ case OMP_SECTIONS:
+ case OMP_SINGLE:
+ case OMP_SECTION:
+ case OMP_MASTER:
+ case OMP_ORDERED:
+ case OMP_CRITICAL:
+ case OMP_ATOMIC:
+ case OMP_ATOMIC_READ:
+ case OMP_ATOMIC_CAPTURE_OLD:
+ case OMP_ATOMIC_CAPTURE_NEW:
+ error_at (EXPR_LOCATION (*tp), "OpenMP statements are not allowed "
+ "within loops annotated with #pragma simd");
+ *valid = false;
+ *walk_subtrees = 0;
+ break;
+
+ default:
+ break;
+ }
+ return NULL_TREE;
+}
+
+/* Validate the body of a _Cilk_for construct or a <#pragma simd> for
+ loop.
+
+ Returns true if there were no errors, false otherwise. */
+
+static bool
+c_check_cilk_loop_body (tree body)
+{
+ bool valid = true;
+ walk_tree (&body, c_validate_cilk_plus_loop, (void *) &valid, NULL);
+ return valid;
+}
+
+/* Validate a _Cilk_for construct (or a #pragma simd for loop, which
+ has the same syntactic restrictions).
+
+ Returns TRUE if there were no errors, FALSE otherwise.
+
+ LOC is the location of the for.
+ DECL is the controlling variable.
+ COND is the condition.
+
+ INCRP is a pointer the increment expression (in case the increment
+ needs to be canonicalized).
+
+ BODY is the body of the LOOP.
+ SCAN_BODY is true if the body must be checked. */
+
+static bool
+c_check_cilk_for_loop (location_t loc, tree decl, tree cond, tree *incrp,
+ tree body, bool scan_body, bool is_cpp,
+ bool proc_templates_p)
+{
+ tree incr = *incrp;
+
+ if (TREE_THIS_VOLATILE (decl))
+ {
+ error_at (loc, "iteration variable cannot be volatile");
+ return false;
+ }
+ if (TREE_STATIC (decl))
+ {
+ error_at (loc, "induction variable cannot be static");
+ return false;
+ }
+ if (DECL_REGISTER (decl))
+ {
+ error_at (loc, "induction variable cannot be declared register");
+ return false;
+ }
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (decl))
+ && !POINTER_TYPE_P (TREE_TYPE (decl)))
+ {
+ /* In C++ iterators are allowed. */
+ if (!is_cpp)
+ {
+ error_at (loc, "induction variable must be of integral "
+ "or pointer type (have %qT)", TREE_TYPE (decl));
+ return false;
+ }
+ /* If we are processing templates then these checks are done
+ in pt.c. */
+ else if (!proc_templates_p
+ && TREE_CODE (TREE_TYPE (decl)) != RECORD_TYPE)
+ {
+ error_at (loc, "induction variable must be of integral "
+ "record or pointer type (have %qT)", TREE_TYPE (decl));
+ return false;
+ }
+ }
+
+ /* Validate the condition. */
+ if (!cond)
+ {
+ error_at (loc, "missing condition");
+ return false;
+ }
+ bool cond_ok = false;
+ if (TREE_CODE (cond) == NE_EXPR
+ || TREE_CODE (cond) == CALL_EXPR
+ || TREE_CODE (cond) == LT_EXPR
+ || TREE_CODE (cond) == LE_EXPR
+ || TREE_CODE (cond) == GT_EXPR
+ || TREE_CODE (cond) == GE_EXPR)
+ {
+ /* Comparison must either be:
+ DECL <comparison_operator> EXPR
+ EXPR <comparison_operator> DECL
+ */
+ if (decl == cilk_simplify_tree (TREE_OPERAND (cond, 0)))
+ cond_ok = true;
+ else if (decl == cilk_simplify_tree (TREE_OPERAND (cond, 1)))
+ {
+ /* Canonicalize the comparison so the DECL is on the LHS. */
+ TREE_SET_CODE (cond,
+ swap_tree_comparison (TREE_CODE (cond)));
+ TREE_OPERAND (cond, 1) = TREE_OPERAND (cond, 0);
+ TREE_OPERAND (cond, 0) = decl;
+ cond_ok = true;
+ }
+ }
+
+ /* In C++ you can have cases like this: x < 5
+ where '<' is overloaded and so it is translated like this:
+ operator< (x, 5), and this is acceptable. */
+ cond = cilk_simplify_tree (cond);
+ if (!cond_ok && is_cpp && TREE_CODE (cond) == CALL_EXPR)
+ {
+ if (call_expr_nargs (cond) < 2)
+ cond_ok = false;
+ for (int ii = 0; ii < call_expr_nargs (cond); ii++)
+ {
+ tree val = cilk_simplify_tree (CALL_EXPR_ARG (cond, ii));
+ if (TREE_CODE (val) == ADDR_EXPR)
+ val = TREE_OPERAND (val, 0);
+ else if (TREE_CODE (val) == TARGET_EXPR)
+ val = TARGET_EXPR_INITIAL (val);
+ if (decl == val)
+ {
+ cond_ok = true;
+ break;
+ }
+ }
+ }
+ if (!cond_ok)
+ {
+ error_at (loc, "invalid controlling predicate");
+ return false;
+ }
+
+ /* Validate and canonicalize the increment. */
+ incr = c_check_cilk_loop_incr (loc, decl, incr);
+ if (incr == error_mark_node)
+ return false;
+ *incrp = incr;
+
+ if (scan_body && !c_check_cilk_loop_body (body))
+ return false;
+
+ return true;
+}
+
+/* Validate and emit code for the _Cilk_for loop
+
+ LOC is the location of the location of the _Cilk_for.
+ DECL is the iteration variable.
+ INIT is the initialization expression.
+ COND is the controlling predicate.
+ INCR is the increment expression.
+ BODY is the body of the loop.
+ SCAN_BODY is true if the body of the loop must be verified.
+
+ Returns the generated statement. */
+
+tree
+c_finish_cilk_for_loop (location_t loc, tree decl, tree init, tree cond,
+ tree incr, tree body, tree grain, bool is_cpp,
+ bool proc_templates_p)
+{
+ if (!c_check_cilk_for_loop (loc, decl, cond, &incr, body, true, is_cpp,
+ proc_templates_p))
+ return NULL;
+
+ /* In the case for "_Cilk_for (int i = 0...)", init will be a decl. It
+ should have a DECL_INITIAL that we can turn into an assignment. */
+ if (init == decl)
+ {
+ location_t rhs_loc = DECL_SOURCE_LOCATION (decl);
+ init = DECL_INITIAL (decl);
+ if (!init)
+ {
+ error_at (rhs_loc, "%qE is not initialized", decl);
+ init = integer_zero_node;
+ return NULL;
+ }
+ init = build2 (INIT_EXPR, TREE_TYPE (decl), decl, init);
+ DECL_INITIAL (decl) = NULL;
+ }
+
+ tree t = make_node (CILK_FOR_STMT);
+ TREE_TYPE (t) = void_type_node;
+
+ init = build2 (INIT_EXPR, TREE_TYPE (decl), decl, init);
+ CILK_FOR_INIT (t) = init;
+ CILK_FOR_COND (t) = cond;
+ CILK_FOR_EXPR (t) = incr;
+ CILK_FOR_BODY (t) = body;
+ CILK_FOR_SCOPE (t) = NULL_TREE;
+ CILK_FOR_VAR (t) = decl;
+ CILK_FOR_GRAIN (t) = grain;
+
+ SET_EXPR_LOCATION (t, loc);
+ return add_stmt (t);
+}
+
+/* Similar to c_finish_cilk_for_loop, but don't actually create the
+ CILK_FOR_STMT tree ad return it. *CILK_FOR_STMT is the CILK_FOR_STMT
+ tree and proc_templates_p is set if we are processing templates. */
+
+void
+cp_finish_cilk_for_loop (tree *cilk_for_stmt, bool proc_templates_p)
+{
+ tree cfor = *cilk_for_stmt;
+ tree incr = CILK_FOR_EXPR (cfor);
+ if (!c_check_cilk_for_loop (EXPR_LOCATION (cfor), CILK_FOR_VAR (cfor),
+ CILK_FOR_COND (cfor), &incr,
+ CILK_FOR_BODY (cfor), true, true,
+ proc_templates_p))
+ *cilk_for_stmt = error_mark_node;
+ else
+ CILK_FOR_EXPR (*cilk_for_stmt) = incr;
+}
+
@@ -416,6 +416,7 @@ const struct c_common_resword c_common_reswords[] =
{ "_Complex", RID_COMPLEX, 0 },
{ "_Cilk_spawn", RID_CILK_SPAWN, 0 },
{ "_Cilk_sync", RID_CILK_SYNC, 0 },
+ { "_Cilk_for", RID_CILK_FOR, 0 },
{ "_Imaginary", RID_IMAGINARY, D_CONLY },
{ "_Decimal32", RID_DFLOAT32, D_CONLY | D_EXT },
{ "_Decimal64", RID_DFLOAT64, D_CONLY | D_EXT },
old mode 100644
new mode 100755
@@ -149,7 +149,7 @@ enum rid
RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
/* Cilk Plus keywords. */
- RID_CILK_SPAWN, RID_CILK_SYNC,
+ RID_CILK_SPAWN, RID_CILK_SYNC, RID_CILK_FOR,
/* Objective-C ("AT" reserved words - they are only keywords when
they follow '@') */
@@ -524,6 +524,14 @@ struct GTY(()) c_language_function {
#define building_stmt_list_p() (stmt_list_stack && !stmt_list_stack->is_empty())
+/* In c-cilkplus.c */
+extern void cp_finish_cilk_for_loop (tree *, bool);
+extern tree c_validate_cilk_plus_loop (tree *, int *, void *);
+extern bool c_check_cilk_loop (location_t, tree);
+extern tree c_finish_cilk_for_loop (location_t, tree, tree, tree, tree, tree,
+ tree, bool, bool);
+
/* Language-specific hooks. */
/* If non-NULL, this function is called after a precompile header file
@@ -1292,7 +1300,6 @@ extern enum stv_conv scalar_to_vector (location_t loc, enum tree_code code,
/* In c-cilkplus.c */
extern tree c_finish_cilk_clauses (tree);
extern tree c_validate_cilk_plus_loop (tree *, int *, void *);
-extern bool c_check_cilk_loop (location_t, tree);
/* These #defines allow users to access different operands of the
array notation tree. */
@@ -1377,5 +1384,31 @@ extern tree build_cilk_spawn (location_t, tree);
extern tree make_cilk_frame (tree);
extern tree create_cilk_function_exit (tree, bool, bool);
extern tree cilk_install_body_pedigree_operations (tree);
-
+extern void cilk_init_cfd (struct cilk_for_desc *);
+extern void cilk_extract_free_variables (tree, struct wrapper_data *, int);
+extern tree cilk_create_cilk_helper_decl (struct wrapper_data *);
+extern void cilk_call_graph_add_fn (tree);
+extern void cilk_outline_body (tree, tree *, struct wrapper_data *, bool *);
+extern tree cilk_check_loop_difference_type (tree);
+extern void declare_cilk_for_parms (struct cilk_for_desc *);
+extern void declare_cilk_for_vars (struct cilk_for_desc *, tree);
+extern tree cilk_loop_convert (tree, tree);
+extern tree cilk_divide_count (tree, enum tree_code, tree, bool, tree);
+extern void cilk_calc_forward_div_op (struct cilk_for_desc *, enum tree_code *,
+ tree *);
+extern tree cilk_compute_loop_count (struct cilk_for_desc *, enum tree_code,
+ tree, tree, tree);
+extern gimple_seq insert_cilk_for_nested_fn (struct cilk_for_desc *, tree,
+ tree);
+extern tree cilk_compute_loop_var (struct cilk_for_desc *, tree, tree,
+ tree (*)(location_t, enum tree_code, tree,
+ tree, tree));
+extern void cilk_set_inclusive_and_direction (struct cilk_for_desc *);
+extern void cilk_set_iter_difftype (struct cilk_for_desc *);
+extern void cilk_set_incr_info (struct cilk_for_desc *, bool);
+extern void cilk_set_init_info (struct cilk_for_desc *);
+extern tree cilk_simplify_tree (tree);
+extern enum tree_code cilk_find_code_from_call (tree);
+extern tree cilk_tree_operand_noconv (tree);
+extern tree cilk_resolve_continue_stmts (tree *, int *, void *);
#endif /* ! GCC_C_COMMON_H */
@@ -1390,6 +1390,11 @@ init_pragma (void)
cpp_register_deferred_pragma (parse_in, "GCC", "ivdep", PRAGMA_IVDEP, false,
false);
+
+ if (flag_enable_cilkplus && !flag_preprocess_only)
+ cpp_register_deferred_pragma (parse_in, "cilk", "grainsize",
+ PRAGMA_CILK_GRAINSIZE, true, false);
+
#ifdef HANDLE_PRAGMA_PACK_WITH_EXPANSION
c_register_pragma_with_expansion (0, "pack", handle_pragma_pack);
#else
@@ -55,6 +55,9 @@ typedef enum pragma_kind {
/* Top level clause to handle all Cilk Plus pragma simd clauses. */
PRAGMA_CILK_SIMD,
+ /* This pragma handles setting of grainsize for a _Cilk_for. */
+ PRAGMA_CILK_GRAINSIZE,
+
PRAGMA_GCC_PCH_PREPROCESS,
PRAGMA_IVDEP,
old mode 100644
new mode 100755
@@ -35,47 +35,6 @@ along with GCC; see the file COPYING3. If not see
#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
@@ -156,8 +115,8 @@ pop_cfun_to (tree outer)
/* This function does whatever is necessary to make the compiler emit a newly
generated function, FNDECL. */
-static void
-call_graph_add_fn (tree fndecl)
+void
+cilk_call_graph_add_fn (tree fndecl)
{
const tree outer = current_function_decl;
struct function *f = DECL_STRUCT_FUNCTION (fndecl);
@@ -283,8 +242,8 @@ cilk_detect_spawn_and_unwrap (tree *exp0)
/* This function will build and return a FUNCTION_DECL using information
from *WD. */
-static tree
-create_cilk_helper_decl (struct wrapper_data *wd)
+tree
+cilk_create_cilk_helper_decl (struct wrapper_data *wd)
{
char name[20];
if (wd->type == CILK_BLOCK_FOR)
@@ -452,6 +411,8 @@ for_local_cb (const void *k_v, void **vp, void *p)
tree k = *(tree *) &k_v;
tree v = (tree) *vp;
+ if (k == v)
+ return true;
if (v == error_mark_node)
*vp = copy_decl_no_change (k, (copy_body_data *) p);
return true;
@@ -472,15 +433,18 @@ wrapper_local_cb (const void *k_v, void **vp, void *data)
return true;
}
-/* Alter a tree STMT from OUTER_FN to form the body of INNER_FN. */
+/* Alter a tree STMT from OUTER_FN to form the body of INNER_FN. THR is set
+ to true if the original function has exception enabled (only applicable for
+ C++ Cilk_for nested function). This value is evaluated and then
+ passed back into cp_function_tree->can_throw. */
-static void
-cilk_outline (tree inner_fn, tree *stmt_p, struct wrapper_data *wd)
+void
+cilk_outline_body (tree inner_fn, tree *stmt_p, struct wrapper_data *wd,
+ bool *thr)
{
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;
@@ -496,7 +460,7 @@ cilk_outline (tree inner_fn, tree *stmt_p, struct wrapper_data *wd)
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.block = 0;
id.transform_lang_insert_block = NULL;
id.transform_new_cfg = true;
@@ -515,8 +479,10 @@ cilk_outline (tree inner_fn, tree *stmt_p, struct wrapper_data *wd)
/* 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 ;
+ bool throws = thr ? *thr : false;
(void) walk_tree_without_duplicates (stmt_p, check_outlined_calls, &throws);
+ if (thr)
+ *thr = throws;
}
/* Generate the body of a wrapper function that assigns the
@@ -538,7 +504,7 @@ create_cilk_wrapper_body (tree stmt, struct wrapper_data *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);
+ fndecl = cilk_create_cilk_helper_decl (wd);
push_struct_function (fndecl);
if (wd->nested && (wd->type == CILK_BLOCK_FOR))
{
@@ -551,7 +517,7 @@ create_cilk_wrapper_body (tree stmt, struct wrapper_data *wd)
for (p = wd->parms; p; p = TREE_CHAIN (p))
DECL_CONTEXT (p) = fndecl;
- cilk_outline (fndecl, &stmt, wd);
+ cilk_outline_body (fndecl, &stmt, wd, NULL);
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);
@@ -560,7 +526,7 @@ create_cilk_wrapper_body (tree stmt, struct wrapper_data *wd)
pop_cfun_to (outer);
/* Recognize the new function. */
- call_graph_add_fn (fndecl);
+ cilk_call_graph_add_fn (fndecl);
return fndecl;
}
@@ -702,14 +668,14 @@ create_cilk_wrapper (tree exp, tree *args_out)
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);
+ cilk_extract_free_variables (TREE_OPERAND (exp, 0), &wd, ADD_WRITE);
+ cilk_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);
+ cilk_extract_free_variables (TREE_TYPE (exp), &wd, ADD_READ);
}
else
- extract_free_variables (exp, &wd, ADD_READ);
+ cilk_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)
@@ -996,14 +962,14 @@ add_variable (struct wrapper_data *wd, tree var, enum add_variable_type how)
/* 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
+ another. HOW_T 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)
+void
+cilk_extract_free_variables (tree t, struct wrapper_data *wd, int how_t)
{
+ enum add_variable_type how = (enum add_variable_type) how_t;
if (t == NULL_TREE)
return;
@@ -1011,7 +977,7 @@ extract_free_variables (tree t, struct wrapper_data *wd,
bool is_expr = IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code));
if (is_expr)
- extract_free_variables (TREE_TYPE (t), wd, ADD_READ);
+ cilk_extract_free_variables (TREE_TYPE (t), wd, ADD_READ);
switch (code)
{
@@ -1031,7 +997,7 @@ extract_free_variables (tree t, struct wrapper_data *wd,
case SSA_NAME:
/* Currently we don't see SSA_NAME. */
- extract_free_variables (SSA_NAME_VAR (t), wd, how);
+ cilk_extract_free_variables (SSA_NAME_VAR (t), wd, how);
return;
case LABEL_DECL:
@@ -1053,12 +1019,12 @@ extract_free_variables (tree t, struct wrapper_data *wd,
case NON_LVALUE_EXPR:
case CONVERT_EXPR:
case NOP_EXPR:
- extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_READ);
+ cilk_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);
+ cilk_extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_BIND);
+ cilk_extract_free_variables (TREE_OPERAND (t, 1), wd, ADD_READ);
return;
case MODIFY_EXPR:
@@ -1067,8 +1033,8 @@ extract_free_variables (tree t, struct wrapper_data *wd,
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);
+ cilk_extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_WRITE);
+ cilk_extract_free_variables (TREE_OPERAND (t, 1), wd, ADD_READ);
return;
case ADDR_EXPR:
@@ -1079,9 +1045,9 @@ extract_free_variables (tree t, struct wrapper_data *wd,
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);
+ cilk_extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_READ);
else
- extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_WRITE);
+ cilk_extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_WRITE);
return;
case ARRAY_REF:
@@ -1093,17 +1059,17 @@ extract_free_variables (tree t, struct wrapper_data *wd,
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);
+ cilk_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);
+ cilk_extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_READ);
+ cilk_extract_free_variables (TREE_OPERAND (t, 1), wd, ADD_READ);
+ cilk_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);
+ cilk_extract_free_variables (TREE_PURPOSE (t), wd, ADD_READ);
+ cilk_extract_free_variables (TREE_VALUE (t), wd, ADD_READ);
+ cilk_extract_free_variables (TREE_CHAIN (t), wd, ADD_READ);
return;
case TREE_VEC:
@@ -1111,7 +1077,7 @@ extract_free_variables (tree t, struct wrapper_data *wd,
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);
+ cilk_extract_free_variables (TREE_VEC_ELT (t, i), wd, ADD_READ);
return;
}
@@ -1119,13 +1085,13 @@ extract_free_variables (tree t, struct wrapper_data *wd,
{
unsigned ii = 0;
for (ii = 0; ii < VECTOR_CST_NELTS (t); ii++)
- extract_free_variables (VECTOR_CST_ELT (t, ii), wd, ADD_READ);
+ cilk_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);
+ cilk_extract_free_variables (TREE_REALPART (t), wd, ADD_READ);
+ cilk_extract_free_variables (TREE_IMAGPART (t), wd, ADD_READ);
return;
case BIND_EXPR:
@@ -1136,11 +1102,11 @@ extract_free_variables (tree t, struct wrapper_data *wd,
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);
+ cilk_extract_free_variables (DECL_INITIAL (decl), wd, ADD_READ);
+ cilk_extract_free_variables (DECL_SIZE (decl), wd, ADD_READ);
+ cilk_extract_free_variables (DECL_SIZE_UNIT (decl), wd, ADD_READ);
}
- extract_free_variables (BIND_EXPR_BODY (t), wd, ADD_READ);
+ cilk_extract_free_variables (BIND_EXPR_BODY (t), wd, ADD_READ);
return;
}
@@ -1148,17 +1114,17 @@ extract_free_variables (tree t, struct wrapper_data *wd,
{
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);
+ cilk_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);
+ cilk_extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_BIND);
+ cilk_extract_free_variables (TREE_OPERAND (t, 1), wd, ADD_READ);
+ cilk_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);
+ cilk_extract_free_variables (TREE_OPERAND (t, 3), wd, ADD_READ);
return;
}
@@ -1172,32 +1138,32 @@ extract_free_variables (tree t, struct wrapper_data *wd,
case DECL_EXPR:
if (TREE_CODE (DECL_EXPR_DECL (t)) != TYPE_DECL)
- extract_free_variables (DECL_EXPR_DECL (t), wd, ADD_BIND);
+ cilk_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);
+ cilk_extract_free_variables (TYPE_MIN_VALUE (t), wd, ADD_READ);
+ cilk_extract_free_variables (TYPE_MAX_VALUE (t), wd, ADD_READ);
return;
case POINTER_TYPE:
- extract_free_variables (TREE_TYPE (t), wd, ADD_READ);
+ cilk_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);
+ cilk_extract_free_variables (TREE_TYPE (t), wd, ADD_READ);
+ cilk_extract_free_variables (TYPE_DOMAIN (t), wd, ADD_READ);
return;
case RECORD_TYPE:
- extract_free_variables (TYPE_FIELDS (t), wd, ADD_READ);
+ cilk_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);
+ cilk_extract_free_variables (TYPE_ARG_TYPES (t), wd, ADD_READ);
+ cilk_extract_free_variables (TYPE_METHOD_BASETYPE (t), wd, ADD_READ);
return;
case AGGR_INIT_EXPR:
@@ -1210,8 +1176,8 @@ extract_free_variables (tree t, struct wrapper_data *wd,
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);
+ cilk_extract_free_variables (TREE_OPERAND (t, ii), wd, ADD_READ);
+ cilk_extract_free_variables (TREE_TYPE (t), wd, ADD_READ);
}
break;
}
@@ -1227,7 +1193,7 @@ extract_free_variables (tree t, struct wrapper_data *wd,
/* 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);
+ cilk_extract_free_variables (TREE_OPERAND (t, i), wd, ADD_READ);
}
}
}
@@ -1304,3 +1270,872 @@ build_cilk_sync (void)
TREE_SIDE_EFFECTS (sync) = 1;
return sync;
}
+
+/* Zeros out all the fields in CFD. */
+
+void
+cilk_init_cfd (struct cilk_for_desc *cfd)
+{
+ memset (cfd, 0, sizeof *cfd);
+ init_wd (&cfd->wd, CILK_BLOCK_FOR);
+}
+
+/* Returns a CALL_EXPR based on the TYPE_PRECISON of COUNT_TYPE. */
+
+static tree
+find_cilk_for_library_fn (tree count_type)
+{
+ if (TYPE_PRECISION (count_type) == 32)
+ return cilk_for_32_fndecl;
+ else if (TYPE_PRECISION (count_type) == 64)
+ return cilk_for_64_fndecl;
+ else
+ gcc_unreachable ();
+}
+
+/* This function finds the direction INCR, the increment expression, of the
+ loop: Return 0 if the sign of INCR_DIRECTION is unknown,
+ +1 if the value is exactly +1,
+ +2 if the value is known to be positive, and
+ -2 if the value is known to be negative. */
+
+static int
+cilk_compute_incr_direction (tree incr)
+{
+ if (TREE_CODE (incr) != INTEGER_CST)
+ return tree_expr_nonnegative_p (incr) ? 2 : 0;
+ else if (integer_onep (incr))
+ return 1;
+ else
+ return 2 * tree_int_cst_sgn (incr);
+}
+
+/* Return the count type based on TYPE of a Cilk for loop, or unsigned long if
+ there is no acceptable type. */
+
+tree
+cilk_check_loop_difference_type (tree type)
+{
+ if ((TYPE_PRECISION (type) > TYPE_PRECISION (long_unsigned_type_node))
+ || (TYPE_MAIN_VARIANT (type) == long_long_integer_type_node)
+ || (TYPE_MAIN_VARIANT (type) == long_long_unsigned_type_node))
+ return long_long_unsigned_type_node;
+
+ return long_unsigned_type_node;
+}
+
+/* Removes unwanted wrappers from a tree, T. */
+
+tree
+cilk_simplify_tree (tree t)
+{
+ extern tree tree_ssa_strip_useless_type_conversions (tree);
+
+ if (TREE_CODE (t) == CLEANUP_POINT_EXPR)
+ t = TREE_OPERAND (t, 0);
+ if (TREE_CODE (t) == NOP_EXPR)
+ t = TREE_OPERAND (t, 0);
+ if ((TREE_CODE (t) == CONVERT_EXPR) && (VOID_TYPE_P (TREE_TYPE (t)) != 0))
+ t = TREE_OPERAND (t, 0);
+
+ STRIP_USELESS_TYPE_CONVERSION (t);
+
+ return t;
+}
+
+/* Set up the variable mapping for the FNDECL and install parameters after
+ declaring the function and scanning the loop body's variable use.
+ Information about the _Cilk_for statement is stored in *CFD. */
+
+void
+declare_cilk_for_vars (struct cilk_for_desc *cfd, tree fndecl)
+{
+ tree var2 = build_decl (cfd->loc, VAR_DECL, DECL_NAME (cfd->var),
+ cfd->var_type);
+ DECL_CONTEXT (var2) = fndecl;
+ cfd->var2 = var2;
+
+ void **mapped = pointer_map_contains (cfd->wd.decl_map, cfd->var);
+ /* The loop control variable must be mapped. */
+ gcc_assert (mapped);
+ const_tree t = (const_tree) *mapped;
+
+ /* The loop control variable may appear as mapped to itself
+ or mapped to integer_one_node depending on its type and
+ how it was modified. */
+ if ((TREE_CODE (t) != INTEGER_CST) || (t == integer_one_node))
+ {
+ tree save_function = current_function_decl;
+ current_function_decl = DECL_CONTEXT (cfd->var);
+ warning (0, "loop body modifies control variable %qD", cfd->var);
+ current_function_decl = save_function;
+ }
+ *mapped = (void *) var2;
+
+ tree p = cfd->wd.parms;
+ DECL_ARGUMENTS (fndecl) = p;
+ do
+ {
+ DECL_CONTEXT (p) = fndecl;
+ p = TREE_CHAIN (p);
+ }
+ while (p);
+}
+
+/* Set up the signature and parameters of the _Cilk_for body function
+ before declaring the function using information stored in CFD. */
+
+void
+declare_cilk_for_parms (struct cilk_for_desc *cfd)
+{
+ tree count_type = cfd->count_type;
+ tree ro_count = build_qualified_type (count_type, TYPE_QUAL_CONST);
+ tree ctx = build_decl (cfd->loc, PARM_DECL, NULL_TREE, ptr_type_node);
+ tree t1 = get_identifier ("__low");
+ tree min_parm = build_decl (cfd->loc, PARM_DECL, t1, ro_count);
+ tree t2 = get_identifier ("__high");
+ tree max_parm = build_decl (cfd->loc, PARM_DECL, t2, ro_count);
+
+ DECL_ARG_TYPE (max_parm) = count_type;
+ DECL_ARTIFICIAL (max_parm) = 1;
+ TREE_READONLY (max_parm) = 1;
+
+ DECL_ARG_TYPE (min_parm) = count_type;
+ DECL_ARTIFICIAL (min_parm) = 1;
+ TREE_READONLY (min_parm) = 1;
+
+ DECL_ARG_TYPE (ctx) = ptr_type_node;
+ DECL_ARTIFICIAL (ctx) = 1;
+ TREE_READONLY (ctx) = 1;
+
+ TREE_CHAIN (min_parm) = max_parm;
+ TREE_CHAIN (ctx) = min_parm;
+
+ tree types = tree_cons (NULL_TREE, TREE_TYPE (max_parm), void_list_node);
+ types = tree_cons (NULL_TREE, TREE_TYPE (min_parm), types);
+ types = tree_cons (NULL_TREE, TREE_TYPE (ctx), types);
+
+ cfd->min_parm = min_parm;
+ cfd->max_parm = max_parm;
+ cfd->wd.argtypes = types;
+ cfd->wd.arglist = NULL_TREE;
+ cfd->wd.parms = ctx;
+}
+
+/* Convert a loop, EXP, to the way required by _Cilk_for and sets it type as
+ indicated by TYPE. */
+
+tree
+cilk_loop_convert (tree type, tree exp)
+{
+ enum tree_code code;
+ int inprec, outprec;
+ if (type == TREE_TYPE (exp))
+ return exp;
+ inprec = TYPE_PRECISION (TREE_TYPE (exp));
+ outprec = TYPE_PRECISION (type);
+ if (outprec > inprec && !TYPE_UNSIGNED (TREE_TYPE (exp)))
+ code = CONVERT_EXPR;
+ else
+ code = NOP_EXPR;
+ return fold_build1 (code, type, exp);
+}
+
+/* Returns the number of times a loop is divided. */
+
+tree
+cilk_divide_count (tree count, enum tree_code op, tree incr, bool negate,
+ tree type)
+{
+ tree dtype;
+
+ if (!count)
+ return NULL_TREE;
+
+ tree ctype = TREE_TYPE (count);
+ tree itype = TREE_TYPE (incr);
+
+ if (op == NOP_EXPR && !negate)
+ return cilk_loop_convert (type, count);
+ /* Return -(unsigned) count instead of (unsigned)-count in case the negate
+ overflows. */
+ if (op == NOP_EXPR && negate)
+ return fold_build1 (NEGATE_EXPR, type, cilk_loop_convert (type, count));
+
+ /* We are dividing two positive values or else the user has invoked
+ undefined behavior. That means we can divide in a common narrow
+ type and widen after. This does not work if we must negate signed
+ INCR to get a positive value because we could be negating INT_MIN. */
+
+ if (ctype != itype || (negate && !TYPE_UNSIGNED (itype)))
+ {
+ incr = cilk_loop_convert (type, incr);
+ count = cilk_loop_convert (type, count);
+ dtype = type;
+ }
+ else
+ dtype = ctype;
+
+ if (negate)
+ incr = fold_build1 (NEGATE_EXPR, TREE_TYPE (incr), incr);
+
+ count = fold_build2 (op, dtype, count, incr);
+ if (dtype != type)
+ count = cilk_loop_convert (type, count);
+
+ return count;
+}
+
+/* Sets *DIV_OP to the appropriate operation to divide the loop and
+ the *FORWARD tree with condition expression based on DIRECTION, INCR_SIGN
+ and EXACTLY_ONE. */
+
+void
+cilk_calc_forward_div_op (struct cilk_for_desc *cfd, enum tree_code *div_op,
+ tree *forward)
+{
+ switch (cfd->direction)
+ {
+ case -2:
+ *forward = boolean_false_node;
+ *div_op = CEIL_DIV_EXPR;
+ break;
+ case -1:
+ *forward = boolean_false_node;
+ *div_op = EXACT_DIV_EXPR;
+ break;
+ case 0:
+ *forward = build2 (cfd->incr_sign > 0 ? GE_EXPR : LT_EXPR,
+ boolean_type_node, cfd->incr, integer_zero_node);
+ /* Loops with indeterminate direction use != and are always exact. */
+ *div_op = EXACT_DIV_EXPR;
+ break;
+ case 1:
+ *forward = boolean_true_node;
+ *div_op = EXACT_DIV_EXPR;
+ break;
+ case 2:
+ *forward = boolean_true_node;
+ *div_op = CEIL_DIV_EXPR;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ if (cfd->exactly_one)
+ *div_op = NOP_EXPR;
+}
+
+/* Returns the loop-count based on the _Cilk_for loop's characteristics given
+ in *CFD. DIV_OP indicates whether we have exact division or a CEILING
+ operation need to be performed. COUNT_UP and COUNT_DOWN are not
+ NULL_TREE if the increment and decrement operation are done using an
+ iterator. */
+
+tree
+cilk_compute_loop_count (struct cilk_for_desc *cfd, enum tree_code div_op,
+ tree forward, tree count_up, tree count_down)
+{
+ /* if initial value is not given, the use the variable since it holds the
+ lower value. */
+ tree low = cfd->lower_bound ? cfd->lower_bound : cfd->var;
+
+ /* Same logic as low for high variable. */
+ tree high = cfd->end_var ? cfd->end_var : cfd->end_expr;
+
+ if (low == error_mark_node || high == error_mark_node)
+ {
+ gcc_assert (errorcount || sorrycount);
+ return error_mark_node;
+ }
+
+ /* If either count_up or count_down are not NULL, then it is an indication
+ that we have an interator for loop computation, so we check if
+ cfd->iterator is set to true. */
+ if (count_up != NULL_TREE || count_down != NULL_TREE)
+ gcc_assert (cfd->iterator);
+ else
+ {
+ tree low_type = TREE_TYPE (low);
+ tree high_type = TREE_TYPE (high);
+ tree sub_type = NULL_TREE;
+
+ if (TREE_CODE (TREE_TYPE (cfd->var)) == POINTER_TYPE)
+ sub_type = ptrdiff_type_node;
+ else
+ {
+ /* We need to compute HIGH - LOW or LOW - HIGH without overflow. */
+ sub_type = common_type (low_type, high_type);
+
+ /* If subtracting two signed vars. without widening then convert them
+ to unsigned. */
+ if (!TYPE_UNSIGNED (sub_type)
+ && (TYPE_PRECISION (sub_type) == TYPE_PRECISION (low_type)
+ || TYPE_PRECISION (sub_type) == TYPE_PRECISION (high_type)))
+ sub_type = unsigned_type_for (sub_type);
+ }
+ if (low_type != sub_type)
+ low = convert (sub_type, low);
+ if (high_type != sub_type)
+ high = convert (sub_type, high);
+
+ if (cfd->direction <= 0)
+ count_down = fold_build2 (MINUS_EXPR, sub_type, low, high);
+ if (cfd->direction >= 0)
+ count_up = fold_build2 (MINUS_EXPR, sub_type, high, low);
+ }
+
+ /* if the loop is not exact add one before dividing. Otherwise add 1 after
+ dividing. Assumed that it can't overflow (meaning that loop range cannot
+ exceed the range of the loop variable or difference type). */
+ if (cfd->inclusive && div_op == CEIL_DIV_EXPR)
+ {
+ if (count_up)
+ count_up = fold_build2 (PLUS_EXPR, TREE_TYPE (count_up), count_up,
+ build_one_cst (TREE_TYPE (count_up)));
+ if (count_down)
+ count_down = fold_build2 (PLUS_EXPR, TREE_TYPE (count_down), count_down,
+ build_one_cst (TREE_TYPE (count_down)));
+ }
+
+ /* Serial semantics: INCR is converted to the common type of VAR and INCR then
+ the result is converted to the type of VAR. */
+ tree incr = cfd->incr;
+ if (!cfd->iterator && TREE_CODE (TREE_TYPE (cfd->var)) != POINTER_TYPE)
+ incr = cilk_loop_convert (common_type (TREE_TYPE (cfd->var),
+ TREE_TYPE (incr)), incr);
+
+ /* Now separately divide each count by +/- INCR yielding a value with type
+ TYPE. */
+ count_up = cilk_divide_count (count_up, div_op, incr, cfd->incr_sign < 0,
+ cfd->count_type);
+ count_down = cilk_divide_count (count_down, div_op, incr, cfd->incr_sign > 0,
+ cfd->count_type);
+ /* Merge forward and backward counts. */
+ tree count = NULL_TREE;
+ if (!count_up)
+ count = count_down;
+ else if (!count_down)
+ count = count_up;
+ else
+ count = fold_build3 (COND_EXPR, cfd->count_type, forward, count_up,
+ count_down);
+
+ /* Add one, maybe. */
+ if (cfd->inclusive && div_op != CEIL_DIV_EXPR)
+ count = fold_build2 (PLUS_EXPR, cfd->count_type, count,
+ build_one_cst (cfd->count_type));
+
+ return count;
+}
+
+/* Returns a GIMPLE_SEQ that contains a call to the Cilk library function and
+ the necessary temporary variables. COUNT and FN are parameters to the
+ library function indicating the loop-count and nested function,
+ respectively. */
+
+gimple_seq
+insert_cilk_for_nested_fn (struct cilk_for_desc *cfd, tree count, tree fn)
+{
+ /* INNER_SEQ contains evaluation of variables holding loop increment and
+ count. These are evaluated inside the loop guard. */
+ gimple_seq inner_seq = 0;
+ if (!TREE_CONSTANT (count))
+ {
+ count = fold_build_cleanup_point_expr (TREE_TYPE (count), count);
+ count = get_formal_tmp_var (count, &inner_seq);
+ }
+
+ if (TREE_SIDE_EFFECTS (cfd->incr))
+ cfd->incr = get_formal_tmp_var (cfd->incr, &inner_seq);
+
+ tree libfun = find_cilk_for_library_fn (cfd->count_type);
+ tree ctx = cfd->ctx_arg;
+ if (ctx)
+ {
+ if (TREE_TYPE (ctx) != ptr_type_node)
+ ctx = fold_build1 (NOP_EXPR, ptr_type_node, ctx);
+ if (!DECL_P (ctx))
+ ctx = get_formal_tmp_var (ctx, &inner_seq);
+ }
+ else
+ {
+ ctx = fold_build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
+ ctx = get_formal_tmp_var (ctx, &inner_seq);
+ }
+ fn = fold_build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
+ TREE_CONSTANT (fn) = 1;
+ fn = get_formal_tmp_var (fn, &inner_seq);
+
+ tree grain = cfd->grain;
+ tree tmv_count_type = TYPE_MAIN_VARIANT (cfd->count_type);
+ if (!grain)
+ grain = get_formal_tmp_var (build_zero_cst (cfd->count_type), &inner_seq);
+ else if (TYPE_MAIN_VARIANT (TREE_TYPE (grain)) != tmv_count_type)
+ grain = convert (cfd->count_type, grain);
+
+ tree libfun_call = build_call_expr (libfun, 4, fn, ctx, count, grain);
+ gimplify_and_add (libfun_call, &inner_seq);
+ return inner_seq;
+}
+
+/* The loop function looks like
+
+ body (void *, unsigned long max, unsigned long min)
+ const T start = [outer_context] var;
+ T var';
+ for (unsigned long i = min; i < max; i++) {
+ var' = start + (T) i * (T) incr;
+ body (var');
+ }
+
+ COMPUTE_LOOP_VAR returns an expression for
+ var' = start + i * incr;
+ or
+ var' = start - i * decr;
+ with suitable type conversions.
+
+ If direction is known we know the sign of INCR (or else it's
+ undefined behavior) and we can work with positive unsigned
+ numbers until the last addition or subtraction.
+
+ If direction is not known then the increment and loop variable
+ are signed but the product of the loop count and increment may
+ not be representable as a signed value.
+
+ We can't do the last addition or subtraction in C without
+ a conditional operation because the conversion of unsigned
+ to signed is undefined for "negative" values of the unsigned
+ number. For now we just pretend this isn't a problem. We
+ may fail on targets with signed overflow.
+
+ For iterator loops we require that the difference type have
+ enough range and simply pass the value to operator+ or operator-
+ based on the static direction of the loop. Iterator loop case is
+ handled by the function passed in a function pointer, *ITER_HANDLER.
+
+ LOOP_VAR has type COUNT_TYPE. */
+
+tree
+cilk_compute_loop_var (struct cilk_for_desc *cfd, tree loop_var,
+ tree lower_bound,
+ tree (*iter_handler) (location_t, enum tree_code,
+ tree, tree, tree))
+{
+ tree count_type = NULL_TREE;
+ if (INTEGRAL_TYPE_P (TREE_TYPE (loop_var)))
+ count_type = TREE_TYPE (loop_var);
+ else
+ count_type = cfd->count_type;
+
+ /* Compute an expression to be added or subtracted.
+
+ We want to add or subtract LOOP_VAR * INCR. INCR may be negative.
+ If the static direction is indeterminate we don't know that at
+ compile time. The code to convert to unsigned and multiply does
+ the right thing in the end. For iterator loops we don't need to
+ go to that trouble, but scalar loops can have range that can not
+ be represented in the signed loop variable. */
+ tree scaled = NULL_TREE, incr = NULL_TREE;
+ if (integer_onep (cfd->incr))
+ scaled = loop_var;
+ else
+ {
+ incr = cilk_loop_convert (count_type, cfd->incr);
+ scaled = fold_build2 (MULT_EXPR, count_type, loop_var, incr);
+ }
+
+ enum tree_code add_op = cfd->incr_sign >= 0 ? PLUS_EXPR : MINUS_EXPR;
+ if (cfd->iterator)
+ {
+ /* Convert LOOP_VAR to T3 (difference_type) so that
+ operator+(T1, T3) is preferred over operator+(T1, count_type)
+ operator+ constructs the object if it returns by value.
+ Use operator- if the user wrote -=. */
+ if (count_type != cfd->difference_type)
+ loop_var = convert (cfd->difference_type, scaled);
+ tree low = lower_bound ? lower_bound : cfd->var;
+ if (TREE_CODE (low) == TREE_LIST)
+ low = TREE_VALUE (low);
+ tree exp = iter_handler (cfd->loc, add_op, low, loop_var, cfd->var2);
+ return exp;
+ }
+ /* The scaled count may not be representable in the type of the
+ loop variable, e.g. if the loop range is INT_MIN+1 to INT_MAX-1
+ the range does not fit in a signed int. The sum of the lower
+ bound and the count is representable. Do the addition or
+ subtraction in the wider type, then narrow. */
+ tree cvt_val = cilk_loop_convert (count_type, lower_bound);
+ tree adjusted = fold_build2 (add_op, count_type, cvt_val, scaled);
+ tree exp = fold_build2 (MODIFY_EXPR, void_type_node, cfd->var2,
+ cilk_loop_convert (cfd->var_type, adjusted));
+ return exp;
+}
+
+/* Remove NOP_EXPR, ADDR_EXPR and INDIRECT_REF wrappers from EXP and
+ return. */
+
+tree
+cilk_tree_operand_noconv (tree exp)
+{
+ tree op = exp;
+ while (TREE_CODE (op) == NOP_EXPR
+ || TREE_CODE (op) == ADDR_EXPR
+ || TREE_CODE (op) == INDIRECT_REF)
+ op = TREE_OPERAND (op, 0);
+ return op;
+}
+
+/* Return the TREE_CODE for an overloaded function call, FN_CALL. */
+
+enum tree_code
+cilk_find_code_from_call (tree fn_call)
+{
+ /* Unwrap the ADDR_EXPR layer. */
+ tree call = TREE_OPERAND (fn_call, 0);
+ call = DECL_NAME (call);
+ const char *name = IDENTIFIER_POINTER (call);
+ char op_name[2];
+ op_name[1] = name[strlen (name) - 1];
+ if (name [strlen (name) - 2] != 'r')
+ op_name[0] = name [strlen (name) - 2];
+ else
+ op_name[0] = ' ';
+
+ if (op_name[1] == '<')
+ return LT_EXPR;
+ else if (op_name[1] == '>')
+ return GT_EXPR;
+ else if (op_name[1] == '=')
+ {
+ if (op_name[0] == '<')
+ return LE_EXPR;
+ else if (op_name[0] == '>')
+ return GE_EXPR;
+ else if (op_name[0] == '!')
+ return NE_EXPR;
+ else if (op_name[0] == '=')
+ return EQ_EXPR;
+ else if (op_name[0] == '+')
+ return PLUS_EXPR;
+ else if (op_name[0] == '-')
+ return MINUS_EXPR;
+ else
+ gcc_unreachable ();
+ }
+ else if (op_name[1] == '+' && op_name[0] == '+')
+ /* This could be post or pre increment expression, but for our case
+ it really does not matter. */
+ return POSTINCREMENT_EXPR;
+ else if (op_name[1] == '-' && op_name[0] == '-')
+ /* Same reasoning as above for decrement expression. */
+ return POSTDECREMENT_EXPR;
+ else
+ gcc_unreachable ();
+ return NOP_EXPR;
+}
+
+/* Extracts the initial value of the initalizer for a CILK_FOR_STMT. This
+ information is stored in CFD->LOWER_BOUND. */
+
+void
+cilk_set_init_info (struct cilk_for_desc *cfd)
+{
+ if (!cfd->lower_bound)
+ return;
+ else if (TREE_CODE (cfd->lower_bound) == MODIFY_EXPR
+ || TREE_CODE (cfd->lower_bound) == INIT_EXPR)
+ {
+ tree op0 = TREE_OPERAND (cfd->lower_bound, 0);
+ tree op1 = TREE_OPERAND (cfd->lower_bound, 1);
+
+ gcc_assert (op0 == cfd->var);
+ cfd->lower_bound = op1;
+ }
+}
+
+/* Sets the CFD->INCLUSIVE, CFD->END_EXPR and CFD->DIRECTION based on the
+ characteristics of the Cilk for statement. */
+
+void
+cilk_set_inclusive_and_direction (struct cilk_for_desc *cfd)
+{
+ tree cond = cfd->cond;
+ enum tree_code cond_code = TREE_CODE (cond);
+ if (cond_code == CALL_EXPR)
+ cond_code = cilk_find_code_from_call (CALL_EXPR_FN (cond));
+
+ switch (cond_code)
+ {
+ case NE_EXPR:
+ cfd->inclusive = false;
+ cfd->direction = 0;
+ break;
+ case GE_EXPR:
+ cfd->inclusive = true;
+ cfd->direction = -2;
+ break;
+ case GT_EXPR:
+ cfd->inclusive = false;
+ cfd->direction = -2;
+ break;
+ case LE_EXPR:
+ cfd->inclusive = true;
+ cfd->direction = 2;
+ break;
+ case LT_EXPR:
+ cfd->inclusive = false;
+ cfd->direction = 2;
+ break;
+ default:
+ /* == is not allowed. */
+ gcc_unreachable ();
+ }
+ tree limit = NULL_TREE;
+ tree arg0, arg1;
+
+ if (TREE_CODE (cond) == CALL_EXPR)
+ {
+ arg0 = CALL_EXPR_ARG (cond, 0);
+ arg1 = CALL_EXPR_ARG (cond, 1);
+ }
+ else
+ {
+ arg0 = TREE_OPERAND (cond, 0);
+ arg1 = TREE_OPERAND (cond, 1);
+ }
+
+ if (cilk_tree_operand_noconv (arg0) == cfd->var)
+ limit = arg1;
+ else
+ {
+ /* If we are here, then we have a case like this: 10 > ii; */
+ limit = arg0;
+ cfd->direction = -cfd->direction;
+ }
+
+ cfd->end_expr = limit;
+}
+
+/* Sets CFD->ITERATOR and CFD->DIFFERENCE_TYPE based on the characteristics of
+ the _Cilk_for statement. */
+
+void
+cilk_set_iter_difftype (struct cilk_for_desc *cfd)
+{
+ tree var_type = TREE_TYPE (cfd->var);
+ gcc_assert (var_type);
+
+ switch (TREE_CODE (var_type))
+ {
+ case POINTER_TYPE:
+ cfd->iterator = false;
+ cfd->difference_type = ptrdiff_type_node;
+ break;
+ case ENUMERAL_TYPE:
+ case BOOLEAN_TYPE:
+ case INTEGER_TYPE:
+ cfd->iterator = false;
+ cfd->difference_type = lang_hooks.types.type_promotes_to (var_type);
+ break;
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ cfd->iterator = true;
+ cfd->difference_type = NULL; /* This will be set later for C++. */
+ break;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Populate CFD with characteristics of the increment expression. If
+ HANDLE_PTR_MULT is set, then increment is multiplied by the size of
+ pointer. This is necessary for C++ but not for C. */
+
+void
+cilk_set_incr_info (struct cilk_for_desc *cfd, bool handle_ptr_mult)
+{
+ int negate_incr = 0, incr_direction = 0;
+
+ cfd->incr = cilk_simplify_tree (cfd->incr);
+ enum tree_code inc_op = TREE_CODE (cfd->incr);
+ bool is_incr = false;
+ tree op0, op1;
+ tree incr;
+ if (inc_op == ADDR_EXPR || inc_op == CALL_EXPR || inc_op == INDIRECT_REF)
+ /* This indicates that the increment operation is overloaded. */
+ incr = cilk_tree_operand_noconv (cfd->incr);
+ else if (inc_op == TARGET_EXPR)
+ incr = TARGET_EXPR_INITIAL (cfd->incr);
+ else
+ incr = cfd->incr;
+
+ if (TREE_CODE (incr) == CALL_EXPR)
+ {
+ inc_op = cilk_find_code_from_call (CALL_EXPR_FN (incr));
+ if (inc_op == PLUS_EXPR || inc_op == MINUS_EXPR)
+ {
+ op1 = CALL_EXPR_ARG (incr, 1);
+ op0 = cilk_tree_operand_noconv (CALL_EXPR_ARG (incr, 0));
+ inc_op = (inc_op == PLUS_EXPR ? PREINCREMENT_EXPR
+ : PREDECREMENT_EXPR);
+ }
+ else if (inc_op == POSTINCREMENT_EXPR || inc_op == POSTDECREMENT_EXPR
+ || inc_op == PREDECREMENT_EXPR || inc_op == PREINCREMENT_EXPR)
+ op1 = integer_one_node;
+ else
+ op1 = CALL_EXPR_ARG (incr, 0);
+ }
+ else
+ op1 = TREE_OPERAND (cfd->incr, 1);
+
+ is_incr = (inc_op == PREINCREMENT_EXPR || inc_op == POSTINCREMENT_EXPR);
+ switch (inc_op)
+ {
+ case POSTDECREMENT_EXPR:
+ case PREDECREMENT_EXPR:
+ case PREINCREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ negate_incr = is_incr ? false : true;
+ incr_direction = is_incr ? -1 : 1;
+ cfd->incr = op1;
+ if (!cfd->incr)
+ {
+ tree var_type = TREE_TYPE (cfd->var);
+ if (TREE_CODE (var_type) == POINTER_TYPE)
+ cfd->incr = size_in_bytes (TREE_TYPE (var_type));
+ else
+ cfd->incr = integer_one_node;
+ }
+ cfd->exactly_one = integer_onep (cfd->incr);
+ break;
+ case MODIFY_EXPR:
+ {
+ /* In here the expressions will have the form var <MODIFY_OP> incr or
+ op = op <OPERATION> incr. */
+ cfd->incr = (TREE_CODE (cfd->incr) != MODIFY_EXPR ? op1
+ : TREE_OPERAND (cfd->incr, 1));
+ enum tree_code increment_code = TREE_CODE (cfd->incr);
+ if (increment_code == PLUS_EXPR || increment_code == POINTER_PLUS_EXPR)
+ {
+ op0 = TREE_OPERAND (cfd->incr, 0);
+ op1 = TREE_OPERAND (cfd->incr, 1);
+
+ if (op0 == cfd->var || DECL_NAME (op0) == DECL_NAME (cfd->var))
+ cfd->incr = op1;
+ else if (op1 == cfd->var || DECL_NAME (op1) == DECL_NAME (cfd->var))
+ cfd->incr = op0;
+ else
+ gcc_unreachable ();
+
+ negate_incr = false;
+ incr_direction = cilk_compute_incr_direction (cfd->incr);
+
+ /* Adding a negative number treated as unsigned is like adding a
+ large positive number. */
+ if (TYPE_UNSIGNED (cfd->difference_type) && incr_direction < 0)
+ incr_direction = 2;
+ cfd->exactly_one = (incr_direction == 1);
+
+ /* Don't need to do this in POINTER_PLUS_EXPR since it already
+ does this for you. */
+ if (handle_ptr_mult && increment_code != POINTER_PLUS_EXPR)
+ {
+ tree var_type = TREE_TYPE (cfd->var);
+ if (TREE_CODE (var_type) == POINTER_TYPE)
+ {
+ tree size = size_in_bytes (TREE_TYPE (var_type));
+ if (!integer_onep (size))
+ {
+ cfd->exactly_one = 0;
+ /* For example, in the following _Cilk_for statement:
+ _Cilk_for (int *p = a, p < b; p += (char)c)
+ We need to do the match in a type wider than c.
+ "build_binary_op" will do the default conversions
+ which should be enough if SIZE is size_t. */
+ cfd->incr = build_binary_op (cfd->loc, MULT_EXPR,
+ cfd->incr, size, 0);
+ }
+ }
+ }
+ }
+ else if (TREE_CODE (cfd->incr) == MINUS_EXPR)
+ {
+ op1 = TREE_OPERAND (cfd->incr, 1);
+ op0 = TREE_OPERAND (cfd->incr, 0);
+
+ gcc_assert (op0 == cfd->var
+ || DECL_NAME (op0) == DECL_NAME (cfd->var));
+ cfd->incr = op1;
+ negate_incr = true;
+ incr_direction = -cilk_compute_incr_direction (cfd->incr);
+
+ /* Subtracting a negative number is treated as adding a
+ positive. */
+ if (TYPE_UNSIGNED (cfd->difference_type) && incr_direction > 0)
+ incr_direction = -2;
+ cfd->exactly_one = (incr_direction == -1);
+
+ /* In C++ we need to handle the pointer arithmetic manually, but
+ in C it seem to automatically figure this out. */
+ if (handle_ptr_mult)
+ {
+ tree var_type = TREE_TYPE (cfd->var);
+ if (TREE_CODE (var_type) == POINTER_TYPE)
+ {
+ tree size = size_in_bytes (TREE_TYPE (var_type));
+ if (!integer_onep (size))
+ {
+ cfd->exactly_one = 0;
+ /* For example, in the following _Cilk_for statement:
+ _Cilk_for (int *p = a, p < b; p += (char)c)
+ We need to do the match in a type wider than c.
+ "build_binary_op" will do the default conversions
+ which should be enough if SIZE is size_t. */
+ cfd->incr = build_binary_op (cfd->loc, MULT_EXPR,
+ cfd->incr, size, 0);
+ }
+ }
+ }
+ }
+ else
+ {
+ location_t incr_loc = EXPR_LOCATION (cfd->incr);
+ error_at (incr_loc, "invalid loop increment operation");
+ cfd->invalid = true;
+ return;
+ }
+ }
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ cfd->var_type = TREE_TYPE (cfd->var);
+ cfd->incr_sign = negate_incr ? -1 : 1;
+}
+
+/* Helper function for walk_tree. Fixes up all the continues inside a
+ _Cilk_for body. */
+
+tree
+cilk_resolve_continue_stmts (tree *tp, int *walk_subtrees, void *data)
+{
+ tree goto_label = NULL_TREE, goto_stmt = NULL_TREE;
+ if (!tp || !*tp)
+ return NULL_TREE;
+
+ if (TREE_CODE (*tp) == CONTINUE_STMT)
+ {
+ goto_label = (tree) data;
+ goto_stmt = build1 (GOTO_EXPR, void_type_node, goto_label);
+ *tp = goto_stmt;
+ *walk_subtrees = 0;
+ }
+ else if (TREE_CODE (*tp) == FOR_STMT || TREE_CODE (*tp) == WHILE_STMT
+ || TREE_CODE (*tp) == DO_STMT || TREE_CODE (*tp) == CILK_FOR_STMT)
+ /* Inside these statements, the continue goes to a different place not
+ end of cilk_for. You do not want to go into these trees because we
+ will resolve those later. */
+ *walk_subtrees = 0;
+
+ return NULL_TREE;
+}
@@ -51,7 +51,7 @@ CFLAGS-c/gccspec.o += $(DRIVER_DEFINES)
# Language-specific object files for C and Objective C.
C_AND_OBJC_OBJS = attribs.o c/c-errors.o c/c-decl.o c/c-typeck.o \
c/c-convert.o c/c-aux-info.o c/c-objc-common.o c/c-parser.o \
- c/c-array-notation.o $(C_COMMON_OBJS) $(C_TARGET_OBJS)
+ c/c-array-notation.o c/c-cilk.o $(C_COMMON_OBJS) $(C_TARGET_OBJS)
# Language-specific object files for C.
C_OBJS = c/c-lang.o c-family/stub-objc.o $(C_AND_OBJC_OBJS)
new file mode 100755
@@ -0,0 +1,359 @@
+/* This file is part of the Intel (R) Cilk (TM) Plus support
+ This file contains the functions required to handle _Cilk_for
+ for the C language.
+ 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 "c-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"
+#include "gimplify.h"
+
+/* Get a block for the CILK_FOR_STMT, CFOR. */
+
+static tree
+block_cilk_for_loop (tree cfor)
+{
+ tree block = tree_block (cfor);
+ if (block)
+ return block;
+ return DECL_INITIAL (current_function_decl);
+}
+
+/* Create or discover the variable to be used in the loop termination
+ condition. Return true if the cfd->end_var should be used in the
+ guard test around the runtime call. Otherwise the guard test uses
+ the complex expression, which in C++ may initialize the variable.
+
+ For example, if END_EXPR is
+
+ (target_expr limit (call constructor ...))
+
+ the variable limit is not initialized until the target_expr is
+ evaluated. */
+
+static bool
+cilk_for_end (struct cilk_for_desc *cfd, gimple_seq *pre_p)
+{
+ tree end = cfd->end_expr;
+ if (TREE_SIDE_EFFECTS (end))
+ {
+ enum tree_code ecode = TREE_CODE (end);
+ if (ecode == INIT_EXPR || ecode == MODIFY_EXPR || ecode == TARGET_EXPR)
+ {
+ cfd->end_var = TREE_OPERAND (end, 0);
+ return false;
+ }
+ else
+ {
+ /* Copy the result of evaluating the expression into a variable.
+ The compiler will probably crash if there's anything
+ complicated in it -- a complicated value needs to go through
+ the other branch of this IF using an explicit temporary. */
+ cfd->end_var = get_formal_tmp_var (end, pre_p);
+ return true;
+ }
+ }
+ cfd->end_var = end;
+ return false;
+}
+
+/* Handler for iterator to compute the loop variable. LOW indicates the
+ starting point and LOOP_VAR is the induction variable, and VAR2 is the
+ original induction variable in the Cilk_for. Returns an expression
+ (or a STATEMENT_LIST of expressions). */
+
+static tree
+compute_loop_var_c_iter_hdl (location_t loc, enum tree_code add_op, tree low,
+ tree loop_var, tree var2)
+{
+ tree exp = fold_build2 (add_op, TREE_TYPE (loop_var), low, loop_var);
+ gcc_assert (exp != error_mark_node);
+
+ exp = build_modify_expr (loc, var2, TREE_TYPE (var2), INIT_EXPR, loc, exp,
+ TREE_TYPE (exp));
+ gcc_assert (exp != error_mark_node);
+ return exp;
+}
+
+
+/* Creates a body of the _Cilk_for wrapper function with the information
+ in *CFD. */
+
+static tree
+create_cilk_for_body (struct cilk_for_desc *cfd)
+{
+ declare_cilk_for_parms (cfd);
+ cfd->wd.fntype = build_function_type (void_type_node, cfd->wd.argtypes);
+ tree fndecl = cilk_create_cilk_helper_decl (&cfd->wd);
+
+ tree outer = current_function_decl;
+ push_struct_function (fndecl);
+ current_function_decl = fndecl;
+
+ declare_cilk_for_vars (cfd, fndecl);
+
+ tree body = push_stmt_list ();
+ tree mod_expr = NULL_TREE, loop_var = NULL_TREE;
+ tree lower_bound = cfd->lower_bound;
+ if (!lower_bound)
+ {
+ lower_bound = cfd->var;
+ tree hack = build_decl (EXPR_LOCATION (cfd->var), VAR_DECL, NULL_TREE,
+ TREE_TYPE (lower_bound));
+ DECL_CONTEXT (hack) = DECL_CONTEXT (lower_bound);
+ DECL_NAME (hack) = DECL_NAME (lower_bound);
+ *pointer_map_insert (cfd->wd.decl_map, hack) = lower_bound;
+ lower_bound = hack;
+ }
+ if (INTEGRAL_TYPE_P (cfd->var_type))
+ {
+ tree new_min_parm = fold_build1 (CONVERT_EXPR, cfd->var_type,
+ cfd->min_parm);
+ loop_var = create_tmp_var (cfd->var_type, NULL);
+ location_t loc = EXPR_LOCATION (cfd->var);
+ mod_expr = build_modify_expr (loc, loop_var, cfd->var_type, NOP_EXPR,
+ loc, new_min_parm, cfd->var_type);
+ }
+ else
+ {
+ loop_var = create_tmp_var (TREE_TYPE (cfd->min_parm), NULL);
+ mod_expr = fold_build2 (INIT_EXPR, void_type_node, loop_var,
+ cfd->min_parm);
+ }
+ add_stmt (mod_expr);
+ tree loop_body = NULL_TREE;
+ tree new_max_parm = NULL_TREE;
+
+ if (!INTEGRAL_TYPE_P (cfd->var_type))
+ new_max_parm = cfd->max_parm;
+ else
+ new_max_parm = fold_build1 (CONVERT_EXPR, cfd->var_type, cfd->max_parm);
+
+ tree end_comp = cilk_compute_loop_var (cfd, loop_var, lower_bound,
+ compute_loop_var_c_iter_hdl);
+ append_to_statement_list (end_comp, &loop_body);
+ append_to_statement_list (cfd->body, &loop_body);
+ loop_body = fold_build_cleanup_point_expr (void_type_node, loop_body);
+ DECL_SEEN_IN_BIND_EXPR_P (cfd->var2) = 1;
+
+ cilk_outline_body (fndecl, &loop_body, &cfd->wd, NULL);
+
+ tree loop = push_stmt_list ();
+ /* Now create a loop with c_finish_loop. */
+ tree incr = fold_build2 (PLUS_EXPR, TREE_TYPE (loop_var), loop_var,
+ build_one_cst (TREE_TYPE (loop_var)));
+ incr = fold_build2 (MODIFY_EXPR, void_type_node, loop_var, incr);
+ tree cond = fold_build2 (LT_EXPR, boolean_type_node, loop_var, new_max_parm);
+ c_finish_loop (EXPR_LOCATION (cfd->var), cond, incr, loop_body, NULL_TREE,
+ NULL_TREE, false);
+ loop = pop_stmt_list (loop);
+ add_stmt (loop);
+ body = pop_stmt_list (body);
+
+ tree block = DECL_INITIAL (fndecl);
+ BLOCK_VARS (block) = loop_var;
+ body = build3 (BIND_EXPR, void_type_node, loop_var, body, block);
+ TREE_CHAIN (loop_var) = cfd->var2;
+ if (cilk_detect_spawn_and_unwrap (&body))
+ lang_hooks.cilkplus.install_body_with_frame_cleanup (fndecl, body);
+ else
+ DECL_SAVED_TREE (fndecl) = body;
+
+ pop_cfun ();
+ current_function_decl = outer;
+ return fndecl;
+}
+
+/* Creates a wrapper function for the body of a _Cilk_for statement with the
+ information stored in *CFD. */
+
+static tree
+create_cilk_for_wrapper (struct cilk_for_desc *cfd)
+{
+ tree old_cfd = current_function_decl;
+ tree incr = cfd->incr;
+ tree var = cfd->var;
+
+ if (POINTER_TYPE_P (TREE_TYPE (var)))
+ cilk_extract_free_variables (cfd->lower_bound, &cfd->wd, ADD_WRITE);
+ else
+ cilk_extract_free_variables (cfd->lower_bound, &cfd->wd, ADD_READ);
+
+ cilk_extract_free_variables (incr, &cfd->wd, ADD_READ);
+
+ /* Map the loop variable to integer_minus_one_node if we won't really
+ be passing it to the loop body and integer_zero_node otherwise.
+
+ If the map ends up integer_one_node then somebody wrote to the loop
+ variable and that's a user error.
+ The correct map will be installed in declare_for_loop_variables. */
+ *pointer_map_insert (cfd->wd.decl_map, var) =
+ (void *) (cfd->lower_bound ? integer_minus_one_node : integer_zero_node);
+
+ /* Note that variables are not extracted from the loop condition
+ and increment. They are evaluated, to the extent they are
+ evaluated, in the context containing the for loop. */
+ cilk_extract_free_variables (cfd->body, &cfd->wd, ADD_READ);
+
+ tree fn = create_cilk_for_body (cfd);
+ DECL_UNINLINABLE (fn) = 1;
+ current_function_decl = old_cfd;
+ set_cfun (DECL_STRUCT_FUNCTION (current_function_decl));
+ cfun->is_cilk_function = 1;
+
+ /* Add the new function to the cgraph list. */
+ cilk_call_graph_add_fn (fn);
+ return fn;
+}
+
+/* Helper function for gimplify_cilk_for. *CFD contains all the relevant
+ information extracted from a _Cilk_for statement passed into the parent
+ function gimplify_cilk_for. */
+
+void
+gimplify_cilk_for_1 (struct cilk_for_desc *cfd, gimple_seq *pre_p)
+{
+ /* We don't have to evaluate INCR only once, but we do have
+ to evaluate it no more times than in the serial loop.
+ The naive method evaluates INCR exactly that many times
+ except if the static loop direction is indeterminate.
+
+ Storing the increment in a variable is thus mandatory
+ if cfd.direction == 0. It is an optimization otherwise
+ and there seems no harm and some benefit in doing it.
+
+ The evaluation is on the inner statement list. The
+ increment can not be referenced prior to the loop test. */
+ if (TREE_SIDE_EFFECTS (cfd->incr))
+ sorry ("_Cilk_for increment with side effects");
+
+ tree cond = cfd->cond;
+ tree op0 = TREE_OPERAND (cond, 0);
+ tree op1 = TREE_OPERAND (cond, 1);
+ if (!cilk_for_end (cfd, pre_p) && cfd->end_var != cfd->end_expr)
+ {
+ if (op1 == cfd->end_expr)
+ op1 = cfd->end_var;
+ else
+ op0 = cfd->end_var;
+ }
+ cond = fold_build2 (TREE_CODE (cond), boolean_type_node, op0, op1);
+
+ tree forward = NULL_TREE;
+
+ /* This is set to NOP_EXPR to have an initial value since we are passing in
+ an address to the function below. */
+ enum tree_code div_op = NOP_EXPR;
+
+ cilk_calc_forward_div_op (cfd, &div_op, &forward);
+
+ tree count = cilk_compute_loop_count (cfd, div_op, forward, NULL_TREE,
+ NULL_TREE);
+ tree fn = create_cilk_for_wrapper (cfd);
+
+ /* Set condition correctly, so that the function below can use it. */
+ cfd->cond = cond;
+ gimple_seq inner_seq = insert_cilk_for_nested_fn (cfd, count, fn);
+ gimple_seq_add_seq (pre_p, inner_seq);
+}
+
+/* Extracts all the relevant information from CFOR, a CILK_FOR_STMT tree and
+ stores them in CFD structure. */
+
+static void
+c_extract_cilk_for_fields (struct cilk_for_desc *cfd, tree cfor)
+{
+ cfd->var = CILK_FOR_VAR (cfor);
+ cfd->cond = CILK_FOR_COND (cfor);
+ cfd->lower_bound = CILK_FOR_INIT (cfor);
+ cfd->incr = CILK_FOR_EXPR (cfor);
+ cfd->loc = EXPR_LOCATION (cfor);
+ cfd->body = CILK_FOR_BODY (cfor);
+ cfd->grain = CILK_FOR_GRAIN (cfor);
+ cfd->invalid = false;
+
+ /* This function shouldn't be setting these two variables. */
+ cfd->ctx_arg = NULL_TREE;
+ cfd->count = NULL_TREE;
+
+ if (TREE_CODE (cfd->lower_bound) == MODIFY_EXPR
+ || TREE_CODE (cfd->lower_bound) == INIT_EXPR)
+ {
+ tree op0 = TREE_OPERAND (cfd->lower_bound, 0);
+ tree op1 = TREE_OPERAND (cfd->lower_bound, 1);
+
+ gcc_assert (op0 == cfd->var);
+ cfd->lower_bound = op1;
+ }
+
+ cilk_set_inclusive_and_direction (cfd);
+ cilk_set_iter_difftype (cfd);
+
+ /* Difference type cannot be NULL_TREE here for C. */
+ cfd->count_type = cilk_check_loop_difference_type (cfd->difference_type);
+ if (cfd->count_type == NULL_TREE)
+ {
+ cfd->invalid = true;
+ return;
+ }
+
+ cilk_set_incr_info (cfd, false);
+}
+
+/* Main entry-point function to gimplify a cilk_for statement. *EXPR_P should
+ be a CILK_FOR_STMT tree. */
+
+int
+c_gimplify_cilk_for (tree *expr_p, gimple_seq *pre_p,
+ gimple_seq *post_p ATTRIBUTE_UNUSED)
+{
+ struct cilk_for_desc cfd;
+ tree cfor_expr = *expr_p;
+
+ cfun->is_cilk_function = 1;
+ cilk_init_cfd (&cfd);
+ cfd.wd.block = block_cilk_for_loop (cfor_expr);
+
+ c_extract_cilk_for_fields (&cfd, cfor_expr);
+
+ *expr_p = NULL_TREE;
+ if (cfd.invalid)
+ return GS_ERROR;
+
+ tree var = CILK_FOR_VAR (cfor_expr);
+ tree init = CILK_FOR_INIT (cfor_expr);
+ tree init_expr = fold_build2 (MODIFY_EXPR, void_type_node, var, init);
+
+ gimplify_and_add (init_expr, pre_p);
+ gimplify_cilk_for_1 (&cfd, pre_p);
+ return GS_ALL_DONE;
+}
@@ -114,4 +114,7 @@ along with GCC; see the file COPYING3. If not see
#undef LANG_HOOKS_CILKPLUS_DETECT_SPAWN_AND_UNWRAP
#define LANG_HOOKS_CILKPLUS_DETECT_SPAWN_AND_UNWRAP \
cilk_detect_spawn_and_unwrap
+
+#undef LANG_HOOKS_CILKPLUS_GIMPLIFY_CILK_FOR
+#define LANG_HOOKS_CILKPLUS_GIMPLIFY_CILK_FOR c_gimplify_cilk_for
#endif /* GCC_C_OBJC_COMMON */
@@ -1165,6 +1165,8 @@ static void c_parser_switch_statement (c_parser *);
static void c_parser_while_statement (c_parser *, bool);
static void c_parser_do_statement (c_parser *, bool);
static void c_parser_for_statement (c_parser *, bool);
+static void c_parser_cilk_for_statement (c_parser *, tree);
+static void c_parser_cilk_grainsize (c_parser *parser);
static tree c_parser_asm_statement (c_parser *);
static tree c_parser_asm_operands (c_parser *);
static tree c_parser_asm_goto_operands (c_parser *);
@@ -4771,6 +4773,12 @@ c_parser_statement_after_labels (c_parser *parser)
case RID_FOR:
c_parser_for_statement (parser, false);
break;
+ case RID_CILK_FOR:
+ if (!flag_enable_cilkplus)
+ error_at (loc, "-fcilkplus must be enabled to use %<_Cilk_for%>");
+ else
+ c_parser_cilk_for_statement (parser, NULL_TREE);
+ break;
case RID_CILK_SYNC:
c_parser_consume_token (parser);
c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
@@ -9381,6 +9389,24 @@ c_parser_pragma (c_parser *parser, enum pragma_context context)
c_parser_cilk_simd (parser);
return false;
+ case PRAGMA_CILK_GRAINSIZE:
+ if (!flag_enable_cilkplus)
+ {
+ warning (0, "%<#pragma grainsize%> ignored because -fcilkplus is not"
+ " enabled");
+ c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
+ return false;
+ }
+ if (context == pragma_external)
+ {
+ error_at (c_parser_peek_token (parser)->location,
+ "%<#pragma grainsize%> must be inside a function");
+ c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
+ return false;
+ }
+ c_parser_cilk_grainsize (parser);
+ return false;
+
default:
if (id < PRAGMA_FIRST_EXTERNAL)
{
@@ -13558,6 +13584,174 @@ c_parser_cilk_all_clauses (c_parser *parser)
return c_finish_cilk_clauses (clauses);
}
+/* Parses a _Cilk_for statement.
+
+ GRAIN is used to pass the Grain value from <#pragma cilk grainsize>. If
+ this field is NULL then runtime will find an appropriate grain size
+ (highly recommended!). */
+
+static void
+c_parser_cilk_for_statement (c_parser *parser, tree grain)
+{
+ tree init, decl, stmt;
+ tree body;
+ bool fail = false;
+
+ if (!c_parser_next_token_is_keyword (parser, RID_CILK_FOR))
+ {
+ c_parser_error (parser, "_Cilk_for statement expected");
+ return;
+ }
+
+ c_parser_consume_token (parser);
+ location_t loc = c_parser_peek_token (parser)->location;
+
+ tree block = c_begin_compound_stmt (true);
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ add_stmt (c_end_compound_stmt (loc, block, true));
+ return;
+ }
+
+ /* Parse the initialization declaration. */
+ if (c_parser_next_tokens_start_declaration (parser))
+ {
+ vec<c_token> none_clauses = vNULL;
+ c_token eof_token;
+ memset (&eof_token, 0, sizeof (eof_token));
+ eof_token.type = CPP_EOF;
+ none_clauses.safe_push (eof_token);
+ none_clauses.safe_push (eof_token);
+ c_parser_declaration_or_fndef (parser, true, false, false,
+ false, false, NULL, none_clauses);
+ decl = check_for_loop_decls (loc, flag_isoc99);
+ if (decl == NULL)
+ goto error_init;
+ if (DECL_INITIAL (decl) == error_mark_node)
+ decl = error_mark_node;
+ init = decl;
+ }
+ else if (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_2nd_token (parser)->type == CPP_EQ)
+ {
+ struct c_expr decl_exp;
+ struct c_expr init_exp;
+ location_t init_loc;
+
+ decl_exp = c_parser_postfix_expression (parser);
+ decl = decl_exp.value;
+
+ c_parser_require (parser, CPP_EQ, "expected %<=%>");
+
+ init_loc = c_parser_peek_token (parser)->location;
+ init_exp = c_parser_expr_no_commas (parser, NULL);
+ init_exp = default_function_array_read_conversion (init_loc,
+ init_exp);
+ init = build_modify_expr (init_loc, decl, decl_exp.original_type,
+ NOP_EXPR, init_loc, init_exp.value,
+ init_exp.original_type);
+ init = c_process_expr_stmt (init_loc, init);
+
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ }
+ else
+ {
+ error_init:
+ c_parser_error (parser, "expected induction variable initialization");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ return;
+ }
+
+ /* Parse the loop condition. */
+ tree cond = NULL_TREE;
+ if (c_parser_next_token_is_not (parser, CPP_SEMICOLON))
+ {
+ location_t cond_loc = c_parser_peek_token (parser)->location;
+ struct c_expr cond_expr = c_parser_binary_expression (parser, NULL, NULL);
+
+ cond = cond_expr.value;
+ cond = c_objc_common_truthvalue_conversion (cond_loc, cond);
+ cond = c_fully_fold (cond, false, NULL);
+ }
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+
+ /* Parse the increment expression. */
+ tree incr = NULL_TREE;
+ if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN))
+ {
+ location_t incr_loc = c_parser_peek_token (parser)->location;
+ incr = c_process_expr_stmt (incr_loc,
+ c_parser_expression (parser).value);
+ }
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+ if (decl == NULL || decl == error_mark_node || init == error_mark_node)
+ fail = true;
+
+ tree save_break = c_break_label;
+ /* Magic number to inform c_finish_bc_stmt() that we are within a
+ Cilk for construct. */
+ c_break_label = build_int_cst (size_type_node, 2);
+
+ tree save_cont = c_cont_label;
+ c_cont_label = NULL_TREE;
+ body = c_parser_c99_block_statement (parser);
+ c_break_label = save_break;
+ c_cont_label = save_cont;
+
+ if (!fail)
+ c_finish_cilk_for_loop (loc, decl, init, cond, incr, body, grain, false,
+ false);
+
+ stmt = c_end_compound_stmt (loc, block, true);
+ add_stmt (stmt);
+ c_break_label = save_break;
+ c_cont_label = save_cont;
+}
+
+/* This function helps parse the grainsize pragma for a _Cilk_for statement.
+ Here is the correct syntax of this pragma:
+ #pragma cilk grainsize = <EXP>
+ */
+
+static void
+c_parser_cilk_grainsize (c_parser *parser)
+{
+ extern tree convert_to_integer (tree, tree);
+
+ c_parser_consume_pragma (parser);
+
+ if (c_parser_require (parser, CPP_EQ, "expected %<=%>") != 0)
+ {
+ struct c_expr g_expr = c_parser_binary_expression (parser, NULL, NULL);
+ if (g_expr.value && TREE_CODE (g_expr.value) == C_MAYBE_CONST_EXPR)
+ {
+ error_at (input_location, "cannot convert grain to long integer.\n");
+ c_parser_skip_to_pragma_eol (parser);
+ }
+ else if (g_expr.value && g_expr.value != error_mark_node)
+ {
+ c_parser_skip_to_pragma_eol (parser);
+ c_token *token = c_parser_peek_token (parser);
+ if (token && token->type == CPP_KEYWORD
+ && token->keyword == RID_CILK_FOR)
+ {
+ tree grain = convert_to_integer (long_integer_type_node,
+ g_expr.value);
+ if (grain && grain != error_mark_node)
+ c_parser_cilk_for_statement (parser, grain);
+ }
+ else
+ warning (0, "grainsize pragma is not followed by %<_Cilk_for%>");
+ }
+ else
+ c_parser_skip_to_pragma_eol (parser);
+ }
+ else
+ c_parser_skip_to_pragma_eol (parser);
+}
+
/* Main entry point for parsing Cilk Plus <#pragma simd> for
loops. */
@@ -684,4 +684,7 @@ extern tree c_check_omp_declare_reduction_r (tree *, int *, void *);
extern void pedwarn_c90 (location_t, int opt, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4);
extern void pedwarn_c99 (location_t, int opt, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4);
+/* In c-cilk.c */
+extern int c_gimplify_cilk_for (tree *, gimple_seq *, gimple_seq *);
+
#endif /* ! GCC_C_TREE_H */
@@ -31,3 +31,5 @@ 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")
+DEF_CILK_BUILTIN_STUB (BUILT_IN_CILK_FOR_32, "__cilkrts_cilk_for_32")
+DEF_CILK_BUILTIN_STUB (BUILT_IN_CILK_FOR_64, "__cilkrts_cilk_for_64")
\ No newline at end of file
@@ -70,7 +70,6 @@ cilk_arrow (tree frame_ptr, int field_number, bool volatil)
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. */
@@ -105,6 +104,27 @@ install_builtin (const char *name, tree fntype, enum built_in_function code,
return fndecl;
}
+/* Returns a FUNCTION_DECL of type TYPE whose name is *NAME. */
+
+static tree
+cilk_declare_looper (const char *name, tree type, enum built_in_function code)
+{
+ tree cb, ft, fn;
+
+ cb = build_function_type_list (void_type_node,
+ ptr_type_node, type, type,
+ NULL_TREE);
+ cb = build_pointer_type (cb);
+ ft = build_function_type_list (void_type_node,
+ cb, ptr_type_node, type,
+ integer_type_node, NULL_TREE);
+ fn = install_builtin (name, ft, code, false);
+ TREE_NOTHROW (fn) = 0;
+
+ return fn;
+}
+
+
/* 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
@@ -268,6 +288,17 @@ cilk_init_builtins (void)
cilk_save_fp_fndecl = install_builtin ("__cilkrts_save_fp_ctrl_state",
fptr_fun, BUILT_IN_CILK_SAVE_FP,
false);
+
+ /* __cilkrts_cilk_for_32 (...); */
+ cilk_for_32_fndecl = cilk_declare_looper ("__cilkrts_cilk_for_32",
+ unsigned_intSI_type_node,
+ BUILT_IN_CILK_FOR_32);
+
+
+ /* __cilkrts_cilk_for_64 (...); */
+ cilk_for_64_fndecl = cilk_declare_looper ("__cilkrts_cilk_for_64",
+ unsigned_intDI_type_node,
+ BUILT_IN_CILK_FOR_64);
}
/* Get the appropriate frame arguments for CALL that is of type CALL_EXPR. */
@@ -40,6 +40,8 @@ enum cilk_tree_index {
CILK_TI_F_POP, /* __cilkrts_pop_frame (...). */
CILK_TI_F_RETHROW, /* __cilkrts_rethrow (...). */
CILK_TI_F_SAVE_FP, /* __cilkrts_save_fp_ctrl_state (...). */
+ CILK_TI_F_LOOP_32, /* __cilkrts_cilk_for_32 (...). */
+ CILK_TI_F_LOOP_64, /* __cilkrts_cilk_for_64 (...). */
/* __cilkrts_stack_frame struct fields. */
CILK_TI_FRAME_FLAGS, /* stack_frame->flags. */
CILK_TI_FRAME_PARENT, /* stack_frame->parent. */
@@ -65,6 +67,140 @@ enum cilk_tree_index {
CILK_TI_MAX
};
+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;
+};
+
+/* This structure holds all the important information necessary for decomposing
+ a cilk_for statement. */
+
+struct cilk_for_desc
+{
+ /* Location of the _Cilk_for statement. */
+ location_t loc;
+
+ /* Information about the wrapper/nested function for _Cilk_for. */
+ struct wrapper_data wd;
+
+ /* Does the loop body trigger undefined behavior at runtime? */
+ bool invalid;
+
+ /* Indicates if the parent function is a nested function (C++ only). */
+ bool nested_ok;
+
+ /* Is the loop control variable a RECORD_TYPE? */
+ bool iterator;
+
+ /* Does the loop range include its upper bound? */
+ bool inclusive;
+
+ /* Does the loop control variable, after converting pointer to
+ machine address and taking into account sizeof pointed to
+ type, increment or decrement by (plus or minus) one? */
+ bool exactly_one;
+
+ /* Is the increment stored in this structure to be added (+1)
+ or subtracted (-1)? */
+ signed char incr_sign;
+
+ /* Direction is +/-1 if the increment is known to be exactly one
+ in the user-visible units, +/-2 if the sign is known but the
+ value is not known to be one, and zero if the sign is not known
+ at compile time. */
+ signed char direction;
+
+ /* Loop upper bound. END_EXPR is the tree for the loop bound.
+ END_VAR is either END_EXPR or a VAR_DECL holding the stabilized
+ value, if computation of the value has side effects. */
+ tree end_expr, end_var;
+
+ /* The originally-declared loop control variable. */
+ tree var;
+
+ /* Lower bound of the loop if it is constant enough.
+ With a constant lower bound the loop body may not
+ need to use the static chain to compute the iterator
+ value. */
+ tree lower_bound;
+
+ /* Several types:
+
+ The declared type of the loop control variable,
+ T1 in the cilk_for spec.
+
+ The type of the loop count and argument to loop body, currently
+ always unsigned long. (If pointers are wider, we will need a
+ pointer-sized type.)
+
+ The static type of end, T2 in the cilk_for spec.
+
+ The difference type T3 of T1-T1, which is the same as T1 for
+ integral types. The difference type may not be wider than the
+ count type. For integers subtraction is done in count_type
+ in case difference_type can't hold the range.
+
+ If integral, the type of the increment is known to be no wider
+ than var_type otherwise the truncation in
+ VAR = (shorter)((longer)VAR + INCR)
+ would have been rejected. */
+ tree var_type, count_type, difference_type;
+ tree incr;
+ tree cond;
+ /* The originally-declared body of the loop. */
+ tree body;
+
+ /* Grainsize set by the user. */
+ tree grain;
+
+ /* Context argument to generated function, if not (fdesc fn 1). */
+ tree ctx_arg;
+
+ /* The number of loop iterations, in case the generated function
+ needs to know. */
+ tree count;
+
+ /* Variables of the generated function. */
+ tree ctx_parm, min_parm, max_parm;
+
+ /* Copy of the induction variable, but at different function context. */
+ tree var2;
+};
+
extern GTY (()) tree cilk_trees[CILK_TI_MAX];
#define cilk_worker_fndecl cilk_trees[CILK_TI_F_WORKER]
@@ -77,6 +213,8 @@ extern GTY (()) tree cilk_trees[CILK_TI_MAX];
#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_for_32_fndecl cilk_trees[CILK_TI_F_LOOP_32]
+#define cilk_for_64_fndecl cilk_trees[CILK_TI_F_LOOP_64]
#define cilk_worker_type_fndecl cilk_trees[CILK_TI_WORKER_TYPE]
#define cilk_frame_type_decl cilk_trees[CILK_TI_FRAME_TYPE]
@@ -90,6 +228,7 @@ 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. */
@@ -7246,6 +7246,11 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
}
break;
+ case CILK_FOR_STMT:
+ ret = (enum gimplify_status)
+ lang_hooks.cilkplus.gimplify_cilk_for (expr_p, pre_p, post_p);
+ break;
+
case CILK_SPAWN_STMT:
gcc_assert
(fn_contains_cilk_spawn_p (cfun)
@@ -219,11 +219,13 @@ 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_GIMPLIFY_CILK_FOR lhd_gimplify_expr
#define LANG_HOOKS_CILKPLUS { \
LANG_HOOKS_CILKPLUS_DETECT_SPAWN_AND_UNWRAP, \
LANG_HOOKS_CILKPLUS_FRAME_CLEANUP, \
- LANG_HOOKS_CILKPLUS_GIMPLIFY_SPAWN \
+ LANG_HOOKS_CILKPLUS_GIMPLIFY_SPAWN, \
+ LANG_HOOKS_CILKPLUS_GIMPLIFY_CILK_FOR \
}
#define LANG_HOOKS_DECLS { \
@@ -154,6 +154,11 @@ struct lang_hooks_for_cilkplus
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 *);
+
+ /* Function to gimplify a _Cilk_for statement. 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_for) (tree *, gimple_seq *, gimple_seq *);
};
/* Language hooks related to decls and the symbol table. */
new file mode 100644
@@ -0,0 +1,34 @@
+/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */
+/* { dg-options "-fcilkplus" } */
+/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */
+
+int main(int argc, char **argv)
+{
+ char Array1[26], Array2[26];
+ char Array1_Serial[26], Array2_Serial[26];
+
+ int ii = 0, error = 0;
+ for (ii = 0; ii < 26; ii++)
+ {
+ Array1[ii] = 'A'+ii;
+ Array1_Serial[ii] = 'A'+ii;
+ }
+ for (ii = 0; ii < 26; ii++)
+ {
+ Array2[ii] = 'a'+ii;
+ Array2_Serial[ii] = 'a'+ii;
+ }
+ ii = 0;
+ _Cilk_for (ii = 0 ; ii < 26; ii++)
+ Array1[ii] = Array2[ii];
+
+ for (ii = 0; ii < 26; ii++)
+ Array1_Serial[ii] = Array2_Serial[ii];
+
+ for (ii = 0; ii < 26; ii++) {
+ if (Array1_Serial[ii] != Array1[ii]) {
+ error = 1;
+ }
+ }
+ return error;
+}
new file mode 100644
@@ -0,0 +1,44 @@
+/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */
+/* { dg-options "-fcilkplus -w" } */
+/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */
+
+#define ARRAY_SIZE 1000
+
+int a[ARRAY_SIZE];
+
+int main(void)
+{
+ int i= 0;
+
+ for (i = 0; i < ARRAY_SIZE; i++)
+ a[i] = 0;
+
+ _Cilk_for (i = (ARRAY_SIZE-1); i >= 0; i--)
+ a[i] = i;
+
+ for (i = 0; i < ARRAY_SIZE; i++)
+ if (a[i] != i)
+ return 1;
+
+ for (i = 0; i < ARRAY_SIZE; i++)
+ a[i] = 0;
+
+ _Cilk_for (i = (ARRAY_SIZE-1); i >= 0; i -= 1)
+ a[i] = i;
+
+ for (i = 0; i < ARRAY_SIZE; i++)
+ if (a[i] != i)
+ return 1;
+
+ for (i = 0; i < ARRAY_SIZE; i++)
+ a[i] = 0;
+
+ _Cilk_for (i = (ARRAY_SIZE-1); i >= 0; --i)
+ a[i] = i;
+
+ for (i = 0; i < ARRAY_SIZE; i++)
+ if (a[i] != i)
+ return 1;
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,61 @@
+struct foo
+{
+ int x,y,z;
+ char q;
+};
+
+int main (void)
+{
+ int q = 0, ii = 0, jj = 0;
+ volatile int vii = 0;
+ static int sii = 0;
+ register int rii = 0;
+ extern int eii;
+ struct foo something, nothing;
+ float fii = 0;
+ _Cilk_for (ii; ii < 10; ii++) /* { dg-error " expected induction variable initialization" } */
+ q = 5;
+
+ _Cilk_for (; ii < 10; ii++) /* { dg-error "expected induction variable initialization" } */
+ q = 2;
+
+ _Cilk_for (ii = 0; ; ii++) /* { dg-error "missing condition" } */
+ q = 2;
+
+ _Cilk_for (ii = 0; ii < 10, jj < 10; ii++) /* { dg-error "expected ';' before ',' token" } */
+ q = 5;
+
+ _Cilk_for (ii = 0; ii < 10; ) /* { dg-error "missing increment" } */
+ q = 5;
+
+ _Cilk_for (ii = 0, jj = 0; ii < 10; ii++) /* { dg-error "expected ';' before ',' token" } */
+ q = 5;
+
+ _Cilk_for (vii = 0; vii < 10; vii++) /* { dg-error "iteration variable cannot be volatile" } */
+ q = 5;
+
+ _Cilk_for (sii = 0; sii < 10; sii++) /* { dg-error "induction variable cannot be static" } */
+ q = 5;
+
+ _Cilk_for (rii = 0; rii < 10; rii++) /* { dg-error "induction variable cannot be declared register" } */
+ q = 5;
+
+ _Cilk_for (something = nothing; ii < 10; ii++) /* { dg-error "induction variable must be of integral or" } */
+ q = 5;
+
+ _Cilk_for (fii = 3.47; fii < 5.23; ii++) /* { dg-error "induction variable must be of integral or pointer type" } */
+ q = 5;
+
+ _Cilk_for (ii = 0; 10 > jj; ii++) /* { dg-error "invalid controlling predicate" } */
+ q = 5;
+
+ _Cilk_for (ii = 0; ii < 10; ii >> 1) /* { dg-error "invalid increment expression" } */
+ q = 5;
+
+ _Cilk_for (ii = 10; ii >= 0; ii--) /* This is OK! */
+ q = 5;
+
+ _Cilk_for (ii; ii < 10; ii++) /* { dg-error "expected induction variable initialization" } */
+ q = 5;
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,34 @@
+/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */
+/* { dg-options "-fcilkplus -w" } */
+/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */
+
+int grain_value = 2;
+int main (void)
+{
+ int Array1[200], Array1_Serial[200];
+ int ii = 0;
+
+ for (ii = 0; ii < 200; ii++)
+ {
+ Array1_Serial[ii] = 2;
+ Array1[ii] = 1;
+ }
+
+#pragma cilk grainsize = 2
+ _Cilk_for (ii = 0; ii < 200; ii++)
+ Array1[ii] = 2;
+
+ for (ii = 0; ii < 200; ii++)
+ if (Array1[ii] != Array1_Serial[ii])
+ return (ii+1);
+
+#pragma cilk grainsize = grain_value
+ _Cilk_for (ii = 0; ii < 200; ii++)
+ Array1[ii] = 2;
+
+ for (ii = 0; ii < 200; ii++)
+ if (Array1[ii] != Array1_Serial[ii])
+ return (ii+1);
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-Wall -fcilkplus" } */
+char Array1[26];
+
+#pragma cilk grainsize = 2 /* { dg-error "must be inside a function" } */
+
+int main(int argc, char **argv)
+{
+ int ii = 0;
+
+/* This is OK. */
+#pragma cilk grainsize = 2
+ _Cilk_for (ii = 0; ii < 10; ii++)
+ Array1[ii] = 0;
+
+#pragma cilk grainsize 2 /* { dg-error "expected '=' before numeric constant" } */
+ _Cilk_for (ii = 0; ii < 10; ii++)
+ Array1[ii] = 0;
+
+#pragma cilk grainsiz = 2 /* { dg-warning "ignoring #pragma cilk grainsiz" } */
+ _Cilk_for (ii = 0; ii < 10; ii++)
+ Array1[ii] = 0;
+
+
+/* This is OK, it will do a type conversion to long int. */
+#pragma cilk grainsize = 0.5
+ _Cilk_for (ii = 0; ii < 10; ii++)
+ Array1[ii] = 0;
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,28 @@
+/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */
+/* { dg-options "-fcilkplus -w" } */
+/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */
+
+/* <feature> loop control variable must have integer, pointer or class type
+ </feature>
+*/
+
+#define ARRAY_SIZE 10000
+int a[ARRAY_SIZE];
+
+int main(void)
+{
+ int *aa = 0;
+ int ii = 0;
+
+ for (ii =0; ii < ARRAY_SIZE; ii++)
+ a[ii] = 5;
+
+ _Cilk_for(aa = a; aa < a + ARRAY_SIZE; aa++)
+ *aa = 0;
+
+ for (ii = 0; ii < ARRAY_SIZE; ii++)
+ if (a[ii] != 0)
+ return 1;
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+int main (void)
+{
+ int ii = 0, q = 2;
+ _Cilk_for (ii = 0; ii < 10; ii++) /* { dg-warning "loop body modifies control variable" } */
+ ii += q;
+
+ return 0;
+}
@@ -60,5 +60,12 @@ if { [check_effective_target_lto] } {
dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -O3 -flto -g -fcilkplus $ALWAYS_CFLAGS" " "
}
-
+dg-runtest [lsort [glob -nocomplain $srcdir/gcc.dg/cilk-plus/CK/*.c]] " -g -fcilkplus $ALWAYS_CFLAGS " " "
+dg-runtest [lsort [glob -nocomplain $srcdir/gcc.dg/cilk-plus/CK/*.c]] " -O1 -fcilkplus $ALWAYS_CFLAGS" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/gcc.dg/cilk-plus/CK/*.c]] " -O2 -std=c99 -fcilkplus $ALWAYS_CFLAGS" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/gcc.dg/cilk-plus/CK/*.c]] " -O2 -ftree-vectorize -fcilkplus $ALWAYS_CFLAGS" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/gcc.dg/cilk-plus/CK/*.c]] " -O3 -g -fcilkplus $ALWAYS_CFLAGS" " "
+if { [check_effective_target_lto] } {
+dg-runtest [lsort [glob -nocomplain $srcdir/gcc.dg/cilk-plus/CK/*.c]] " -O3 -flto -g -fcilkplus $ALWAYS_CFLAGS" " "
+}
dg-finish
@@ -2661,6 +2661,29 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
pp_string (buffer, "_Cilk_sync");
break;
+ case CILK_FOR_STMT:
+ if (CILK_FOR_GRAIN (node))
+ {
+ pp_string (buffer, "#pragma cilk grainsize = ");
+ dump_generic_node (buffer, CILK_FOR_GRAIN (node), spc, flags, false);
+ newline_and_indent (buffer, spc);
+ }
+ pp_string (buffer, "_Cilk_for (");
+ dump_generic_node (buffer, CILK_FOR_INIT (node), spc, flags, false);
+ pp_string (buffer, "; ");
+ dump_generic_node (buffer, CILK_FOR_COND (node), spc, flags, false);
+ pp_string (buffer, "; ");
+ dump_generic_node (buffer, CILK_FOR_EXPR (node), spc, flags, false);
+ pp_string (buffer, ")");
+ newline_and_indent (buffer, spc + 2);
+ pp_left_brace (buffer);
+ newline_and_indent (buffer, spc + 4);
+ dump_generic_node (buffer, CILK_FOR_BODY (node), spc + 4, flags, false);
+ newline_and_indent (buffer, spc + 2);
+ pp_right_brace (buffer);
+ is_expr = false;
+ break;
+
default:
NIY;
}
@@ -1285,6 +1285,16 @@ 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)
+/* Cilk for statement
+ Operand 0 is the initializer.
+ Operand 1 is the loop terminating condition.
+ Operand 2 is the increment/decrement expression.
+ Operand 3 is the loop-body.
+ Operand 4 is the scope.
+ Operand 5 is the induction variable.
+ Operand 6 is the grain that is passed in through a pragma. */
+DEFTREECODE (CILK_FOR_STMT, "cilk_for_stmt", tcc_statement, 7)
+
/*
Local variables:
mode:c
@@ -804,6 +804,15 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
/* Cilk keywords accessors. */
#define CILK_SPAWN_FN(NODE) TREE_OPERAND (CILK_SPAWN_STMT_CHECK (NODE), 0)
+/* CILK_FOR_STMT accessors. */
+#define CILK_FOR_INIT(NODE) TREE_OPERAND (CILK_FOR_STMT_CHECK (NODE), 0)
+#define CILK_FOR_COND(NODE) TREE_OPERAND (CILK_FOR_STMT_CHECK (NODE), 1)
+#define CILK_FOR_EXPR(NODE) TREE_OPERAND (CILK_FOR_STMT_CHECK (NODE), 2)
+#define CILK_FOR_BODY(NODE) TREE_OPERAND (CILK_FOR_STMT_CHECK (NODE), 3)
+#define CILK_FOR_SCOPE(NODE) TREE_OPERAND (CILK_FOR_STMT_CHECK (NODE), 4)
+#define CILK_FOR_VAR(NODE) TREE_OPERAND (CILK_FOR_STMT_CHECK (NODE), 5)
+#define CILK_FOR_GRAIN(NODE) TREE_OPERAND (CILK_FOR_STMT_CHECK (NODE), 6)
+
/* 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). */