Patchwork Tweak IRA checks for singleton register classes

login
register
mail settings
Submitter Richard Sandiford
Date Sept. 30, 2012, 6:21 p.m.
Message ID <871uhjs760.fsf@talisman.home>
Download mbox | patch
Permalink /patch/188186/
State New
Headers show

Comments

Richard Sandiford - Sept. 30, 2012, 6:21 p.m.
IRA has code to check whether there is only a single acceptable register
for a given operand.  This code uses conditions like:

  ira_class_hard_regs_num[cl] != 0
  && (ira_class_hard_regs_num[cl] <= ira_reg_class_max_nregs[cl][mode])

i.e. the number of registers needed to store the mode is >=
the number of alloctable registers in the class.  Then:

  ira_class_hard_regs[cl][0]

gives the register in question.

MIPS has a slightly strange situation in which HI can only be allocated
alongside LO; it can't be allocated independently.  At the moment,
HI and LO have their own register classes (MD0_REG and MD1_REG,
with the mapping depending on endianness) and MD_REGS is used when both
HI and LO are required.  There is also ACC_REGS, which is equivalent to
MD_REGS when the DSP ASE is not being used.  MD_REGS and ACC_REGS are
already mapped to constraints.

Having MD0_REG and MD1_REG leads to some confusing costs and makes
HI and LO irregular WRT the DSP ASE accumulator registers.  I've been
experimenting with patches to remove these classes and just have MD_REGS.
I wanted to get to a situtation where this change has no effect on cc1 .ii
files for -mno-dsp; the patch below is one of those needed to get to that
stage.

