From e256967df601a2efaf6a0e27efe5db974b132359 Mon Sep 17 00:00:00 2001 From: rsandifo Date: Wed, 3 Jan 2018 21:43:44 +0000 Subject: [PATCH] [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 Alan Hayward David Sherwood 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, and3) (ior3): 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@256205 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 37 +++ gcc/config/aarch64/aarch64-protos.h | 5 +- gcc/config/aarch64/aarch64-simd.md | 13 +- gcc/config/aarch64/aarch64.c | 387 ++++++++++++++------------- gcc/config/aarch64/constraints.md | 11 +- gcc/config/aarch64/iterators.md | 7 + gcc/config/aarch64/predicates.md | 8 +- gcc/testsuite/ChangeLog | 7 + gcc/testsuite/gcc.target/aarch64/vect-movi.c | 14 + 9 files changed, 285 insertions(+), 204 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index dd5d70306f0..9437ae9fd6c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -2,6 +2,43 @@ Alan Hayward David Sherwood + * 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, and3) + (ior3): 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 + Alan Hayward + David Sherwood + * 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 fba063237e0..7df3aae4353 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 a2e0893d8f3..5a85f82880e 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, 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, 128); + return aarch64_output_simd_mov_immediate (operands[1], 128); default: gcc_unreachable (); } @@ -647,8 +646,8 @@ case 0: return "and\t%0., %1., %2."; case 1: - return aarch64_output_simd_mov_immediate (operands[2], - mode, GET_MODE_BITSIZE (mode), AARCH64_CHECK_BIC); + return aarch64_output_simd_mov_immediate (operands[2], , + AARCH64_CHECK_BIC); default: gcc_unreachable (); } @@ -668,8 +667,8 @@ case 0: return "orr\t%0., %1., %2."; case 1: - return aarch64_output_simd_mov_immediate (operands[2], - mode, GET_MODE_BITSIZE (mode), AARCH64_CHECK_ORR); + return aarch64_output_simd_mov_immediate (operands[2], , + AARCH64_CHECK_ORR); default: gcc_unreachable (); } diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 5c258a90cd0..a1896058c6d 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 (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 (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 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 474151eaa40..3ca7ec7c975 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 3330379e05b..b5e9f37629f 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 ce7bbb16a1e..10259c03ad8 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 1b8e7ad6ea5..2003706744e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2018-01-03 Richard Sandiford + Alan Hayward + David Sherwood + + * gcc.target/aarch64/vect-movi.c (movi_float_lsl24): New function. + (main): Call it. + 2018-01-03 Jeff Law PR target/83641 diff --git a/gcc/testsuite/gcc.target/aarch64/vect-movi.c b/gcc/testsuite/gcc.target/aarch64/vect-movi.c index 53bb491ee64..311d3dafaec 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; } -- 2.11.4.GIT