I think push_reload() is doing something weird with this insn: Breakpoint 1, find_reloads (insn=0xb7f7e348, replace=0, ind_levels=0, live_known=0, reload_reg_p=0x8878a7c) at ../../../cvssrc/gcc/gcc/reload.c:2535 2535 { (gdb) call debug_rtx(insn) (insn 12 10 16 2 /tmp/ashiftsi3_1.c:3 (parallel [ (set (subreg:HI (reg:SI 2 a [orig:20 D.1497 ] [20]) 0) (ashift:HI (reg:HI 8 si [orig:26 x ] [26]) (const_int 1 [0x1]))) (clobber (reg:CC 13 cc)) ]) 353 {*ashlhi3} (nil) (expr_list:REG_DEAD (reg:HI 8 si [orig:26 x ] [26]) (expr_list:REG_UNUSED (reg:CC 13 cc) (insn_list:REG_RETVAL 13 (nil)))))
where operands 0 and 1 must match. The resulting reloads are: Spilling for insn 12. Using reg 8 for reload 0 Reloads for insn # 12 Reload order: 0 Reload 0: reload_in (HI) = (reg:HI 26 [ x ]) reload_out (SI) = (reg:SI 2 a [orig:20 D.1497 ] [20]) GENERAL_REGS, RELOAD_OTHER (opnum = 0) reload_in_reg: (reg:HI 26 [ x ]) reload_out_reg: (reg:SI 2 a [orig:20 D.1497 ] [20]) reload_reg_rtx: (reg:SI 8 si) ;; Register dispositions: 20 in 2 21 in 8 22 in 9 23 in 2 24 in 0 25 in 0 It seems unnecessary to create a SImode output reload here and worse, it clobbers (reg:HI 4 d) which is live ((reg:SI 2 a) is four registers): (insn 40 10 12 2 /tmp/ashiftsi3_1.c:3 (set (reg:HI 8 si) (mem/c:HI (plus:HI (reg/f:HI 10 bp) (const_int -2 [0xfffffffe])) [0 S2 A8])) 9 {*movhi} (nil) (nil)) (insn 12 40 41 2 /tmp/ashiftsi3_1.c:3 (parallel [ (set (reg:HI 8 si) (ashift:HI (reg:HI 8 si) (const_int 1 [0x1]))) (clobber (reg:CC 13 cc)) ]) 353 {*ashlhi3} (nil) (nil)) (insn 41 12 42 2 /tmp/ashiftsi3_1.c:3 (set (reg:HI 2 a [orig:20 D.1497 ] [20]) (reg:HI 8 si)) 9 {*movhi} (nil) (nil)) (insn 42 41 14 2 /tmp/ashiftsi3_1.c:3 (set (reg:HI 4 d [ D.1497+2 ]) (reg:HI 9 di [+2 ])) 9 {*movhi} (nil) (nil)) Register di was dead at this point, btw. The call to push_reload() seems OK: push_reload (in=0xb7f833b0, out=0xb7f7578c, inloc=0xb7f758bc, outloc=0xb7f758c8, class=GENERAL_REGS, inmode=HImode, outmode=HImode, strict_low=0, optional=0, opnum=0, type=RELOAD_OTHER) at ../../../cvssrc/gcc/gcc/reload.c:929 (gdb) call debug_rtx(in) (reg:HI 8 si [orig:26 x ] [26]) (gdb) call debug_rtx(out) (subreg:HI (reg:SI 2 a [orig:20 D.1497 ] [20]) 0) Starting at line 1097 of reload.c is the interesting part: /* Similarly for paradoxical and problematical SUBREGs on the output. Note that there is no reason we need worry about the previous value of SUBREG_REG (out); even if wider than out, storing in a subreg is entitled to clobber it all (except in the case of STRICT_LOW_PART, and in that case the constraint should label it input-output.) */ [...] || (REG_P (SUBREG_REG (out)) && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER && ((GET_MODE_SIZE (outmode) <= UNITS_PER_WORD && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))) > UNITS_PER_WORD) && ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))) / UNITS_PER_WORD) != (int) hard_regno_nregs[REGNO (SUBREG_REG (out))] [GET_MODE (SUBREG_REG (out))])) || ! HARD_REGNO_MODE_OK (subreg_regno (out), outmode))) [...] { out_subreg_loc = outloc; outloc = &SUBREG_REG (out); out = *outloc; #if ! defined (LOAD_EXTEND_OP) && ! defined (WORD_REGISTER_OPERATIONS) gcc_assert (!MEM_P (out) || GET_MODE_SIZE (GET_MODE (out)) <= GET_MODE_SIZE (outmode)); #endif outmode = GET_MODE (out); } What is the condition with hard_regno_nregs[][] supposed to check? In this particular case, we have: GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))) = 4 UNITS_PER_WORD = 2 hard_regno_nregs[2][SImode] = 4 (8-bit registers) so the condition 4 / 2 != 4 is true and reload thinks the SUBREG is problematical. I don't see what is problematical about it. I tried to "svn blame" someone, but ended with: ------------------------------------------------------------------------ r363 | kenner | 1992-02-28 11:23:25 +0100 (fre, 28 feb 1992) | 2 lines Initial revision ------------------------------------------------------------------------ -- Rask Ingemann Lambertsen