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