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)))
    ])

Reply via email to