[AArch64] : Use MOVI for low‑64‑bit integer SIMD constant vectors [PR113926]

Message ID 20260408132341.430684-1-naveen.siddegowda@oss.qualcomm.com
State New
Delegated to: Andrew Pinski
Headers
Series [AArch64] : Use MOVI for low‑64‑bit integer SIMD constant vectors [PR113926] |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gcc_build--master-arm success Build passed

Commit Message

Naveen April 8, 2026, 1:23 p.m. UTC
  Extend AdvSIMD constant materialization to recognize 128‑bit integer vector
constants where the low 64 bits contain a duplicated scalar value and the high
64 bits are zero.
Bootstrapped and tested on aarch64-linux-gnu.

PR target/113926

gcc/ChangeLog:

	* config/aarch64/aarch64.cc (aarch64_const_vec_int_zero_p): New function.
	(aarch64_simd_valid_mov_imm_low64): New function.

gcc/testsuite/ChangeLog:
	* gcc.target/aarch64/pr113926.c: New test.

Signed-off-by: Naveen <naveen.siddegowda@oss.qualcomm.com>
---
 gcc/config/aarch64/aarch64.cc               | 89 ++++++++++++++++++++-
 gcc/testsuite/gcc.target/aarch64/pr113926.c | 15 ++++
 2 files changed, 103 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.target/aarch64/pr113926.c
  

Patch

diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 4405074cdad..50bfb6f65bd 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -24639,11 +24639,90 @@  aarch64_expand_maskloadstore (rtx *operands, machine_mode mode)
   return false;
 }
 
+/* Return true if X is a constant integer zero.  */
+static bool
+aarch64_const_vec_int_zero_p (rtx x)
+{
+  return CONST_INT_P (x) && INTVAL (x) == 0;
+}
+
+/* Return true if OP is a 128-bit vector constant whose low 64 bits are all
+   equal to the same scalar integer value and whose high 64 bits are zero.  */
+static bool
+aarch64_simd_valid_mov_imm_low64 (rtx op, simd_immediate_info *info,
+				  unsigned *out_width)
+{
+  if (!CONST_VECTOR_P (op))
+    return false;
+
+  /* Handle 128-bit vectors.  */
+  machine_mode mode = GET_MODE (op);
+  if (!known_eq (GET_MODE_SIZE (mode), 16))
+    return false;
+
+  scalar_mode inner_mode = GET_MODE_INNER (mode);
+  scalar_int_mode int_mode;
+
+  /* Vector elements must be integers.  */
+  if (!is_a <scalar_int_mode> (inner_mode, &int_mode))
+    return false;
+
+  /* Elements wider than 64 bits cannot form a low-64-bit split.  */
+  if (GET_MODE_BITSIZE (int_mode) > 64)
+    return false;
+
+  /* Determine the start of the low and high 64-bit halves, taking target
+     endianness into account.  */
+  unsigned int nunits = GET_MODE_NUNITS (mode).to_constant ();
+  unsigned int low_nunits = 64 / GET_MODE_BITSIZE (int_mode);
+  unsigned int low_first = BYTES_BIG_ENDIAN ? nunits - low_nunits : 0;
+  unsigned int high_first = BYTES_BIG_ENDIAN ? 0 : low_nunits;
+
+  rtx first = CONST_VECTOR_ELT (op, low_first);
+
+  /* Low half must be a duplicated integer constant.  */
+  if (!CONST_INT_P (first))
+    return false;
+
+  for (unsigned int i = 0; i < low_nunits; ++i)
+    if (!rtx_equal_p (CONST_VECTOR_ELT (op, low_first + i), first))
+      return false;
+
+  for (unsigned int i = 0; i < low_nunits; ++i)
+    if (!aarch64_const_vec_int_zero_p (CONST_VECTOR_ELT (op, high_first + i)))
+      return false;
+
+  machine_mode low_mode;
+  switch (int_mode)
+    {
+      case E_QImode: low_mode = V8QImode; break;
+      case E_HImode: low_mode = V4HImode; break;
+      case E_SImode: low_mode = V2SImode; break;
+      default:
+	return false;
+    }
+
+  HOST_WIDE_INT val = INTVAL (first);
+  rtx low_vec = aarch64_simd_gen_const_vector_dup (low_mode, val);
+  simd_immediate_info tmp;
+
+  /* Validate whether the low 64-bit vector can be encoded as a MOV immediate.  */
+  if (!aarch64_simd_valid_imm (low_vec, &tmp, AARCH64_CHECK_MOV))
+    return false;
+
+  if (info)
+    *info = tmp;
+  if (out_width)
+    *out_width = 64;
+  return true;
+}
+
 /* Return true if OP is a valid SIMD move immediate for SVE or AdvSIMD.  */
 bool
 aarch64_simd_valid_mov_imm (rtx op)
 {
-  return aarch64_simd_valid_imm (op, NULL, AARCH64_CHECK_MOV);
+  return (aarch64_simd_valid_imm (op, NULL, AARCH64_CHECK_MOV)
+	  || aarch64_simd_valid_mov_imm_low64 (op, NULL, NULL));
 }
 
 /* Return true if OP is a valid SIMD orr immediate for SVE or AdvSIMD.  */
@@ -26966,10 +27045,18 @@  aarch64_output_simd_imm (rtx const_vector, unsigned width,
   char element_char;
 
   struct simd_immediate_info info;
+  unsigned output_width = width;
 
   is_valid = aarch64_simd_valid_imm (const_vector, &info, which);
+
+  if (!is_valid && which == AARCH64_CHECK_MOV)
+    is_valid = aarch64_simd_valid_mov_imm_low64 (const_vector, &info,
+						 &output_width);
+
   gcc_assert (is_valid);
 
+  width = output_width;
+
   element_char = sizetochar (GET_MODE_BITSIZE (info.elt_mode));
   lane_count = width / GET_MODE_BITSIZE (info.elt_mode);
 
diff --git a/gcc/testsuite/gcc.target/aarch64/pr113926.c b/gcc/testsuite/gcc.target/aarch64/pr113926.c
new file mode 100644
index 00000000000..bc7cff8ada1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/pr113926.c
@@ -0,0 +1,15 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-additional-options "-march=armv8-a+fp16" } */
+
+typedef int vect128_int __attribute__((vector_size(16)));
+
+vect128_int
+f1 (void)
+{
+  return (vect128_int){1, 1, 0, 0};
+}
+
+/* Should use MOVI instruction.  */
+/* { dg-final { scan-assembler-times {\tmovi\tv[0-9]+\.2s, 0x1} 1 } }  */
+/* { dg-final { scan-assembler-not {\tldr\tq[0-9]+,} } } */