[RTL, ColdFire 24/63] Add support for a MODE_INDEX_REG_CLASS macro

Richard Sandiford richard@codesourcery.com
Wed Jan 10 11:23:00 GMT 2007


At the moment, gcc expects there to be a single INDEX_REG_CLASS that
applies to all MEM modes.  This is not true when using a ColdFire FPU,
as index registers are not allowed for floating-point modes.  The port
tries to hack around this by using "<Q>U" instead of "m" in the movsf
constraints, but that's only a half solution.  If reload has to reload
an indexed MEM (rather than the MEM's address), it will expect that
instruction to match.

The fix is to allow the class of index register to vary depending on
the mode of the addressed value, as the base register class already can.

This patch does the target-independent bit.  It adds new target macros
called MODE_INDEX_REG_CLASS and REGNO_MODE_OK_FOR_INDEX_P, to accompany
the existing MODE_BASE_REG_CLASS and REGNO_MODE_OK_FOR_BASE_P.  It also
defines index equivalents of the addresses.h base functions.  This is
all a direct image of the base register code (including the wording
of comments and documentation).  I think the two should be consistent.
The patch then adjusts all code to use thse new addresses.h functions.

Bootstrapped & regression-tested on x86_64-linux-gnu.

Richard


gcc/
	* Makefile.in (postreload.o): Depend on addresses.h.
	* addresses.h (index_reg_class, ok_for_index_p_1): New functions.
	(regno_ok_for_index_p): New function.
	* postreload.c: Include addresses.h.
	(reload_combine): Use index_reg_class instead of INDEX_REG_CLASS.
	* regclass.c (ok_for_index_p_nonstrict): Add a mode argument.
	Use ok_for_index_p_1 instead of REGNO_OK_FOR_INDEX_P.
	(record_address_regs): Use index_reg_class instead of INDEX_REG_CLASS.
	Update calls to ok_for_index_p_nonstrict.
	* regrename.c (scan_rtx_address): Use regno_ok_for_index_p instead of
	REGNO_OK_FOR_INDEX_P and index_reg_class instead of INDEX_REG_CLASS.
	(replace_oldest_value_addr): Likewise.
	* reload.c (find_reloads_address): Use index_reg_class instead
	of INDEX_REG_CLASS.  Do not push an index register reload if
	index_reg_class returns NO_REGS.
	(find_reloads_address_1): Use index_reg_class instead
	of INDEX_REG_CLASS and regno_ok_for_index_p instead of
	REGNO_OK_FOR_INDEX_P.
	* doc/tm.texi (MODE_INDEX_REG_CLASS): Document new macro.
	(REGNO_MODE_OK_FOR_INDEX_P): Likewise.

Index: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in	2007-01-09 15:01:56.000000000 +0000
+++ gcc/Makefile.in	2007-01-09 15:02:06.000000000 +0000
@@ -2532,7 +2532,7 @@ postreload.o : postreload.c $(CONFIG_H) 
    $(RTL_H) $(REAL_H) $(FLAGS_H) $(EXPR_H) $(OPTABS_H) reload.h $(REGS_H) \
    hard-reg-set.h insn-config.h $(BASIC_BLOCK_H) $(RECOG_H) output.h \
    $(FUNCTION_H) toplev.h cselib.h $(TM_P_H) except.h $(TREE_H) $(MACHMODE_H) \
-   $(OBSTACK_H) $(TIMEVAR_H) tree-pass.h
+   $(OBSTACK_H) $(TIMEVAR_H) tree-pass.h addresses.h
 postreload-gcse.o : postreload-gcse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
    $(TM_H) $(RTL_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) insn-config.h \
    $(RECOG_H) $(EXPR_H) $(BASIC_BLOCK_H) $(FUNCTION_H) output.h toplev.h \
Index: gcc/addresses.h
===================================================================
--- gcc/addresses.h	2007-01-09 15:01:41.000000000 +0000
+++ gcc/addresses.h	2007-01-09 15:02:06.000000000 +0000
@@ -79,3 +79,42 @@ regno_ok_for_base_p (unsigned regno, enu
 
   return ok_for_base_p_1 (regno, mode, outer_code, index_code);
 }
+
+/* Wrapper function to unify target macros MODE_INDEX_REG_CLASS and
+   INDEX_REG_CLASS.  Arguments as for the MODE_INDEX_REG_CLASS macro.  */
+
+static inline enum reg_class
+index_reg_class (enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+#ifdef MODE_INDEX_REG_CLASS
+  return MODE_INDEX_REG_CLASS (mode);
+#else
+  return INDEX_REG_CLASS;
+#endif
+}
+
+/* Wrapper function to unify target macros REGNO_MODE_OK_FOR_INDEX_P
+   and REGNO_OK_FOR_INDEX_P.  Arguments as for the
+   REGNO_MODE_OK_FOR_INDEX_P macro.  */
+
+static inline bool
+ok_for_index_p_1 (unsigned regno, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+#ifdef REGNO_MODE_OK_FOR_INDEX_P
+  return REGNO_MODE_OK_FOR_INDEX_P (regno, mode);
+#else
+  return REGNO_OK_FOR_INDEX_P (regno);
+#endif
+}
+
+/* Wrapper around ok_for_index_p_1, for use after register allocation is
+   complete.  Arguments as for the called function.  */
+
+static inline bool
+regno_ok_for_index_p (unsigned regno, enum machine_mode mode)
+{
+  if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] >= 0)
+    regno = reg_renumber[regno];
+
+  return ok_for_index_p_1 (regno, mode);
+}
Index: gcc/postreload.c
===================================================================
--- gcc/postreload.c	2007-01-09 15:01:41.000000000 +0000
+++ gcc/postreload.c	2007-01-09 15:02:06.000000000 +0000
@@ -46,6 +46,7 @@ Software Foundation; either version 2, o
 #include "tree.h"
 #include "timevar.h"
 #include "tree-pass.h"
