This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Endianness-dependent ordering of the MIPS hi and lo registers
- From: Richard Sandiford <richard at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Fri, 20 Jul 2007 16:41:01 +0100
- Subject: 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>")])