http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60071
Oleg Endo <olegendo at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|UNCONFIRMED |NEW Last reconfirmed| |2014-02-25 Ever confirmed|0 |1 --- Comment #6 from Oleg Endo <olegendo at gcc dot gnu.org> --- I've just tried this with -O2. This is what happens... After combine, there is the problematic insn: (insn 41 40 34 3 (parallel [ (set (reg:SI 161 [ <retval> ]) (minus:SI (const_int -2147483648 [0xffffffff80000000]) (reg:SI 147 t))) (clobber (reg:SI 147 t)) ]) sh_tmp.cpp:10 404 {*mov_t_msb_neg} (nil)) After split1 it is split correctly into constant load + negc and before the IRA pass it looks like this: (insn 45 40 46 4 (set (reg:SI 169) (const_int -2147483648 [0xffffffff80000000])) sh_tmp.cpp:10 257 {movsi_ie} (nil)) (insn 46 45 43 4 (parallel [ (set (reg:SI 161 [ <retval> ]) (minus:SI (neg:SI (reg:SI 169)) (reg:SI 147 t))) (clobber (reg:SI 147 t)) ]) sh_tmp.cpp:10 205 {*negc} (nil)) However, the IRA pass moves the constant back and replaces the insn: (insn 46 40 43 4 (parallel [ (set (reg:SI 161 [ <retval> ]) (minus:SI (const_int -2147483648 [0xffffffff80000000]) (reg:SI 147 t))) (clobber (reg:SI 147 t)) ]) sh_tmp.cpp:10 404 {*mov_t_msb_neg} which happens while can_create_pseudo_p () returns 'true', thus the insn matches. This is a bit counter productive. The constant load was split out on purpose so that it can be hoisted/combined easier (I was thinking of adding an SH specific RTL pass to optimize constant loads and sharing. On SH there are a couple of cases where constants are emitted during combine and split1 which won't be CSE'd). The following seems to fix the problem (although not fully tested): Index: gcc/config/sh/sh.md =================================================================== --- gcc/config/sh/sh.md (revision 208155) +++ gcc/config/sh/sh.md (working copy) @@ -11434,6 +11434,10 @@ ;; T = 1: 0x80000000 -> reg ;; T = 0: 0x7FFFFFFF -> reg ;; This works because 0 - 0x80000000 = 0x80000000. +;; +;; This insn must not match again after it has been split into the constant +;; load and negc. This is accomplished by the special negc insn that +;; has a use on the operand. (define_insn_and_split "*mov_t_msb_neg" [(set (match_operand:SI 0 "arith_reg_dest") (minus:SI (const_int -2147483648) ;; 0x80000000 @@ -11444,12 +11448,23 @@ "&& can_create_pseudo_p ()" [(set (match_dup 2) (const_int -2147483648)) (parallel [(set (match_dup 0) (minus:SI (neg:SI (match_dup 2)) - (reg:SI T_REG))) - (clobber (reg:SI T_REG))])] + (reg:SI T_REG))) + (clobber (reg:SI T_REG)) + (use (match_dup 2))])] { operands[2] = gen_reg_rtx (SImode); }) +(define_insn "*mov_t_msb_neg_negc" + [(set (match_operand:SI 0 "arith_reg_dest" "=r") + (minus:SI (neg:SI (match_operand:SI 1 "arith_reg_operand" "r")) + (match_operand:SI 2 "t_reg_operand"))) + (clobber (reg:SI T_REG)) + (use (match_dup 1))] + "TARGET_SH1" + "negc %1,%0" + [(set_attr "type" "arith")]) + ;; These are essentially the same as above, but with the inverted T bit. ;; Combine recognizes the split patterns, but does not take them sometimes ;; if the T_REG clobber is specified. Instead it tries to split out the