From 147255d877091f864506da47ae1ff766725bfe06 Mon Sep 17 00:00:00 2001 From: Jim Wilson Date: Thu, 13 Jan 1994 15:51:01 -0800 Subject: [PATCH] (dfhigh, dflow, sfhigh, sflow): New variables. (mips_sw_reg_names): Consistently use $ as name prefix. (large_int): Handle 64 bit constants. (reg_or_0_operand, mips_const_double_ok): Don't examine CONST_DOUBLE internals. (mips_const_double_ok): Use REAL_VALUE_* macros. (simple_memory_operand): Add 64 bit support. Only test TARGET_GP_OPT to determine if doing gp optimizations. Pass address not MEM to eliminate_constant_term. Use SMALL_INT. (mips_fill_delay_slot): Add 64 bit support. (mips_move_1word): Add 64 bit support. Don't examine CONST_DOUBLE internals. (mips_move_2words): Likewise. (mips_address_cost): Pass address not MEM to eliminate_constant_term. Use SMALL_INT. (gen_int_relational): New variable mode. Add 64 bit support. (gen_conditional_branch): Add 64 bit support. (block_move_load_store, block_move_loop, block_move_call, expand_block_move, output_block_move, function_arg_advance, function_arg, function_arg_partial_nregs): Likewise. (override_options): Clear MASK_GPOPT if threshold is zero or negative. Set MASK_GPOPT if optimizing. Set mips_isa from -misa= option, else from MIPS_ISA_DEFAULT if defined, else to 1. Make default cpu depend on isa. Add cpus r4400, r4600, orion. Rewrite TARGET_NAME_REGS support. Initialize dfhigh, dflow, sfhigh, sflow. Add 64 bit support. (print_operand): Use REAL_VALUE_* macros. (mips_output_external): Don't depend on mips_section_threshold. (make_temp_file): Define P_tmpdir when __MSDOS__. Malloc filename string. Don't unlink temp file when __MSDOS__. (mips_asm_file_start): Delete TARGET_NAME_REGS support. (mips_asm_file_end): Unlike temp file when __MSDOS__. (mips_declare_object): Don't test mips_sections_threshold. (compute_frame_size, save_restore_insns, function_prologue, mips_expand_prologue, function_epilogue, mips_expand_epilogue): Add 64 bit support. (function_epilogue): Correctly output `#' before .set volatile. From-SVN: r6391 --- gcc/config/mips/mips.c | 839 +++++++++++++++++++++++++++++------------ 1 file changed, 606 insertions(+), 233 deletions(-) diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index b7a53c2b15b..04097ef40f5 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -1,7 +1,9 @@ /* Subroutines for insn-output.c for MIPS Contributed by A. Lichnewsky, lich@inria.inria.fr. Changes by Michael Meissner, meissner@osf.org. - Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc. + 64 bit r4000 support by Ian Lance Taylor, ian@cygnus.com, and + Brendan Eich, brendan@microunity.com. + Copyright (C) 1989, 1990, 1991, 1993 Free Software Foundation, Inc. This file is part of GNU CC. @@ -19,6 +21,10 @@ You should have received a copy of the GNU General Public License along with GNU CC; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* ??? The TARGET_FP_CALL_32 macros are intended to simulate a 32 bit + calling convention in 64 bit mode. It doesn't work though, and should + be replaced with something better designed. */ + #include "config.h" #include "rtl.h" #include "regs.h" @@ -193,6 +199,11 @@ char *mips_isa_string; /* for -mips{1,2,3} */ /* Generating calls to position independent functions? */ enum mips_abicalls_type mips_abicalls; +/* High and low marks for floating point values which we will accept + as legitimate constants for LEGITIMATE_CONSTANT_P. These are + initialized in override_options. */ +REAL_VALUE_TYPE dfhigh, dflow, sfhigh, sflow; + /* Array to RTX class classification. At present, we care about whether the operator is an add-type operator, or a divide/modulus, and if divide/modulus, whether it is unsigned. This is for the @@ -244,10 +255,10 @@ char mips_reg_names[][8] = char mips_sw_reg_names[][8] = { - "$0", "at", "v0", "v1", "a0", "a1", "a2", "a3", - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", - "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", - "t8", "t9", "k0", "k1", "gp", "sp", "$fp", "ra", + "$zero","$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3", + "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", + "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7", + "$t8", "$t9", "$k0", "$k1", "$gp", "$sp", "$fp", "$ra", "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", @@ -419,7 +430,9 @@ large_int (op, mode) if (((unsigned long)(value + 32768)) <= 32767) /* subu reg,$r0,value */ return FALSE; - if ((value & 0xffff0000) == value) /* lui reg,value>>16 */ + if ((value & 0x0000ffff) == 0 /* lui reg,value>>16 */ + && ((value & ~2147483647) == 0 /* signed value */ + || (value & ~2147483647) == ~2147483647)) return FALSE; return TRUE; @@ -441,7 +454,7 @@ reg_or_0_operand (op, mode) return (INTVAL (op) == 0); case CONST_DOUBLE: - if (CONST_DOUBLE_HIGH (op) != 0 || CONST_DOUBLE_LOW (op) != 0) + if (op != CONST0_RTX (mode)) return FALSE; return TRUE; @@ -493,35 +506,34 @@ mips_const_double_ok (op, mode) if (mode != SFmode && mode != DFmode) return FALSE; - if (CONST_DOUBLE_HIGH (op) == 0 && CONST_DOUBLE_LOW (op) == 0) + if (op == CONST0_RTX (mode)) return TRUE; -#if HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT if (TARGET_MIPS_AS) /* gas doesn't like li.d/li.s yet */ { - union { double d; int i[2]; } u; - double d; - - u.i[0] = CONST_DOUBLE_LOW (op); - u.i[1] = CONST_DOUBLE_HIGH (op); - d = u.d; - - if (d != d) - return FALSE; /* NAN */ + REAL_VALUE_TYPE d; - if (d < 0.0) - d = - d; + REAL_VALUE_FROM_CONST_DOUBLE (d, op); - /* Rather than trying to get the accuracy down to the last bit, - just use approximate ranges. */ + if (REAL_VALUE_ISNAN (d)) + return FALSE; - if (mode == DFmode && d > 1.0e-300 && d < 1.0e300) - return TRUE; + if (REAL_VALUE_NEGATIVE (d)) + d = REAL_VALUE_NEGATE (d); - if (mode == SFmode && d > 1.0e-38 && d < 1.0e+38) - return TRUE; + if (mode == DFmode) + { + if (REAL_VALUES_LESS (d, dfhigh) + && REAL_VALUES_LESS (dflow, d)) + return TRUE; + } + else + { + if (REAL_VALUES_LESS (d, sfhigh) + && REAL_VALUES_LESS (sflow, d)) + return TRUE; + } } -#endif return FALSE; } @@ -541,7 +553,7 @@ simple_memory_operand (op, mode) return FALSE; /* dword operations really put out 2 instructions, so eliminate them. */ - if (GET_MODE_SIZE (GET_MODE (op)) > (HAVE_64BIT_P () ? 8 : 4)) + if (GET_MODE_SIZE (GET_MODE (op)) > UNITS_PER_WORD) return FALSE; /* Decode the address now. */ @@ -585,17 +597,17 @@ simple_memory_operand (op, mode) case CONST: /* If -G 0, we can never have a GP relative memory operation. Also, save some time if not optimizing. */ - if (mips_section_threshold == 0 || !optimize || !TARGET_GP_OPT) + if (!TARGET_GP_OPT) return FALSE; { rtx offset = const0_rtx; - addr = eliminate_constant_term (addr, &offset); + addr = eliminate_constant_term (XEXP (addr, 0), &offset); if (GET_CODE (op) != SYMBOL_REF) return FALSE; /* let's be paranoid.... */ - if (INTVAL (offset) < 0 || INTVAL (offset) > 0xffff) + if (! SMALL_INT (offset)) return FALSE; } /* fall through */ @@ -778,10 +790,12 @@ mips_fill_delay_slot (ret, type, operands, cur_insn) mode = GET_MODE (set_reg); dslots_number_nops = num_nops; - mips_load_reg = set_reg; - mips_load_reg2 = (mode == DImode || mode == DFmode) - ? gen_rtx (REG, SImode, REGNO (set_reg) + 1) - : (rtx)0; + mips_load_reg = set_reg; + if (GET_MODE_SIZE (mode) + > (FP_REG_P (set_reg) ? UNITS_PER_FPREG : UNITS_PER_WORD)) + mips_load_reg2 = gen_rtx (REG, SImode, REGNO (set_reg) + 1); + else + mips_load_reg2 = 0; if (type == DELAY_HILO) { @@ -1028,11 +1042,22 @@ mips_move_1word (operands, insn, unsignedp) target, so zero/sign extend can use this code as well. */ switch (GET_MODE (op1)) { - default: break; - case SFmode: ret = "lw\t%0,%1"; break; - case SImode: ret = "lw\t%0,%1"; break; - case HImode: ret = (unsignedp) ? "lhu\t%0,%1" : "lh\t%0,%1"; break; - case QImode: ret = (unsignedp) ? "lbu\t%0,%1" : "lb\t%0,%1"; break; + default: + break; + case SFmode: + ret = "lw\t%0,%1"; + break; + case SImode: + ret = ((unsignedp && TARGET_64BIT) + ? "lwu\t%0,%1" + : "lw\t%0,%1"); + break; + case HImode: + ret = (unsignedp) ? "lhu\t%0,%1" : "lh\t%0,%1"; + break; + case QImode: + ret = (unsignedp) ? "lbu\t%0,%1" : "lb\t%0,%1"; + break; } } @@ -1070,7 +1095,7 @@ mips_move_1word (operands, insn, unsignedp) else if (code1 == CONST_DOUBLE && mode == SFmode) { - if (CONST_DOUBLE_HIGH (op1) == 0 && CONST_DOUBLE_LOW (op1) == 0) + if (op1 == CONST0_RTX (SFmode)) { if (GP_REG_P (regno0)) ret = "move\t%0,%."; @@ -1116,15 +1141,22 @@ mips_move_1word (operands, insn, unsignedp) if (INTVAL (offset) == 0) { delay = DELAY_LOAD; - ret = "lw\t%0,%2"; + ret = (unsignedp && TARGET_64BIT + ? "lwu\t%0,%2" + : "lw\t%0,%2"); } else { dslots_load_total++; operands[3] = offset; - ret = (SMALL_INT (offset)) - ? "lw\t%0,%2%#\n\tadd\t%0,%0,%3" - : "lw\t%0,%2%#\n\t%[li\t%@,%3\n\tadd\t%0,%0,%@%]"; + if (unsignedp && TARGET_64BIT) + ret = (SMALL_INT (offset)) + ? "lwu\t%0,%2%#\n\tadd\t%0,%0,%3" + : "lwu\t%0,%2%#\n\t%[li\t%@,%3\n\tadd\t%0,%0,%@%]"; + else + ret = (SMALL_INT (offset)) + ? "lw\t%0,%2%#\n\tadd\t%0,%0,%3" + : "lw\t%0,%2%#\n\t%[li\t%@,%3\n\tadd\t%0,%0,%@%]"; } } } @@ -1191,7 +1223,7 @@ mips_move_1word (operands, insn, unsignedp) } } - else if (code1 == CONST_DOUBLE && CONST_DOUBLE_HIGH (op1) == 0 && CONST_DOUBLE_LOW (op1) == 0) + else if (code1 == CONST_DOUBLE && op1 == CONST0_RTX (mode)) { switch (mode) { @@ -1278,32 +1310,57 @@ mips_move_2words (operands, insn) else { delay = DELAY_LOAD; - ret = (TARGET_FLOAT64) - ? "dmtc1\t%1,%0" - : "mtc1\t%L1,%0\n\tmtc1\t%M1,%D0"; + if (TARGET_64BIT) + { +#ifdef TARGET_FP_CALL_32 + if (FP_CALL_GP_REG_P (regno1)) + ret = "dsll\t%1,32\n\tor\t%1,%D1\n\tdmtc1\t%1,%0"; + else +#endif + ret = "dmtc1\t%1,%0"; + } + else + ret = "mtc1\t%L1,%0\n\tmtc1\t%M1,%D0"; } } else if (FP_REG_P (regno1)) { delay = DELAY_LOAD; - ret = (TARGET_FLOAT64) - ? "dmfc1\t%0,%1" - : "mfc1\t%L0,%1\n\tmfc1\t%M0,%D1"; + if (TARGET_64BIT) + { +#ifdef TARGET_FP_CALL_32 + if (FP_CALL_GP_REG_P (regno0)) + ret = "dmfc1\t%0,%1\n\tmfc1\t%D0,%1\n\tdsrl\t%0,32"; + else +#endif + ret = "dmfc1\t%0,%1"; + } + else + ret = "mfc1\t%L0,%1\n\tmfc1\t%M0,%D1"; } else if (MD_REG_P (regno0) && GP_REG_P (regno1)) { delay = DELAY_HILO; - ret = "mthi\t%M1\n\tmtlo\t%L1"; + if (TARGET_64BIT) + ret = "mt%0\t%1"; + else + ret = "mthi\t%M1\n\tmtlo\t%L1"; } else if (GP_REG_P (regno0) && MD_REG_P (regno1)) { delay = DELAY_HILO; - ret = "mfhi\t%M0\n\tmflo\t%L0"; + if (TARGET_64BIT) + ret = "mf%1\t%0"; + else + ret = "mfhi\t%M0\n\tmflo\t%L0"; } + else if (TARGET_64BIT) + ret = "move\t%0,%1"; + else if (regno0 != (regno1+1)) ret = "move\t%0,%1\n\tmove\t%D0,%D1"; @@ -1313,14 +1370,22 @@ mips_move_2words (operands, insn) else if (code1 == CONST_DOUBLE) { - if (CONST_DOUBLE_HIGH (op1) != 0 || CONST_DOUBLE_LOW (op1) != 0) + if (op1 != CONST0_RTX (GET_MODE (op1))) { if (GET_MODE (op1) == DFmode) { delay = DELAY_LOAD; - ret = "li.d\t%0,%1"; +#ifdef TARGET_FP_CALL_32 + if (FP_CALL_GP_REG_P (regno0)) + ret = "li.d\t%0,%1\n\tdsll\t%D0,%0,32\n\tdsrl\t%D0,32\n\tdsrl\t%0,32"; + else +#endif + ret = "li.d\t%0,%1"; } + else if (TARGET_64BIT) + ret = "li\t%0,%1"; + else { operands[2] = GEN_INT (CONST_DOUBLE_LOW (op1)); @@ -1332,12 +1397,18 @@ mips_move_2words (operands, insn) else { if (GP_REG_P (regno0)) - ret = "move\t%0,%.\n\tmove\t%D0,%."; + ret = (TARGET_64BIT +#ifdef TARGET_FP_CALL_32 + && ! FP_CALL_GP_REG_P (regno0) +#endif + ) + ? "move\t%0,%." + : "move\t%0,%.\n\tmove\t%D0,%."; else if (FP_REG_P (regno0)) { delay = DELAY_LOAD; - ret = (TARGET_FLOAT64) + ret = (TARGET_64BIT) ? "dmtc1\t%.,%0" : "mtc1\t%.,%0\n\tmtc1\t%.,%D0"; } @@ -1347,12 +1418,14 @@ mips_move_2words (operands, insn) else if (code1 == CONST_INT && INTVAL (op1) == 0) { if (GP_REG_P (regno0)) - ret = "move\t%0,%.\n\tmove\t%D0,%."; + ret = (TARGET_64BIT) + ? "move\t%0,%." + : "move\t%0,%.\n\tmove\t%D0,%."; else if (FP_REG_P (regno0)) { delay = DELAY_LOAD; - ret = (TARGET_FLOAT64) + ret = (TARGET_64BIT) ? "dmtc1\t%.,%0" : "mtc1\t%.,%0\n\tmtc1\t%.,%D0"; } @@ -1360,8 +1433,13 @@ mips_move_2words (operands, insn) else if (code1 == CONST_INT && GET_MODE (op0) == DImode && GP_REG_P (regno0)) { - operands[2] = GEN_INT (INTVAL (operands[1]) >= 0 ? 0 : -1); - ret = "li\t%M0,%2\n\tli\t%L0,%1"; + if (TARGET_64BIT) + ret = "li\t%0,%1"; + else + { + operands[2] = GEN_INT (INTVAL (operands[1]) >= 0 ? 0 : -1); + ret = "li\t%M0,%2\n\tli\t%L0,%1"; + } } else if (code1 == MEM) @@ -1374,6 +1452,21 @@ mips_move_2words (operands, insn) if (FP_REG_P (regno0)) ret = "l.d\t%0,%1"; + else if (TARGET_64BIT) + { +#ifdef TARGET_FP_CALL_32 + if (FP_CALL_GP_REG_P (regno0)) + { + if (offsettable_address_p (FALSE, SImode, op1)) + ret = "lwu\t%0,%1\n\tlwu\t%D0,4+%1"; + else + ret = "ld\t%0,%1\n\tdsll\t%D0,%0,32\n\tdsrl\t%D0,32\n\tdsrl\t%0,32"; + } + else +#endif + ret = "ld\t%0,%1"; + } + else if (offsettable_address_p (1, DFmode, XEXP (op1, 0))) { operands[2] = adj_offsettable_operand (op1, 4); @@ -1393,6 +1486,15 @@ mips_move_2words (operands, insn) ret = volatile_buffer; } } + + else if (code1 == LABEL_REF + || code1 == SYMBOL_REF + || code1 == CONST) + { + if (! TARGET_64BIT) + abort (); + return mips_move_1word (operands, insn, 0); + } } else if (code0 == MEM) @@ -1404,6 +1506,16 @@ mips_move_2words (operands, insn) if (FP_REG_P (regno1)) ret = "s.d\t%1,%0"; + else if (TARGET_64BIT) + { +#ifdef TARGET_FP_CALL_32 + if (FP_CALL_GP_REG_P (regno1)) + ret = "dsll\t%1,32\n\tor\t%1,%D1\n\tsd\t%1,%0"; + else +#endif + ret = "sd\t%1,%0"; + } + else if (offsettable_address_p (1, DFmode, XEXP (op0, 0))) { operands[2] = adj_offsettable_operand (op0, 4); @@ -1411,12 +1523,13 @@ mips_move_2words (operands, insn) } } - else if (code1 == CONST_DOUBLE - && CONST_DOUBLE_HIGH (op1) == 0 - && CONST_DOUBLE_LOW (op1) == 0 - && offsettable_address_p (1, DFmode, XEXP (op0, 0))) + else if (((code1 == CONST_INT && INTVAL (op1) == 0) + || (code1 == CONST_DOUBLE + && op1 == CONST0_RTX (GET_MODE (op1)))) + && (TARGET_64BIT + || offsettable_address_p (1, DFmode, XEXP (op0, 0)))) { - if (TARGET_FLOAT64) + if (TARGET_64BIT) ret = "sd\t%.,%0"; else { @@ -1474,14 +1587,14 @@ mips_address_cost (addr) case CONST: { rtx offset = const0_rtx; - addr = eliminate_constant_term (addr, &offset); + addr = eliminate_constant_term (XEXP (addr, 0), &offset); if (GET_CODE (addr) == LABEL_REF) return 2; if (GET_CODE (addr) != SYMBOL_REF) return 4; - if (INTVAL (offset) < -32768 || INTVAL (offset) > 32767) + if (! SMALL_INT (offset)) return 2; } /* fall through */ @@ -1509,10 +1622,7 @@ mips_address_cost (addr) break; case CONST_INT: - { - int value = INTVAL (plus1); - return (value < -32768 || value > 32767) ? 2 : 1; - } + return (SMALL_INT (plus1) ? 1 : 2); case CONST: case SYMBOL_REF: @@ -1557,7 +1667,24 @@ map_test_to_internal_test (test_code) /* Generate the code to compare two integer values. The return value is: (reg:SI xx) The pseudo register the comparison is in - (rtx)0 No register, generate a simple branch. */ + (rtx)0 No register, generate a simple branch. + + ??? This is called with result nonzero by the Scond patterns in + mips.md. These patterns are called with a target in the mode of + the Scond instruction pattern. Since this must be a constant, we + must use SImode. This means that if RESULT is non-zero, it will + always be an SImode register, even if TARGET_64BIT is true. We + cope with this by calling convert_move rather than emit_move_insn. + This will sometimes lead to an unnecessary extension of the result; + for example: + + long long + foo (long long i) + { + return i < 5; + } + + */ rtx gen_int_relational (test_code, result, cmp0, cmp1, p_invert) @@ -1594,6 +1721,7 @@ gen_int_relational (test_code, result, cmp0, cmp1, p_invert) }; enum internal_test test; + enum machine_mode mode; struct cmp_info *p_info; int branch_p; int eqne_p; @@ -1608,6 +1736,10 @@ gen_int_relational (test_code, result, cmp0, cmp1, p_invert) p_info = &info[ (int)test ]; eqne_p = (p_info->test_code == XOR); + mode = GET_MODE (cmp0); + if (mode == VOIDmode) + mode = GET_MODE (cmp1); + /* Eliminate simple branches */ branch_p = (result == (rtx)0); if (branch_p) @@ -1624,18 +1756,28 @@ gen_int_relational (test_code, result, cmp0, cmp1, p_invert) } /* allocate a pseudo to calculate the value in. */ - result = gen_reg_rtx (SImode); + result = gen_reg_rtx (mode); } /* Make sure we can handle any constants given to us. */ if (GET_CODE (cmp0) == CONST_INT) - cmp0 = force_reg (SImode, cmp0); + cmp0 = force_reg (mode, cmp0); if (GET_CODE (cmp1) == CONST_INT) { HOST_WIDE_INT value = INTVAL (cmp1); - if (value < p_info->const_low || value > p_info->const_high) - cmp1 = force_reg (SImode, cmp1); + if (value < p_info->const_low + || value > p_info->const_high + /* ??? Why? And why wasn't the similar code below modified too? */ + || (TARGET_64BIT + && HOST_BITS_PER_WIDE_INT < 64 + && p_info->const_add != 0 + && ((p_info->unsignedp + ? ((unsigned HOST_WIDE_INT) (value + p_info->const_add) + > INTVAL (cmp1)) + : (value + p_info->const_add) > INTVAL (cmp1)) + != (p_info->const_add > 0)))) + cmp1 = force_reg (mode, cmp1); } /* See if we need to invert the result. */ @@ -1685,25 +1827,25 @@ gen_int_relational (test_code, result, cmp0, cmp1, p_invert) reg = cmp0; else { - reg = (invert || eqne_p) ? gen_reg_rtx (SImode) : result; - emit_move_insn (reg, gen_rtx (p_info->test_code, SImode, cmp0, cmp1)); + reg = (invert || eqne_p) ? gen_reg_rtx (mode) : result; + convert_move (reg, gen_rtx (p_info->test_code, mode, cmp0, cmp1), 0); } if (test == ITEST_NE) { - emit_move_insn (result, gen_rtx (GTU, SImode, reg, const0_rtx)); + convert_move (result, gen_rtx (GTU, mode, reg, const0_rtx), 0); invert = FALSE; } else if (test == ITEST_EQ) { - reg2 = (invert) ? gen_reg_rtx (SImode) : result; - emit_move_insn (reg2, gen_rtx (LTU, SImode, reg, const1_rtx)); + reg2 = (invert) ? gen_reg_rtx (mode) : result; + convert_move (reg2, gen_rtx (LTU, mode, reg, const1_rtx), 0); reg = reg2; } if (invert) - emit_move_insn (result, gen_rtx (XOR, SImode, reg, const1_rtx)); + convert_move (result, gen_rtx (XOR, mode, reg, const1_rtx), 0); return result; } @@ -1711,7 +1853,7 @@ gen_int_relational (test_code, result, cmp0, cmp1, p_invert) /* Emit the common code for doing conditional branches. operand[0] is the label to jump to. - The comparison operands are saved away by cmp{si,sf,df}. */ + The comparison operands are saved away by cmp{si,di,sf,df}. */ void gen_conditional_branch (operands, test_code) @@ -1731,6 +1873,18 @@ gen_conditional_branch (operands, test_code) SImode, /* ltu */ SImode, /* leu */ }, + { /* CMP_DI */ + DImode, /* eq */ + DImode, /* ne */ + DImode, /* gt */ + DImode, /* ge */ + DImode, /* lt */ + DImode, /* le */ + DImode, /* gtu */ + DImode, /* geu */ + DImode, /* ltu */ + DImode, /* leu */ + }, { /* CMP_SF */ CC_FPmode, /* eq */ CC_REV_FPmode, /* ne */ @@ -1769,7 +1923,7 @@ gen_conditional_branch (operands, test_code) if (test == ITEST_MAX) { - mode = SImode; + mode = word_mode; goto fail; } @@ -1778,12 +1932,13 @@ gen_conditional_branch (operands, test_code) if (mode == VOIDmode) goto fail; - switch (branch_type) + switch (type) { default: goto fail; case CMP_SI: + case CMP_DI: reg = gen_int_relational (test_code, (rtx)0, cmp0, cmp1, &invert); if (reg != (rtx)0) { @@ -1794,7 +1949,7 @@ gen_conditional_branch (operands, test_code) /* Make sure not non-zero constant if ==/!= */ else if (GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) != 0) - cmp1 = force_reg (SImode, cmp1); + cmp1 = force_reg (mode, cmp1); break; @@ -1831,12 +1986,14 @@ fail: } -#define UNITS_PER_SHORT (SHORT_TYPE_SIZE / BITS_PER_UNIT) - +#if 0 /* Internal code to generate the load and store of one word/short/byte. The load is emitted directly, and the store insn is returned. */ -#if 0 +#define UNITS_PER_MIPS_DWORD 8 +#define UNITS_PER_MIPS_WORD 4 +#define UNITS_PER_MIPS_HWORD 2 + static rtx block_move_load_store (dest_reg, src_reg, p_bytes, p_offset, align, orig_src) rtx src_reg; /* register holding source memory address */ @@ -1862,30 +2019,38 @@ block_move_load_store (dest_reg, src_reg, p_bytes, p_offset, align, orig_src) if (bytes <= 0 || align <= 0) abort (); - if (bytes >= UNITS_PER_WORD && align >= UNITS_PER_WORD) + if (bytes >= UNITS_PER_MIPS_DWORD && align >= UNIS_PER_MIPS_DWORD) + { + mode = DImode; + size = UNITS_PER_MIPS_DWORD; + load_func = gen_movdi; + store_func = gen_movdi; + } + else if (bytes >= UNITS_PER_MIPS_WORD && align >= UNITS_PER_MIPS_WORD) { mode = SImode; - size = UNITS_PER_WORD; + size = UNITS_PER_MIPS_WORD; load_func = gen_movsi; store_func = gen_movsi; } #if 0 /* Don't generate unaligned moves here, rather defer those to the - general movestrsi_internal pattern. */ - else if (bytes >= UNITS_PER_WORD) + general movestrsi_internal pattern. + If this gets commented back in, then should add the dword equivalent. */ + else if (bytes >= UNITS_PER_MIPS_WORD) { mode = SImode; - size = UNITS_PER_WORD; + size = UNITS_PER_MIPS_WORD; load_func = gen_movsi_ulw; store_func = gen_movsi_usw; } #endif - else if (bytes >= UNITS_PER_SHORT && align >= UNITS_PER_SHORT) + else if (bytes >= UNITS_PER_MIPS_SHORT && align >= UNITS_PER_MIPS_SHORT) { mode = HImode; - size = UNITS_PER_SHORT; + size = UNITS_PER_MIPS_SHORT; load_func = gen_movhi; store_func = gen_movhi; } @@ -2007,6 +2172,8 @@ block_move_sequence (dest_reg, src_reg, bytes, align, orig_src) #define MAX_MOVE_REGS 4 #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD) +/* ??? Should add code to use DWORD load/stores. */ + static void block_move_loop (dest_reg, src_reg, bytes, align, orig_src) rtx dest_reg; /* register holding destination address */ @@ -2035,19 +2202,41 @@ block_move_loop (dest_reg, src_reg, bytes, align, orig_src) if (bytes > 0x7fff) { - emit_insn (gen_movsi (final_src, bytes_rtx)); - emit_insn (gen_addsi3 (final_src, final_src, src_reg)); + if (TARGET_LONG64) + { + emit_insn (gen_movdi (final_src, bytes_rtx)); + emit_insn (gen_adddi3 (final_src, final_src, src_reg)); + } + else + { + emit_insn (gen_movsi (final_src, bytes_rtx)); + emit_insn (gen_addsi3 (final_src, final_src, src_reg)); + } } else - emit_insn (gen_addsi3 (final_src, src_reg, bytes_rtx)); + { + if (TARGET_LONG64) + emit_insn (gen_adddi3 (final_src, src_reg, bytes_rtx)); + else + emit_insn (gen_addsi3 (final_src, src_reg, bytes_rtx)); + } emit_label (label); bytes_rtx = GEN_INT (MAX_MOVE_BYTES); emit_insn (gen_movstrsi_internal (dest_mem, src_mem, bytes_rtx, align_rtx)); - emit_insn (gen_addsi3 (src_reg, src_reg, bytes_rtx)); - emit_insn (gen_addsi3 (dest_reg, dest_reg, bytes_rtx)); - emit_insn (gen_cmpsi (src_reg, final_src)); + if (TARGET_LONG64) + { + emit_insn (gen_adddi3 (src_reg, src_reg, bytes_rtx)); + emit_insn (gen_adddi3 (dest_reg, dest_reg, bytes_rtx)); + emit_insn (gen_cmpdi (src_reg, final_src)); + } + else + { + emit_insn (gen_addsi3 (src_reg, src_reg, bytes_rtx)); + emit_insn (gen_addsi3 (dest_reg, dest_reg, bytes_rtx)); + emit_insn (gen_cmpsi (src_reg, final_src)); + } emit_jump_insn (gen_bne (label)); if (leftover) @@ -2065,18 +2254,24 @@ block_move_call (dest_reg, src_reg, bytes_rtx) rtx src_reg; rtx bytes_rtx; { + /* We want to pass the size as Pmode, which will normally be SImode + but will be DImode if we are using 64 bit longs and pointers. */ + if (GET_MODE (bytes_rtx) != VOIDmode + && GET_MODE (bytes_rtx) != Pmode) + bytes_rtx = convert_to_mode (Pmode, bytes_rtx, TRUE); + #ifdef TARGET_MEM_FUNCTIONS emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), 0, VOIDmode, 3, dest_reg, Pmode, src_reg, Pmode, - bytes_rtx, SImode); + bytes_rtx, Pmode); #else emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcopy"), 0, VOIDmode, 3, src_reg, Pmode, dest_reg, Pmode, - bytes_rtx, SImode); + bytes_rtx, Pmode); #endif } @@ -2140,9 +2335,18 @@ expand_block_move (operands) bytes -= leftover; - emit_insn (gen_iorsi3 (temp, src_reg, dest_reg)); - emit_insn (gen_andsi3 (temp, temp, GEN_INT (UNITS_PER_WORD-1))); - emit_insn (gen_cmpsi (temp, const0_rtx)); + if (TARGET_LONG64) + { + emit_insn (gen_iordi3 (temp, src_reg, dest_reg)); + emit_insn (gen_anddi3 (temp, temp, GEN_INT (UNITS_PER_WORD-1))); + emit_insn (gen_cmpdi (temp, const0_rtx)); + } + else + { + emit_insn (gen_iorsi3 (temp, src_reg, dest_reg)); + emit_insn (gen_andsi3 (temp, temp, GEN_INT (UNITS_PER_WORD-1))); + emit_insn (gen_cmpsi (temp, const0_rtx)); + } emit_jump_insn (gen_beq (aligned_label)); /* Unaligned loop. */ @@ -2290,7 +2494,41 @@ output_block_move (insn, operands, num_regs, move_type) { load_store[num].offset = offset; - if (bytes >= UNITS_PER_WORD && align >= UNITS_PER_WORD) + if (TARGET_64BIT && bytes >= 8 && align >= 8) + { + load_store[num].load = "ld\t%0,%1"; + load_store[num].load_nop = "ld\t%0,%1%#"; + load_store[num].store = "sd\t%0,%1"; + load_store[num].last_store = "sd\t%0,%1"; + load_store[num].final = (char *)0; + load_store[num].mode = DImode; + offset += 8; + bytes -= 8; + } + + /* ??? Fails because of a MIPS assembler bug? */ + else if (TARGET_64BIT && bytes >= 8) + { +#if BYTES_BIG_ENDIAN + load_store[num].load = "ldl\t%0,%1\n\tldr\t%0,%2"; + load_store[num].load_nop = "ldl\t%0,%1\n\tldr\t%0,%2%#"; + load_store[num].store = "sdl\t%0,%1\n\tsdr\t%0,%2"; + load_store[num].last_store = "sdr\t%0,%2"; + load_store[num].final = "sdl\t%0,%1"; +#else + load_store[num].load = "ldl\t%0,%2\n\tldr\t%0,%1"; + load_store[num].load_nop = "ldl\t%0,%2\n\tldr\t%0,%1%#"; + load_store[num].store = "sdl\t%0,%2\n\tsdr\t%0,%1"; + load_store[num].last_store = "sdr\t%0,%1"; + load_store[num].final = "sdl\t%0,%2"; +#endif + load_store[num].mode = DImode; + offset += 8; + bytes -= 8; + use_lwl_lwr = TRUE; + } + + else if (bytes >= 4 && align >= 4) { load_store[num].load = "lw\t%0,%1"; load_store[num].load_nop = "lw\t%0,%1%#"; @@ -2298,11 +2536,11 @@ output_block_move (insn, operands, num_regs, move_type) load_store[num].last_store = "sw\t%0,%1"; load_store[num].final = (char *)0; load_store[num].mode = SImode; - offset += UNITS_PER_WORD; - bytes -= UNITS_PER_WORD; + offset += 4; + bytes -= 4; } - else if (bytes >= UNITS_PER_WORD) + else if (bytes >= 4) { #if BYTES_BIG_ENDIAN load_store[num].load = "lwl\t%0,%1\n\tlwr\t%0,%2"; @@ -2318,22 +2556,21 @@ output_block_move (insn, operands, num_regs, move_type) load_store[num].final = "swl\t%0,%2"; #endif load_store[num].mode = SImode; - offset += UNITS_PER_WORD; - bytes -= UNITS_PER_WORD; + offset += 4; + bytes -= 4; use_lwl_lwr = TRUE; } - else if (bytes >= UNITS_PER_SHORT && align >= UNITS_PER_SHORT) + else if (bytes >= 2 && align >= 2) { load_store[num].load = "lh\t%0,%1"; load_store[num].load_nop = "lh\t%0,%1%#"; load_store[num].store = "sh\t%0,%1"; load_store[num].last_store = "sh\t%0,%1"; load_store[num].final = (char *)0; - load_store[num].offset = offset; load_store[num].mode = HImode; - offset += UNITS_PER_SHORT; - bytes -= UNITS_PER_SHORT; + offset += 2; + bytes -= 2; } else @@ -2391,8 +2628,14 @@ output_block_move (insn, operands, num_regs, move_type) plus_constant (src_reg, offset)); if (use_lwl_lwr) - xoperands[2] = gen_rtx (MEM, load_store[i].mode, - plus_constant (src_reg, UNITS_PER_WORD-1+offset)); + { + int extra_offset; + extra_offset = GET_MODE_SIZE (load_store[i].mode) - 1; + xoperands[2] = gen_rtx (MEM, load_store[i].mode, + plus_constant (src_reg, + extra_offset + + offset)); + } output_asm_insn (load_store[i].load, xoperands); } @@ -2409,8 +2652,14 @@ output_block_move (insn, operands, num_regs, move_type) if (use_lwl_lwr) - xoperands[2] = gen_rtx (MEM, load_store[i].mode, - plus_constant (dest_reg, UNITS_PER_WORD-1+offset)); + { + int extra_offset; + extra_offset = GET_MODE_SIZE (load_store[i].mode) - 1; + xoperands[2] = gen_rtx (MEM, load_store[i].mode, + plus_constant (dest_reg, + extra_offset + + offset)); + } if (move_type == BLOCK_MOVE_NORMAL) output_asm_insn (load_store[i].store, xoperands); @@ -2429,7 +2678,7 @@ output_block_move (insn, operands, num_regs, move_type) } num = 0; /* reset load_store */ - use_lwl_lwr = FALSE; /* reset whether or not we used lwl/lwr */ + use_lwl_lwr = FALSE; } } @@ -2512,12 +2761,14 @@ function_arg_advance (cum, mode, type, named) && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT) abort (); cum->gp_reg_found = 1; - cum->arg_words += (GET_MODE_SIZE (mode) + 3) / 4; + cum->arg_words += ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) + / UNITS_PER_WORD); break; case BLKmode: cum->gp_reg_found = 1; - cum->arg_words += (int_size_in_bytes (type) + 3) / 4; + cum->arg_words += ((int_size_in_bytes (type) + UNITS_PER_WORD - 1) + / UNITS_PER_WORD); break; case SFmode: @@ -2525,12 +2776,12 @@ function_arg_advance (cum, mode, type, named) break; case DFmode: - cum->arg_words += 2; + cum->arg_words += (TARGET_64BIT ? 1 : 2); break; case DImode: cum->gp_reg_found = 1; - cum->arg_words += 2; + cum->arg_words += (TARGET_64BIT ? 1 : 2); break; case QImode: @@ -2542,8 +2793,8 @@ function_arg_advance (cum, mode, type, named) } } -/* Return a RTL expression containing the register for the given mode, - or 0 if the argument is too be passed on the stack. */ +/* Return an RTL expression containing the register for the given mode, + or 0 if the argument is to be passed on the stack. */ struct rtx_def * function_arg (cum, mode, type, named) @@ -2579,7 +2830,8 @@ function_arg (cum, mode, type, named) break; case DFmode: - cum->arg_words += (cum->arg_words & 1); + if (! TARGET_64BIT) + cum->arg_words += (cum->arg_words & 1); regbase = (cum->gp_reg_found || TARGET_SOFT_FLOAT || cum->arg_number >= 2 ? GP_ARG_FIRST : FP_ARG_FIRST); @@ -2592,7 +2844,8 @@ function_arg (cum, mode, type, named) /* Drops through. */ case BLKmode: - if (type != (tree)0 && TYPE_ALIGN (type) > BITS_PER_WORD) + if (type != (tree)0 && TYPE_ALIGN (type) > BITS_PER_WORD + && ! TARGET_64BIT) cum->arg_words += (cum->arg_words & 1); regbase = GP_ARG_FIRST; @@ -2606,7 +2859,8 @@ function_arg (cum, mode, type, named) break; case DImode: - cum->arg_words += (cum->arg_words & 1); + if (! TARGET_64BIT) + cum->arg_words += (cum->arg_words & 1); regbase = GP_ARG_FIRST; } @@ -2634,19 +2888,29 @@ function_arg (cum, mode, type, named) This also makes varargs work. If we have such a structure, we save the adjustment RTL, and the call define expands will emit them. For the VOIDmode argument (argument after the - last real argument, pass back a parallel vector holding each + last real argument), pass back a parallel vector holding each of the adjustments. */ /* ??? function_arg can be called more than once for each argument. As a result, we compute more adjustments than we need here. See the CUMULATIVE_ARGS definition in mips.h. */ - if (struct_p && int_size_in_bytes (type) < 4) + /* ??? This scheme requires everything smaller than the word size to + shifted to the left, but when TARGET_64BIT and ! TARGET_INT64, + that would mean every int needs to be shifted left, which is very + inefficient. Let's not carry this compatibility to the 64 bit + calling convention for now. */ + + if (struct_p && int_size_in_bytes (type) < UNITS_PER_WORD + && ! TARGET_64BIT) { rtx amount = GEN_INT (BITS_PER_WORD - int_size_in_bytes (type) * BITS_PER_UNIT); - rtx reg = gen_rtx (REG, SImode, regbase + cum->arg_words + bias); - cum->adjust[ cum->num_adjusts++ ] = gen_ashlsi3 (reg, reg, amount); + rtx reg = gen_rtx (REG, word_mode, regbase + cum->arg_words + bias); + if (TARGET_64BIT) + cum->adjust[ cum->num_adjusts++ ] = gen_ashldi3 (reg, reg, amount); + else + cum->adjust[ cum->num_adjusts++ ] = gen_ashlsi3 (reg, reg, amount); } } @@ -2671,9 +2935,10 @@ function_arg_partial_nregs (cum, mode, type, named) { int words; if (mode == BLKmode) - words = (int_size_in_bytes (type) + 3) / 4; + words = ((int_size_in_bytes (type) + UNITS_PER_WORD - 1) + / UNITS_PER_WORD); else - words = (GET_MODE_SIZE (mode) + 3) / 4; + words = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; if (words + cum->arg_words <= MAX_ARGS_IN_REGISTERS) return 0; /* structure fits in registers */ @@ -2685,7 +2950,8 @@ function_arg_partial_nregs (cum, mode, type, named) return MAX_ARGS_IN_REGISTERS - cum->arg_words; } - else if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS-1) + else if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS-1 + && ! TARGET_64BIT) { if (TARGET_DEBUG_E_MODE) fprintf (stderr, "function_arg_partial_nregs = 1\n"); @@ -2821,13 +3087,57 @@ override_options () mips_section_threshold = (g_switch_set) ? g_switch_value : MIPS_DEFAULT_GVALUE; + if (mips_section_threshold <= 0) + target_flags &= ~MASK_GPOPT; + else if (optimize) + target_flags |= MASK_GPOPT; + + /* Get the architectural level. */ + if (mips_isa_string == (char *)0) + { +#ifdef MIPS_ISA_DEFAULT + mips_isa = MIPS_ISA_DEFAULT; +#else + mips_isa = 1; +#endif + } + + else if (isdigit (*mips_isa_string)) + { + mips_isa = atoi (mips_isa_string); + if (mips_isa < 1 || mips_isa > 3) + { + error ("-mips%d not supported", mips_isa); + mips_isa = 1; + } + } + + else + { + error ("bad value (%s) for -mips switch", mips_isa_string); + mips_isa = 1; + } + /* Identify the processor type */ if (mips_cpu_string == (char *)0 || !strcmp (mips_cpu_string, "default") || !strcmp (mips_cpu_string, "DEFAULT")) { - mips_cpu_string = "default"; - mips_cpu = PROCESSOR_DEFAULT; + switch (mips_isa) + { + default: + mips_cpu_string = "3000"; + mips_cpu = PROCESSOR_R3000; + break; + case 2: + mips_cpu_string = "6000"; + mips_cpu = PROCESSOR_R6000; + break; + case 3: + mips_cpu_string = "4000"; + mips_cpu = PROCESSOR_R4000; + break; + } } else @@ -2856,12 +3166,23 @@ override_options () case '4': if (!strcmp (p, "4000") || !strcmp (p, "4k") || !strcmp (p, "4K")) mips_cpu = PROCESSOR_R4000; + /* The r4400 is exactly the same as the r4000 from the compiler's + viewpoint. */ + else if (!strcmp (p, "4400")) + mips_cpu = PROCESSOR_R4000; + else if (!strcmp (p, "4600")) + mips_cpu = PROCESSOR_R4600; break; case '6': if (!strcmp (p, "6000") || !strcmp (p, "6k") || !strcmp (p, "6K")) mips_cpu = PROCESSOR_R6000; break; + + case 'o': + if (!strcmp (p, "orion")) + mips_cpu = PROCESSOR_R4600; + break; } if (mips_cpu == PROCESSOR_DEFAULT) @@ -2871,46 +3192,32 @@ override_options () } } - /* Now get the architectural level. */ - if (mips_isa_string == (char *)0) - mips_isa = 1; - - else if (isdigit (*mips_isa_string)) - mips_isa = atoi (mips_isa_string); - - else - { - error ("bad value (%s) for -mips switch", mips_isa_string); - mips_isa = 1; - } - - if (mips_isa < 0 || mips_isa > 3) - error ("-mips%d not supported", mips_isa); - - else if (mips_isa > 1 - && (mips_cpu == PROCESSOR_DEFAULT || mips_cpu == PROCESSOR_R3000)) - error ("-mcpu=%s does not support -mips%d", mips_cpu_string, mips_isa); - - else if (mips_cpu == PROCESSOR_R6000 && mips_isa > 2) + if ((mips_cpu == PROCESSOR_R3000 && mips_isa > 1) + || (mips_cpu == PROCESSOR_R6000 && mips_isa > 2)) error ("-mcpu=%s does not support -mips%d", mips_cpu_string, mips_isa); /* make sure sizes of ints/longs/etc. are ok */ if (mips_isa < 3) { if (TARGET_INT64) - fatal ("Only the r4000 can support 64 bit ints"); + fatal ("Only MIPS-III CPUs can support 64 bit ints"); else if (TARGET_LONG64) - fatal ("Only the r4000 can support 64 bit longs"); + fatal ("Only MIPS-III CPUs can support 64 bit longs"); else if (TARGET_LLONG128) - fatal ("Only the r4000 can support 128 bit long longs"); + fatal ("Only MIPS-III CPUs can support 128 bit long longs"); else if (TARGET_FLOAT64) - fatal ("Only the r4000 can support 64 bit fp registers"); + fatal ("Only MIPS-III CPUs can support 64 bit fp registers"); + } + else + { + target_flags |= MASK_64BIT; + + if (TARGET_LLONG128) + fatal ("128 bit long longs are not supported"); } - else if (TARGET_INT64 || TARGET_LONG64 || TARGET_LLONG128 || TARGET_FLOAT64) - warning ("r4000 64/128 bit types not yet supported"); /* Tell halfpic.c that we have half-pic code if we do. */ if (TARGET_HALF_PIC) @@ -2922,20 +3229,12 @@ override_options () mips_abicalls = MIPS_ABICALLS_NO; /* -mrnames says to use the MIPS software convention for register - names instead of the hardware names (ie, a0 instead of $4). + names instead of the hardware names (ie, $a0 instead of $4). We do this by switching the names in mips_reg_names, which the reg_names points into via the REGISTER_NAMES macro. */ if (TARGET_NAME_REGS) - { - if (TARGET_GAS) - { - target_flags &= ~ MASK_NAME_REGS; - error ("Gas does not support the MIPS software register name convention."); - } - else - bcopy ((char *) mips_sw_reg_names, (char *) mips_reg_names, sizeof (mips_reg_names)); - } + bcopy ((char *) mips_sw_reg_names, (char *) mips_reg_names, sizeof (mips_reg_names)); /* If this is OSF/1, set up a SIGINFO handler so we can see what function is currently being compiled. */ @@ -2958,6 +3257,14 @@ override_options () #endif #endif + /* Initialize the high and low values for legitimate floating point + constants. Rather than trying to get the accuracy down to the + last bit, just use approximate ranges. */ + dfhigh = REAL_VALUE_ATOF ("1.0e300", DFmode); + dflow = REAL_VALUE_ATOF ("1.0e-300", DFmode); + sfhigh = REAL_VALUE_ATOF ("1.0e38", SFmode); + sflow = REAL_VALUE_ATOF ("1.0e-38", SFmode); + /* Set up the classification arrays now. */ mips_rtx_classify[(int)PLUS] = CLASS_ADD_OP; mips_rtx_classify[(int)MINUS] = CLASS_ADD_OP; @@ -3046,7 +3353,14 @@ override_options () || (TARGET_DEBUG_H_MODE && class == MODE_INT))); else if (MD_REG_P (regno)) - temp = (mode == SImode || (regno == MD_REG_FIRST && mode == DImode)); + { + if (TARGET_64BIT) + temp = (mode == DImode + || (regno == MD_REG_FIRST && mode == TImode)); + else + temp = (mode == SImode + || (regno == MD_REG_FIRST && mode == DImode)); + } else temp = FALSE; @@ -3331,20 +3645,12 @@ print_operand (file, op, letter) else if (code == CONST_DOUBLE) { -#if HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT - union { double d; int i[2]; } u; - u.i[0] = CONST_DOUBLE_LOW (op); - u.i[1] = CONST_DOUBLE_HIGH (op); - if (GET_MODE (op) == SFmode) - { - float f; - f = u.d; - u.d = f; - } - fprintf (file, "%.20e", u.d); -#else - fatal ("CONST_DOUBLE found in cross compilation"); -#endif + REAL_VALUE_TYPE d; + char s[30]; + + REAL_VALUE_FROM_CONST_DOUBLE (d, op); + REAL_VALUE_TO_DECIMAL (d, "%.20e", s); + fprintf (file, s); } else if ((letter == 'x') && (GET_CODE(op) == CONST_INT)) @@ -3468,7 +3774,6 @@ mips_output_external (file, decl, name) int len; if (TARGET_GP_OPT - && mips_section_threshold != 0 && ((TREE_CODE (decl)) != FUNCTION_DECL) && ((len = int_size_in_bytes (TREE_TYPE (decl))) > 0)) { @@ -3484,6 +3789,14 @@ mips_output_external (file, decl, name) /* Compute a string to use as a temporary file name. */ +/* On MSDOS, write temp files in current dir + because there's no place else we can expect to use. */ +#if __MSDOS__ +#ifndef P_tmpdir +#define P_tmpdir "./" +#endif +#endif + static FILE * make_temp_file () { @@ -3505,19 +3818,25 @@ make_temp_file () } len = strlen (base); - temp_filename = (char *) alloca (len + sizeof("/ccXXXXXX")); + /* temp_filename is global, so we must use malloc, not alloca. */ + temp_filename = (char *) xmalloc (len + sizeof("/ctXXXXXX")); strcpy (temp_filename, base); if (len > 0 && temp_filename[len-1] != '/') temp_filename[len++] = '/'; - strcpy (temp_filename + len, "ccXXXXXX"); + strcpy (temp_filename + len, "ctXXXXXX"); mktemp (temp_filename); stream = fopen (temp_filename, "w+"); if (!stream) pfatal_with_name (temp_filename); +#ifndef __MSDOS__ + /* In MSDOS, we cannot unlink the temporary file until we are finished using + it. Otherwise, we delete it now, so that it will be gone even if the + compiler happens to crash. */ unlink (temp_filename); +#endif return stream; } @@ -3706,9 +4025,6 @@ mips_asm_file_start (stream) else asm_out_data_file = asm_out_text_file = stream; - if (TARGET_NAME_REGS) - fprintf (asm_out_file, "#include \n"); - print_options (stream); } @@ -3764,6 +4080,10 @@ mips_asm_file_end (file) if (fclose (asm_out_text_file) != 0) pfatal_with_name (temp_filename); + +#ifdef __MSDOS__ + unlink (temp_filename); +#endif } } @@ -3784,7 +4104,7 @@ mips_declare_object (stream, name, init_string, final_string, size) assemble_name (stream, name); fprintf (stream, final_string, size); /* ":\n", ",%u\n", ",%u\n" */ - if (TARGET_GP_OPT && mips_section_threshold != 0) + if (TARGET_GP_OPT) { tree name_tree = get_identifier (name); TREE_ASM_WRITTEN (name_tree) = 1; @@ -4011,7 +4331,7 @@ compute_frame_size (size) { if (regs_ever_live[regno] && !call_used_regs[regno]) { - fp_reg_size += 2*UNITS_PER_WORD; + fp_reg_size += fp_inc * UNITS_PER_FPREG; fmask |= fp_bits << (regno - FP_REG_FIRST); } } @@ -4042,7 +4362,7 @@ compute_frame_size (size) current_frame_info.fmask = fmask; current_frame_info.initialized = reload_completed; current_frame_info.num_gp = gp_reg_size / UNITS_PER_WORD; - current_frame_info.num_fp = fp_reg_size / (2*UNITS_PER_WORD); + current_frame_info.num_fp = fp_reg_size / (fp_inc * UNITS_PER_FPREG); if (mask) { @@ -4060,8 +4380,9 @@ compute_frame_size (size) if (fmask) { - unsigned long offset = args_size + extra_size + var_size - + gp_reg_rounded + fp_reg_size - 2*UNITS_PER_WORD; + unsigned long offset = (args_size + extra_size + var_size + + gp_reg_rounded + fp_reg_size + - fp_inc * UNITS_PER_FPREG); current_frame_info.fp_sp_offset = offset; current_frame_info.fp_save_offset = offset - total_size + UNITS_PER_WORD; } @@ -4140,9 +4461,15 @@ save_restore_insns (store_p, large_reg, large_offset, file) base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM); base_offset = large_offset; if (file == (FILE *)0) - emit_insn (gen_addsi3 (base_reg_rtx, large_reg, stack_pointer_rtx)); + { + if (TARGET_LONG64) + emit_insn (gen_adddi3 (base_reg_rtx, large_reg, stack_pointer_rtx)); + else + emit_insn (gen_addsi3 (base_reg_rtx, large_reg, stack_pointer_rtx)); + } else - fprintf (file, "\taddu\t%s,%s,%s\n", + fprintf (file, "\t%s\t%s,%s,%s\n", + TARGET_LONG64 ? "daddu" : "addu", reg_names[MIPS_TEMP2_REGNUM], reg_names[REGNO (large_reg)], reg_names[STACK_POINTER_REGNUM]); @@ -4155,13 +4482,17 @@ save_restore_insns (store_p, large_reg, large_offset, file) if (file == (FILE *)0) { emit_move_insn (base_reg_rtx, GEN_INT (gp_offset)); - emit_insn (gen_addsi3 (base_reg_rtx, base_reg_rtx, stack_pointer_rtx)); + if (TARGET_LONG64) + emit_insn (gen_adddi3 (base_reg_rtx, base_reg_rtx, stack_pointer_rtx)); + else + emit_insn (gen_addsi3 (base_reg_rtx, base_reg_rtx, stack_pointer_rtx)); } else - fprintf (file, "\tli\t%s,0x%.08lx\t# %ld\n\taddu\t%s,%s,%s\n", + fprintf (file, "\tli\t%s,0x%.08lx\t# %ld\n\t%s\t%s,%s,%s\n", reg_names[MIPS_TEMP2_REGNUM], (long)base_offset, (long)base_offset, + TARGET_LONG64 ? "daddu" : "addu", reg_names[MIPS_TEMP2_REGNUM], reg_names[MIPS_TEMP2_REGNUM], reg_names[STACK_POINTER_REGNUM]); @@ -4173,8 +4504,8 @@ save_restore_insns (store_p, large_reg, large_offset, file) { if (file == (FILE *)0) { - rtx reg_rtx = gen_rtx (REG, Pmode, regno); - rtx mem_rtx = gen_rtx (MEM, Pmode, + rtx reg_rtx = gen_rtx (REG, word_mode, regno); + rtx mem_rtx = gen_rtx (MEM, word_mode, gen_rtx (PLUS, Pmode, base_reg_rtx, GEN_INT (gp_offset - base_offset))); @@ -4189,7 +4520,9 @@ save_restore_insns (store_p, large_reg, large_offset, file) if (store_p || !TARGET_ABICALLS || regno != (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST)) fprintf (file, "\t%s\t%s,%ld(%s)\n", - (store_p) ? "sw" : "lw", + (TARGET_64BIT + ? (store_p) ? "sd" : "ld" + : (store_p) ? "sw" : "lw"), reg_names[regno], gp_offset - base_offset, reg_names[REGNO(base_reg_rtx)]); @@ -4209,10 +4542,11 @@ save_restore_insns (store_p, large_reg, large_offset, file) if (fmask) { int fp_inc = (TARGET_FLOAT64) ? 1 : 2; + int fp_size = fp_inc * UNITS_PER_FPREG; /* Pick which pointer to use as a base register. */ fp_offset = current_frame_info.fp_sp_offset; - end_offset = fp_offset - (current_frame_info.fp_reg_size - 2*UNITS_PER_WORD); + end_offset = fp_offset - (current_frame_info.fp_reg_size - fp_size); if (fp_offset < 0 || end_offset < 0) fatal ("fp_offset (%ld) or end_offset (%ld) is less than zero.", @@ -4238,9 +4572,15 @@ save_restore_insns (store_p, large_reg, large_offset, file) base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM); base_offset = large_offset; if (file == (FILE *)0) - emit_insn (gen_addsi3 (base_reg_rtx, large_reg, stack_pointer_rtx)); + { + if (TARGET_LONG64) + emit_insn (gen_adddi3 (base_reg_rtx, large_reg, stack_pointer_rtx)); + else + emit_insn (gen_addsi3 (base_reg_rtx, large_reg, stack_pointer_rtx)); + } else - fprintf (file, "\taddu\t%s,%s,%s\n", + fprintf (file, "\t%s\t%s,%s,%s\n", + TARGET_LONG64 ? "daddu" : "addu", reg_names[MIPS_TEMP2_REGNUM], reg_names[REGNO (large_reg)], reg_names[STACK_POINTER_REGNUM]); @@ -4253,13 +4593,17 @@ save_restore_insns (store_p, large_reg, large_offset, file) if (file == (FILE *)0) { emit_move_insn (base_reg_rtx, GEN_INT (fp_offset)); - emit_insn (gen_addsi3 (base_reg_rtx, base_reg_rtx, stack_pointer_rtx)); + if (TARGET_LONG64) + emit_insn (gen_adddi3 (base_reg_rtx, base_reg_rtx, stack_pointer_rtx)); + else + emit_insn (gen_addsi3 (base_reg_rtx, base_reg_rtx, stack_pointer_rtx)); } else - fprintf (file, "\tli\t%s,0x%.08lx\t# %ld\n\taddu\t%s,%s,%s\n", + fprintf (file, "\tli\t%s,0x%.08lx\t# %ld\n\t%s\t%s,%s,%s\n", reg_names[MIPS_TEMP2_REGNUM], (long)base_offset, (long)base_offset, + TARGET_LONG64 ? "daddu" : "addu", reg_names[MIPS_TEMP2_REGNUM], reg_names[MIPS_TEMP2_REGNUM], reg_names[STACK_POINTER_REGNUM]); @@ -4289,7 +4633,7 @@ save_restore_insns (store_p, large_reg, large_offset, file) reg_names[REGNO(base_reg_rtx)]); - fp_offset -= 2*UNITS_PER_WORD; + fp_offset -= fp_size; } } } @@ -4342,7 +4686,9 @@ function_prologue (file, size) reg_names[PIC_FUNCTION_ADDR_REGNUM]); if (tsize > 0) { - fprintf (file, "\tsubu\t%s,%s,%d\n", sp_str, sp_str, tsize); + fprintf (file, "\t%s\t%s,%s,%d\n", + (TARGET_LONG64 ? "dsubu" : "subu"), + sp_str, sp_str, tsize); fprintf (file, "\t.cprestore %d\n", current_frame_info.args_size); } } @@ -4474,8 +4820,8 @@ mips_expand_prologue () { if (offset != 0) ptr = gen_rtx (PLUS, Pmode, stack_pointer_rtx, GEN_INT (offset)); - emit_move_insn (gen_rtx (MEM, Pmode, ptr), - gen_rtx (REG, Pmode, regno)); + emit_move_insn (gen_rtx (MEM, word_mode, ptr), + gen_rtx (REG, word_mode, regno)); offset += UNITS_PER_WORD; } } @@ -4489,19 +4835,28 @@ mips_expand_prologue () { if (tsize > 32767) { - tmp_rtx = gen_rtx (REG, SImode, MIPS_TEMP1_REGNUM); + tmp_rtx = gen_rtx (REG, Pmode, MIPS_TEMP1_REGNUM); emit_move_insn (tmp_rtx, tsize_rtx); tsize_rtx = tmp_rtx; } - emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, - tsize_rtx)); + if (TARGET_LONG64) + emit_insn (gen_subdi3 (stack_pointer_rtx, stack_pointer_rtx, + tsize_rtx)); + else + emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, + tsize_rtx)); } save_restore_insns (TRUE, tmp_rtx, tsize, (FILE *)0); if (frame_pointer_needed) - emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx)); + { + if (TARGET_64BIT) + emit_insn (gen_movdi (frame_pointer_rtx, stack_pointer_rtx)); + else + emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx)); + } } /* If we are profiling, make sure no instructions are scheduled before @@ -4580,7 +4935,7 @@ function_epilogue (file, size) if (set_volatile != 0) { set_volatile = 0; - fprintf (file, "\t#.set\tnovolatile\n", (TARGET_MIPS_AS) ? "" : "#"); + fprintf (file, "\t%s.set\tnovolatile\n", (TARGET_MIPS_AS) ? "" : "#"); error ("internal gcc error: .set volatile left on in epilogue"); } @@ -4654,10 +5009,14 @@ function_epilogue (file, size) fprintf (file, "\tj\t%s\n", reg_names[GP_REG_FIRST + 31]); if (tsize > 32767) - fprintf (file, "\taddu\t%s,%s,%s\n", sp_str, sp_str, t1_str); + fprintf (file, "\t%s\t%s,%s,%s\n", + TARGET_LONG64 ? "daddu" : "addu", + sp_str, sp_str, t1_str); else if (tsize > 0) - fprintf (file, "\taddu\t%s,%s,%d\n", sp_str, sp_str, tsize); + fprintf (file, "\t%s\t%s,%s,%d\n", + TARGET_LONG64 ? "daddu" : "addu", + sp_str, sp_str, tsize); else if (!load_only_r31 && epilogue_delay != 0) final_scan_insn (XEXP (epilogue_delay, 0), @@ -4672,10 +5031,14 @@ function_epilogue (file, size) else { if (tsize > 32767) - fprintf (file, "\taddu\t%s,%s,%s\n", sp_str, sp_str, t1_str); + fprintf (file, "\t%s\t%s,%s,%s\n", + TARGET_LONG64 ? "daddu" : "addu", + sp_str, sp_str, t1_str); else if (tsize > 0) - fprintf (file, "\taddu\t%s,%s,%d\n", sp_str, sp_str, tsize); + fprintf (file, "\t%s\t%s,%s,%d\n", + TARGET_LONG64 ? "daddu" : "addu", + sp_str, sp_str, tsize); fprintf (file, "\tj\t%s\n", reg_names[GP_REG_FIRST + 31]); } @@ -4777,7 +5140,7 @@ mips_expand_epilogue () if (tsize > 32767) { - tmp_rtx = gen_rtx (REG, SImode, MIPS_TEMP1_REGNUM); + tmp_rtx = gen_rtx (REG, Pmode, MIPS_TEMP1_REGNUM); emit_move_insn (tmp_rtx, tsize_rtx); tsize_rtx = tmp_rtx; } @@ -4785,11 +5148,21 @@ mips_expand_epilogue () if (tsize > 0) { if (frame_pointer_needed) - emit_insn (gen_movsi (stack_pointer_rtx, frame_pointer_rtx)); + { + if (TARGET_LONG64) + emit_insn (gen_movdi (stack_pointer_rtx, frame_pointer_rtx)); + else + emit_insn (gen_movsi (stack_pointer_rtx, frame_pointer_rtx)); + } save_restore_insns (FALSE, tmp_rtx, tsize, (FILE *)0); - emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, tsize_rtx)); + if (TARGET_LONG64) + emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx, + tsize_rtx)); + else + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + tsize_rtx)); } emit_jump_insn (gen_return_internal (gen_rtx (REG, Pmode, GP_REG_FIRST+31))); -- 2.30.2