/* Lower vector operations to scalar operations.
- Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009
+ Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010
Free Software Foundation, Inc.
This file is part of GCC.
v = VEC_alloc(constructor_elt, gc, (nunits + delta - 1) / delta);
for (i = 0; i < nunits;
- i += delta, index = int_const_binop (PLUS_EXPR, index, part_width, 0))
+ i += delta, index = int_const_binop (PLUS_EXPR, index, part_width))
{
tree result = f (gsi, inner_type, a, b, index, part_width, code);
constructor_elt *ce = VEC_quick_push (constructor_elt, v, NULL);
a, b, code);
}
+/* Check if vector VEC consists of all the equal elements and
+ that the number of elements corresponds to the type of VEC.
+ The function returns first element of the vector
+ or NULL_TREE if the vector is not uniform. */
+static tree
+uniform_vector_p (tree vec)
+{
+ tree first, t, els;
+ unsigned i;
+
+ if (vec == NULL_TREE)
+ return NULL_TREE;
+
+ if (TREE_CODE (vec) == VECTOR_CST)
+ {
+ els = TREE_VECTOR_CST_ELTS (vec);
+ first = TREE_VALUE (els);
+ els = TREE_CHAIN (els);
+
+ for (t = els; t; t = TREE_CHAIN (t))
+ if (!operand_equal_p (first, TREE_VALUE (t), 0))
+ return NULL_TREE;
+
+ return first;
+ }
+
+ else if (TREE_CODE (vec) == CONSTRUCTOR)
+ {
+ first = error_mark_node;
+
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (vec), i, t)
+ {
+ if (i == 0)
+ {
+ first = t;
+ continue;
+ }
+ if (!operand_equal_p (first, t, 0))
+ return NULL_TREE;
+ }
+ if (i != TYPE_VECTOR_SUBPARTS (TREE_TYPE (vec)))
+ return NULL_TREE;
+
+ return first;
+ }
+
+ return NULL_TREE;
+}
+
static tree
expand_vector_operation (gimple_stmt_iterator *gsi, tree type, tree compute_type,
gimple assign, enum tree_code code)
for (; mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode))
if (GET_MODE_INNER (mode) == inner_mode
&& GET_MODE_NUNITS (mode) > best_nunits
- && optab_handler (op, mode)->insn_code != CODE_FOR_nothing)
+ && optab_handler (op, mode) != CODE_FOR_nothing)
best_mode = mode, best_nunits = GET_MODE_NUNITS (mode);
if (best_mode == VOIDmode)
tree lhs, rhs1, rhs2 = NULL, type, compute_type;
enum tree_code code;
enum machine_mode compute_mode;
- optab op;
+ optab op = NULL;
enum gimple_rhs_class rhs_class;
tree new_rhs;
|| code == LROTATE_EXPR
|| code == RROTATE_EXPR)
{
- /* If the 2nd argument is vector, we need a vector/vector shift */
+ bool vector_scalar_shift;
+ op = optab_for_tree_code (code, type, optab_scalar);
+
+ /* Vector/Scalar shift is supported. */
+ vector_scalar_shift = (op && (optab_handler (op, TYPE_MODE (type))
+ != CODE_FOR_nothing));
+
+ /* If the 2nd argument is vector, we need a vector/vector shift.
+ Except all the elements in the second vector are the same. */
if (VECTOR_MODE_P (TYPE_MODE (TREE_TYPE (rhs2))))
- op = optab_for_tree_code (code, type, optab_vector);
- else
+ {
+ tree first;
+ gimple def_stmt;
+
+ /* Check whether we have vector <op> {x,x,x,x} where x
+ could be a scalar variable or a constant. Transform
+ vector <op> {x,x,x,x} ==> vector <op> scalar. */
+ if (vector_scalar_shift
+ && ((TREE_CODE (rhs2) == VECTOR_CST
+ && (first = uniform_vector_p (rhs2)) != NULL_TREE)
+ || (TREE_CODE (rhs2) == SSA_NAME
+ && (def_stmt = SSA_NAME_DEF_STMT (rhs2))
+ && gimple_assign_single_p (def_stmt)
+ && (first = uniform_vector_p
+ (gimple_assign_rhs1 (def_stmt))) != NULL_TREE)))
+ {
+ gimple_assign_set_rhs2 (stmt, first);
+ update_stmt (stmt);
+ rhs2 = first;
+ }
+ else
+ op = optab_for_tree_code (code, type, optab_vector);
+ }
+
+ /* Try for a vector/scalar shift, and if we don't have one, see if we
+ have a vector/vector shift */
+ else if (!vector_scalar_shift)
{
- /* Try for a vector/scalar shift, and if we don't have one, see if we
- have a vector/vector shift */
- op = optab_for_tree_code (code, type, optab_scalar);
- if (!op
- || (op->handlers[(int) TYPE_MODE (type)].insn_code
- == CODE_FOR_nothing))
- op = optab_for_tree_code (code, type, optab_vector);
+ op = optab_for_tree_code (code, type, optab_vector);
+
+ if (op && (optab_handler (op, TYPE_MODE (type))
+ != CODE_FOR_nothing))
+ {
+ /* Transform vector <op> scalar => vector <op> {x,x,x,x}. */
+ int n_parts = TYPE_VECTOR_SUBPARTS (type);
+ int part_size = tree_low_cst (TYPE_SIZE (TREE_TYPE (type)), 1);
+ tree part_type = lang_hooks.types.type_for_size (part_size, 1);
+ tree vect_type = build_vector_type (part_type, n_parts);
+
+ rhs2 = fold_convert (part_type, rhs2);
+ rhs2 = build_vector_from_val (vect_type, rhs2);
+ gimple_assign_set_rhs2 (stmt, rhs2);
+ update_stmt (stmt);
+ }
}
}
else
|| GET_MODE_CLASS (compute_mode) == MODE_VECTOR_ACCUM
|| GET_MODE_CLASS (compute_mode) == MODE_VECTOR_UACCUM)
&& op != NULL
- && optab_handler (op, compute_mode)->insn_code != CODE_FOR_nothing)
+ && optab_handler (op, compute_mode) != CODE_FOR_nothing)
return;
else
/* There is no operation in hardware, so fall back to scalars. */
way to do it is change expand_vector_operation and its callees to
return a tree_code, RHS1 and RHS2 instead of a tree. */
gimple_assign_set_rhs_from_tree (gsi, new_rhs);
-
- gimple_set_modified (gsi_stmt (*gsi), true);
+ update_stmt (gsi_stmt (*gsi));
}
\f
/* Use this to lower vector operations introduced by the vectorizer,
{
gimple_stmt_iterator gsi;
basic_block bb;
+ bool cfg_changed = false;
FOR_EACH_BB (bb)
{
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
expand_vector_operations_1 (&gsi);
- update_stmt_if_modified (gsi_stmt (gsi));
+ /* ??? If we do not cleanup EH then we will ICE in
+ verification. But in reality we have created wrong-code
+ as we did not properly transition EH info and edges to
+ the piecewise computations. */
+ if (maybe_clean_eh_stmt (gsi_stmt (gsi))
+ && gimple_purge_dead_eh_edges (bb))
+ cfg_changed = true;
}
}
- return 0;
+
+ return cfg_changed ? TODO_cleanup_cfg : 0;
}
struct gimple_opt_pass pass_lower_vector =
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_func | TODO_ggc_collect
- | TODO_verify_stmts /* todo_flags_finish */
+ TODO_dump_func | TODO_update_ssa /* todo_flags_finish */
+ | TODO_verify_ssa
+ | TODO_verify_stmts | TODO_verify_flow
}
};