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

--- Comment #67 from Uroš Bizjak <ubizjak at gmail dot com> ---
(In reply to 75773-quiet from comment #0)

> unsigned long foo(unsigned long a, unsigned long b) {
>       unsigned long c = a - b;
> 
>       if (a < b) {
>               c += 100;
>       }
> 
>       return c;
> }

We expand this testcase to:

(insn 7 4 8 2 (parallel [
            (set (reg/v:DI 98 [ <retval> ])
                (minus:DI (reg/v:DI 99 [ a ])
                    (reg/v:DI 100 [ b ])))
            (clobber (reg:CC 17 flags))
        ]) "pr3507.c":2:16 395 {*subdi_1}
     (nil))
(insn 8 7 9 2 (set (reg:CC 17 flags)
        (compare:CC (reg/v:DI 99 [ a ])
            (reg/v:DI 100 [ b ]))) "pr3507.c":4:5 16 {*cmpdi_1}
     (nil))
(jump_insn 9 8 10 2 (set (pc)
        (if_then_else (geu (reg:CC 17 flags)
                (const_int 0 [0]))
            (label_ref:DI 16)
            (pc))) "pr3507.c":4:5 1490 {*jcc}
     (int_list:REG_BR_PROB 536870913 (nil))
 -> 16)

but since we have two-operand destructive operations, reload creates a copy, so
post-reload compare elimination pass gets:

   28: ax:DI=di:DI
    7: {ax:DI=ax:DI-si:DI;clobber flags:CC;}
   30: dx:DI=ax:DI+0x64
   23: flags:CC=cmp(di:DI,si:DI)
   24: ax:DI={(ltu(flags:CC,0))?dx:DI:ax:DI}

where operands of (insn 7) and (insn 23) do not match anymore.

With three-operand non-destructive operations (RiscV, c.f. Comment#65 and x86
with -mapxf):

    7: {ax:DI=di:DI-si:DI;clobber flags:CC;}
   28: dx:DI=ax:DI+0x64
   23: flags:CC=cmp(di:DI,si:DI)
   24: ax:DI={(ltu(flags:CC,0))?dx:DI:ax:DI}

where post-reload compare elimination pass merges (insn 7) and (insn 23):

    7: {flags:CC=cmp(di:DI,si:DI);ax:DI=di:DI-si:DI;}
   28: dx:DI=ax:DI+0x64
   24: ax:DI={(ltu(flags:CC,0))?dx:DI:ax:DI}

resulting in:

        subq    %rsi, %rdi, %rax
        leaq    100(%rax), %rdx
        cmovb   %rdx, %rax
        ret

So, the solution is to generalize CMP elimination pass to also handle pseudos
and put the pass before RTL ifcvt pass (_.ce1). ifcvt can create sequence that
clobbers flags between subtract and compare:

    7: {r98:DI=r99:DI-r100:DI;clobber flags:CC;}
      REG_UNUSED flags:CC
   21: r103:DI=r98:DI
   22: {r102:DI=r98:DI+0x64;clobber flags:CC;}
   23: flags:CC=cmp(r99:DI,r100:DI)

Reply via email to