https://gcc.gnu.org/g:2887d4857aaaed75f6c7aa6843c5b3cd58954124
commit r17-2428-g2887d4857aaaed75f6c7aa6843c5b3cd58954124 Author: wangjue <[email protected]> Date: Wed Jul 15 15:11:22 2026 -0600 [PATCH v1] RISC-V: Share bases for scaled indexed addresses 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. Diff: --- gcc/config/riscv/riscv.cc | 11 ++++--- .../gcc.target/riscv/large-frame-indexed-base.c | 37 ++++++++++++++++++++++ .../gcc.target/riscv/small-frame-indexed-base.c | 35 ++++++++++++++++++++ 3 files changed, 78 insertions(+), 5 deletions(-) diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 873defc5a5b5..6eeaa11caab2 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 000000000000..98549996cfa8 --- /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 000000000000..9ed0ecdd03e2 --- /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 } } */
