aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@arm.com>2024-01-25 12:03:18 +0000
committerRichard Sandiford <richard.sandiford@arm.com>2024-01-25 12:03:18 +0000
commit8eead1148cd0ac086b39a7abccea404041c85cb5 (patch)
tree580fde4f0f6ff136e42dab6cd98113958b37e674
parentf251bbfec9174169510b2dec14b9bf763e7b77af (diff)
downloadgcc-8eead1148cd0ac086b39a7abccea404041c85cb5.zip
gcc-8eead1148cd0ac086b39a7abccea404041c85cb5.tar.gz
gcc-8eead1148cd0ac086b39a7abccea404041c85cb5.tar.bz2
aarch64: Handle overlapping registers in movv8di [PR113550]
The LS64 movv8di pattern didn't handle loads that overlapped with the address register (unless the overlap happened to be in the last subload). gcc/ PR target/113550 * config/aarch64/aarch64-simd.md: In the movv8di splitter, check whether each split instruction is a load that clobbers the source address. Emit that instruction last if so. gcc/testsuite/ PR target/113550 * gcc.target/aarch64/pr113550.c: New test.
-rw-r--r--gcc/config/aarch64/aarch64-simd.md18
-rw-r--r--gcc/testsuite/gcc.target/aarch64/pr113550.c48
2 files changed, 62 insertions, 4 deletions
diff --git a/gcc/config/aarch64/aarch64-simd.md b/gcc/config/aarch64/aarch64-simd.md
index 48f0741..f036f6c 100644
--- a/gcc/config/aarch64/aarch64-simd.md
+++ b/gcc/config/aarch64/aarch64-simd.md
@@ -8221,11 +8221,21 @@
|| (memory_operand (operands[0], V8DImode)
&& register_operand (operands[1], V8DImode)))
{
+ std::pair<rtx, rtx> last_pair = {};
for (int offset = 0; offset < 64; offset += 16)
- emit_move_insn (simplify_gen_subreg (TImode, operands[0],
- V8DImode, offset),
- simplify_gen_subreg (TImode, operands[1],
- V8DImode, offset));
+ {
+ std::pair<rtx, rtx> pair = {
+ simplify_gen_subreg (TImode, operands[0], V8DImode, offset),
+ simplify_gen_subreg (TImode, operands[1], V8DImode, offset)
+ };
+ if (register_operand (pair.first, TImode)
+ && reg_overlap_mentioned_p (pair.first, pair.second))
+ last_pair = pair;
+ else
+ emit_move_insn (pair.first, pair.second);
+ }
+ if (last_pair.first)
+ emit_move_insn (last_pair.first, last_pair.second);
DONE;
}
else
diff --git a/gcc/testsuite/gcc.target/aarch64/pr113550.c b/gcc/testsuite/gcc.target/aarch64/pr113550.c
new file mode 100644
index 0000000..0ff3c7b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/pr113550.c
@@ -0,0 +1,48 @@
+/* { dg-options "-O" } */
+/* { dg-do run } */
+
+#pragma GCC push_options
+#pragma GCC target "+ls64"
+#pragma GCC aarch64 "arm_acle.h"
+#pragma GCC pop_options
+
+#define DEF_FUNCTION(NAME, ARGS) \
+ __attribute__((noipa)) \
+ __arm_data512_t \
+ NAME ARGS \
+ { \
+ return *ptr; \
+ }
+
+DEF_FUNCTION (f0, (__arm_data512_t *ptr))
+DEF_FUNCTION (f1, (int x0, __arm_data512_t *ptr))
+DEF_FUNCTION (f2, (int x0, int x1, __arm_data512_t *ptr))
+DEF_FUNCTION (f3, (int x0, int x1, int x2, __arm_data512_t *ptr))
+DEF_FUNCTION (f4, (int x0, int x1, int x2, int x3, __arm_data512_t *ptr))
+DEF_FUNCTION (f5, (int x0, int x1, int x2, int x3, int x4,
+ __arm_data512_t *ptr))
+DEF_FUNCTION (f6, (int x0, int x1, int x2, int x3, int x4, int x5,
+ __arm_data512_t *ptr))
+DEF_FUNCTION (f7, (int x0, int x1, int x2, int x3, int x4, int x5, int x6,
+ __arm_data512_t *ptr))
+
+int
+main (void)
+{
+ __arm_data512_t x = { 0, 10, 20, 30, 40, 50, 60, 70 };
+ __arm_data512_t res[8] =
+ {
+ f0 (&x),
+ f1 (0, &x),
+ f2 (0, 1, &x),
+ f3 (0, 1, 2, &x),
+ f4 (0, 1, 2, 3, &x),
+ f5 (0, 1, 2, 3, 4, &x),
+ f6 (0, 1, 2, 3, 4, 5, &x),
+ f7 (0, 1, 2, 3, 4, 5, 6, &x)
+ };
+ for (int i = 0; i < 8; ++i)
+ if (__builtin_memcmp (&x, &res[i], sizeof (x)) != 0)
+ __builtin_abort ();
+ return 0;
+}