https://gcc.gnu.org/g:8ebf07db4065afb654756ae77d397e2024fef436

commit r17-5116-g8ebf07db4065afb654756ae77d397e2024fef436
Author: Jeff Law <[email protected]>
Date:   Tue Oct 13 07:17:57 2026 -0600

    [RISC-V][PR target/127778] Use synthesize_add more on RISC-V
    
    As the pr127778 shows the changes to generally improve how we synthesize x+C
    regressed a class of cases, particularly those with C in the range 
[2048..4095]
    that are used as an address for a memory reference during initial RTL
    generation.
    
    The problem can be seen in this .expand fragment:
    
    (insn 7 4 8 2 (set (reg:DI 136)
            (const_int 4096 [0x1000])) "j.c":4:11 -1
         (nil))
    (insn 8 7 9 2 (set (reg/f:DI 137)
            (plus:DI (reg/v/f:DI 134 [ p ])
                (reg:DI 136))) "j.c":4:11 -1
         (nil))
    (insn 9 8 0 2 (set (mem:SI (plus:DI (reg/f:DI 137)
                    (const_int -96 [0xffffffffffffffa0])) [1 MEM[(int *)p_1(D) 
+ 4000B]+0 S4 A32])
            (subreg/s/u:SI (reg/v:DI 135 [ v ]) 0)) "j.c":4:11 -1
         (nil))
    
    So we're not using add synthesis, but instead falling back to naive code
    generation.  It turns out there's a path through the RISC-V target files 
which
    avoids the add expanders.  So while we could try to recover good code
    generation later, it seems much better to just generate reasonable code at 
the
    gimple-RTL phase.
    
    This patch intercepts the path through riscv_add_offset and will use
    synthesize_add when possible.  So we get this kind of initial RTL instead:
    
    (insn 7 4 8 2 (set (reg/f:SI 136)
            (plus:SI (reg/v/f:SI 134 [ p ])
                (const_int 1953 [0x7a1]))) "j.c":4:15 -1
         (nil))
    (insn 8 7 9 2 (set (reg/f:SI 136)
            (plus:SI (reg/f:SI 136)
                (const_int 2047 [0x7ff]))) "j.c":4:15 -1
         (nil))
    (insn 9 8 0 2 (set (mem:SI (reg/f:SI 136) [1 MEM[(int *)p_1(D) + 4000B]+0 
S4 A32])
            (reg/v:SI 135 [ v ])) "j.c":4:15 -1
         (nil))
    
    It's trivial to combine insn 8 and insn 9 resulting in the final code
    generation we want to see.
    
    We still bypass the synthesis code when presented with the code in pr105733:
    
    > #define BUF_SIZE 2064
    >
    > void
    > foo(unsigned long i)
    > {
    >    volatile char buf[BUF_SIZE];
    >
    >    buf[i] = 0;
    > }
    >
    In this case the offset is going to be formed with virtual-stack-vars. That
    later gets turned into sp+offset.  Anyway, the initial code generation for 
that
    case looks like this if we're not careful:
    
    (insn 6 3 7 2 (set (reg/f:SI 135)
           (plus:SI (reg/f:SI 129 virtual-stack-vars)
               (const_int -16 [0xfffffffffffffff0]))) "j.c":8:12 -1
        (nil))
    (insn 7 6 8 2 (set (reg/f:SI 135)
           (plus:SI (reg/f:SI 135)
               (const_int -2048 [0xfffffffffffff800]))) "j.c":8:12 -1
        (nil))
    (insn 8 7 9 2 (set (reg/f:SI 136)
           (plus:SI (reg/f:SI 135)
               (reg/v:SI 134 [ i ]))) "j.c":8:12 -1
        (nil))
    (insn 9 8 0 2 (set (mem/v:QI (reg/f:SI 136) [0 buf[i_2(D)]+0 S1 A8])
           (const_int 0 [0])) "j.c":8:12 -1
        (nil))
    
    In this case we'd be dependent upon something rewriting this mess to push 
the
    constant offset down into the mem, and clean up the virtual-stack-vars
    reference post-reload.  fold-mem-offsets would be the natural choice.  But 
it's
    easy enough to special case the base registers that get eliminated so that 
the
    initial RTL we generate looks like this:
    
    (insn 6 3 7 2 (set (reg:SI 135)
            (const_int -4096 [0xfffffffffffff000])) "j.c":8:12 -1
         (nil))
    (insn 7 6 8 2 (set (reg/f:SI 136)
            (plus:SI (reg/f:SI 129 virtual-stack-vars)
                (reg:SI 135))) "j.c":8:12 -1
         (nil))
    (insn 8 7 9 2 (set (reg/f:SI 137)
            (plus:SI (reg/f:SI 136)
                (reg/v:SI 134 [ i ]))) "j.c":8:12 -1
         (nil))
    (insn 9 8 0 2 (set (mem/v:QI (plus:SI (reg/f:SI 137)
                    (const_int 2032 [0x7f0])) [0 buf[i_2(D)]+0 S1 A8])
            (const_int 0 [0])) "j.c":8:12 -1
         (nil))
    
    Which avoids regressing pr105733.  There's still some cruft in the final
    assembly, but I think that's ultimately a failing of fold-mem-offsets that I
    haven't chased down.  I'll get that cruft filed as a distinct bug against
    f-m-o.
    
    Tested on riscv32-elf and riscv64-elf.  I don't recall if this made it into 
my
    tester's git repo early enough to make the overnight bootstraps.  
Regardless,
    it'll get picked up today/tonight.
    
            PR target/127778
    gcc/
            * config/riscv/riscv.cc (riscv_add_offset): Use synthesize_add
            when safe and likely profitable.
    
    gcc/testsuite
            * gcc.target/riscv/pr127778.c: New test.

Diff:
---
 gcc/config/riscv/riscv.cc                 | 14 ++++++++++++++
 gcc/testsuite/gcc.target/riscv/pr127778.c | 16 ++++++++++++++++
 2 files changed, 30 insertions(+)

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index e910245c2bcc..7e480e978d6d 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -3384,6 +3384,20 @@ riscv_add_offset (rtx temp, rtx reg, HOST_WIDE_INT 
offset)
 {
   if (!SMALL_OPERAND (offset))
     {
+      /* Re-use synthesize_add to try and emit efficient code here.  */
+      if ((temp || can_create_pseudo_p ())
+         && reg != frame_pointer_rtx
+         && reg != hard_frame_pointer_rtx
+         && reg != virtual_stack_vars_rtx)
+       {
+         rtx operands[3];
+         operands[0] = temp ? temp : gen_reg_rtx (word_mode);
+         operands[1] = reg;
+         operands[2] = GEN_INT (offset);
+         if (synthesize_add (operands))
+           return operands[0];
+       }
+
       rtx high;
 
       /* Leave OFFSET as a 16-bit offset and put the excess in HIGH.
diff --git a/gcc/testsuite/gcc.target/riscv/pr127778.c 
b/gcc/testsuite/gcc.target/riscv/pr127778.c
new file mode 100644
index 000000000000..3a0d02da473d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr127778.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gcb_zicond -mabi=lp64d" { target { rv64 } } } 
*/
+/* { dg-options "-O2 -march=rv32gcb_zicond -mabi=ilp32d" { target { rv32 } } } 
*/
+
+  void
+  store_4000 (int *p, int v)
+  {
+    p[1000] = v;
+  }
+
+/* { dg-final { scan-assembler-not {\mli} } } */
+/* { dg-final { scan-assembler-times {\maddi\M} 1 } } */
+/* { dg-final { scan-assembler-times {\msw\M} 1 } } */
+
+
+

Reply via email to