From: juewang <[email protected]>
riscv_legitimize_address handled scaled indexed addresses only when
the constant offset fit an I-type immediate. Large offsets fell back to
generic legalization and could materialize the same base at each
reference.
Use riscv_add_offset for all offsets before adding the scaled index.
This preserves small-offset code generation and exposes large bases to
CSE.
gcc/ChangeLog:
* config/riscv/riscv.cc (riscv_legitimize_address): Use
riscv_add_offset for scaled indexed addresses.
gcc/testsuite/ChangeLog:
* gcc.target/riscv/large-frame-indexed-base.c: New test.
* gcc.target/riscv/small-frame-indexed-base.c: New test.
---
gcc/config/riscv/riscv.cc | 11 +++---
.../riscv/large-frame-indexed-base.c | 37 +++++++++++++++++++
.../riscv/small-frame-indexed-base.c | 35 ++++++++++++++++++
3 files changed, 78 insertions(+), 5 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/large-frame-indexed-base.c
create mode 100644 gcc/testsuite/gcc.target/riscv/small-frame-indexed-base.c
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 873defc5a5b..6eeaa11caab 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -3464,9 +3464,11 @@ riscv_legitimize_address (rtx x, rtx oldx
ATTRIBUTE_UNUSED,
rtx base = XEXP (x, 0);
HOST_WIDE_INT offset = INTVAL (XEXP (x, 1));
- /* Handle (plus (plus (mult (a) (mem_shadd_constant)) (fp)) (C)) case.
*/
- if (GET_CODE (base) == PLUS && mem_shadd_or_shadd_rtx_p (XEXP (base, 0))
- && SMALL_OPERAND (offset))
+ /* Handle (plus (plus (mult (a) (mem_shadd_constant))
+ (stack_base)) (C)).
+ Form STACK_BASE + C before adding the scaled index, so that CSE can
+ share the base when C is a large frame offset. */
+ if (GET_CODE (base) == PLUS && mem_shadd_or_shadd_rtx_p (XEXP (base, 0)))
{
rtx index = XEXP (base, 0);
rtx fp = XEXP (base, 1);
@@ -3479,10 +3481,9 @@ riscv_legitimize_address (rtx x, rtx oldx
ATTRIBUTE_UNUSED,
if (GET_CODE (index) == MULT)
shift_val = exact_log2 (shift_val);
- rtx reg1 = gen_reg_rtx (Pmode);
+ rtx reg1 = force_reg (Pmode, riscv_add_offset (NULL, fp, offset));
rtx reg2 = gen_reg_rtx (Pmode);
rtx reg3 = gen_reg_rtx (Pmode);
- riscv_emit_binary (PLUS, reg1, fp, GEN_INT (offset));
riscv_emit_binary (ASHIFT, reg2, XEXP (index, 0), GEN_INT
(shift_val));
riscv_emit_binary (PLUS, reg3, reg2, reg1);
diff --git a/gcc/testsuite/gcc.target/riscv/large-frame-indexed-base.c
b/gcc/testsuite/gcc.target/riscv/large-frame-indexed-base.c
new file mode 100644
index 00000000000..98549996cfa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/large-frame-indexed-base.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-stack-protector -march=rv64gc_zba -mabi=lp64d" } */
+
+struct item
+{
+ struct item *a;
+ long b;
+ long c;
+ long d;
+};
+
+extern void init (struct item **);
+
+static __attribute__ ((always_inline)) inline void
+update (long *index, struct item **perm, struct item *value, long x)
+{
+ ++*index;
+ perm[*index]->a = value;
+ perm[*index]->b = x;
+ perm[*index]->c = x < 0 ? -x : x;
+ perm[*index]->d = 0;
+}
+
+__attribute__ ((noinline, noclone))
+void
+large_frame_indexed_loop (long *indices, struct item **values, long count)
+{
+ struct item *perm[4096];
+
+ init (perm);
+ for (long i = 0; i < count; ++i)
+ update (&indices[i], perm, values[i], i);
+}
+
+/* { dg-final { scan-assembler-times {\tli\t[^\n]+,-32768} 1 } } */
+/* { dg-final { scan-assembler-times {\tli\t[^\n]+,32768} 1 } } */
+/* { dg-final { scan-assembler {\tsh3add\t} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/small-frame-indexed-base.c
b/gcc/testsuite/gcc.target/riscv/small-frame-indexed-base.c
new file mode 100644
index 00000000000..9ed0ecdd03e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/small-frame-indexed-base.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-stack-protector -march=rv64gc_zba -mabi=lp64d" } */
+
+struct item
+{
+ struct item *a;
+ long b;
+ long c;
+ long d;
+};
+
+extern void init (struct item **);
+
+static __attribute__ ((always_inline)) inline void
+update (long *index, struct item **perm, struct item *value, long x)
+{
+ ++*index;
+ perm[*index]->a = value;
+ perm[*index]->b = x;
+ perm[*index]->c = x < 0 ? -x : x;
+ perm[*index]->d = 0;
+}
+
+__attribute__ ((noinline, noclone))
+void
+small_frame_indexed_access (long *index, struct item *value, long x)
+{
+ struct item *perm[64];
+
+ init (perm);
+ update (index, perm, value, x);
+}
+
+/* { dg-final { scan-assembler-not {\tli\t} } } */
+/* { dg-final { scan-assembler-times {\tsh3add\t} 3 } } */
--
2.34.1