+#include "addresses.h"
 
 static int reload_cse_noop_set_p (rtx);
 static void reload_cse_simplify (rtx, rtx);
@@ -703,17 +704,19 @@ reload_combine (void)
   int last_label_ruid;
   int min_labelno, n_labels;
   HARD_REG_SET ever_live_at_start, *label_live;
+  enum reg_class index_regs;
 
   /* If reg+reg can be used in offsetable memory addresses, the main chunk of
      reload has already used it where appropriate, so there is no use in
      trying to generate it now.  */
-  if (double_reg_address_ok && INDEX_REG_CLASS != NO_REGS)
+  index_regs = index_reg_class (VOIDmode);
+  if (double_reg_address_ok && index_regs != NO_REGS)
     return;
 
   /* To avoid wasting too much time later searching for an index register,
      determine the minimum and maximum index register numbers.  */
   for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
-    if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS], r))
+    if (TEST_HARD_REG_BIT (reg_class_contents[index_regs], r))
       {
 	if (first_index_reg == -1)
 	  first_index_reg = r;
@@ -822,8 +825,8 @@ reload_combine (void)
 	     substitute uses of REG (typically in MEMs) with.
 	     First check REG and BASE for being index registers;
 	     we can use them even if they are not dead.  */
-	  if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS], regno)
-	      || TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS],
+	  if (TEST_HARD_REG_BIT (reg_class_contents[index_regs], regno)
+	      || TEST_HARD_REG_BIT (reg_class_contents[index_regs],
 				    REGNO (base)))
 	    {
 	      const_reg = reg;
@@ -837,8 +840,7 @@ reload_combine (void)
 		 two registers.  */
 	      for (i = first_index_reg; i <= last_index_reg; i++)
 		{
-		  if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS],
-					 i)
+		  if (TEST_HARD_REG_BIT (reg_class_contents[index_regs], i)
 		      && reg_state[i].use_index == RELOAD_COMBINE_MAX_USES
 		      && reg_state[i].store_ruid <= reg_state[regno].use_ruid
 		      && hard_regno_nregs[i][GET_MODE (reg)] == 1)
