Commit b187677b by Richard Sandiford Committed by Richard Sandiford

[AArch64] Rewrite aarch64_simd_valid_immediate

This patch reworks aarch64_simd_valid_immediate so that
it's easier to add SVE support.  The main changes are:

- make simd_immediate_info easier to construct
- replace the while (1) { ... break; } blocks with checks that use
  the full 64-bit value of the constant
- treat floating-point modes as integers if they aren't valid
  as floating-point values

2018-01-03  Richard Sandiford  <richard.sandiford@linaro.org>
	    Alan Hayward  <alan.hayward@arm.com>
	    David Sherwood  <david.sherwood@arm.com>

gcc/
	* 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.

gcc/testsuite/
	* gcc.target/aarch64/vect-movi.c (movi_float_lsl24): New function.
	(main): Call it.

Co-Authored-By: Alan Hayward <alan.hayward@arm.com>
Co-Authored-By: David Sherwood <david.sherwood@arm.com>

From-SVN: r256205
parent c6561a1a
...@@ -2,6 +2,43 @@ ...@@ -2,6 +2,43 @@
Alan Hayward <alan.hayward@arm.com> Alan Hayward <alan.hayward@arm.com>
David Sherwood <david.sherwood@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. * machmode.h (mode_precision): Prefix with CONST_MODE_PRECISION.
(mode_nunits): Likewise CONST_MODE_NUNITS. (mode_nunits): Likewise CONST_MODE_NUNITS.
* machmode.def (ADJUST_NUNITS): Document. * machmode.def (ADJUST_NUNITS): Document.
......
...@@ -368,7 +368,7 @@ bool aarch64_mov_operand_p (rtx, machine_mode); ...@@ -368,7 +368,7 @@ bool aarch64_mov_operand_p (rtx, machine_mode);
rtx aarch64_reverse_mask (machine_mode, unsigned int); rtx aarch64_reverse_mask (machine_mode, unsigned int);
bool aarch64_offset_7bit_signed_scaled_p (machine_mode, HOST_WIDE_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_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); enum simd_immediate_check w = AARCH64_CHECK_MOV);
bool aarch64_pad_reg_upward (machine_mode, const_tree, bool); bool aarch64_pad_reg_upward (machine_mode, const_tree, bool);
bool aarch64_regno_ok_for_base_p (int, 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, ...@@ -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_imm_zero_p (rtx, machine_mode);
bool aarch64_simd_scalar_immediate_valid_for_move (rtx, scalar_int_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_shift_imm_p (rtx, machine_mode, bool);
bool aarch64_simd_valid_immediate (rtx, machine_mode, bool, bool aarch64_simd_valid_immediate (rtx, struct simd_immediate_info *,
struct simd_immediate_info *,
enum simd_immediate_check w = AARCH64_CHECK_MOV); enum simd_immediate_check w = AARCH64_CHECK_MOV);
bool aarch64_split_dimode_const_store (rtx, rtx); bool aarch64_split_dimode_const_store (rtx, rtx);
bool aarch64_symbolic_address_p (rtx); bool aarch64_symbolic_address_p (rtx);
......
...@@ -120,8 +120,7 @@ ...@@ -120,8 +120,7 @@
case 5: return "fmov\t%d0, %1"; case 5: return "fmov\t%d0, %1";
case 6: return "mov\t%0, %1"; case 6: return "mov\t%0, %1";
case 7: case 7:
return aarch64_output_simd_mov_immediate (operands[1], return aarch64_output_simd_mov_immediate (operands[1], 64);
<MODE>mode, 64);
default: gcc_unreachable (); default: gcc_unreachable ();
} }
} }
...@@ -154,7 +153,7 @@ ...@@ -154,7 +153,7 @@
case 6: case 6:
return "#"; return "#";
case 7: case 7:
return aarch64_output_simd_mov_immediate (operands[1], <MODE>mode, 128); return aarch64_output_simd_mov_immediate (operands[1], 128);
default: default:
gcc_unreachable (); gcc_unreachable ();
} }
...@@ -647,8 +646,8 @@ ...@@ -647,8 +646,8 @@
case 0: case 0:
return "and\t%0.<Vbtype>, %1.<Vbtype>, %2.<Vbtype>"; return "and\t%0.<Vbtype>, %1.<Vbtype>, %2.<Vbtype>";
case 1: case 1:
return aarch64_output_simd_mov_immediate (operands[2], return aarch64_output_simd_mov_immediate (operands[2], <bitsize>,
<MODE>mode, GET_MODE_BITSIZE (<MODE>mode), AARCH64_CHECK_BIC); AARCH64_CHECK_BIC);
default: default:
gcc_unreachable (); gcc_unreachable ();
} }
...@@ -668,8 +667,8 @@ ...@@ -668,8 +667,8 @@
case 0: case 0:
return "orr\t%0.<Vbtype>, %1.<Vbtype>, %2.<Vbtype>"; return "orr\t%0.<Vbtype>, %1.<Vbtype>, %2.<Vbtype>";
case 1: case 1:
return aarch64_output_simd_mov_immediate (operands[2], return aarch64_output_simd_mov_immediate (operands[2], <bitsize>,
<MODE>mode, GET_MODE_BITSIZE (<MODE>mode), AARCH64_CHECK_ORR); AARCH64_CHECK_ORR);
default: default:
gcc_unreachable (); gcc_unreachable ();
} }
......
...@@ -117,15 +117,53 @@ struct aarch64_address_info { ...@@ -117,15 +117,53 @@ struct aarch64_address_info {
enum aarch64_symbol_type symbol_type; enum aarch64_symbol_type symbol_type;
}; };
/* Information about a legitimate vector immediate operand. */
struct simd_immediate_info 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; rtx value;
int shift;
int element_width; /* The instruction to use to move the immediate into a vector. */
bool mvn; insn_type insn;
bool msl;
/* 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. */ /* The current code model. */
enum aarch64_code_model aarch64_cmodel; enum aarch64_code_model aarch64_cmodel;
...@@ -4873,7 +4911,7 @@ aarch64_can_const_movi_rtx_p (rtx x, machine_mode mode) ...@@ -4873,7 +4911,7 @@ aarch64_can_const_movi_rtx_p (rtx x, machine_mode mode)
vmode = aarch64_simd_container_mode (imode, width); vmode = aarch64_simd_container_mode (imode, width);
rtx v_op = aarch64_simd_gen_const_vector_dup (vmode, ival); 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) ...@@ -11493,200 +11531,185 @@ sizetochar (int size)
} }
} }
/* Return true iff x is a uniform vector of floating-point /* Return true if replicating VAL32 is a valid 2-byte or 4-byte immediate
constants, and the constant can be represented in for the Advanced SIMD operation described by WHICH and INSN. If INFO
quarter-precision form. Note, as aarch64_float_const_representable is nonnull, use it to describe valid immediates. */
rejects both +0.0 and -0.0, we will also reject +0.0 and -0.0. */
static bool static bool
aarch64_vect_float_const_representable_p (rtx x) aarch64_advsimd_valid_immediate_hs (unsigned int val32,
{ simd_immediate_info *info,
rtx elt; enum simd_immediate_check which,
return (GET_MODE_CLASS (GET_MODE (x)) == MODE_VECTOR_FLOAT simd_immediate_info::insn_type insn)
&& const_vec_duplicate_p (x, &elt) {
&& aarch64_float_const_representable_p (elt)); /* Try a 4-byte immediate with LSL. */
} for (unsigned int shift = 0; shift < 32; shift += 8)
if ((val32 & (0xff << shift)) == val32)
/* Return true for valid and false for invalid. */ {
bool if (info)
aarch64_simd_valid_immediate (rtx op, machine_mode mode, bool inverse, *info = simd_immediate_info (SImode, val32 >> shift, insn,
struct simd_immediate_info *info, simd_immediate_info::LSL, shift);
enum simd_immediate_check which) return true;
{ }
#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;
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); if (info)
scalar_float_mode elt_mode *info = simd_immediate_info (HImode, imm16 >> shift, insn,
= as_a <scalar_float_mode> (GET_MODE (elt)); simd_immediate_info::LSL, shift);
return true;
info->value = elt;
info->element_width = GET_MODE_BITSIZE (elt_mode);
info->mvn = false;
info->shift = 0;
} }
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. */ return false;
for (i = 0; i < n_elts; i++) }
/* 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, if ((which & AARCH64_CHECK_ORR) != 0
it must be laid out in the vector register in reverse order. */ && aarch64_advsimd_valid_immediate_hs (val32, info, which,
rtx el = CONST_VECTOR_ELT (op, BYTES_BIG_ENDIAN ? (n_elts - 1 - i) : i); simd_immediate_info::MOV))
unsigned HOST_WIDE_INT elpart; return true;
gcc_assert (CONST_INT_P (el)); if ((which & AARCH64_CHECK_BIC) != 0
elpart = INTVAL (el); && 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; if (info)
elpart >>= BITS_PER_UNIT; *info = simd_immediate_info (QImode, val8);
return true;
} }
} }
/* Sanity check. */ /* Try using a bit-to-bytemask. */
gcc_assert (idx == GET_MODE_SIZE (mode)); if (which == AARCH64_CHECK_MOV)
do
{ {
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 unsigned char byte = (val64 >> i) & 0xff;
&& bytes[i + 2] == 0 && bytes[i + 3] == 0, 0, 0); if (byte != 0 && byte != 0xff)
break;
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);
} }
if (i == 64)
/* Shifting ones / 8-bit / 64-bit variants only checked
for 'ALL' (MOVI/MVNI). */
if (which == AARCH64_CHECK_MOV)
{ {
CHECK (4, 32, 12, bytes[i] == 0xff && bytes[i + 1] == bytes[1] if (info)
&& bytes[i + 2] == 0 && bytes[i + 3] == 0, 8, 0); *info = simd_immediate_info (DImode, val64);
return true;
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);
} }
} }
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; 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; if (info)
info->mvn = emvn != 0; *info = simd_immediate_info (elt_float_mode, elt);
info->shift = eshift; return true;
}
unsigned HOST_WIDE_INT imm = 0;
if (immtype >= 12 && immtype <= 15) unsigned int elt_size = GET_MODE_SIZE (elt_mode);
info->msl = true; if (elt_size > 8)
return false;
/* Un-invert bytes of recognized vector, if necessary. */ scalar_int_mode elt_int_mode = int_mode_for_mode (elt_mode).require ();
if (invmask != 0)
for (i = 0; i < idx; i++)
bytes[i] ^= invmask;
if (immtype == 17) /* Expand the vector constant out into a byte vector, with the least
{ significant byte of the register first. */
/* FIXME: Broken on 32-bit H_W_I hosts. */ auto_vec<unsigned char, 16> bytes;
gcc_assert (sizeof (HOST_WIDE_INT) == 8); 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++) if (elt_mode != elt_int_mode)
imm |= (unsigned HOST_WIDE_INT) (bytes[i] ? 0xff : 0) elt = gen_lowpart (elt_int_mode, elt);
<< (i * BITS_PER_UNIT);
if (!CONST_INT_P (elt))
return false;
info->value = GEN_INT (imm); unsigned HOST_WIDE_INT elt_val = INTVAL (elt);
} for (unsigned int byte = 0; byte < elt_size; byte++)
else
{ {
for (i = 0; i < elsize / BITS_PER_UNIT; i++) bytes.quick_push (elt_val & 0xff);
imm |= (unsigned HOST_WIDE_INT) bytes[i] << (i * BITS_PER_UNIT); elt_val >>= 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);
} }
} }
return true; /* The immediate must repeat every eight bytes. */
#undef CHECK 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. */ /* 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) ...@@ -11758,7 +11781,7 @@ aarch64_simd_scalar_immediate_valid_for_move (rtx op, scalar_int_mode mode)
vmode = aarch64_preferred_simd_mode (mode); vmode = aarch64_preferred_simd_mode (mode);
rtx op_v = aarch64_simd_gen_const_vector_dup (vmode, INTVAL (op)); 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 /* Construct and return a PARALLEL RTX vector with elements numbering the
...@@ -12006,7 +12029,7 @@ aarch64_simd_make_constant (rtx vals) ...@@ -12006,7 +12029,7 @@ aarch64_simd_make_constant (rtx vals)
gcc_unreachable (); gcc_unreachable ();
if (const_vec != NULL_RTX 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. */ /* Load using MOVI/MVNI. */
return const_vec; return const_vec;
else if ((const_dup = aarch64_simd_dup_constant (vals)) != NULL_RTX) else if ((const_dup = aarch64_simd_dup_constant (vals)) != NULL_RTX)
...@@ -13086,9 +13109,7 @@ aarch64_float_const_representable_p (rtx x) ...@@ -13086,9 +13109,7 @@ aarch64_float_const_representable_p (rtx x)
immediate with a CONST_VECTOR of MODE and WIDTH. WHICH selects whether to immediate with a CONST_VECTOR of MODE and WIDTH. WHICH selects whether to
output MOVI/MVNI, ORR or BIC immediate. */ output MOVI/MVNI, ORR or BIC immediate. */
char* char*
aarch64_output_simd_mov_immediate (rtx const_vector, aarch64_output_simd_mov_immediate (rtx const_vector, unsigned width,
machine_mode mode,
unsigned width,
enum simd_immediate_check which) enum simd_immediate_check which)
{ {
bool is_valid; bool is_valid;
...@@ -13098,23 +13119,21 @@ aarch64_output_simd_mov_immediate (rtx const_vector, ...@@ -13098,23 +13119,21 @@ aarch64_output_simd_mov_immediate (rtx const_vector,
unsigned int lane_count = 0; unsigned int lane_count = 0;
char element_char; 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 /* 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. a AdvSIMD MOVI instruction (or, implicitly, MVNI), ORR or BIC immediate.
It will also update INFO to show how the immediate should be generated. It will also update INFO to show how the immediate should be generated.
WHICH selects whether to check for MOVI/MVNI, ORR or BIC. */ WHICH selects whether to check for MOVI/MVNI, ORR or BIC. */
is_valid = aarch64_simd_valid_immediate (const_vector, mode, false, is_valid = aarch64_simd_valid_immediate (const_vector, &info, which);
&info, which);
gcc_assert (is_valid); gcc_assert (is_valid);
element_char = sizetochar (info.element_width); element_char = sizetochar (GET_MODE_BITSIZE (info.elt_mode));
lane_count = width / info.element_width; lane_count = width / GET_MODE_BITSIZE (info.elt_mode);
mode = GET_MODE_INNER (mode); if (GET_MODE_CLASS (info.elt_mode) == MODE_FLOAT)
if (GET_MODE_CLASS (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 /* For FP zero change it to a CONST_INT 0 and use the integer SIMD
move immediate path. */ move immediate path. */
if (aarch64_float_const_zero_rtx_p (info.value)) if (aarch64_float_const_zero_rtx_p (info.value))
...@@ -13125,7 +13144,7 @@ aarch64_output_simd_mov_immediate (rtx const_vector, ...@@ -13125,7 +13144,7 @@ aarch64_output_simd_mov_immediate (rtx const_vector,
char float_buf[buf_size] = {'\0'}; char float_buf[buf_size] = {'\0'};
real_to_decimal_for_mode (float_buf, real_to_decimal_for_mode (float_buf,
CONST_DOUBLE_REAL_VALUE (info.value), CONST_DOUBLE_REAL_VALUE (info.value),
buf_size, buf_size, 1, mode); buf_size, buf_size, 1, info.elt_mode);
if (lane_count == 1) if (lane_count == 1)
snprintf (templ, sizeof (templ), "fmov\t%%d0, %s", float_buf); snprintf (templ, sizeof (templ), "fmov\t%%d0, %s", float_buf);
...@@ -13140,8 +13159,8 @@ aarch64_output_simd_mov_immediate (rtx const_vector, ...@@ -13140,8 +13159,8 @@ aarch64_output_simd_mov_immediate (rtx const_vector,
if (which == AARCH64_CHECK_MOV) if (which == AARCH64_CHECK_MOV)
{ {
mnemonic = info.mvn ? "mvni" : "movi"; mnemonic = info.insn == simd_immediate_info::MVN ? "mvni" : "movi";
shift_op = info.msl ? "msl" : "lsl"; shift_op = info.modifier == simd_immediate_info::MSL ? "msl" : "lsl";
if (lane_count == 1) if (lane_count == 1)
snprintf (templ, sizeof (templ), "%s\t%%d0, " HOST_WIDE_INT_PRINT_HEX, snprintf (templ, sizeof (templ), "%s\t%%d0, " HOST_WIDE_INT_PRINT_HEX,
mnemonic, UINTVAL (info.value)); mnemonic, UINTVAL (info.value));
...@@ -13157,7 +13176,7 @@ aarch64_output_simd_mov_immediate (rtx const_vector, ...@@ -13157,7 +13176,7 @@ aarch64_output_simd_mov_immediate (rtx const_vector,
else else
{ {
/* For AARCH64_CHECK_BIC and AARCH64_CHECK_ORR. */ /* 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) if (info.shift)
snprintf (templ, sizeof (templ), "%s\t%%0.%d%c, #" snprintf (templ, sizeof (templ), "%s\t%%0.%d%c, #"
HOST_WIDE_INT_PRINT_DEC ", %s #%d", mnemonic, lane_count, 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) ...@@ -13191,7 +13210,7 @@ aarch64_output_scalar_simd_mov_immediate (rtx immediate, scalar_int_mode mode)
vmode = aarch64_simd_container_mode (mode, width); vmode = aarch64_simd_container_mode (mode, width);
rtx v_op = aarch64_simd_gen_const_vector_dup (vmode, INTVAL (immediate)); 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]. */ /* Split operands into moves from op[1] + op[2] into op[0]. */
......
...@@ -210,22 +210,21 @@ ...@@ -210,22 +210,21 @@
"@internal "@internal
A constraint that matches vector of immediates for orr." A constraint that matches vector of immediates for orr."
(and (match_code "const_vector") (and (match_code "const_vector")
(match_test "aarch64_simd_valid_immediate (op, mode, false, (match_test "aarch64_simd_valid_immediate (op, NULL,
NULL, AARCH64_CHECK_ORR)"))) AARCH64_CHECK_ORR)")))
(define_constraint "Db" (define_constraint "Db"
"@internal "@internal
A constraint that matches vector of immediates for bic." A constraint that matches vector of immediates for bic."
(and (match_code "const_vector") (and (match_code "const_vector")
(match_test "aarch64_simd_valid_immediate (op, mode, false, (match_test "aarch64_simd_valid_immediate (op, NULL,
NULL, AARCH64_CHECK_BIC)"))) AARCH64_CHECK_BIC)")))
(define_constraint "Dn" (define_constraint "Dn"
"@internal "@internal
A constraint that matches vector of immediates." A constraint that matches vector of immediates."
(and (match_code "const_vector") (and (match_code "const_vector")
(match_test "aarch64_simd_valid_immediate (op, GET_MODE (op), (match_test "aarch64_simd_valid_immediate (op, NULL)")))
false, NULL)")))
(define_constraint "Dh" (define_constraint "Dh"
"@internal "@internal
......
...@@ -461,6 +461,13 @@ ...@@ -461,6 +461,13 @@
(V1DF "1") (V2DF "2") (V1DF "1") (V2DF "2")
(DI "1") (DF "1")]) (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 ;; 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")]) (define_mode_attr s [(HF "h") (SF "s") (DF "d") (SI "s") (DI "d")])
......
...@@ -72,14 +72,14 @@ ...@@ -72,14 +72,14 @@
(define_predicate "aarch64_reg_or_orr_imm" (define_predicate "aarch64_reg_or_orr_imm"
(ior (match_operand 0 "register_operand") (ior (match_operand 0 "register_operand")
(and (match_code "const_vector") (and (match_code "const_vector")
(match_test "aarch64_simd_valid_immediate (op, mode, false, (match_test "aarch64_simd_valid_immediate (op, NULL,
NULL, AARCH64_CHECK_ORR)")))) AARCH64_CHECK_ORR)"))))
(define_predicate "aarch64_reg_or_bic_imm" (define_predicate "aarch64_reg_or_bic_imm"
(ior (match_operand 0 "register_operand") (ior (match_operand 0 "register_operand")
(and (match_code "const_vector") (and (match_code "const_vector")
(match_test "aarch64_simd_valid_immediate (op, mode, false, (match_test "aarch64_simd_valid_immediate (op, NULL,
NULL, AARCH64_CHECK_BIC)")))) AARCH64_CHECK_BIC)"))))
(define_predicate "aarch64_fp_compare_operand" (define_predicate "aarch64_fp_compare_operand"
(ior (match_operand 0 "register_operand") (ior (match_operand 0 "register_operand")
......
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> 2018-01-03 Jeff Law <law@redhat.com>
PR target/83641 PR target/83641
......
...@@ -45,10 +45,21 @@ mvni_msl16 (int *__restrict a) ...@@ -45,10 +45,21 @@ mvni_msl16 (int *__restrict a)
a[i] = 0xff540000; 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 int
main (void) main (void)
{ {
int a[N] = { 0 }; int a[N] = { 0 };
float b[N] = { 0 };
int i; int i;
#define CHECK_ARRAY(a, val) \ #define CHECK_ARRAY(a, val) \
...@@ -68,6 +79,9 @@ main (void) ...@@ -68,6 +79,9 @@ main (void)
mvni_msl16 (a); mvni_msl16 (a);
CHECK_ARRAY (a, 0xff540000); CHECK_ARRAY (a, 0xff540000);
movi_float_lsl24 (b);
CHECK_ARRAY (b, 128.0);
return 0; return 0;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment