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]

Endianness-dependent ordering of the MIPS hi and lo registers


One of the long-standing warts of the MIPS port is that the HI and LO
hard registers are always numbered in that order (big-endian).  This leads
to things like:

      if (TARGET_BIG_ENDIAN)
        ...
      else
	{
	  /* LO_REGNO == HI_REGNO + 1, so if a multi-word value is stored
	     in LO and HI, the high word always comes first.  We therefore
	     can't allow values stored in HI to change between single-word
	     and multi-word modes.
	     This rule applies to both the original HI/LO pair and the new
	     DSP accumulators.  */
	  if (reg_classes_intersect_p (ACC_REGS, class))
	    return true;

and associated code in mips_subword.

This patch makes the internal numbering match the endianness, so that
HI_REGNUM == LO_REGNUM + 1 on little-endian targets.  It trades
complexity in the subreg handling for complexity in the debug-register
mapping, but the trade-off is a good one: the current subreg handling
places an artificial limit on little-endian code generation that isn't
there for big-endian, whereas the more complex debug-register mapping
has no effect on the output.  (I checked that the debug information
for doubleword "hi" and "lo" variables was unchanged.)

This patch also makes the change I mentioned in passing a few weeks ago;
we now use an inclusive rather than an exclusive mapping for DWARF frame
registers.

My first thought was that static arrays like REGISTER_NAMES should
not mention "hi" or "lo" at all to begin with, but that doesn't work:
these arrays are used to process comamnd-line arguments like
-fstack-limit-register=, -fcall-saved-, -fcall-used- and
-ffixed-reg-.  (The testsuite has instances of -ffixed-hi and
-ffixed-lo.)  I wondered about delaying the processing of these
options until after OVERRIDE_OPTIONS, but that's complicated,
and doesn't sit particularly well with the proposed target_init
interface.  I therefore went for the simpler approach of swapping
the register entries in CONDITIONAL_REGISTER_USAGE.

The mips.md change isn't directly related.  I was auditing the
uses of HI_REGNUM and LO_REGNUM and noticed that this pattern
could juse use a normal alternative-dependent template.

Regression-tested on mipsisa64-elf with Adam's combine patch
and my subreg-notes patch applied.  Committed to trunk.

It would be nice to do the same for floating-point registers,
but that's a much bigger change.

Richard


gcc/
2007-07-20  Nigel Stephens  <nigel@mips.com>
	    Richard Sandiford  <richard@codesourcery.com>

	* config/mips/mips.h (mips_dwarf_regno): Declare.
	(DBX_REGISTER_NUMBER): Remove redundant brackets.
	(HI_REGNUM, LO_REGNUM): Define in an endian-dependent way.
	(AC1HI_REGNUM, AC1LO_REGNUM, AC2HI_REGNUM, AC2LO_REGNUM)
	(AC3HI_REGNUM, AC3LO_REGNUM, ACC_HI_REG_P): Delete.
	(reg_class): Rename HI_REG to MD0_REG and LO_REG to MD1_REG.
	(REG_CLASS_NAMES): Update accordingly.
	* config/mips/mips.c (mips_dwarf_regno): New array.
	(mips_regno_to_class): Rename HI_REG to MD0_REG and LO_REG to MD1_REG.
	(mips_subword): Remove special handling for accumulator registers.
	(override_options): Initiailize mips_dwarf_regno.  Remove use
	of ACC_HI_REG_P.
	(mips_swap_registers): New function.
	(mips_conditional_register_usage): Swap accumulator registers
	around if TARGET_LITTLE_ENDIAN.
	(mips_cannot_change_mode_class): Remove special treatment of ACC_REGS.
	* config/mips/constraints.md (h, l): Use the endianness to choose
	between MD0_REG and MD1_REG.
	* config/mips/mips.md (*mfhilo_<mode>_macc): Use a fixed-string,
	alternative-dependent template.

Index: gcc/config/mips/mips.h
===================================================================
--- gcc/config/mips/mips.h	2007-07-20 10:17:00.000000000 +0100
+++ gcc/config/mips/mips.h	2007-07-20 13:40:28.000000000 +0100
@@ -126,7 +126,8 @@ struct mips_cpu_info {
 extern int set_noat;			/* # of nested .set noat's  */
 extern int set_volatile;		/* # of nested .set volatile's  */
 extern int mips_branch_likely;		/* emit 'l' after br (branch likely) */
-extern int mips_dbx_regno[];		/* Map register # to debug register # */
+extern int mips_dbx_regno[];
+extern int mips_dwarf_regno[];
 extern bool mips_split_p[];
 extern GTY(()) rtx cmp_operands[2];
 extern enum processor_type mips_arch;   /* which cpu to codegen for */
@@ -1010,11 +1011,10 @@ #define USER_LABEL_PREFIX	""
 #define DBX_CONTIN_LENGTH 1500
 
 /* How to renumber registers for dbx and gdb.  */
-#define DBX_REGISTER_NUMBER(REGNO) mips_dbx_regno[ (REGNO) ]
+#define DBX_REGISTER_NUMBER(REGNO) mips_dbx_regno[REGNO]
 
 /* The mapping from gcc register number to DWARF 2 CFA column number.  */
-#define DWARF_FRAME_REGNUM(REG) \
-  ((REG) == DWARF_ALT_FRAME_RETURN_COLUMN ? INVALID_REGNUM : (REG))
+#define DWARF_FRAME_REGNUM(REGNO) mips_dwarf_regno[REGNO]
 
 /* The DWARF 2 CFA column which tracks the return address.  */
 #define DWARF_FRAME_RETURN_COLUMN (GP_REG_FIRST + 31)
@@ -1393,14 +1393,8 @@ #define DSP_ACC_REG_LAST 181
 #define DSP_ACC_REG_NUM (DSP_ACC_REG_LAST - DSP_ACC_REG_FIRST + 1)
 
 #define AT_REGNUM	(GP_REG_FIRST + 1)
-#define HI_REGNUM	(MD_REG_FIRST + 0)
-#define LO_REGNUM	(MD_REG_FIRST + 1)
-#define AC1HI_REGNUM	(DSP_ACC_REG_FIRST + 0)
-#define AC1LO_REGNUM	(DSP_ACC_REG_FIRST + 1)
-#define AC2HI_REGNUM	(DSP_ACC_REG_FIRST + 2)
-#define AC2LO_REGNUM	(DSP_ACC_REG_FIRST + 3)
-#define AC3HI_REGNUM	(DSP_ACC_REG_FIRST + 4)
-#define AC3LO_REGNUM	(DSP_ACC_REG_FIRST + 5)
+#define HI_REGNUM	(TARGET_BIG_ENDIAN ? MD_REG_FIRST : MD_REG_FIRST + 1)
+#define LO_REGNUM	(TARGET_BIG_ENDIAN ? MD_REG_FIRST + 1 : MD_REG_FIRST)
 
 /* FPSW_REGNUM is the single condition code used if !ISA_HAS_8CC.
    If ISA_HAS_8CC, it should not be used, and an arbitrary ST_REG
@@ -1431,10 +1425,6 @@ #define DSP_ACC_REG_P(REGNO) \
 /* Test if REGNO is hi, lo, or one of the 6 new DSP accumulators.  */
 #define ACC_REG_P(REGNO) \
   (MD_REG_P (REGNO) || DSP_ACC_REG_P (REGNO))
-/* Test if REGNO is HI or the first register of 3 new DSP accumulator pairs.  */
-#define ACC_HI_REG_P(REGNO) \
-  ((REGNO) == HI_REGNUM || (REGNO) == AC1HI_REGNUM || (REGNO) == AC2HI_REGNUM \
-   || (REGNO) == AC3HI_REGNUM)
 
 #define FP_REG_RTX_P(X) (REG_P (X) && FP_REG_P (REGNO (X)))
 
@@ -1562,8 +1552,8 @@ enum reg_class
   LEA_REGS,			/* Every GPR except $25 */
   GR_REGS,			/* integer registers */
   FP_REGS,			/* floating point registers */
-  HI_REG,			/* hi register */
-  LO_REG,			/* lo register */
+  MD0_REG,			/* first multiply/divide register */
+  MD1_REG,			/* second multiply/divide register */
   MD_REGS,			/* multiply/divide registers (hi/lo) */
   COP0_REGS,			/* generic coprocessor classes */
   COP2_REGS,
@@ -1603,8 +1593,8 @@ #define REG_CLASS_NAMES							\
   "LEA_REGS",								\
   "GR_REGS",								\
   "FP_REGS",								\
-  "HI_REG",								\
-  "LO_REG",								\
+  "MD0_REG",								\
+  "MD1_REG",								\
   "MD_REGS",								\
   /* coprocessor registers */						\
   "COP0_REGS",								\
Index: gcc/config/mips/mips.c
===================================================================
--- gcc/config/mips/mips.c	2007-07-20 13:40:17.000000000 +0100
+++ gcc/config/mips/mips.c	2007-07-20 13:40:28.000000000 +0100
@@ -639,6 +639,7 @@ char mips_hard_regno_mode_ok[(int)MAX_MA
 
 /* Map GCC register number to debugger register number.  */
 int mips_dbx_regno[FIRST_PSEUDO_REGISTER];
+int mips_dwarf_regno[FIRST_PSEUDO_REGISTER];
 
 /* A copy of the original flag_delayed_branch: see override_options.  */
 static int mips_flag_delayed_branch;
@@ -676,7 +677,7 @@ const enum reg_class mips_regno_to_class
   FP_REGS,	FP_REGS,	FP_REGS,	FP_REGS,
   FP_REGS,	FP_REGS,	FP_REGS,	FP_REGS,
   FP_REGS,	FP_REGS,	FP_REGS,	FP_REGS,
-  HI_REG,	LO_REG,		NO_REGS,	ST_REGS,
+  MD0_REG,	MD1_REG,	NO_REGS,	ST_REGS,
   ST_REGS,	ST_REGS,	ST_REGS,	ST_REGS,
   ST_REGS,	ST_REGS,	ST_REGS,	NO_REGS,
   NO_REGS,	ALL_REGS,	ALL_REGS,	NO_REGS,
@@ -3004,13 +3005,8 @@ mips_subword (rtx op, int high_p)
   else
     byte = 0;
 
-  if (REG_P (op))
-    {
-      if (FP_REG_P (REGNO (op)))
-	return gen_rtx_REG (word_mode, high_p ? REGNO (op) + 1 : REGNO (op));
-      if (ACC_HI_REG_P (REGNO (op)))
-	return gen_rtx_REG (word_mode, high_p ? REGNO (op) : REGNO (op) + 1);
-    }
+  if (FP_REG_RTX_P (op))
+    return gen_rtx_REG (word_mode, high_p ? REGNO (op) + 1 : REGNO (op));
 
   if (MEM_P (op))
     return mips_rewrite_small_data (adjust_address (op, word_mode, byte));
@@ -5306,7 +5302,13 @@ override_options (void)
      Ignore the special purpose register numbers.  */
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    mips_dbx_regno[i] = -1;
+    {
+      mips_dbx_regno[i] = INVALID_REGNUM;
+      if (GP_REG_P (i) || FP_REG_P (i) || ALL_COP_REG_P (i))
+	mips_dwarf_regno[i] = i;
+      else
+	mips_dwarf_regno[i] = INVALID_REGNUM;
+    }
 
   start = GP_DBX_FIRST - GP_REG_FIRST;
   for (i = GP_REG_FIRST; i <= GP_REG_LAST; i++)
@@ -5316,8 +5318,16 @@ override_options (void)
   for (i = FP_REG_FIRST; i <= FP_REG_LAST; i++)
     mips_dbx_regno[i] = i + start;
 
+  /* HI and LO debug registers use big-endian ordering.  */
   mips_dbx_regno[HI_REGNUM] = MD_DBX_FIRST + 0;
   mips_dbx_regno[LO_REGNUM] = MD_DBX_FIRST + 1;
+  mips_dwarf_regno[HI_REGNUM] = MD_REG_FIRST + 0;
+  mips_dwarf_regno[LO_REGNUM] = MD_REG_FIRST + 1;
+  for (i = DSP_ACC_REG_FIRST; i <= DSP_ACC_REG_LAST; i += 2)
+    {
+      mips_dwarf_regno[i + TARGET_LITTLE_ENDIAN] = i;
+      mips_dwarf_regno[i + TARGET_BIG_ENDIAN] = i + 1;
+    }
 
   /* Set up array giving whether a given register can hold a given mode.  */
 
@@ -5375,9 +5385,11 @@ override_options (void)
 
           else if (ACC_REG_P (regno))
 	    temp = (INTEGRAL_MODE_P (mode)
+		    && size <= UNITS_PER_WORD * 2
 		    && (size <= UNITS_PER_WORD
-			|| (ACC_HI_REG_P (regno)
-			    && size == 2 * UNITS_PER_WORD)));
+			|| regno == MD_REG_FIRST
+			|| (DSP_ACC_REG_P (regno)
+			    && ((regno - DSP_ACC_REG_FIRST) & 1) == 0)));
 
 	  else if (ALL_COP_REG_P (regno))
 	    temp = (class == MODE_INT && size <= UNITS_PER_WORD);
@@ -5522,6 +5534,29 @@ override_options (void)
     target_flags |= MASK_FIX_R4400;
 }
 
