+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.
+
2007-07-20 Richard Sandiford <richard@codesourcery.com>
* config/arm/arm.md (movsi): Use can_create_pseudo_p instead of
/* 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;
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,
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));
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++)
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. */
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);
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
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. */
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
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 */
#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)
#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
/* 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)))
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,
"LEA_REGS", \
"GR_REGS", \
"FP_REGS", \
- "HI_REG", \
- "LO_REG", \
+ "MD0_REG", \
+ "MD1_REG", \
"MD_REGS", \
/* coprocessor registers */ \
"COP0_REGS", \