]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
AArch64: Reassociate CONST in address expressions
authorWilco Dijkstra <wilco.dijkstra@arm.com>
Tue, 16 Jan 2024 16:27:02 +0000 (16:27 +0000)
committerWilco Dijkstra <wilco.dijkstra@arm.com>
Tue, 16 Jan 2024 17:12:48 +0000 (17:12 +0000)
GCC tends to optimistically create CONST of globals with an immediate offset.
However it is almost always better to CSE addresses of globals and add immediate
offsets separately (the offset could be merged later in single-use cases).
Splitting CONST expressions with an index in aarch64_legitimize_address fixes
part of PR112573.

gcc/ChangeLog:
PR target/112573
* config/aarch64/aarch64.cc (aarch64_legitimize_address): Reassociate
badly formed CONST expressions.

gcc/testsuite/ChangeLog:
PR target/112573
* gcc.target/aarch64/pr112573.c: Add new test.

gcc/config/aarch64/aarch64.cc
gcc/testsuite/gcc.target/aarch64/pr112573.c [new file with mode: 0644]

index 7d1f8c65ce41044d6850262300cf08a23d606617..e6bd3fd0bb42c70603d5335402b89c9deeaf48d8 100644 (file)
@@ -12617,6 +12617,17 @@ aarch64_legitimize_address (rtx x, rtx /* orig_x  */, machine_mode mode)
      not to split a CONST for some forms of address expression, otherwise
      it will generate sub-optimal code.  */
 
+  /* First split X + CONST (base, offset) into (base + X) + offset.  */
+  if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST)
+    {
+      poly_int64 offset;
+      rtx base = strip_offset (XEXP (x, 1), &offset);
+
+      base = expand_binop (Pmode, add_optab, base, XEXP (x, 0),
+                          NULL_RTX, true, OPTAB_DIRECT);
+      x = plus_constant (Pmode, base, offset);
+    }
+
   if (GET_CODE (x) == PLUS && CONST_INT_P (XEXP (x, 1)))
     {
       rtx base = XEXP (x, 0);
diff --git a/gcc/testsuite/gcc.target/aarch64/pr112573.c b/gcc/testsuite/gcc.target/aarch64/pr112573.c
new file mode 100644 (file)
index 0000000..be04c0c
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-section-anchors" } */
+
+char a[100];
+
+void f1 (int x, int y)
+{
+  *((a + y) + 3) = x;
+  *((a + y) + 2) = x;
+  *((a + y) + 1) = x;
+  *((a + y) + 0) = x;
+}
+
+/* { dg-final { scan-assembler-times "strb" 4 } } */
+/* { dg-final { scan-assembler-times "adrp" 1 } } */