[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
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
@@ -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);
new file mode 100644
@@ -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]+,} } } */