This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Fix multi-reg regno_reg_rtx entry


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]