On Sat, Jun 20, 2026 at 2:34 PM H.J. Lu <[email protected]> wrote:
>
> On Sat, Jun 20, 2026 at 12:13 PM H.J. Lu <[email protected]> wrote:
> >
> > Since LCP stall peepholes are added after register allocation, each
> > peephole may use a different scratch register.  For input:
> >
> > extern void bar (void);
> >
> > void
> > foo (short *dst)
> > {
> >   dst[0] = 3;
> >   asm volatile ("" : : : "memory");
> >   dst[2] = 3;
> >   bar ();
> >   dst[1] = 3;
> >   asm volatile ("" : : : "memory");
> >   dst[4] = 3;
> > }
> >
> > with LCP stall peepholes, GCC generates:
> >
> > movl $3, %eax
> > pushq %rbx
> > movq %rdi, %rbx
> > movw %ax, (%rdi)
> > movl $3, %edx
> > movw %dx, 4(%rdi)
> > call bar
> > movl $3, %ecx
> > movw %cx, 2(%rbx)
> > movl $3, %esi
> > movw %si, 8(%rbx)
> > popq %rbx
> >
> > using 4 different scratch registers vs without LCP stall peepholes:
> >
> > pushq %rbx
> > movq %rdi, %rbx
> > movw $3, (%rdi)
> > movw $3, 4(%rdi)
> > call bar
> > movw $3, 2(%rbx)
> > movw $3, 8(%rbx)
> > popq %rbx
> >
> > Add X86_CSE_LCP_STALL to x86_cse to run before the cprop_hardreg pass
> > if there are multiple LCP stall peepholes:
> >
> > 1. Collect all LCP stall peepholes along with their scratch register
> > definitions in the same basic block.  Group peepholes together with the
> > same integer constant in their scratch registers if the first scratch
> > register definition doesn't become invalid beyond a barrier, which can
> > be a function call, a definition or a use, before other peepholes.
> > 2. Track scratch register barriers after scratch register definitions.
> > 3. Mark a scratch register definition redundant in the group if the first
> > scratch register doesn't become invalid beyond a barrier.
> > 4. Replace the redundant scratch register in LCP stall peepholes in the
> > group with the first scratch register and mark the scratch register
> > definition redundant for deletion.
> > 5. Delete redundant scratch register definitions at the end.
> >
> > so that the same scratch register can be reused if possible:
> >
> > movl $3, %eax
> > pushq %rbx
> > movq %rdi, %rbx
> > movw %ax, (%rdi)
> > movw %ax, 4(%rdi)
> > call bar
> > movl $3, %ecx
> > movw %cx, 2(%rbx)
> > movw %cx, 8(%rbx)
> > popq %rbx
> >
> > gcc/
> >
> > PR target/125893
> > * config/i386/i386-features.cc (x86_cse_kind): Add
> > X86_CSE_LCP_STALL.
> > (replace_vector_const): Skip if SRC == VECTOR_CONST.
> > (pass_x86_cse::gate): Also run if there are multiple LCP stall
> > peepholes and reload is completed.
> > (pass_x86_cse::clone): New.
> > (pass_x86_cse::candidate_lcp_stall_p): Likewise.
> > (pass_x86_cse::x86_cse): Replace the redundant scratch register
> > in LCP stall peepholes in the group with the first scratch
> > register and mark the scratch register definition redundant for
> > deletion.  Delete redundant scratch register definitions at the
> > end.
> > * config/i386/i386-passes.def: Add pass_x86_cse before
> > pass_cprop_hardreg.
> > * config/i386/i386.h (machine_function): Add
> > lcp_stall_peephole_generated.
> > (ix86_lcp_stall_peephole_generated): New.
> > * config/i386/i386.md (TARGET_LCP_STALL peepholes): Update
> > ix86_lcp_stall_peephole_generated.
> >
> > gcc/testsuite/
> >
> > PR target/125893
> > * gcc.target/i386/pr125893-1.c: New test.
> > * gcc.target/i386/pr125893-2.c: Likewise.
> > * gcc.target/i386/pr125893-3.c: Likewise.
> > * gcc.target/i386/pr125893-4.c: Likewise.
> > * gcc.target/i386/pr125893-5.c: Likewise.
> > * gcc.target/i386/pr125893-6.c: Likewise.
> >
> >
> > --
> > H.J.
>
> I backported this patch to GCC 16:
>
> 1. When bootstrapping GCC 16 with only C and C++ enabled, this optimization
> triggers 54 times.  No regressions.
> 2. When building glibc 2.44, this optimization triggers 33 times.  No
> regressions.
> 3. When building Linux kernel 7.1.1, this optimization triggers 2099 times.
> Kernel boots correctly.
>
> --
> H.J.

I withdrew this patch.  I am testing a different approach.

-- 
H.J.

Reply via email to