Index: gcc/regclass.c
===================================================================
--- gcc/regclass.c	2007-01-09 15:01:41.000000000 +0000
+++ gcc/regclass.c	2007-01-09 15:02:06.000000000 +0000
@@ -864,10 +864,10 @@ static void reg_scan_mark_refs (rtx, rtx
 /* Wrapper around REGNO_OK_FOR_INDEX_P, to allow pseudo registers.  */
 
 static inline bool
-ok_for_index_p_nonstrict (rtx reg)
+ok_for_index_p_nonstrict (rtx reg, enum machine_mode mode)
 {
   unsigned regno = REGNO (reg);
-  return regno >= FIRST_PSEUDO_REGISTER || REGNO_OK_FOR_INDEX_P (regno);
+  return regno >= FIRST_PSEUDO_REGISTER || ok_for_index_p_1 (regno, mode);
 }
 
 /* A version of regno_ok_for_base_p for use during regclass, when all pseudos
@@ -1946,7 +1946,7 @@ record_address_regs (enum machine_mode m
   enum reg_class class;
 
   if (context == 1)
-    class = INDEX_REG_CLASS;
+    class = index_reg_class (mode);
   else
     class = base_reg_class (mode, outer_code, index_code);
 
@@ -1996,7 +1996,8 @@ record_address_regs (enum machine_mode m
 	   as well as in the tests below, that all addresses are in
 	   canonical form.  */
 
-	else if (INDEX_REG_CLASS == base_reg_class (VOIDmode, PLUS, SCRATCH))
+	else if (index_reg_class (mode)
+		 == base_reg_class (mode, PLUS, SCRATCH))
 	  {
 	    record_address_regs (mode, arg0, context, PLUS, code1, scale);
 	    if (! CONSTANT_P (arg1))
@@ -2022,7 +2023,7 @@ record_address_regs (enum machine_mode m
 	else if (code0 == REG && code1 == REG
 		 && REGNO (arg0) < FIRST_PSEUDO_REGISTER
 		 && (ok_for_base_p_nonstrict (arg0, mode, PLUS, REG)
-		     || ok_for_index_p_nonstrict (arg0)))
+		     || ok_for_index_p_nonstrict (arg0, mode)))
 	  record_address_regs (mode, arg1,
 			       ok_for_base_p_nonstrict (arg0, mode, PLUS, REG)
 			       ? 1 : 0,
@@ -2030,7 +2031,7 @@ record_address_regs (enum machine_mode m
 	else if (code0 == REG && code1 == REG
 		 && REGNO (arg1) < FIRST_PSEUDO_REGISTER
 		 && (ok_for_base_p_nonstrict (arg1, mode, PLUS, REG)
-		     || ok_for_index_p_nonstrict (arg1)))
+		     || ok_for_index_p_nonstrict (arg1, mode)))
 	  record_address_regs (mode, arg0,
 			       ok_for_base_p_nonstrict (arg1, mode, PLUS, REG)
 			       ? 1 : 0,
Index: gcc/regrename.c
===================================================================
--- gcc/regrename.c	2007-01-09 15:01:41.000000000 +0000
+++ gcc/regrename.c	2007-01-09 15:02:06.000000000 +0000
@@ -574,17 +574,17 @@ scan_rtx_address (rtx insn, rtx *loc, en
 	    int index_op;
 	    unsigned regno0 = REGNO (op0), regno1 = REGNO (op1);
 
-	    if (REGNO_OK_FOR_INDEX_P (regno0)
+	    if (regno_ok_for_index_p (regno0, mode)
 		&& regno_ok_for_base_p (regno1, mode, PLUS, REG))
 	      index_op = 0;
-	    else if (REGNO_OK_FOR_INDEX_P (regno1)
+	    else if (regno_ok_for_index_p (regno1, mode)
 		     && regno_ok_for_base_p (regno0, mode, PLUS, REG))
 	      index_op = 1;
 	    else if (regno_ok_for_base_p (regno1, mode, PLUS, REG))
 	      index_op = 0;
 	    else if (regno_ok_for_base_p (regno0, mode, PLUS, REG))
 	      index_op = 1;
-	    else if (REGNO_OK_FOR_INDEX_P (regno1))
+	    else if (regno_ok_for_index_p (regno1, mode))
 	      index_op = 1;
 	    else
 	      index_op = 0;
@@ -607,7 +607,7 @@ scan_rtx_address (rtx insn, rtx *loc, en
 	  }
 
 	if (locI)
-	  scan_rtx_address (insn, locI, INDEX_REG_CLASS, action, mode);
+	  scan_rtx_address (insn, locI, index_reg_class (mode), action, mode);
 	if (locB)
 	  scan_rtx_address (insn, locB, base_reg_class (mode, PLUS, index_code),
 			    action, mode);
@@ -1498,17 +1498,17 @@ replace_oldest_value_addr (rtx *loc, enu
 	    int index_op;
 	    unsigned regno0 = REGNO (op0), regno1 = REGNO (op1);
 
-	    if (REGNO_OK_FOR_INDEX_P (regno0)
+	    if (regno_ok_for_index_p (regno0, mode)
 		&& regno_ok_for_base_p (regno1, mode, PLUS, REG))
 	      index_op = 0;
-	    else if (REGNO_OK_FOR_INDEX_P (regno1)
+	    else if (regno_ok_for_index_p (regno1, mode)
 		     && regno_ok_for_base_p (regno0, mode, PLUS, REG))
 	      index_op = 1;
 	    else if (regno_ok_for_base_p (regno1, mode, PLUS, REG))
 	      index_op = 0;
 	    else if (regno_ok_for_base_p (regno0, mode, PLUS, REG))
 	      index_op = 1;
-	    else if (REGNO_OK_FOR_INDEX_P (regno1))
+	    else if (regno_ok_for_index_p (regno1, mode))
 	      index_op = 1;
 	    else
 	      index_op = 0;
@@ -1531,8 +1531,8 @@ replace_oldest_value_addr (rtx *loc, enu
 	  }
 
 	if (locI)
-	  changed |= replace_oldest_value_addr (locI, INDEX_REG_CLASS, mode,
-						insn, vd);
+	  changed |= replace_oldest_value_addr (locI, index_reg_class (mode),
+						mode, insn, vd);
 	if (locB)
 	  changed |= replace_oldest_value_addr (locB,
 						base_reg_class (mode, PLUS,
Index: gcc/reload.c
===================================================================
--- gcc/reload.c	2007-01-09 15:01:41.000000000 +0000
+++ gcc/reload.c	2007-01-09 15:02:06.000000000 +0000
@@ -4965,7 +4965,7 @@ find_reloads_address (enum machine_mode 
 	    loc = &XEXP (*loc, 0);
 	}
 
-      if (double_reg_address_ok)
+      if (double_reg_address_ok && index_reg_class (mode) != NO_REGS)
 	{
 	  /* Unshare the sum as well.  */
 	  *loc = ad = copy_rtx (ad);
@@ -4973,8 +4973,8 @@ find_reloads_address (enum machine_mode 
 	  /* Reload the displacement into an index reg.
 	     We assume the frame pointer or arg pointer is a base reg.  */
 	  find_reloads_address_part (XEXP (ad, 1), &XEXP (ad, 1),
-				     INDEX_REG_CLASS, GET_MODE (ad), opnum,
-				     type, ind_levels);
+				     index_reg_class (mode), GET_MODE (ad),
+				     opnum, type, ind_levels);
 	  return 0;
 	}
       else
@@ -5366,13 +5366,13 @@ find_reloads_address_1 (enum machine_mod
 #define REG_OK_FOR_CONTEXT(CONTEXT, REGNO, MODE, OUTER, INDEX)		\
   ((CONTEXT) == 0							\
    ? regno_ok_for_base_p (REGNO, MODE, OUTER, INDEX)			\
-   : REGNO_OK_FOR_INDEX_P (REGNO))					
+   : regno_ok_for_index_p (REGNO, MODE))
 
   enum reg_class context_reg_class;
   RTX_CODE code = GET_CODE (x);
 
   if (context == 1)
-    context_reg_class = INDEX_REG_CLASS;
+    context_reg_class = index_reg_class (mode);
   else
     context_reg_class = base_reg_class (mode, outer_code, index_code);
 
@@ -5464,10 +5464,10 @@ #define REG_OK_FOR_CONTEXT(CONTEXT, REGN
 
 	else if (code0 == REG && code1 == REG)
 	  {
-	    if (REGNO_OK_FOR_INDEX_P (REGNO (op0))
+	    if (regno_ok_for_index_p (REGNO (op0), mode)
 		&& regno_ok_for_base_p (REGNO (op1), mode, PLUS, REG))
 	      return 0;
-	    else if (REGNO_OK_FOR_INDEX_P (REGNO (op1))
+	    else if (regno_ok_for_index_p (REGNO (op1), mode)
 		     && regno_ok_for_base_p (REGNO (op0), mode, PLUS, REG))
 	      return 0;
 	    else if (regno_ok_for_base_p (REGNO (op1), mode, PLUS, REG))
@@ -5478,11 +5478,11 @@ #define REG_OK_FOR_CONTEXT(CONTEXT, REGN
 	      find_reloads_address_1 (mode, orig_op1, 1, PLUS, SCRATCH,
 				      &XEXP (x, 1), opnum, type, ind_levels,
 				      insn);
-	    else if (REGNO_OK_FOR_INDEX_P (REGNO (op1)))
+	    else if (regno_ok_for_index_p (REGNO (op1), mode))
 	      find_reloads_address_1 (mode, orig_op0, 0, PLUS, REG,
 				      &XEXP (x, 0), opnum, type, ind_levels,
 				      insn);
-	    else if (REGNO_OK_FOR_INDEX_P (REGNO (op0)))
+	    else if (regno_ok_for_index_p (REGNO (op0), mode))
 	      find_reloads_address_1 (mode, orig_op1, 0, PLUS, REG,
 				      &XEXP (x, 1), opnum, type, ind_levels,
 				      insn);
@@ -5549,7 +5549,7 @@ #define REG_OK_FOR_CONTEXT(CONTEXT, REGN
 	   need to live longer than a TYPE reload normally would, so be
 	   conservative and class it as RELOAD_OTHER.  */
 	if (REG_P (XEXP (op1, 1)))
-	  if (!REGNO_OK_FOR_INDEX_P (REGNO (XEXP (op1, 1))))
+	  if (!regno_ok_for_index_p (REGNO (XEXP (op1, 1)), mode))
 	    find_reloads_address_1 (mode, XEXP (op1, 1), 1, code, SCRATCH,
 				    &XEXP (op1, 1), opnum, RELOAD_OTHER,
 				    ind_levels, insn);
Index: gcc/doc/tm.texi
===================================================================
--- gcc/doc/tm.texi	2007-01-09 15:01:41.000000000 +0000
+++ gcc/doc/tm.texi	2007-01-09 15:02:06.000000000 +0000
@@ -2352,6 +2352,15 @@ address where its value is either multip
 added to another register (as well as added to a displacement).
 @end defmac
 
+@defmac MODE_INDEX_REG_CLASS (@var{mode})
+This is a variation of the @code{INDEX_REG_CLASS} macro which allows
+the selection of an index register in a mode dependent manner.  It can
+return @code{NO_REGS} for modes that do not support any form of index
+register.  If @var{mode} is @code{VOIDmode} then the macro should
+return a class of registers that is suitable for all addresses in
+which an index register of some form is allowed.
+@end defmac
+
 @defmac REGNO_OK_FOR_BASE_P (@var{num})
 A C expression which is nonzero if register number @var{num} is
 suitable for use as a base register in operand addresses.  It may be
@@ -2409,6 +2418,14 @@ looking for one that is valid, and will 
 only if neither labeling works.
 @end defmac
 
+@defmac REGNO_MODE_OK_FOR_INDEX_P (@var{num}, @var{mode})
+A C expression that is just like @code{REGNO_OK_FOR_INDEX_P}, except
+that the expression may examine the mode of the memory reference
+in @var{mode}.  If @var{mode} is @code{VOIDmode}, the macro should
+return true if @var{x} is suitable for all modes in which some
+form of index register is allowed.
+@end defmac
+
 @defmac PREFERRED_RELOAD_CLASS (@var{x}, @var{class})
 A C expression that places additional restrictions on the register class
 to use when it is necessary to copy value @var{x} into a register in class



More information about the Gcc-patches mailing list