aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Wilson <wilson@gcc.gnu.org>1995-02-04 10:04:15 -0800
committerJim Wilson <wilson@gcc.gnu.org>1995-02-04 10:04:15 -0800
commit335634874738d42760f1966133810dd7c069cab8 (patch)
tree7993b387421f5724d47a2426679b878445e08212
parent516a2dfd6f337bb262112331fa8a9c8fe19463eb (diff)
downloadgcc-335634874738d42760f1966133810dd7c069cab8.zip
gcc-335634874738d42760f1966133810dd7c069cab8.tar.gz
gcc-335634874738d42760f1966133810dd7c069cab8.tar.bz2
(mips_isa_string): Add mips4 to comment.
(large_int): Delete code for handling 64 bit constants. (mips_const_double_ok): For irix6, reject all floating point constants. (mips_move_2words): Use dli not li for 64 bit constants. Use dla not la for 64 bit addresses. (output_block_move): Likewise. (function_arg): Add support for 64bit ABI. (override_options): Add support for mips4 and R8000. (print_operand): Handle new modifiers 'B', 'b', 'T', 't'. Make 'X' case work for 64 bit host. (mips_output_filename): Use ASM_OUTPUT_FILENAME. (mips_asm_file_start): Go to text section for 64bit ABI. (compure_frame_size, save_restore_insns, function_prologue, mips_expand_prologue, function_epilogue): Add support for 64 bit ABI. (type_dependent_reg, mips_function_value): New functions. From-SVN: r8863
-rw-r--r--gcc/config/mips/mips.c264
1 files changed, 206 insertions, 58 deletions
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index 9d9b0ff..e3a7472 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -194,7 +194,7 @@ int mips_isa;
/* Strings to hold which cpu and instruction set architecture to use. */
char *mips_cpu_string; /* for -mcpu=<xxx> */
-char *mips_isa_string; /* for -mips{1,2,3} */
+char *mips_isa_string; /* for -mips{1,2,3,4} */
/* Generating calls to position independent functions? */
enum mips_abicalls_type mips_abicalls;
@@ -409,7 +409,7 @@ small_int (op, mode)
return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
}
-/* Return truth value of whether OP is an integer which is too big to
+/* Return truth value of whether OP is a 32 bit integer which is too big to
be loaded with one instruction. */
int
@@ -429,9 +429,7 @@ large_int (op, mode)
if (((unsigned long)(value + 32768)) <= 32767) /* subu reg,$r0,value */
return FALSE;
- if ((value & 0x0000ffff) == 0 /* lui reg,value>>16 */
- && ((value & ~2147483647) == 0 /* signed value */
- || (value & ~2147483647) == ~2147483647))
+ if ((value & 0x0000ffff) == 0) /* lui reg,value>>16 */
return FALSE;
return TRUE;
@@ -487,6 +485,10 @@ mips_const_double_ok (op, mode)
if (op == CONST0_RTX (mode))
return TRUE;
+ /* ??? li.s does not work right with SGI's Irix 6 assembler. */
+ if (ABI_64BIT)
+ return FALSE;
+
REAL_VALUE_FROM_CONST_DOUBLE (d, op);
if (REAL_VALUE_ISNAN (d))
@@ -1349,8 +1351,8 @@ mips_move_2words (operands, insn)
ret = "li.d\t%0,%1";
}
- else if (TARGET_FLOAT64)
- ret = "li\t%0,%1";
+ else if (TARGET_64BIT)
+ ret = "dli\t%0,%1";
else
{
@@ -1401,7 +1403,17 @@ mips_move_2words (operands, insn)
else if (code1 == CONST_INT && GET_MODE (op0) == DImode && GP_REG_P (regno0))
{
if (TARGET_64BIT)
- ret = "li\t%0,%1";
+ {
+ if (HOST_BITS_PER_WIDE_INT < 64)
+ /* We can't use 'X' for negative numbers, because then we won't
+ get the right value for the upper 32 bits. */
+ ret = ((INTVAL (op1) < 0) ? "dli\t%0,%1\t\t\t# %X1"
+ : "dli\t%0,%X1\t\t# %1");
+ else
+ /* We must use 'X', because otherwise LONG_MIN will print as
+ a number that the assembler won't accept. */
+ ret = "dli\t%0,%X1\t\t# %1";
+ }
else
{
operands[2] = GEN_INT (INTVAL (operands[1]) >= 0 ? 0 : -1);
@@ -1458,9 +1470,10 @@ mips_move_2words (operands, insn)
|| code1 == SYMBOL_REF
|| code1 == CONST)
{
- if (! TARGET_64BIT)
- abort ();
- return mips_move_1word (operands, insn, 0);
+ if (TARGET_STATS)
+ mips_count_memory_refs (op1, 2);
+
+ ret = "dla\t%0,%a1";
}
}
@@ -2445,7 +2458,10 @@ output_block_move (insn, operands, num_regs, move_type)
{
xoperands[1] = operands[1];
xoperands[0] = src_reg;
- output_asm_insn ("la\t%0,%1", xoperands);
+ if (Pmode == DImode)
+ output_asm_insn ("dla\t%0,%1", xoperands);
+ else
+ output_asm_insn ("la\t%0,%1", xoperands);
}
}
@@ -2459,7 +2475,10 @@ output_block_move (insn, operands, num_regs, move_type)
{
xoperands[1] = operands[0];
xoperands[0] = dest_reg;
- output_asm_insn ("la\t%0,%1", xoperands);
+ if (Pmode == DImode)
+ output_asm_insn ("dla\t%0,%1", xoperands);
+ else
+ output_asm_insn ("la\t%0,%1", xoperands);
}
}
}
@@ -2802,28 +2821,36 @@ function_arg (cum, mode, type, named)
switch (mode)
{
case SFmode:
- if (cum->gp_reg_found || cum->arg_number >= 2 || TARGET_SOFT_FLOAT)
- regbase = GP_ARG_FIRST;
- else
+ if (! ABI_64BIT || mips_isa < 3)
{
- regbase = FP_ARG_FIRST;
- /* If the first arg was a float in a floating point register,
- then set bias to align this float arg properly. */
- if (cum->arg_words == 1)
- bias = 1;
+ if (cum->gp_reg_found || cum->arg_number >= 2 || TARGET_SOFT_FLOAT)
+ regbase = GP_ARG_FIRST;
+ else
+ {
+ regbase = FP_ARG_FIRST;
+ /* If the first arg was a float in a floating point register,
+ then set bias to align this float arg properly. */
+ if (cum->arg_words == 1)
+ bias = 1;
+ }
}
-
+ else
+ regbase = (TARGET_SOFT_FLOAT || ! named ? GP_ARG_FIRST : FP_ARG_FIRST);
break;
case DFmode:
if (! TARGET_64BIT)
cum->arg_words += (cum->arg_words & 1);
- regbase = ((cum->gp_reg_found
- || TARGET_SOFT_FLOAT
- || TARGET_SINGLE_FLOAT
- || cum->arg_number >= 2)
- ? GP_ARG_FIRST
- : FP_ARG_FIRST);
+ if (! ABI_64BIT || mips_isa < 3)
+ regbase = ((cum->gp_reg_found
+ || TARGET_SOFT_FLOAT
+ || TARGET_SINGLE_FLOAT
+ || cum->arg_number >= 2)
+ ? GP_ARG_FIRST
+ : FP_ARG_FIRST);
+ else
+ regbase = (TARGET_SOFT_FLOAT || TARGET_SINGLE_FLOAT || ! named
+ ? GP_ARG_FIRST : FP_ARG_FIRST);
break;
default:
@@ -3094,7 +3121,7 @@ override_options ()
else if (isdigit (*mips_isa_string))
{
mips_isa = atoi (mips_isa_string);
- if (mips_isa < 1 || mips_isa > 3)
+ if (mips_isa < 1 || mips_isa > 4)
{
error ("-mips%d not supported", mips_isa);
mips_isa = 1;
@@ -3126,6 +3153,10 @@ override_options ()
mips_cpu_string = "4000";
mips_cpu = PROCESSOR_R4000;
break;
+ case 4:
+ mips_cpu_string = "8000";
+ mips_cpu = PROCESSOR_R8000;
+ break;
}
#ifdef MIPS_CPU_DEFAULT
@@ -3180,6 +3211,11 @@ override_options ()
mips_cpu = PROCESSOR_R6000;
break;
+ case '8':
+ if (!strcmp (p, "8000"))
+ mips_cpu = PROCESSOR_R8000;
+ break;
+
case 'o':
if (!strcmp (p, "orion"))
mips_cpu = PROCESSOR_R4600;
@@ -3194,25 +3230,30 @@ override_options ()
}
if ((mips_cpu == PROCESSOR_R3000 && mips_isa > 1)
- || (mips_cpu == PROCESSOR_R6000 && mips_isa > 2))
+ || (mips_cpu == PROCESSOR_R6000 && mips_isa > 2)
+ || ((mips_cpu == PROCESSOR_R4000 || mips_cpu == PROCESSOR_R4600)
+ && mips_isa > 3))
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 MIPS-III CPUs can support 64 bit ints");
+ fatal ("Only MIPS-III or MIPS-IV CPUs can support 64 bit ints");
else if (TARGET_LONG64)
- fatal ("Only MIPS-III CPUs can support 64 bit longs");
+ fatal ("Only MIPS-III or MIPS-IV CPUs can support 64 bit longs");
else if (TARGET_FLOAT64)
- fatal ("Only MIPS-III CPUs can support 64 bit fp registers");
+ fatal ("Only MIPS-III or MIPS-IV CPUs can support 64 bit fp registers");
else if (TARGET_64BIT)
- fatal ("Only MIPS-III CPUs can support 64 bit gp registers");
+ fatal ("Only MIPS-III or MIPS-IV CPUs can support 64 bit gp registers");
}
+ if (ABI_64BIT && mips_isa >= 3)
+ flag_pcc_struct_return = 0;
+
/* Tell halfpic.c that we have half-pic code if we do. */
if (TARGET_HALF_PIC)
HALF_PIC_INIT ();
@@ -3445,6 +3486,10 @@ mips_debugger_offset (addr, offset)
'C' print part of opcode for a branch condition.
'N' print part of opcode for a branch condition, inverted.
'S' X is CODE_LABEL, print with prefix of "LS" (for embedded switch).
+ 'B' print 'z' for EQ, 'n' for NE
+ 'b' print 'n' for EQ, 'z' for NE
+ 'T' print 'f' for EQ, 't' for NE
+ 't' print 't' for EQ, 'f' for NE
'(' Turn on .set noreorder
')' Turn on .set reorder
'[' Turn on .set noat
@@ -3664,9 +3709,14 @@ print_operand (file, op, letter)
else if ((letter == 'x') && (GET_CODE(op) == CONST_INT))
fprintf (file, "0x%04x", 0xffff & (INTVAL(op)));
- else if ((letter == 'X') && (GET_CODE(op) == CONST_INT))
+ else if ((letter == 'X') && (GET_CODE(op) == CONST_INT)
+ && HOST_BITS_PER_WIDE_INT == 32)
fprintf (file, "0x%08x", INTVAL(op));
+ else if ((letter == 'X') && (GET_CODE(op) == CONST_INT)
+ && HOST_BITS_PER_WIDE_INT == 64)
+ fprintf (file, "0x%016lx", INTVAL(op));
+
else if ((letter == 'd') && (GET_CODE(op) == CONST_INT))
fprintf (file, "%d", (INTVAL(op)));
@@ -3678,6 +3728,15 @@ print_operand (file, op, letter)
else if (letter == 'd' || letter == 'x' || letter == 'X')
fatal ("PRINT_OPERAND: letter %c was found & insn was not CONST_INT", letter);
+ else if (letter == 'B')
+ fputs (code == EQ ? "z" : "n", file);
+ else if (letter == 'b')
+ fputs (code == EQ ? "n" : "z", file);
+ else if (letter == 'T')
+ fputs (code == EQ ? "f" : "t", file);
+ else if (letter == 't')
+ fputs (code == EQ ? "t" : "f", file);
+
else
output_addr_const (file, op);
}
@@ -3902,9 +3961,7 @@ mips_output_filename (stream, name)
first_time = FALSE;
SET_FILE_NUMBER ();
current_function_file = name;
- fprintf (stream, "\t.file\t%d ", num_source_filenames);
- output_quoted_string (stream, name);
- fprintf (stream, "\n");
+ ASM_OUTPUT_FILENAME (stream, num_source_filenames, name);
/* This tells mips-tfile that stabs will follow. */
if (!TARGET_GAS && write_symbols == DBX_DEBUG)
fprintf (stream, "\t#@stabs\n");
@@ -3929,18 +3986,13 @@ mips_output_filename (stream, name)
ignore_line_number = TRUE;
warning ("MIPS ECOFF format does not allow changing filenames within functions with #line");
}
-
- fprintf (stream, "\t#.file\t%d ", num_source_filenames);
}
-
else
{
SET_FILE_NUMBER ();
current_function_file = name;
- fprintf (stream, "\t.file\t%d ", num_source_filenames);
+ ASM_OUTPUT_FILENAME (stream, num_source_filenames, name);
}
- output_quoted_string (stream, name);
- fprintf (stream, "\n");
}
}
@@ -4061,6 +4113,11 @@ mips_asm_file_start (stream)
/* ??? but do not want this (or want pic0) if -non-shared? */
fprintf (stream, "\t%s\n", ABICALLS_ASM_OP);
+ /* Start a section, so that the first .popsection directive is guaranteed
+ to have a previously defined section to pop back to. */
+ if (ABI_64BIT && mips_isa >= 3)
+ fprintf (stream, "\t.section\t.text\n");
+
/* This code exists so that we can put all externs before all symbol
references. This is necessary for the assembler's global pointer
optimizations to work. */
@@ -4426,7 +4483,11 @@ compute_frame_size (size)
gp_reg_rounded = MIPS_STACK_ALIGN (gp_reg_size);
total_size += gp_reg_rounded + MIPS_STACK_ALIGN (fp_reg_size);
- if (total_size == extra_size)
+ /* The gp reg is caller saved in the 32 bit ABI, so there is no need
+ for leaf routines (total_size == extra_size) to save the gp reg.
+ The gp reg is callee saved in the 64 bit ABI, so all routines must
+ save the gp reg. */
+ if (total_size == extra_size && ! (ABI_64BIT && mips_isa >= 3))
total_size = extra_size = 0;
else if (TARGET_ABICALLS)
{
@@ -4438,6 +4499,11 @@ compute_frame_size (size)
total_size += gp_reg_rounded;
}
+ /* Add in space reserved on the stack by the callee for storing arguments
+ passed in registers. */
+ if (ABI_64BIT && mips_isa >= 3)
+ total_size += MIPS_STACK_ALIGN (current_function_pretend_args_size);
+
/* Save other computed information. */
current_frame_info.total_size = total_size;
current_frame_info.var_size = var_size;
@@ -4453,8 +4519,8 @@ compute_frame_size (size)
if (mask)
{
- unsigned long offset = args_size + extra_size + var_size
- + gp_reg_size - UNITS_PER_WORD;
+ unsigned long offset = (args_size + extra_size + var_size
+ + gp_reg_size - UNITS_PER_WORD);
current_frame_info.gp_sp_offset = offset;
current_frame_info.gp_save_offset = offset - total_size;
}
@@ -4598,13 +4664,13 @@ save_restore_insns (store_p, large_reg, large_offset, file)
if (store_p)
emit_move_insn (mem_rtx, reg_rtx);
- else if (!TARGET_ABICALLS
+ else if (!TARGET_ABICALLS || (ABI_64BIT && mips_isa >= 3)
|| regno != (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
emit_move_insn (reg_rtx, mem_rtx);
}
else
{
- if (store_p || !TARGET_ABICALLS
+ if (store_p || !TARGET_ABICALLS || (ABI_64BIT && mips_isa >= 3)
|| regno != (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
fprintf (file, "\t%s\t%s,%ld(%s)\n",
(TARGET_64BIT
@@ -4769,7 +4835,7 @@ function_prologue (file, size)
current_frame_info.fmask,
current_frame_info.fp_save_offset);
- if (TARGET_ABICALLS)
+ if (TARGET_ABICALLS && ! (ABI_64BIT && mips_isa >= 3))
{
char *sp_str = reg_names[STACK_POINTER_REGNUM];
@@ -4896,17 +4962,18 @@ mips_expand_prologue ()
/* If this function is a varargs function, store any registers that
would normally hold arguments ($4 - $7) on the stack. */
- if ((TYPE_ARG_TYPES (fntype) != 0
- && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) != void_type_node))
- || (arg_name != (char *)0
- && ((arg_name[0] == '_' && strcmp (arg_name, "__builtin_va_alist") == 0)
- || (arg_name[0] == 'v' && strcmp (arg_name, "va_alist") == 0))))
+ if ((! ABI_64BIT || mips_isa < 3)
+ && ((TYPE_ARG_TYPES (fntype) != 0
+ && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) != void_type_node))
+ || (arg_name != (char *)0
+ && ((arg_name[0] == '_' && strcmp (arg_name, "__builtin_va_alist") == 0)
+ || (arg_name[0] == 'v' && strcmp (arg_name, "va_alist") == 0)))))
{
int offset = (regno - GP_ARG_FIRST) * UNITS_PER_WORD;
rtx ptr = stack_pointer_rtx;
/* If we are doing svr4-abi, sp has already been decremented by tsize. */
- if (TARGET_ABICALLS)
+ if (TARGET_ABICALLS && ! (ABI_64BIT && mips_isa >= 3))
offset += tsize;
for (; regno <= GP_ARG_LAST; regno++)
@@ -4924,7 +4991,7 @@ mips_expand_prologue ()
rtx tsize_rtx = GEN_INT (tsize);
/* If we are doing svr4-abi, sp move is done by function_prologue. */
- if (!TARGET_ABICALLS)
+ if (!TARGET_ABICALLS || (ABI_64BIT && mips_isa >= 3))
{
if (tsize > 32767)
{
@@ -4950,6 +5017,9 @@ mips_expand_prologue ()
else
emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx));
}
+
+ if (TARGET_ABICALLS && (ABI_64BIT && mips_isa >= 3))
+ emit_insn (gen_loadgp (XEXP (DECL_RTL (current_function_decl), 0)));
}
/* If we are profiling, make sure no instructions are scheduled before
@@ -5070,7 +5140,8 @@ function_epilogue (file, size)
save_restore_insns (FALSE, tmp_rtx, tsize, file);
load_only_r31 = (((current_frame_info.mask
- & ~ (TARGET_ABICALLS ? PIC_OFFSET_TABLE_MASK : 0))
+ & ~ (TARGET_ABICALLS && ! (ABI_64BIT && mips_isa >= 3)
+ ? PIC_OFFSET_TABLE_MASK : 0))
== RA_MASK)
&& current_frame_info.fmask == 0);
@@ -5382,6 +5453,83 @@ mips_select_section (decl, reloc)
data_section ();
}
}
+
+#if ABI_64BIT
+/* Support functions for the 64 bit ABI. */
+
+/* Return the register to be used for word INDEX of a variable with type TYPE
+ being passed starting at general purpose reg REGNO.
+
+ If the word being passed is a single field of a structure which has type
+ double, then pass it in a floating point reg instead of a general purpose
+ reg. Otherwise, we return the default value REGNO + INDEX. */
+
+rtx
+type_dependent_reg (regno, index, type)
+ int regno;
+ int index;
+ tree type;
+{
+ tree field;
+ tree offset;
+
+ /* If type isn't a structure type, return the default value now. */
+ if (! type || TREE_CODE (type) != RECORD_TYPE || mips_isa < 3)
+ return gen_rtx (REG, word_mode, regno + index);
+
+ /* Iterate through the structure fields to find which one corresponds to
+ this index. */
+ offset = size_int (index * BITS_PER_WORD);
+ for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ {
+ if (! tree_int_cst_lt (DECL_FIELD_BITPOS (field), offset))
+ break;
+ }
+
+ if (field && tree_int_cst_equal (DECL_FIELD_BITPOS (field), offset)
+ && TREE_CODE (TREE_TYPE (field)) == REAL_TYPE
+ && TYPE_PRECISION (TREE_TYPE (field)) == BITS_PER_WORD)
+ return gen_rtx (REG, DFmode,
+ regno + index + FP_ARG_FIRST - GP_ARG_FIRST);
+ else
+ return gen_rtx (REG, word_mode, regno + index);
+}
+
+/* Return register to use for a function return value with VALTYPE for function
+ FUNC. */
+
+rtx
+mips_function_value (valtype, func)
+ tree valtype;
+ tree func;
+{
+ int reg = GP_RETURN;
+ enum machine_mode mode = TYPE_MODE (valtype);
+ enum mode_class mclass = GET_MODE_CLASS (mode);
+
+ if (mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT)
+ reg = FP_RETURN;
+ else if (TREE_CODE (valtype) == RECORD_TYPE && mips_isa >= 3)
+ {
+ /* A struct with only one or two floating point fields is returned in
+ the floating point registers. */
+ tree field;
+ int i;
+
+ for (i = 0, field = TYPE_FIELDS (valtype); field;
+ field = TREE_CHAIN (field), i++)
+ {
+ if (TREE_CODE (TREE_TYPE (field)) != REAL_TYPE || i >= 2)
+ break;
+ }
+
+ if (! field)
+ reg = FP_RETURN;
+ }
+
+ return gen_rtx (REG, mode, reg);
+}
+#endif
/* Moving the HI or LO register somewhere requires a general register. */