return NULL_RTX;
}
+/* Expand a vector initialisation sequence, such that TARGET is
+ initialised to contain VALS. */
+
void
aarch64_expand_vector_init (rtx target, rtx vals)
{
machine_mode mode = GET_MODE (target);
machine_mode inner_mode = GET_MODE_INNER (mode);
+ /* The number of vector elements. */
int n_elts = GET_MODE_NUNITS (mode);
+ /* The number of vector elements which are not constant. */
int n_var = 0;
rtx any_const = NULL_RTX;
+ /* The first element of vals. */
+ rtx v0 = XVECEXP (vals, 0, 0);
bool all_same = true;
+ /* Count the number of variable elements to initialise. */
for (int i = 0; i < n_elts; ++i)
{
rtx x = XVECEXP (vals, 0, i);
- if (!CONST_INT_P (x) && !CONST_DOUBLE_P (x))
+ if (!(CONST_INT_P (x) || CONST_DOUBLE_P (x)))
++n_var;
else
any_const = x;
- if (i > 0 && !rtx_equal_p (x, XVECEXP (vals, 0, 0)))
- all_same = false;
+ all_same &= rtx_equal_p (x, v0);
}
+ /* No variable elements, hand off to aarch64_simd_make_constant which knows
+ how best to handle this. */
if (n_var == 0)
{
rtx constant = aarch64_simd_make_constant (vals);
/* Splat a single non-constant element if we can. */
if (all_same)
{
- rtx x = copy_to_mode_reg (inner_mode, XVECEXP (vals, 0, 0));
+ rtx x = copy_to_mode_reg (inner_mode, v0);
aarch64_emit_move (target, gen_rtx_VEC_DUPLICATE (mode, x));
return;
}
- /* Half the fields (or less) are non-constant. Load constant then overwrite
- varying fields. Hope that this is more efficient than using the stack. */
- if (n_var <= n_elts/2)
+ /* Initialise a vector which is part-variable. We want to first try
+ to build those lanes which are constant in the most efficient way we
+ can. */
+ if (n_var != n_elts)
{
rtx copy = copy_rtx (vals);
XVECEXP (copy, 0, i) = subst;
}
aarch64_expand_vector_init (target, copy);
+ }
- /* Insert variables. */
- enum insn_code icode = optab_handler (vec_set_optab, mode);
- gcc_assert (icode != CODE_FOR_nothing);
+ /* Insert the variable lanes directly. */
- for (int i = 0; i < n_elts; i++)
- {
- rtx x = XVECEXP (vals, 0, i);
- if (CONST_INT_P (x) || CONST_DOUBLE_P (x))
- continue;
- x = copy_to_mode_reg (inner_mode, x);
- emit_insn (GEN_FCN (icode) (target, x, GEN_INT (i)));
- }
- return;
- }
+ enum insn_code icode = optab_handler (vec_set_optab, mode);
+ gcc_assert (icode != CODE_FOR_nothing);
- /* Construct the vector in memory one field at a time
- and load the whole vector. */
- rtx mem = assign_stack_temp (mode, GET_MODE_SIZE (mode));
for (int i = 0; i < n_elts; i++)
- emit_move_insn (adjust_address_nv (mem, inner_mode,
- i * GET_MODE_SIZE (inner_mode)),
- XVECEXP (vals, 0, i));
- emit_move_insn (target, mem);
-
+ {
+ rtx x = XVECEXP (vals, 0, i);
+ if (CONST_INT_P (x) || CONST_DOUBLE_P (x))
+ continue;
+ x = copy_to_mode_reg (inner_mode, x);
+ emit_insn (GEN_FCN (icode) (target, x, GEN_INT (i)));
+ }
}
static unsigned HOST_WIDE_INT