]> git.ipfire.org Git - thirdparty/gcc.git/commit
RISC-V: Add RTX costs for `if_then_else' expressions
authorMaciej W. Rozycki <macro@embecosm.com>
Wed, 27 Jul 2022 10:09:42 +0000 (11:09 +0100)
committerMaciej W. Rozycki <macro@embecosm.com>
Wed, 27 Jul 2022 10:09:42 +0000 (11:09 +0100)
commit98cf74a2ad893d26de81911e571b634a282a61aa
tree86465921781e4b50ce586b8d0aa87eb3f17ce547
parentf9671b60f9395cb1dca128b92f5dd215f5aeaae1
RISC-V: Add RTX costs for `if_then_else' expressions

Fix a performance regression from commit 391500af1932 ("Do not ignore
costs of jump insns in combine."), a part of the m68k series for MODE_CC
conversion (<https://gcc.gnu.org/ml/gcc-patches/2019-11/msg01028.html>),
observed in soft-fp code in libgcc used by some of the embench-iot
benchmarks.

The immediate origin of the regression is the middle end, which in the
absence of cost information from the backend estimates the cost of an
RTL expression by assuming a single machine instruction for each of the
expression's subexpression.

So for `if_then_else', which takes 3 operands, the estimated cost is 3
instructions (i.e. 12 units) even though a branch instruction evaluates
it in a single machine cycle (ignoring the cost of actually taking the
branch of course, which is handled elsewhere).  Consequently an insn
sequence like:

(insn 595 594 596 43 (set (reg:DI 305)
        (lshiftrt:DI (reg/v:DI 160 [ R_f ])
            (const_int 55 [0x37]))) ".../libgcc/soft-fp/adddf3.c":46:3 216 {lshrdi3}
     (nil))
(insn 596 595 597 43 (set (reg:DI 304)
        (and:DI (reg:DI 305)
            (const_int 1 [0x1]))) ".../libgcc/soft-fp/adddf3.c":46:3 109 {anddi3}
     (expr_list:REG_DEAD (reg:DI 305)
        (nil)))
(jump_insn 597 596 598 43 (set (pc)
        (if_then_else (eq (reg:DI 304)
                (const_int 0 [0]))
            (label_ref:DI 1644)
            (pc))) ".../libgcc/soft-fp/adddf3.c":46:3 237 {*branchdi}
     (expr_list:REG_DEAD (reg:DI 304)
        (int_list:REG_BR_PROB 536870916 (nil)))
 -> 1644)

does not (anymore, as from the commit referred) get combined into:

(note 595 594 596 43 NOTE_INSN_DELETED)
(note 596 595 597 43 NOTE_INSN_DELETED)
(jump_insn 597 596 598 43 (parallel [
            (set (pc)
                (if_then_else (eq (zero_extract:DI (reg/v:DI 160 [ R_f ])
                            (const_int 1 [0x1])
                            (const_int 55 [0x37]))
                        (const_int 0 [0]))
                    (label_ref:DI 1644)
                    (pc)))
            (clobber (scratch:DI))
        ]) ".../libgcc/soft-fp/adddf3.c":46:3 243 {*branch_on_bitdi}
     (int_list:REG_BR_PROB 536870916 (nil))
 -> 1644)

This is because the new cost is incorrectly calculated as 28 units while
the cost of the original 3 instructions was 24:

rejecting combination of insns 595, 596 and 597
original costs 4 + 4 + 16 = 24
replacement cost 28

Before the commit referred the cost of jump instruction was ignored and
considered 0 (i.e. unknown) and a sequence of instructions of a known
cost used to win:

allowing combination of insns 595, 596 and 597
original costs 4 + 4 + 0 = 0
replacement cost 28

Add the missing costs for the 3 variants of `if_then_else' expressions
we currently define in the backend.

With the fix in place the cost of this particular `if_then_else' pattern
is 2 instructions or 8 units (because of the shift operation) and
therefore the ultimate cost of the original 3 RTL insns will work out at
16 units (4 + 4 + 8), however the replacement single RTL insn will cost
8 units only.

gcc/
* config/riscv/riscv.cc (riscv_rtx_costs) <IF_THEN_ELSE>: New
case.
gcc/config/riscv/riscv.cc