X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Ftree-vect-generic.c;h=2bb71a137abc0ab618743bb5334ff823e03fc3f1;hp=2da1ed2e936d7ca97a134ec77898e7c73cc929fd;hb=e6db644e168e952eba485ba7727808b3d24d4335;hpb=0501cacc16fc60cbd753fe813a0b85696efbe408 diff --git a/gcc/tree-vect-generic.c b/gcc/tree-vect-generic.c index 2da1ed2e936..2bb71a137ab 100644 --- a/gcc/tree-vect-generic.c +++ b/gcc/tree-vect-generic.c @@ -1,22 +1,22 @@ /* Lower vector operations to scalar operations. - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 + 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 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 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, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +along with GCC; see the file COPYING3. If not see +. */ #include "config.h" #include "system.h" @@ -31,7 +31,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "machmode.h" #include "langhooks.h" #include "tree-flow.h" -#include "tree-gimple.h" +#include "gimple.h" #include "tree-iterator.h" #include "tree-pass.h" #include "flags.h" @@ -97,40 +97,35 @@ build_word_mode_vector_type (int nunits) return vector_last_type; } -typedef tree (*elem_op_func) (block_stmt_iterator *, +typedef tree (*elem_op_func) (gimple_stmt_iterator *, tree, tree, tree, tree, tree, enum tree_code); static inline tree -tree_vec_extract (block_stmt_iterator *bsi, tree type, +tree_vec_extract (gimple_stmt_iterator *gsi, tree type, tree t, tree bitsize, tree bitpos) { if (bitpos) - return gimplify_build3 (bsi, BIT_FIELD_REF, type, t, bitsize, bitpos); - - /* Build a conversion; VIEW_CONVERT_EXPR is very expensive unless T will - anyway be stored in memory, so prefer NOP_EXPR. */ - else if (TYPE_MODE (type) == BLKmode) - return gimplify_build1 (bsi, VIEW_CONVERT_EXPR, type, t); + return gimplify_build3 (gsi, BIT_FIELD_REF, type, t, bitsize, bitpos); else - return gimplify_build1 (bsi, NOP_EXPR, type, t); + return gimplify_build1 (gsi, VIEW_CONVERT_EXPR, type, t); } static tree -do_unop (block_stmt_iterator *bsi, tree inner_type, tree a, +do_unop (gimple_stmt_iterator *gsi, tree inner_type, tree a, tree b ATTRIBUTE_UNUSED, tree bitpos, tree bitsize, enum tree_code code) { - a = tree_vec_extract (bsi, inner_type, a, bitsize, bitpos); - return gimplify_build1 (bsi, code, inner_type, a); + a = tree_vec_extract (gsi, inner_type, a, bitsize, bitpos); + return gimplify_build1 (gsi, code, inner_type, a); } static tree -do_binop (block_stmt_iterator *bsi, tree inner_type, tree a, tree b, +do_binop (gimple_stmt_iterator *gsi, tree inner_type, tree a, tree b, tree bitpos, tree bitsize, enum tree_code code) { - a = tree_vec_extract (bsi, inner_type, a, bitsize, bitpos); - b = tree_vec_extract (bsi, inner_type, b, bitsize, bitpos); - return gimplify_build2 (bsi, code, inner_type, a, b); + a = tree_vec_extract (gsi, inner_type, a, bitsize, bitpos); + b = tree_vec_extract (gsi, inner_type, b, bitsize, bitpos); + return gimplify_build2 (gsi, code, inner_type, a, b); } /* Expand vector addition to scalars. This does bit twiddling @@ -147,7 +142,7 @@ do_binop (block_stmt_iterator *bsi, tree inner_type, tree a, tree b, This optimization should be done only if 4 vector items or more fit into a word. */ static tree -do_plus_minus (block_stmt_iterator *bsi, tree word_type, tree a, tree b, +do_plus_minus (gimple_stmt_iterator *gsi, tree word_type, tree a, tree b, tree bitpos ATTRIBUTE_UNUSED, tree bitsize ATTRIBUTE_UNUSED, enum tree_code code) { @@ -159,26 +154,26 @@ do_plus_minus (block_stmt_iterator *bsi, tree word_type, tree a, tree b, low_bits = build_replicated_const (word_type, inner_type, max >> 1); high_bits = build_replicated_const (word_type, inner_type, max & ~(max >> 1)); - a = tree_vec_extract (bsi, word_type, a, bitsize, bitpos); - b = tree_vec_extract (bsi, word_type, b, bitsize, bitpos); + a = tree_vec_extract (gsi, word_type, a, bitsize, bitpos); + b = tree_vec_extract (gsi, word_type, b, bitsize, bitpos); - signs = gimplify_build2 (bsi, BIT_XOR_EXPR, word_type, a, b); - b_low = gimplify_build2 (bsi, BIT_AND_EXPR, word_type, b, low_bits); + signs = gimplify_build2 (gsi, BIT_XOR_EXPR, word_type, a, b); + b_low = gimplify_build2 (gsi, BIT_AND_EXPR, word_type, b, low_bits); if (code == PLUS_EXPR) - a_low = gimplify_build2 (bsi, BIT_AND_EXPR, word_type, a, low_bits); + a_low = gimplify_build2 (gsi, BIT_AND_EXPR, word_type, a, low_bits); else { - a_low = gimplify_build2 (bsi, BIT_IOR_EXPR, word_type, a, high_bits); - signs = gimplify_build1 (bsi, BIT_NOT_EXPR, word_type, signs); + a_low = gimplify_build2 (gsi, BIT_IOR_EXPR, word_type, a, high_bits); + signs = gimplify_build1 (gsi, BIT_NOT_EXPR, word_type, signs); } - signs = gimplify_build2 (bsi, BIT_AND_EXPR, word_type, signs, high_bits); - result_low = gimplify_build2 (bsi, code, word_type, a_low, b_low); - return gimplify_build2 (bsi, BIT_XOR_EXPR, word_type, result_low, signs); + signs = gimplify_build2 (gsi, BIT_AND_EXPR, word_type, signs, high_bits); + result_low = gimplify_build2 (gsi, code, word_type, a_low, b_low); + return gimplify_build2 (gsi, BIT_XOR_EXPR, word_type, result_low, signs); } static tree -do_negate (block_stmt_iterator *bsi, tree word_type, tree b, +do_negate (gimple_stmt_iterator *gsi, tree word_type, tree b, tree unused ATTRIBUTE_UNUSED, tree bitpos ATTRIBUTE_UNUSED, tree bitsize ATTRIBUTE_UNUSED, enum tree_code code ATTRIBUTE_UNUSED) @@ -191,23 +186,23 @@ do_negate (block_stmt_iterator *bsi, tree word_type, tree b, low_bits = build_replicated_const (word_type, inner_type, max >> 1); high_bits = build_replicated_const (word_type, inner_type, max & ~(max >> 1)); - b = tree_vec_extract (bsi, word_type, b, bitsize, bitpos); + b = tree_vec_extract (gsi, word_type, b, bitsize, bitpos); - b_low = gimplify_build2 (bsi, BIT_AND_EXPR, word_type, b, low_bits); - signs = gimplify_build1 (bsi, BIT_NOT_EXPR, word_type, b); - signs = gimplify_build2 (bsi, BIT_AND_EXPR, word_type, signs, high_bits); - result_low = gimplify_build2 (bsi, MINUS_EXPR, word_type, high_bits, b_low); - return gimplify_build2 (bsi, BIT_XOR_EXPR, word_type, result_low, signs); + b_low = gimplify_build2 (gsi, BIT_AND_EXPR, word_type, b, low_bits); + signs = gimplify_build1 (gsi, BIT_NOT_EXPR, word_type, b); + signs = gimplify_build2 (gsi, BIT_AND_EXPR, word_type, signs, high_bits); + result_low = gimplify_build2 (gsi, MINUS_EXPR, word_type, high_bits, b_low); + return gimplify_build2 (gsi, BIT_XOR_EXPR, word_type, result_low, signs); } /* Expand a vector operation to scalars, by using many operations whose type is the vector type's inner type. */ static tree -expand_vector_piecewise (block_stmt_iterator *bsi, elem_op_func f, +expand_vector_piecewise (gimple_stmt_iterator *gsi, elem_op_func f, tree type, tree inner_type, tree a, tree b, enum tree_code code) { - tree head, *chain = &head; + VEC(constructor_elt,gc) *v; tree part_width = TYPE_SIZE (inner_type); tree index = bitsize_int (0); int nunits = TYPE_VECTOR_SUBPARTS (type); @@ -215,22 +210,24 @@ expand_vector_piecewise (block_stmt_iterator *bsi, elem_op_func f, / tree_low_cst (TYPE_SIZE (TREE_TYPE (type)), 1); int i; + 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)) { - tree result = f (bsi, inner_type, a, b, index, part_width, code); - *chain = tree_cons (NULL_TREE, result, NULL_TREE); - chain = &TREE_CHAIN (*chain); + tree result = f (gsi, inner_type, a, b, index, part_width, code); + constructor_elt *ce = VEC_quick_push (constructor_elt, v, NULL); + ce->index = NULL_TREE; + ce->value = result; } - return build1 (CONSTRUCTOR, type, head); + return build_constructor (type, v); } /* Expand a vector operation to scalars with the freedom to use a scalar integer type, or to use a different size for the items in the vector type. */ static tree -expand_vector_parallel (block_stmt_iterator *bsi, elem_op_func f, tree type, +expand_vector_parallel (gimple_stmt_iterator *gsi, elem_op_func f, tree type, tree a, tree b, enum tree_code code) { @@ -243,23 +240,24 @@ expand_vector_parallel (block_stmt_iterator *bsi, elem_op_func f, tree type, one word, do it a word at a time; finally, if the vector is smaller than one word, do it as a scalar. */ if (TYPE_MODE (TREE_TYPE (type)) == word_mode) - return expand_vector_piecewise (bsi, f, + return expand_vector_piecewise (gsi, f, type, TREE_TYPE (type), a, b, code); else if (n_words > 1) { tree word_type = build_word_mode_vector_type (n_words); - result = expand_vector_piecewise (bsi, f, + result = expand_vector_piecewise (gsi, f, word_type, TREE_TYPE (word_type), a, b, code); - result = gimplify_val (bsi, word_type, result); + result = force_gimple_operand_gsi (gsi, result, true, NULL, true, + GSI_SAME_STMT); } else { /* Use a single scalar operation with a mode no wider than word_mode. */ mode = mode_for_size (tree_low_cst (TYPE_SIZE (type), 1), MODE_INT, 0); compute_type = lang_hooks.types.type_for_mode (mode, 1); - result = f (bsi, compute_type, a, b, NULL_TREE, NULL_TREE, code); + result = f (gsi, compute_type, a, b, NULL_TREE, NULL_TREE, code); } return result; @@ -271,7 +269,7 @@ expand_vector_parallel (block_stmt_iterator *bsi, elem_op_func f, tree type, they can process at least four items, that is, only if the vector holds at least four items and if a word can hold four items. */ static tree -expand_vector_addition (block_stmt_iterator *bsi, +expand_vector_addition (gimple_stmt_iterator *gsi, elem_op_func f, elem_op_func f_parallel, tree type, tree a, tree b, enum tree_code code) { @@ -281,17 +279,17 @@ expand_vector_addition (block_stmt_iterator *bsi, if (INTEGRAL_TYPE_P (TREE_TYPE (type)) && parts_per_word >= 4 && TYPE_VECTOR_SUBPARTS (type) >= 4) - return expand_vector_parallel (bsi, f_parallel, + return expand_vector_parallel (gsi, f_parallel, type, a, b, code); else - return expand_vector_piecewise (bsi, f, + return expand_vector_piecewise (gsi, f, type, TREE_TYPE (type), a, b, code); } static tree -expand_vector_operation (block_stmt_iterator *bsi, tree type, tree compute_type, - tree rhs, enum tree_code code) +expand_vector_operation (gimple_stmt_iterator *gsi, tree type, tree compute_type, + gimple assign, enum tree_code code) { enum machine_mode compute_mode = TYPE_MODE (compute_type); @@ -299,34 +297,38 @@ expand_vector_operation (block_stmt_iterator *bsi, tree type, tree compute_type, 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)) - return expand_vector_addition (bsi, do_binop, do_plus_minus, type, - TREE_OPERAND (rhs, 0), - TREE_OPERAND (rhs, 1), code); + if (!TYPE_OVERFLOW_TRAPS (type)) + return expand_vector_addition (gsi, do_binop, do_plus_minus, type, + gimple_assign_rhs1 (assign), + gimple_assign_rhs2 (assign), code); break; case NEGATE_EXPR: - if (!TYPE_TRAP_SIGNED (type)) - return expand_vector_addition (bsi, do_unop, do_negate, type, - TREE_OPERAND (rhs, 0), + if (!TYPE_OVERFLOW_TRAPS (type)) + return expand_vector_addition (gsi, do_unop, do_negate, type, + gimple_assign_rhs1 (assign), NULL_TREE, code); break; case BIT_AND_EXPR: case BIT_IOR_EXPR: case BIT_XOR_EXPR: - return expand_vector_parallel (bsi, do_binop, type, - TREE_OPERAND (rhs, 0), - TREE_OPERAND (rhs, 1), code); + return expand_vector_parallel (gsi, do_binop, type, + gimple_assign_rhs1 (assign), + gimple_assign_rhs2 (assign), code); case BIT_NOT_EXPR: - return expand_vector_parallel (bsi, do_unop, type, - TREE_OPERAND (rhs, 0), + return expand_vector_parallel (gsi, do_unop, type, + gimple_assign_rhs1 (assign), NULL_TREE, code); default: @@ -334,85 +336,136 @@ expand_vector_operation (block_stmt_iterator *bsi, tree type, tree compute_type, } if (TREE_CODE_CLASS (code) == tcc_unary) - return expand_vector_piecewise (bsi, do_unop, type, compute_type, - TREE_OPERAND (rhs, 0), + return expand_vector_piecewise (gsi, do_unop, type, compute_type, + gimple_assign_rhs1 (assign), NULL_TREE, code); else - return expand_vector_piecewise (bsi, do_binop, type, compute_type, - TREE_OPERAND (rhs, 0), - TREE_OPERAND (rhs, 1), code); + return expand_vector_piecewise (gsi, do_binop, type, compute_type, + gimple_assign_rhs1 (assign), + gimple_assign_rhs2 (assign), code); } /* 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 (GET_MODE_CLASS (inner_mode) == MODE_FLOAT) + 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. */ static void -expand_vector_operations_1 (block_stmt_iterator *bsi) +expand_vector_operations_1 (gimple_stmt_iterator *gsi) { - tree stmt = bsi_stmt (*bsi); - tree *p_lhs, *p_rhs, lhs, rhs, type, compute_type; + gimple stmt = gsi_stmt (*gsi); + tree lhs, rhs1, rhs2 = NULL, type, compute_type; enum tree_code code; enum machine_mode compute_mode; optab op; + enum gimple_rhs_class rhs_class; + tree new_rhs; - switch (TREE_CODE (stmt)) - { - case RETURN_EXPR: - stmt = TREE_OPERAND (stmt, 0); - if (!stmt || TREE_CODE (stmt) != MODIFY_EXPR) - return; + if (gimple_code (stmt) != GIMPLE_ASSIGN) + return; - /* FALLTHRU */ + code = gimple_assign_rhs_code (stmt); + rhs_class = get_gimple_rhs_class (code); - case MODIFY_EXPR: - p_lhs = &TREE_OPERAND (stmt, 0); - p_rhs = &TREE_OPERAND (stmt, 1); - lhs = *p_lhs; - rhs = *p_rhs; - break; + if (rhs_class != GIMPLE_UNARY_RHS && rhs_class != GIMPLE_BINARY_RHS) + return; - default: - return; - } + lhs = gimple_assign_lhs (stmt); + rhs1 = gimple_assign_rhs1 (stmt); + type = gimple_expr_type (stmt); + if (rhs_class == GIMPLE_BINARY_RHS) + rhs2 = gimple_assign_rhs2 (stmt); - type = TREE_TYPE (rhs); if (TREE_CODE (type) != VECTOR_TYPE) return; - code = TREE_CODE (rhs); - if (TREE_CODE_CLASS (code) != tcc_unary - && TREE_CODE_CLASS (code) != tcc_binary) + if (code == NOP_EXPR + || code == FLOAT_EXPR + || code == FIX_TRUNC_EXPR + || code == VIEW_CONVERT_EXPR) return; - if (code == NOP_EXPR || code == VIEW_CONVERT_EXPR) - return; - gcc_assert (code != CONVERT_EXPR); - op = optab_for_tree_code (code, type); + + /* The signedness is determined from input argument. */ + if (code == VEC_UNPACK_FLOAT_HI_EXPR + || code == VEC_UNPACK_FLOAT_LO_EXPR) + type = TREE_TYPE (rhs1); + + /* Choose between vector shift/rotate by vector and vector shift/rotate by + scalar */ + if (code == LSHIFT_EXPR + || code == RSHIFT_EXPR + || code == LROTATE_EXPR + || code == RROTATE_EXPR) + { + /* If the 2nd argument is vector, we need a vector/vector shift */ + if (VECTOR_MODE_P (TYPE_MODE (TREE_TYPE (rhs2)))) + op = optab_for_tree_code (code, type, optab_vector); + else + { + /* 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); + } + } + else + op = optab_for_tree_code (code, type, optab_default); + + /* For widening/narrowing vector operations, the relevant type is of the + 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_TRUNC_EXPR + || code == VEC_PACK_SAT_EXPR + || code == VEC_PACK_FIX_TRUNC_EXPR) + type = TREE_TYPE (rhs1); /* Optabs will try converting a negation into a subtraction, so look for it as well. TODO: negation of floating-point vectors @@ -420,16 +473,19 @@ expand_vector_operations_1 (block_stmt_iterator *bsi) if (op == NULL && code == NEGATE_EXPR && INTEGRAL_TYPE_P (TREE_TYPE (type))) - op = optab_for_tree_code (MINUS_EXPR, type); + op = optab_for_tree_code (MINUS_EXPR, type, optab_default); /* For very wide vectors, try using a smaller vector mode. */ compute_type = type; if (TYPE_MODE (type) == BLKmode && op) { tree vector_compute_type - = type_for_widest_vector_mode (TYPE_MODE (TREE_TYPE (type)), op); - if (vector_compute_type != NULL_TREE) - compute_type = vector_compute_type; + = type_for_widest_vector_mode (TYPE_MODE (TREE_TYPE (type)), op, + TYPE_SATURATING (TREE_TYPE (type))); + if (vector_compute_type != NULL_TREE + && (TYPE_VECTOR_SUBPARTS (vector_compute_type) + < TYPE_VECTOR_SUBPARTS (compute_type))) + compute_type = vector_compute_type; } /* If we are breaking a BLKmode vector into smaller pieces, @@ -439,31 +495,31 @@ expand_vector_operations_1 (block_stmt_iterator *bsi) { 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. */ compute_type = TREE_TYPE (type); } - rhs = expand_vector_operation (bsi, type, compute_type, rhs, code); - if (lang_hooks.types_compatible_p (TREE_TYPE (lhs), TREE_TYPE (rhs))) - *p_rhs = rhs; - else - { - /* Build a conversion; VIEW_CONVERT_EXPR is very expensive unless T will - be stored in memory anyway, so prefer NOP_EXPR. We should also try - performing the VIEW_CONVERT_EXPR on the left side of the - assignment. */ - if (TYPE_MODE (TREE_TYPE (rhs)) == BLKmode) - *p_rhs = gimplify_build1 (bsi, VIEW_CONVERT_EXPR, TREE_TYPE (lhs), rhs); - else - *p_rhs = gimplify_build1 (bsi, NOP_EXPR, TREE_TYPE (lhs), rhs); - } + gcc_assert (code != VEC_LSHIFT_EXPR && code != VEC_RSHIFT_EXPR); + new_rhs = expand_vector_operation (gsi, type, compute_type, stmt, code); + if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (new_rhs))) + new_rhs = gimplify_build1 (gsi, VIEW_CONVERT_EXPR, TREE_TYPE (lhs), + new_rhs); + + /* NOTE: We should avoid using gimple_assign_set_rhs_from_tree. One + 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); - mark_stmt_modified (bsi_stmt (*bsi)); + gimple_set_modified (gsi_stmt (*gsi), true); } /* Use this to lower vector operations introduced by the vectorizer, @@ -475,57 +531,62 @@ gate_expand_vector_operations (void) return flag_tree_vectorize != 0; } -static void +static unsigned int expand_vector_operations (void) { - block_stmt_iterator bsi; + gimple_stmt_iterator gsi; basic_block bb; FOR_EACH_BB (bb) { - for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { - expand_vector_operations_1 (&bsi); - update_stmt_if_modified (bsi_stmt (bsi)); + expand_vector_operations_1 (&gsi); + update_stmt_if_modified (gsi_stmt (gsi)); } } + 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 */ NULL, /* sub */ NULL, /* next */ 0, /* static_pass_number */ - 0, /* tv_id */ + TV_NONE, /* tv_id */ PROP_cfg, /* properties_required */ 0, /* properties_provided */ 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 */ NULL, /* sub */ NULL, /* next */ 0, /* static_pass_number */ - 0, /* tv_id */ + TV_NONE, /* tv_id */ PROP_cfg, /* properties_required */ 0, /* properties_provided */ 0, /* properties_destroyed */ 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"