The short version: This patch fixes a case where regno_reg_rtx[HI_REGNUM] included LO_REGNUM. regno_reg_rtx[X] is supposed to refer only to register X.
The long version: This patch fixes an ICE in compile/950612-1.c for -mips32r2 -mfp64 -mips16, which is a 4.7 regression. combine.c:distribute_notes was trying to decompose a (reg:DI hi) REG_DEAD note into individual HI and LO registers. It used regno_reg_rtx[] to get these individual registers, but because regno_reg_rtx[HI_REGNUM] was itself (reg:DI hi), we recursed endlessly. HI is not allowed to store values independently of LO, so there is no mode M for which: HARD_REGNO_MODE_OK (HI_REGNUM, M) && HARD_REGNO_NREGS (HI_REGNUM, M) == 1 This causes init_reg_modes_target to pick the following default: /* If we couldn't find a valid mode, just use the previous mode. ??? One situation in which we need to do this is on the mips where HARD_REGNO_NREGS (fpreg, [SD]Fmode) returns 2. Ideally we'd like to use DF mode for the even registers and VOIDmode for the odd (for the cpu models where the odd ones are inaccessible). */ if (reg_raw_mode[i] == VOIDmode) reg_raw_mode[i] = i == 0 ? word_mode : reg_raw_mode[i-1]; The problem is that register i-1 is the last FPR, which for -mips32r2 -mfp64 is a double-word (DImode) value. So we end up using DImode for HI too. [ BTw, I think the MIPS comment is wrong. HARD_REGNO_NREGS (fpreg, SFmode) is (now) 1, even when using paired FPRs. And the suggestion doesn't seem at all ideal to me. OK to remove? ] A simple fix, which I've used below, is to make sure that the previous mode requires only one register. We could drop the new assert if we want to be even more conservative at this stage. A riskier but perhaps more logical fix would be to call choose_hard_reg_mode again, this time telling it to ignore HARD_REGNO_MODE_OK. Tested on mips-sde-elf and x86_64-linux-gnu. OK to install? Richard gcc/ * reginfo.c (init_reg_modes_target): Only use the previous mode if it fits within one register. Index: gcc/reginfo.c =================================================================== --- gcc/reginfo.c 2012-01-28 09:38:46.000000000 +0000 +++ gcc/reginfo.c 2012-01-28 09:38:46.000000000 +0000 @@ -621,7 +621,15 @@ init_reg_modes_target (void) to use DF mode for the even registers and VOIDmode for the odd (for the cpu models where the odd ones are inaccessible). */ if (reg_raw_mode[i] == VOIDmode) - reg_raw_mode[i] = i == 0 ? word_mode : reg_raw_mode[i-1]; + { + if (i > 0 && hard_regno_nregs[i][reg_raw_mode[i - 1]] == 1) + reg_raw_mode[i] = reg_raw_mode[i - 1]; + else + { + reg_raw_mode[i] = word_mode; + gcc_assert (hard_regno_nregs[i][reg_raw_mode[i]] == 1); + } + } } }