Hello Everyone,
This patch is for the Cilkplus branch affecting both C and C++ compilers.
This patch will insert elemental functions when the loop is vectorized.
Thanking You,
Yours Sincerely,
Balaji V. Iyer.
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)