+/* Swap the register information for registers I and I + 1, which
+   currently have the wrong endianness.  Note that the registers'
+   fixedness and call-clobberedness might have been set on the
+   command line.  */
+
+static void
+mips_swap_registers (unsigned int i)
+{
+  int tmpi;
+  const char *tmps;
+
+#define SWAP_INT(X, Y) (tmpi = (X), (X) = (Y), (Y) = tmpi)
+#define SWAP_STRING(X, Y) (tmps = (X), (X) = (Y), (Y) = tmps)
+
+  SWAP_INT (fixed_regs[i], fixed_regs[i + 1]);
+  SWAP_INT (call_used_regs[i], call_used_regs[i + 1]);
+  SWAP_INT (call_really_used_regs[i], call_really_used_regs[i + 1]);
+  SWAP_STRING (reg_names[i], reg_names[i + 1]);
+
+#undef SWAP_STRING
+#undef SWAP_INT
+}
+
 /* Implement CONDITIONAL_REGISTER_USAGE.  */
 
 void
@@ -5583,6 +5618,15 @@ mips_conditional_register_usage (void)
       for (regno = FP_REG_FIRST + 21; regno <= FP_REG_FIRST + 31; regno+=2)
 	call_really_used_regs[regno] = call_used_regs[regno] = 1;
     }
+  /* Make sure that double-register accumulator values are correctly
+     ordered for the current endianness.  */
+  if (TARGET_LITTLE_ENDIAN)
+    {
+      int regno;
+      mips_swap_registers (MD_REG_FIRST);
+      for (regno = DSP_ACC_REG_FIRST; regno <= DSP_ACC_REG_LAST; regno += 2)
+	mips_swap_registers (regno);
+    }
 }
 
 /* Allocate a chunk of memory for per-function machine-dependent data.  */
@@ -8498,17 +8542,6 @@ mips_cannot_change_mode_class (enum mach
 	  if (MAX_FPRS_PER_FMT > 1 && reg_classes_intersect_p (FP_REGS, class))
 	    return true;
 	}
-      else
-	{
-	  /* LO_REGNO == HI_REGNO + 1, so if a multi-word value is stored
-	     in LO and HI, the high word always comes first.  We therefore
-	     can't allow values stored in HI to change between single-word
-	     and multi-word modes.
-	     This rule applies to both the original HI/LO pair and the new
-	     DSP accumulators.  */
-	  if (reg_classes_intersect_p (ACC_REGS, class))
-	    return true;
-	}
     }
 
   /* gcc assumes that each word of a multiword register can be accessed
Index: gcc/config/mips/constraints.md
===================================================================
--- gcc/config/mips/constraints.md	2007-07-20 10:17:00.000000000 +0100
+++ gcc/config/mips/constraints.md	2007-07-20 13:40:28.000000000 +0100
@@ -30,10 +30,10 @@ (define_register_constraint "t" "T_REG"
 (define_register_constraint "f" "TARGET_HARD_FLOAT ? FP_REGS : NO_REGS"
   "A floating-point register (if available).")
 
-(define_register_constraint "h" "HI_REG"
+(define_register_constraint "h" "TARGET_BIG_ENDIAN ? MD0_REG : MD1_REG"
   "The @code{hi} register.")
 
-(define_register_constraint "l" "LO_REG"
+(define_register_constraint "l" "TARGET_BIG_ENDIAN ? MD1_REG : MD0_REG"
   "The @code{lo} register.")
 
 (define_register_constraint "x" "MD_REGS"
Index: gcc/config/mips/mips.md
===================================================================
--- gcc/config/mips/mips.md	2007-07-20 13:40:17.000000000 +0100
+++ gcc/config/mips/mips.md	2007-07-20 15:01:53.000000000 +0100
@@ -4059,12 +4059,9 @@ (define_insn "*mfhilo_<mode>_macc"
 		     (match_operand:GPR 2 "register_operand" "l,h")]
 		    UNSPEC_MFHILO))]
   "ISA_HAS_MACCHI"
-{
-  if (REGNO (operands[1]) == HI_REGNUM)
-    return "<d>macchi\t%0,%.,%.";
-  else
-    return "<d>macc\t%0,%.,%.";
-}
+  "@
+   <d>macchi\t%0,%.,%.
+   <d>macc\t%0,%.,%."
   [(set_attr "type" "mfhilo")
    (set_attr "mode" "<MODE>")])
 


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