diff --git a/gcc/ChangeLog.cilk b/gcc/ChangeLog.cilk index 523b7ac..d6b28e2 100644 --- a/gcc/ChangeLog.cilk +++ b/gcc/ChangeLog.cilk @@ -1,3 +1,19 @@ +2012-04-24 Balaji V. Iyer + + * elem-function.c (find_elem_fn_param_type_1): New function. + (find_elem_fn_param_type): Likewise. + (find_elem_fn_name): Likewise. + (is_elem_fn): Make it unstatic. + * tree-data-ref.c (find_data_references_in_stmt): Added support for + functions that can be made to elemental functions. + * tree-vect-stmts.c (vect_get_vec_def_for_operand): Added a check for + the parameters to see whether it is uniform, linear or neither. + (vectorizable_function): Handled code to substitute regular function + with the equivalent elemental function. + (vectorizable_call): Set the function type for substituted elemental + function. + * tree.h (enum elem_fn_parm_type): New enum. + 2012-04-20 Balaji V. Iyer * final.c (rest_of_handle_final): Moved outputing ZCA data after diff --git a/gcc/cilk.h b/gcc/cilk.h index 27d5dd0..27ccd16 100644 --- a/gcc/cilk.h +++ b/gcc/cilk.h @@ -269,5 +269,7 @@ extern void cilk_remove_annotated_functions (rtx first); extern bool cilk_annotated_function_p (char *); extern void debug_zca_data (void); extern zca_data *get_zca_entry (int); -extern void insert_in_zca_table (zca_data); +extern void insert_in_zca_table (zca_data); +extern bool is_elem_fn (tree); +extern tree find_elem_fn_name (tree, tree, tree); #endif /* GCC_CILK_H */ diff --git a/gcc/elem-function.c b/gcc/elem-function.c index 4cc9035..42f6248 100644 --- a/gcc/elem-function.c +++ b/gcc/elem-function.c @@ -83,6 +83,58 @@ static elem_fn_info *extract_elem_fn_values (tree); static tree create_optimize_attribute (int); static tree create_processor_attribute (elem_fn_info *, tree *); +/* this is an helper function for find_elem_fn_param_type */ +static enum elem_fn_parm_type +find_elem_fn_parm_type_1 (tree fndecl, int parm_no) +{ + int ii = 0; + elem_fn_info *elem_fn_values; + + elem_fn_values = extract_elem_fn_values (fndecl); + if (!elem_fn_values) + return TYPE_NONE; + + for (ii = 0; ii < elem_fn_values->no_lvars; ii++) + if (elem_fn_values->linear_location[ii] == parm_no) + return TYPE_LINEAR; + + for (ii = 0; ii < elem_fn_values->no_uvars; ii++) + if (elem_fn_values->uniform_location[ii] == parm_no) + return TYPE_UNIFORM; + + return TYPE_NONE; +} + + +/* this function will return the type of a parameter in elemental function. + The choices are UNIFORM or LINEAR. */ +enum elem_fn_parm_type +find_elem_fn_parm_type (gimple stmt, tree op) +{ + tree fndecl, parm = NULL_TREE; + int ii, nargs; + enum elem_fn_parm_type return_type = TYPE_NONE; + + if (gimple_code (stmt) != GIMPLE_CALL) + return TYPE_NONE; + + fndecl = gimple_call_fndecl (stmt); + gcc_assert (fndecl); + + nargs = gimple_call_num_args (stmt); + + for (ii = 0; ii < nargs; ii++) + { + parm = gimple_call_arg (stmt, ii); + if (op == parm) + { + return_type = find_elem_fn_parm_type_1 (fndecl, 1); + return return_type; + } + } + return return_type; +} + /* this function will concatinate the suffix to the existing function decl */ static tree rename_elem_fn (tree decl, const char *suffix) @@ -108,7 +160,7 @@ rename_elem_fn (tree decl, const char *suffix) /* this function will check to see if the node is part of an function that * needs to be converted to its vector equivalent. */ -static bool +bool is_elem_fn (tree fndecl) { tree ii_tree; @@ -349,6 +401,55 @@ find_suffix (elem_fn_info *elem_fn_values, bool masked) return suffix; } +tree +find_elem_fn_name (tree old_fndecl, + tree vectype_out ATTRIBUTE_UNUSED, + tree vectype_in ATTRIBUTE_UNUSED) +{ + elem_fn_info *elem_fn_values = NULL; + tree new_fndecl = NULL_TREE, arg_type = NULL_TREE; + char *suffix = NULL; + + elem_fn_values = extract_elem_fn_values (old_fndecl); + + if (elem_fn_values) + { + if (elem_fn_values->no_vlengths > 0) + { + if (elem_fn_values->vectorlength[0] == + (int)TYPE_VECTOR_SUBPARTS (vectype_out)) + suffix = find_suffix (elem_fn_values, false); + else + return NULL_TREE; + } + else + return NULL_TREE; + } + else + return NULL_TREE; + + new_fndecl = copy_node (rename_elem_fn (old_fndecl, suffix)); + TREE_TYPE (new_fndecl) = copy_node (TREE_TYPE (old_fndecl)); + + TYPE_ARG_TYPES (TREE_TYPE (new_fndecl)) = + copy_list (TYPE_ARG_TYPES (TREE_TYPE (new_fndecl))); + + for (arg_type = TYPE_ARG_TYPES (TREE_TYPE (new_fndecl)); + arg_type && arg_type != void_type_node; + arg_type = TREE_CHAIN (arg_type)) + TREE_VALUE (arg_type) = vectype_out; + + if (TREE_TYPE (TREE_TYPE (new_fndecl)) != void_type_node) + { + TREE_TYPE (TREE_TYPE (new_fndecl)) = + copy_node (TREE_TYPE (TREE_TYPE (new_fndecl))); + TREE_TYPE (TREE_TYPE (new_fndecl)) = vectype_out; + DECL_MODE (new_fndecl) = TYPE_MODE (vectype_out); + } + + return new_fndecl; +} + /* this function wil create the elemental vector function node */ static struct cgraph_node * create_elem_fn_nodes (struct cgraph_node *node) diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c index 1381b53..bea2773 100644 --- a/gcc/tree-data-ref.c +++ b/gcc/tree-data-ref.c @@ -86,6 +86,7 @@ along with GCC; see the file COPYING3. If not see #include "langhooks.h" #include "tree-affine.h" #include "params.h" +#include "cilk.h" static struct datadep_stats { @@ -4383,8 +4384,18 @@ find_data_references_in_stmt (struct loop *nest, gimple stmt, if (get_references_in_stmt (stmt, &references)) { - VEC_free (data_ref_loc, heap, references); - return false; + /* If we have an elemental function, then dont worry about its refernce + * it is probably available somewhere */ + if (flag_enable_cilk + && gimple_code (stmt) == GIMPLE_CALL + && gimple_call_fndecl (stmt) + && is_elem_fn (gimple_call_fndecl (stmt))) + ; + else + { + VEC_free (data_ref_loc, heap, references); + return false; + } } FOR_EACH_VEC_ELT (data_ref_loc, references, i, ref) diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index 968e4ed..6eb5f56 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -40,7 +40,7 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic-core.h" #include "tree-vectorizer.h" #include "langhooks.h" - +#include "cilk.h" /* Return a variable of type ELEM_TYPE[NELEMS]. */ @@ -1260,6 +1260,8 @@ vect_get_vec_def_for_operand (tree op, gimple stmt, tree *scalar_def) bool is_simple_use; tree vector_type; + extern enum elem_fn_parm_type find_elem_fn_parm_type (gimple, tree); + if (vect_print_dump_info (REPORT_DETAILS)) { fprintf (vect_dump, "vect_get_vec_def_for_operand: "); @@ -1283,13 +1285,26 @@ vect_get_vec_def_for_operand (tree op, gimple stmt, tree *scalar_def) } } + if (flag_enable_cilk + && gimple_code (stmt) == GIMPLE_CALL + && is_elem_fn (gimple_call_fndecl (stmt))) + { + enum elem_fn_parm_type parm_type = find_elem_fn_parm_type (stmt, op); + if (parm_type == TYPE_UNIFORM) + dt = vect_constant_def; + else if (parm_type == TYPE_LINEAR) + { + ; + } + } + switch (dt) { /* Case 1: operand is a constant. */ case vect_constant_def: { vector_type = get_vectype_for_scalar_type (TREE_TYPE (op)); - gcc_assert (vector_type); + gcc_assert (vector_type); nunits = TYPE_VECTOR_SUBPARTS (vector_type); if (scalar_def) @@ -1566,6 +1581,20 @@ vectorizable_function (gimple call, tree vectype_out, tree vectype_in) { tree fndecl = gimple_call_fndecl (call); + if (flag_enable_cilk && is_elem_fn (fndecl)) + { + if (DECL_ELEM_FN_ALREADY_CLONED (fndecl)) + return fndecl; + else + { + tree new_fndecl = find_elem_fn_name (copy_node (fndecl), + vectype_out, vectype_in); + if (new_fndecl) + DECL_ELEM_FN_ALREADY_CLONED (new_fndecl) = 1; + /* gimple_call_set_fntype (call, TREE_TYPE (new_fndecl)); */ + return new_fndecl; + } + } /* We only handle functions that do not read or clobber memory -- i.e. const or novops ones. */ if (!(gimple_call_flags (call) & (ECF_CONST | ECF_NOVOPS))) @@ -1718,8 +1747,6 @@ vectorizable_call (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, return false; } - gcc_assert (!gimple_vuse (stmt)); - if (slp_node || PURE_SLP_STMT (stmt_info)) ncopies = 1; else if (modifier == NARROW) @@ -1824,7 +1851,8 @@ vectorizable_call (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, new_stmt = gimple_build_call_vec (fndecl, vargs); new_temp = make_ssa_name (vec_dest, new_stmt); gimple_call_set_lhs (new_stmt, new_temp); - + if (flag_enable_cilk && is_elem_fn (fndecl)) + gimple_call_set_fntype (new_stmt, TREE_TYPE (fndecl)); vect_finish_stmt_generation (stmt, new_stmt, gsi); mark_symbols_for_renaming (new_stmt); diff --git a/gcc/tree.h b/gcc/tree.h index 79a27bf..06fb8d3 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -3671,6 +3671,9 @@ extern VEC(tree, gc) **decl_debug_args_insert (tree); #define DECL_FUNCTION_SPECIFIC_OPTIMIZATION(NODE) \ (FUNCTION_DECL_CHECK (NODE)->function_decl.function_specific_optimization) +#define DECL_ELEM_FN_ALREADY_CLONED(NODE) \ + (FUNCTION_DECL_CHECK (NODE)->function_decl.elem_fn_already_cloned) + /* FUNCTION_DECL inherits from DECL_NON_COMMON because of the use of the arguments/result/saved_tree fields by front ends. It was either inherit FUNCTION_DECL from non_common, or inherit non_common from FUNCTION_DECL, @@ -3718,6 +3721,7 @@ struct GTY(()) tree_function_decl { unsigned cilk_has_spawn : 1; signed int kills_registers : DECL_KILLS_REGISTERS_BITS; unsigned tm_clone_flag : 1; + unsigned elem_fn_already_cloned : 1; /* 1 bit left */ }; @@ -3801,6 +3805,12 @@ enum function_linkage linkage_cilk }; +enum elem_fn_parm_type +{ + TYPE_NONE = 0, + TYPE_UNIFORM = 1, + TYPE_LINEAR = 2 +}; #define TREE_OPTIMIZATION(NODE) \ (&OPTIMIZATION_NODE_CHECK (NODE)->optimization.opts)