aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog37
-rw-r--r--gcc/config/aarch64/aarch64-protos.h5
-rw-r--r--gcc/config/aarch64/aarch64-simd.md13
-rw-r--r--gcc/config/aarch64/aarch64.c387
-rw-r--r--gcc/config/aarch64/constraints.md11
-rw-r--r--gcc/config/aarch64/iterators.md7
-rw-r--r--gcc/config/aarch64/predicates.md8
-rw-r--r--gcc/testsuite/ChangeLog7
-rw-r--r--gcc/testsuite/gcc.target/aarch64/vect-movi.c14
9 files changed, 285 insertions, 204 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index dd5d703..9437ae9 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -2,6 +2,43 @@
Alan Hayward <alan.hayward@arm.com>
David Sherwood <david.sherwood@arm.com>
+ * config/aarch64/aarch64-protos.h (aarch64_output_simd_mov_immediate):
+ Remove the mode argument.
+ (aarch64_simd_valid_immediate): Remove the mode and inverse
+ arguments.
+ * config/aarch64/iterators.md (bitsize): New iterator.
+ * config/aarch64/aarch64-simd.md (*aarch64_simd_mov<mode>, and<mode>3)
+ (ior<mode>3): Update calls to aarch64_output_simd_mov_immediate.
+ * config/aarch64/constraints.md (Do, Db, Dn): Update calls to
+ aarch64_simd_valid_immediate.
+ * config/aarch64/predicates.md (aarch64_reg_or_orr_imm): Likewise.
+ (aarch64_reg_or_bic_imm): Likewise.
+ * config/aarch64/aarch64.c (simd_immediate_info): Replace mvn
+ with an insn_type enum and msl with a modifier_type enum.
+ Replace element_width with a scalar_mode. Change the shift
+ to unsigned int. Add constructors for scalar_float_mode and
+ scalar_int_mode elements.
+ (aarch64_vect_float_const_representable_p): Delete.
+ (aarch64_can_const_movi_rtx_p)
+ (aarch64_simd_scalar_immediate_valid_for_move)
+ (aarch64_simd_make_constant): Update call to
+ aarch64_simd_valid_immediate.
+ (aarch64_advsimd_valid_immediate_hs): New function.
+ (aarch64_advsimd_valid_immediate): Likewise.
+ (aarch64_simd_valid_immediate): Remove mode and inverse
+ arguments. Rewrite to use the above. Use const_vec_duplicate_p
+ to detect duplicated constants and use aarch64_float_const_zero_rtx_p
+ and aarch64_float_const_representable_p on the result.
+ (aarch64_output_simd_mov_immediate): Remove mode argument.
+ Update call to aarch64_simd_valid_immediate and use of
+ simd_immediate_info.
+ (aarch64_output_scalar_simd_mov_immediate): Update call
+ accordingly.
+
+2018-01-03 Richard Sandiford <richard.sandiford@linaro.org>
+ Alan Hayward <alan.hayward@arm.com>
+ David Sherwood <david.sherwood@arm.com>
+
* machmode.h (mode_precision): Prefix with CONST_MODE_PRECISION.
(mode_nunits): Likewise CONST_MODE_NUNITS.
* machmode.def (ADJUST_NUNITS): Document.
diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index fba0632..7df3aae 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -368,7 +368,7 @@ bool aarch64_mov_operand_p (rtx, machine_mode);
rtx aarch64_reverse_mask (machine_mode, unsigned int);
bool aarch64_offset_7bit_signed_scaled_p (machine_mode, HOST_WIDE_INT);
char *aarch64_output_scalar_simd_mov_immediate (rtx, scalar_int_mode);
-char *aarch64_output_simd_mov_immediate (rtx, machine_mode, unsigned,
+char *aarch64_output_simd_mov_immediate (rtx, unsigned,
enum simd_immediate_check w = AARCH64_CHECK_MOV);
bool aarch64_pad_reg_upward (machine_mode, const_tree, bool);
bool aarch64_regno_ok_for_base_p (int, bool);
@@ -379,8 +379,7 @@ bool aarch64_simd_check_vect_par_cnst_half (rtx op, machine_mode mode,
bool aarch64_simd_imm_zero_p (rtx, machine_mode);
bool aarch64_simd_scalar_immediate_valid_for_move (rtx, scalar_int_mode);
bool aarch64_simd_shift_imm_p (rtx, machine_mode, bool);
-bool aarch64_simd_valid_immediate (rtx, machine_mode, bool,
- struct simd_immediate_info *,
+bool aarch64_simd_valid_immediate (rtx, struct simd_immediate_info *,
enum simd_immediate_check w = AARCH64_CHECK_MOV);
bool aarch64_split_dimode_const_store (rtx, rtx);
bool aarch64_symbolic_address_p (rtx);
diff --git a/gcc/config/aarch64/aarch64-simd.md b/gcc/config/aarch64/aarch64-simd.md
index a2e0893..5a85f82 100644
--- a/gcc/config/aarch64/aarch64-simd.md
+++ b/gcc/config/aarch64/aarch64-simd.md
@@ -120,8 +120,7 @@
case 5: return "fmov\t%d0, %1";
case 6: return "mov\t%0, %1";
case 7:
- return aarch64_output_simd_mov_immediate (operands[1],
- <MODE>mode, 64);
+ return aarch64_output_simd_mov_immediate (operands[1], 64);
default: gcc_unreachable ();
}
}
@@ -154,7 +153,7 @@
case 6:
return "#";
case 7:
- return aarch64_output_simd_mov_immediate (operands[1], <MODE>mode, 128);
+ return aarch64_output_simd_mov_immediate (operands[1], 128);
default:
gcc_unreachable ();
}
@@ -647,8 +646,8 @@
case 0:
return "and\t%0.<Vbtype>, %1.<Vbtype>, %2.<Vbtype>";
case 1:
- return aarch64_output_simd_mov_immediate (operands[2],
- <MODE>mode, GET_MODE_BITSIZE (<MODE>mode), AARCH64_CHECK_BIC);
+ return aarch64_output_simd_mov_immediate (operands[2], <bitsize>,
+ AARCH64_CHECK_BIC);
default:
gcc_unreachable ();
}
@@ -668,8 +667,8 @@
case 0:
return "orr\t%0.<Vbtype>, %1.<Vbtype>, %2.<Vbtype>";
case 1:
- return aarch64_output_simd_mov_immediate (operands[2],
- <MODE>mode, GET_MODE_BITSIZE (<MODE>mode), AARCH64_CHECK_ORR);
+ return aarch64_output_simd_mov_immediate (operands[2], <bitsize>,
+ AARCH64_CHECK_ORR);
default:
gcc_unreachable ();
}
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 5c258a9..a189605 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -117,15 +117,53 @@ struct aarch64_address_info {
enum aarch64_symbol_type symbol_type;
};
+/* Information about a legitimate vector immediate operand. */
struct simd_immediate_info
{
+ enum insn_type { MOV, MVN };
+ enum modifier_type { LSL, MSL };
+
+ simd_immediate_info () {}
+ simd_immediate_info (scalar_float_mode, rtx);
+ simd_immediate_info (scalar_int_mode, unsigned HOST_WIDE_INT,
+ insn_type = MOV, modifier_type = LSL,
+ unsigned int = 0);
+
+ /* The mode of the elements. */
+ scalar_mode elt_mode;
+
+ /* The value of each element. */
rtx value;
- int shift;
- int element_width;
- bool mvn;
- bool msl;
+
+ /* The instruction to use to move the immediate into a vector. */
+ insn_type insn;
+
+ /* The kind of shift modifier to use, and the number of bits to shift.
+ This is (LSL, 0) if no shift is needed. */
+ modifier_type modifier;
+ unsigned int shift;
};
+/* Construct a floating-point immediate in which each element has mode
+ ELT_MODE_IN and value VALUE_IN. */
+inline simd_immediate_info
+::simd_immediate_info (scalar_float_mode elt_mode_in, rtx value_in)
+ : elt_mode (elt_mode_in), value (value_in), insn (MOV),
+ modifier (LSL), shift (0)
+{}
+
+/* Construct an integer immediate in which each element has mode ELT_MODE_IN
+ and value VALUE_IN. The other parameters are as for the structure
+ fields. */
+inline simd_immediate_info
+::simd_immediate_info (scalar_int_mode elt_mode_in,
+ unsigned HOST_WIDE_INT value_in,
+ insn_type insn_in, modifier_type modifier_in,
+ unsigned int shift_in)
+ : elt_mode (elt_mode_in), value (gen_int_mode (value_in, elt_mode_in)),
+ insn (insn_in), modifier (modifier_in), shift (shift_in)
+{}
+
/* The current code model. */
enum aarch64_code_model aarch64_cmodel;
@@ -4873,7 +4911,7 @@ aarch64_can_const_movi_rtx_p (rtx x, machine_mode mode)
vmode = aarch64_simd_container_mode (imode, width);
rtx v_op = aarch64_simd_gen_const_vector_dup (vmode, ival);
- return aarch64_simd_valid_immediate (v_op, vmode, false, NULL);
+ return aarch64_simd_valid_immediate (v_op, NULL);
}
@@ -11493,200 +11531,185 @@ sizetochar (int size)
}
}
-/* Return true iff x is a uniform vector of floating-point
- constants, and the constant can be represented in
- quarter-precision form. Note, as aarch64_float_const_representable
- rejects both +0.0 and -0.0, we will also reject +0.0 and -0.0. */
+/* Return true if replicating VAL32 is a valid 2-byte or 4-byte immediate
+ for the Advanced SIMD operation described by WHICH and INSN. If INFO
+ is nonnull, use it to describe valid immediates. */
static bool
-aarch64_vect_float_const_representable_p (rtx x)
-{
- rtx elt;
- return (GET_MODE_CLASS (GET_MODE (x)) == MODE_VECTOR_FLOAT
- && const_vec_duplicate_p (x, &elt)
- && aarch64_float_const_representable_p (elt));
-}
-
-/* Return true for valid and false for invalid. */
-bool
-aarch64_simd_valid_immediate (rtx op, machine_mode mode, bool inverse,
- struct simd_immediate_info *info,
- enum simd_immediate_check which)
-{
-#define CHECK(STRIDE, ELSIZE, CLASS, TEST, SHIFT, NEG) \
- matches = 1; \
- for (i = 0; i < idx; i += (STRIDE)) \
- if (!(TEST)) \
- matches = 0; \
- if (matches) \
- { \
- immtype = (CLASS); \
- elsize = (ELSIZE); \
- eshift = (SHIFT); \
- emvn = (NEG); \
- break; \
- }
-
- unsigned int i, elsize = 0, idx = 0, n_elts = CONST_VECTOR_NUNITS (op);
- unsigned int innersize = GET_MODE_UNIT_SIZE (mode);
- unsigned char bytes[16];
- int immtype = -1, matches;
- unsigned int invmask = inverse ? 0xff : 0;
- int eshift, emvn;
-
- if (GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
- {
- if (! (aarch64_simd_imm_zero_p (op, mode)
- || aarch64_vect_float_const_representable_p (op)))
- return false;
+aarch64_advsimd_valid_immediate_hs (unsigned int val32,
+ simd_immediate_info *info,
+ enum simd_immediate_check which,
+ simd_immediate_info::insn_type insn)
+{
+ /* Try a 4-byte immediate with LSL. */
+ for (unsigned int shift = 0; shift < 32; shift += 8)
+ if ((val32 & (0xff << shift)) == val32)
+ {
+ if (info)
+ *info = simd_immediate_info (SImode, val32 >> shift, insn,
+ simd_immediate_info::LSL, shift);
+ return true;
+ }
- if (info)
+ /* Try a 2-byte immediate with LSL. */
+ unsigned int imm16 = val32 & 0xffff;
+ if (imm16 == (val32 >> 16))
+ for (unsigned int shift = 0; shift < 16; shift += 8)
+ if ((imm16 & (0xff << shift)) == imm16)
{
- rtx elt = CONST_VECTOR_ELT (op, 0);
- scalar_float_mode elt_mode
- = as_a <scalar_float_mode> (GET_MODE (elt));
-
- info->value = elt;
- info->element_width = GET_MODE_BITSIZE (elt_mode);
- info->mvn = false;
- info->shift = 0;
+ if (info)
+ *info = simd_immediate_info (HImode, imm16 >> shift, insn,
+ simd_immediate_info::LSL, shift);
+ return true;
}
- return true;
- }
+ /* Try a 4-byte immediate with MSL, except for cases that MVN
+ can handle. */
+ if (which == AARCH64_CHECK_MOV)
+ for (unsigned int shift = 8; shift < 24; shift += 8)
+ {
+ unsigned int low = (1 << shift) - 1;
+ if (((val32 & (0xff << shift)) | low) == val32)
+ {
+ if (info)
+ *info = simd_immediate_info (SImode, val32 >> shift, insn,
+ simd_immediate_info::MSL, shift);
+ return true;
+ }
+ }
- /* Splat vector constant out into a byte vector. */
- for (i = 0; i < n_elts; i++)
+ return false;
+}
+
+/* Return true if replicating VAL64 is a valid immediate for the
+ Advanced SIMD operation described by WHICH. If INFO is nonnull,
+ use it to describe valid immediates. */
+static bool
+aarch64_advsimd_valid_immediate (unsigned HOST_WIDE_INT val64,
+ simd_immediate_info *info,
+ enum simd_immediate_check which)
+{
+ unsigned int val32 = val64 & 0xffffffff;
+ unsigned int val16 = val64 & 0xffff;
+ unsigned int val8 = val64 & 0xff;
+
+ if (val32 == (val64 >> 32))
{
- /* The vector is provided in gcc endian-neutral fashion. For aarch64_be,
- it must be laid out in the vector register in reverse order. */
- rtx el = CONST_VECTOR_ELT (op, BYTES_BIG_ENDIAN ? (n_elts - 1 - i) : i);
- unsigned HOST_WIDE_INT elpart;
+ if ((which & AARCH64_CHECK_ORR) != 0
+ && aarch64_advsimd_valid_immediate_hs (val32, info, which,
+ simd_immediate_info::MOV))
+ return true;
- gcc_assert (CONST_INT_P (el));
- elpart = INTVAL (el);
+ if ((which & AARCH64_CHECK_BIC) != 0
+ && aarch64_advsimd_valid_immediate_hs (~val32, info, which,
+ simd_immediate_info::MVN))
+ return true;
- for (unsigned int byte = 0; byte < innersize; byte++)
+ /* Try using a replicated byte. */
+ if (which == AARCH64_CHECK_MOV
+ && val16 == (val32 >> 16)
+ && val8 == (val16 >> 8))
{
- bytes[idx++] = (elpart & 0xff) ^ invmask;
- elpart >>= BITS_PER_UNIT;
+ if (info)
+ *info = simd_immediate_info (QImode, val8);
+ return true;
}
-
}
- /* Sanity check. */
- gcc_assert (idx == GET_MODE_SIZE (mode));
-
- do
+ /* Try using a bit-to-bytemask. */
+ if (which == AARCH64_CHECK_MOV)
{
- if (which & AARCH64_CHECK_ORR)
+ unsigned int i;
+ for (i = 0; i < 64; i += 8)
{
- CHECK (4, 32, 0, bytes[i] == bytes[0] && bytes[i + 1] == 0
- && bytes[i + 2] == 0 && bytes[i + 3] == 0, 0, 0);
-
- CHECK (4, 32, 1, bytes[i] == 0 && bytes[i + 1] == bytes[1]
- && bytes[i + 2] == 0 && bytes[i + 3] == 0, 8, 0);
-
- CHECK (4, 32, 2, bytes[i] == 0 && bytes[i + 1] == 0
- && bytes[i + 2] == bytes[2] && bytes[i + 3] == 0, 16, 0);
-
- CHECK (4, 32, 3, bytes[i] == 0 && bytes[i + 1] == 0
- && bytes[i + 2] == 0 && bytes[i + 3] == bytes[3], 24, 0);
-
- CHECK (2, 16, 4, bytes[i] == bytes[0] && bytes[i + 1] == 0, 0, 0);
-
- CHECK (2, 16, 5, bytes[i] == 0 && bytes[i + 1] == bytes[1], 8, 0);
- }
-
- if (which & AARCH64_CHECK_BIC)
- {
- CHECK (4, 32, 6, bytes[i] == bytes[0] && bytes[i + 1] == 0xff
- && bytes[i + 2] == 0xff && bytes[i + 3] == 0xff, 0, 1);
-
- CHECK (4, 32, 7, bytes[i] == 0xff && bytes[i + 1] == bytes[1]
- && bytes[i + 2] == 0xff && bytes[i + 3] == 0xff, 8, 1);
-
- CHECK (4, 32, 8, bytes[i] == 0xff && bytes[i + 1] == 0xff
- && bytes[i + 2] == bytes[2] && bytes[i + 3] == 0xff, 16, 1);
-
- CHECK (4, 32, 9, bytes[i] == 0xff && bytes[i + 1] == 0xff
- && bytes[i + 2] == 0xff && bytes[i + 3] == bytes[3], 24, 1);
-
- CHECK (2, 16, 10, bytes[i] == bytes[0] && bytes[i + 1] == 0xff, 0, 1);
-
- CHECK (2, 16, 11, bytes[i] == 0xff && bytes[i + 1] == bytes[1], 8, 1);
+ unsigned char byte = (val64 >> i) & 0xff;
+ if (byte != 0 && byte != 0xff)
+ break;
}
-
- /* Shifting ones / 8-bit / 64-bit variants only checked
- for 'ALL' (MOVI/MVNI). */
- if (which == AARCH64_CHECK_MOV)
+ if (i == 64)
{
- CHECK (4, 32, 12, bytes[i] == 0xff && bytes[i + 1] == bytes[1]
- && bytes[i + 2] == 0 && bytes[i + 3] == 0, 8, 0);
-
- CHECK (4, 32, 13, bytes[i] == 0 && bytes[i + 1] == bytes[1]
- && bytes[i + 2] == 0xff && bytes[i + 3] == 0xff, 8, 1);
-
- CHECK (4, 32, 14, bytes[i] == 0xff && bytes[i + 1] == 0xff
- && bytes[i + 2] == bytes[2] && bytes[i + 3] == 0, 16, 0);
-
- CHECK (4, 32, 15, bytes[i] == 0 && bytes[i + 1] == 0
- && bytes[i + 2] == bytes[2] && bytes[i + 3] == 0xff, 16, 1);
-
- CHECK (1, 8, 16, bytes[i] == bytes[0], 0, 0);
-
- CHECK (1, 64, 17, (bytes[i] == 0 || bytes[i] == 0xff)
- && bytes[i] == bytes[(i + 8) % idx], 0, 0);
+ if (info)
+ *info = simd_immediate_info (DImode, val64);
+ return true;
}
}
- while (0);
+ return false;
+}
- if (immtype == -1)
+/* Return true if OP is a valid SIMD immediate for the operation
+ described by WHICH. If INFO is nonnull, use it to describe valid
+ immediates. */
+bool
+aarch64_simd_valid_immediate (rtx op, simd_immediate_info *info,
+ enum simd_immediate_check which)
+{
+ rtx elt = NULL;
+ unsigned int n_elts;
+ if (const_vec_duplicate_p (op, &elt))
+ n_elts = 1;
+ else if (GET_CODE (op) == CONST_VECTOR)
+ n_elts = CONST_VECTOR_NUNITS (op);
+ else
return false;
- if (info)
+ machine_mode mode = GET_MODE (op);
+ scalar_mode elt_mode = GET_MODE_INNER (mode);
+ scalar_float_mode elt_float_mode;
+ if (elt
+ && is_a <scalar_float_mode> (elt_mode, &elt_float_mode)
+ && (aarch64_float_const_zero_rtx_p (elt)
+ || aarch64_float_const_representable_p (elt)))
{
- info->element_width = elsize;
- info->mvn = emvn != 0;
- info->shift = eshift;
-
- unsigned HOST_WIDE_INT imm = 0;
+ if (info)
+ *info = simd_immediate_info (elt_float_mode, elt);
+ return true;
+ }
- if (immtype >= 12 && immtype <= 15)
- info->msl = true;
+ unsigned int elt_size = GET_MODE_SIZE (elt_mode);
+ if (elt_size > 8)
+ return false;
- /* Un-invert bytes of recognized vector, if necessary. */
- if (invmask != 0)
- for (i = 0; i < idx; i++)
- bytes[i] ^= invmask;
+ scalar_int_mode elt_int_mode = int_mode_for_mode (elt_mode).require ();
- if (immtype == 17)
- {
- /* FIXME: Broken on 32-bit H_W_I hosts. */
- gcc_assert (sizeof (HOST_WIDE_INT) == 8);
+ /* Expand the vector constant out into a byte vector, with the least
+ significant byte of the register first. */
+ auto_vec<unsigned char, 16> bytes;
+ bytes.reserve (n_elts * elt_size);
+ for (unsigned int i = 0; i < n_elts; i++)
+ {
+ if (!elt || n_elts != 1)
+ /* The vector is provided in gcc endian-neutral fashion.
+ For aarch64_be, it must be laid out in the vector register
+ in reverse order. */
+ elt = CONST_VECTOR_ELT (op, BYTES_BIG_ENDIAN ? (n_elts - 1 - i) : i);
- for (i = 0; i < 8; i++)
- imm |= (unsigned HOST_WIDE_INT) (bytes[i] ? 0xff : 0)
- << (i * BITS_PER_UNIT);
+ if (elt_mode != elt_int_mode)
+ elt = gen_lowpart (elt_int_mode, elt);
+ if (!CONST_INT_P (elt))
+ return false;
- info->value = GEN_INT (imm);
- }
- else
+ unsigned HOST_WIDE_INT elt_val = INTVAL (elt);
+ for (unsigned int byte = 0; byte < elt_size; byte++)
{
- for (i = 0; i < elsize / BITS_PER_UNIT; i++)
- imm |= (unsigned HOST_WIDE_INT) bytes[i] << (i * BITS_PER_UNIT);
-
- /* Construct 'abcdefgh' because the assembler cannot handle
- generic constants. */
- if (info->mvn)
- imm = ~imm;
- imm = (imm >> info->shift) & 0xff;
- info->value = GEN_INT (imm);
+ bytes.quick_push (elt_val & 0xff);
+ elt_val >>= BITS_PER_UNIT;
}
}
- return true;
-#undef CHECK
+ /* The immediate must repeat every eight bytes. */
+ unsigned int nbytes = bytes.length ();
+ for (unsigned i = 8; i < nbytes; ++i)
+ if (bytes[i] != bytes[i - 8])
+ return false;
+
+ /* Get the repeating 8-byte value as an integer. No endian correction
+ is needed here because bytes is already in lsb-first order. */
+ unsigned HOST_WIDE_INT val64 = 0;
+ for (unsigned int i = 0; i < 8; i++)
+ val64 |= ((unsigned HOST_WIDE_INT) bytes[i % nbytes]
+ << (i * BITS_PER_UNIT));
+
+ return aarch64_advsimd_valid_immediate (val64, info, which);
}
/* Check of immediate shift constants are within range. */
@@ -11758,7 +11781,7 @@ aarch64_simd_scalar_immediate_valid_for_move (rtx op, scalar_int_mode mode)
vmode = aarch64_preferred_simd_mode (mode);
rtx op_v = aarch64_simd_gen_const_vector_dup (vmode, INTVAL (op));
- return aarch64_simd_valid_immediate (op_v, vmode, false, NULL);
+ return aarch64_simd_valid_immediate (op_v, NULL);
}
/* Construct and return a PARALLEL RTX vector with elements numbering the
@@ -12006,7 +12029,7 @@ aarch64_simd_make_constant (rtx vals)
gcc_unreachable ();
if (const_vec != NULL_RTX
- && aarch64_simd_valid_immediate (const_vec, mode, false, NULL))
+ && aarch64_simd_valid_immediate (const_vec, NULL))
/* Load using MOVI/MVNI. */
return const_vec;
else if ((const_dup = aarch64_simd_dup_constant (vals)) != NULL_RTX)
@@ -13086,9 +13109,7 @@ aarch64_float_const_representable_p (rtx x)
immediate with a CONST_VECTOR of MODE and WIDTH. WHICH selects whether to
output MOVI/MVNI, ORR or BIC immediate. */
char*
-aarch64_output_simd_mov_immediate (rtx const_vector,
- machine_mode mode,
- unsigned width,
+aarch64_output_simd_mov_immediate (rtx const_vector, unsigned width,
enum simd_immediate_check which)
{
bool is_valid;
@@ -13098,23 +13119,21 @@ aarch64_output_simd_mov_immediate (rtx const_vector,
unsigned int lane_count = 0;
char element_char;
- struct simd_immediate_info info = { NULL_RTX, 0, 0, false, false };
+ struct simd_immediate_info info;
/* This will return true to show const_vector is legal for use as either
a AdvSIMD MOVI instruction (or, implicitly, MVNI), ORR or BIC immediate.
It will also update INFO to show how the immediate should be generated.
WHICH selects whether to check for MOVI/MVNI, ORR or BIC. */
- is_valid = aarch64_simd_valid_immediate (const_vector, mode, false,
- &info, which);
+ is_valid = aarch64_simd_valid_immediate (const_vector, &info, which);
gcc_assert (is_valid);
- element_char = sizetochar (info.element_width);
- lane_count = width / info.element_width;
+ element_char = sizetochar (GET_MODE_BITSIZE (info.elt_mode));
+ lane_count = width / GET_MODE_BITSIZE (info.elt_mode);
- mode = GET_MODE_INNER (mode);
- if (GET_MODE_CLASS (mode) == MODE_FLOAT)
+ if (GET_MODE_CLASS (info.elt_mode) == MODE_FLOAT)
{
- gcc_assert (info.shift == 0 && ! info.mvn);
+ gcc_assert (info.shift == 0 && info.insn == simd_immediate_info::MOV);
/* For FP zero change it to a CONST_INT 0 and use the integer SIMD
move immediate path. */
if (aarch64_float_const_zero_rtx_p (info.value))
@@ -13125,7 +13144,7 @@ aarch64_output_simd_mov_immediate (rtx const_vector,
char float_buf[buf_size] = {'\0'};
real_to_decimal_for_mode (float_buf,
CONST_DOUBLE_REAL_VALUE (info.value),
- buf_size, buf_size, 1, mode);
+ buf_size, buf_size, 1, info.elt_mode);
if (lane_count == 1)
snprintf (templ, sizeof (templ), "fmov\t%%d0, %s", float_buf);
@@ -13140,8 +13159,8 @@ aarch64_output_simd_mov_immediate (rtx const_vector,
if (which == AARCH64_CHECK_MOV)
{
- mnemonic = info.mvn ? "mvni" : "movi";
- shift_op = info.msl ? "msl" : "lsl";
+ mnemonic = info.insn == simd_immediate_info::MVN ? "mvni" : "movi";
+ shift_op = info.modifier == simd_immediate_info::MSL ? "msl" : "lsl";
if (lane_count == 1)
snprintf (templ, sizeof (templ), "%s\t%%d0, " HOST_WIDE_INT_PRINT_HEX,
mnemonic, UINTVAL (info.value));
@@ -13157,7 +13176,7 @@ aarch64_output_simd_mov_immediate (rtx const_vector,
else
{
/* For AARCH64_CHECK_BIC and AARCH64_CHECK_ORR. */
- mnemonic = info.mvn ? "bic" : "orr";
+ mnemonic = info.insn == simd_immediate_info::MVN ? "bic" : "orr";
if (info.shift)
snprintf (templ, sizeof (templ), "%s\t%%0.%d%c, #"
HOST_WIDE_INT_PRINT_DEC ", %s #%d", mnemonic, lane_count,
@@ -13191,7 +13210,7 @@ aarch64_output_scalar_simd_mov_immediate (rtx immediate, scalar_int_mode mode)
vmode = aarch64_simd_container_mode (mode, width);
rtx v_op = aarch64_simd_gen_const_vector_dup (vmode, INTVAL (immediate));
- return aarch64_output_simd_mov_immediate (v_op, vmode, width);
+ return aarch64_output_simd_mov_immediate (v_op, width);
}
/* Split operands into moves from op[1] + op[2] into op[0]. */
diff --git a/gcc/config/aarch64/constraints.md b/gcc/config/aarch64/constraints.md
index 474151e..3ca7ec7 100644
--- a/gcc/config/aarch64/constraints.md
+++ b/gcc/config/aarch64/constraints.md
@@ -210,22 +210,21 @@
"@internal
A constraint that matches vector of immediates for orr."
(and (match_code "const_vector")
- (match_test "aarch64_simd_valid_immediate (op, mode, false,
- NULL, AARCH64_CHECK_ORR)")))
+ (match_test "aarch64_simd_valid_immediate (op, NULL,
+ AARCH64_CHECK_ORR)")))
(define_constraint "Db"
"@internal
A constraint that matches vector of immediates for bic."
(and (match_code "const_vector")
- (match_test "aarch64_simd_valid_immediate (op, mode, false,
- NULL, AARCH64_CHECK_BIC)")))
+ (match_test "aarch64_simd_valid_immediate (op, NULL,
+ AARCH64_CHECK_BIC)")))
(define_constraint "Dn"
"@internal
A constraint that matches vector of immediates."
(and (match_code "const_vector")
- (match_test "aarch64_simd_valid_immediate (op, GET_MODE (op),
- false, NULL)")))
+ (match_test "aarch64_simd_valid_immediate (op, NULL)")))
(define_constraint "Dh"
"@internal
diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md
index 3330379..b5e9f37 100644
--- a/gcc/config/aarch64/iterators.md
+++ b/gcc/config/aarch64/iterators.md
@@ -461,6 +461,13 @@
(V1DF "1") (V2DF "2")
(DI "1") (DF "1")])
+;; Map a mode to the number of bits in it, if the size of the mode
+;; is constant.
+(define_mode_attr bitsize [(V8QI "64") (V16QI "128")
+ (V4HI "64") (V8HI "128")
+ (V2SI "64") (V4SI "128")
+ (V2DI "128")])
+
;; Map a floating point or integer mode to the appropriate register name prefix
(define_mode_attr s [(HF "h") (SF "s") (DF "d") (SI "s") (DI "d")])
diff --git a/gcc/config/aarch64/predicates.md b/gcc/config/aarch64/predicates.md
index ce7bbb1..10259c0 100644
--- a/gcc/config/aarch64/predicates.md
+++ b/gcc/config/aarch64/predicates.md
@@ -72,14 +72,14 @@
(define_predicate "aarch64_reg_or_orr_imm"
(ior (match_operand 0 "register_operand")
(and (match_code "const_vector")
- (match_test "aarch64_simd_valid_immediate (op, mode, false,
- NULL, AARCH64_CHECK_ORR)"))))
+ (match_test "aarch64_simd_valid_immediate (op, NULL,
+ AARCH64_CHECK_ORR)"))))
(define_predicate "aarch64_reg_or_bic_imm"
(ior (match_operand 0 "register_operand")
(and (match_code "const_vector")
- (match_test "aarch64_simd_valid_immediate (op, mode, false,
- NULL, AARCH64_CHECK_BIC)"))))
+ (match_test "aarch64_simd_valid_immediate (op, NULL,
+ AARCH64_CHECK_BIC)"))))
(define_predicate "aarch64_fp_compare_operand"
(ior (match_operand 0 "register_operand")
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 1b8e7ad..2003706 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,10 @@
+2018-01-03 Richard Sandiford <richard.sandiford@linaro.org>
+ Alan Hayward <alan.hayward@arm.com>
+ David Sherwood <david.sherwood@arm.com>
+
+ * gcc.target/aarch64/vect-movi.c (movi_float_lsl24): New function.
+ (main): Call it.
+
2018-01-03 Jeff Law <law@redhat.com>
PR target/83641
diff --git a/gcc/testsuite/gcc.target/aarch64/vect-movi.c b/gcc/testsuite/gcc.target/aarch64/vect-movi.c
index 53bb491..311d3da 100644
--- a/gcc/testsuite/gcc.target/aarch64/vect-movi.c
+++ b/gcc/testsuite/gcc.target/aarch64/vect-movi.c
@@ -45,10 +45,21 @@ mvni_msl16 (int *__restrict a)
a[i] = 0xff540000;
}
+static void
+movi_float_lsl24 (float * a)
+{
+ int i;
+
+ /* { dg-final { scan-assembler {\tmovi\tv[0-9]+\.[42]s, 0x43, lsl 24\n} } } */
+ for (i = 0; i < N; i++)
+ a[i] = 128.0;
+}
+
int
main (void)
{
int a[N] = { 0 };
+ float b[N] = { 0 };
int i;
#define CHECK_ARRAY(a, val) \
@@ -68,6 +79,9 @@ main (void)
mvni_msl16 (a);
CHECK_ARRAY (a, 0xff540000);
+ movi_float_lsl24 (b);
+ CHECK_ARRAY (b, 128.0);
+
return 0;
}