https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127778

--- Comment #2 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by Jeff Law <[email protected]>:

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.

Reply via email to