[AArch64] Rewrite aarch64_simd_valid_immediate
authorRichard Sandiford <richard.sandiford@linaro.org>
Wed, 3 Jan 2018 21:43:44 +0000 (21:43 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Wed, 3 Jan 2018 21:43:44 +0000 (21:43 +0000)
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

gcc/ChangeLog
gcc/config/aarch64/aarch64-protos.h
gcc/config/aarch64/aarch64-simd.md
gcc/config/aarch64/aarch64.c
gcc/config/aarch64/constraints.md
gcc/config/aarch64/iterators.md
gcc/config/aarch64/predicates.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/aarch64/vect-movi.c

index dd5d70306f02ef8df8416151ffddff95681376b5..9437ae9fd6c35b1088eaf736a8c2e3c399d37f62 100644 (file)
@@ -1,3 +1,40 @@
+2018-01-03  Richard Sandiford  <richard.sandiford@linaro.org>
+           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>
index fba063237e0c8819881499ceb2ad67364bd0a6c3..7df3aae4353f6f9e71f5d554c1c935881a958d28 100644 (file)
@@ -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);
index a2e0893d8f3aa04f23a737b1eddcb11b66216fe2..5a85f82880e0f190f52a74d77c01d0207ed7d000 100644 (file)
      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 ();
      }
 }
     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 ();
     }
       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 ();
       }
       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 ();
       }
index 5c258a90cd09da663a8541b329ed21f87062d4d7..a1896058c6d305af1b7cea8b7fb5d9a815b31cb5 100644 (file)
@@ -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].  */
index 474151eaa40fd4a708f3ac9c6ccee0c54caf6fd7..3ca7ec7c975d5190a165bc51b17471ebcde4ff34 100644 (file)
   "@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
index 3330379e05b56e9b256143451fa8fb21d2bb2a3a..b5e9f37629fe2b5ed17093be780e973ec0ac8670 100644 (file)
                          (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")])
 
index ce7bbb16a1e257a3abfb7eac88f64454f9c90b80..10259c03ad865e65cdbbc63f6d68bb8a5d7bcdc5 100644 (file)
 (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")
index 1b8e7ad6ea5a41e366af964a3847c3a568d3419d..2003706744e7e70a5e524d261eae3b9ccde16519 100644 (file)
@@ -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
index 53bb491ee6472d87f38b375d5a51148aa19acd31..311d3dafaec73e76591abc96df50827e5bd6b94c 100644 (file)
@@ -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;
 }