diff options
author | hiller <hiller@138bc75d-0d04-0410-961f-82ee72b054a4> | 2002-04-25 19:31:45 +0000 |
---|---|---|
committer | hiller <hiller@138bc75d-0d04-0410-961f-82ee72b054a4> | 2002-04-25 19:31:45 +0000 |
commit | 8d85666fc0908fb696e383b2939f32f162f2b540 (patch) | |
tree | 3f73c185f3047203d3682074bdd5aa45213cb02e /gcc/config/mips/mips.c | |
parent | dc600c9e677e39d5cf78bfdf4678bb74d0e5cc25 (diff) | |
download | gcc-8d85666fc0908fb696e383b2939f32f162f2b540.tar.gz |
2002-04-24 Matt Hiller <hiller@redhat.com>
* 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 <hiller@redhat.com>
* 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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@52765 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/mips/mips.c')
-rw-r--r-- | gcc/config/mips/mips.c | 285 |
1 files changed, 281 insertions, 4 deletions
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 0da1adb8720..a02dc6a42a0 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. */ |