MD_REGS has only one SImode register.  As describe above, the same goes
for ACC_REGS unless the DSP ASE is being used.  However, both classes
fail the check above because HI (which doesn't accept SImode) is also
allocatable.  That is, the classes have two allocatable registers,
but only one of them can be used for SImode.

The patch below adds a new array for tracking which class/mode
combinations specify a single register, and for recording which
register that is.  The net effect will be the same on almost all
targets.

I deliberately didn't change:

	      for (p2 = &reg_class_subclasses[cl2][0];
		   *p2 != LIM_REG_CLASSES; p2++)
		if (ira_class_hard_regs_num[*p2] > 0
		    && (ira_reg_class_max_nregs[*p2][mode]
			<= ira_class_hard_regs_num[*p2]))
		  cost = MAX (cost, ira_register_move_cost[mode][cl1][*p2]);

	      for (p1 = &reg_class_subclasses[cl1][0];
		   *p1 != LIM_REG_CLASSES; p1++)
		if (ira_class_hard_regs_num[*p1] > 0
		    && (ira_reg_class_max_nregs[*p1][mode]
			<= ira_class_hard_regs_num[*p1]))
		  cost = MAX (cost, ira_register_move_cost[mode][*p1][cl2]);

from ira_init_register_move_cost because that had more effect
than I was expecting and wasn't needed for the MIPS patch.
It could be done as a follow-up if I ever find time...

I checked that this produced no difference in assembly output for
a set of x86_64 gcc .ii files (tested with -O2 -march=native on gcc20).
Also tested on x86_64-linux-gnu (including -m32) and mipsisa64-elf.
OK to install?

Richard


gcc/
	* ira.h (target_ira): Add x_ira_class_singleton.
	(ira_class_singleton): New macro.
	* ira.c (setup_prohibited_class_mode_regs): Set up ira_class_singleton.
	* ira-build.c (update_conflict_hard_reg_costs): Use
	ira_class_singleton to check for classes with a single
	allocatable register.
	* ira-lives.c (ira_implicitly_set_insn_hard_regs): Likewise.
	(single_reg_class): Likewise.  When more than one class is specified,
	check whether they have the same singleton register.
	(process_single_reg_class_operands): Require single_reg_class
	to return NO_REGS or a class with a single allocatable register.
	Obtain that register from ira_class_singleton.
Vladimir Makarov - Oct. 1, 2012, 4:48 p.m.
On 12-09-30 2:21 PM, Richard Sandiford wrote:
> IRA has code to check whether there is only a single acceptable register
> for a given operand.  This code uses conditions like:
>
>    ira_class_hard_regs_num[cl] != 0
>    && (ira_class_hard_regs_num[cl] <= ira_reg_class_max_nregs[cl][mode])
>
> i.e. the number of registers needed to store the mode is >=
> the number of alloctable registers in the class.  Then:
>
>    ira_class_hard_regs[cl][0]
>
> gives the register in question.
>
> MIPS has a slightly strange situation in which HI can only be allocated
> alongside LO; it can't be allocated independently.  At the moment,
> HI and LO have their own register classes (MD0_REG and MD1_REG,
> with the mapping depending on endianness) and MD_REGS is used when both
> HI and LO are required.  There is also ACC_REGS, which is equivalent to
> MD_REGS when the DSP ASE is not being used.  MD_REGS and ACC_REGS are
> already mapped to constraints.
>
> Having MD0_REG and MD1_REG leads to some confusing costs and makes
> HI and LO irregular WRT the DSP ASE accumulator registers.  I've been
> experimenting with patches to remove these classes and just have MD_REGS.
> I wanted to get to a situtation where this change has no effect on cc1 .ii
> files for -mno-dsp; the patch below is one of those needed to get to that
> stage.
>
> MD_REGS has only one SImode register.  As describe above, the same goes
> for ACC_REGS unless the DSP ASE is being used.  However, both classes
> fail the check above because HI (which doesn't accept SImode) is also
> allocatable.  That is, the classes have two allocatable registers,
> but only one of them can be used for SImode.
>
> The patch below adds a new array for tracking which class/mode
> combinations specify a single register, and for recording which
> register that is.  The net effect will be the same on almost all
> targets.
>
> I deliberately didn't change:
>
> 	      for (p2 = &reg_class_subclasses[cl2][0];
> 		   *p2 != LIM_REG_CLASSES; p2++)
> 		if (ira_class_hard_regs_num[*p2] > 0
> 		    && (ira_reg_class_max_nregs[*p2][mode]
> 			<= ira_class_hard_regs_num[*p2]))
> 		  cost = MAX (cost, ira_register_move_cost[mode][cl1][*p2]);
>
> 	      for (p1 = &reg_class_subclasses[cl1][0];
> 		   *p1 != LIM_REG_CLASSES; p1++)
> 		if (ira_class_hard_regs_num[*p1] > 0
> 		    && (ira_reg_class_max_nregs[*p1][mode]
> 			<= ira_class_hard_regs_num[*p1]))
> 		  cost = MAX (cost, ira_register_move_cost[mode][*p1][cl2]);
>
> from ira_init_register_move_cost because that had more effect
> than I was expecting and wasn't needed for the MIPS patch.
> It could be done as a follow-up if I ever find time...
>
> I checked that this produced no difference in assembly output for
> a set of x86_64 gcc .ii files (tested with -O2 -march=native on gcc20).
> Also tested on x86_64-linux-gnu (including -m32) and mipsisa64-elf.
> OK to install?
It is OK for me, Richard.  Although it was hard to me understand 
correctness of the following changes.

Thanks for the patch.
> Index: gcc/ira-lives.c
> ===================================================================
> --- gcc/ira-lives.c	2012-09-30 12:56:14.344185269 +0100
> +++ gcc/ira-lives.c	2012-09-30 17:45:14.962463976 +0100
> @@ -849,9 +849,10 @@ single_reg_class (const char *constraint
>   	  next_cl = (c == 'r'
>   		     ? GENERAL_REGS
>   		     : REG_CLASS_FROM_CONSTRAINT (c, constraints));
> -	  if ((cl != NO_REGS && next_cl != cl)
> -	      || (ira_class_hard_regs_num[next_cl]
> -		  > ira_reg_class_max_nregs[next_cl][GET_MODE (op)]))
> +	  if (cl == NO_REGS
> +	      ? ira_class_singleton[next_cl][GET_MODE (op)] < 0
> +	      : (ira_class_singleton[cl][GET_MODE (op)]
> +		 != ira_class_singleton[next_cl][GET_MODE (op)]))
>   
>   	    return NO_REGS;
>   	  cl = next_cl;
>   	  break;
> @@ -861,10 +862,10 @@ single_reg_class (const char *constraint
>   	  next_cl
>   	    = single_reg_class (recog_data.constraints[c - '0'],
>   				recog_data.operand[c - '0'], NULL_RTX);
> -	  if ((cl != NO_REGS && next_cl != cl)
> -	      || next_cl == NO_REGS
> -	      || (ira_class_hard_regs_num[next_cl]
> -		  > ira_reg_class_max_nregs[next_cl][GET_MODE (op)]))
> +	  if (cl == NO_REGS
> +	      ? ira_class_singleton[next_cl][GET_MODE (op)] < 0
> +	      : (ira_class_singleton[cl][GET_MODE (op)]
> +		 != ira_class_singleton[next_cl][GET_MODE (op)]))
>   	    return NO_REGS;
>   	  cl = next_cl;
>   	  break;
>

Patch

Index: gcc/ira.h
===================================================================
--- gcc/ira.h	2012-09-30 12:56:14.344185269 +0100
+++ gcc/ira.h	2012-09-30 17:45:14.964463976 +0100
@@ -79,6 +79,10 @@  struct target_ira {
      class.  */
   int x_ira_class_hard_regs_num[N_REG_CLASSES];
 
+  /* If class CL has a single allocatable register of mode M,
+     index [CL][M] gives the number of that register, otherwise it is -1.  */
+  short x_ira_class_singleton[N_REG_CLASSES][MAX_MACHINE_MODE];
+
   /* Function specific hard registers can not be used for the register
      allocation.  */
   HARD_REG_SET x_ira_no_alloc_regs;
@@ -117,6 +121,8 @@  #define ira_class_hard_regs \
   (this_target_ira->x_ira_class_hard_regs)
 #define ira_class_hard_regs_num \
   (this_target_ira->x_ira_class_hard_regs_num)
+#define ira_class_singleton \
+  (this_target_ira->x_ira_class_singleton)
 #define ira_no_alloc_regs \
   (this_target_ira->x_ira_no_alloc_regs)
 
Index: gcc/ira.c
===================================================================
--- gcc/ira.c	2012-09-30 12:56:14.344185269 +0100
+++ gcc/ira.c	2012-09-30 19:20:32.555409864 +0100
@@ -1451,16 +1451,21 @@  setup_reg_class_nregs (void)
 
 
 
-/* Set up IRA_PROHIBITED_CLASS_MODE_REGS.  */
+/* Set up IRA_PROHIBITED_CLASS_MODE_REGS and IRA_CLASS_SINGLETON.
+   This function is called once IRA_CLASS_HARD_REGS has been initialized.  */
 static void
 setup_prohibited_class_mode_regs (void)
 {
-  int j, k, hard_regno, cl;
+  int j, k, hard_regno, cl, last_hard_regno, count;
 
   for (cl = (int) N_REG_CLASSES - 1; cl >= 0; cl--)
     {
+      COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl]);
+      AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs);
       for (j = 0; j < NUM_MACHINE_MODES; j++)
 	{
+	  count = 0;
+	  last_hard_regno = -1;
 	  CLEAR_HARD_REG_SET (ira_prohibited_class_mode_regs[cl][j]);
 	  for (k = ira_class_hard_regs_num[cl] - 1; k >= 0; k--)
 	    {
@@ -1468,7 +1473,14 @@  setup_prohibited_class_mode_regs (void)
 	      if (! HARD_REGNO_MODE_OK (hard_regno, (enum machine_mode) j))
 		SET_HARD_REG_BIT (ira_prohibited_class_mode_regs[cl][j],
 				  hard_regno);
+	      else if (in_hard_reg_set_p (temp_hard_regset,
+					  (enum machine_mode) j, hard_regno))
+		{
+		  last_hard_regno = hard_regno;
+		  count++;
+		}
 	    }
+	  ira_class_singleton[cl][j] = (count == 1 ? last_hard_regno : -1);
 	}
     }
 }
Index: gcc/ira-build.c
===================================================================
--- gcc/ira-build.c	2012-09-30 12:56:14.344185269 +0100
+++ gcc/ira-build.c	2012-09-30 17:45:14.965463976 +0100
@@ -3047,11 +3047,10 @@  update_conflict_hard_reg_costs (void)
     {
       reg_class_t aclass = ALLOCNO_CLASS (a);
       reg_class_t pref = reg_preferred_class (ALLOCNO_REGNO (a));
-
-      if (reg_class_size[(int) pref] != 1)
+      int singleton = ira_class_singleton[pref][ALLOCNO_MODE (a)];
+      if (singleton < 0)
 	continue;
-      index = ira_class_hard_reg_index[(int) aclass]
-				      [ira_class_hard_regs[(int) pref][0]];
+      index = ira_class_hard_reg_index[(int) aclass][singleton];
       if (index < 0)
 	continue;
       if (ALLOCNO_CONFLICT_HARD_REG_COSTS (a) == NULL
Index: gcc/ira-lives.c
===================================================================
--- gcc/ira-lives.c	2012-09-30 12:56:14.344185269 +0100
+++ gcc/ira-lives.c	2012-09-30 17:45:14.962463976 +0100
@@ -849,9 +849,10 @@  single_reg_class (const char *constraint
 	  next_cl = (c == 'r'
 		     ? GENERAL_REGS
 		     : REG_CLASS_FROM_CONSTRAINT (c, constraints));
-	  if ((cl != NO_REGS && next_cl != cl)
-	      || (ira_class_hard_regs_num[next_cl]
-		  > ira_reg_class_max_nregs[next_cl][GET_MODE (op)]))
+	  if (cl == NO_REGS
+	      ? ira_class_singleton[next_cl][GET_MODE (op)] < 0
+	      : (ira_class_singleton[cl][GET_MODE (op)]
+		 != ira_class_singleton[next_cl][GET_MODE (op)]))
 	    return NO_REGS;
 	  cl = next_cl;
 	  break;
@@ -861,10 +862,10 @@  single_reg_class (const char *constraint
 	  next_cl
 	    = single_reg_class (recog_data.constraints[c - '0'],
 				recog_data.operand[c - '0'], NULL_RTX);
-	  if ((cl != NO_REGS && next_cl != cl)
-	      || next_cl == NO_REGS
-	      || (ira_class_hard_regs_num[next_cl]
-		  > ira_reg_class_max_nregs[next_cl][GET_MODE (op)]))
+	  if (cl == NO_REGS
+	      ? ira_class_singleton[next_cl][GET_MODE (op)] < 0
+	      : (ira_class_singleton[cl][GET_MODE (op)]
+		 != ira_class_singleton[next_cl][GET_MODE (op)]))
 	    return NO_REGS;
 	  cl = next_cl;
 	  break;
@@ -939,13 +940,14 @@  ira_implicitly_set_insn_hard_regs (HARD_
 		  cl = (c == 'r'
 			? GENERAL_REGS
 			: REG_CLASS_FROM_CONSTRAINT (c, p));
-		  if (cl != NO_REGS
+		  if (cl != NO_REGS)
+		    {
 		      /* There is no register pressure problem if all of the
 			 regs in this class are fixed.  */
-		      && ira_class_hard_regs_num[cl] != 0
-		      && (ira_class_hard_regs_num[cl]
-			  <= ira_reg_class_max_nregs[cl][mode]))
-		    IOR_HARD_REG_SET (*set, reg_class_contents[cl]);
+		      int regno = ira_class_singleton[cl][mode];
+		      if (regno >= 0)
+			add_to_hard_reg_set (set, mode, regno);
+		    }
 		  break;
 		}
 	}
@@ -989,8 +991,7 @@  process_single_reg_class_operands (bool
 
 	  operand_a = ira_curr_regno_allocno_map[regno];
 	  aclass = ALLOCNO_CLASS (operand_a);
-	  if (ira_class_subset_p[cl][aclass]
-	      && ira_class_hard_regs_num[cl] != 0)
+	  if (ira_class_subset_p[cl][aclass])
 	    {
 	      /* View the desired allocation of OPERAND as:
 
@@ -1004,7 +1005,8 @@  process_single_reg_class_operands (bool
 	      HOST_WIDE_INT offset;
 
 	      xmode = recog_data.operand_mode[i];
-	      xregno = ira_class_hard_regs[cl][0];
+	      xregno = ira_class_singleton[cl][xmode];
+	      gcc_assert (xregno >= 0);
 	      ymode = ALLOCNO_MODE (operand_a);
 	      offset = subreg_lowpart_offset (ymode, xmode);
 	      yregno = simplify_subreg_regno (xregno, xmode, offset, ymode);