From d604bca36430702c878d4e4cca1e8e0ccee35124 Mon Sep 17 00:00:00 2001 From: Matt Hiller Date: Thu, 25 Apr 2002 19:31:45 +0000 Subject: [PATCH] mips.c (mips_class_max_nregs, [...]): New functions. 2002-04-24 Matt Hiller * mips.c (mips_class_max_nregs, mips_register_move_cost): New functions. * mips.h (CLASS_MAX_NREGS, REGISTER_MOVE_COST): Redefine as calls of the corresponding functions. * mips-protos.h (mips_class_max_nregs, mips_register_move_cost): New prototypes. 2002-04-24 Matt Hiller * config/mips/mips.h (mips_sw_reg_names): Declare as extern. (ALL_COP_ADDITIONAL_REGISTER_NAMES): New macro. (FIRST_PSEUDO_REGISTER): Redefine considering coprocessor registers, adjust comment accordingly. (FIXED_REGISTERS, CALL_USED_REGISTERS, CALL_REALLY_USED_REGISTERS, reg_class, REG_CLASS_NAMES, REG_CLASS_CONTENTS, REGISTER_NAMES, DEBUG_REGISTER_NAMES, REG_ALLOC_ORDER): Adjust to include entries for coprocessor registers. (ADDITIONAL_REGISTER_NAMES): Include ALL_COP_ADDITIONAL_REGISTER_NAMES. (COP0_REG_FIRST, COP0_REG_LAST, COP0_REG_NUM, COP2_REG_FIRST, COP2_REG_LAST, COP2_REG_NUM, COP3_REG_FIRST, COP3_REG_LAST, COP3_REG_NUM, COP0_REG_P, COP2_REG_P, COP3_REG_P, ALL_COP_REG_P, COPNUM_AS_CHAR_FROM_REGNUM, COP_REG_CLASS_P): New macros. (mips_char_to_class): Adjust comment to include coprocessor constraint letters. * config/mips/mips.c (coprocessor_operand, coprocessor2_operand): New functions. (mips_reg_names, mips_regno_to_class): Include coprocessor information. (mips_sw_reg_names): Ditto, make non-static. (mips_move_1word): Handle moves to and from coprocessor registers. (mips_move_2words): Handle moves to and from coprocessor registers. (mips_class_max_nregs, mips_register_move_cost): Handle coprocessor register classes. (override_options): Initialize mips_char_to_class and mips_hard_regno_mode_ok properly for coprocessor registers. * config/mips/mips.md (movdi_internal, movdi_internal2, movsi_internal1, movsi_internal2): Add constraint-sets for coprocessor registers. * testsuite/gcc.c-torture/mipscop-1.c: New testcase. * testsuite/gcc.c-torture/mipscop-1.x: Disable above if target isn't mips. * testsuite/gcc.c-torture/mipscop-2.c: New testcase. * testsuite/gcc.c-torture/mipscop-2.x: Disable above if target isn't mips. * testsuite/gcc.c-torture/mipscop-3.c: New testcase. * testsuite/gcc.c-torture/mipscop-3.x: Disable above if target isn't mips. * testsuite/gcc.c-torture/mipscop-4.c: New testcase. * testsuite/gcc.c-torture/mipscop-4.x: Disable above if target isn't mips. * doc/tm.texi: Document feature. From-SVN: r52765 --- gcc/ChangeLog | 63 +++++ gcc/config/mips/mips-protos.h | 5 + gcc/config/mips/mips.c | 285 ++++++++++++++++++++- gcc/config/mips/mips.h | 321 +++++++++++++++++++----- gcc/config/mips/mips.md | 32 +-- gcc/doc/tm.texi | 45 ++++ gcc/testsuite/gcc.c-torture/compile/mipscop-1.c | 10 + gcc/testsuite/gcc.c-torture/compile/mipscop-1.x | 8 + gcc/testsuite/gcc.c-torture/compile/mipscop-2.c | 16 ++ gcc/testsuite/gcc.c-torture/compile/mipscop-2.x | 8 + gcc/testsuite/gcc.c-torture/compile/mipscop-3.c | 16 ++ gcc/testsuite/gcc.c-torture/compile/mipscop-3.x | 8 + gcc/testsuite/gcc.c-torture/compile/mipscop-4.c | 16 ++ gcc/testsuite/gcc.c-torture/compile/mipscop-4.x | 8 + 14 files changed, 753 insertions(+), 88 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/compile/mipscop-1.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/mipscop-1.x create mode 100644 gcc/testsuite/gcc.c-torture/compile/mipscop-2.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/mipscop-2.x create mode 100644 gcc/testsuite/gcc.c-torture/compile/mipscop-3.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/mipscop-3.x create mode 100644 gcc/testsuite/gcc.c-torture/compile/mipscop-4.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/mipscop-4.x diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 77741da..855042c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,66 @@ +2002-04-25 Matt Hiller + + * mips.c (mips_class_max_nregs, mips_register_move_cost): New + functions. + * mips.h (CLASS_MAX_NREGS, REGISTER_MOVE_COST): Redefine as calls + of the corresponding functions. + * mips-protos.h (mips_class_max_nregs, mips_register_move_cost): + New prototypes. + +2002-04-25 Matt Hiller + + * config/mips/mips.h (mips_sw_reg_names): Declare as extern. + + (ALL_COP_ADDITIONAL_REGISTER_NAMES): New macro. + (FIRST_PSEUDO_REGISTER): Redefine considering coprocessor + registers, adjust comment accordingly. + (FIXED_REGISTERS, CALL_USED_REGISTERS, CALL_REALLY_USED_REGISTERS, + reg_class, REG_CLASS_NAMES, REG_CLASS_CONTENTS, REGISTER_NAMES, + DEBUG_REGISTER_NAMES, REG_ALLOC_ORDER): Adjust to include entries + for coprocessor registers. + (ADDITIONAL_REGISTER_NAMES): Include + ALL_COP_ADDITIONAL_REGISTER_NAMES. + + (COP0_REG_FIRST, COP0_REG_LAST, COP0_REG_NUM, + COP2_REG_FIRST, COP2_REG_LAST, COP2_REG_NUM, + COP3_REG_FIRST, COP3_REG_LAST, COP3_REG_NUM, + COP0_REG_P, COP2_REG_P, COP3_REG_P, ALL_COP_REG_P, + COPNUM_AS_CHAR_FROM_REGNUM, COP_REG_CLASS_P): New macros. + + (mips_char_to_class): Adjust comment to include coprocessor + constraint letters. + + * config/mips/mips.c (coprocessor_operand, coprocessor2_operand): + New functions. + (mips_reg_names, mips_regno_to_class): Include coprocessor + information. + (mips_sw_reg_names): Ditto, make non-static. + (mips_move_1word): Handle moves to and from coprocessor registers. + (mips_move_2words): Handle moves to and from coprocessor + registers. + (mips_class_max_nregs, mips_register_move_cost): Handle + coprocessor register classes. + (override_options): Initialize mips_char_to_class and + mips_hard_regno_mode_ok properly for coprocessor registers. + + * config/mips/mips.md (movdi_internal, movdi_internal2, + movsi_internal1, movsi_internal2): Add constraint-sets for + coprocessor registers. + * testsuite/gcc.c-torture/mipscop-1.c: New testcase. + * testsuite/gcc.c-torture/mipscop-1.x: Disable above if target + isn't mips. + * testsuite/gcc.c-torture/mipscop-2.c: New testcase. + * testsuite/gcc.c-torture/mipscop-2.x: Disable above if target + isn't mips. + * testsuite/gcc.c-torture/mipscop-3.c: New testcase. + * testsuite/gcc.c-torture/mipscop-3.x: Disable above if target + isn't mips. + * testsuite/gcc.c-torture/mipscop-4.c: New testcase. + * testsuite/gcc.c-torture/mipscop-4.x: Disable above if target + isn't mips. + + * doc/tm.texi: Document feature. + 2002-04-25 Neil Booth * integrate.c (function_attribute_inlinable_p): Simplify. diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h index 1ea662e..29854f0 100644 --- a/gcc/config/mips/mips-protos.h +++ b/gcc/config/mips/mips-protos.h @@ -117,6 +117,11 @@ extern int mips_adjust_insn_length PARAMS ((rtx, int)); extern enum reg_class mips_secondary_reload_class PARAMS ((enum reg_class, enum machine_mode, rtx, int)); +extern int mips_class_max_nregs PARAMS ((enum reg_class, + enum machine_mode)); +extern int mips_register_move_cost PARAMS ((enum machine_mode, + enum reg_class, + enum reg_class)); extern void mips_select_rtx_section PARAMS ((enum machine_mode, rtx)); diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 0da1adb..a02dc6a 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -90,6 +90,10 @@ struct mips_arg_info; static enum internal_test map_test_to_internal_test PARAMS ((enum rtx_code)); static int mips16_simple_memory_operand PARAMS ((rtx, rtx, enum machine_mode)); +int coprocessor_operand PARAMS ((rtx, + enum machine_mode)); +int coprocessor2_operand PARAMS ((rtx, + enum machine_mode)); static int m16_check_op PARAMS ((rtx, int, int, int)); static void block_move_loop PARAMS ((rtx, rtx, unsigned int, @@ -383,13 +387,25 @@ char mips_reg_names[][8] = "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31", "hi", "lo", "accum","$fcc0","$fcc1","$fcc2","$fcc3","$fcc4", - "$fcc5","$fcc6","$fcc7","$rap" + "$fcc5","$fcc6","$fcc7","$rap", "", "", "", "", + "$c0r0", "$c0r1", "$c0r2", "$c0r3", "$c0r4", "$c0r5", "$c0r6", "$c0r7", + "$c0r8", "$c0r9", "$c0r10","$c0r11","$c0r12","$c0r13","$c0r14","$c0r15", + "$c0r16","$c0r17","$c0r18","$c0r19","$c0r20","$c0r21","$c0r22","$c0r23", + "$c0r24","$c0r25","$c0r26","$c0r27","$c0r28","$c0r29","$c0r30","$c0r31", + "$c2r0", "$c2r1", "$c2r2", "$c2r3", "$c2r4", "$c2r5", "$c2r6", "$c2r7", + "$c2r8", "$c2r9", "$c2r10","$c2r11","$c2r12","$c2r13","$c2r14","$c2r15", + "$c2r16","$c2r17","$c2r18","$c2r19","$c2r20","$c2r21","$c2r22","$c2r23", + "$c2r24","$c2r25","$c2r26","$c2r27","$c2r28","$c2r29","$c2r30","$c2r31", + "$c3r0", "$c3r1", "$c3r2", "$c3r3", "$c3r4", "$c3r5", "$c3r6", "$c3r7", + "$c3r8", "$c3r9", "$c3r10","$c3r11","$c3r12","$c3r13","$c3r14","$c3r15", + "$c3r16","$c3r17","$c3r18","$c3r19","$c3r20","$c3r21","$c3r22","$c3r23", + "$c3r24","$c3r25","$c3r26","$c3r27","$c3r28","$c3r29","$c3r30","$c3r31" }; /* Mips software names for the registers, used to overwrite the mips_reg_names array. */ -static const char mips_sw_reg_names[][8] = +char mips_sw_reg_names[][8] = { "$zero","$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3", "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", @@ -400,7 +416,19 @@ static const char mips_sw_reg_names[][8] = "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31", "hi", "lo", "accum","$fcc0","$fcc1","$fcc2","$fcc3","$fcc4", - "$fcc5","$fcc6","$fcc7","$rap" + "$fcc5","$fcc6","$fcc7","$rap", "", "", "", "", + "$c0r0", "$c0r1", "$c0r2", "$c0r3", "$c0r4", "$c0r5", "$c0r6", "$c0r7", + "$c0r8", "$c0r9", "$c0r10","$c0r11","$c0r12","$c0r13","$c0r14","$c0r15", + "$c0r16","$c0r17","$c0r18","$c0r19","$c0r20","$c0r21","$c0r22","$c0r23", + "$c0r24","$c0r25","$c0r26","$c0r27","$c0r28","$c0r29","$c0r30","$c0r31", + "$c2r0", "$c2r1", "$c2r2", "$c2r3", "$c2r4", "$c2r5", "$c2r6", "$c2r7", + "$c2r8", "$c2r9", "$c2r10","$c2r11","$c2r12","$c2r13","$c2r14","$c2r15", + "$c2r16","$c2r17","$c2r18","$c2r19","$c2r20","$c2r21","$c2r22","$c2r23", + "$c2r24","$c2r25","$c2r26","$c2r27","$c2r28","$c2r29","$c2r30","$c2r31", + "$c3r0", "$c3r1", "$c3r2", "$c3r3", "$c3r4", "$c3r5", "$c3r6", "$c3r7", + "$c3r8", "$c3r9", "$c3r10","$c3r11","$c3r12","$c3r13","$c3r14","$c3r15", + "$c3r16","$c3r17","$c3r18","$c3r19","$c3r20","$c3r21","$c3r22","$c3r23", + "$c3r24","$c3r25","$c3r26","$c3r27","$c3r28","$c3r29","$c3r30","$c3r31" }; /* Map hard register number to register class */ @@ -424,7 +452,32 @@ const enum reg_class mips_regno_to_class[] = FP_REGS, FP_REGS, FP_REGS, FP_REGS, HI_REG, LO_REG, HILO_REG, ST_REGS, ST_REGS, ST_REGS, ST_REGS, ST_REGS, - ST_REGS, ST_REGS, ST_REGS, GR_REGS + ST_REGS, ST_REGS, ST_REGS, GR_REGS, + NO_REGS, NO_REGS, NO_REGS, NO_REGS, + COP0_REGS, COP0_REGS, COP0_REGS, COP0_REGS, + COP0_REGS, COP0_REGS, COP0_REGS, COP0_REGS, + COP0_REGS, COP0_REGS, COP0_REGS, COP0_REGS, + COP0_REGS, COP0_REGS, COP0_REGS, COP0_REGS, + COP0_REGS, COP0_REGS, COP0_REGS, COP0_REGS, + COP0_REGS, COP0_REGS, COP0_REGS, COP0_REGS, + COP0_REGS, COP0_REGS, COP0_REGS, COP0_REGS, + COP0_REGS, COP0_REGS, COP0_REGS, COP0_REGS, + COP2_REGS, COP2_REGS, COP2_REGS, COP2_REGS, + COP2_REGS, COP2_REGS, COP2_REGS, COP2_REGS, + COP2_REGS, COP2_REGS, COP2_REGS, COP2_REGS, + COP2_REGS, COP2_REGS, COP2_REGS, COP2_REGS, + COP2_REGS, COP2_REGS, COP2_REGS, COP2_REGS, + COP2_REGS, COP2_REGS, COP2_REGS, COP2_REGS, + COP2_REGS, COP2_REGS, COP2_REGS, COP2_REGS, + COP2_REGS, COP2_REGS, COP2_REGS, COP2_REGS, + COP3_REGS, COP3_REGS, COP3_REGS, COP3_REGS, + COP3_REGS, COP3_REGS, COP3_REGS, COP3_REGS, + COP3_REGS, COP3_REGS, COP3_REGS, COP3_REGS, + COP3_REGS, COP3_REGS, COP3_REGS, COP3_REGS, + COP3_REGS, COP3_REGS, COP3_REGS, COP3_REGS, + COP3_REGS, COP3_REGS, COP3_REGS, COP3_REGS, + COP3_REGS, COP3_REGS, COP3_REGS, COP3_REGS, + COP3_REGS, COP3_REGS, COP3_REGS, COP3_REGS }; /* Map register constraint character to register class. */ @@ -1284,6 +1337,29 @@ consttable_operand (op, mode) return CONSTANT_P (op); } +/* Coprocessor operand; return true if rtx is a REG and refers to a + coprocessor. */ + +int +coprocessor_operand (op, mode) + rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + return (GET_CODE (op) == REG + && COP0_REG_FIRST <= REGNO (op) + && REGNO (op) <= COP3_REG_LAST); +} + +int +coprocessor2_operand (op, mode) + rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + return (GET_CODE (op) == REG + && COP2_REG_FIRST <= REGNO (op) + && REGNO (op) <= COP2_REG_LAST); +} + /* Return nonzero if we split the address into high and low parts. */ /* ??? We should also handle reg+array somewhere. We get four @@ -1995,7 +2071,13 @@ mips_move_1word (operands, insn, unsignedp) delay = DELAY_LOAD; if (FP_REG_P (regno1)) ret = "mfc1\t%0,%1"; + else if (ALL_COP_REG_P (regno1)) + { + static char retval[] = "mfc_\t%0,%1"; + retval[3] = COPNUM_AS_CHAR_FROM_REGNUM (regno1); + ret = retval; + } else if (regno1 == FPSW_REGNUM && ! ISA_HAS_8CC) ret = "cfc1\t%0,$31"; } @@ -2031,6 +2113,21 @@ mips_move_1word (operands, insn, unsignedp) ret = "ctc1\t%0,$31"; } } + else if (ALL_COP_REG_P (regno0)) + { + if (GP_REG_P (regno1)) + { + static char retval[] = "mtc_\t%1,%0"; + char cop = COPNUM_AS_CHAR_FROM_REGNUM (regno0); + + if (cop == '0') + abort_with_insn (insn, + "mtc0 not supported; it disturbs virtual address translation"); + delay = DELAY_LOAD; + retval[3] = cop; + ret = retval; + } + } } else if (code1 == MEM) @@ -2069,6 +2166,19 @@ mips_move_1word (operands, insn, unsignedp) else if (FP_REG_P (regno0) && (mode == SImode || mode == SFmode)) ret = "l.s\t%0,%1"; + else if (ALL_COP_REG_P (regno0)) + { + static char retval[] = "lwc_\t%0,%1"; + char cop = COPNUM_AS_CHAR_FROM_REGNUM (regno0); + + if (cop == '0') + abort_with_insn (insn, + "loads from memory to COP0 are illegal"); + delay = DELAY_LOAD; + retval[3] = cop; + ret = retval; + } + if (ret != (char *)0 && MEM_VOLATILE_P (op1)) { size_t i = strlen (ret); @@ -2267,6 +2377,13 @@ mips_move_1word (operands, insn, unsignedp) else if (FP_REG_P (regno1) && (mode == SImode || mode == SFmode)) ret = "s.s\t%1,%0"; + else if (ALL_COP_REG_P (regno1)) + { + static char retval[] = "swc_\t%1,%0"; + + retval[3] = COPNUM_AS_CHAR_FROM_REGNUM (regno1); + ret = retval; + } } else if (code1 == CONST_INT && INTVAL (op1) == 0) @@ -2453,7 +2570,28 @@ mips_move_2words (operands, insn) else ret = "mfhi\t%M0\n\tmflo\t%L0"; } + else if (GP_REG_P (regno0) && ALL_COP_REG_P (regno1) + && TARGET_64BIT) + { + static char retval[] = "dmfc_\t%0,%1"; + + delay = DELAY_LOAD; + retval[4] = COPNUM_AS_CHAR_FROM_REGNUM (regno1); + ret = retval; + } + else if (ALL_COP_REG_P (regno0) && GP_REG_P (regno1) + && TARGET_64BIT) + { + static char retval[] = "dmtc_\t%1,%0"; + char cop = COPNUM_AS_CHAR_FROM_REGNUM (regno0); + if (cop == '0') + abort_with_insn (insn, + "dmtc0 not supported; it disturbs virtual address translation"); + delay = DELAY_LOAD; + retval[4] = cop; + ret = retval; + } else if (TARGET_64BIT) ret = "move\t%0,%1"; @@ -2634,6 +2772,19 @@ mips_move_2words (operands, insn) if (FP_REG_P (regno0)) ret = "l.d\t%0,%1"; + else if (ALL_COP_REG_P (regno0) && TARGET_64BIT) + { + static char retval[] = "ldc_\t%0,%1"; + char cop = COPNUM_AS_CHAR_FROM_REGNUM (regno0); + + if (cop == '0') + abort_with_insn (insn, + "loads from memory to COP0 are illegal"); + delay = DELAY_LOAD; + retval[3] = cop; + ret = retval; + } + else if (TARGET_64BIT) { @@ -2727,6 +2878,13 @@ mips_move_2words (operands, insn) if (FP_REG_P (regno1)) ret = "s.d\t%1,%0"; + else if (ALL_COP_REG_P (regno1) && TARGET_64BIT) + { + static char retval[] = "sdc_\t%1,%0"; + + retval[3] = COPNUM_AS_CHAR_FROM_REGNUM (regno1); + ret = retval; + } else if (TARGET_64BIT) { @@ -5172,6 +5330,9 @@ override_options () mips_char_to_class['b'] = ALL_REGS; mips_char_to_class['y'] = GR_REGS; mips_char_to_class['z'] = ST_REGS; + mips_char_to_class['B'] = COP0_REGS; + mips_char_to_class['C'] = COP2_REGS; + mips_char_to_class['D'] = COP3_REGS; /* Set up array to map GCC register number to debug register number. Ignore the special purpose register numbers. */ @@ -5237,6 +5398,8 @@ override_options () || (regno == MD_REG_FIRST && size == 2 * UNITS_PER_WORD))); + else if (ALL_COP_REG_P (regno)) + temp = (class == MODE_INT && size <= UNITS_PER_WORD); else temp = 0; @@ -8215,6 +8378,20 @@ mips_secondary_reload_class (class, mode, x, in_p) return NO_REGS; } + +/* This function returns the maximum number of consecutive registers + needed to represent mode MODE in registers of class CLASS. */ + +int +mips_class_max_nregs (class, mode) + enum reg_class class; + enum machine_mode mode; +{ + if (class == FP_REGS) + return FP_INC; + else + return (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; +} /* For each mips16 function which refers to GP relative symbols, we use a pseudo register, initialized at the start of the function, to @@ -9529,6 +9706,106 @@ highpart_shift_operator (x, mode) || code == ROTATE); } +/* Return a number assessing the cost of moving a register in class + FROM to class TO. The classes are expressed using the enumeration + values such as `GENERAL_REGS'. A value of 2 is the default; other + values are interpreted relative to that. + + It is not required that the cost always equal 2 when FROM is the + same as TO; on some machines it is expensive to move between + registers if they are not general registers. + + If reload sees an insn consisting of a single `set' between two + hard registers, and if `REGISTER_MOVE_COST' applied to their + classes returns a value of 2, reload does not check to ensure that + the constraints of the insn are met. Setting a cost of other than + 2 will allow reload to verify that the constraints are met. You + should do this if the `movM' pattern's constraints do not allow + such copying. + + ??? We make make the cost of moving from HI/LO/HILO/MD into general + registers the same as for one of moving general registers to + HI/LO/HILO/MD for TARGET_MIPS16 in order to prevent allocating a + pseudo to HI/LO/HILO/MD. This might hurt optimizations though, it + isn't clear if it is wise. And it might not work in all cases. We + could solve the DImode LO reg problem by using a multiply, just + like reload_{in,out}si. We could solve the SImode/HImode HI reg + problem by using divide instructions. divu puts the remainder in + the HI reg, so doing a divide by -1 will move the value in the HI + reg for all values except -1. We could handle that case by using a + signed divide, e.g. -1 / 2 (or maybe 1 / -2?). We'd have to emit + a compare/branch to test the input value to see which instruction + we need to use. This gets pretty messy, but it is feasible. */ + +int +mips_register_move_cost (mode, to, from) + enum machine_mode mode; + enum reg_class to, from; +{ + if (from == M16_REGS && GR_REG_CLASS_P (to)) + return 2; + else if (from == M16_NA_REGS && GR_REG_CLASS_P (to)) + return 2; + else if (GR_REG_CLASS_P (from)) + { + if (to == M16_REGS) + return 2; + else if (to == M16_NA_REGS) + return 2; + else if (GR_REG_CLASS_P (to)) + { + if (TARGET_MIPS16) + return 4; + else + return 2; + } + else if (to == FP_REGS) + return 4; + else if (to == HI_REG || to == LO_REG || to == MD_REGS + || to == HILO_REG) + { + if (TARGET_MIPS16) + return 12; + else + return 6; + } + else if (COP_REG_CLASS_P (to)) + { + return 5; + } + } /* GR_REG_CLASS_P (from) */ + else if (from == FP_REGS) + { + if (GR_REG_CLASS_P (to)) + return 4; + else if (to == FP_REGS) + return 2; + else if (to == ST_REGS) + return 8; + } /* from == FP_REGS */ + else if (from == HI_REG || from == LO_REG || from == MD_REGS + || from == HILO_REG) + { + if (GR_REG_CLASS_P (to)) + { + if (TARGET_MIPS16) + return 12; + else + return 6; + } + } /* from == HI_REG, etc. */ + else if (from == ST_REGS && GR_REG_CLASS_P (to)) + return 4; + else if (COP_REG_CLASS_P (from)) + { + return 5; + } /* COP_REG_CLASS_P (from) */ + + /* fallthru */ + + return 12; +} + /* Return the length of INSN. LENGTH is the initial length computed by attributes in the machine-description file. */ diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index ab5bd5e..670b413 100644 --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -1795,28 +1795,44 @@ do { \ On the Mips, we have 32 integer registers, 32 floating point registers, 8 condition code registers, and the special registers - hi, lo, hilo, and rap. The 8 condition code registers are only - used if mips_isa >= 4. The hilo register is only used in 64 bit - mode. It represents a 64 bit value stored as two 32 bit values in - the hi and lo registers; this is the result of the mult - instruction. rap is a pointer to the stack where the return - address reg ($31) was stored. This is needed for C++ exception - handling. */ + hi, lo, hilo, and rap. Afetr that we have 32 COP0 registers, 32 + COP2 registers, and 32 COp3 registers. (COP1 is the floating-point + processor.) The 8 condition code registers are only used if + mips_isa >= 4. The hilo register is only used in 64 bit mode. It + represents a 64 bit value stored as two 32 bit values in the hi and + lo registers; this is the result of the mult instruction. rap is a + pointer to the stack where the return address reg ($31) was stored. + This is needed for C++ exception handling. */ -#define FIRST_PSEUDO_REGISTER 76 +#define FIRST_PSEUDO_REGISTER 176 /* 1 for registers that have pervasive standard uses and are not available for the register allocator. On the MIPS, see conventions, page D-2 */ +/* Regarding coprocessor registers: without evidence to the contrary, + it's best to assume that each coprocessor register has a unique + use. This can be overridden, in, e.g., override_options() or + CONDITIONAL_REGISTER_USAGE should the assumption be inappropriate + for a particular target. */ + #define FIXED_REGISTERS \ { \ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, \ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, \ + /* COP0 registers */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + /* COP2 registers */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + /* COP3 registers */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 \ } @@ -1833,7 +1849,16 @@ do { \ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, \ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, \ + /* COP0 registers */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + /* COP2 registers */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + /* COP3 registers */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 \ } /* Like `CALL_USED_REGISTERS' but used to overcome a historical @@ -1853,7 +1878,16 @@ do { \ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ /* Others. */ \ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, \ + /* COP0 registers */ \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + /* COP2 registers */ \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + /* COP3 registers */ \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \ } /* Internal macros to classify a register number as to whether it's a @@ -1880,6 +1914,20 @@ do { \ #define RAP_REG_NUM 75 +#define COP0_REG_FIRST 80 +#define COP0_REG_LAST 111 +#define COP0_REG_NUM (COP0_REG_LAST - COP0_REG_FIRST + 1) + +#define COP2_REG_FIRST 112 +#define COP2_REG_LAST 143 +#define COP2_REG_NUM (COP2_REG_LAST - COP2_REG_FIRST + 1) + +#define COP3_REG_FIRST 144 +#define COP3_REG_LAST 175 +#define COP3_REG_NUM (COP3_REG_LAST - COP3_REG_FIRST + 1) +/* ALL_COP_REG_NUM assumes that COP0,2,and 3 are numbered consecutively. */ +#define ALL_COP_REG_NUM (COP3_REG_LAST - COP0_REG_FIRST + 1) + #define AT_REGNUM (GP_REG_FIRST + 1) #define HI_REGNUM (MD_REG_FIRST + 0) #define LO_REGNUM (MD_REG_FIRST + 1) @@ -1900,6 +1948,20 @@ do { \ ((unsigned int) ((int) (REGNO) - MD_REG_FIRST) < MD_REG_NUM) #define ST_REG_P(REGNO) \ ((unsigned int) ((int) (REGNO) - ST_REG_FIRST) < ST_REG_NUM) +#define COP0_REG_P(REGNO) \ + ((unsigned int) ((int) (REGNO) - COP0_REG_FIRST) < COP0_REG_NUM) +#define COP2_REG_P(REGNO) \ + ((unsigned int) ((int) (REGNO) - COP2_REG_FIRST) < COP2_REG_NUM) +#define COP3_REG_P(REGNO) \ + ((unsigned int) ((int) (REGNO) - COP3_REG_FIRST) < COP3_REG_NUM) +#define ALL_COP_REG_P(REGNO) \ + ((unsigned int) ((int) (REGNO) - COP0_REG_FIRST) < ALL_COP_REG_NUM) + +/* Return coprocessor number from register number. */ + +#define COPNUM_AS_CHAR_FROM_REGNUM(REGNO) \ + (COP0_REG_P (REGNO) ? '0' : COP2_REG_P (REGNO) ? '2' \ + : COP3_REG_P (REGNO) ? '3' : '?') /* Return number of consecutive hard regs needed starting at reg REGNO to hold something of mode MODE. @@ -2051,10 +2113,18 @@ enum reg_class LO_REG, /* lo register */ HILO_REG, /* hilo register pair for 64 bit mode mult */ MD_REGS, /* multiply/divide registers (hi/lo) */ + COP0_REGS, /* generic coprocessor classes */ + COP2_REGS, + COP3_REGS, HI_AND_GR_REGS, /* union classes */ LO_AND_GR_REGS, HILO_AND_GR_REGS, HI_AND_FP_REGS, + COP0_AND_GR_REGS, + COP2_AND_GR_REGS, + COP3_AND_GR_REGS, + ALL_COP_REGS, + ALL_COP_AND_GR_REGS, ST_REGS, /* status registers (fp status) */ ALL_REGS, /* all registers */ LIM_REG_CLASSES /* max value + 1 */ @@ -2081,10 +2151,19 @@ enum reg_class "LO_REG", \ "HILO_REG", \ "MD_REGS", \ + /* coprocessor registers */ \ + "COP0_REGS", \ + "COP2_REGS", \ + "COP3_REGS", \ "HI_AND_GR_REGS", \ "LO_AND_GR_REGS", \ "HILO_AND_GR_REGS", \ "HI_AND_FP_REGS", \ + "COP0_AND_GR_REGS", \ + "COP2_AND_GR_REGS", \ + "COP3_AND_GR_REGS", \ + "ALL_COP_REGS", \ + "ALL_COP_AND_GR_REGS", \ "ST_REGS", \ "ALL_REGS" \ } @@ -2102,23 +2181,31 @@ enum reg_class #define REG_CLASS_CONTENTS \ { \ - { 0x00000000, 0x00000000, 0x00000000 }, /* no registers */ \ - { 0x0003000c, 0x00000000, 0x00000000 }, /* mips16 nonarg regs */\ - { 0x000300fc, 0x00000000, 0x00000000 }, /* mips16 registers */ \ - { 0x01000000, 0x00000000, 0x00000000 }, /* mips16 T register */ \ - { 0x010300fc, 0x00000000, 0x00000000 }, /* mips16 and T regs */ \ - { 0xffffffff, 0x00000000, 0x00000000 }, /* integer registers */ \ - { 0x00000000, 0xffffffff, 0x00000000 }, /* floating registers*/ \ - { 0x00000000, 0x00000000, 0x00000001 }, /* hi register */ \ - { 0x00000000, 0x00000000, 0x00000002 }, /* lo register */ \ - { 0x00000000, 0x00000000, 0x00000004 }, /* hilo register */ \ - { 0x00000000, 0x00000000, 0x00000003 }, /* mul/div registers */ \ - { 0xffffffff, 0x00000000, 0x00000001 }, /* union classes */ \ - { 0xffffffff, 0x00000000, 0x00000002 }, \ - { 0xffffffff, 0x00000000, 0x00000004 }, \ - { 0x00000000, 0xffffffff, 0x00000001 }, \ - { 0x00000000, 0x00000000, 0x000007f8 }, /* status registers */ \ - { 0xffffffff, 0xffffffff, 0x000007ff } /* all registers */ \ + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* no registers */ \ + { 0x0003000c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* mips16 nonarg regs */\ + { 0x000300fc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* mips16 registers */ \ + { 0x01000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* mips16 T register */ \ + { 0x010300fc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* mips16 and T regs */ \ + { 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* integer registers */ \ + { 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* floating registers*/ \ + { 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000 }, /* hi register */ \ + { 0x00000000, 0x00000000, 0x00000002, 0x00000000, 0x00000000, 0x00000000 }, /* lo register */ \ + { 0x00000000, 0x00000000, 0x00000004, 0x00000000, 0x00000000, 0x00000000 }, /* hilo register */ \ + { 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000000, 0x00000000 }, /* mul/div registers */ \ + { 0x00000000, 0x00000000, 0xffff0000, 0x0000ffff, 0x00000000, 0x00000000 }, /* cop0 registers */ \ + { 0x00000000, 0x00000000, 0x00000000, 0xffff0000, 0x0000ffff, 0x00000000 }, /* cop2 registers */ \ + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffff0000, 0x0000ffff }, /* cop3 registers */ \ + { 0xffffffff, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000 }, /* union classes */ \ + { 0xffffffff, 0x00000000, 0x00000002, 0x00000000, 0x00000000, 0x00000000 }, \ + { 0xffffffff, 0x00000000, 0x00000004, 0x00000000, 0x00000000, 0x00000000 }, \ + { 0x00000000, 0xffffffff, 0x00000001, 0x00000000, 0x00000000, 0x00000000 }, \ + { 0xffffffff, 0x00000000, 0xffff0000, 0x0000ffff, 0x00000000, 0x00000000 }, \ + { 0xffffffff, 0x00000000, 0x00000000, 0xffff0000, 0x0000ffff, 0x00000000 }, \ + { 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffff0000, 0x0000ffff }, \ + { 0x00000000, 0x00000000, 0xffff0000, 0xffffffff, 0xffffffff, 0x0000ffff }, \ + { 0xffffffff, 0x00000000, 0xffff0000, 0xffffffff, 0xffffffff, 0x0000ffff }, \ + { 0x00000000, 0x00000000, 0x000007f8, 0x00000000, 0x00000000, 0x00000000 }, /* status registers */ \ + { 0xffffffff, 0xffffffff, 0xffff07ff, 0xffffffff, 0xffffffff, 0x0000ffff } /* all registers */ \ } @@ -2157,6 +2244,10 @@ extern const enum reg_class mips_regno_to_class[]; ((CLASS) == GR_REGS || (CLASS) == M16_REGS || (CLASS) == T_REG \ || (CLASS) == M16_T_REGS || (CLASS) == M16_NA_REGS) +/* This macro is also used later on in the file. */ +#define COP_REG_CLASS_P(CLASS) \ + ((CLASS) == COP0_REGS || (CLASS) == COP2_REGS || (CLASS) == COP3_REGS) + /* REG_ALLOC_ORDER is to order in which to allocate registers. This is the default value (allocate the registers in numeric order). We define it just so that we can override it for the mips16 target in @@ -2167,7 +2258,13 @@ extern const enum reg_class mips_regno_to_class[]; 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, \ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, \ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, \ - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75 \ + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, \ + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, \ + 96, 97, 98, 99, 100,101,102,103,104,105,106,107,108,109,110,111, \ + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, \ + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, \ + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, \ + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175 \ } /* ORDER_REGS_FOR_LOCAL_ALLOC is a macro which permits reg_alloc_order @@ -2195,6 +2292,9 @@ extern const enum reg_class mips_regno_to_class[]; 'x' Multiply/divide registers 'a' HILO_REG 'z' FP Status register + 'B' Cop0 register + 'C' Cop2 register + 'D' Cop3 register 'b' All registers */ extern enum reg_class mips_char_to_class[256]; @@ -2333,10 +2433,7 @@ extern enum reg_class mips_char_to_class[256]; /* Return the maximum number of consecutive registers needed to represent mode MODE in a register of class CLASS. */ -#define CLASS_MAX_NREGS(CLASS, MODE) \ - ((CLASS) == FP_REGS \ - ? FP_INC \ - : (GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) +#define CLASS_MAX_NREGS(CLASS, MODE) mips_class_max_nregs (CLASS, MODE) /* If defined, gives a class of registers that cannot be used as the operand of a SUBREG that changes the mode of the object illegally. @@ -3939,40 +4036,10 @@ while (0) that the constraints of the insn are met. Setting a cost of other than 2 will allow reload to verify that the constraints are met. You should do this if the `movM' pattern's constraints do - not allow such copying. - - ??? We make make the cost of moving from HI/LO/HILO/MD into general - registers the same as for one of moving general registers to - HI/LO/HILO/MD for TARGET_MIPS16 in order to prevent allocating a - pseudo to HI/LO/HILO/MD. This might hurt optimizations though, it - isn't clear if it is wise. And it might not work in all cases. We - could solve the DImode LO reg problem by using a multiply, just like - reload_{in,out}si. We could solve the SImode/HImode HI reg problem - by using divide instructions. divu puts the remainder in the HI - reg, so doing a divide by -1 will move the value in the HI reg for - all values except -1. We could handle that case by using a signed - divide, e.g. -1 / 2 (or maybe 1 / -2?). We'd have to emit a - compare/branch to test the input value to see which instruction we - need to use. This gets pretty messy, but it is feasible. */ - -#define REGISTER_MOVE_COST(MODE, FROM, TO) \ - ((FROM) == M16_REGS && GR_REG_CLASS_P (TO) ? 2 \ - : (FROM) == M16_NA_REGS && GR_REG_CLASS_P (TO) ? 2 \ - : GR_REG_CLASS_P (FROM) && (TO) == M16_REGS ? 2 \ - : GR_REG_CLASS_P (FROM) && (TO) == M16_NA_REGS ? 2 \ - : GR_REG_CLASS_P (FROM) && GR_REG_CLASS_P (TO) ? (TARGET_MIPS16 ? 4 : 2) \ - : (FROM) == FP_REGS && (TO) == FP_REGS ? 2 \ - : GR_REG_CLASS_P (FROM) && (TO) == FP_REGS ? 4 \ - : (FROM) == FP_REGS && GR_REG_CLASS_P (TO) ? 4 \ - : (((FROM) == HI_REG || (FROM) == LO_REG \ - || (FROM) == MD_REGS || (FROM) == HILO_REG) \ - && GR_REG_CLASS_P (TO)) ? (TARGET_MIPS16 ? 12 : 6) \ - : (((TO) == HI_REG || (TO) == LO_REG \ - || (TO) == MD_REGS || (TO) == HILO_REG) \ - && GR_REG_CLASS_P (FROM)) ? (TARGET_MIPS16 ? 12 : 6) \ - : (FROM) == ST_REGS && GR_REG_CLASS_P (TO) ? 4 \ - : (FROM) == FP_REGS && (TO) == ST_REGS ? 8 \ - : 12) + not allow such copying. */ + +#define REGISTER_MOVE_COST(MODE, FROM, TO) \ + mips_register_move_cost (MODE, FROM, TO) /* ??? Fix this to be right for the R8000. */ #define MEMORY_MOVE_COST(MODE,CLASS,TO_P) \ @@ -4201,6 +4268,106 @@ while (0) &mips_reg_names[73][0], \ &mips_reg_names[74][0], \ &mips_reg_names[75][0], \ + &mips_reg_names[76][0], \ + &mips_reg_names[77][0], \ + &mips_reg_names[78][0], \ + &mips_reg_names[79][0], \ + &mips_reg_names[80][0], \ + &mips_reg_names[81][0], \ + &mips_reg_names[82][0], \ + &mips_reg_names[83][0], \ + &mips_reg_names[84][0], \ + &mips_reg_names[85][0], \ + &mips_reg_names[86][0], \ + &mips_reg_names[87][0], \ + &mips_reg_names[88][0], \ + &mips_reg_names[89][0], \ + &mips_reg_names[90][0], \ + &mips_reg_names[91][0], \ + &mips_reg_names[92][0], \ + &mips_reg_names[93][0], \ + &mips_reg_names[94][0], \ + &mips_reg_names[95][0], \ + &mips_reg_names[96][0], \ + &mips_reg_names[97][0], \ + &mips_reg_names[98][0], \ + &mips_reg_names[99][0], \ + &mips_reg_names[100][0], \ + &mips_reg_names[101][0], \ + &mips_reg_names[102][0], \ + &mips_reg_names[103][0], \ + &mips_reg_names[104][0], \ + &mips_reg_names[105][0], \ + &mips_reg_names[106][0], \ + &mips_reg_names[107][0], \ + &mips_reg_names[108][0], \ + &mips_reg_names[109][0], \ + &mips_reg_names[110][0], \ + &mips_reg_names[111][0], \ + &mips_reg_names[112][0], \ + &mips_reg_names[113][0], \ + &mips_reg_names[114][0], \ + &mips_reg_names[115][0], \ + &mips_reg_names[116][0], \ + &mips_reg_names[117][0], \ + &mips_reg_names[118][0], \ + &mips_reg_names[119][0], \ + &mips_reg_names[120][0], \ + &mips_reg_names[121][0], \ + &mips_reg_names[122][0], \ + &mips_reg_names[123][0], \ + &mips_reg_names[124][0], \ + &mips_reg_names[125][0], \ + &mips_reg_names[126][0], \ + &mips_reg_names[127][0], \ + &mips_reg_names[128][0], \ + &mips_reg_names[129][0], \ + &mips_reg_names[130][0], \ + &mips_reg_names[131][0], \ + &mips_reg_names[132][0], \ + &mips_reg_names[133][0], \ + &mips_reg_names[134][0], \ + &mips_reg_names[135][0], \ + &mips_reg_names[136][0], \ + &mips_reg_names[137][0], \ + &mips_reg_names[138][0], \ + &mips_reg_names[139][0], \ + &mips_reg_names[140][0], \ + &mips_reg_names[141][0], \ + &mips_reg_names[142][0], \ + &mips_reg_names[143][0], \ + &mips_reg_names[144][0], \ + &mips_reg_names[145][0], \ + &mips_reg_names[146][0], \ + &mips_reg_names[147][0], \ + &mips_reg_names[148][0], \ + &mips_reg_names[149][0], \ + &mips_reg_names[150][0], \ + &mips_reg_names[151][0], \ + &mips_reg_names[152][0], \ + &mips_reg_names[153][0], \ + &mips_reg_names[154][0], \ + &mips_reg_names[155][0], \ + &mips_reg_names[156][0], \ + &mips_reg_names[157][0], \ + &mips_reg_names[158][0], \ + &mips_reg_names[159][0], \ + &mips_reg_names[160][0], \ + &mips_reg_names[161][0], \ + &mips_reg_names[162][0], \ + &mips_reg_names[163][0], \ + &mips_reg_names[164][0], \ + &mips_reg_names[165][0], \ + &mips_reg_names[166][0], \ + &mips_reg_names[167][0], \ + &mips_reg_names[168][0], \ + &mips_reg_names[169][0], \ + &mips_reg_names[170][0], \ + &mips_reg_names[171][0], \ + &mips_reg_names[172][0], \ + &mips_reg_names[173][0], \ + &mips_reg_names[174][0], \ + &mips_reg_names[175][0] \ } /* print-rtl.c can't use REGISTER_NAMES, since it depends on mips.c. @@ -4216,7 +4383,19 @@ while (0) "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", \ "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31", \ "hi", "lo", "accum","$fcc0","$fcc1","$fcc2","$fcc3","$fcc4", \ - "$fcc5","$fcc6","$fcc7","$rap" \ + "$fcc5","$fcc6","$fcc7","$rap", "", "", "", "", \ + "$c0r0", "$c0r1", "$c0r2", "$c0r3", "$c0r4", "$c0r5", "$c0r6", "$c0r7",\ + "$c0r8", "$c0r9", "$c0r10","$c0r11","$c0r12","$c0r13","$c0r14","$c0r15",\ + "$c0r16","$c0r17","$c0r18","$c0r19","$c0r20","$c0r21","$c0r22","$c0r23",\ + "$c0r24","$c0r25","$c0r26","$c0r27","$c0r28","$c0r29","$c0r30","$c0r31",\ + "$c2r0", "$c2r1", "$c2r2", "$c2r3", "$c2r4", "$c2r5", "$c2r6", "$c2r7",\ + "$c2r8", "$c2r9", "$c2r10","$c2r11","$c2r12","$c2r13","$c2r14","$c2r15",\ + "$c2r16","$c2r17","$c2r18","$c2r19","$c2r20","$c2r21","$c2r22","$c2r23",\ + "$c2r24","$c2r25","$c2r26","$c2r27","$c2r28","$c2r29","$c2r30","$c2r31",\ + "$c3r0", "$c3r1", "$c3r2", "$c3r3", "$c3r4", "$c3r5", "$c3r6", "$c3r7",\ + "$c3r8", "$c3r9", "$c3r10","$c3r11","$c3r12","$c3r13","$c3r14","$c3r15",\ + "$c3r16","$c3r17","$c3r18","$c3r19","$c3r20","$c3r21","$c3r22","$c3r23",\ + "$c3r24","$c3r25","$c3r26","$c3r27","$c3r28","$c3r29","$c3r30","$c3r31"\ } /* If defined, a C initializer for an array of structures @@ -4296,8 +4475,14 @@ while (0) { "ra", 31 + GP_REG_FIRST }, \ { "$sp", 29 + GP_REG_FIRST }, \ { "$fp", 30 + GP_REG_FIRST } \ + ALL_COP_ADDITIONAL_REGISTER_NAMES \ } +/* This is meant to be redefined in the host dependent files. It is a + set of alternative names and regnums for mips coprocessors. */ + +#define ALL_COP_ADDITIONAL_REGISTER_NAMES + /* A C compound statement to output to stdio stream STREAM the assembler syntax for an instruction operand X. X is an RTL expression. diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index 34566ff..2229f55 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -5092,17 +5092,17 @@ move\\t%0,%z4\\n\\ (set_attr "length" "4,8")]) (define_insn "movdi_internal" - [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,R,o,*x,*d,*x") - (match_operand:DI 1 "general_operand" "d,iF,R,o,d,d,J,*x,*d"))] + [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,R,o,*x,*d,*x,*B*C*D,*B*C*D,*B*C*D,*d,*m,*R") + (match_operand:DI 1 "general_operand" "d,iF,R,o,d,d,J,*x,*d,*d,*m,*R,*B*C*D,*B*C*D,*B*C*D"))] "!TARGET_64BIT && !TARGET_MIPS16 && (register_operand (operands[0], DImode) || register_operand (operands[1], DImode) || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0) || operands[1] == CONST0_RTX (DImode))" "* return mips_move_2words (operands, insn); " - [(set_attr "type" "move,arith,load,load,store,store,hilo,hilo,hilo") + [(set_attr "type" "move,arith,load,load,store,store,hilo,hilo,hilo,xfer,load,load,xfer,store,store") (set_attr "mode" "DI") - (set_attr "length" "8,16,8,16,8,16,8,8,8")]) + (set_attr "length" "8,16,8,16,8,16,8,8,8,8,8,8,8,8,8")]) (define_insn "" [(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,R,To,*d") @@ -5128,17 +5128,17 @@ move\\t%0,%z4\\n\\ "") (define_insn "movdi_internal2" - [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*x,*d,*x,*a") - (match_operand:DI 1 "movdi_operand" "d,S,IKL,Mnis,R,m,dJ,dJ,J,*x,*d,*J"))] + [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*x,*d,*x,*a,*B*C*D,*B*C*D,*B*C*D,*d,*m,*R") + (match_operand:DI 1 "movdi_operand" "d,S,IKL,Mnis,R,m,dJ,dJ,J,*x,*d,*J,*d,*m,*R,*B*C*D,*B*C*D,*B*C*D"))] "TARGET_64BIT && !TARGET_MIPS16 && (register_operand (operands[0], DImode) || se_register_operand (operands[1], DImode) || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0) || operands[1] == CONST0_RTX (DImode))" "* return mips_move_2words (operands, insn); " - [(set_attr "type" "move,load,arith,arith,load,load,store,store,hilo,hilo,hilo,hilo") + [(set_attr "type" "move,load,arith,arith,load,load,store,store,hilo,hilo,hilo,hilo,xfer,load,load,xfer,store,store") (set_attr "mode" "DI") - (set_attr "length" "4,8,4,8,4,8,4,8,4,4,4,8")]) + (set_attr "length" "4,8,4,8,4,8,4,8,4,4,4,8,8,8,8,8,8,8")]) (define_insn "" [(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,d,R,m,*d") @@ -5524,28 +5524,28 @@ move\\t%0,%z4\\n\\ ;; in FP registers (off by default, use -mdebugh to enable). (define_insn "movsi_internal1" - [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*d,*f*z,*f,*f,*f,*R,*m,*x,*x,*d,*d") - (match_operand:SI 1 "move_operand" "d,S,IKL,Mnis,R,m,dJ,dJ,*f*z,*d,*f,*R,*m,*f,*f,J,*d,*x,*a"))] + [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*d,*f*z,*f,*f,*f,*R,*m,*x,*x,*d,*d,*B*C*D,*B*C*D,*B*C*D,*d,*m,*R") + (match_operand:SI 1 "move_operand" "d,S,IKL,Mnis,R,m,dJ,dJ,*f*z,*d,*f,*R,*m,*f,*f,J,*d,*x,*a,*d,*m,*R,*B*C*D,*B*C*D,*B*C*D"))] "TARGET_DEBUG_H_MODE && !TARGET_MIPS16 && (register_operand (operands[0], SImode) || register_operand (operands[1], SImode) || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))" "* return mips_move_1word (operands, insn, FALSE);" - [(set_attr "type" "move,load,arith,arith,load,load,store,store,xfer,xfer,move,load,load,store,store,hilo,hilo,hilo,hilo") + [(set_attr "type" "move,load,arith,arith,load,load,store,store,xfer,xfer,move,load,load,store,store,hilo,hilo,hilo,hilo,xfer,load,load,xfer,store,store") (set_attr "mode" "SI") - (set_attr "length" "4,8,4,8,4,8,4,8,4,4,4,4,8,4,8,4,4,4,4")]) + (set_attr "length" "4,8,4,8,4,8,4,8,4,4,4,4,8,4,8,4,4,4,4,4,4,8,4,4,8")]) (define_insn "movsi_internal2" - [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*d,*z,*x,*d,*x,*d") - (match_operand:SI 1 "move_operand" "d,S,IKL,Mnis,R,m,dJ,dJ,*z,*d,J,*x,*d,*a"))] + [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*d,*z,*x,*d,*x,*d,*B*C*D,*B*C*D,*B*C*D,*d,*m,*R") + (match_operand:SI 1 "move_operand" "d,S,IKL,Mnis,R,m,dJ,dJ,*z,*d,J,*x,*d,*a,*d,*m,*R,*B*C*D,*B*C*D,*B*C*D"))] "!TARGET_DEBUG_H_MODE && !TARGET_MIPS16 && (register_operand (operands[0], SImode) || register_operand (operands[1], SImode) || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))" "* return mips_move_1word (operands, insn, FALSE);" - [(set_attr "type" "move,load,arith,arith,load,load,store,store,xfer,xfer,hilo,hilo,hilo,hilo") + [(set_attr "type" "move,load,arith,arith,load,load,store,store,xfer,xfer,hilo,hilo,hilo,hilo,xfer,load,load,xfer,store,store") (set_attr "mode" "SI") - (set_attr "length" "4,8,4,8,4,8,4,8,4,4,4,4,4,4")]) + (set_attr "length" "4,8,4,8,4,8,4,8,4,4,4,4,4,4,4,4,8,4,4,8")]) ;; This is the mips16 movsi instruction. We accept a small integer as ;; the source if the destination is a GP memory reference. This is diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index c566c29..f3243b2 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -49,6 +49,7 @@ through the macros defined in the @file{.h} file. * Floating Point:: Handling floating point for cross-compilers. * Mode Switching:: Insertion of mode-switching instructions. * Target Attributes:: Defining target-specific uses of @code{__attribute__}. +* MIPS Coprocessors:: MIPS coprocessor support and how to customize it. * Misc:: Everything else. @end menu @@ -8039,6 +8040,50 @@ attributes, @code{false} otherwise. By default, if a function has a target specific attribute attached to it, it will not be inlined. @end deftypefn +@node MIPS Coprocessors +@section Defining coprocessor specifics for MIPS targets. +@cindex MIPS coprocessor-definition macros + +The MIPS specification allows MIPS implementations to have as many as 4 +coprocessors, each with as many as 32 private registers. gcc supports +accessing these registers and transferring values between the registers +and memory using asm-ized variables. For example: + +@smallexample + register unsigned int cp0count asm ("c0r1"); + unsigned int d; + + d = cp0count + 3; +@end smallexample + +(``c0r1'' is the default name of register 1 in coprocessor 0; alternate +names may be added as described below, or the default names may be +overridden entirely in @code{SUBTARGET_CONDITIONAL_REGISTER_USAGE}.) + +Coprocessor registers are assumed to be epilogue-used; sets to them will +be preserved even if it does not appear that the register is used again +later in the function. + +Another note: according to the MIPS spec, coprocessor 1 (if present) is +the FPU. One accesses COP1 registers through standard mips +floating-point support; they are not included in this mechanism. + +There is one macro used in defining the MIPS coprocessor interface which +you may want to override in subtargets; it is described below. + +@table @code + +@item ALL_COP_ADDITIONAL_REGISTER_NAMES +@findex ALL_COP_ADDITIONAL_REGISTER_NAMES +A comma-separated list (with leading comma) of pairs describing the +alternate names of coprocessor registers. The format of each entry should be +@smallexample +@{ @var{alternatename}, @var{register_number}@} +@end smallexample +Default: empty. + +@end table + @node Misc @section Miscellaneous Parameters @cindex parameters, miscellaneous diff --git a/gcc/testsuite/gcc.c-torture/compile/mipscop-1.c b/gcc/testsuite/gcc.c-torture/compile/mipscop-1.c new file mode 100644 index 0000000..13be514 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/mipscop-1.c @@ -0,0 +1,10 @@ +register unsigned int cp0count asm ("$c0r1"); + +int +main (int argc, char *argv[]) +{ + unsigned int d; + + d = cp0count + 3; + printf ("%d\n", d); +} diff --git a/gcc/testsuite/gcc.c-torture/compile/mipscop-1.x b/gcc/testsuite/gcc.c-torture/compile/mipscop-1.x new file mode 100644 index 0000000..3d780ad --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/mipscop-1.x @@ -0,0 +1,8 @@ +global target_triplet + +if { ![istarget "*mips*"] } { + return 1 +} + +return 0 + diff --git a/gcc/testsuite/gcc.c-torture/compile/mipscop-2.c b/gcc/testsuite/gcc.c-torture/compile/mipscop-2.c new file mode 100644 index 0000000..88e95db --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/mipscop-2.c @@ -0,0 +1,16 @@ +register unsigned int c3r1 asm ("$c3r1"); + +extern unsigned int b, c; + +void +foo () +{ + unsigned int a, d; + + c3r1 = a; + b = c3r1; + + c3r1 = c; + d = c3r1; + printf ("%d\n", d); +} diff --git a/gcc/testsuite/gcc.c-torture/compile/mipscop-2.x b/gcc/testsuite/gcc.c-torture/compile/mipscop-2.x new file mode 100644 index 0000000..3d780ad --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/mipscop-2.x @@ -0,0 +1,8 @@ +global target_triplet + +if { ![istarget "*mips*"] } { + return 1 +} + +return 0 + diff --git a/gcc/testsuite/gcc.c-torture/compile/mipscop-3.c b/gcc/testsuite/gcc.c-torture/compile/mipscop-3.c new file mode 100644 index 0000000..eb602c8 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/mipscop-3.c @@ -0,0 +1,16 @@ +register unsigned int c3r1 asm ("$c3r1"), c3r2 asm ("$c3r2"); + +extern unsigned int b, c; + +void +foo () +{ + unsigned int a, d; + + c3r1 = a; + b = c3r1; + + c3r2 = c; + d = c3r1; + printf ("%d\n", d); +} diff --git a/gcc/testsuite/gcc.c-torture/compile/mipscop-3.x b/gcc/testsuite/gcc.c-torture/compile/mipscop-3.x new file mode 100644 index 0000000..3d780ad --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/mipscop-3.x @@ -0,0 +1,8 @@ +global target_triplet + +if { ![istarget "*mips*"] } { + return 1 +} + +return 0 + diff --git a/gcc/testsuite/gcc.c-torture/compile/mipscop-4.c b/gcc/testsuite/gcc.c-torture/compile/mipscop-4.c new file mode 100644 index 0000000..368db5e --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/mipscop-4.c @@ -0,0 +1,16 @@ +register unsigned long c3r1 asm ("$c3r1"), c3r2 asm ("$c3r2"); + +extern unsigned long b, c; + +void +foo () +{ + unsigned long a, d; + + c3r1 = a; + b = c3r1; + + c3r2 = c; + d = c3r1; + printf ("%d\n", d); +} diff --git a/gcc/testsuite/gcc.c-torture/compile/mipscop-4.x b/gcc/testsuite/gcc.c-torture/compile/mipscop-4.x new file mode 100644 index 0000000..3d780ad --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/mipscop-4.x @@ -0,0 +1,8 @@ +global target_triplet + +if { ![istarget "*mips*"] } { + return 1 +} + +return 0 + -- 2.7.4