- abort ();
- }
-}
-\f
-/* Build a constant of type TYPE, made of VALUE's bits replicated
- every TYPE_SIZE (INNER_TYPE) bits to fit TYPE's precision. */
-static tree
-build_replicated_const (tree type, tree inner_type, HOST_WIDE_INT value)
-{
- int width = tree_low_cst (TYPE_SIZE (inner_type), 1);
- int n = HOST_BITS_PER_WIDE_INT / width;
- unsigned HOST_WIDE_INT low, high, mask;
- tree ret;
-
- if (n == 0)
- abort ();
-
- if (width == HOST_BITS_PER_WIDE_INT)
- low = value;
- else
- {
- mask = ((HOST_WIDE_INT)1 << width) - 1;
- low = (unsigned HOST_WIDE_INT) ~0 / mask * (value & mask);
- }
-
- if (TYPE_PRECISION (type) < HOST_BITS_PER_WIDE_INT)
- low &= ((HOST_WIDE_INT)1 << TYPE_PRECISION (type)) - 1, high = 0;
- else if (TYPE_PRECISION (type) == HOST_BITS_PER_WIDE_INT)
- high = 0;
- else if (TYPE_PRECISION (type) == 2 * HOST_BITS_PER_WIDE_INT)
- high = low;
- else
- abort ();
-
- ret = build_int_cst (type, low, high);
- return ret;
-}
-
-/* Return a suitable vector types made of SUBPARTS units each of mode
- "word_mode" (the global variable). */
-static tree
-build_word_mode_vector_type (int nunits)
-{
- static tree innertype;
- static tree last;
- static int last_nunits;
-
- if (!innertype)
- innertype = lang_hooks.types.type_for_mode (word_mode, 1);
- else if (last_nunits == nunits)
- return last;
-
- /* We build a new type, but we canonicalize it nevertheless,
- because it still saves some memory. */
- last_nunits = nunits;
- last = type_hash_canon (nunits, build_vector_type (innertype, nunits));
- return last;
-}
-
-typedef tree (*elem_op_func) (block_stmt_iterator *,
- tree, tree, tree, tree, tree, enum tree_code);
-
-static inline tree
-tree_vec_extract (block_stmt_iterator *bsi, tree type,
- tree t, tree bitsize, tree bitpos)
-{
- if (bitpos)
- return gimplify_build3 (bsi, BIT_FIELD_REF, type, t, bitsize, bitpos);
- else
- return gimplify_build1 (bsi, VIEW_CONVERT_EXPR, type, t);
-}
-
-static tree
-do_unop (block_stmt_iterator *bsi, 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);
-}
-
-static tree
-do_binop (block_stmt_iterator *bsi, 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);
-}
-
-/* Expand vector addition to scalars. This does bit twiddling
- in order to increase parallelism:
-
- a + b = (((int) a & 0x7f7f7f7f) + ((int) b & 0x7f7f7f7f)) ^
- (a ^ b) & 0x80808080
-
- a - b = (((int) a | 0x80808080) - ((int) b & 0x7f7f7f7f)) ^
- (a ^ ~b) & 0x80808080
-
- -b = (0x80808080 - ((int) b & 0x7f7f7f7f)) ^ (~b & 0x80808080)
-
- 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,
- tree bitpos ATTRIBUTE_UNUSED, tree bitsize ATTRIBUTE_UNUSED,
- enum tree_code code)
-{
- tree inner_type = TREE_TYPE (TREE_TYPE (a));
- unsigned HOST_WIDE_INT max;
- tree low_bits, high_bits, a_low, b_low, result_low, signs;
-
- max = GET_MODE_MASK (TYPE_MODE (inner_type));
- 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);
-
- signs = gimplify_build2 (bsi, BIT_XOR_EXPR, word_type, a, b);
- b_low = gimplify_build2 (bsi, 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);
- else
- {
- a_low = gimplify_build2 (bsi, BIT_IOR_EXPR, word_type, a, high_bits);
- signs = gimplify_build1 (bsi, 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);
-}
-
-static tree
-do_negate (block_stmt_iterator *bsi, tree word_type, tree b,
- tree unused ATTRIBUTE_UNUSED, tree bitpos ATTRIBUTE_UNUSED,
- tree bitsize ATTRIBUTE_UNUSED,
- enum tree_code code ATTRIBUTE_UNUSED)
-{
- tree inner_type = TREE_TYPE (TREE_TYPE (b));
- HOST_WIDE_INT max;
- tree low_bits, high_bits, b_low, result_low, signs;
-
- max = GET_MODE_MASK (TYPE_MODE (inner_type));
- 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_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);
-}
-
-/* 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,
- tree type, tree inner_type,
- tree a, tree b, enum tree_code code)
-{
- tree head, *chain = &head;
- tree part_width = TYPE_SIZE (inner_type);
- tree index = bitsize_int (0);
- int nunits = TYPE_VECTOR_SUBPARTS (type);
- int delta = tree_low_cst (part_width, 1)
- / tree_low_cst (TYPE_SIZE (TREE_TYPE (type)), 1);
- int i;
-
- 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);
- }
-
- return build1 (CONSTRUCTOR, type, head);
-}
-
-/* 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,
- tree a, tree b,
- enum tree_code code)
-{
- tree result, compute_type;
- enum machine_mode mode;
- int n_words = tree_low_cst (TYPE_SIZE_UNIT (type), 1) / UNITS_PER_WORD;
-
- /* 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
- 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,
- 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,
- word_type, TREE_TYPE (word_type),
- a, b, code);
- result = gimplify_val (bsi, word_type, result);