1169689Skan/* Lower vector operations to scalar operations. 2169689Skan Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc. 3169689Skan 4169689SkanThis file is part of GCC. 5169689Skan 6169689SkanGCC is free software; you can redistribute it and/or modify it 7169689Skanunder the terms of the GNU General Public License as published by the 8169689SkanFree Software Foundation; either version 2, or (at your option) any 9169689Skanlater version. 10169689Skan 11169689SkanGCC is distributed in the hope that it will be useful, but WITHOUT 12169689SkanANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13169689SkanFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14169689Skanfor more details. 15169689Skan 16169689SkanYou should have received a copy of the GNU General Public License 17169689Skanalong with GCC; see the file COPYING. If not, write to the Free 18169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 19169689Skan02110-1301, USA. */ 20169689Skan 21169689Skan#include "config.h" 22169689Skan#include "system.h" 23169689Skan#include "coretypes.h" 24169689Skan#include "tree.h" 25169689Skan#include "tm.h" 26169689Skan#include "rtl.h" 27169689Skan#include "expr.h" 28169689Skan#include "insn-codes.h" 29169689Skan#include "diagnostic.h" 30169689Skan#include "optabs.h" 31169689Skan#include "machmode.h" 32169689Skan#include "langhooks.h" 33169689Skan#include "tree-flow.h" 34169689Skan#include "tree-gimple.h" 35169689Skan#include "tree-iterator.h" 36169689Skan#include "tree-pass.h" 37169689Skan#include "flags.h" 38169689Skan#include "ggc.h" 39169689Skan 40169689Skan 41169689Skan/* Build a constant of type TYPE, made of VALUE's bits replicated 42169689Skan every TYPE_SIZE (INNER_TYPE) bits to fit TYPE's precision. */ 43169689Skanstatic tree 44169689Skanbuild_replicated_const (tree type, tree inner_type, HOST_WIDE_INT value) 45169689Skan{ 46169689Skan int width = tree_low_cst (TYPE_SIZE (inner_type), 1); 47169689Skan int n = HOST_BITS_PER_WIDE_INT / width; 48169689Skan unsigned HOST_WIDE_INT low, high, mask; 49169689Skan tree ret; 50169689Skan 51169689Skan gcc_assert (n); 52169689Skan 53169689Skan if (width == HOST_BITS_PER_WIDE_INT) 54169689Skan low = value; 55169689Skan else 56169689Skan { 57169689Skan mask = ((HOST_WIDE_INT)1 << width) - 1; 58169689Skan low = (unsigned HOST_WIDE_INT) ~0 / mask * (value & mask); 59169689Skan } 60169689Skan 61169689Skan if (TYPE_PRECISION (type) < HOST_BITS_PER_WIDE_INT) 62169689Skan low &= ((HOST_WIDE_INT)1 << TYPE_PRECISION (type)) - 1, high = 0; 63169689Skan else if (TYPE_PRECISION (type) == HOST_BITS_PER_WIDE_INT) 64169689Skan high = 0; 65169689Skan else if (TYPE_PRECISION (type) == 2 * HOST_BITS_PER_WIDE_INT) 66169689Skan high = low; 67169689Skan else 68169689Skan gcc_unreachable (); 69169689Skan 70169689Skan ret = build_int_cst_wide (type, low, high); 71169689Skan return ret; 72169689Skan} 73169689Skan 74169689Skanstatic GTY(()) tree vector_inner_type; 75169689Skanstatic GTY(()) tree vector_last_type; 76169689Skanstatic GTY(()) int vector_last_nunits; 77169689Skan 78169689Skan/* Return a suitable vector types made of SUBPARTS units each of mode 79169689Skan "word_mode" (the global variable). */ 80169689Skanstatic tree 81169689Skanbuild_word_mode_vector_type (int nunits) 82169689Skan{ 83169689Skan if (!vector_inner_type) 84169689Skan vector_inner_type = lang_hooks.types.type_for_mode (word_mode, 1); 85169689Skan else if (vector_last_nunits == nunits) 86169689Skan { 87169689Skan gcc_assert (TREE_CODE (vector_last_type) == VECTOR_TYPE); 88169689Skan return vector_last_type; 89169689Skan } 90169689Skan 91169689Skan /* We build a new type, but we canonicalize it nevertheless, 92169689Skan because it still saves some memory. */ 93169689Skan vector_last_nunits = nunits; 94169689Skan vector_last_type = type_hash_canon (nunits, 95169689Skan build_vector_type (vector_inner_type, 96169689Skan nunits)); 97169689Skan return vector_last_type; 98169689Skan} 99169689Skan 100169689Skantypedef tree (*elem_op_func) (block_stmt_iterator *, 101169689Skan tree, tree, tree, tree, tree, enum tree_code); 102169689Skan 103169689Skanstatic inline tree 104169689Skantree_vec_extract (block_stmt_iterator *bsi, tree type, 105169689Skan tree t, tree bitsize, tree bitpos) 106169689Skan{ 107169689Skan if (bitpos) 108169689Skan return gimplify_build3 (bsi, BIT_FIELD_REF, type, t, bitsize, bitpos); 109169689Skan else 110169689Skan return gimplify_build1 (bsi, VIEW_CONVERT_EXPR, type, t); 111169689Skan} 112169689Skan 113169689Skanstatic tree 114169689Skando_unop (block_stmt_iterator *bsi, tree inner_type, tree a, 115169689Skan tree b ATTRIBUTE_UNUSED, tree bitpos, tree bitsize, 116169689Skan enum tree_code code) 117169689Skan{ 118169689Skan a = tree_vec_extract (bsi, inner_type, a, bitsize, bitpos); 119169689Skan return gimplify_build1 (bsi, code, inner_type, a); 120169689Skan} 121169689Skan 122169689Skanstatic tree 123169689Skando_binop (block_stmt_iterator *bsi, tree inner_type, tree a, tree b, 124169689Skan tree bitpos, tree bitsize, enum tree_code code) 125169689Skan{ 126169689Skan a = tree_vec_extract (bsi, inner_type, a, bitsize, bitpos); 127169689Skan b = tree_vec_extract (bsi, inner_type, b, bitsize, bitpos); 128169689Skan return gimplify_build2 (bsi, code, inner_type, a, b); 129169689Skan} 130169689Skan 131169689Skan/* Expand vector addition to scalars. This does bit twiddling 132169689Skan in order to increase parallelism: 133169689Skan 134169689Skan a + b = (((int) a & 0x7f7f7f7f) + ((int) b & 0x7f7f7f7f)) ^ 135169689Skan (a ^ b) & 0x80808080 136169689Skan 137169689Skan a - b = (((int) a | 0x80808080) - ((int) b & 0x7f7f7f7f)) ^ 138169689Skan (a ^ ~b) & 0x80808080 139169689Skan 140169689Skan -b = (0x80808080 - ((int) b & 0x7f7f7f7f)) ^ (~b & 0x80808080) 141169689Skan 142169689Skan This optimization should be done only if 4 vector items or more 143169689Skan fit into a word. */ 144169689Skanstatic tree 145169689Skando_plus_minus (block_stmt_iterator *bsi, tree word_type, tree a, tree b, 146169689Skan tree bitpos ATTRIBUTE_UNUSED, tree bitsize ATTRIBUTE_UNUSED, 147169689Skan enum tree_code code) 148169689Skan{ 149169689Skan tree inner_type = TREE_TYPE (TREE_TYPE (a)); 150169689Skan unsigned HOST_WIDE_INT max; 151169689Skan tree low_bits, high_bits, a_low, b_low, result_low, signs; 152169689Skan 153169689Skan max = GET_MODE_MASK (TYPE_MODE (inner_type)); 154169689Skan low_bits = build_replicated_const (word_type, inner_type, max >> 1); 155169689Skan high_bits = build_replicated_const (word_type, inner_type, max & ~(max >> 1)); 156169689Skan 157169689Skan a = tree_vec_extract (bsi, word_type, a, bitsize, bitpos); 158169689Skan b = tree_vec_extract (bsi, word_type, b, bitsize, bitpos); 159169689Skan 160169689Skan signs = gimplify_build2 (bsi, BIT_XOR_EXPR, word_type, a, b); 161169689Skan b_low = gimplify_build2 (bsi, BIT_AND_EXPR, word_type, b, low_bits); 162169689Skan if (code == PLUS_EXPR) 163169689Skan a_low = gimplify_build2 (bsi, BIT_AND_EXPR, word_type, a, low_bits); 164169689Skan else 165169689Skan { 166169689Skan a_low = gimplify_build2 (bsi, BIT_IOR_EXPR, word_type, a, high_bits); 167169689Skan signs = gimplify_build1 (bsi, BIT_NOT_EXPR, word_type, signs); 168169689Skan } 169169689Skan 170169689Skan signs = gimplify_build2 (bsi, BIT_AND_EXPR, word_type, signs, high_bits); 171169689Skan result_low = gimplify_build2 (bsi, code, word_type, a_low, b_low); 172169689Skan return gimplify_build2 (bsi, BIT_XOR_EXPR, word_type, result_low, signs); 173169689Skan} 174169689Skan 175169689Skanstatic tree 176169689Skando_negate (block_stmt_iterator *bsi, tree word_type, tree b, 177169689Skan tree unused ATTRIBUTE_UNUSED, tree bitpos ATTRIBUTE_UNUSED, 178169689Skan tree bitsize ATTRIBUTE_UNUSED, 179169689Skan enum tree_code code ATTRIBUTE_UNUSED) 180169689Skan{ 181169689Skan tree inner_type = TREE_TYPE (TREE_TYPE (b)); 182169689Skan HOST_WIDE_INT max; 183169689Skan tree low_bits, high_bits, b_low, result_low, signs; 184169689Skan 185169689Skan max = GET_MODE_MASK (TYPE_MODE (inner_type)); 186169689Skan low_bits = build_replicated_const (word_type, inner_type, max >> 1); 187169689Skan high_bits = build_replicated_const (word_type, inner_type, max & ~(max >> 1)); 188169689Skan 189169689Skan b = tree_vec_extract (bsi, word_type, b, bitsize, bitpos); 190169689Skan 191169689Skan b_low = gimplify_build2 (bsi, BIT_AND_EXPR, word_type, b, low_bits); 192169689Skan signs = gimplify_build1 (bsi, BIT_NOT_EXPR, word_type, b); 193169689Skan signs = gimplify_build2 (bsi, BIT_AND_EXPR, word_type, signs, high_bits); 194169689Skan result_low = gimplify_build2 (bsi, MINUS_EXPR, word_type, high_bits, b_low); 195169689Skan return gimplify_build2 (bsi, BIT_XOR_EXPR, word_type, result_low, signs); 196169689Skan} 197169689Skan 198169689Skan/* Expand a vector operation to scalars, by using many operations 199169689Skan whose type is the vector type's inner type. */ 200169689Skanstatic tree 201169689Skanexpand_vector_piecewise (block_stmt_iterator *bsi, elem_op_func f, 202169689Skan tree type, tree inner_type, 203169689Skan tree a, tree b, enum tree_code code) 204169689Skan{ 205169689Skan VEC(constructor_elt,gc) *v; 206169689Skan tree part_width = TYPE_SIZE (inner_type); 207169689Skan tree index = bitsize_int (0); 208169689Skan int nunits = TYPE_VECTOR_SUBPARTS (type); 209169689Skan int delta = tree_low_cst (part_width, 1) 210169689Skan / tree_low_cst (TYPE_SIZE (TREE_TYPE (type)), 1); 211169689Skan int i; 212169689Skan 213169689Skan v = VEC_alloc(constructor_elt, gc, (nunits + delta - 1) / delta); 214169689Skan for (i = 0; i < nunits; 215169689Skan i += delta, index = int_const_binop (PLUS_EXPR, index, part_width, 0)) 216169689Skan { 217169689Skan tree result = f (bsi, inner_type, a, b, index, part_width, code); 218169689Skan constructor_elt *ce = VEC_quick_push (constructor_elt, v, NULL); 219169689Skan ce->index = NULL_TREE; 220169689Skan ce->value = result; 221169689Skan } 222169689Skan 223169689Skan return build_constructor (type, v); 224169689Skan} 225169689Skan 226169689Skan/* Expand a vector operation to scalars with the freedom to use 227169689Skan a scalar integer type, or to use a different size for the items 228169689Skan in the vector type. */ 229169689Skanstatic tree 230169689Skanexpand_vector_parallel (block_stmt_iterator *bsi, elem_op_func f, tree type, 231169689Skan tree a, tree b, 232169689Skan enum tree_code code) 233169689Skan{ 234169689Skan tree result, compute_type; 235169689Skan enum machine_mode mode; 236169689Skan int n_words = tree_low_cst (TYPE_SIZE_UNIT (type), 1) / UNITS_PER_WORD; 237169689Skan 238169689Skan /* We have three strategies. If the type is already correct, just do 239169689Skan the operation an element at a time. Else, if the vector is wider than 240169689Skan one word, do it a word at a time; finally, if the vector is smaller 241169689Skan than one word, do it as a scalar. */ 242169689Skan if (TYPE_MODE (TREE_TYPE (type)) == word_mode) 243169689Skan return expand_vector_piecewise (bsi, f, 244169689Skan type, TREE_TYPE (type), 245169689Skan a, b, code); 246169689Skan else if (n_words > 1) 247169689Skan { 248169689Skan tree word_type = build_word_mode_vector_type (n_words); 249169689Skan result = expand_vector_piecewise (bsi, f, 250169689Skan word_type, TREE_TYPE (word_type), 251169689Skan a, b, code); 252169689Skan result = gimplify_val (bsi, word_type, result); 253169689Skan } 254169689Skan else 255169689Skan { 256169689Skan /* Use a single scalar operation with a mode no wider than word_mode. */ 257169689Skan mode = mode_for_size (tree_low_cst (TYPE_SIZE (type), 1), MODE_INT, 0); 258169689Skan compute_type = lang_hooks.types.type_for_mode (mode, 1); 259169689Skan result = f (bsi, compute_type, a, b, NULL_TREE, NULL_TREE, code); 260169689Skan } 261169689Skan 262169689Skan return result; 263169689Skan} 264169689Skan 265169689Skan/* Expand a vector operation to scalars; for integer types we can use 266169689Skan special bit twiddling tricks to do the sums a word at a time, using 267169689Skan function F_PARALLEL instead of F. These tricks are done only if 268169689Skan they can process at least four items, that is, only if the vector 269169689Skan holds at least four items and if a word can hold four items. */ 270169689Skanstatic tree 271169689Skanexpand_vector_addition (block_stmt_iterator *bsi, 272169689Skan elem_op_func f, elem_op_func f_parallel, 273169689Skan tree type, tree a, tree b, enum tree_code code) 274169689Skan{ 275169689Skan int parts_per_word = UNITS_PER_WORD 276169689Skan / tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (type)), 1); 277169689Skan 278169689Skan if (INTEGRAL_TYPE_P (TREE_TYPE (type)) 279169689Skan && parts_per_word >= 4 280169689Skan && TYPE_VECTOR_SUBPARTS (type) >= 4) 281169689Skan return expand_vector_parallel (bsi, f_parallel, 282169689Skan type, a, b, code); 283169689Skan else 284169689Skan return expand_vector_piecewise (bsi, f, 285169689Skan type, TREE_TYPE (type), 286169689Skan a, b, code); 287169689Skan} 288169689Skan 289169689Skanstatic tree 290169689Skanexpand_vector_operation (block_stmt_iterator *bsi, tree type, tree compute_type, 291169689Skan tree rhs, enum tree_code code) 292169689Skan{ 293169689Skan enum machine_mode compute_mode = TYPE_MODE (compute_type); 294169689Skan 295169689Skan /* If the compute mode is not a vector mode (hence we are not decomposing 296169689Skan a BLKmode vector to smaller, hardware-supported vectors), we may want 297169689Skan to expand the operations in parallel. */ 298169689Skan if (GET_MODE_CLASS (compute_mode) != MODE_VECTOR_INT 299169689Skan && GET_MODE_CLASS (compute_mode) != MODE_VECTOR_FLOAT) 300169689Skan switch (code) 301169689Skan { 302169689Skan case PLUS_EXPR: 303169689Skan case MINUS_EXPR: 304169689Skan if (!TYPE_OVERFLOW_TRAPS (type)) 305169689Skan return expand_vector_addition (bsi, do_binop, do_plus_minus, type, 306169689Skan TREE_OPERAND (rhs, 0), 307169689Skan TREE_OPERAND (rhs, 1), code); 308169689Skan break; 309169689Skan 310169689Skan case NEGATE_EXPR: 311169689Skan if (!TYPE_OVERFLOW_TRAPS (type)) 312169689Skan return expand_vector_addition (bsi, do_unop, do_negate, type, 313169689Skan TREE_OPERAND (rhs, 0), 314169689Skan NULL_TREE, code); 315169689Skan break; 316169689Skan 317169689Skan case BIT_AND_EXPR: 318169689Skan case BIT_IOR_EXPR: 319169689Skan case BIT_XOR_EXPR: 320169689Skan return expand_vector_parallel (bsi, do_binop, type, 321169689Skan TREE_OPERAND (rhs, 0), 322169689Skan TREE_OPERAND (rhs, 1), code); 323169689Skan 324169689Skan case BIT_NOT_EXPR: 325169689Skan return expand_vector_parallel (bsi, do_unop, type, 326169689Skan TREE_OPERAND (rhs, 0), 327169689Skan NULL_TREE, code); 328169689Skan 329169689Skan default: 330169689Skan break; 331169689Skan } 332169689Skan 333169689Skan if (TREE_CODE_CLASS (code) == tcc_unary) 334169689Skan return expand_vector_piecewise (bsi, do_unop, type, compute_type, 335169689Skan TREE_OPERAND (rhs, 0), 336169689Skan NULL_TREE, code); 337169689Skan else 338169689Skan return expand_vector_piecewise (bsi, do_binop, type, compute_type, 339169689Skan TREE_OPERAND (rhs, 0), 340169689Skan TREE_OPERAND (rhs, 1), code); 341169689Skan} 342169689Skan 343169689Skan/* Return a type for the widest vector mode whose components are of mode 344169689Skan INNER_MODE, or NULL_TREE if none is found. */ 345169689Skanstatic tree 346169689Skantype_for_widest_vector_mode (enum machine_mode inner_mode, optab op) 347169689Skan{ 348169689Skan enum machine_mode best_mode = VOIDmode, mode; 349169689Skan int best_nunits = 0; 350169689Skan 351169689Skan if (SCALAR_FLOAT_MODE_P (inner_mode)) 352169689Skan mode = MIN_MODE_VECTOR_FLOAT; 353169689Skan else 354169689Skan mode = MIN_MODE_VECTOR_INT; 355169689Skan 356169689Skan for (; mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) 357169689Skan if (GET_MODE_INNER (mode) == inner_mode 358169689Skan && GET_MODE_NUNITS (mode) > best_nunits 359169689Skan && op->handlers[mode].insn_code != CODE_FOR_nothing) 360169689Skan best_mode = mode, best_nunits = GET_MODE_NUNITS (mode); 361169689Skan 362169689Skan if (best_mode == VOIDmode) 363169689Skan return NULL_TREE; 364169689Skan else 365169689Skan return lang_hooks.types.type_for_mode (best_mode, 1); 366169689Skan} 367169689Skan 368169689Skan/* Process one statement. If we identify a vector operation, expand it. */ 369169689Skan 370169689Skanstatic void 371169689Skanexpand_vector_operations_1 (block_stmt_iterator *bsi) 372169689Skan{ 373169689Skan tree stmt = bsi_stmt (*bsi); 374169689Skan tree *p_lhs, *p_rhs, lhs, rhs, type, compute_type; 375169689Skan enum tree_code code; 376169689Skan enum machine_mode compute_mode; 377169689Skan optab op; 378169689Skan 379169689Skan switch (TREE_CODE (stmt)) 380169689Skan { 381169689Skan case RETURN_EXPR: 382169689Skan stmt = TREE_OPERAND (stmt, 0); 383169689Skan if (!stmt || TREE_CODE (stmt) != MODIFY_EXPR) 384169689Skan return; 385169689Skan 386169689Skan /* FALLTHRU */ 387169689Skan 388169689Skan case MODIFY_EXPR: 389169689Skan p_lhs = &TREE_OPERAND (stmt, 0); 390169689Skan p_rhs = &TREE_OPERAND (stmt, 1); 391169689Skan lhs = *p_lhs; 392169689Skan rhs = *p_rhs; 393169689Skan break; 394169689Skan 395169689Skan default: 396169689Skan return; 397169689Skan } 398169689Skan 399169689Skan type = TREE_TYPE (rhs); 400169689Skan if (TREE_CODE (type) != VECTOR_TYPE) 401169689Skan return; 402169689Skan 403169689Skan code = TREE_CODE (rhs); 404169689Skan if (TREE_CODE_CLASS (code) != tcc_unary 405169689Skan && TREE_CODE_CLASS (code) != tcc_binary) 406169689Skan return; 407169689Skan 408169689Skan if (code == NOP_EXPR || code == VIEW_CONVERT_EXPR) 409169689Skan return; 410169689Skan 411169689Skan gcc_assert (code != CONVERT_EXPR); 412169689Skan op = optab_for_tree_code (code, type); 413169689Skan 414169689Skan /* For widening vector operations, the relevant type is of the arguments, 415169689Skan not the widened result. */ 416169689Skan if (code == WIDEN_SUM_EXPR) 417169689Skan type = TREE_TYPE (TREE_OPERAND (rhs, 0)); 418169689Skan 419169689Skan /* Optabs will try converting a negation into a subtraction, so 420169689Skan look for it as well. TODO: negation of floating-point vectors 421169689Skan might be turned into an exclusive OR toggling the sign bit. */ 422169689Skan if (op == NULL 423169689Skan && code == NEGATE_EXPR 424169689Skan && INTEGRAL_TYPE_P (TREE_TYPE (type))) 425169689Skan op = optab_for_tree_code (MINUS_EXPR, type); 426169689Skan 427169689Skan /* For very wide vectors, try using a smaller vector mode. */ 428169689Skan compute_type = type; 429169689Skan if (TYPE_MODE (type) == BLKmode && op) 430169689Skan { 431169689Skan tree vector_compute_type 432169689Skan = type_for_widest_vector_mode (TYPE_MODE (TREE_TYPE (type)), op); 433169689Skan if (vector_compute_type != NULL_TREE) 434169689Skan compute_type = vector_compute_type; 435169689Skan } 436169689Skan 437169689Skan /* If we are breaking a BLKmode vector into smaller pieces, 438169689Skan type_for_widest_vector_mode has already looked into the optab, 439169689Skan so skip these checks. */ 440169689Skan if (compute_type == type) 441169689Skan { 442169689Skan compute_mode = TYPE_MODE (compute_type); 443169689Skan if ((GET_MODE_CLASS (compute_mode) == MODE_VECTOR_INT 444169689Skan || GET_MODE_CLASS (compute_mode) == MODE_VECTOR_FLOAT) 445169689Skan && op != NULL 446169689Skan && op->handlers[compute_mode].insn_code != CODE_FOR_nothing) 447169689Skan return; 448169689Skan else 449169689Skan /* There is no operation in hardware, so fall back to scalars. */ 450169689Skan compute_type = TREE_TYPE (type); 451169689Skan } 452169689Skan 453169689Skan gcc_assert (code != VEC_LSHIFT_EXPR && code != VEC_RSHIFT_EXPR); 454169689Skan rhs = expand_vector_operation (bsi, type, compute_type, rhs, code); 455169689Skan if (lang_hooks.types_compatible_p (TREE_TYPE (lhs), TREE_TYPE (rhs))) 456169689Skan *p_rhs = rhs; 457169689Skan else 458169689Skan *p_rhs = gimplify_build1 (bsi, VIEW_CONVERT_EXPR, TREE_TYPE (lhs), rhs); 459169689Skan 460169689Skan mark_stmt_modified (bsi_stmt (*bsi)); 461169689Skan} 462169689Skan 463169689Skan/* Use this to lower vector operations introduced by the vectorizer, 464169689Skan if it may need the bit-twiddling tricks implemented in this file. */ 465169689Skan 466169689Skanstatic bool 467169689Skangate_expand_vector_operations (void) 468169689Skan{ 469169689Skan return flag_tree_vectorize != 0; 470169689Skan} 471169689Skan 472169689Skanstatic unsigned int 473169689Skanexpand_vector_operations (void) 474169689Skan{ 475169689Skan block_stmt_iterator bsi; 476169689Skan basic_block bb; 477169689Skan 478169689Skan FOR_EACH_BB (bb) 479169689Skan { 480169689Skan for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) 481169689Skan { 482169689Skan expand_vector_operations_1 (&bsi); 483169689Skan update_stmt_if_modified (bsi_stmt (bsi)); 484169689Skan } 485169689Skan } 486169689Skan return 0; 487169689Skan} 488169689Skan 489169689Skanstruct tree_opt_pass pass_lower_vector = 490169689Skan{ 491169689Skan "veclower", /* name */ 492169689Skan 0, /* gate */ 493169689Skan expand_vector_operations, /* execute */ 494169689Skan NULL, /* sub */ 495169689Skan NULL, /* next */ 496169689Skan 0, /* static_pass_number */ 497169689Skan 0, /* tv_id */ 498169689Skan PROP_cfg, /* properties_required */ 499169689Skan 0, /* properties_provided */ 500169689Skan 0, /* properties_destroyed */ 501169689Skan 0, /* todo_flags_start */ 502169689Skan TODO_dump_func | TODO_ggc_collect 503169689Skan | TODO_verify_stmts, /* todo_flags_finish */ 504169689Skan 0 /* letter */ 505169689Skan}; 506169689Skan 507169689Skanstruct tree_opt_pass pass_lower_vector_ssa = 508169689Skan{ 509169689Skan "veclower2", /* name */ 510169689Skan gate_expand_vector_operations, /* gate */ 511169689Skan expand_vector_operations, /* execute */ 512169689Skan NULL, /* sub */ 513169689Skan NULL, /* next */ 514169689Skan 0, /* static_pass_number */ 515169689Skan 0, /* tv_id */ 516169689Skan PROP_cfg, /* properties_required */ 517169689Skan 0, /* properties_provided */ 518169689Skan 0, /* properties_destroyed */ 519169689Skan 0, /* todo_flags_start */ 520169689Skan TODO_dump_func | TODO_update_ssa /* todo_flags_finish */ 521169689Skan | TODO_verify_ssa 522169689Skan | TODO_verify_stmts | TODO_verify_flow, 523169689Skan 0 /* letter */ 524169689Skan}; 525169689Skan 526169689Skan#include "gt-tree-vect-generic.h" 527