/* Lower vector operations to scalar operations.
- Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
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 2, or (at your option) any
+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
for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
a BLKmode vector to smaller, hardware-supported vectors), we may want
to expand the operations in parallel. */
if (GET_MODE_CLASS (compute_mode) != MODE_VECTOR_INT
- && GET_MODE_CLASS (compute_mode) != MODE_VECTOR_FLOAT)
+ && GET_MODE_CLASS (compute_mode) != MODE_VECTOR_FLOAT
+ && GET_MODE_CLASS (compute_mode) != MODE_VECTOR_FRACT
+ && GET_MODE_CLASS (compute_mode) != MODE_VECTOR_UFRACT
+ && GET_MODE_CLASS (compute_mode) != MODE_VECTOR_ACCUM
+ && GET_MODE_CLASS (compute_mode) != MODE_VECTOR_UACCUM)
switch (code)
{
case PLUS_EXPR:
case MINUS_EXPR:
- if (!TYPE_TRAP_SIGNED (type))
+ if (!TYPE_OVERFLOW_TRAPS (type))
return expand_vector_addition (bsi, do_binop, do_plus_minus, type,
TREE_OPERAND (rhs, 0),
TREE_OPERAND (rhs, 1), code);
break;
case NEGATE_EXPR:
- if (!TYPE_TRAP_SIGNED (type))
+ if (!TYPE_OVERFLOW_TRAPS (type))
return expand_vector_addition (bsi, do_unop, do_negate, type,
TREE_OPERAND (rhs, 0),
NULL_TREE, code);
}
\f
/* Return a type for the widest vector mode whose components are of mode
- INNER_MODE, or NULL_TREE if none is found. */
+ INNER_MODE, or NULL_TREE if none is found.
+ SATP is true for saturating fixed-point types. */
+
static tree
-type_for_widest_vector_mode (enum machine_mode inner_mode, optab op)
+type_for_widest_vector_mode (enum machine_mode inner_mode, optab op, int satp)
{
enum machine_mode best_mode = VOIDmode, mode;
int best_nunits = 0;
if (SCALAR_FLOAT_MODE_P (inner_mode))
mode = MIN_MODE_VECTOR_FLOAT;
+ else if (SCALAR_FRACT_MODE_P (inner_mode))
+ mode = MIN_MODE_VECTOR_FRACT;
+ else if (SCALAR_UFRACT_MODE_P (inner_mode))
+ mode = MIN_MODE_VECTOR_UFRACT;
+ else if (SCALAR_ACCUM_MODE_P (inner_mode))
+ mode = MIN_MODE_VECTOR_ACCUM;
+ else if (SCALAR_UACCUM_MODE_P (inner_mode))
+ mode = MIN_MODE_VECTOR_UACCUM;
else
mode = MIN_MODE_VECTOR_INT;
for (; mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode))
if (GET_MODE_INNER (mode) == inner_mode
&& GET_MODE_NUNITS (mode) > best_nunits
- && op->handlers[mode].insn_code != CODE_FOR_nothing)
+ && optab_handler (op, mode)->insn_code != CODE_FOR_nothing)
best_mode = mode, best_nunits = GET_MODE_NUNITS (mode);
if (best_mode == VOIDmode)
return NULL_TREE;
else
- return lang_hooks.types.type_for_mode (best_mode, 1);
+ {
+ /* For fixed-point modes, we need to pass satp as the 2nd parameter. */
+ if (ALL_FIXED_POINT_MODE_P (best_mode))
+ return lang_hooks.types.type_for_mode (best_mode, satp);
+
+ return lang_hooks.types.type_for_mode (best_mode, 1);
+ }
}
/* Process one statement. If we identify a vector operation, expand it. */
{
case RETURN_EXPR:
stmt = TREE_OPERAND (stmt, 0);
- if (!stmt || TREE_CODE (stmt) != MODIFY_EXPR)
+ if (!stmt || TREE_CODE (stmt) != GIMPLE_MODIFY_STMT)
return;
/* FALLTHRU */
- case MODIFY_EXPR:
- p_lhs = &TREE_OPERAND (stmt, 0);
- p_rhs = &TREE_OPERAND (stmt, 1);
+ case GIMPLE_MODIFY_STMT:
+ p_lhs = &GIMPLE_STMT_OPERAND (stmt, 0);
+ p_rhs = &GIMPLE_STMT_OPERAND (stmt, 1);
lhs = *p_lhs;
rhs = *p_rhs;
break;
&& TREE_CODE_CLASS (code) != tcc_binary)
return;
- if (code == NOP_EXPR || code == VIEW_CONVERT_EXPR)
+ if (code == NOP_EXPR
+ || code == FLOAT_EXPR
+ || code == FIX_TRUNC_EXPR
+ || code == VIEW_CONVERT_EXPR)
return;
gcc_assert (code != CONVERT_EXPR);
+
+ /* The signedness is determined from input argument. */
+ if (code == VEC_UNPACK_FLOAT_HI_EXPR
+ || code == VEC_UNPACK_FLOAT_LO_EXPR)
+ type = TREE_TYPE (TREE_OPERAND (rhs, 0));
+
op = optab_for_tree_code (code, type);
/* For widening/narrowing vector operations, the relevant type is of the
- arguments, not the widened result. */
+ arguments, not the widened result. VEC_UNPACK_FLOAT_*_EXPR is
+ calculated in the same way above. */
if (code == WIDEN_SUM_EXPR
|| code == VEC_WIDEN_MULT_HI_EXPR
|| code == VEC_WIDEN_MULT_LO_EXPR
|| code == VEC_UNPACK_HI_EXPR
|| code == VEC_UNPACK_LO_EXPR
- || code == VEC_PACK_MOD_EXPR
- || code == VEC_PACK_SAT_EXPR)
+ || code == VEC_PACK_TRUNC_EXPR
+ || code == VEC_PACK_SAT_EXPR
+ || code == VEC_PACK_FIX_TRUNC_EXPR)
type = TREE_TYPE (TREE_OPERAND (rhs, 0));
/* Optabs will try converting a negation into a subtraction, so
if (TYPE_MODE (type) == BLKmode && op)
{
tree vector_compute_type
- = type_for_widest_vector_mode (TYPE_MODE (TREE_TYPE (type)), op);
+ = type_for_widest_vector_mode (TYPE_MODE (TREE_TYPE (type)), op,
+ TYPE_SATURATING (TREE_TYPE (type)));
if (vector_compute_type != NULL_TREE)
compute_type = vector_compute_type;
}
{
compute_mode = TYPE_MODE (compute_type);
if ((GET_MODE_CLASS (compute_mode) == MODE_VECTOR_INT
- || GET_MODE_CLASS (compute_mode) == MODE_VECTOR_FLOAT)
+ || GET_MODE_CLASS (compute_mode) == MODE_VECTOR_FLOAT
+ || GET_MODE_CLASS (compute_mode) == MODE_VECTOR_FRACT
+ || GET_MODE_CLASS (compute_mode) == MODE_VECTOR_UFRACT
+ || GET_MODE_CLASS (compute_mode) == MODE_VECTOR_ACCUM
+ || GET_MODE_CLASS (compute_mode) == MODE_VECTOR_UACCUM)
&& op != NULL
- && op->handlers[compute_mode].insn_code != CODE_FOR_nothing)
+ && optab_handler (op, compute_mode)->insn_code != CODE_FOR_nothing)
return;
else
/* There is no operation in hardware, so fall back to scalars. */
gcc_assert (code != VEC_LSHIFT_EXPR && code != VEC_RSHIFT_EXPR);
rhs = expand_vector_operation (bsi, type, compute_type, rhs, code);
- if (lang_hooks.types_compatible_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
+ if (useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
*p_rhs = rhs;
else
*p_rhs = gimplify_build1 (bsi, VIEW_CONVERT_EXPR, TREE_TYPE (lhs), rhs);
return 0;
}
-struct tree_opt_pass pass_lower_vector =
+struct gimple_opt_pass pass_lower_vector =
{
+ {
+ GIMPLE_PASS,
"veclower", /* name */
0, /* gate */
expand_vector_operations, /* execute */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func | TODO_ggc_collect
- | TODO_verify_stmts, /* todo_flags_finish */
- 0 /* letter */
+ | TODO_verify_stmts /* todo_flags_finish */
+ }
};
-struct tree_opt_pass pass_lower_vector_ssa =
+struct gimple_opt_pass pass_lower_vector_ssa =
{
+ {
+ GIMPLE_PASS,
"veclower2", /* name */
gate_expand_vector_operations, /* gate */
expand_vector_operations, /* execute */
0, /* todo_flags_start */
TODO_dump_func | TODO_update_ssa /* todo_flags_finish */
| TODO_verify_ssa
- | TODO_verify_stmts | TODO_verify_flow,
- 0 /* letter */
+ | TODO_verify_stmts | TODO_verify_flow
+ }
};
#include "gt-tree-vect-generic.h"