http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59278

            Bug ID: 59278
           Summary: combine does not replace matched insn
           Product: gcc
           Version: 4.9.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: rtl-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: olegendo at gcc dot gnu.org
            Target: sh*-*-*

The following happens on SH, with the following example function:

struct result
{
  int a, b;
};

result test2 (int a, int b, int d)
{
  result r;
  r.a = a != b;
  r.b = d + b + 1;
  return r;
};

With -O2 -m4 -ml it compiles to:

        cmp/eq  r5,r4
        add     r5,r6
        mov     #-1,r0
        mov     r6,r1
        negc    r0,r0
        rts
        add     #1,r1

... where it fails to utilize the addc (a + b + T) insn, which is usually
formed during combine.
The RTL before combine looks as follows:

(note 6 0 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
(insn 2 6 3 2 (set (reg/v:SI 166 [ a ])
        (reg:SI 4 r4 [ a ])) sh_tmp.cpp:540 257 {movsi_ie}
     (expr_list:REG_DEAD (reg:SI 4 r4 [ a ])
        (nil)))
(insn 3 2 4 2 (set (reg/v:SI 167 [ b ])
        (reg:SI 5 r5 [ b ])) sh_tmp.cpp:540 257 {movsi_ie}
     (expr_list:REG_DEAD (reg:SI 5 r5 [ b ])
        (nil)))
(insn 4 3 5 2 (set (reg/v:SI 168 [ d ])
        (reg:SI 6 r6 [ d ])) sh_tmp.cpp:540 257 {movsi_ie}
     (expr_list:REG_DEAD (reg:SI 6 r6 [ d ])
        (nil)))
(note 5 4 8 2 NOTE_INSN_FUNCTION_BEG)
(insn 8 5 9 2 (set (reg:SI 147 t)
        (eq:SI (reg/v:SI 166 [ a ])
            (reg/v:SI 167 [ b ]))) sh_tmp.cpp:542 17 {cmpeqsi_t}
     (expr_list:REG_DEAD (reg/v:SI 166 [ a ])
        (nil)))
(insn 9 8 10 2 (set (reg:SI 171)
        (const_int -1 [0xffffffffffffffff])) sh_tmp.cpp:542 257 {movsi_ie}
     (nil))
(insn 10 9 12 2 (parallel [
            (set (reg:SI 170 [ D.1945 ])
                (xor:SI (reg:SI 147 t)
                    (const_int 1 [0x1])))
            (set (reg:SI 147 t)
                (const_int 1 [0x1]))
            (use (reg:SI 171))
        ]) sh_tmp.cpp:542 401 {movrt_negc}
     (expr_list:REG_DEAD (reg:SI 171)
        (expr_list:REG_UNUSED (reg:SI 147 t)
            (nil))))
(insn 12 10 13 2 (set (reg:SI 172 [ D.1946 ])
        (plus:SI (reg/v:SI 168 [ d ])
            (reg/v:SI 167 [ b ]))) sh_tmp.cpp:543 75 {*addsi3_compact}
     (expr_list:REG_DEAD (reg/v:SI 168 [ d ])
        (expr_list:REG_DEAD (reg/v:SI 167 [ b ])
            (nil))))
(insn 13 12 27 2 (set (reg:SI 173 [ D.1946 ])
        (plus:SI (reg:SI 172 [ D.1946 ])
            (const_int 1 [0x1]))) sh_tmp.cpp:543 75 {*addsi3_compact}
     (expr_list:REG_DEAD (reg:SI 172 [ D.1946 ])
        (nil)))
(insn 27 13 28 2 (set (reg:SI 0 r0)
        (reg:SI 170 [ D.1945 ])) sh_tmp.cpp:546 257 {movsi_ie}
     (expr_list:REG_DEAD (reg:SI 170 [ D.1945 ])
        (nil)))
(insn 28 27 22 2 (set (reg:SI 1 r1 [+4 ])
        (reg:SI 173 [ D.1946 ])) sh_tmp.cpp:546 257 {movsi_ie}
     (expr_list:REG_DEAD (reg:SI 173 [ D.1946 ])
        (nil)))
(insn 22 28 0 2 (use (reg/i:DI 0 r0)) sh_tmp.cpp:546 -1
     (nil))


During combine, the following is tried:

Trying 12 -> 13:
Successfully matched this instruction:
(set (reg:SI 173 [ D.1946 ])
    (plus:SI (plus:SI (reg:SI 6 r6 [ d ])
            (reg/v:SI 167 [ b ]))
        (const_int 1 [0x1])))

Trying 12 -> 13:
Successfully matched this instruction:
(set (reg:SI 173 [ D.1946 ])
    (plus:SI (plus:SI (reg:SI 6 r6 [ d ])
            (reg/v:SI 167 [ b ]))
        (const_int 1 [0x1])))

Trying 28 -> 22:

Trying 13, 28 -> 22:
starting the processing of deferred insns
rescanning insn with uid = 8.
rescanning insn with uid = 12.
ending the processing of deferred insns

There's an 'reg + reg + 1' insn in sh.md, which combine obviously successfully
matches:

(define_insn_and_split "*addc_r_r_1"
  [(set (match_operand:SI 0 "arith_reg_dest" "")
    (plus:SI (plus:SI (match_operand:SI 1 "arith_reg_operand" "")
              (match_operand:SI 2 "arith_reg_operand" ""))
         (const_int 1)))
   (clobber (reg:SI T_REG))]
  "TARGET_SH1"
  "#"
  "&& 1"
  [(set (reg:SI T_REG) (const_int 1))
   (parallel [(set (match_dup 0) (plus:SI (plus:SI (match_dup 1) (match_dup 2))
                          (reg:SI T_REG)))
          (clobber (reg:SI T_REG))])])

.. but for some reason the matched insn is not used.


Modifying the function above a little bit to

result test2 (int a, int b, int d)
{
  result r;
  r.a = a == b;
  r.b = d + b + 1;
  return r;
};

will re-order the insns before combine, so that it can't combine the plus
insns, because the T_REG that holds the comparison result is live across the
plus insns.

(note 7 0 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
(insn 2 7 3 2 (set (reg/v:SI 166 [ a ])
        (reg:SI 4 r4 [ a ])) sh_tmp.cpp:540 257 {movsi_ie}
     (expr_list:REG_DEAD (reg:SI 4 r4 [ a ])
        (nil)))
(insn 3 2 4 2 (set (reg/v:SI 167 [ b ])
        (reg:SI 5 r5 [ b ])) sh_tmp.cpp:540 257 {movsi_ie}
     (expr_list:REG_DEAD (reg:SI 5 r5 [ b ])
        (nil)))
(insn 4 3 5 2 (set (reg/v:SI 168 [ d ])
        (reg:SI 6 r6 [ d ])) sh_tmp.cpp:540 257 {movsi_ie}
     (expr_list:REG_DEAD (reg:SI 6 r6 [ d ])
        (nil)))
(insn 5 4 6 2 (set (reg/v:SI 169 [ e ])
        (reg:SI 7 r7 [ e ])) sh_tmp.cpp:540 257 {movsi_ie}
     (expr_list:REG_DEAD (reg:SI 7 r7 [ e ])
        (nil)))
(note 6 5 9 2 NOTE_INSN_FUNCTION_BEG)
(insn 9 6 12 2 (set (reg:SI 147 t)
        (eq:SI (reg/v:SI 166 [ a ])
            (reg/v:SI 167 [ b ]))) sh_tmp.cpp:542 17 {cmpeqsi_t}
     (expr_list:REG_DEAD (reg/v:SI 167 [ b ])
        (expr_list:REG_DEAD (reg/v:SI 166 [ a ])
            (nil))))
(insn 12 9 13 2 (set (reg:SI 172 [ D.1947 ])
        (plus:SI (reg/v:SI 168 [ d ])
            (reg/v:SI 169 [ e ]))) sh_tmp.cpp:543 75 {*addsi3_compact}
     (expr_list:REG_DEAD (reg/v:SI 169 [ e ])
        (expr_list:REG_DEAD (reg/v:SI 168 [ d ])
            (nil))))
(insn 13 12 27 2 (set (reg:SI 173 [ D.1947 ])
        (plus:SI (reg:SI 172 [ D.1947 ])
            (const_int 1 [0x1]))) sh_tmp.cpp:543 75 {*addsi3_compact}
     (expr_list:REG_DEAD (reg:SI 172 [ D.1947 ])
        (nil)))
(insn 27 13 28 2 (set (reg:SI 0 r0)
        (reg:SI 147 t)) sh_tmp.cpp:545 399 {movt}
     (expr_list:REG_DEAD (reg:SI 147 t)
        (nil)))
(insn 28 27 22 2 (set (reg:SI 1 r1 [+4 ])
        (reg:SI 173 [ D.1947 ])) sh_tmp.cpp:545 257 {movsi_ie}
     (expr_list:REG_DEAD (reg:SI 173 [ D.1947 ])
        (nil)))
(insn 22 28 0 2 (use (reg/i:DI 0 r0)) sh_tmp.cpp:545 -1
     (nil))

However, in the first case, there is no register overlap and yet the insns
don't get combined.  I guess this is because of the SH's multiple set negc
insn:

(insn 10 9 12 2 (parallel [
            (set (reg:SI 170 [ D.1945 ])
                (xor:SI (reg:SI 147 t)
                    (const_int 1 [0x1])))
            (set (reg:SI 147 t)
                (const_int 1 [0x1]))
            (use (reg:SI 171))
        ]) sh_tmp.cpp:542 401 {movrt_negc}
     (expr_list:REG_DEAD (reg:SI 171)
        (expr_list:REG_UNUSED (reg:SI 147 t)
            (nil))))

which sets the T_REG to a constant '1' but the T_REG is marked as unused and
not dead, and combine doesn't understand this and thinks that T_REG can't be
clobbered by the following insn (the missed addc insn would clobber the T_REG).

Reply via email to