/* Subroutines for insn-output.c for MIPS
- Copyright (C) 1989, 90, 91, 93-97, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1989, 90, 91, 93-98, 1999 Free Software Foundation, Inc.
Contributed by A. Lichnewsky, lich@inria.inria.fr.
Changes by Michael Meissner, meissner@osf.org.
64 bit r4000 support by Ian Lance Taylor, ian@cygnus.com, and
be replaced with something better designed. */
#include "config.h"
-
-#include <stdio.h>
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
+#include "system.h"
+#include <signal.h>
#include "rtl.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "insn-attr.h"
#include "insn-codes.h"
#include "recog.h"
+#include "toplev.h"
#include "output.h"
-#undef MAX /* sys/param.h may also define these */
-#undef MIN
-
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/file.h>
-#include <ctype.h>
#include "tree.h"
+#include "function.h"
#include "expr.h"
#include "flags.h"
#include "reload.h"
-
-#ifndef R_OK
-#define R_OK 4
-#define W_OK 2
-#define X_OK 1
-#endif
+#include "output.h"
+#include "tm_p.h"
+#include "ggc.h"
#if defined(USG) || !defined(HAVE_STAB_H)
#include "gstab.h" /* If doing DBX on sysV, use our own stab.h. */
#define STAB_CODE_TYPE int
#endif
-extern void abort ();
-extern int atoi ();
-extern char *getenv ();
-extern char *mktemp ();
-
-extern rtx adj_offsettable_operand ();
-extern rtx copy_to_reg ();
-extern void error ();
-extern tree lookup_name ();
-extern void pfatal_with_name ();
-extern void warning ();
-
-extern FILE *asm_out_file;
+extern char *mktemp PARAMS ((char *));
+extern tree lookup_name PARAMS ((tree));
/* Enumeration for all of the relational tests, so that we can build
arrays indexed by the test type, and not worry about the order
static void block_move_loop PROTO ((rtx, rtx, int, int,
rtx, rtx));
static void block_move_call PROTO ((rtx, rtx, rtx));
-static FILE *make_temp_file PROTO ((void));
+static FILE *mips_make_temp_file PROTO ((void));
static void save_restore_insns PROTO ((int, rtx,
long, FILE *));
static void mips16_output_gp_offset PROTO ((FILE *, rtx));
static void dump_constants PROTO ((struct constant *,
rtx));
static rtx mips_find_symbol PROTO ((rtx));
-
+static void abort_with_insn PROTO ((rtx, const char *))
+ ATTRIBUTE_NORETURN;
+static int symbolic_expression_p PROTO ((rtx));
+static void mips_add_gc_roots PROTO ((void));
/* Global variables for machine-dependent things. */
struct extern_list
{
struct extern_list *next; /* next external */
- char *name; /* name of the external */
+ const char *name; /* name of the external */
int size; /* size in bytes */
} *extern_head = 0;
/* Name of the file containing the current function. */
-char *current_function_file = "";
+const char *current_function_file = "";
/* Warning given that Mips ECOFF can't support changing files
within a function. */
#endif
/* 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,4} */
-char *mips_abi_string; /* for -mabi={o32,32,n32,n64,64,eabi} */
+const char *mips_cpu_string; /* for -mcpu=<xxx> */
+const char *mips_isa_string; /* for -mips{1,2,3,4} */
+const char *mips_abi_string; /* for -mabi={32,n32,64,eabi} */
/* Whether we are generating mips16 code. This is a synonym for
TARGET_MIPS16, and exists for use as an attribute. */
/* This variable is set by -mno-mips16. We only care whether
-mno-mips16 appears or not, and using a string in this fashion is
just a way to avoid using up another bit in target_flags. */
-char *mips_no_mips16_string;
+const char *mips_no_mips16_string;
+
+/* This is only used to determine if an type size setting option was
+ explicitly specified (-mlong64, -mint64, -mlong32). The specs
+ set this option if such an option is used. */
+const char *mips_explicit_type_size_string;
/* Whether we are generating mips16 hard float code. In mips16 mode
we always set TARGET_SOFT_FLOAT; this variable is nonzero if
/* This variable is set by -mentry. We only care whether -mentry
appears or not, and using a string in this fashion is just a way to
avoid using up another bit in target_flags. */
-char *mips_entry_string;
+const char *mips_entry_string;
/* Whether we should entry and exit pseudo-ops in mips16 mode. */
int mips_entry;
initialized in override_options. */
REAL_VALUE_TYPE dfhigh, dflow, sfhigh, sflow;
+/* Mode used for saving/restoring general purpose registers. */
+static enum machine_mode gpr_mode;
+
/* Array giving truth value on whether or not a given hard register
can support a given mode. */
char mips_hard_regno_mode_ok[(int)MAX_MACHINE_MODE][FIRST_PSEUDO_REGISTER];
struct string_constant
{
struct string_constant *next;
- char *label;
+ const char *label;
};
static struct string_constant *string_constants;
int
small_int (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
}
int
large_int (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
HOST_WIDE_INT value;
return 0;
}
+/* Return truth value of whether OP is a register or the constant 0,
+ even in mips16 mode. */
+
+int
+true_reg_or_0_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ switch (GET_CODE (op))
+ {
+ case CONST_INT:
+ return INTVAL (op) == 0;
+
+ case CONST_DOUBLE:
+ return op == CONST0_RTX (mode);
+
+ case REG:
+ case SUBREG:
+ return register_operand (op, mode);
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
/* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */
int
return 1;
/* ??? li.s does not work right with SGI's Irix 6 assembler. */
- if (mips_abi != ABI_32 && mips_abi != ABI_EABI)
+ if (mips_abi != ABI_32 && mips_abi != ABI_O64 && mips_abi != ABI_EABI)
return 0;
REAL_VALUE_FROM_CONST_DOUBLE (d, op);
int
pc_or_label_operand (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (op == pc_rtx)
return 1;
int
call_insn_operand (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return (CONSTANT_ADDRESS_P (op)
|| (GET_CODE (op) == REG && op != arg_pointer_rtx
int
consttable_operand (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return CONSTANT_P (op);
}
int
m16_uimm3_b (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return m16_check_op (op, 0x1, 0x8, 0);
}
int
m16_simm4_1 (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return m16_check_op (op, - 0x8, 0x7, 0);
}
int
m16_nsimm4_1 (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return m16_check_op (op, - 0x7, 0x8, 0);
}
int
m16_simm5_1 (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return m16_check_op (op, - 0x10, 0xf, 0);
}
int
m16_nsimm5_1 (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return m16_check_op (op, - 0xf, 0x10, 0);
}
int
m16_uimm5_4 (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return m16_check_op (op, (- 0x10) << 2, 0xf << 2, 3);
}
int
m16_nuimm5_4 (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return m16_check_op (op, (- 0xf) << 2, 0x10 << 2, 3);
}
int
m16_simm8_1 (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return m16_check_op (op, - 0x80, 0x7f, 0);
}
int
m16_nsimm8_1 (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return m16_check_op (op, - 0x7f, 0x80, 0);
}
int
m16_uimm8_1 (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return m16_check_op (op, 0x0, 0xff, 0);
}
int
m16_nuimm8_1 (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return m16_check_op (op, - 0xff, 0x0, 0);
}
int
m16_uimm8_m1_1 (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return m16_check_op (op, - 0x1, 0xfe, 0);
}
int
m16_uimm8_4 (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return m16_check_op (op, 0x0, 0xff << 2, 3);
}
int
m16_nuimm8_4 (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return m16_check_op (op, (- 0xff) << 2, 0x0, 3);
}
int
m16_simm8_8 (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return m16_check_op (op, (- 0x80) << 3, 0x7f << 3, 7);
}
int
m16_nsimm8_8 (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return m16_check_op (op, (- 0x7f) << 3, 0x80 << 3, 7);
}
int
m16_usym8_4 (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (GET_CODE (op) == SYMBOL_REF
&& SYMBOL_REF_FLAG (op)
int
m16_usym5_4 (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (GET_CODE (op) == SYMBOL_REF
&& SYMBOL_REF_FLAG (op)
/* ??? This function no longer does anything useful, because final_prescan_insn
now will never emit a nop. */
-char *
+const char *
mips_fill_delay_slot (ret, type, operands, cur_insn)
- char *ret; /* normal string to return */
+ const char *ret; /* normal string to return */
enum delay_type type; /* type of delay */
rtx operands[]; /* operands to use */
rtx cur_insn; /* current insn */
mips_load_reg = set_reg;
if (GET_MODE_SIZE (mode)
> (FP_REG_P (REGNO (set_reg)) ? UNITS_PER_FPREG : UNITS_PER_WORD))
- mips_load_reg2 = gen_rtx (REG, SImode, REGNO (set_reg) + 1);
+ mips_load_reg2 = gen_rtx_REG (SImode, REGNO (set_reg) + 1);
else
mips_load_reg2 = 0;
if (type == DELAY_HILO)
{
- mips_load_reg3 = gen_rtx (REG, SImode, MD_REG_FIRST);
- mips_load_reg4 = gen_rtx (REG, SImode, MD_REG_FIRST+1);
+ mips_load_reg3 = gen_rtx_REG (SImode, MD_REG_FIRST);
+ mips_load_reg4 = gen_rtx_REG (SImode, MD_REG_FIRST+1);
}
else
{
pop_topmost_sequence ();
}
- return gen_rtx (CONST, Pmode,
- gen_rtx (MINUS, Pmode, x,
- XEXP (DECL_RTL (current_function_decl), 0)));
+ return
+ gen_rtx_CONST (Pmode,
+ gen_rtx_MINUS (Pmode, x,
+ XEXP (DECL_RTL (current_function_decl), 0)));
}
/* Return the appropriate instructions to move one operand to another. */
-char *
+const char *
mips_move_1word (operands, insn, unsignedp)
rtx operands[];
rtx insn;
int unsignedp;
{
- char *ret = 0;
+ const char *ret = 0;
rtx op0 = operands[0];
rtx op1 = operands[1];
enum rtx_code code0 = GET_CODE (op0);
if (ret != (char *)0 && MEM_VOLATILE_P (op1))
{
- int i = strlen (ret);
+ size_t i = strlen (ret);
if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
abort ();
if (ret != 0 && MEM_VOLATILE_P (op0))
{
- int i = strlen (ret);
+ size_t i = strlen (ret);
if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
abort ();
\f
/* Return the appropriate instructions to move 2 words */
-char *
+const char *
mips_move_2words (operands, insn)
rtx operands[];
rtx insn;
{
- char *ret = 0;
+ const char *ret = 0;
rtx op0 = operands[0];
rtx op1 = operands[1];
enum rtx_code code0 = GET_CODE (operands[0]);
if (ret != 0 && MEM_VOLATILE_P (op1))
{
- int i = strlen (ret);
+ size_t i = strlen (ret);
if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
abort ();
if (ret != 0 && MEM_VOLATILE_P (op0))
{
- int i = strlen (ret);
+ size_t i = strlen (ret);
if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
abort ();
&& p_info->const_add != 0
&& ((p_info->unsignedp
? ((unsigned HOST_WIDE_INT) (value + p_info->const_add)
- > INTVAL (cmp1))
+ > (unsigned HOST_WIDE_INT) INTVAL (cmp1))
: (value + p_info->const_add) > INTVAL (cmp1))
!= (p_info->const_add > 0))))
cmp1 = force_reg (mode, cmp1);
we would get the wrong answer if we follow the usual path;
thus, x > 0xffffffffU would turn into x > 0U. */
if ((p_info->unsignedp
- ? (unsigned HOST_WIDE_INT) new > INTVAL (cmp1)
+ ? (unsigned HOST_WIDE_INT) new >
+ (unsigned HOST_WIDE_INT) INTVAL (cmp1)
: new > INTVAL (cmp1))
!= (p_info->const_add > 0))
{
else if (test == ITEST_EQ)
{
reg2 = invert ? gen_reg_rtx (mode) : result;
- convert_move (reg2, gen_rtx (LTU, mode, reg, const1_rtx), 0);
+ convert_move (reg2, gen_rtx_LTU (mode, reg, const1_rtx), 0);
reg = reg2;
}
case CMP_SF:
case CMP_DF:
if (mips_isa < 4)
- reg = gen_rtx (REG, CCmode, FPSW_REGNUM);
+ reg = gen_rtx_REG (CCmode, FPSW_REGNUM);
else
reg = gen_reg_rtx (CCmode);
0 in the instruction built below. The MIPS FPU handles
inequality testing by testing for equality and looking for a
false result. */
- emit_insn (gen_rtx (SET, VOIDmode, reg,
- gen_rtx (test_code == NE ? EQ : test_code,
- CCmode, cmp0, cmp1)));
-
+ emit_insn (gen_rtx_SET (VOIDmode, reg,
+ gen_rtx (test_code == NE ? EQ : test_code,
+ CCmode, cmp0, cmp1)));
+
test_code = test_code == NE ? EQ : NE;
mode = CCmode;
cmp0 = reg;
/* Generate the branch. */
- label1 = gen_rtx (LABEL_REF, VOIDmode, operands[0]);
+ label1 = gen_rtx_LABEL_REF (VOIDmode, operands[0]);
label2 = pc_rtx;
if (invert)
label1 = pc_rtx;
}
- emit_jump_insn (gen_rtx (SET, VOIDmode, pc_rtx,
- gen_rtx (IF_THEN_ELSE, VOIDmode,
- gen_rtx (test_code, mode, cmp0, cmp1),
- label1, label2)));
+ emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
+ gen_rtx_IF_THEN_ELSE (VOIDmode,
+ gen_rtx (test_code, mode,
+ cmp0, cmp1),
+ label1, label2)));
}
/* Emit the common code for conditional moves. OPERANDS is the array
abort ();
cmp_reg = gen_reg_rtx (cmp_mode);
- emit_insn (gen_rtx (SET, cmp_mode, cmp_reg,
- gen_rtx (cmp_code, cmp_mode, op0, op1)));
-
- emit_insn (gen_rtx (SET, op_mode, operands[0],
- gen_rtx (IF_THEN_ELSE, op_mode,
- gen_rtx (move_code, VOIDmode,
- cmp_reg, CONST0_RTX (SImode)),
- operands[2], operands[3])));
+ emit_insn (gen_rtx_SET (cmp_mode, cmp_reg,
+ gen_rtx (cmp_code, cmp_mode, op0, op1)));
+
+ emit_insn (gen_rtx_SET (op_mode, operands[0],
+ gen_rtx_IF_THEN_ELSE (op_mode,
+ gen_rtx (move_code, VOIDmode,
+ cmp_reg,
+ CONST0_RTX (SImode)),
+ operands[2], operands[3])));
}
\f
/* Write a loop to move a constant number of bytes.
bytes_rtx = convert_to_mode (Pmode, bytes_rtx, 1);
#ifdef TARGET_MEM_FUNCTIONS
- emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), 0,
+ emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "memcpy"), 0,
VOIDmode, 3, dest_reg, Pmode, src_reg, Pmode,
convert_to_mode (TYPE_MODE (sizetype), bytes_rtx,
TREE_UNSIGNED (sizetype)),
TYPE_MODE (sizetype));
#else
- emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcopy"), 0,
+ emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "bcopy"), 0,
VOIDmode, 3, src_reg, Pmode, dest_reg, Pmode,
convert_to_mode (TYPE_MODE (integer_type_node), bytes_rtx,
TREE_UNSIGNED (integer_type_node)),
if (TARGET_MEMCPY)
block_move_call (dest_reg, src_reg, bytes_rtx);
+ else if (constp && bytes <= 2 * MAX_MOVE_BYTES
+ && align == UNITS_PER_WORD)
+ move_by_pieces (orig_dest, orig_src, bytes, align);
+
else if (constp && bytes <= 2 * MAX_MOVE_BYTES)
emit_insn (gen_movstrsi_internal (change_address (orig_dest, BLKmode,
dest_reg),
BLOCK_MOVE_NOT_LAST Do all but the last store.
BLOCK_MOVE_LAST Do just the last store. */
-char *
+const char *
output_block_move (insn, operands, num_regs, move_type)
rtx insn;
rtx operands[];
rtx xoperands[10];
struct {
- char *load; /* load insn without nop */
- char *load_nop; /* load insn with trailing nop */
- char *store; /* store insn */
- char *final; /* if last_store used: NULL or swr */
- char *last_store; /* last store instruction */
+ const char *load; /* load insn without nop */
+ const char *load_nop; /* load insn with trailing nop */
+ const char *store; /* store insn */
+ const char *final; /* if last_store used: NULL or swr */
+ const char *last_store; /* last store instruction */
int offset; /* current offset */
enum machine_mode mode; /* mode to use on (MEM) */
} load_store[4];
the number of registers available. */
for (i = 4;
i < last_operand
- && safe_regs < (sizeof(xoperands) / sizeof(xoperands[0]));
+ && safe_regs < (int)(sizeof(xoperands) / sizeof(xoperands[0]));
i++)
if (! reg_mentioned_p (operands[i], operands[0])
&& ! reg_mentioned_p (operands[i], operands[1]))
}
}
- if (num_regs > sizeof (load_store) / sizeof (load_store[0]))
+ if (num_regs > (int)(sizeof (load_store) / sizeof (load_store[0])))
num_regs = sizeof (load_store) / sizeof (load_store[0]);
else if (num_regs < 1)
abort ();
if (GET_MODE (operands[i + 4]) != load_store[i].mode)
- operands[i + 4] = gen_rtx (REG, load_store[i].mode,
- REGNO (operands[i + 4]));
+ operands[i + 4] = gen_rtx_REG (load_store[i].mode,
+ REGNO (operands[i + 4]));
offset = load_store[i].offset;
xoperands[0] = operands[i + 4];
- xoperands[1] = gen_rtx (MEM, load_store[i].mode,
- plus_constant (src_reg, offset));
+ xoperands[1] = gen_rtx_MEM (load_store[i].mode,
+ plus_constant (src_reg, offset));
if (use_lwl_lwr)
{
int 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));
+ xoperands[2] = gen_rtx_MEM (load_store[i].mode,
+ plus_constant (src_reg,
+ extra_offset
+ + offset));
}
output_asm_insn (load_store[i].load, xoperands);
int offset = load_store[i].offset;
xoperands[0] = operands[i + 4];
- xoperands[1] = gen_rtx (MEM, load_store[i].mode,
- plus_constant (dest_reg, offset));
+ xoperands[1] = gen_rtx_MEM (load_store[i].mode,
+ plus_constant (dest_reg, offset));
if (use_lwl_lwr)
{
int 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));
+ xoperands[2] = gen_rtx_MEM (load_store[i].mode,
+ plus_constant (dest_reg,
+ extra_offset
+ + offset));
}
if (move_type == BLOCK_MOVE_NORMAL)
void
init_cumulative_args (cum, fntype, libname)
- CUMULATIVE_ARGS *cum; /* argument info to initialize */
- tree fntype; /* tree ptr for function decl */
- rtx libname; /* SYMBOL_REF of library name or 0 */
+ CUMULATIVE_ARGS *cum; /* argument info to initialize */
+ tree fntype; /* tree ptr for function decl */
+ rtx libname ATTRIBUTE_UNUSED; /* SYMBOL_REF of library name or 0 */
{
static CUMULATIVE_ARGS zero_cum;
tree param, next_param;
int named; /* whether or not the argument was named */
{
if (TARGET_DEBUG_E_MODE)
- fprintf (stderr,
- "function_adv({gp reg found = %d, arg # = %2d, words = %2d}, %4s, 0x%.8x, %d )\n\n",
- cum->gp_reg_found, cum->arg_number, cum->arg_words,
- GET_MODE_NAME (mode), type, named);
+ {
+ fprintf (stderr,
+ "function_adv({gp reg found = %d, arg # = %2d, words = %2d}, %4s, ",
+ cum->gp_reg_found, cum->arg_number, cum->arg_words,
+ GET_MODE_NAME (mode));
+ fprintf (stderr, HOST_PTR_PRINTF, type);
+ fprintf (stderr, ", %d )\n\n", named);
+ }
cum->arg_number++;
switch (mode)
|| TREE_CODE (type) == QUAL_UNION_TYPE));
if (TARGET_DEBUG_E_MODE)
- fprintf (stderr,
- "function_arg( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, 0x%.8x, %d ) = ",
- cum->gp_reg_found, cum->arg_number, cum->arg_words,
- GET_MODE_NAME (mode), type, named);
+ {
+ fprintf (stderr,
+ "function_arg( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, ",
+ cum->gp_reg_found, cum->arg_number, cum->arg_words,
+ GET_MODE_NAME (mode));
+ fprintf (stderr, HOST_PTR_PRINTF, type);
+ fprintf (stderr, ", %d ) = ", named);
+ }
+
cum->last_arg_fp = 0;
switch (mode)
{
case SFmode:
- if (mips_abi == ABI_32)
+ if (mips_abi == ABI_32 || mips_abi == ABI_O64)
{
if (cum->gp_reg_found || cum->arg_number >= 2 || TARGET_SOFT_FLOAT)
regbase = GP_ARG_FIRST;
cum->arg_words += cum->arg_words & 1;
}
- if (mips_abi == ABI_32)
+ if (mips_abi == ABI_32 || mips_abi == ABI_O64)
regbase = ((cum->gp_reg_found
|| TARGET_SOFT_FLOAT || TARGET_SINGLE_FLOAT
|| cum->arg_number >= 2)
/* Drops through. */
case BLKmode:
- if (type != (tree)0 && TYPE_ALIGN (type) > BITS_PER_WORD
+ if (type != (tree)0 && TYPE_ALIGN (type) > (unsigned) BITS_PER_WORD
&& ! TARGET_64BIT && mips_abi != ABI_EABI)
cum->arg_words += (cum->arg_words & 1);
regbase = GP_ARG_FIRST;
abort ();
if (! type || TREE_CODE (type) != RECORD_TYPE || mips_abi == ABI_32
- || mips_abi == ABI_EABI || ! named)
- ret = gen_rtx (REG, mode, regbase + *arg_words + bias);
+ || mips_abi == ABI_EABI || mips_abi == ABI_O64 || ! named)
+ ret = gen_rtx_REG (mode, regbase + *arg_words + bias);
else
{
/* The Irix 6 n32/n64 ABIs say that if any 64 bit chunk of the
/* If the whole struct fits a DFmode register,
we don't need the PARALLEL. */
if (! field || mode == DFmode)
- ret = gen_rtx (REG, mode, regbase + *arg_words + bias);
+ ret = gen_rtx_REG (mode, regbase + *arg_words + bias);
else
{
/* Now handle the special case by returning a PARALLEL
/* assign_parms checks the mode of ENTRY_PARM, so we must
use the actual mode here. */
- ret = gen_rtx (PARALLEL, mode, rtvec_alloc (chunks));
+ ret = gen_rtx_PARALLEL (mode, rtvec_alloc (chunks));
bitpos = 0;
regno = regbase + *arg_words + bias;
&& TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field)) == bitpos
&& TREE_CODE (TREE_TYPE (field)) == REAL_TYPE
&& TYPE_PRECISION (TREE_TYPE (field)) == BITS_PER_WORD)
- reg = gen_rtx (REG, DFmode,
- regno + FP_ARG_FIRST - GP_ARG_FIRST);
+ reg = gen_rtx_REG (DFmode,
+ regno + FP_ARG_FIRST - GP_ARG_FIRST);
else
- reg = gen_rtx (REG, word_mode, regno);
-
+ reg = gen_rtx_REG (word_mode, regno);
+
XVECEXP (ret, 0, i)
- = gen_rtx (EXPR_LIST, VOIDmode, reg,
- GEN_INT (bitpos / BITS_PER_UNIT));
+ = gen_rtx_EXPR_LIST (VOIDmode, reg,
+ GEN_INT (bitpos / BITS_PER_UNIT));
bitpos += 64;
regno++;
{
rtx amount = GEN_INT (BITS_PER_WORD
- int_size_in_bytes (type) * BITS_PER_UNIT);
- rtx reg = gen_rtx (REG, word_mode, regbase + *arg_words + bias);
+ rtx reg = gen_rtx_REG (word_mode, regbase + *arg_words + bias);
if (TARGET_64BIT)
cum->adjust[cum->num_adjusts++] = gen_ashldi3 (reg, reg, amount);
CUMULATIVE_ARGS *cum; /* current arg information */
enum machine_mode mode; /* current arg mode */
tree type; /* type of the argument or 0 if lib support */
- int named; /* != 0 for normal args, == 0 for ... args */
+ int named ATTRIBUTE_UNUSED;/* != 0 for normal args, == 0 for ... args */
{
if ((mode == BLKmode
|| GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
return 0;
}
\f
-/* Abort after printing out a specific insn. */
+/* Create the va_list data type. */
+
+tree
+mips_build_va_list ()
+{
+ if (mips_abi == ABI_EABI && !TARGET_SOFT_FLOAT && !TARGET_SINGLE_FLOAT)
+ {
+ tree f_fpr, f_rem, f_gpr, record;
+
+ record = make_node (RECORD_TYPE);
+
+ f_fpr = build_decl (FIELD_DECL, get_identifier ("__fp_regs"),
+ ptr_type_node);
+ f_rem = build_decl (FIELD_DECL, get_identifier ("__fp_left"),
+ integer_type_node);
+ f_gpr = build_decl (FIELD_DECL, get_identifier ("__gp_regs"),
+ ptr_type_node);
+
+ DECL_FIELD_CONTEXT (f_fpr) = record;
+ DECL_FIELD_CONTEXT (f_rem) = record;
+ DECL_FIELD_CONTEXT (f_gpr) = record;
+
+ TYPE_FIELDS (record) = f_fpr;
+ TREE_CHAIN (f_fpr) = f_rem;
+ TREE_CHAIN (f_gpr) = f_gpr;
+
+ layout_type (record);
+
+ return record;
+ }
+ else
+ return ptr_type_node;
+}
+
+/* Implement va_start. */
void
+mips_va_start (stdarg_p, valist, nextarg)
+ int stdarg_p;
+ tree valist;
+ rtx nextarg;
+{
+ int arg_words, fp_arg_words;
+ tree t;
+
+ arg_words = current_function_args_info.arg_words;
+ fp_arg_words = current_function_args_info.fp_arg_words;
+
+ if (mips_abi == ABI_EABI)
+ {
+ if (!TARGET_SOFT_FLOAT && !TARGET_SINGLE_FLOAT)
+ {
+ tree f_fpr, f_rem, f_gpr, fpr, rem, gpr;
+ tree gprv, fprv;
+ int gpro, fpro;
+
+ f_fpr = TYPE_FIELDS (va_list_type_node);
+ f_rem = TREE_CHAIN (f_fpr);
+ f_gpr = TREE_CHAIN (f_gpr);
+
+ fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
+ rem = build (COMPONENT_REF, TREE_TYPE (f_rem), valist, f_rem);
+ gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
+
+ if (arg_words < 8)
+ gpro = (8 - arg_words) * UNITS_PER_WORD;
+ else
+ gpro = (stdarg_p ? 0 : UNITS_PER_WORD);
+
+ gprv = make_tree (ptr_type_node, nextarg);
+ if (gpro != 0)
+ {
+ gprv = build (PLUS_EXPR, ptr_type_node, gprv,
+ build_int_2 (-gpro, -1));
+ }
+
+ t = build (MODIFY_EXPR, ptr_type_node, gpr, gprv);
+ TREE_SIDE_EFFECTS (t) = 1;
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ t = build (MODIFY_EXPR, integer_type_node, rem,
+ build_int_2 (8 - fp_arg_words, 0));
+ TREE_SIDE_EFFECTS (t) = 1;
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ fpro = (8 - fp_arg_words) * 8;
+ if (fpro == 0)
+ fprv = gprv;
+ else
+ fprv = fold (build (PLUS_EXPR, ptr_type_node, gprv,
+ build_int_2 (-fpro, -1)));
+
+ if (! TARGET_64BIT)
+ fprv = fold (build (BIT_AND_EXPR, ptr_type_node, fprv,
+ build_int_2 (-8, -1)));
+
+ t = build (MODIFY_EXPR, ptr_type_node, fpr, fprv);
+ TREE_SIDE_EFFECTS (t) = 1;
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ }
+ else
+ {
+ int ofs;
+
+ if (arg_words >= 8)
+ ofs = (stdarg_p ? 0 : UNITS_PER_WORD);
+ else
+ ofs = (8 - arg_words) * UNITS_PER_WORD;
+
+ nextarg = plus_constant (nextarg, -ofs);
+ std_expand_builtin_va_start (1, valist, nextarg);
+ }
+ }
+ else
+ {
+ int ofs;
+
+ if (stdarg_p)
+ ofs = 0;
+ else
+ {
+ /* ??? This had been conditional on
+ _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32
+ and both iris5.h and iris6.h define _MIPS_SIM. */
+ if (mips_abi == ABI_N32 || mips_abi == ABI_64)
+ ofs = (arg_words >= 8 ? -UNITS_PER_WORD : 0);
+ else
+ ofs = -UNITS_PER_WORD;
+ }
+
+ nextarg = plus_constant (nextarg, ofs);
+ std_expand_builtin_va_start (1, valist, nextarg);
+ }
+}
+
+/* Implement va_arg. */
+
+rtx
+mips_va_arg (valist, type)
+ tree valist, type;
+{
+ HOST_WIDE_INT size, rsize;
+ rtx addr_rtx;
+ tree t;
+
+ size = int_size_in_bytes (type);
+ rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
+
+ if (mips_abi == ABI_EABI)
+ {
+ tree gpr;
+ int indirect;
+ rtx lab_over = NULL_RTX, lab_false, r;
+
+ indirect
+ = function_arg_pass_by_reference (NULL, TYPE_MODE (type), type, 0);
+ if (indirect)
+ size = rsize = POINTER_SIZE / BITS_PER_UNIT;
+
+ addr_rtx = gen_reg_rtx (Pmode);
+
+ if (!TARGET_SOFT_FLOAT && !TARGET_SINGLE_FLOAT)
+ {
+ tree f_fpr, f_rem, f_gpr, fpr, rem;
+
+ f_fpr = TYPE_FIELDS (va_list_type_node);
+ f_rem = TREE_CHAIN (f_fpr);
+ f_gpr = TREE_CHAIN (f_gpr);
+
+ fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
+ rem = build (COMPONENT_REF, TREE_TYPE (f_rem), valist, f_rem);
+ gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
+
+ if (TREE_CODE (type) == REAL_TYPE)
+ {
+ lab_false = gen_label_rtx ();
+ lab_over = gen_label_rtx ();
+
+ r = expand_expr (rem, NULL_RTX, TYPE_MODE (TREE_TYPE (rem)),
+ EXPAND_NORMAL);
+ emit_cmp_and_jump_insns (r, const0_rtx, LE, const1_rtx,
+ GET_MODE (r), 1, 1, lab_false);
+
+ t = build (PLUS_EXPR, TREE_TYPE (rem), rem,
+ build_int_2 (-1, -1));
+ t = build (MODIFY_EXPR, TREE_TYPE (rem), rem, t);
+ TREE_SIDE_EFFECTS (t) = 1;
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ t = build (POSTINCREMENT_EXPR, TREE_TYPE (fpr), fpr,
+ build_int_2 (8, 0));
+ TREE_SIDE_EFFECTS (t) = 1;
+ r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
+ if (r != addr_rtx)
+ emit_move_insn (addr_rtx, r);
+
+ emit_jump (gen_jump (lab_over));
+ emit_barrier ();
+ emit_label (lab_false);
+ }
+ }
+ else
+ gpr = valist;
+
+ if (! indirect
+ && ! TARGET_64BIT
+ && TYPE_ALIGN (type) > (unsigned) BITS_PER_WORD)
+ {
+ t = build (PLUS_EXPR, TREE_TYPE (gpr), gpr,
+ build_int_2 (2*UNITS_PER_WORD - 1, 0));
+ t = build (BIT_AND_EXPR, TREE_TYPE (t), t,
+ build_int_2 (-2*UNITS_PER_WORD, -1));
+ t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr, t);
+ TREE_SIDE_EFFECTS (t) = 1;
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ }
+
+ t = build (POSTINCREMENT_EXPR, TREE_TYPE (gpr), gpr, rsize);
+ TREE_SIDE_EFFECTS (t) = 1;
+ r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
+ if (r != addr_rtx)
+ emit_move_insn (addr_rtx, r);
+
+ if (lab_over)
+ emit_label (lab_over);
+
+ if (indirect)
+ {
+ r = gen_rtx_MEM (Pmode, addr_rtx);
+ MEM_ALIAS_SET (r) = get_varargs_alias_set ();
+ emit_move_insn (addr_rtx, r);
+ }
+ else
+ {
+ if (BYTES_BIG_ENDIAN && rsize != size)
+ addr_rtx = plus_constant (addr_rtx, rsize - size);
+ }
+ }
+ else
+ {
+ int align;
+
+ /* ??? The original va-mips.h did always align, despite the fact
+ that alignments <= UNITS_PER_WORD are preserved by the va_arg
+ increment mechanism. */
+
+ if (TARGET_64BIT)
+ align = 8;
+ else if (TYPE_ALIGN (type) > 32)
+ align = 8;
+ else
+ align = 4;
+
+ t = build (PLUS_EXPR, TREE_TYPE (valist), valist,
+ build_int_2 (align - 1, 0));
+ t = build (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-align, -1));
+ t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
+ TREE_SIDE_EFFECTS (t) = 1;
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ /* Everything past the alignment is standard. */
+ return std_expand_builtin_va_arg (valist, type);
+ }
+}
+\f
+/* Abort after printing out a specific insn. */
+
+static void
abort_with_insn (insn, reason)
rtx insn;
- char *reason;
+ const char *reason;
{
error (reason);
debug_rtx (insn);
abort ();
}
-
-/* Write a message to stderr (for use in macros expanded in files that do not
- include stdio.h). */
-
-void
-trace (s, s1, s2)
- char *s, *s1, *s2;
-{
- fprintf (stderr, s, s1, s2);
-}
\f
/* Set up the threshold for data to go into the small data area, instead
of the normal data area, and detect any conflicts in the switches. */
if (mips_isa_string == 0)
mips_isa = MIPS_ISA_DEFAULT;
- else if (isdigit (*mips_isa_string))
+ else if (ISDIGIT (*mips_isa_string))
{
mips_isa = atoi (mips_isa_string);
if (mips_isa == 16)
}
#ifdef MIPS_ABI_DEFAULT
- /* Get the ABI to use. Currently this code is only used for Irix 6. */
+ /* Get the ABI to use. */
if (mips_abi_string == (char *) 0)
mips_abi = MIPS_ABI_DEFAULT;
- else if (! strcmp (mips_abi_string, "32")
- || ! strcmp (mips_abi_string, "o32"))
+ else if (! strcmp (mips_abi_string, "32"))
mips_abi = ABI_32;
+ else if (! strcmp (mips_abi_string, "o64"))
+ mips_abi = ABI_O64;
else if (! strcmp (mips_abi_string, "n32"))
mips_abi = ABI_N32;
- else if (! strcmp (mips_abi_string, "64")
- || ! strcmp (mips_abi_string, "n64"))
+ else if (! strcmp (mips_abi_string, "64"))
mips_abi = ABI_64;
else if (! strcmp (mips_abi_string, "eabi"))
mips_abi = ABI_EABI;
error ("bad value (%s) for -mabi= switch", mips_abi_string);
/* A specified ISA defaults the ABI if it was not specified. */
- if (mips_abi_string == 0 && mips_isa_string && mips_abi != ABI_EABI)
+ if (mips_abi_string == 0 && mips_isa_string
+ && mips_abi != ABI_EABI && mips_abi != ABI_O64)
{
if (mips_isa <= 2)
mips_abi = ABI_32;
}
/* A specified ABI defaults the ISA if it was not specified. */
- else if (mips_isa_string == 0 && mips_abi_string && mips_abi != ABI_EABI)
+ else if (mips_isa_string == 0 && mips_abi_string
+ && mips_abi != ABI_EABI && mips_abi != ABI_O64)
{
if (mips_abi == ABI_32)
mips_isa = 1;
/* If both ABI and ISA were specified, check for conflicts. */
else if (mips_isa_string && mips_abi_string)
{
- if ((mips_isa <= 2 && (mips_abi == ABI_N32 || mips_abi == ABI_64))
+ if ((mips_isa <= 2 && (mips_abi == ABI_N32 || mips_abi == ABI_64
+ || mips_abi == ABI_O64))
|| (mips_isa >= 3 && mips_abi == ABI_32))
error ("-mabi=%s does not support -mips%d", mips_abi_string, mips_isa);
}
if (mips_abi == ABI_32)
target_flags &= ~ (MASK_FLOAT64|MASK_64BIT);
- /* In the EABI in 64 bit mode, longs and pointers are 64 bits. Likewise
- for the SGI Irix6 N64 ABI. */
- if ((mips_abi == ABI_EABI && TARGET_64BIT)
- || mips_abi == ABI_64)
+ /* If no type size setting options (-mlong64,-mint64,-mlong32) were used
+ then set the type sizes. In the EABI in 64 bit mode, longs and
+ pointers are 64 bits. Likewise for the SGI Irix6 N64 ABI. */
+ if (mips_explicit_type_size_string == NULL
+ && ((mips_abi == ABI_EABI && TARGET_64BIT)
+ || mips_abi == ABI_64))
target_flags |= MASK_LONG64;
/* ??? This doesn't work yet, so don't let people try to use it. */
else
{
- char *p = mips_cpu_string;
+ const char *p = mips_cpu_string;
int seen_v = 0;
/* We need to cope with the various "vr" prefixes for the NEC 4300
mips_cpu = PROCESSOR_DEFAULT;
switch (*p)
{
- /* start-sanitize-tx19 */
- case '1':
- if (!strcmp (p, "1900"))
- mips_cpu = PROCESSOR_R3900;
- break;
- /* end-sanitize-tx19 */
-
case '2':
if (!strcmp (p, "2000") || !strcmp (p, "2k") || !strcmp (p, "2K"))
mips_cpu = PROCESSOR_R3000;
/* make sure sizes of ints/longs/etc. are ok */
if (mips_isa < 3)
{
- if (TARGET_INT64)
- fatal ("Only MIPS-III or MIPS-IV CPUs can support 64 bit ints");
-
- else if (TARGET_LONG64)
- fatal ("Only MIPS-III or MIPS-IV CPUs can support 64 bit longs");
-
- else if (TARGET_FLOAT64)
+ if (TARGET_FLOAT64)
fatal ("Only MIPS-III or MIPS-IV CPUs can support 64 bit fp registers");
else if (TARGET_64BIT)
fatal ("Only MIPS-III or MIPS-IV CPUs can support 64 bit gp registers");
}
- if (mips_abi != ABI_32)
+ if (mips_abi != ABI_32 && mips_abi != ABI_O64)
flag_pcc_struct_return = 0;
/* Tell halfpic.c that we have half-pic code if we do. */
mips_print_operand_punct['^'] = 1;
mips_print_operand_punct['$'] = 1;
mips_print_operand_punct['+'] = 1;
+ mips_print_operand_punct['~'] = 1;
mips_char_to_class['d'] = TARGET_MIPS16 ? M16_REGS : GR_REGS;
mips_char_to_class['e'] = M16_NA_REGS;
mips_hard_regno_mode_ok[(int)mode][regno] = temp;
}
}
+
+ /* Save GPR registers in word_mode sized hunks. word_mode hasn't been
+ initialized yet, so we can't use that here. */
+ gpr_mode = TARGET_64BIT ? DImode : SImode;
+
+ /* Provide default values for align_* for 64-bit targets. */
+ if (TARGET_64BIT)
+ {
+ if (align_loops == 0)
+ align_loops = 8;
+ if (align_jumps == 0)
+ align_jumps = 8;
+ if (align_functions == 0)
+ align_functions = 8;
+ }
+
+ /* Register global variables with the garbage collector. */
+ mips_add_gc_roots ();
}
/* On the mips16, we want to allocate $24 (T_REG) before other
? compute_frame_size (get_frame_size ())
: current_frame_info.total_size;
+ /* MIPS16 frame is smaller */
+ if (frame_pointer_needed && TARGET_MIPS16)
+ frame_size -= current_function_outgoing_args_size;
+
offset = offset - frame_size;
}
'L' print low-order register of double-word register operand.
'M' print high-order register of double-word register operand.
'C' print part of opcode for a branch condition.
+ 'F' print part of opcode for a floating-point branch condition.
'N' print part of opcode for a branch condition, inverted.
+ 'W' print part of opcode for a floating-point 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
'.' Print the name of the register with a hard-wired zero (zero or $0).
'^' Print the name of the pic call-through register (t9 or $25).
'$' Print the name of the stack pointer register (sp or $29).
- '+' Print the name of the gp register (gp or $28). */
+ '+' Print the name of the gp register (gp or $28).
+ '~' Output an branch alignment to LABEL_ALIGN(NULL). */
void
print_operand (file, op, letter)
break;
+ case '~':
+ {
+ if (align_labels_log > 0)
+ ASM_OUTPUT_ALIGN (file, align_labels_log);
+ }
+ break;
+
default:
error ("PRINT_OPERAND: Unknown punctuation '%c'", letter);
break;
abort_with_insn (op, "PRINT_OPERAND, invalid insn for %%N");
}
+ else if (letter == 'F')
+ switch (code)
+ {
+ case EQ: fputs ("c1f", file); break;
+ case NE: fputs ("c1t", file); break;
+ default:
+ abort_with_insn (op, "PRINT_OPERAND, invalid insn for %%F");
+ }
+
+ else if (letter == 'W')
+ switch (code)
+ {
+ case EQ: fputs ("c1t", file); break;
+ case NE: fputs ("c1f", file); break;
+ default:
+ abort_with_insn (op, "PRINT_OPERAND, invalid insn for %%W");
+ }
+
else if (letter == 'S')
{
char buffer[100];
int
mips_output_external (file, decl, name)
- FILE *file;
+ FILE *file ATTRIBUTE_UNUSED;
tree decl;
- char *name;
+ const char *name;
{
register struct extern_list *p;
int len;
int
mips_output_external_libcall (file, name)
FILE *file;
- char *name;
+ const char *name;
{
register struct extern_list *p;
#endif
static FILE *
-make_temp_file ()
+mips_make_temp_file ()
{
FILE *stream;
- char *base = getenv ("TMPDIR");
+ const char *base = getenv ("TMPDIR");
int len;
if (base == 0)
void
mips_output_filename (stream, name)
FILE *stream;
- char *name;
+ const char *name;
{
static int first_time = 1;
char ltext_label_name[100];
void
final_prescan_insn (insn, opvec, noperands)
rtx insn;
- rtx opvec[];
- int noperands;
+ rtx opvec[] ATTRIBUTE_UNUSED;
+ int noperands ATTRIBUTE_UNUSED;
{
if (dslots_number_nops > 0)
{
/* Start a section, so that the first .popsection directive is guaranteed
to have a previously defined section to pop back to. */
- if (mips_abi != ABI_32 && mips_abi != ABI_EABI)
+ if (mips_abi != ABI_32 && mips_abi != ABI_O64 && mips_abi != ABI_EABI)
fprintf (stream, "\t.section\t.text\n");
/* This code exists so that we can put all externs before all symbol
if (TARGET_FILE_SWITCHING && ! TARGET_MIPS16)
{
asm_out_data_file = stream;
- asm_out_text_file = make_temp_file ();
+ asm_out_text_file = mips_make_temp_file ();
}
else
fatal_io_error (temp_filename);
while ((len = fread (buffer, 1, sizeof (buffer), asm_out_text_file)) > 0)
- if (fwrite (buffer, 1, len, file) != len)
+ if ((int) fwrite (buffer, 1, len, file) != len)
pfatal_with_name (asm_file_name);
if (len < 0)
void
mips_declare_object (stream, name, init_string, final_string, size)
FILE *stream;
- char *name;
- char *init_string;
- char *final_string;
+ const char *name;
+ const char *init_string;
+ const char *final_string;
int size;
{
fputs (init_string, stream); /* "", "\t.comm\t", or "\t.lcomm\t" */
|| (GET_MODE_SIZE (DECL_MODE (DECL_RESULT (current_function_decl)))
<= 4))))
{
- gp_reg_size += UNITS_PER_WORD;
+ gp_reg_size += GET_MODE_SIZE (gpr_mode);
mask |= 1L << (regno - GP_REG_FIRST);
/* The entry and exit pseudo instructions can not save $17
fp_bits = 3;
}
- for (regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno += fp_inc)
+ /* This loop must iterate over the same space as its companion in
+ save_restore_regs. */
+ for (regno = (FP_REG_LAST - fp_inc + 1);
+ regno >= FP_REG_FIRST;
+ regno -= fp_inc)
{
if (regs_ever_live[regno] && !call_used_regs[regno])
{
The gp reg is callee saved in the 64 bit ABI, so all routines must
save the gp reg. This is not a leaf routine if -p, because of the
call to mcount. */
- if (total_size == extra_size && (mips_abi == ABI_32 || mips_abi == ABI_EABI)
+ if (total_size == extra_size
+ && (mips_abi == ABI_32 || mips_abi == ABI_O64 || mips_abi == ABI_EABI)
&& ! profile_flag)
total_size = extra_size = 0;
else if (TARGET_ABICALLS)
/* Add in space reserved on the stack by the callee for storing arguments
passed in registers. */
- if (mips_abi != ABI_32)
+ if (mips_abi != ABI_32 && mips_abi != ABI_O64)
total_size += MIPS_STACK_ALIGN (current_function_pretend_args_size);
/* The entry pseudo instruction will allocate 32 bytes on the stack. */
top of the stack. */
if (! mips_entry)
offset = (args_size + extra_size + var_size
- + gp_reg_size - UNITS_PER_WORD);
+ + gp_reg_size - GET_MODE_SIZE (gpr_mode));
else
- offset = total_size - UNITS_PER_WORD;
+ offset = total_size - GET_MODE_SIZE (gpr_mode);
+
current_frame_info.gp_sp_offset = offset;
current_frame_info.gp_save_offset = offset - total_size;
}
gp_offset = current_frame_info.gp_sp_offset;
end_offset
- = gp_offset - (current_frame_info.gp_reg_size - UNITS_PER_WORD);
+ = gp_offset - (current_frame_info.gp_reg_size
+ - GET_MODE_SIZE (gpr_mode));
if (gp_offset < 0 || end_offset < 0)
fatal ("gp_offset (%ld) or end_offset (%ld) is less than zero.",
- gp_offset, end_offset);
+ (long) gp_offset, (long) end_offset);
/* If we see a large frame in mips16 mode, we save the registers
before adjusting the stack pointer, and load them afterward. */
&& (unsigned HOST_WIDE_INT) (large_offset - gp_offset) < 32768
&& (unsigned HOST_WIDE_INT) (large_offset - end_offset) < 32768)
{
- base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM);
+ base_reg_rtx = gen_rtx_REG (Pmode, MIPS_TEMP2_REGNUM);
base_offset = large_offset;
if (file == 0)
{
else
{
- base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM);
+ base_reg_rtx = gen_rtx_REG (Pmode, MIPS_TEMP2_REGNUM);
base_offset = gp_offset;
if (file == 0)
{
split. */
/* ??? There is no DImode ori immediate pattern, so we can only
do this for 32 bit code. */
- if (large_int (gp_offset_rtx)
+ if (large_int (gp_offset_rtx, GET_MODE (gp_offset_rtx))
&& GET_MODE (base_reg_rtx) == SImode)
{
insn = emit_move_insn (base_reg_rtx,
RTX_FRAME_RELATED_P (insn) = 1;
}
else
- fprintf (file, "\tli\t%s,0x%.08lx\t# %ld\n\t%s\t%s,%s,%s\n",
- reg_names[MIPS_TEMP2_REGNUM],
- base_offset, base_offset,
- Pmode == DImode ? "daddu" : "addu",
- reg_names[MIPS_TEMP2_REGNUM],
- reg_names[MIPS_TEMP2_REGNUM],
- reg_names[STACK_POINTER_REGNUM]);
+ {
+ fprintf (file, "\tli\t%s,0x%.08lx\t# ",
+ reg_names[MIPS_TEMP2_REGNUM], (long) base_offset);
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, base_offset);
+ fprintf (file, "\n\t%s\t%s,%s,%s\n",
+ Pmode == DImode ? "daddu" : "addu",
+ reg_names[MIPS_TEMP2_REGNUM],
+ reg_names[MIPS_TEMP2_REGNUM],
+ reg_names[STACK_POINTER_REGNUM]);
+ }
}
/* When we restore the registers in MIPS16 mode, then if we are
{
rtx reg_rtx;
rtx mem_rtx
- = gen_rtx (MEM, word_mode,
+ = gen_rtx (MEM, gpr_mode,
gen_rtx (PLUS, Pmode, base_reg_rtx,
GEN_INT (gp_offset - base_offset)));
$31, so we load $7 instead, and work things out
in the caller. */
if (TARGET_MIPS16 && ! store_p && regno == GP_REG_FIRST + 31)
- reg_rtx = gen_rtx (REG, word_mode, GP_REG_FIRST + 7);
+ reg_rtx = gen_rtx (REG, gpr_mode, GP_REG_FIRST + 7);
/* The mips16 sometimes needs to save $18. */
else if (TARGET_MIPS16
&& regno != GP_REG_FIRST + 31
&& ! M16_REG_P (regno))
{
if (! store_p)
- reg_rtx = gen_rtx (REG, word_mode, 6);
+ reg_rtx = gen_rtx (REG, gpr_mode, 6);
else
{
- reg_rtx = gen_rtx (REG, word_mode, 3);
+ reg_rtx = gen_rtx (REG, gpr_mode, 3);
emit_move_insn (reg_rtx,
- gen_rtx (REG, word_mode, regno));
+ gen_rtx (REG, gpr_mode, regno));
}
}
else
- reg_rtx = gen_rtx (REG, word_mode, regno);
+ reg_rtx = gen_rtx (REG, gpr_mode, regno);
if (store_p)
{
insn = emit_move_insn (mem_rtx, reg_rtx);
RTX_FRAME_RELATED_P (insn) = 1;
}
- else if (!TARGET_ABICALLS || mips_abi != ABI_32
+ else if (!TARGET_ABICALLS
+ || (mips_abi != ABI_32 && mips_abi != ABI_O64)
|| regno != (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
{
emit_move_insn (reg_rtx, mem_rtx);
if (TARGET_MIPS16
&& regno != GP_REG_FIRST + 31
&& ! M16_REG_P (regno))
- emit_move_insn (gen_rtx (REG, word_mode, regno),
+ emit_move_insn (gen_rtx (REG, gpr_mode, regno),
reg_rtx);
}
}
else
{
- if (store_p || !TARGET_ABICALLS || mips_abi != ABI_32
+ if (store_p || !TARGET_ABICALLS
+ || (mips_abi != ABI_32 && mips_abi != ABI_O64)
|| regno != (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
{
int r = regno;
reg_names[r], reg_names[regno]);
}
}
- fprintf (file, "\t%s\t%s,%ld(%s)\n",
+ fprintf (file, "\t%s\t%s,",
(TARGET_64BIT
? (store_p) ? "sd" : "ld"
: (store_p) ? "sw" : "lw"),
- reg_names[r],
- gp_offset - base_offset,
- reg_names[REGNO(base_reg_rtx)]);
+ reg_names[r]);
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC,
+ gp_offset - base_offset);
+ fprintf (file, "(%s)\n", reg_names[REGNO(base_reg_rtx)]);
if (! store_p
&& TARGET_MIPS16
&& regno != GP_REG_FIRST + 31
}
}
- gp_offset -= UNITS_PER_WORD;
+ gp_offset -= GET_MODE_SIZE (gpr_mode);
}
}
else
if (fp_offset < 0 || end_offset < 0)
fatal ("fp_offset (%ld) or end_offset (%ld) is less than zero.",
- fp_offset, end_offset);
+ (long) fp_offset, (long) end_offset);
else if (fp_offset < 32768)
base_reg_rtx = stack_pointer_rtx, base_offset = 0;
&& (unsigned HOST_WIDE_INT) (large_offset - fp_offset) < 32768
&& (unsigned HOST_WIDE_INT) (large_offset - end_offset) < 32768)
{
- base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM);
+ base_reg_rtx = gen_rtx_REG (Pmode, MIPS_TEMP2_REGNUM);
base_offset = large_offset;
if (file == 0)
{
else
{
- base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM);
+ base_reg_rtx = gen_rtx_REG (Pmode, MIPS_TEMP2_REGNUM);
base_offset = fp_offset;
if (file == 0)
{
split. */
/* ??? There is no DImode ori immediate pattern, so we can only
do this for 32 bit code. */
- if (large_int (fp_offset_rtx)
+ if (large_int (fp_offset_rtx, GET_MODE (fp_offset_rtx))
&& GET_MODE (base_reg_rtx) == SImode)
{
insn = emit_move_insn (base_reg_rtx,
RTX_FRAME_RELATED_P (insn) = 1;
}
else
- fprintf (file, "\tli\t%s,0x%.08lx\t# %ld\n\t%s\t%s,%s,%s\n",
- reg_names[MIPS_TEMP2_REGNUM],
- base_offset, base_offset,
- Pmode == DImode ? "daddu" : "addu",
- reg_names[MIPS_TEMP2_REGNUM],
- reg_names[MIPS_TEMP2_REGNUM],
- reg_names[STACK_POINTER_REGNUM]);
+ {
+ fprintf (file, "\tli\t%s,0x%.08lx\t# ",
+ reg_names[MIPS_TEMP2_REGNUM], (long) base_offset);
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, base_offset);
+ fprintf (file, "\n\t%s\t%s,%s,%s\n",
+ Pmode == DImode ? "daddu" : "addu",
+ reg_names[MIPS_TEMP2_REGNUM],
+ reg_names[MIPS_TEMP2_REGNUM],
+ reg_names[STACK_POINTER_REGNUM]);
+ }
}
- for (regno = FP_REG_LAST-1; regno >= FP_REG_FIRST; regno -= fp_inc)
+ /* This loop must iterate over the same space as its companion in
+ compute_frame_size. */
+ for (regno = (FP_REG_LAST - fp_inc + 1);
+ regno >= FP_REG_FIRST;
+ regno -= fp_inc)
if (BITSET_P (fmask, regno - FP_REG_FIRST))
{
if (file == 0)
emit_move_insn (reg_rtx, mem_rtx);
}
else
- fprintf (file, "\t%s\t%s,%ld(%s)\n",
- (TARGET_SINGLE_FLOAT
- ? (store_p ? "s.s" : "l.s")
- : (store_p ? "s.d" : "l.d")),
- reg_names[regno],
- fp_offset - base_offset,
- reg_names[REGNO(base_reg_rtx)]);
+ {
+ fprintf (file, "\t%s\t%s,",
+ (TARGET_SINGLE_FLOAT
+ ? (store_p ? "s.s" : "l.s")
+ : (store_p ? "s.d" : "l.d")),
+ reg_names[regno]);
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC,
+ fp_offset - base_offset);
+ fprintf (file, "(%s)\n", reg_names[REGNO(base_reg_rtx)]);
+ }
fp_offset -= fp_size;
}
void
function_prologue (file, size)
FILE *file;
- int size;
+ int size ATTRIBUTE_UNUSED;
{
#ifndef FUNCTION_NAME_ALREADY_DECLARED
- char *fnname;
+ const char *fnname;
#endif
long tsize = current_frame_info.total_size;
if (!flag_inhibit_size_directive)
{
+ /* .frame FRAMEREG, FRAMESIZE, RETREG */
fprintf (file,
"\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d/%d, args= %d, extra= %ld\n",
(reg_names[(frame_pointer_needed)
? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
- tsize, reg_names[31 + GP_REG_FIRST],
+ ((frame_pointer_needed && TARGET_MIPS16)
+ ? (tsize - current_function_outgoing_args_size)
+ : tsize),
+ reg_names[31 + GP_REG_FIRST],
current_frame_info.var_size,
current_frame_info.num_gp,
current_frame_info.num_fp,
current_function_outgoing_args_size,
current_frame_info.extra_size);
+ /* .mask MASK, GPOFFSET; .fmask FPOFFSET */
fprintf (file, "\t.mask\t0x%08lx,%ld\n\t.fmask\t0x%08lx,%ld\n",
current_frame_info.mask,
current_frame_info.gp_save_offset,
current_frame_info.fmask,
current_frame_info.fp_save_offset);
+
+ /* Require:
+ OLD_SP == *FRAMEREG + FRAMESIZE => can find old_sp from nominated FP reg.
+ HIGHEST_GP_SAVED == *FRAMEREG + FRAMESIZE + GPOFFSET => can find saved regs. */
}
if (mips_entry && ! mips_can_use_return_insn ())
fprintf (file, "\n");
}
- if (TARGET_ABICALLS && mips_abi == ABI_32)
+ if (TARGET_ABICALLS && (mips_abi == ABI_32 || mips_abi == ABI_O64))
{
- char *sp_str = reg_names[STACK_POINTER_REGNUM];
+ const char *const sp_str = reg_names[STACK_POINTER_REGNUM];
fprintf (file, "\t.set\tnoreorder\n\t.cpload\t%s\n\t.set\treorder\n",
reg_names[PIC_FUNCTION_ADDR_REGNUM]);
int regno;
HOST_WIDE_INT tsize;
rtx tmp_rtx = 0;
- char *arg_name = 0;
+ const char *arg_name = 0;
tree fndecl = current_function_decl;
tree fntype = TREE_TYPE (fndecl);
tree fnargs = DECL_ARGUMENTS (fndecl);
/* If this function is a varargs function, store any registers that
would normally hold arguments ($4 - $7) on the stack. */
- if (mips_abi == ABI_32
+ if ((mips_abi == ABI_32 || mips_abi == ABI_O64)
&& (! mips_entry || mips_can_use_return_insn ())
&& ((TYPE_ARG_TYPES (fntype) != 0
&& (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
{
if (offset != 0)
ptr = gen_rtx (PLUS, Pmode, stack_pointer_rtx, GEN_INT (offset));
- emit_move_insn (gen_rtx (MEM, word_mode, ptr),
- gen_rtx (REG, word_mode, regno));
- offset += UNITS_PER_WORD;
+ emit_move_insn (gen_rtx (MEM, gpr_mode, ptr),
+ gen_rtx (REG, gpr_mode, regno));
+
+ offset += GET_MODE_SIZE (gpr_mode);
}
}
moment. */
if (TARGET_MIPS16 && BITSET_P (current_frame_info.mask, 18))
{
- rtx reg_rtx = gen_rtx (REG, word_mode, GP_REG_FIRST + 3);
+ rtx reg_rtx = gen_rtx (REG, gpr_mode, GP_REG_FIRST + 3);
long gp_offset, base_offset;
gp_offset = current_frame_info.gp_sp_offset;
base_offset = 0;
start_sequence ();
emit_move_insn (reg_rtx,
- gen_rtx (REG, word_mode, GP_REG_FIRST + 18));
- emit_move_insn (gen_rtx (MEM, word_mode,
+ gen_rtx (REG, gpr_mode, GP_REG_FIRST + 18));
+ emit_move_insn (gen_rtx (MEM, gpr_mode,
gen_rtx (PLUS, Pmode, stack_pointer_rtx,
GEN_INT (gp_offset
- base_offset))),
/* If we are doing svr4-abi, sp move is done by
function_prologue. In mips16 mode with a large frame, we
save the registers before adjusting the stack. */
- if ((!TARGET_ABICALLS || mips_abi != ABI_32)
+ if ((!TARGET_ABICALLS || (mips_abi != ABI_32 && mips_abi != ABI_O64))
&& (!TARGET_MIPS16 || tsize <= 32767))
{
rtx insn;
split. */
/* ??? There is no DImode ori immediate pattern, so we can only
do this for 32 bit code. */
- if (large_int (tsize_rtx) && GET_MODE (tmp_rtx) == SImode)
+ if (large_int (tsize_rtx, GET_MODE (tsize_rtx))
+ && GET_MODE (tmp_rtx) == SImode)
{
insn = emit_move_insn (tmp_rtx,
GEN_INT (tsize & 0xffff0000));
else if (reg_18_save != NULL_RTX)
emit_insn (reg_18_save);
- if ((!TARGET_ABICALLS || mips_abi != ABI_32)
+ if ((!TARGET_ABICALLS || (mips_abi != ABI_32 && mips_abi != ABI_O64))
&& TARGET_MIPS16
&& tsize > 32767)
{
instructions when using the frame pointer by pointing the
frame pointer ahead of the argument space allocated on
the stack. */
- if ((! TARGET_ABICALLS || mips_abi != ABI_32)
+ if ((! TARGET_ABICALLS || (mips_abi != ABI_32 && mips_abi != ABI_O64))
&& TARGET_MIPS16
&& tsize > 32767)
{
RTX_FRAME_RELATED_P (insn) = 1;
}
- if (TARGET_ABICALLS && mips_abi != ABI_32)
+ if (TARGET_ABICALLS && (mips_abi != ABI_32 && mips_abi != ABI_O64))
emit_insn (gen_loadgp (XEXP (DECL_RTL (current_function_decl), 0),
- gen_rtx (REG, DImode, 25)));
+ gen_rtx_REG (DImode, 25)));
}
/* If we are profiling, make sure no instructions are scheduled before
void
function_epilogue (file, size)
- FILE *file;
- HOST_WIDE_INT size;
+ FILE *file ATTRIBUTE_UNUSED;
+ HOST_WIDE_INT size ATTRIBUTE_UNUSED;
{
- char *fnname;
+ const char *fnname;
#ifndef FUNCTION_NAME_ALREADY_DECLARED
/* Get the function name the same way that toplev.c does before calling
int num_gp_regs = current_frame_info.gp_reg_size / 4;
int num_fp_regs = current_frame_info.fp_reg_size / 8;
int num_regs = num_gp_regs + num_fp_regs;
- char *name = fnname;
+ const char *name = fnname;
if (name[0] == '*')
name++;
dslots_load_total += num_regs;
fprintf (stderr,
- "%-20s fp=%c leaf=%c alloca=%c setjmp=%c stack=%4ld arg=%3ld reg=%2d/%d delay=%3d/%3dL %3d/%3dJ refs=%3d/%3d/%3d",
+ "%-20s fp=%c leaf=%c alloca=%c setjmp=%c stack=%4ld arg=%3d reg=%2d/%d delay=%3d/%3dL %3d/%3dJ refs=%3d/%3d/%3d",
name, frame_pointer_needed ? 'y' : 'n',
(current_frame_info.mask & RA_MASK) != 0 ? 'n' : 'y',
current_function_calls_alloca ? 'y' : 'n',
if (tsize > 32767 && ! TARGET_MIPS16)
{
- tmp_rtx = gen_rtx (REG, Pmode, MIPS_TEMP1_REGNUM);
+ tmp_rtx = gen_rtx_REG (Pmode, MIPS_TEMP1_REGNUM);
emit_move_insn (tmp_rtx, tsize_rtx);
tsize_rtx = tmp_rtx;
}
/* The GP/PIC register is implicitly used by all SYMBOL_REFs, so if we
are going to restore it, then we must emit a blockage insn to
prevent the scheduler from moving the restore out of the epilogue. */
- else if (TARGET_ABICALLS && mips_abi != ABI_32
+ else if (TARGET_ABICALLS && mips_abi != ABI_32 && mips_abi != ABI_O64
&& (current_frame_info.mask
& (1L << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))))
emit_insn (gen_blockage ());
return compute_frame_size (get_frame_size ()) == 0;
}
\f
+/* Returns non-zero if X contains a SYMBOL_REF. */
+
+static int
+symbolic_expression_p (x)
+ rtx x;
+{
+ if (GET_CODE (x) == SYMBOL_REF)
+ return 1;
+
+ if (GET_CODE (x) == CONST)
+ return symbolic_expression_p (XEXP (x, 0));
+
+ if (GET_RTX_CLASS (GET_CODE (x)) == '1')
+ return symbolic_expression_p (XEXP (x, 0));
+
+ if (GET_RTX_CLASS (GET_CODE (x)) == 'c'
+ || GET_RTX_CLASS (GET_CODE (x)) == '2')
+ return (symbolic_expression_p (XEXP (x, 0))
+ || symbolic_expression_p (XEXP (x, 1)));
+
+ return 0;
+}
+
/* Choose the section to use for the constant rtx expression X that has
mode MODE. */
void
mips_select_rtx_section (mode, x)
enum machine_mode mode;
- rtx x;
+ rtx x ATTRIBUTE_UNUSED;
{
if (TARGET_MIPS16)
{
- /* In mips16 mode, the constant table always goes in the .text
- section, so that constants can be loaded using PC relative
+ /* In mips16 mode, the constant table always goes in the same section
+ as the function, so that constants can be loaded using PC relative
addressing. */
- text_section ();
+ function_section (current_function_decl);
}
else if (TARGET_EMBEDDED_DATA)
{
if (GET_MODE_SIZE (mode) <= mips_section_threshold
&& mips_section_threshold > 0)
SMALL_DATA_SECTION ();
+ else if (flag_pic && symbolic_expression_p (x))
+ /* Any expression involving a SYMBOL_REF might need a run-time
+ relocation. (The symbol might be defined in a shared
+ library loaded at an unexpected base address.) So, we must
+ put such expressions in the data segment (which is
+ writable), rather than the text segment (which is
+ read-only). */
+ data_section ();
else
READONLY_DATA_SECTION ();
}
}
/* Choose the section to use for DECL. RELOC is true if its value contains
- any relocatable expression. */
+ any relocatable expression.
+
+ Some of the logic used here needs to be replicated in
+ ENCODE_SECTION_INFO in mips.h so that references to these symbols
+ are done correctly. Specifically, at least all symbols assigned
+ here to rom (.text and/or .rodata) must not be referenced via
+ ENCODE_SECTION_INFO with %gprel, as the rom might be too far away.
+
+ If you need to make a change here, you probably should check
+ ENCODE_SECTION_INFO to see if it needs a similar change. */
void
mips_select_section (decl, reloc)
rtx
mips_function_value (valtype, func)
tree valtype;
- tree func;
+ tree func ATTRIBUTE_UNUSED;
{
int reg = GP_RETURN;
enum machine_mode mode = TYPE_MODE (valtype);
}
else if (TREE_CODE (valtype) == RECORD_TYPE
- && mips_abi != ABI_32 && mips_abi != ABI_EABI)
+ && mips_abi != ABI_32
+ && mips_abi != ABI_O64
+ && mips_abi != ABI_EABI)
{
/* A struct with only one or two floating point fields is returned in
the floating point registers. */
strictly necessary. */
enum machine_mode field_mode = TYPE_MODE (TREE_TYPE (fields[0]));
- return gen_rtx (PARALLEL, mode,
- gen_rtvec (1,
- gen_rtx (EXPR_LIST, VOIDmode,
- gen_rtx (REG, field_mode,
- FP_RETURN),
- const0_rtx)));
+ return gen_rtx_PARALLEL
+ (mode,
+ gen_rtvec (1,
+ gen_rtx_EXPR_LIST (VOIDmode,
+ gen_rtx_REG (field_mode,
+ FP_RETURN),
+ const0_rtx)));
}
else if (i == 2)
int second_offset
= TREE_INT_CST_LOW (DECL_FIELD_BITPOS (fields[1]));
- return gen_rtx (PARALLEL, mode,
- gen_rtvec (2,
- gen_rtx (EXPR_LIST, VOIDmode,
- gen_rtx (REG, first_mode,
- FP_RETURN),
- GEN_INT (first_offset
- / BITS_PER_UNIT)),
- gen_rtx (EXPR_LIST, VOIDmode,
- gen_rtx (REG, second_mode,
- FP_RETURN + 2),
- GEN_INT (second_offset
- / BITS_PER_UNIT))));
+ return gen_rtx_PARALLEL
+ (mode,
+ gen_rtvec (2,
+ gen_rtx_EXPR_LIST (VOIDmode,
+ gen_rtx_REG (first_mode,
+ FP_RETURN),
+ GEN_INT (first_offset
+ / BITS_PER_UNIT)),
+ gen_rtx_EXPR_LIST (VOIDmode,
+ gen_rtx_REG (second_mode,
+ FP_RETURN + 2),
+ GEN_INT (second_offset
+ / BITS_PER_UNIT))));
}
}
}
- return gen_rtx (REG, mode, reg);
+ return gen_rtx_REG (mode, reg);
}
+#endif
/* The implementation of FUNCTION_ARG_PASS_BY_REFERENCE. Return
nonzero when an argument must be passed by reference. */
int
function_arg_pass_by_reference (cum, mode, type, named)
- CUMULATIVE_ARGS *cum;
+ CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED;
enum machine_mode mode;
tree type;
- int named;
+ int named ATTRIBUTE_UNUSED;
{
int size;
+ /* We must pass by reference if we would be both passing in registers
+ and the stack. This is because any subsequent partial arg would be
+ handled incorrectly in this case.
+
+ ??? This is really a kludge. We should either fix GCC so that such
+ a situation causes an abort and then do something in the MIPS port
+ to prevent it, or add code to function.c to properly handle the case. */
+ if (FUNCTION_ARG (*cum, mode, type, named) != 0
+ && MUST_PASS_IN_STACK (mode, type))
+ return 1;
+
+ /* Otherwise, we only do this if EABI is selected. */
if (mips_abi != ABI_EABI)
return 0;
size = int_size_in_bytes (type);
return size == -1 || size > UNITS_PER_WORD;
}
-#endif
/* This function returns the register class required for a secondary
register when copying between one of the registers in CLASS, and X,
}
if (! gp_reg_p)
{
+ /* The stack pointer isn't a valid operand to an add instruction,
+ so we need to load it into M16_REGS first. This can happen as
+ a result of register elimination and form_sum converting
+ (plus reg (plus SP CONST)) to (plus (plus reg SP) CONST). We
+ need an extra register if the dest is the same as the other
+ register. In that case, we can't fix the problem by loading SP
+ into the dest first. */
+ if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == REG
+ && GET_CODE (XEXP (x, 1)) == REG
+ && (XEXP (x, 0) == stack_pointer_rtx
+ || XEXP (x, 1) == stack_pointer_rtx))
+ return (class == M16_REGS ? M16_NA_REGS : M16_REGS);
+
if (class == M16_REGS || class == M16_NA_REGS)
return NO_REGS;
return M16_REGS;
ASM_GENERATE_INTERNAL_LABEL as called by output_constant_def. */
if (SYMBOL_REF_FLAG (x))
{
- char *name = XSTR (x, 0);
+ const char *name = XSTR (x, 0);
return (name[0] == '*'
&& strncmp (name + 1, LOCAL_LABEL_PREFIX,
int fp_code;
int from_fp_p;
{
- char *s;
+ const char *s;
int gparg, fparg;
unsigned int f;
- /* This code only works for the original 32 bit ABI. */
- if (mips_abi != ABI_32)
+ /* This code only works for the original 32 bit ABI and the O64 ABI. */
+ if (mips_abi != ABI_32 && mips_abi != ABI_O64)
abort ();
if (from_fp_p)
{
if ((fparg & 1) != 0)
++fparg;
- fprintf (file, "\t%s\t%s,%s\n\t%s\t%s,%s\n", s,
- reg_names[gparg], reg_names[fparg + 1], s,
- reg_names[gparg + 1], reg_names[fparg]);
+ if (TARGET_BIG_ENDIAN)
+ fprintf (file, "\t%s\t%s,%s\n\t%s\t%s,%s\n", s,
+ reg_names[gparg], reg_names[fparg + 1], s,
+ reg_names[gparg + 1], reg_names[fparg]);
+ else
+ fprintf (file, "\t%s\t%s,%s\n\t%s\t%s,%s\n", s,
+ reg_names[gparg], reg_names[fparg], s,
+ reg_names[gparg + 1], reg_names[fparg + 1]);
++gparg;
++fparg;
}
build_mips16_function_stub (file)
FILE *file;
{
- char *fnname;
+ const char *fnname;
char *secname, *stubname;
tree stubid, stubdecl;
int need_comma;
{
int fpret;
rtx fn;
- char *fnname, *secname, *stubname;
+ const char *fnname;
+ char *secname, *stubname;
struct mips16_stub *l;
tree stubid, stubdecl;
int need_comma;
&& strncmp (XSTR (fn, 0), "__mips16_", 9) == 0)
return 0;
- /* This code will only work for the standard ABI. The other ABI's
+ /* This code will only work for o32 and o64 abis. The other ABI's
require more sophisticated support. */
- if (mips_abi != ABI_32)
+ if (mips_abi != ABI_32 && mips_abi != ABI_O64)
abort ();
/* We can only handle SFmode and DFmode floating point return
reg_names[GP_REG_FIRST + 2], reg_names[FP_REG_FIRST + 0]);
else
{
- fprintf (asm_out_file, "\tmfc1\t%s,%s\n",
- reg_names[GP_REG_FIRST + 2],
- reg_names[FP_REG_FIRST + 1]);
- fprintf (asm_out_file, "\tmfc1\t%s,%s\n",
- reg_names[GP_REG_FIRST + 3],
- reg_names[FP_REG_FIRST + 0]);
+ if (TARGET_BIG_ENDIAN)
+ {
+ fprintf (asm_out_file, "\tmfc1\t%s,%s\n",
+ reg_names[GP_REG_FIRST + 2],
+ reg_names[FP_REG_FIRST + 1]);
+ fprintf (asm_out_file, "\tmfc1\t%s,%s\n",
+ reg_names[GP_REG_FIRST + 3],
+ reg_names[FP_REG_FIRST + 0]);
+ }
+ else
+ {
+ fprintf (asm_out_file, "\tmfc1\t%s,%s\n",
+ reg_names[GP_REG_FIRST + 2],
+ reg_names[FP_REG_FIRST + 0]);
+ fprintf (asm_out_file, "\tmfc1\t%s,%s\n",
+ reg_names[GP_REG_FIRST + 3],
+ reg_names[FP_REG_FIRST + 1]);
+ }
}
fprintf (asm_out_file, "\tj\t%s\n", reg_names[GP_REG_FIRST + 18]);
/* As above, we can't fill the delay slot. */
/* Record this stub. */
l = (struct mips16_stub *) xmalloc (sizeof *l);
- l->name = (char *) xmalloc (strlen (fnname) + 1);
- strcpy (l->name, fnname);
+ l->name = xstrdup (fnname);
l->fpret = fpret;
l->next = mips16_stubs;
mips16_stubs = l;
machine_dependent_reorg (first)
rtx first;
{
- int insns_len, max_internal_pool_size, pool_size, addr;
+ int insns_len, max_internal_pool_size, pool_size, addr, first_constant_ref;
rtx insn;
struct constant *constants;
insns_len = 0;
for (insn = first; insn; insn = NEXT_INSN (insn))
{
- insns_len += get_attr_length (insn) * 2;
+ insns_len += get_attr_length (insn);
/* ??? We put switch tables in .text, but we don't define
JUMP_TABLES_IN_TEXT_SECTION, so get_attr_length will not
constants = NULL;
addr = 0;
+ first_constant_ref = -1;
for (insn = first; insn; insn = NEXT_INSN (insn))
{
SET_DEST (PATTERN (insn)),
newsrc);
INSN_CODE (insn) = -1;
+
+ if (first_constant_ref < 0)
+ first_constant_ref = addr;
}
}
- addr += get_attr_length (insn) * 2;
+ addr += get_attr_length (insn);
/* ??? We put switch tables in .text, but we don't define
JUMP_TABLES_IN_TEXT_SECTION, so get_attr_length will not
if (constants != NULL)
dump_constants (constants, insn);
constants = NULL;
+ first_constant_ref = -1;
}
+
+ if (constants != NULL
+ && (NEXT_INSN (insn) == NULL
+ || (first_constant_ref >= 0
+ && (((addr - first_constant_ref)
+ + 2 /* for alignment */
+ + 2 /* for a short jump insn */
+ + pool_size)
+ >= 0x8000))))
+ {
+ /* If we haven't had a barrier within 0x8000 bytes of a
+ constant reference or we are at the end of the function,
+ emit a barrier now. */
- /* ??? If we don't find a barrier within 0x8000 bytes of
- instructions and constants in CONSTANTS, we need to invent
- one. This seems sufficiently unlikely that I am not going to
- worry about it. */
- }
-
- if (constants != NULL)
- {
- rtx label, jump, barrier;
-
- label = gen_label_rtx ();
- jump = emit_jump_insn_after (gen_jump (label), get_last_insn ());
- JUMP_LABEL (jump) = label;
- LABEL_NUSES (label) = 1;
- barrier = emit_barrier_after (jump);
- emit_label_after (label, barrier);
- dump_constants (constants, barrier);
- constants = NULL;
- }
+ rtx label, jump, barrier;
+
+ label = gen_label_rtx ();
+ jump = emit_jump_insn_after (gen_jump (label), insn);
+ JUMP_LABEL (jump) = label;
+ LABEL_NUSES (label) = 1;
+ barrier = emit_barrier_after (jump);
+ emit_label_after (label, barrier);
+ first_constant_ref = -1;
+ }
+ }
/* ??? If we output all references to a constant in internal
constants table, we don't need to output the constant in the real
int
extend_operator (x, mode)
rtx x;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
enum rtx_code code = GET_CODE (x);
return code == SIGN_EXTEND || code == ZERO_EXTEND;
int
highpart_shift_operator (x, mode)
rtx x;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
enum rtx_code code = GET_CODE (x);
return (code == LSHIFTRT
|| code == ROTATERT
|| code == ROTATE);
}
+
+/* Return the length of INSN. LENGTH is the initial length computed by
+ attributes in the machine-description file. */
+
+int
+mips_adjust_insn_length (insn, length)
+ rtx insn;
+ int length;
+{
+ /* A unconditional jump has an unfilled delay slot if it is not part
+ of a sequence. A conditional jump normally has a delay slot, but
+ does not on MIPS16. */
+ if (simplejump_p (insn)
+ || (!TARGET_MIPS16 && (GET_CODE (insn) == JUMP_INSN
+ || GET_CODE (insn) == CALL_INSN)))
+ length += 4;
+
+ /* All MIPS16 instructions are a measly two bytes. */
+ if (TARGET_MIPS16)
+ length /= 2;
+
+ return length;
+}
+
+/* Output assembly instructions to peform a conditional branch.
+
+ INSN is the branch instruction. OPERANDS[0] is the condition.
+ OPERANDS[1] is the target of the branch. OPERANDS[2] is the target
+ of the first operand to the condition. If TWO_OPERANDS_P is
+ non-zero the comparison takes two operands; OPERANDS[3] will be the
+ second operand.
+
+ If INVERTED_P is non-zero we are to branch if the condition does
+ not hold. If FLOAT_P is non-zero this is a floating-point comparison.
+
+ LENGTH is the length (in bytes) of the sequence we are to generate.
+ That tells us whether to generate a simple conditional branch, or a
+ reversed conditional branch around a `jr' instruction. */
+char *
+mips_output_conditional_branch (insn,
+ operands,
+ two_operands_p,
+ float_p,
+ inverted_p,
+ length)
+ rtx insn;
+ rtx *operands;
+ int two_operands_p;
+ int float_p;
+ int inverted_p;
+ int length;
+{
+ static char buffer[200];
+ /* The kind of comparison we are doing. */
+ enum rtx_code code = GET_CODE (operands[0]);
+ /* Non-zero if the opcode for the comparison needs a `z' indicating
+ that it is a comparision against zero. */
+ int need_z_p;
+ /* A string to use in the assembly output to represent the first
+ operand. */
+ const char *op1 = "%z2";
+ /* A string to use in the assembly output to represent the second
+ operand. Use the hard-wired zero register if there's no second
+ operand. */
+ const char *op2 = (two_operands_p ? ",%z3" : ",%.");
+ /* The operand-printing string for the comparison. */
+ const char *comp = (float_p ? "%F0" : "%C0");
+ /* The operand-printing string for the inverted comparison. */
+ const char *inverted_comp = (float_p ? "%W0" : "%N0");
+
+ /* The MIPS processors (for levels of the ISA at least two), have
+ "likely" variants of each branch instruction. These instructions
+ annul the instruction in the delay slot if the branch is not
+ taken. */
+ mips_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn));
+
+ if (!two_operands_p)
+ {
+ /* To compute whether than A > B, for example, we normally
+ subtract B from A and then look at the sign bit. But, if we
+ are doing an unsigned comparison, and B is zero, we don't
+ have to do the subtraction. Instead, we can just check to
+ see if A is non-zero. Thus, we change the CODE here to
+ reflect the simpler comparison operation. */
+ switch (code)
+ {
+ case GTU:
+ code = NE;
+ break;
+
+ case LEU:
+ code = EQ;
+ break;
+
+ case GEU:
+ /* A condition which will always be true. */
+ code = EQ;
+ op1 = "%.";
+ break;
+
+ case LTU:
+ /* A condition which will always be false. */
+ code = NE;
+ op1 = "%.";
+ break;
+
+ default:
+ /* Not a special case. */
+ break;
+ }
+ }
+
+ /* Relative comparisons are always done against zero. But
+ equality comparisons are done between two operands, and therefore
+ do not require a `z' in the assembly language output. */
+ need_z_p = (!float_p && code != EQ && code != NE);
+ /* For comparisons against zero, the zero is not provided
+ explicitly. */
+ if (need_z_p)
+ op2 = "";
+
+ /* Begin by terminating the buffer. That way we can always use
+ strcat to add to it. */
+ buffer[0] = '\0';
+
+ switch (length)
+ {
+ case 4:
+ case 8:
+ /* Just a simple conditional branch. */
+ if (float_p)
+ sprintf (buffer, "%%*b%s%%?\t%%Z2%%1",
+ inverted_p ? inverted_comp : comp);
+ else
+ sprintf (buffer, "%%*b%s%s%%?\t%s%s,%%1",
+ inverted_p ? inverted_comp : comp,
+ need_z_p ? "z" : "",
+ op1,
+ op2);
+ return buffer;
+
+ case 12:
+ case 16:
+ {
+ /* Generate a reversed conditional branch around ` j'
+ instruction:
+
+ .set noreorder
+ .set nomacro
+ bc l
+ nop
+ j target
+ .set macro
+ .set reorder
+ l:
+
+ Because we have to jump four bytes *past* the following
+ instruction if this branch was annulled, we can't just use
+ a label, as in the picture above; there's no way to put the
+ label after the next instruction, as the assembler does not
+ accept `.L+4' as the target of a branch. (We can't just
+ wait until the next instruction is output; it might be a
+ macro and take up more than four bytes. Once again, we see
+ why we want to eliminate macros.)
+
+ If the branch is annulled, we jump four more bytes that we
+ would otherwise; that way we skip the annulled instruction
+ in the delay slot. */
+
+ const char *target
+ = ((mips_branch_likely || length == 16) ? ".+16" : ".+12");
+ char *c;
+
+ strcpy (buffer, "%(%<");
+ c = strchr (buffer, '\0');
+ /* Generate the reversed comparision. This takes four
+ bytes. */
+ if (float_p)
+ sprintf (c, "%%*b%s\t%%Z2%s",
+ inverted_p ? comp : inverted_comp,
+ target);
+ else
+ sprintf (c, "%%*b%s%s\t%s%s,%s",
+ inverted_p ? comp : inverted_comp,
+ need_z_p ? "z" : "",
+ op1,
+ op2,
+ target);
+ strcat (c, "\n\tnop\n\tj\t%1");
+ if (length == 16)
+ /* The delay slot was unfilled. Since we're inside
+ .noreorder, the assembler will not fill in the NOP for
+ us, so we must do it ourselves. */
+ strcat (buffer, "\n\tnop");
+ strcat (buffer, "%>%)");
+ return buffer;
+ }
+
+ /* We do not currently use this code. It handles jumps to
+ arbitrary locations, using `jr', even across a 256MB boundary.
+ We could add a -mhuge switch, and then use this code instead of
+ the `j' alternative above when -mhuge was used. */
+#if 0
+ case 16:
+ case 20:
+ {
+ /* Generate a reversed conditional branch around a `jr'
+ instruction:
+
+ .set noreorder
+ .set nomacro
+ .set noat
+ bc l
+ la $at, target
+ jr $at
+ .set at
+ .set macro
+ .set reorder
+ l:
+
+ Not pretty, but allows a conditional branch anywhere in the
+ 32-bit address space. If the original branch is annulled,
+ then the instruction in the delay slot should be executed
+ only if the branch is taken. The la instruction is really
+ a macro which will usually take eight bytes, but sometimes
+ takes only four, if the instruction to which we're jumping
+ gets its own entry in the global pointer table, which will
+ happen if its a case label. The assembler will then
+ generate only a four-byte sequence, rather than eight, and
+ there seems to be no way to tell it not to. Thus, we can't
+ just use a `.+x' addressing form; we don't know what value
+ to give for `x'.
+
+ So, we resort to using the explicit relocation syntax
+ available in the assembler and do:
+
+ lw $at,%got_page(target)($gp)
+ daddiu $at,$at,%got_ofst(target)
+
+ That way, this always takes up eight bytes, and we can use
+ the `.+x' form. Of course, these explicit machinations
+ with relocation will not work with old assemblers. Then
+ again, neither do out-of-range branches, so we haven't lost
+ anything. */
+
+ /* The target of the reversed branch. */
+ const char *target
+ = ((mips_branch_likely || length == 20) ? ".+20" : ".+16");
+ const char *at_register = mips_reg_names[ASSEMBLER_SCRATCH_REGNUM];
+ const char *gp_register = mips_reg_names[PIC_OFFSET_TABLE_REGNUM];
+ char *c;
+
+ strcpy (buffer, "%(%<%[");
+ c = strchr (buffer, '\0');
+ /* Generate the reversed comparision. This takes four
+ bytes. */
+ if (float_p)
+ sprintf (c, "%%*b%s\t%%Z2%s",
+ inverted_p ? comp : inverted_comp,
+ target);
+ else
+ sprintf (c, "%%*b%s%s\t%s%s,%s",
+ inverted_p ? comp : inverted_comp,
+ need_z_p ? "z" : "",
+ op1,
+ op2,
+ target);
+ c = strchr (buffer, '\0');
+ /* Generate the load-address, and jump. This takes twelve
+ bytes, for a total of 16. */
+ sprintf (c,
+ "\n\tlw\t%s,%%%%got_page(%%1)(%s)\n\tdaddiu\t%s,%s,%%%%got_ofst(%%1)\n\tjr\t%s",
+ at_register,
+ gp_register,
+ at_register,
+ at_register,
+ at_register);
+ if (length == 20)
+ /* The delay slot was unfilled. Since we're inside
+ .noreorder, the assembler will not fill in the NOP for
+ us, so we must do it ourselves. */
+ strcat (buffer, "\n\tnop");
+ strcat (buffer, "%]%>%)");
+ return buffer;
+ }
+#endif
+
+ default:
+ abort ();
+ }
+
+ /* NOTREACHED */
+ return 0;
+}
+
+/* Called to register all of our global variables with the garbage
+ collector. */
+
+static void
+mips_add_gc_roots ()
+{
+ ggc_add_rtx_root (&mips_load_reg, 1);
+ ggc_add_rtx_root (&mips_load_reg2, 1);
+ ggc_add_rtx_root (&mips_load_reg3, 1);
+ ggc_add_rtx_root (&mips_load_reg4, 1);
+ ggc_add_rtx_root (branch_cmp, sizeof (branch_cmp) / sizeof (rtx));
+ ggc_add_rtx_root (&embedded_pic_fnaddr_rtx, 1);
+ ggc_add_rtx_root (&mips16_gp_pseudo_rtx, 1);
+}