X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Ftree-vect-generic.c;h=cb64065f2e84759b04dd7e6e62b82d6145f38155;hp=9919389dfc3f45a3bfed7d21d792a4f8078cd024;hb=70d2aaaa4527221ce952bdc3253a788be0d8c875;hpb=75a70cf95f65fe9204b15ad9aba31c571381d224 diff --git a/gcc/tree-vect-generic.c b/gcc/tree-vect-generic.c index 9919389dfc3..cb64065f2e8 100644 --- a/gcc/tree-vect-generic.c +++ b/gcc/tree-vect-generic.c @@ -1,18 +1,19 @@ /* Lower vector operations to scalar operations. - Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 + 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 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 COPYING3. If not see . */ @@ -22,12 +23,6 @@ along with GCC; see the file COPYING3. If not see #include "coretypes.h" #include "tree.h" #include "tm.h" -#include "rtl.h" -#include "expr.h" -#include "insn-codes.h" -#include "diagnostic.h" -#include "optabs.h" -#include "machmode.h" #include "langhooks.h" #include "tree-flow.h" #include "gimple.h" @@ -35,6 +30,14 @@ along with GCC; see the file COPYING3. If not see #include "tree-pass.h" #include "flags.h" #include "ggc.h" +#include "diagnostic.h" + +/* Need to include rtl.h, expr.h, etc. for optabs. */ +#include "expr.h" +#include "optabs.h" + + +static void expand_vector_operations_1 (gimple_stmt_iterator *); /* Build a constant of type TYPE, made of VALUE's bits replicated @@ -122,9 +125,35 @@ static tree do_binop (gimple_stmt_iterator *gsi, tree inner_type, tree a, tree b, tree bitpos, tree bitsize, enum tree_code code) { + if (TREE_CODE (TREE_TYPE (a)) == VECTOR_TYPE) + a = tree_vec_extract (gsi, inner_type, a, bitsize, bitpos); + if (TREE_CODE (TREE_TYPE (b)) == VECTOR_TYPE) + b = tree_vec_extract (gsi, inner_type, b, bitsize, bitpos); + return gimplify_build2 (gsi, code, inner_type, a, b); +} + +/* Construct expression (A[BITPOS] code B[BITPOS]) ? -1 : 0 + + INNER_TYPE is the type of A and B elements + + returned expression is of signed integer type with the + size equal to the size of INNER_TYPE. */ +static tree +do_compare (gimple_stmt_iterator *gsi, tree inner_type, tree a, tree b, + tree bitpos, tree bitsize, enum tree_code code) +{ + tree comp_type; + 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); + + comp_type = build_nonstandard_integer_type + (GET_MODE_BITSIZE (TYPE_MODE (inner_type)), 0); + + return gimplify_build3 (gsi, COND_EXPR, comp_type, + fold_build2 (code, boolean_type_node, a, b), + build_int_cst (comp_type, -1), + build_int_cst (comp_type, 0)); } /* Expand vector addition to scalars. This does bit twiddling @@ -208,10 +237,18 @@ expand_vector_piecewise (gimple_stmt_iterator *gsi, elem_op_func f, int delta = tree_low_cst (part_width, 1) / tree_low_cst (TYPE_SIZE (TREE_TYPE (type)), 1); int i; + location_t loc = gimple_location (gsi_stmt (*gsi)); + + if (types_compatible_p (gimple_expr_type (gsi_stmt (*gsi)), type)) + warning_at (loc, OPT_Wvector_operation_performance, + "vector operation will be expanded piecewise"); + else + warning_at (loc, OPT_Wvector_operation_performance, + "vector operation will be expanded in parallel"); 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); @@ -233,6 +270,7 @@ expand_vector_parallel (gimple_stmt_iterator *gsi, elem_op_func f, tree type, tree result, compute_type; enum machine_mode mode; int n_words = tree_low_cst (TYPE_SIZE_UNIT (type), 1) / UNITS_PER_WORD; + location_t loc = gimple_location (gsi_stmt (*gsi)); /* We have three strategies. If the type is already correct, just do the operation an element at a time. Else, if the vector is wider than @@ -257,6 +295,9 @@ expand_vector_parallel (gimple_stmt_iterator *gsi, elem_op_func f, tree type, 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 (gsi, compute_type, a, b, NULL_TREE, NULL_TREE, code); + warning_at (loc, OPT_Wvector_operation_performance, + "vector operation will be expanded with a " + "single scalar operation"); } return result; @@ -286,6 +327,73 @@ expand_vector_addition (gimple_stmt_iterator *gsi, 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; +} + +/* Try to expand vector comparison expression OP0 CODE OP1 by + querying optab if the following expression: + VEC_COND_EXPR< OP0 CODE OP1, {-1,...}, {0,...}> + can be expanded. */ +static tree +expand_vector_comparison (gimple_stmt_iterator *gsi, tree type, tree op0, + tree op1, enum tree_code code) +{ + tree t; + if (! expand_vec_cond_expr_p (type, TREE_TYPE (op0))) + t = expand_vector_piecewise (gsi, do_compare, type, + TREE_TYPE (TREE_TYPE (op0)), op0, op1, code); + else + t = NULL_TREE; + + return t; +} + static tree expand_vector_operation (gimple_stmt_iterator *gsi, tree type, tree compute_type, gimple assign, enum tree_code code) @@ -306,8 +414,8 @@ expand_vector_operation (gimple_stmt_iterator *gsi, tree type, tree compute_type case PLUS_EXPR: case MINUS_EXPR: if (!TYPE_OVERFLOW_TRAPS (type)) - return expand_vector_addition (gsi, do_binop, do_plus_minus, type, - gimple_assign_rhs1 (assign), + return expand_vector_addition (gsi, do_binop, do_plus_minus, type, + gimple_assign_rhs1 (assign), gimple_assign_rhs2 (assign), code); break; @@ -328,8 +436,27 @@ expand_vector_operation (gimple_stmt_iterator *gsi, tree type, tree compute_type case BIT_NOT_EXPR: return expand_vector_parallel (gsi, do_unop, type, gimple_assign_rhs1 (assign), - NULL_TREE, code); + NULL_TREE, code); + case EQ_EXPR: + case NE_EXPR: + case GT_EXPR: + case LT_EXPR: + case GE_EXPR: + case LE_EXPR: + case UNEQ_EXPR: + case UNGT_EXPR: + case UNLT_EXPR: + case UNGE_EXPR: + case UNLE_EXPR: + case LTGT_EXPR: + case ORDERED_EXPR: + case UNORDERED_EXPR: + { + tree rhs1 = gimple_assign_rhs1 (assign); + tree rhs2 = gimple_assign_rhs2 (assign); + return expand_vector_comparison (gsi, type, rhs1, rhs2, code); + } default: break; } @@ -344,13 +471,13 @@ expand_vector_operation (gimple_stmt_iterator *gsi, tree type, tree compute_type 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. - SATP is true for saturating fixed-point types. */ +/* Return a type for the widest vector mode whose components are of type + TYPE, or NULL_TREE if none is found. */ static tree -type_for_widest_vector_mode (enum machine_mode inner_mode, optab op, int satp) +type_for_widest_vector_mode (tree type, optab op) { + enum machine_mode inner_mode = TYPE_MODE (type); enum machine_mode best_mode = VOIDmode, mode; int best_nunits = 0; @@ -370,19 +497,232 @@ type_for_widest_vector_mode (enum machine_mode inner_mode, optab op, int satp) 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) return NULL_TREE; else + return build_vector_type_for_mode (type, best_mode); +} + + +/* Build a reference to the element of the vector VECT. Function + returns either the element itself, either BIT_FIELD_REF, or an + ARRAY_REF expression. + + GSI is requred to insert temporary variables while building a + refernece to the element of the vector VECT. + + PTMPVEC is a pointer to the temporary variable for caching + purposes. In case when PTMPVEC is NULL new temporary variable + will be created. */ +static tree +vector_element (gimple_stmt_iterator *gsi, tree vect, tree idx, tree *ptmpvec) +{ + tree vect_type, vect_elt_type; + gimple asgn; + tree tmpvec; + tree arraytype; + bool need_asgn = true; + unsigned int elements; + + vect_type = TREE_TYPE (vect); + vect_elt_type = TREE_TYPE (vect_type); + elements = TYPE_VECTOR_SUBPARTS (vect_type); + + if (TREE_CODE (idx) == INTEGER_CST) { - /* 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); + unsigned HOST_WIDE_INT index; - return lang_hooks.types.type_for_mode (best_mode, 1); + /* Given that we're about to compute a binary modulus, + we don't care about the high bits of the value. */ + index = TREE_INT_CST_LOW (idx); + if (!host_integerp (idx, 1) || index >= elements) + { + index &= elements - 1; + idx = build_int_cst (TREE_TYPE (idx), index); + } + + /* When lowering a vector statement sequence do some easy + simplification by looking through intermediate vector results. */ + if (TREE_CODE (vect) == SSA_NAME) + { + gimple def_stmt = SSA_NAME_DEF_STMT (vect); + if (is_gimple_assign (def_stmt) + && (gimple_assign_rhs_code (def_stmt) == VECTOR_CST + || gimple_assign_rhs_code (def_stmt) == CONSTRUCTOR)) + vect = gimple_assign_rhs1 (def_stmt); + } + + if (TREE_CODE (vect) == VECTOR_CST) + { + unsigned i; + tree vals = TREE_VECTOR_CST_ELTS (vect); + for (i = 0; vals; vals = TREE_CHAIN (vals), ++i) + if (i == index) + return TREE_VALUE (vals); + return build_zero_cst (vect_elt_type); + } + else if (TREE_CODE (vect) == CONSTRUCTOR) + { + unsigned i; + tree elt_i, elt_v; + + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (vect), i, elt_i, elt_v) + if (operand_equal_p (elt_i, idx, 0)) + return elt_v; + return build_zero_cst (vect_elt_type); + } + else + { + tree size = TYPE_SIZE (vect_elt_type); + tree pos = fold_build2 (MULT_EXPR, bitsizetype, bitsize_int (index), + size); + return fold_build3 (BIT_FIELD_REF, vect_elt_type, vect, size, pos); + } + } + + if (!ptmpvec) + tmpvec = create_tmp_var (vect_type, "vectmp"); + else if (!*ptmpvec) + tmpvec = *ptmpvec = create_tmp_var (vect_type, "vectmp"); + else + { + tmpvec = *ptmpvec; + need_asgn = false; + } + + if (need_asgn) + { + TREE_ADDRESSABLE (tmpvec) = 1; + asgn = gimple_build_assign (tmpvec, vect); + gsi_insert_before (gsi, asgn, GSI_SAME_STMT); + } + + arraytype = build_array_type_nelts (vect_elt_type, elements); + return build4 (ARRAY_REF, vect_elt_type, + build1 (VIEW_CONVERT_EXPR, arraytype, tmpvec), + idx, NULL_TREE, NULL_TREE); +} + +/* Check if VEC_PERM_EXPR within the given setting is supported + by hardware, or lower it piecewise. + + When VEC_PERM_EXPR has the same first and second operands: + VEC_PERM_EXPR the lowered version would be + {v0[mask[0]], v0[mask[1]], ...} + MASK and V0 must have the same number of elements. + + Otherwise VEC_PERM_EXPR is lowered to + {mask[0] < len(v0) ? v0[mask[0]] : v1[mask[0]], ...} + V0 and V1 must have the same type. MASK, V0, V1 must have the + same number of arguments. */ + +static void +lower_vec_perm (gimple_stmt_iterator *gsi) +{ + gimple stmt = gsi_stmt (*gsi); + tree mask = gimple_assign_rhs3 (stmt); + tree vec0 = gimple_assign_rhs1 (stmt); + tree vec1 = gimple_assign_rhs2 (stmt); + tree vect_type = TREE_TYPE (vec0); + tree mask_type = TREE_TYPE (mask); + tree vect_elt_type = TREE_TYPE (vect_type); + tree mask_elt_type = TREE_TYPE (mask_type); + unsigned int elements = TYPE_VECTOR_SUBPARTS (vect_type); + VEC(constructor_elt,gc) *v; + tree constr, t, si, i_val; + tree vec0tmp = NULL_TREE, vec1tmp = NULL_TREE, masktmp = NULL_TREE; + bool two_operand_p = !operand_equal_p (vec0, vec1, 0); + location_t loc = gimple_location (gsi_stmt (*gsi)); + unsigned i; + + if (TREE_CODE (mask) == VECTOR_CST) + { + unsigned char *sel_int = XALLOCAVEC (unsigned char, elements); + tree vals = TREE_VECTOR_CST_ELTS (mask); + + for (i = 0; i < elements; ++i, vals = TREE_CHAIN (vals)) + sel_int[i] = TREE_INT_CST_LOW (TREE_VALUE (vals)) & (2 * elements - 1); + + if (can_vec_perm_p (TYPE_MODE (vect_type), false, sel_int)) + return; + } + else if (can_vec_perm_p (TYPE_MODE (vect_type), true, NULL)) + return; + + warning_at (loc, OPT_Wvector_operation_performance, + "vector shuffling operation will be expanded piecewise"); + + v = VEC_alloc (constructor_elt, gc, elements); + for (i = 0; i < elements; i++) + { + si = size_int (i); + i_val = vector_element (gsi, mask, si, &masktmp); + + if (TREE_CODE (i_val) == INTEGER_CST) + { + unsigned HOST_WIDE_INT index; + + index = TREE_INT_CST_LOW (i_val); + if (!host_integerp (i_val, 1) || index >= elements) + i_val = build_int_cst (mask_elt_type, index & (elements - 1)); + + if (two_operand_p && (index & elements) != 0) + t = vector_element (gsi, vec1, i_val, &vec1tmp); + else + t = vector_element (gsi, vec0, i_val, &vec0tmp); + + t = force_gimple_operand_gsi (gsi, t, true, NULL_TREE, + true, GSI_SAME_STMT); + } + else + { + tree cond = NULL_TREE, v0_val; + + if (two_operand_p) + { + cond = fold_build2 (BIT_AND_EXPR, mask_elt_type, i_val, + build_int_cst (mask_elt_type, elements)); + cond = force_gimple_operand_gsi (gsi, cond, true, NULL_TREE, + true, GSI_SAME_STMT); + } + + i_val = fold_build2 (BIT_AND_EXPR, mask_elt_type, i_val, + build_int_cst (mask_elt_type, elements - 1)); + i_val = force_gimple_operand_gsi (gsi, i_val, true, NULL_TREE, + true, GSI_SAME_STMT); + + v0_val = vector_element (gsi, vec0, i_val, &vec0tmp); + v0_val = force_gimple_operand_gsi (gsi, v0_val, true, NULL_TREE, + true, GSI_SAME_STMT); + + if (two_operand_p) + { + tree v1_val; + + v1_val = vector_element (gsi, vec1, i_val, &vec1tmp); + v1_val = force_gimple_operand_gsi (gsi, v1_val, true, NULL_TREE, + true, GSI_SAME_STMT); + + cond = fold_build2 (EQ_EXPR, boolean_type_node, + cond, build_zero_cst (mask_elt_type)); + cond = fold_build3 (COND_EXPR, vect_elt_type, + cond, v0_val, v1_val); + t = force_gimple_operand_gsi (gsi, cond, true, NULL_TREE, + true, GSI_SAME_STMT); + } + else + t = v0_val; + } + + CONSTRUCTOR_APPEND_ELT (v, si, t); } + + constr = build_constructor (vect_type, v); + gimple_assign_set_rhs_from_tree (gsi, constr); + update_stmt (gsi_stmt (*gsi)); } /* Process one statement. If we identify a vector operation, expand it. */ @@ -394,7 +734,7 @@ expand_vector_operations_1 (gimple_stmt_iterator *gsi) 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; @@ -403,11 +743,17 @@ expand_vector_operations_1 (gimple_stmt_iterator *gsi) code = gimple_assign_rhs_code (stmt); rhs_class = get_gimple_rhs_class (code); + lhs = gimple_assign_lhs (stmt); + + if (code == VEC_PERM_EXPR) + { + lower_vec_perm (gsi); + return; + } if (rhs_class != GIMPLE_UNARY_RHS && rhs_class != GIMPLE_BINARY_RHS) return; - lhs = gimple_assign_lhs (stmt); rhs1 = gimple_assign_rhs1 (stmt); type = gimple_expr_type (stmt); if (rhs_class == GIMPLE_BINARY_RHS) @@ -416,12 +762,12 @@ expand_vector_operations_1 (gimple_stmt_iterator *gsi) if (TREE_CODE (type) != VECTOR_TYPE) return; - if (code == NOP_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. */ @@ -431,29 +777,53 @@ expand_vector_operations_1 (gimple_stmt_iterator *gsi) /* Choose between vector shift/rotate by vector and vector shift/rotate by scalar */ - if (code == LSHIFT_EXPR - || code == RSHIFT_EXPR + 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); + optab opv; + + /* Check whether we have vector {x,x,x,x} where x + could be a scalar variable or a constant. Transform + vector {x,x,x,x} ==> vector scalar. */ + if (VECTOR_INTEGER_TYPE_P (TREE_TYPE (rhs2))) + { + tree first; + gimple def_stmt; + + if ((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; + } + } + + opv = optab_for_tree_code (code, type, optab_vector); + if (VECTOR_INTEGER_TYPE_P (TREE_TYPE (rhs2))) + op = opv; 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); + op = optab_for_tree_code (code, type, optab_scalar); + + /* The rtl expander will expand vector/scalar as vector/vector + if necessary. Don't bother converting the stmt here. */ + if (optab_handler (op, TYPE_MODE (type)) == CODE_FOR_nothing + && optab_handler (opv, TYPE_MODE (type)) != CODE_FOR_nothing) + return; } } else op = optab_for_tree_code (code, type, optab_default); - /* For widening/narrowing vector operations, the relevant type is of the + /* 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 @@ -463,7 +833,9 @@ expand_vector_operations_1 (gimple_stmt_iterator *gsi) || code == VEC_UNPACK_LO_EXPR || code == VEC_PACK_TRUNC_EXPR || code == VEC_PACK_SAT_EXPR - || code == VEC_PACK_FIX_TRUNC_EXPR) + || code == VEC_PACK_FIX_TRUNC_EXPR + || code == VEC_WIDEN_LSHIFT_HI_EXPR + || code == VEC_WIDEN_LSHIFT_LO_EXPR) type = TREE_TYPE (rhs1); /* Optabs will try converting a negation into a subtraction, so @@ -476,13 +848,16 @@ expand_vector_operations_1 (gimple_stmt_iterator *gsi) /* For very wide vectors, try using a smaller vector mode. */ compute_type = type; - if (TYPE_MODE (type) == BLKmode && op) + if (!VECTOR_MODE_P (TYPE_MODE (type)) && op) { tree 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) - compute_type = vector_compute_type; + = type_for_widest_vector_mode (TREE_TYPE (type), op); + if (vector_compute_type != NULL_TREE + && (TYPE_VECTOR_SUBPARTS (vector_compute_type) + < TYPE_VECTOR_SUBPARTS (compute_type)) + && (optab_handler (op, TYPE_MODE (vector_compute_type)) + != CODE_FOR_nothing)) + compute_type = vector_compute_type; } /* If we are breaking a BLKmode vector into smaller pieces, @@ -491,14 +866,9 @@ expand_vector_operations_1 (gimple_stmt_iterator *gsi) if (compute_type == 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_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) + if (VECTOR_MODE_P (compute_mode) && 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. */ @@ -507,6 +877,11 @@ expand_vector_operations_1 (gimple_stmt_iterator *gsi) gcc_assert (code != VEC_LSHIFT_EXPR && code != VEC_RSHIFT_EXPR); new_rhs = expand_vector_operation (gsi, type, compute_type, stmt, code); + + /* Leave expression untouched for later expansion. */ + if (new_rhs == NULL_TREE) + return; + 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); @@ -515,17 +890,16 @@ expand_vector_operations_1 (gimple_stmt_iterator *gsi) 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)); } /* Use this to lower vector operations introduced by the vectorizer, if it may need the bit-twiddling tricks implemented in this file. */ static bool -gate_expand_vector_operations (void) +gate_expand_vector_operations_ssa (void) { - return flag_tree_vectorize != 0; + return optimize == 0; } static unsigned int @@ -533,56 +907,67 @@ expand_vector_operations (void) { 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 = +struct gimple_opt_pass pass_lower_vector = { { GIMPLE_PASS, "veclower", /* name */ - 0, /* gate */ + gate_expand_vector_operations_ssa, /* 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 */ + TODO_update_ssa /* todo_flags_finish */ + | TODO_verify_ssa + | TODO_verify_stmts | TODO_verify_flow + | TODO_cleanup_cfg } }; -struct gimple_opt_pass pass_lower_vector_ssa = +struct gimple_opt_pass pass_lower_vector_ssa = { { GIMPLE_PASS, "veclower2", /* name */ - gate_expand_vector_operations, /* gate */ + 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_update_ssa /* todo_flags_finish */ + TODO_update_ssa /* todo_flags_finish */ | TODO_verify_ssa | TODO_verify_stmts | TODO_verify_flow + | TODO_cleanup_cfg } };