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

--- Comment #2 from James Greenhalgh <jgreenhalgh at gcc dot gnu.org> ---
(In reply to Martin Liška from comment #1)
> Confirmed, started with r238594.

The cost model relies on the target giving a reasonable approximation for an
instruction size through ix86_rtx_costs.

The basic branch structure looks like:


t = mod
if (a / b % 2)
  t = b - mod


In RTL, this looks like:

  (insn 14 13 15 2 (set (reg:CCZ 17 flags)
        (compare:CCZ (reg:SI 99)
            (const_int 0 [0]))) "foo.c":5 3 {*cmpsi_ccno_1}
     (expr_list:REG_DEAD (reg:SI 99)
        (nil)))
  (jump_insn 15 14 16 2 (set (pc)
        (if_then_else (eq (reg:CCZ 17 flags)
                (const_int 0 [0]))
            (label_ref:DI 22)
            (pc))) "foo.c":5 617 {*jcc_1}
     (expr_list:REG_DEAD (reg:CCZ 17 flags)
        (int_list:REG_BR_PROB 20000 (nil)))
   -> 22)

  (note 16 15 17 3 [bb 3] NOTE_INSN_BASIC_BLOCK)
  (insn 17 16 22 3 (parallel [
            (set (reg/v:SI 93 [ <retval> ])
                (minus:SI (reg/v:SI 95 [ b ])
                    (reg/v:SI 93 [ <retval> ])))
            (clobber (reg:CC 17 flags))
        ]) "foo.c":5 273 {*subsi_1}
     (expr_list:REG_DEAD (reg/v:SI 95 [ b ])
        (expr_list:REG_UNUSED (reg:CC 17 flags)
            (nil))))
  (code_label 22 17 25 4 1 (nil) [1 uses])

That is to say, we're starting with a comparison, a branch and a subtract. We
want to know if that sequence is cheaper than a subtract a and conditional
select.

In the cost model, we take an approximation for the branch and comparison of
COST_N_INSNS(2) and the backend tells us the cost of a subtract is
COST_N_INSNS(1). Thus, the cost before transformation is COST_N_INSNS (3) ==
12.

After the transformation, we create this RTL:

  (insn 31 0 32 (set (reg:SI 102)
        (reg/v:SI 93 [ <retval> ])) 82 {*movsi_internal}
       (nil))

  (insn 32 31 33 (parallel [
            (set (reg:SI 101)
                (minus:SI (reg/v:SI 95 [ b ])
                    (reg/v:SI 93 [ <retval> ])))
            (clobber (reg:CC 17 flags))
        ]) 273 {*subsi_1}
       (nil))

  (insn 33 32 34 (set (reg:CCZ 17 flags)
        (compare:CCZ (reg:SI 99)
            (const_int 0 [0]))) 3 {*cmpsi_ccno_1}
       (nil))

  (insn 34 33 0 (set (reg/v:SI 93 [ <retval> ])
        (if_then_else:SI (ne (reg:CCZ 17 flags)
                (const_int 0 [0]))
            (reg:SI 101)
            (reg:SI 102))) 966 {*movsicc_noc}
       (nil))

That is a set to protect the "false" value, the same subtract, a comparison to
set the flags, and a conditional move. When we ask the backend to give us costs
for this it gives us COST_N_INSNS(1) for the set, COST_N_INSNS(1) for the
subtract, COST_N_INSNS(1) for the comparison, and COST_N_INSNS(2) for the
conditional move. That's a total cost of COST_N_INSNS(5) == 20 for the whole
sequence. 20 > 12, so from the perspective of the ifcvt cost model this is a
bad transformation.

Note that ifcvt is not aware that an extra set will be introduced after the
original subtract, nor does it care about the final movl %edx, %eax as that is
unconditional. I thinks it is being asked to trade test, branch, subtract for
set, subtract, test branch - when you spell it out like that it should be clear
why it makes the decision it does.

I can't treproduce your comment about -m32 - I still see branches at -Os.

Reply via email to