http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54429
--- Comment #4 from Oleg Endo <olegendo at gcc dot gnu.org> 2012-11-13 22:25:30 UTC --- (In reply to comment #3) > I've tested this: > > Index: gcc/config/sh/sh.c > =================================================================== > --- gcc/config/sh/sh.c (revision 193423) > +++ gcc/config/sh/sh.c (working copy) > @@ -12113,6 +12113,11 @@ > if (FP_REGISTER_P (regno) && mode == SFmode) > return true; > > + if (FP_REGISTER_P (regno) > + && !(GET_MODE_CLASS (mode) == MODE_FLOAT > + || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)) > + return false; > + > if (mode == V2SFmode) > { > if (((FP_REGISTER_P (regno) && (regno - FIRST_FP_REG) % 2 == 0) > > > on rev 193423. There are a few failures on targets with HW FPU: > It seems these problems happen on big endian targets only. > FAIL: gcc.c-torture/execute/20080502-1.c compilation Reload failure. Problematic insn: (insn 12 44 13 2 (set (reg:SI 147 t) (eq:SI (and:SI (reg:SI 1 r1 [166]) (subreg:SI (reg:DF 68 fr4 [ x ]) 0)) (const_int 0 [0]))) sh_tmp.cpp:110 1 {tstsi_t} (expr_list:REG_DEAD (reg:SI 1 r1 [166]) (expr_list:REG_DEAD (reg:DF 68 fr4 [ x ]) (nil)))) > FAIL: gcc.c-torture/execute/ieee/copysign1.c compilation Reload failure. Problematic insn: (insn 10 41 11 2 (set (reg:SI 147 t) (eq:SI (and:SI (reg:SI 1 r1 [165]) (subreg:SI (reg:DF 70 fr6 [ y ]) 0)) (const_int 0 [0]))) sh_tmp.cpp:67 1 {tstsi_t} (expr_list:REG_DEAD (reg:SI 1 r1 [165]) (expr_list:REG_DEAD (reg:DF 70 fr6 [ y ]) (nil)))) > FAIL: gcc.dg/builtins-32.c (internal compiler error) Reload failure. Problematic insn: (insn 8 7 21 2 (set (reg:SI 0 r0 [164]) (and:SI (reg:SI 0 r0 [164]) (subreg:SI (reg:DF 68 fr4 [ x ]) 0))) sh_tmp.cpp:30 111 {*andsi_compact} (expr_list:REG_DEAD (reg:DF 68 fr4 [ x ]) (nil))) > FAIL: gcc.dg/builtins-50.c (internal compiler error) Reload failure. Problematic insn: (insn 10 43 11 2 (set (reg:SI 147 t) (eq:SI (and:SI (reg:SI 1 r1 [165]) (subreg:SI (reg:DF 70 fr6 [ y ]) 0)) (const_int 0 [0]))) sh_tmp.cpp:24 1 {tstsi_t} (expr_list:REG_DEAD (reg:SI 1 r1 [165]) (expr_list:REG_DEAD (reg:DF 70 fr6 [ y ]) (nil)))) > FAIL: gcc.dg/pr48335-7.c (internal compiler error) Reload failure. Problematic insn: (insn 9 3 10 2 (set (reg:SI 0 r0 [167]) (ashift:SI (subreg:SI (reg:DF 68 fr4 [ x ]) 0) (const_int 8 [0x8]))) sh_tmp.cpp:28 149 {ashlsi3_k} (expr_list:REG_DEAD (reg:DF 68 fr4 [ x ]) (nil))) The problem is that 'arith_reg_operand' matches subregs of FP modes and so, for example, combine folds insn sequences such as (insn 8 7 9 2 (set (reg:SI 166) (subreg:SI (reg:DI 165) 0)) sh_tmp.cpp:33 -1 (nil)) (insn 9 8 10 2 (set (reg:SI 167) (ashift:SI (reg:SI 166) (const_int 8 [0x8]))) sh_tmp.cpp:33 -1 (nil)) Adding this: Index: gcc/config/sh/predicates.md =================================================================== --- gcc/config/sh/predicates.md (revision 193423) +++ gcc/config/sh/predicates.md (working copy) @@ -156,7 +156,12 @@ if (REG_P (op)) regno = REGNO (op); else if (GET_CODE (op) == SUBREG && REG_P (SUBREG_REG (op))) - regno = REGNO (SUBREG_REG (op)); + { + regno = REGNO (SUBREG_REG (op)); + if (!(GET_MODE_CLASS (GET_MODE (SUBREG_REG (op))) == MODE_INT + || GET_MODE_CLASS (GET_MODE (SUBREG_REG (op))) == MODE_VECTOR_INT)) + return false; + } else return 1; makes the unwanted subreg propagation go away, but ends up in another reload trouble: sh_tmp.cpp:92:1: error: unable to find a register to spill in class 'TARGET_REGS' } ^ sh_tmp.cpp:92:1: error: this is the insn: (insn 7 4 8 2 (set (reg:SI 1 r1 [165]) (subreg:SI (reg:DF 70 fr6 [ y ]) 0)) sh_tmp.cpp:91 244 {movsi_ie} (expr_list:REG_DEAD (reg:DF 70 fr6 [ y ]) (nil))) On little endian this problem does not happen and the same insn right before the reload pass looks like: (insn 7 4 8 2 (set (reg:SI 165) (subreg:SI (reg/v:DF 163 [ y ]) 4)) sh_tmp.cpp:91 244 {movsi_ie} (expr_list:REG_DEAD (reg/v:DF 163 [ y ]) (nil))) Notice that on big endian the insn contains hard regs. I've tried tapping sh_secondary_reload and there are some weird things happening such as: in = 1 rlcass = 8 mode = SI x = (reg:DF 70 fr6 [ y ]) --> rclass = 5 This is caused by the way sh_cannot_change_mode_class handles stuff on big endian. Adding this to 'sh_cannot_change_mode_class': if (from == DFmode && to == SImode) return true; fixes at least one of the test cases, but I'm totally unaware of the consequences.