]> git.ipfire.org Git - thirdparty/gcc.git/commit
Iterating cprop_hardreg... Third time's a charm.
authorRoger Sayle <roger@nextmovesoftware.com>
Sat, 25 Jun 2022 08:35:45 +0000 (09:35 +0100)
committerRoger Sayle <roger@nextmovesoftware.com>
Sat, 25 Jun 2022 08:35:45 +0000 (09:35 +0100)
commitdefa8537afc734faefde07c9ebdb38252133fbb1
tree1c4fa22a20fefde10307b3cbea8843578d2f0a6e
parent476ef855d08db02a027150ea92611c1626ea7350
Iterating cprop_hardreg... Third time's a charm.

This middle-end patch proposes the "hard register constant propagation"
pass be performed up to three times on each basic block (up from the
current two times) if the second pass successfully made changes.

The motivation for three passes is to handle the "swap idiom" (i.e.
t = x; x = y; y = t;" sequences) that get generated by register allocation
(reload).

Consider the x86_64 test case for __int128 addition recently discussed
on gcc-patches.  With that proposed patch, the input to the cprop_hardreg
pass looks like:

movq %rdi, %r8
movq %rsi, %rdi
movq %r8, %rsi
        movq    %rdx, %rax
        movq    %rcx, %rdx
        addq    %rsi %rax
        adcq    %rdi, %rdx
        ret

where the first three instructions effectively swap %rsi and %rdi.

On the first pass of cprop_hardreg, we notice that the third insn,
%rsi := %r8, is redundant and can eliminated/propagated to produce:

        movq    %rdi, %r8
        movq    %rsi, %rdi
        movq    %rdx, %rax
        movq    %rcx, %rdx
        addq    %r8 %rax
        adcq    %rdi, %rdx
        ret

Because a successful propagation was found, cprop_hardreg then runs
a second pass/sweep on affected basic blocks (using worklist), and
on this second pass notices that the second instruction, %rdi := %rsi,
may now be propagated (%rsi was killed in the before the first transform),
and after a second pass, we now end up with:

        movq    %rdi, %r8
        movq    %rdx, %rax
        movq    %rcx, %rdx
        addq    %r8, %rax
        adcq    %rsi, %rdx
        ret

which is the current behaviour on mainline.  However, a third and final
pass would now notice that the first insn, "%r8 := %rdi" is also now
eliminable, and a third iteration would produce optimal code:

        movq    %rdx, %rax
        movq    %rcx, %rdx
        addq    %rdi, %rax
        adcq    %rsi, %rdx
        ret

The patch below creates two worklists, and alternates between them on
sucessive passes, populating NEXT with the basic block id's of blocks
that were updated during the current pass over the CURR worklist.
It should be noted that this a regression fix; GCC 4.8 generated
optimal code with two moves (whereas GCC 12 required 5 moves, up
from GCC 11's 4 moves).

2022-06-25  Roger Sayle  <roger@nextmovesoftware.com>
    Richard Biener  <rguenther@suse.de>

gcc/ChangeLog
* regcprop.cc (pass_cprop_hardreg::execute): Perform a third
iteration over each basic block that was updated by the second
iteration.
gcc/regcprop.cc