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.
