/* Statement Analysis and Transformation for Vectorization
- Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software
- Foundation, Inc.
+ Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ Free Software Foundation, Inc.
Contributed by Dorit Naishlos <dorit@il.ibm.com>
and Ira Rosen <irar@il.ibm.com>
#include "tree.h"
#include "target.h"
#include "basic-block.h"
-#include "diagnostic.h"
+#include "tree-pretty-print.h"
+#include "gimple-pretty-print.h"
#include "tree-flow.h"
#include "tree-dump.h"
#include "cfgloop.h"
#include "expr.h"
#include "recog.h"
#include "optabs.h"
+#include "diagnostic-core.h"
#include "toplev.h"
#include "tree-vectorizer.h"
#include "langhooks.h"
}
+/* Get cost by calling cost target builtin. */
+
+static inline
+int vect_get_stmt_cost (enum vect_cost_for_stmt type_of_cost)
+{
+ tree dummy_type = NULL;
+ int dummy = 0;
+
+ return targetm.vectorize.builtin_vectorization_cost (type_of_cost,
+ dummy_type, dummy);
+}
+
int
cost_for_stmt (gimple stmt)
{
switch (STMT_VINFO_TYPE (stmt_info))
{
case load_vec_info_type:
- return TARG_SCALAR_LOAD_COST;
+ return vect_get_stmt_cost (scalar_load);
case store_vec_info_type:
- return TARG_SCALAR_STORE_COST;
+ return vect_get_stmt_cost (scalar_store);
case op_vec_info_type:
case condition_vec_info_type:
case assignment_vec_info_type:
case type_demotion_vec_info_type:
case type_conversion_vec_info_type:
case call_vec_info_type:
- return TARG_SCALAR_STMT_COST;
+ return vect_get_stmt_cost (scalar_stmt);
case undef_vec_info_type:
default:
gcc_unreachable ();
if (PURE_SLP_STMT (stmt_info))
return;
- inside_cost = ncopies * TARG_VEC_STMT_COST;
+ inside_cost = ncopies * vect_get_stmt_cost (vector_stmt);
/* FORNOW: Assuming maximum 2 args per stmts. */
for (i = 0; i < 2; i++)
{
if (dt[i] == vect_constant_def || dt[i] == vect_external_def)
- outside_cost += TARG_SCALAR_TO_VEC_COST;
+ outside_cost += vect_get_stmt_cost (vector_stmt);
}
if (vect_print_dump_info (REPORT_COST))
enum vect_def_type dt, slp_tree slp_node)
{
int group_size;
- int inside_cost = 0, outside_cost = 0;
+ unsigned int inside_cost = 0, outside_cost = 0;
+ struct data_reference *first_dr;
+ gimple first_stmt;
/* The SLP costs were already calculated during SLP tree build. */
if (PURE_SLP_STMT (stmt_info))
return;
if (dt == vect_constant_def || dt == vect_external_def)
- outside_cost = TARG_SCALAR_TO_VEC_COST;
+ outside_cost = vect_get_stmt_cost (scalar_to_vec);
/* Strided access? */
- if (DR_GROUP_FIRST_DR (stmt_info) && !slp_node)
- group_size = vect_cost_strided_group_size (stmt_info);
+ if (DR_GROUP_FIRST_DR (stmt_info))
+ {
+ if (slp_node)
+ {
+ first_stmt = VEC_index (gimple, SLP_TREE_SCALAR_STMTS (slp_node), 0);
+ group_size = 1;
+ }
+ else
+ {
+ first_stmt = DR_GROUP_FIRST_DR (stmt_info);
+ group_size = vect_cost_strided_group_size (stmt_info);
+ }
+
+ first_dr = STMT_VINFO_DATA_REF (vinfo_for_stmt (first_stmt));
+ }
/* Not a strided access. */
else
- group_size = 1;
+ {
+ group_size = 1;
+ first_dr = STMT_VINFO_DATA_REF (stmt_info);
+ }
/* Is this an access in a group of stores, which provide strided access?
If so, add in the cost of the permutes. */
{
/* Uses a high and low interleave operation for each needed permute. */
inside_cost = ncopies * exact_log2(group_size) * group_size
- * TARG_VEC_STMT_COST;
+ * vect_get_stmt_cost (vector_stmt);
if (vect_print_dump_info (REPORT_COST))
fprintf (vect_dump, "vect_model_store_cost: strided group_size = %d .",
}
/* Costs of the stores. */
- inside_cost += ncopies * TARG_VEC_STORE_COST;
+ vect_get_store_cost (first_dr, ncopies, &inside_cost);
if (vect_print_dump_info (REPORT_COST))
fprintf (vect_dump, "vect_model_store_cost: inside_cost = %d, "
}
+/* Calculate cost of DR's memory access. */
+void
+vect_get_store_cost (struct data_reference *dr, int ncopies,
+ unsigned int *inside_cost)
+{
+ int alignment_support_scheme = vect_supportable_dr_alignment (dr, false);
+
+ switch (alignment_support_scheme)
+ {
+ case dr_aligned:
+ {
+ *inside_cost += ncopies * vect_get_stmt_cost (vector_store);
+
+ if (vect_print_dump_info (REPORT_COST))
+ fprintf (vect_dump, "vect_model_store_cost: aligned.");
+
+ break;
+ }
+
+ case dr_unaligned_supported:
+ {
+ gimple stmt = DR_STMT (dr);
+ stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
+ tree vectype = STMT_VINFO_VECTYPE (stmt_info);
+
+ /* Here, we assign an additional cost for the unaligned store. */
+ *inside_cost += ncopies
+ * targetm.vectorize.builtin_vectorization_cost (unaligned_store,
+ vectype, DR_MISALIGNMENT (dr));
+
+ if (vect_print_dump_info (REPORT_COST))
+ fprintf (vect_dump, "vect_model_store_cost: unaligned supported by "
+ "hardware.");
+
+ break;
+ }
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+
/* Function vect_model_load_cost
Models cost for loads. In the case of strided accesses, the last access
{
int group_size;
- int alignment_support_cheme;
gimple first_stmt;
struct data_reference *dr = STMT_VINFO_DATA_REF (stmt_info), *first_dr;
- int inside_cost = 0, outside_cost = 0;
+ unsigned int inside_cost = 0, outside_cost = 0;
/* The SLP costs were already calculated during SLP tree build. */
if (PURE_SLP_STMT (stmt_info))
first_dr = dr;
}
- alignment_support_cheme = vect_supportable_dr_alignment (first_dr);
-
/* Is this an access in a group of loads providing strided access?
If so, add in the cost of the permutes. */
if (group_size > 1)
{
/* Uses an even and odd extract operations for each needed permute. */
inside_cost = ncopies * exact_log2(group_size) * group_size
- * TARG_VEC_STMT_COST;
+ * vect_get_stmt_cost (vector_stmt);
if (vect_print_dump_info (REPORT_COST))
fprintf (vect_dump, "vect_model_load_cost: strided group_size = %d .",
group_size);
-
}
/* The loads themselves. */
- switch (alignment_support_cheme)
+ vect_get_load_cost (first_dr, ncopies,
+ ((!DR_GROUP_FIRST_DR (stmt_info)) || group_size > 1 || slp_node),
+ &inside_cost, &outside_cost);
+
+ if (vect_print_dump_info (REPORT_COST))
+ fprintf (vect_dump, "vect_model_load_cost: inside_cost = %d, "
+ "outside_cost = %d .", inside_cost, outside_cost);
+
+ /* Set the costs either in STMT_INFO or SLP_NODE (if exists). */
+ stmt_vinfo_set_inside_of_loop_cost (stmt_info, slp_node, inside_cost);
+ stmt_vinfo_set_outside_of_loop_cost (stmt_info, slp_node, outside_cost);
+}
+
+
+/* Calculate cost of DR's memory access. */
+void
+vect_get_load_cost (struct data_reference *dr, int ncopies,
+ bool add_realign_cost, unsigned int *inside_cost,
+ unsigned int *outside_cost)
+{
+ int alignment_support_scheme = vect_supportable_dr_alignment (dr, false);
+
+ switch (alignment_support_scheme)
{
case dr_aligned:
{
- inside_cost += ncopies * TARG_VEC_LOAD_COST;
+ *inside_cost += ncopies * vect_get_stmt_cost (vector_load);
if (vect_print_dump_info (REPORT_COST))
fprintf (vect_dump, "vect_model_load_cost: aligned.");
}
case dr_unaligned_supported:
{
- /* Here, we assign an additional cost for the unaligned load. */
- inside_cost += ncopies * TARG_VEC_UNALIGNED_LOAD_COST;
+ gimple stmt = DR_STMT (dr);
+ stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
+ tree vectype = STMT_VINFO_VECTYPE (stmt_info);
+ /* Here, we assign an additional cost for the unaligned load. */
+ *inside_cost += ncopies
+ * targetm.vectorize.builtin_vectorization_cost (unaligned_load,
+ vectype, DR_MISALIGNMENT (dr));
if (vect_print_dump_info (REPORT_COST))
fprintf (vect_dump, "vect_model_load_cost: unaligned supported by "
"hardware.");
}
case dr_explicit_realign:
{
- inside_cost += ncopies * (2*TARG_VEC_LOAD_COST + TARG_VEC_STMT_COST);
+ *inside_cost += ncopies * (2 * vect_get_stmt_cost (vector_load)
+ + vect_get_stmt_cost (vector_stmt));
/* FIXME: If the misalignment remains fixed across the iterations of
the containing loop, the following cost should be added to the
outside costs. */
if (targetm.vectorize.builtin_mask_for_load)
- inside_cost += TARG_VEC_STMT_COST;
+ *inside_cost += vect_get_stmt_cost (vector_stmt);
break;
}
access in the group. Inside the loop, there is a load op
and a realignment op. */
- if ((!DR_GROUP_FIRST_DR (stmt_info)) || group_size > 1 || slp_node)
+ if (add_realign_cost)
{
- outside_cost = 2*TARG_VEC_STMT_COST;
+ *outside_cost = 2 * vect_get_stmt_cost (vector_stmt);
if (targetm.vectorize.builtin_mask_for_load)
- outside_cost += TARG_VEC_STMT_COST;
+ *outside_cost += vect_get_stmt_cost (vector_stmt);
}
- inside_cost += ncopies * (TARG_VEC_LOAD_COST + TARG_VEC_STMT_COST);
-
+ *inside_cost += ncopies * (vect_get_stmt_cost (vector_load)
+ + vect_get_stmt_cost (vector_stmt));
break;
}
default:
gcc_unreachable ();
}
-
- if (vect_print_dump_info (REPORT_COST))
- fprintf (vect_dump, "vect_model_load_cost: inside_cost = %d, "
- "outside_cost = %d .", inside_cost, outside_cost);
-
- /* Set the costs either in STMT_INFO or SLP_NODE (if exists). */
- stmt_vinfo_set_inside_of_loop_cost (stmt_info, slp_node, inside_cost);
- stmt_vinfo_set_outside_of_loop_cost (stmt_info, slp_node, outside_cost);
}
slp_tree slp_node)
{
if (slp_node)
- vect_get_slp_defs (slp_node, vec_oprnds0, vec_oprnds1);
+ vect_get_slp_defs (slp_node, vec_oprnds0, vec_oprnds1, -1);
else
{
tree vec_oprnd;
vectorizable_function (gimple call, tree vectype_out, tree vectype_in)
{
tree fndecl = gimple_call_fndecl (call);
- enum built_in_function code;
/* We only handle functions that do not read or clobber memory -- i.e.
const or novops ones. */
|| !DECL_BUILT_IN (fndecl))
return NULL_TREE;
- code = DECL_FUNCTION_CODE (fndecl);
- return targetm.vectorize.builtin_vectorized_function (code, vectype_out,
+ return targetm.vectorize.builtin_vectorized_function (fndecl, vectype_out,
vectype_in);
}
int nunits_in;
int nunits_out;
loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info);
- tree fndecl, new_temp, def, rhs_type, lhs_type;
+ tree fndecl, new_temp, def, rhs_type;
gimple def_stmt;
enum vect_def_type dt[2] = {vect_unknown_def_type, vect_unknown_def_type};
gimple new_stmt = NULL;
if (TREE_CODE (gimple_call_lhs (stmt)) != SSA_NAME)
return false;
+ vectype_out = STMT_VINFO_VECTYPE (stmt_info);
+
/* Process function arguments. */
rhs_type = NULL_TREE;
+ vectype_in = NULL_TREE;
nargs = gimple_call_num_args (stmt);
/* Bail out if the function has more than two arguments, we
for (i = 0; i < nargs; i++)
{
+ tree opvectype;
+
op = gimple_call_arg (stmt, i);
/* We can only handle calls with arguments of the same type. */
if (rhs_type
- && rhs_type != TREE_TYPE (op))
+ && !types_compatible_p (rhs_type, TREE_TYPE (op)))
{
if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "argument types differ.");
return false;
}
- rhs_type = TREE_TYPE (op);
+ if (!rhs_type)
+ rhs_type = TREE_TYPE (op);
- if (!vect_is_simple_use (op, loop_vinfo, NULL, &def_stmt, &def, &dt[i]))
+ if (!vect_is_simple_use_1 (op, loop_vinfo, NULL,
+ &def_stmt, &def, &dt[i], &opvectype))
{
if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "use not simple.");
return false;
}
- }
- vectype_in = get_vectype_for_scalar_type (rhs_type);
+ if (!vectype_in)
+ vectype_in = opvectype;
+ else if (opvectype
+ && opvectype != vectype_in)
+ {
+ if (vect_print_dump_info (REPORT_DETAILS))
+ fprintf (vect_dump, "argument vector types differ.");
+ return false;
+ }
+ }
+ /* If all arguments are external or constant defs use a vector type with
+ the same size as the output vector type. */
if (!vectype_in)
- return false;
- nunits_in = TYPE_VECTOR_SUBPARTS (vectype_in);
+ vectype_in = get_same_sized_vectype (rhs_type, vectype_out);
+ if (vec_stmt)
+ gcc_assert (vectype_in);
+ if (!vectype_in)
+ {
+ if (vect_print_dump_info (REPORT_DETAILS))
+ {
+ fprintf (vect_dump, "no vectype for scalar type ");
+ print_generic_expr (vect_dump, rhs_type, TDF_SLIM);
+ }
- lhs_type = TREE_TYPE (gimple_call_lhs (stmt));
- vectype_out = get_vectype_for_scalar_type (lhs_type);
- if (!vectype_out)
- return false;
- nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
+ return false;
+ }
/* FORNOW */
+ nunits_in = TYPE_VECTOR_SUBPARTS (vectype_in);
+ nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
if (nunits_in == nunits_out / 2)
modifier = NARROW;
else if (nunits_out == nunits_in)
int nunits_out;
tree vectype_out, vectype_in;
int ncopies, j;
- tree rhs_type, lhs_type;
+ tree rhs_type;
tree builtin_decl;
enum { NARROW, NONE, WIDEN } modifier;
int i;
VEC(tree,heap) *vec_oprnds0 = NULL;
tree vop0;
- tree integral_type;
VEC(tree,heap) *dummy = NULL;
int dummy_int;
return false;
/* Check types of lhs and rhs. */
+ scalar_dest = gimple_assign_lhs (stmt);
+ vectype_out = STMT_VINFO_VECTYPE (stmt_info);
+
op0 = gimple_assign_rhs1 (stmt);
rhs_type = TREE_TYPE (op0);
- vectype_in = get_vectype_for_scalar_type (rhs_type);
+ /* Check the operands of the operation. */
+ if (!vect_is_simple_use_1 (op0, loop_vinfo, NULL,
+ &def_stmt, &def, &dt[0], &vectype_in))
+ {
+ if (vect_print_dump_info (REPORT_DETAILS))
+ fprintf (vect_dump, "use not simple.");
+ return false;
+ }
+ /* If op0 is an external or constant defs use a vector type of
+ the same size as the output vector type. */
if (!vectype_in)
- return false;
- nunits_in = TYPE_VECTOR_SUBPARTS (vectype_in);
+ vectype_in = get_same_sized_vectype (rhs_type, vectype_out);
+ if (vec_stmt)
+ gcc_assert (vectype_in);
+ if (!vectype_in)
+ {
+ if (vect_print_dump_info (REPORT_DETAILS))
+ {
+ fprintf (vect_dump, "no vectype for scalar type ");
+ print_generic_expr (vect_dump, rhs_type, TDF_SLIM);
+ }
- scalar_dest = gimple_assign_lhs (stmt);
- lhs_type = TREE_TYPE (scalar_dest);
- vectype_out = get_vectype_for_scalar_type (lhs_type);
- if (!vectype_out)
- return false;
- nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
+ return false;
+ }
/* FORNOW */
+ nunits_in = TYPE_VECTOR_SUBPARTS (vectype_in);
+ nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
if (nunits_in == nunits_out / 2)
modifier = NARROW;
else if (nunits_out == nunits_in)
else
return false;
- if (modifier == NONE)
- gcc_assert (STMT_VINFO_VECTYPE (stmt_info) == vectype_out);
-
- /* Bail out if the types are both integral or non-integral. */
- if ((INTEGRAL_TYPE_P (rhs_type) && INTEGRAL_TYPE_P (lhs_type))
- || (!INTEGRAL_TYPE_P (rhs_type) && !INTEGRAL_TYPE_P (lhs_type)))
- return false;
-
- integral_type = INTEGRAL_TYPE_P (rhs_type) ? vectype_in : vectype_out;
-
if (modifier == NARROW)
ncopies = LOOP_VINFO_VECT_FACTOR (loop_vinfo) / nunits_out;
else
needs to be generated. */
gcc_assert (ncopies >= 1);
- /* Check the operands of the operation. */
- if (!vect_is_simple_use (op0, loop_vinfo, NULL, &def_stmt, &def, &dt[0]))
- {
- if (vect_print_dump_info (REPORT_DETAILS))
- fprintf (vect_dump, "use not simple.");
- return false;
- }
-
/* Supportable by target? */
if ((modifier == NONE
- && !targetm.vectorize.builtin_conversion (code, integral_type))
+ && !targetm.vectorize.builtin_conversion (code, vectype_out, vectype_in))
|| (modifier == WIDEN
- && !supportable_widening_operation (code, stmt, vectype_in,
+ && !supportable_widening_operation (code, stmt,
+ vectype_out, vectype_in,
&decl1, &decl2,
&code1, &code2,
&dummy_int, &dummy))
|| (modifier == NARROW
- && !supportable_narrowing_operation (code, stmt, vectype_in,
+ && !supportable_narrowing_operation (code, vectype_out, vectype_in,
&code1, &dummy_int, &dummy)))
{
if (vect_print_dump_info (REPORT_DETAILS))
if (modifier != NONE)
{
- STMT_VINFO_VECTYPE (stmt_info) = vectype_in;
/* FORNOW: SLP not supported. */
if (STMT_SLP_TYPE (stmt_info))
return false;
vect_get_vec_defs_for_stmt_copy (dt, &vec_oprnds0, NULL);
builtin_decl =
- targetm.vectorize.builtin_conversion (code, integral_type);
+ targetm.vectorize.builtin_conversion (code,
+ vectype_out, vectype_in);
for (i = 0; VEC_iterate (tree, vec_oprnds0, i, vop0); i++)
{
/* Arguments are ready. create the new vector stmt. */
else
vec_oprnd0 = vect_get_vec_def_for_stmt_copy (dt[0], vec_oprnd0);
- STMT_VINFO_VECTYPE (stmt_info) = vectype_in;
-
/* Generate first half of the widened result: */
new_stmt
= vect_gen_widened_results_half (code1, decl1,
tree def;
gimple def_stmt;
enum vect_def_type dt[2] = {vect_unknown_def_type, vect_unknown_def_type};
- int nunits = TYPE_VECTOR_SUBPARTS (vectype);
+ unsigned int nunits = TYPE_VECTOR_SUBPARTS (vectype);
int ncopies;
int i, j;
VEC(tree,heap) *vec_oprnds = NULL;
bb_vec_info bb_vinfo = STMT_VINFO_BB_VINFO (stmt_info);
gimple new_stmt = NULL;
stmt_vec_info prev_stmt_info = NULL;
+ enum tree_code code;
+ tree vectype_in;
/* Multiple types in SLP are handled by creating the appropriate number of
vectorized stmts for each SLP node. Hence, NCOPIES is always 1 in
if (TREE_CODE (scalar_dest) != SSA_NAME)
return false;
+ code = gimple_assign_rhs_code (stmt);
if (gimple_assign_single_p (stmt)
- || gimple_assign_rhs_code (stmt) == PAREN_EXPR)
+ || code == PAREN_EXPR
+ || CONVERT_EXPR_CODE_P (code))
op = gimple_assign_rhs1 (stmt);
else
return false;
- if (!vect_is_simple_use (op, loop_vinfo, bb_vinfo, &def_stmt, &def, &dt[0]))
+ if (!vect_is_simple_use_1 (op, loop_vinfo, bb_vinfo,
+ &def_stmt, &def, &dt[0], &vectype_in))
{
if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "use not simple.");
return false;
}
+ /* We can handle NOP_EXPR conversions that do not change the number
+ of elements or the vector size. */
+ if (CONVERT_EXPR_CODE_P (code)
+ && (!vectype_in
+ || TYPE_VECTOR_SUBPARTS (vectype_in) != nunits
+ || (GET_MODE_SIZE (TYPE_MODE (vectype))
+ != GET_MODE_SIZE (TYPE_MODE (vectype_in)))))
+ return false;
+
if (!vec_stmt) /* transformation not required. */
{
STMT_VINFO_TYPE (stmt_info) = assignment_vec_info_type;
/* Arguments are ready. create the new vector stmt. */
for (i = 0; VEC_iterate (tree, vec_oprnds, i, vop); i++)
{
+ if (CONVERT_EXPR_CODE_P (code))
+ vop = build1 (VIEW_CONVERT_EXPR, vectype, vop);
new_stmt = gimple_build_assign (vec_dest, vop);
new_temp = make_ssa_name (vec_dest, new_stmt);
gimple_assign_set_lhs (new_stmt, new_temp);
tree op0, op1 = NULL;
tree vec_oprnd1 = NULL_TREE;
stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
- tree vectype = STMT_VINFO_VECTYPE (stmt_info);
+ tree vectype;
loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info);
enum tree_code code;
enum machine_mode vec_mode;
enum vect_def_type dt[2] = {vect_unknown_def_type, vect_unknown_def_type};
gimple new_stmt = NULL;
stmt_vec_info prev_stmt_info;
- int nunits_in = TYPE_VECTOR_SUBPARTS (vectype);
+ int nunits_in;
int nunits_out;
tree vectype_out;
int ncopies;
bb_vec_info bb_vinfo = STMT_VINFO_BB_VINFO (stmt_info);
int vf;
- if (loop_vinfo)
- vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
- else
- vf = 1;
-
- /* Multiple types in SLP are handled by creating the appropriate number of
- vectorized stmts for each SLP node. Hence, NCOPIES is always 1 in
- case of SLP. */
- if (slp_node)
- ncopies = 1;
- else
- ncopies = LOOP_VINFO_VECT_FACTOR (loop_vinfo) / nunits_in;
-
- gcc_assert (ncopies >= 1);
-
if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
return false;
if (TREE_CODE (gimple_assign_lhs (stmt)) != SSA_NAME)
return false;
- scalar_dest = gimple_assign_lhs (stmt);
- vectype_out = get_vectype_for_scalar_type (TREE_TYPE (scalar_dest));
- if (!vectype_out)
- return false;
- nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
- if (nunits_out != nunits_in)
- return false;
-
code = gimple_assign_rhs_code (stmt);
/* For pointer addition, we should use the normal plus for
return false;
}
+ scalar_dest = gimple_assign_lhs (stmt);
+ vectype_out = STMT_VINFO_VECTYPE (stmt_info);
+
op0 = gimple_assign_rhs1 (stmt);
- if (!vect_is_simple_use (op0, loop_vinfo, bb_vinfo, &def_stmt, &def, &dt[0]))
+ if (!vect_is_simple_use_1 (op0, loop_vinfo, bb_vinfo,
+ &def_stmt, &def, &dt[0], &vectype))
{
if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "use not simple.");
return false;
}
+ /* If op0 is an external or constant def use a vector type with
+ the same size as the output vector type. */
+ if (!vectype)
+ vectype = get_same_sized_vectype (TREE_TYPE (op0), vectype_out);
+ if (vec_stmt)
+ gcc_assert (vectype);
+ if (!vectype)
+ {
+ if (vect_print_dump_info (REPORT_DETAILS))
+ {
+ fprintf (vect_dump, "no vectype for scalar type ");
+ print_generic_expr (vect_dump, TREE_TYPE (op0), TDF_SLIM);
+ }
+
+ return false;
+ }
+
+ nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
+ nunits_in = TYPE_VECTOR_SUBPARTS (vectype);
+ if (nunits_out != nunits_in)
+ return false;
if (op_type == binary_op)
{
}
}
+ if (loop_vinfo)
+ vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
+ else
+ vf = 1;
+
+ /* Multiple types in SLP are handled by creating the appropriate number of
+ vectorized stmts for each SLP node. Hence, NCOPIES is always 1 in
+ case of SLP. */
+ if (slp_node)
+ ncopies = 1;
+ else
+ ncopies = LOOP_VINFO_VECT_FACTOR (loop_vinfo) / nunits_in;
+
+ gcc_assert (ncopies >= 1);
+
/* If this is a shift/rotate, determine whether the shift amount is a vector,
or scalar. If the shift/rotate amount is a vector, use the vector/vector
shift optabs. */
{
optab = optab_for_tree_code (code, vectype, optab_scalar);
if (optab
- && (optab_handler (optab, TYPE_MODE (vectype))->insn_code
- != CODE_FOR_nothing))
+ && optab_handler (optab, TYPE_MODE (vectype)) != CODE_FOR_nothing)
{
scalar_shift_arg = true;
if (vect_print_dump_info (REPORT_DETAILS))
{
optab = optab_for_tree_code (code, vectype, optab_vector);
if (optab
- && (optab_handler (optab, TYPE_MODE (vectype))->insn_code
+ && (optab_handler (optab, TYPE_MODE (vectype))
!= CODE_FOR_nothing))
{
if (vect_print_dump_info (REPORT_DETAILS))
return false;
}
vec_mode = TYPE_MODE (vectype);
- icode = (int) optab_handler (optab, vec_mode)->insn_code;
+ icode = (int) optab_handler (optab, vec_mode);
if (icode == CODE_FOR_nothing)
{
if (vect_print_dump_info (REPORT_DETAILS))
if (!CONVERT_EXPR_CODE_P (code))
return false;
+ scalar_dest = gimple_assign_lhs (stmt);
+ vectype_out = STMT_VINFO_VECTYPE (stmt_info);
+
+ /* Check the operands of the operation. */
op0 = gimple_assign_rhs1 (stmt);
- vectype_in = get_vectype_for_scalar_type (TREE_TYPE (op0));
- if (!vectype_in)
+ if (! ((INTEGRAL_TYPE_P (TREE_TYPE (scalar_dest))
+ && INTEGRAL_TYPE_P (TREE_TYPE (op0)))
+ || (SCALAR_FLOAT_TYPE_P (TREE_TYPE (scalar_dest))
+ && SCALAR_FLOAT_TYPE_P (TREE_TYPE (op0))
+ && CONVERT_EXPR_CODE_P (code))))
return false;
- nunits_in = TYPE_VECTOR_SUBPARTS (vectype_in);
+ if (!vect_is_simple_use_1 (op0, loop_vinfo, NULL,
+ &def_stmt, &def, &dt[0], &vectype_in))
+ {
+ if (vect_print_dump_info (REPORT_DETAILS))
+ fprintf (vect_dump, "use not simple.");
+ return false;
+ }
+ /* If op0 is an external def use a vector type with the
+ same size as the output vector type if possible. */
+ if (!vectype_in)
+ vectype_in = get_same_sized_vectype (TREE_TYPE (op0), vectype_out);
+ if (vec_stmt)
+ gcc_assert (vectype_in);
+ if (!vectype_in)
+ {
+ if (vect_print_dump_info (REPORT_DETAILS))
+ {
+ fprintf (vect_dump, "no vectype for scalar type ");
+ print_generic_expr (vect_dump, TREE_TYPE (op0), TDF_SLIM);
+ }
- scalar_dest = gimple_assign_lhs (stmt);
- vectype_out = get_vectype_for_scalar_type (TREE_TYPE (scalar_dest));
- if (!vectype_out)
- return false;
+ return false;
+ }
+
+ nunits_in = TYPE_VECTOR_SUBPARTS (vectype_in);
nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
if (nunits_in >= nunits_out)
return false;
ncopies = LOOP_VINFO_VECT_FACTOR (loop_vinfo) / nunits_out;
gcc_assert (ncopies >= 1);
- if (! ((INTEGRAL_TYPE_P (TREE_TYPE (scalar_dest))
- && INTEGRAL_TYPE_P (TREE_TYPE (op0)))
- || (SCALAR_FLOAT_TYPE_P (TREE_TYPE (scalar_dest))
- && SCALAR_FLOAT_TYPE_P (TREE_TYPE (op0))
- && CONVERT_EXPR_CODE_P (code))))
- return false;
-
- /* Check the operands of the operation. */
- if (!vect_is_simple_use (op0, loop_vinfo, NULL, &def_stmt, &def, &dt[0]))
- {
- if (vect_print_dump_info (REPORT_DETAILS))
- fprintf (vect_dump, "use not simple.");
- return false;
- }
-
/* Supportable by target? */
- if (!supportable_narrowing_operation (code, stmt, vectype_in, &code1,
- &multi_step_cvt, &interm_types))
+ if (!supportable_narrowing_operation (code, vectype_out, vectype_in,
+ &code1, &multi_step_cvt, &interm_types))
return false;
- STMT_VINFO_VECTYPE (stmt_info) = vectype_in;
-
if (!vec_stmt) /* transformation not required. */
{
STMT_VINFO_TYPE (stmt_info) = type_demotion_vec_info_type;
{
/* Handle uses. */
if (slp_node)
- vect_get_slp_defs (slp_node, &vec_oprnds0, NULL);
+ vect_get_slp_defs (slp_node, &vec_oprnds0, NULL, -1);
else
{
VEC_free (tree, heap, vec_oprnds0);
&& code != WIDEN_MULT_EXPR)
return false;
+ scalar_dest = gimple_assign_lhs (stmt);
+ vectype_out = STMT_VINFO_VECTYPE (stmt_info);
+
+ /* Check the operands of the operation. */
op0 = gimple_assign_rhs1 (stmt);
- vectype_in = get_vectype_for_scalar_type (TREE_TYPE (op0));
- if (!vectype_in)
+ if (! ((INTEGRAL_TYPE_P (TREE_TYPE (scalar_dest))
+ && INTEGRAL_TYPE_P (TREE_TYPE (op0)))
+ || (SCALAR_FLOAT_TYPE_P (TREE_TYPE (scalar_dest))
+ && SCALAR_FLOAT_TYPE_P (TREE_TYPE (op0))
+ && CONVERT_EXPR_CODE_P (code))))
return false;
- nunits_in = TYPE_VECTOR_SUBPARTS (vectype_in);
+ if (!vect_is_simple_use_1 (op0, loop_vinfo, NULL,
+ &def_stmt, &def, &dt[0], &vectype_in))
+ {
+ if (vect_print_dump_info (REPORT_DETAILS))
+ fprintf (vect_dump, "use not simple.");
+ return false;
+ }
+ /* If op0 is an external or constant def use a vector type with
+ the same size as the output vector type. */
+ if (!vectype_in)
+ vectype_in = get_same_sized_vectype (TREE_TYPE (op0), vectype_out);
+ if (vec_stmt)
+ gcc_assert (vectype_in);
+ if (!vectype_in)
+ {
+ if (vect_print_dump_info (REPORT_DETAILS))
+ {
+ fprintf (vect_dump, "no vectype for scalar type ");
+ print_generic_expr (vect_dump, TREE_TYPE (op0), TDF_SLIM);
+ }
- scalar_dest = gimple_assign_lhs (stmt);
- vectype_out = get_vectype_for_scalar_type (TREE_TYPE (scalar_dest));
- if (!vectype_out)
- return false;
+ return false;
+ }
+
+ nunits_in = TYPE_VECTOR_SUBPARTS (vectype_in);
nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
if (nunits_in <= nunits_out)
return false;
gcc_assert (ncopies >= 1);
- if (! ((INTEGRAL_TYPE_P (TREE_TYPE (scalar_dest))
- && INTEGRAL_TYPE_P (TREE_TYPE (op0)))
- || (SCALAR_FLOAT_TYPE_P (TREE_TYPE (scalar_dest))
- && SCALAR_FLOAT_TYPE_P (TREE_TYPE (op0))
- && CONVERT_EXPR_CODE_P (code))))
- return false;
-
- /* Check the operands of the operation. */
- if (!vect_is_simple_use (op0, loop_vinfo, NULL, &def_stmt, &def, &dt[0]))
- {
- if (vect_print_dump_info (REPORT_DETAILS))
- fprintf (vect_dump, "use not simple.");
- return false;
- }
-
op_type = TREE_CODE_LENGTH (code);
if (op_type == binary_op)
{
}
/* Supportable by target? */
- if (!supportable_widening_operation (code, stmt, vectype_in,
+ if (!supportable_widening_operation (code, stmt, vectype_out, vectype_in,
&decl1, &decl2, &code1, &code2,
&multi_step_cvt, &interm_types))
return false;
architecture. */
gcc_assert (!(multi_step_cvt && op_type == binary_op));
- STMT_VINFO_VECTYPE (stmt_info) = vectype_in;
-
if (!vec_stmt) /* transformation not required. */
{
STMT_VINFO_TYPE (stmt_info) = type_promotion_vec_info_type;
if (j == 0)
{
if (slp_node)
- vect_get_slp_defs (slp_node, &vec_oprnds0, &vec_oprnds1);
+ vect_get_slp_defs (slp_node, &vec_oprnds0, &vec_oprnds1, -1);
else
{
vec_oprnd0 = vect_get_vec_def_for_operand (op0, stmt, NULL);
&& TREE_CODE (scalar_dest) != INDIRECT_REF
&& TREE_CODE (scalar_dest) != COMPONENT_REF
&& TREE_CODE (scalar_dest) != IMAGPART_EXPR
- && TREE_CODE (scalar_dest) != REALPART_EXPR)
+ && TREE_CODE (scalar_dest) != REALPART_EXPR
+ && TREE_CODE (scalar_dest) != MEM_REF)
return false;
gcc_assert (gimple_assign_single_p (stmt));
vec_mode = TYPE_MODE (vectype);
/* FORNOW. In some cases can vectorize even if data-type not supported
(e.g. - array initialization with 0). */
- if (optab_handler (mov_optab, (int)vec_mode)->insn_code == CODE_FOR_nothing)
+ if (optab_handler (mov_optab, vec_mode) == CODE_FOR_nothing)
return false;
if (!STMT_VINFO_DATA_REF (stmt_info))
}
if (slp)
- strided_store = false;
-
- /* VEC_NUM is the number of vect stmts to be created for this group. */
- if (slp)
- vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
+ {
+ strided_store = false;
+ /* VEC_NUM is the number of vect stmts to be created for this
+ group. */
+ vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
+ first_stmt = VEC_index (gimple, SLP_TREE_SCALAR_STMTS (slp_node), 0);
+ first_dr = STMT_VINFO_DATA_REF (vinfo_for_stmt (first_stmt));
+ }
else
+ /* VEC_NUM is the number of vect stmts to be created for this
+ group. */
vec_num = group_size;
}
else
dr_chain = VEC_alloc (tree, heap, group_size);
oprnds = VEC_alloc (tree, heap, group_size);
- alignment_support_scheme = vect_supportable_dr_alignment (first_dr);
+ alignment_support_scheme = vect_supportable_dr_alignment (first_dr, false);
gcc_assert (alignment_support_scheme);
/* In case the vectorization factor (VF) is bigger than the number
if (slp)
{
/* Get vectorized arguments for SLP_NODE. */
- vect_get_slp_defs (slp_node, &vec_oprnds, NULL);
+ vect_get_slp_defs (slp_node, &vec_oprnds, NULL, -1);
vec_oprnd = VEC_index (tree, vec_oprnds, 0);
}
vec_oprnd = VEC_index (tree, result_chain, i);
if (aligned_access_p (first_dr))
- data_ref = build_fold_indirect_ref (dataref_ptr);
+ data_ref
+ = build2 (MEM_REF, TREE_TYPE (vec_oprnd), dataref_ptr,
+ build_int_cst (reference_alias_ptr_type
+ (DR_REF (first_dr)), 0));
else
{
int mis = DR_MISALIGNMENT (first_dr);
data_ref = build2 (MISALIGNED_INDIRECT_REF, vectype, dataref_ptr, tmis);
}
- /* If accesses through a pointer to vectype do not alias the original
- memory reference we have a problem. This should never happen. */
- gcc_assert (alias_sets_conflict_p (get_alias_set (data_ref),
- get_alias_set (gimple_assign_lhs (stmt))));
-
/* Arguments are ready. Create the new vector stmt. */
new_stmt = gimple_build_assign (data_ref, vec_oprnd);
vect_finish_stmt_generation (stmt, new_stmt, gsi);
struct data_reference *dr = STMT_VINFO_DATA_REF (stmt_info), *first_dr;
tree vectype = STMT_VINFO_VECTYPE (stmt_info);
tree new_temp;
- int mode;
+ enum machine_mode mode;
gimple new_stmt = NULL;
tree dummy;
enum dr_alignment_support alignment_support_scheme;
&& code != INDIRECT_REF
&& code != COMPONENT_REF
&& code != IMAGPART_EXPR
- && code != REALPART_EXPR)
+ && code != REALPART_EXPR
+ && code != MEM_REF)
return false;
if (!STMT_VINFO_DATA_REF (stmt_info))
return false;
scalar_type = TREE_TYPE (DR_REF (dr));
- mode = (int) TYPE_MODE (vectype);
+ mode = TYPE_MODE (vectype);
/* FORNOW. In some cases can vectorize even if data-type not supported
(e.g. - data copies). */
- if (optab_handler (mov_optab, mode)->insn_code == CODE_FOR_nothing)
+ if (optab_handler (mov_optab, mode) == CODE_FOR_nothing)
{
if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "Aligned load, but unsupported type.");
group_size = vec_num = 1;
}
- alignment_support_scheme = vect_supportable_dr_alignment (first_dr);
+ alignment_support_scheme = vect_supportable_dr_alignment (first_dr, false);
gcc_assert (alignment_support_scheme);
/* In case the vectorization factor (VF) is bigger than the number
{
case dr_aligned:
gcc_assert (aligned_access_p (first_dr));
- data_ref = build_fold_indirect_ref (dataref_ptr);
+ data_ref
+ = build2 (MEM_REF, vectype, dataref_ptr,
+ build_int_cst (reference_alias_ptr_type
+ (DR_REF (first_dr)), 0));
break;
case dr_unaligned_supported:
{
dr_explicit_realign,
dataref_ptr, NULL);
- data_ref = build1 (ALIGN_INDIRECT_REF, vectype, dataref_ptr);
+ new_stmt = gimple_build_assign_with_ops
+ (BIT_AND_EXPR, NULL_TREE, dataref_ptr,
+ build_int_cst
+ (TREE_TYPE (dataref_ptr),
+ -(HOST_WIDE_INT)TYPE_ALIGN_UNIT (vectype)));
+ ptr = make_ssa_name (SSA_NAME_VAR (dataref_ptr), new_stmt);
+ gimple_assign_set_lhs (new_stmt, ptr);
+ vect_finish_stmt_generation (stmt, new_stmt, gsi);
+ data_ref
+ = build2 (MEM_REF, vectype, ptr,
+ build_int_cst (reference_alias_ptr_type
+ (DR_REF (first_dr)), 0));
vec_dest = vect_create_destination_var (scalar_dest, vectype);
new_stmt = gimple_build_assign (vec_dest, data_ref);
new_temp = make_ssa_name (vec_dest, new_stmt);
bump = size_binop (MULT_EXPR, vs_minus_1,
TYPE_SIZE_UNIT (scalar_type));
ptr = bump_vector_ptr (dataref_ptr, NULL, gsi, stmt, bump);
- data_ref = build1 (ALIGN_INDIRECT_REF, vectype, ptr);
+ new_stmt = gimple_build_assign_with_ops
+ (BIT_AND_EXPR, NULL_TREE, ptr,
+ build_int_cst
+ (TREE_TYPE (ptr),
+ -(HOST_WIDE_INT)TYPE_ALIGN_UNIT (vectype)));
+ ptr = make_ssa_name (SSA_NAME_VAR (dataref_ptr), new_stmt);
+ gimple_assign_set_lhs (new_stmt, ptr);
+ vect_finish_stmt_generation (stmt, new_stmt, gsi);
+ data_ref
+ = build2 (MEM_REF, vectype, ptr,
+ build_int_cst (reference_alias_ptr_type
+ (DR_REF (first_dr)), 0));
break;
}
case dr_explicit_realign_optimized:
- data_ref = build1 (ALIGN_INDIRECT_REF, vectype, dataref_ptr);
+ new_stmt = gimple_build_assign_with_ops
+ (BIT_AND_EXPR, NULL_TREE, dataref_ptr,
+ build_int_cst
+ (TREE_TYPE (dataref_ptr),
+ -(HOST_WIDE_INT)TYPE_ALIGN_UNIT (vectype)));
+ new_temp = make_ssa_name (SSA_NAME_VAR (dataref_ptr), new_stmt);
+ gimple_assign_set_lhs (new_stmt, new_temp);
+ vect_finish_stmt_generation (stmt, new_stmt, gsi);
+ data_ref
+ = build2 (MEM_REF, vectype, new_temp,
+ build_int_cst (reference_alias_ptr_type
+ (DR_REF (first_dr)), 0));
break;
default:
gcc_unreachable ();
}
- /* If accesses through a pointer to vectype do not alias the original
- memory reference we have a problem. This should never happen. */
- gcc_assert (alias_sets_conflict_p (get_alias_set (data_ref),
- get_alias_set (gimple_assign_rhs1 (stmt))));
vec_dest = vect_create_destination_var (scalar_dest, vectype);
new_stmt = gimple_build_assign (vec_dest, data_ref);
new_temp = make_ssa_name (vec_dest, new_stmt);
/* We do not handle two different vector types for the condition
and the values. */
- if (TREE_TYPE (TREE_OPERAND (cond_expr, 0)) != TREE_TYPE (vectype))
+ if (!types_compatible_p (TREE_TYPE (TREE_OPERAND (cond_expr, 0)),
+ TREE_TYPE (vectype)))
return false;
if (TREE_CODE (then_clause) == SSA_NAME)
bb_vec_info bb_vinfo = STMT_VINFO_BB_VINFO (stmt_info);
enum vect_relevant relevance = STMT_VINFO_RELEVANT (stmt_info);
bool ok;
- HOST_WIDE_INT dummy;
tree scalar_type, vectype;
if (vect_print_dump_info (REPORT_DETAILS))
{
gcc_assert (PURE_SLP_STMT (stmt_info));
- scalar_type = vect_get_smallest_scalar_type (stmt, &dummy, &dummy);
+ scalar_type = TREE_TYPE (gimple_get_lhs (stmt));
if (vect_print_dump_info (REPORT_DETAILS))
{
fprintf (vect_dump, "get vectype for scalar type: ");
|| vectorizable_load (stmt, NULL, NULL, NULL, NULL)
|| vectorizable_call (stmt, NULL, NULL)
|| vectorizable_store (stmt, NULL, NULL, NULL)
- || vectorizable_reduction (stmt, NULL, NULL)
+ || vectorizable_reduction (stmt, NULL, NULL, NULL)
|| vectorizable_condition (stmt, NULL, NULL, NULL, 0));
else
{
break;
case reduc_vec_info_type:
- gcc_assert (!slp_node);
- done = vectorizable_reduction (stmt, gsi, &vec_stmt);
+ done = vectorizable_reduction (stmt, gsi, &vec_stmt, slp_node);
gcc_assert (done);
break;
STMT_VINFO_LIVE_P (res) = false;
STMT_VINFO_VECTYPE (res) = NULL;
STMT_VINFO_VEC_STMT (res) = NULL;
+ STMT_VINFO_VECTORIZABLE (res) = true;
STMT_VINFO_IN_PATTERN_P (res) = false;
STMT_VINFO_RELATED_STMT (res) = NULL;
STMT_VINFO_DATA_REF (res) = NULL;
if (nbytes < TYPE_ALIGN_UNIT (scalar_type))
return NULL_TREE;
+ /* If we'd build a vector type of elements whose mode precision doesn't
+ match their types precision we'll get mismatched types on vector
+ extracts via BIT_FIELD_REFs. This effectively means we disable
+ vectorization of bool and/or enum types in some languages. */
+ if (INTEGRAL_TYPE_P (scalar_type)
+ && GET_MODE_BITSIZE (inner_mode) != TYPE_PRECISION (scalar_type))
+ return NULL_TREE;
+
/* FORNOW: Only a single vector size per mode (UNITS_PER_SIMD_WORD)
is expected. */
nunits = UNITS_PER_SIMD_WORD (inner_mode) / nbytes;
return vectype;
}
+/* Function get_same_sized_vectype
+
+ Returns a vector type corresponding to SCALAR_TYPE of size
+ VECTOR_TYPE if supported by the target. */
+
+tree
+get_same_sized_vectype (tree scalar_type, tree vector_type ATTRIBUTE_UNUSED)
+{
+ return get_vectype_for_scalar_type (scalar_type);
+}
+
/* Function vect_is_simple_use.
Input:
return true;
}
+/* Function vect_is_simple_use_1.
+
+ Same as vect_is_simple_use_1 but also determines the vector operand
+ type of OPERAND and stores it to *VECTYPE. If the definition of
+ OPERAND is vect_uninitialized_def, vect_constant_def or
+ vect_external_def *VECTYPE will be set to NULL_TREE and the caller
+ is responsible to compute the best suited vector type for the
+ scalar operand. */
+
+bool
+vect_is_simple_use_1 (tree operand, loop_vec_info loop_vinfo,
+ bb_vec_info bb_vinfo, gimple *def_stmt,
+ tree *def, enum vect_def_type *dt, tree *vectype)
+{
+ if (!vect_is_simple_use (operand, loop_vinfo, bb_vinfo, def_stmt, def, dt))
+ return false;
+
+ /* Now get a vector type if the def is internal, otherwise supply
+ NULL_TREE and leave it up to the caller to figure out a proper
+ type for the use stmt. */
+ if (*dt == vect_internal_def
+ || *dt == vect_induction_def
+ || *dt == vect_reduction_def
+ || *dt == vect_double_reduction_def
+ || *dt == vect_nested_cycle)
+ {
+ stmt_vec_info stmt_info = vinfo_for_stmt (*def_stmt);
+ if (STMT_VINFO_IN_PATTERN_P (stmt_info))
+ stmt_info = vinfo_for_stmt (STMT_VINFO_RELATED_STMT (stmt_info));
+ *vectype = STMT_VINFO_VECTYPE (stmt_info);
+ gcc_assert (*vectype != NULL_TREE);
+ }
+ else if (*dt == vect_uninitialized_def
+ || *dt == vect_constant_def
+ || *dt == vect_external_def)
+ *vectype = NULL_TREE;
+ else
+ gcc_unreachable ();
+
+ return true;
+}
+
/* Function supportable_widening_operation
Check whether an operation represented by the code CODE is a
widening operation that is supported by the target platform in
- vector form (i.e., when operating on arguments of type VECTYPE).
+ vector form (i.e., when operating on arguments of type VECTYPE_IN
+ producing a result of type VECTYPE_OUT).
Widening operations we currently support are NOP (CONVERT), FLOAT
and WIDEN_MULT. This function checks if these operations are supported
widening operation (short in the above example). */
bool
-supportable_widening_operation (enum tree_code code, gimple stmt, tree vectype,
+supportable_widening_operation (enum tree_code code, gimple stmt,
+ tree vectype_out, tree vectype_in,
tree *decl1, tree *decl2,
enum tree_code *code1, enum tree_code *code2,
int *multi_step_cvt,
enum machine_mode vec_mode;
enum insn_code icode1, icode2;
optab optab1, optab2;
- tree type = gimple_expr_type (stmt);
- tree wide_vectype = get_vectype_for_scalar_type (type);
+ tree vectype = vectype_in;
+ tree wide_vectype = vectype_out;
enum tree_code c1, c2;
/* The result of a vectorized widening operation usually requires two vectors
if (code == FIX_TRUNC_EXPR)
{
/* The signedness is determined from output operand. */
- optab1 = optab_for_tree_code (c1, type, optab_default);
- optab2 = optab_for_tree_code (c2, type, optab_default);
+ optab1 = optab_for_tree_code (c1, vectype_out, optab_default);
+ optab2 = optab_for_tree_code (c2, vectype_out, optab_default);
}
else
{
return false;
vec_mode = TYPE_MODE (vectype);
- if ((icode1 = optab_handler (optab1, vec_mode)->insn_code) == CODE_FOR_nothing
- || (icode2 = optab_handler (optab2, vec_mode)->insn_code)
- == CODE_FOR_nothing)
+ if ((icode1 = optab_handler (optab1, vec_mode)) == CODE_FOR_nothing
+ || (icode2 = optab_handler (optab2, vec_mode)) == CODE_FOR_nothing)
return false;
/* Check if it's a multi-step conversion that can be done using intermediate
optab4 = optab_for_tree_code (c2, intermediate_type, optab_default);
if (!optab3 || !optab4
- || (icode1 = optab1->handlers[(int) prev_mode].insn_code)
- == CODE_FOR_nothing
+ || ((icode1 = optab_handler (optab1, prev_mode))
+ == CODE_FOR_nothing)
|| insn_data[icode1].operand[0].mode != intermediate_mode
- || (icode2 = optab2->handlers[(int) prev_mode].insn_code)
- == CODE_FOR_nothing
+ || ((icode2 = optab_handler (optab2, prev_mode))
+ == CODE_FOR_nothing)
|| insn_data[icode2].operand[0].mode != intermediate_mode
- || (icode1 = optab3->handlers[(int) intermediate_mode].insn_code)
- == CODE_FOR_nothing
- || (icode2 = optab4->handlers[(int) intermediate_mode].insn_code)
- == CODE_FOR_nothing)
+ || ((icode1 = optab_handler (optab3, intermediate_mode))
+ == CODE_FOR_nothing)
+ || ((icode2 = optab_handler (optab4, intermediate_mode))
+ == CODE_FOR_nothing))
return false;
VEC_quick_push (tree, *interm_types, intermediate_type);
Check whether an operation represented by the code CODE is a
narrowing operation that is supported by the target platform in
- vector form (i.e., when operating on arguments of type VECTYPE).
+ vector form (i.e., when operating on arguments of type VECTYPE_IN
+ and producing a result of type VECTYPE_OUT).
Narrowing operations we currently support are NOP (CONVERT) and
FIX_TRUNC. This function checks if these operations are supported by
bool
supportable_narrowing_operation (enum tree_code code,
- const_gimple stmt, tree vectype,
+ tree vectype_out, tree vectype_in,
enum tree_code *code1, int *multi_step_cvt,
VEC (tree, heap) **interm_types)
{
enum machine_mode vec_mode;
enum insn_code icode1;
optab optab1, interm_optab;
- tree type = gimple_expr_type (stmt);
- tree narrow_vectype = get_vectype_for_scalar_type (type);
+ tree vectype = vectype_in;
+ tree narrow_vectype = vectype_out;
enum tree_code c1;
tree intermediate_type, prev_type;
int i;
if (code == FIX_TRUNC_EXPR)
/* The signedness is determined from output operand. */
- optab1 = optab_for_tree_code (c1, type, optab_default);
+ optab1 = optab_for_tree_code (c1, vectype_out, optab_default);
else
optab1 = optab_for_tree_code (c1, vectype, optab_default);
return false;
vec_mode = TYPE_MODE (vectype);
- if ((icode1 = optab_handler (optab1, vec_mode)->insn_code)
- == CODE_FOR_nothing)
+ if ((icode1 = optab_handler (optab1, vec_mode)) == CODE_FOR_nothing)
return false;
/* Check if it's a multi-step conversion that can be done using intermediate
interm_optab = optab_for_tree_code (c1, intermediate_type,
optab_default);
if (!interm_optab
- || (icode1 = optab1->handlers[(int) prev_mode].insn_code)
- == CODE_FOR_nothing
+ || ((icode1 = optab_handler (optab1, prev_mode))
+ == CODE_FOR_nothing)
|| insn_data[icode1].operand[0].mode != intermediate_mode
- || (icode1
- = interm_optab->handlers[(int) intermediate_mode].insn_code)
- == CODE_FOR_nothing)
+ || ((icode1 = optab_handler (interm_optab, intermediate_mode))
+ == CODE_FOR_nothing))
return false;
VEC_quick_push (tree, *interm_types, intermediate_type);