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);
+           }
+       }
     }
 }
 

Reply via email to