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

--- Comment #5 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
Created attachment 41256
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=41256&action=edit
gcc8-pr80491.patch

The conditional jump is part of the overflow checking optabs, the expectation
was that we have ifcvt.c and combine.c that should be able to transform it back
into add with carry etc. if beneficial.  Otherwise we'd need to add optabs next
to the overflow checking with jump that would perform effectively setcc (1 for
overflow, 0 otherwise into a pseudo) and during expansion check the uses of the
IMAGPART_EXPR to see which kind of expansion is more beneficial if target
provides both.

Anyway, there are two reasons why ifcvt.c/combine.c don't DTRT here.
One is that ifcvt.c for some strange reason when it sees no else_bb only looks
at a single insn before the condition, while there might be other insns in
between x's setter and the cond_earliest insn.  This is hopefully fixed by the
attached patch.

And the second issue is that in the combiner is called on:
(insn 43 10 18 2 (set (reg:DI 97 [ _15+8 ])
        (ltu:DI (reg:CCC 17 flags)
            (const_int 0 [0]))) 610 {*setcc_di_1}
     (expr_list:REG_DEAD (reg:CCC 17 flags)
        (nil)))
...
(insn 20 19 21 2 (parallel [
            (set (reg:DI 106)
                (plus:DI (mem:DI (plus:DI (reg/v/f:DI 101 [ a ])
                            (const_int 8 [0x8])) [2 a_11(D)->hi+0 S8 A64])
                    (reg:DI 108 [ b_12(D)->hi ])))
            (clobber (reg:CC 17 flags))
        ]) "pr80491.c":8 218 {*adddi_1}
     (expr_list:REG_DEAD (reg/v/f:DI 101 [ a ])
        (expr_list:REG_UNUSED (reg:CC 17 flags)
            (expr_list:REG_DEAD (reg:DI 108 [ b_12(D)->hi ])
                (nil)))))
...
(note 21 20 22 2 NOTE_INSN_DELETED)
(note 22 21 23 2 NOTE_INSN_DELETED)
(note 23 22 24 2 NOTE_INSN_DELETED)
(insn 24 23 39 2 (parallel [
            (set (reg:DI 95 [ _9 ])
                (plus:DI (reg:DI 106)
                    (reg:DI 97 [ _15+8 ])))
            (clobber (reg:CC 17 flags))
        ]) "pr80491.c":8 218 {*adddi_1}
     (expr_list:REG_DEAD (reg:DI 97 [ _15+8 ])
        (expr_list:REG_UNUSED (reg:CC 17 flags)
            (expr_list:REG_DEAD (reg:DI 106)
                (nil)))))

where i3 is 24, i2 is 43 and i1 is 20 (and not i2 20 and i1 43), and we bail
out on that early because the flags hard register is clobbered in insn 20, I
think it is:
&& use_crosses_set_p (src, DF_INSN_LUID (insn)))
in can_combine_p that fails for the flags register.

If I slightly modify the testcase, like:
struct S { unsigned long long low, hi; };

struct S
add (struct S *a, struct S *b)
{
  struct S s;
  s.hi = a->hi + b->hi;
  s.low = a->low + b->low;
  s.hi += (s.low < a->low);
  return s;
}
then unpatched gcc at -O2 on x86_64-linux still creates:
movq 8(%rsi), %rdx
movq 8(%rdi), %rcx
movq (%rsi), %rax
addq %rdx, %rcx
xorl%edx, %edx
addq (%rdi), %rax
jc .L5
.L2:
addq %rcx, %rdx
ret
.L5:
movl $1, %edx
jmp .L2
but patched gcc creates:
movq (%rsi), %rax
addq (%rdi), %rax
movq 8(%rsi), %rdx
adcq 8(%rdi), %rdx
This is because then the high addition except for the carry comes before the
overflow checking addition and so combine.c sees the two insns in a different
order.

Reply via email to