[Bug rtl-optimization/59278] New: combine does not replace matched insn
olegendo at gcc dot gnu.org
gcc-bugzilla@gcc.gnu.org
Sun Nov 24 20:13:00 GMT 2013
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).
More information about the Gcc-bugs
mailing list