https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67382
Bug ID: 67382 Summary: RTL combiner is too eager to combine (plus (reg 92) (reg 92)) to (ashift (reg 92) (const_int 1)) Product: gcc Version: 6.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: rtl-optimization Assignee: unassigned at gcc dot gnu.org Reporter: ubizjak at gmail dot com Target Milestone: --- Target: x86_64 Following testcase: --cut here-- extern void abort (void); void test (void) { unsigned char c = 0; unsigned int x = 0xFFFFFFFF; unsigned int y = 0xFFFFFFFF; unsigned int sum_ref = 0xFFFFFFFE; /* X = 0xFFFFFFFF, Y = 0xFFFFFFFF, C = 0. */ c = __builtin_ia32_addcarryx_u32 (c, x, y, &x); /* X = 0xFFFFFFFE, Y = 0xFFFFFFFF, C = 1. */ c = __builtin_ia32_addcarryx_u32 (c, x, y, &x); /* X = 0xFFFFFFFE, Y = 0xFFFFFFFF, C = 1. */ if (x != sum_ref) abort (); } --cut here-- compiles to unoptimized code on x86_64-linux-gnu with -O2: movl $-1, %edx movl $-4, %eax subq $24, %rsp addl %edx, %eax adcl %edx, %eax cmpl $-2, %eax movl %eax, 12(%rsp) jne .L5 addq $24, %rsp ret .L5: call abort The problem is with combine pass, which tries to combine: (insn 10 7 11 2 (parallel [ (set (reg:CCC 17 flags) (compare:CCC (plus:QI (reg:QI 91) (const_int -1 [0xffffffffffffffff])) (reg:QI 91))) (clobber (scratch:QI)) ]) carry.c:11 292 {*addqi3_cconly_overflow} (expr_list:REG_DEAD (reg:QI 91) (expr_list:REG_EQUAL (compare:CCC (const_int -1 [0xffffffffffffffff]) (const_int 0 [0])) (nil)))) (insn 11 10 12 2 (parallel [ (set (reg:CCC 17 flags) (compare:CCC (plus:SI (plus:SI (ltu:SI (reg:CCC 17 flags) (const_int 0 [0])) (reg:SI 92)) (reg:SI 92)) (reg:SI 92))) (set (reg:SI 95) (plus:SI (plus:SI (ltu:SI (reg:CCC 17 flags) (const_int 0 [0])) (reg:SI 92)) (reg:SI 92))) ]) carry.c:11 283 {addcarrysi} (nil)) to: Trying 10 -> 11: Failed to match this instruction: (parallel [ (set (reg:CC 17 flags) (compare:CC (ashift:SI (reg:SI 92) (const_int 1 [0x1])) (reg:SI 92))) (set (reg:SI 95) (ashift:SI (reg:SI 92) (const_int 1 [0x1]))) ]) Failed to match this instruction: (parallel [ (set (reg:CC 17 flags) (compare:CC (ashift:SI (reg:SI 92) (const_int 1 [0x1])) (reg:SI 92))) (set (reg:SI 95) (ashift:SI (reg:SI 92) (const_int 1 [0x1]))) ]) Please note that combine pass converts (plus (reg 92) (reg 92)) to (ashift (reg 92) (const_int 1) and combined pattern fails. BTW: The duplicate pattern is copied verbatim from the dump. It looks like combine is trying to do something with unrecognized pattern to re-recognize it. When we change e.g.: unsigned int x = 0xFFFFFFFF; to unsigned int x = 0xFFFFFFFC; we get the expected pattern: Trying 10 -> 11: Successfully matched this instruction: (parallel [ (set (reg:CCC 17 flags) (compare:CCC (plus:SI (reg:SI 92) (reg:SI 93)) (reg:SI 92))) (set (reg:SI 95) (plus:SI (reg:SI 92) (reg:SI 93))) ])