#include "real.h"
#include "insn-config.h"
#include "conditions.h"
-#include "insn-flags.h"
#include "insn-attr.h"
-#include "insn-codes.h"
#include "recog.h"
#include "toplev.h"
#include "output.h"
#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. */
-#else
-#include <stab.h> /* On BSD, use the system's stab.h. */
-#endif /* not USG */
+#include "gstab.h"
+#include "target.h"
+#include "target-def.h"
#ifdef __GNU_STAB__
#define STAB_CODE_TYPE enum __stab_debug_code
enum machine_mode));
static int m16_check_op PARAMS ((rtx, int, int, int));
static void block_move_loop PARAMS ((rtx, rtx,
- unsigned int,
+ unsigned int,
int,
rtx, rtx));
static void block_move_call PARAMS ((rtx, rtx, rtx));
ATTRIBUTE_NORETURN;
static int symbolic_expression_p PARAMS ((rtx));
static void mips_add_gc_roots PARAMS ((void));
+static void mips_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
+static void mips_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
+static enum processor_type mips_parse_cpu PARAMS ((const char *));
/* Global variables for machine-dependent things. */
static int prev_half_pic_ptrs = 0;
static int prev_half_pic_refs = 0;
-/* which cpu are we scheduling for */
-enum processor_type mips_cpu;
+/* The target cpu for code generation. */
+enum processor_type mips_arch;
+
+/* The target cpu for optimization and scheduling. */
+enum processor_type mips_tune;
/* which instruction set architecture to use. */
int mips_isa;
/* Strings to hold which cpu and instruction set architecture to use. */
const char *mips_cpu_string; /* for -mcpu=<xxx> */
+const char *mips_arch_string; /* for -march=<xxx> */
+const char *mips_tune_string; /* for -mtune=<xxx> */
const char *mips_isa_string; /* for -mips{1,2,3,4} */
const char *mips_abi_string; /* for -mabi={32,n32,64,eabi} */
just a way to avoid using up another bit in target_flags. */
const char *mips_no_mips16_string;
-/* This is only used to determine if an type size setting option was
+/* 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;
NO_REGS, NO_REGS, NO_REGS, NO_REGS,
NO_REGS, NO_REGS, NO_REGS, NO_REGS,
};
+\f
+/* Initialize the GCC target structure. */
+#undef TARGET_ASM_FUNCTION_PROLOGUE
+#define TARGET_ASM_FUNCTION_PROLOGUE mips_output_function_prologue
+#undef TARGET_ASM_FUNCTION_EPILOGUE
+#define TARGET_ASM_FUNCTION_EPILOGUE mips_output_function_epilogue
+struct gcc_target targetm = TARGET_INITIALIZER;
\f
/* Return truth value of whether OP can be used as an operands
where a register or 16 bit unsigned integer is needed. */
rtx op;
enum machine_mode mode;
{
- rtx addr;
-
if (GET_CODE (op) != MEM
|| ! memory_operand (op, mode))
{
/* Make sure that 4 added to the address is a valid memory address.
This essentially just checks for overflow in an added constant. */
- addr = XEXP (op, 0);
-
- if (CONSTANT_ADDRESS_P (addr))
+ if (CONSTANT_ADDRESS_P (XEXP (op, 0)))
return 1;
- return memory_address_p ((GET_MODE_CLASS (mode) == MODE_INT
- ? SImode
- : SFmode),
- plus_constant_for_output (addr, 4));
+ op = adjust_address_nv (op, GET_MODE_CLASS (mode) == MODE_INT
+ ? SImode : SFmode, 4);
+ return memory_address_p (GET_MODE (op), XEXP (op, 0));
}
/* Return nonzero if the code of this rtx pattern is EQ or NE. */
mips_check_split (address, mode)
rtx address;
enum machine_mode mode;
-{
+{
/* ??? This is the same check used in simple_memory_operand.
We use it here because LO_SUM is not offsettable. */
if (GET_MODE_SIZE (mode) > (unsigned) UNITS_PER_WORD)
enum machine_mode mode;
int strict;
{
- return (strict
+ return (strict
? REGNO_MODE_OK_FOR_BASE_P (REGNO (reg), mode)
: GP_REG_OR_PSEUDO_NONSTRICT_P (REGNO (reg), mode));
}
rtx xinsn;
int strict;
{
- if (TARGET_DEBUG_B_MODE)
- {
- GO_PRINTF2 ("\n========== GO_IF_LEGITIMATE_ADDRESS, %sstrict\n",
- strict ? "" : "not ");
- GO_DEBUG_RTX (xinsn);
- }
-
- /* Check for constant before stripping off SUBREG, so that we don't
- accept (subreg (const_int)) which will fail to reload. */
- if (CONSTANT_ADDRESS_P (xinsn)
+ if (TARGET_DEBUG_B_MODE)
+ {
+ GO_PRINTF2 ("\n========== GO_IF_LEGITIMATE_ADDRESS, %sstrict\n",
+ strict ? "" : "not ");
+ GO_DEBUG_RTX (xinsn);
+ }
+
+ /* Check for constant before stripping off SUBREG, so that we don't
+ accept (subreg (const_int)) which will fail to reload. */
+ if (CONSTANT_ADDRESS_P (xinsn)
&& ! (mips_split_addresses && mips_check_split (xinsn, mode))
- && (! TARGET_MIPS16 || mips16_constant (xinsn, mode, 1, 0)))
- return 1;
-
- while (GET_CODE (xinsn) == SUBREG)
- xinsn = SUBREG_REG (xinsn);
-
- /* The mips16 can only use the stack pointer as a base register when
- loading SImode or DImode values. */
- if (GET_CODE (xinsn) == REG
- && mips_reg_mode_ok_for_base_p (xinsn, mode, strict))
- return 1;
-
- if (GET_CODE (xinsn) == LO_SUM && mips_split_addresses)
- {
- register rtx xlow0 = XEXP (xinsn, 0);
- register rtx xlow1 = XEXP (xinsn, 1);
-
- while (GET_CODE (xlow0) == SUBREG)
- xlow0 = SUBREG_REG (xlow0);
- if (GET_CODE (xlow0) == REG
+ && (! TARGET_MIPS16 || mips16_constant (xinsn, mode, 1, 0)))
+ return 1;
+
+ while (GET_CODE (xinsn) == SUBREG)
+ xinsn = SUBREG_REG (xinsn);
+
+ /* The mips16 can only use the stack pointer as a base register when
+ loading SImode or DImode values. */
+ if (GET_CODE (xinsn) == REG
+ && mips_reg_mode_ok_for_base_p (xinsn, mode, strict))
+ return 1;
+
+ if (GET_CODE (xinsn) == LO_SUM && mips_split_addresses)
+ {
+ register rtx xlow0 = XEXP (xinsn, 0);
+ register rtx xlow1 = XEXP (xinsn, 1);
+
+ while (GET_CODE (xlow0) == SUBREG)
+ xlow0 = SUBREG_REG (xlow0);
+ if (GET_CODE (xlow0) == REG
&& mips_reg_mode_ok_for_base_p (xlow0, mode, strict)
&& mips_check_split (xlow1, mode))
- return 1;
- }
-
- if (GET_CODE (xinsn) == PLUS)
- {
- register rtx xplus0 = XEXP (xinsn, 0);
- register rtx xplus1 = XEXP (xinsn, 1);
- register enum rtx_code code0;
- register enum rtx_code code1;
-
- while (GET_CODE (xplus0) == SUBREG)
- xplus0 = SUBREG_REG (xplus0);
- code0 = GET_CODE (xplus0);
-
- while (GET_CODE (xplus1) == SUBREG)
- xplus1 = SUBREG_REG (xplus1);
- code1 = GET_CODE (xplus1);
-
- /* The mips16 can only use the stack pointer as a base register
- when loading SImode or DImode values. */
- if (code0 == REG
- && mips_reg_mode_ok_for_base_p (xplus0, mode, strict))
- {
+ return 1;
+ }
+
+ if (GET_CODE (xinsn) == PLUS)
+ {
+ register rtx xplus0 = XEXP (xinsn, 0);
+ register rtx xplus1 = XEXP (xinsn, 1);
+ register enum rtx_code code0;
+ register enum rtx_code code1;
+
+ while (GET_CODE (xplus0) == SUBREG)
+ xplus0 = SUBREG_REG (xplus0);
+ code0 = GET_CODE (xplus0);
+
+ while (GET_CODE (xplus1) == SUBREG)
+ xplus1 = SUBREG_REG (xplus1);
+ code1 = GET_CODE (xplus1);
+
+ /* The mips16 can only use the stack pointer as a base register
+ when loading SImode or DImode values. */
+ if (code0 == REG
+ && mips_reg_mode_ok_for_base_p (xplus0, mode, strict))
+ {
if (code1 == CONST_INT && SMALL_INT (xplus1))
return 1;
-
- /* On the mips16, we represent GP relative offsets in RTL.
- These are 16 bit signed values, and can serve as register
- offsets. */
- if (TARGET_MIPS16
- && mips16_gp_offset_p (xplus1))
- return 1;
-
- /* For some code sequences, you actually get better code by
- pretending that the MIPS supports an address mode of a
- constant address + a register, even though the real
- machine doesn't support it. This is because the
- assembler can use $r1 to load just the high 16 bits, add
- in the register, and fold the low 16 bits into the memory
- reference, whereas the compiler generates a 4 instruction
- sequence. On the other hand, CSE is not as effective.
- It would be a win to generate the lui directly, but the
- MIPS assembler does not have syntax to generate the
- appropriate relocation. */
-
- /* Also accept CONST_INT addresses here, so no else. */
- /* Reject combining an embedded PIC text segment reference
- with a register. That requires an additional
- instruction. */
- /* ??? Reject combining an address with a register for the MIPS
- 64 bit ABI, because the SGI assembler can not handle this. */
- if (!TARGET_DEBUG_A_MODE
- && (mips_abi == ABI_32
- || mips_abi == ABI_O64
- || mips_abi == ABI_EABI)
- && CONSTANT_ADDRESS_P (xplus1)
- && ! mips_split_addresses
- && (!TARGET_EMBEDDED_PIC
- || code1 != CONST
- || GET_CODE (XEXP (xplus1, 0)) != MINUS)
- /* When assembling for machines with 64 bit registers,
+
+ /* On the mips16, we represent GP relative offsets in RTL.
+ These are 16 bit signed values, and can serve as register
+ offsets. */
+ if (TARGET_MIPS16
+ && mips16_gp_offset_p (xplus1))
+ return 1;
+
+ /* For some code sequences, you actually get better code by
+ pretending that the MIPS supports an address mode of a
+ constant address + a register, even though the real
+ machine doesn't support it. This is because the
+ assembler can use $r1 to load just the high 16 bits, add
+ in the register, and fold the low 16 bits into the memory
+ reference, whereas the compiler generates a 4 instruction
+ sequence. On the other hand, CSE is not as effective.
+ It would be a win to generate the lui directly, but the
+ MIPS assembler does not have syntax to generate the
+ appropriate relocation. */
+
+ /* Also accept CONST_INT addresses here, so no else. */
+ /* Reject combining an embedded PIC text segment reference
+ with a register. That requires an additional
+ instruction. */
+ /* ??? Reject combining an address with a register for the MIPS
+ 64 bit ABI, because the SGI assembler can not handle this. */
+ if (!TARGET_DEBUG_A_MODE
+ && (mips_abi == ABI_32
+ || mips_abi == ABI_O64
+ || mips_abi == ABI_EABI)
+ && CONSTANT_ADDRESS_P (xplus1)
+ && ! mips_split_addresses
+ && (!TARGET_EMBEDDED_PIC
+ || code1 != CONST
+ || GET_CODE (XEXP (xplus1, 0)) != MINUS)
+ /* When assembling for machines with 64 bit registers,
the assembler will not sign-extend the constant "foo"
in "la x, foo(x)" */
&& (!TARGET_64BIT || (INTVAL (xplus1) > 0))
- && !TARGET_MIPS16)
- return 1;
- }
- }
-
- if (TARGET_DEBUG_B_MODE)
+ && !TARGET_MIPS16)
+ return 1;
+ }
+ }
+
+ if (TARGET_DEBUG_B_MODE)
GO_PRINTF ("Not a legitimate address\n");
-
+
/* The address was not legitimate. */
return 0;
}
rtx seq;
embedded_pic_fnaddr_rtx = gen_reg_rtx (Pmode);
-
+
/* Output code at function start to initialize the pseudo-reg. */
/* ??? We used to do this in FINALIZE_PIC, but that does not work for
inline functions, because it is called after RTL for the function
enum rtx_code code0 = GET_CODE (op0);
enum rtx_code code1 = GET_CODE (op1);
enum machine_mode mode = GET_MODE (op0);
- int subreg_word0 = 0;
- int subreg_word1 = 0;
+ int subreg_offset0 = 0;
+ int subreg_offset1 = 0;
enum delay_type delay = DELAY_NONE;
while (code0 == SUBREG)
{
- subreg_word0 += SUBREG_WORD (op0);
+ subreg_offset0 += subreg_regno_offset (REGNO (SUBREG_REG (op0)),
+ GET_MODE (SUBREG_REG (op0)),
+ SUBREG_BYTE (op0),
+ GET_MODE (op0));
op0 = SUBREG_REG (op0);
code0 = GET_CODE (op0);
}
while (code1 == SUBREG)
{
- subreg_word1 += SUBREG_WORD (op1);
+ subreg_offset1 += subreg_regno_offset (REGNO (SUBREG_REG (op1)),
+ GET_MODE (SUBREG_REG (op1)),
+ SUBREG_BYTE (op1),
+ GET_MODE (op1));
op1 = SUBREG_REG (op1);
code1 = GET_CODE (op1);
}
if (code0 == REG)
{
- int regno0 = REGNO (op0) + subreg_word0;
+ int regno0 = REGNO (op0) + subreg_offset0;
if (code1 == REG)
{
- int regno1 = REGNO (op1) + subreg_word1;
+ int regno1 = REGNO (op1) + subreg_offset1;
/* Just in case, don't do anything for assigning a register
to itself, unless we are filling a delay slot. */
if (code1 == REG)
{
- int regno1 = REGNO (op1) + subreg_word1;
+ int regno1 = REGNO (op1) + subreg_offset1;
if (GP_REG_P (regno1))
{
if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
abort ();
-
+
sprintf (volatile_buffer, "%%{%s%%}", ret);
ret = volatile_buffer;
}
rtx op1 = operands[1];
enum rtx_code code0 = GET_CODE (operands[0]);
enum rtx_code code1 = GET_CODE (operands[1]);
- int subreg_word0 = 0;
- int subreg_word1 = 0;
+ int subreg_offset0 = 0;
+ int subreg_offset1 = 0;
enum delay_type delay = DELAY_NONE;
while (code0 == SUBREG)
{
- subreg_word0 += SUBREG_WORD (op0);
+ subreg_offset0 += subreg_regno_offset (REGNO (SUBREG_REG (op0)),
+ GET_MODE (SUBREG_REG (op0)),
+ SUBREG_BYTE (op0),
+ GET_MODE (op0));
op0 = SUBREG_REG (op0);
code0 = GET_CODE (op0);
}
while (code1 == SUBREG)
{
- subreg_word1 += SUBREG_WORD (op1);
+ subreg_offset1 += subreg_regno_offset (REGNO (SUBREG_REG (op1)),
+ GET_MODE (SUBREG_REG (op1)),
+ SUBREG_BYTE (op1),
+ GET_MODE (op1));
op1 = SUBREG_REG (op1);
code1 = GET_CODE (op1);
}
-
+
/* Sanity check. */
if (GET_CODE (operands[1]) == SIGN_EXTEND
&& code1 != REG
if (code0 == REG)
{
- int regno0 = REGNO (op0) + subreg_word0;
+ int regno0 = REGNO (op0) + subreg_offset0;
if (code1 == REG)
{
- int regno1 = REGNO (op1) + subreg_word1;
+ int regno1 = REGNO (op1) + subreg_offset1;
/* Just in case, don't do anything for assigning a register
to itself, unless we are filling a delay slot. */
or higher. For !TARGET_64BIT && gp registers we
need to avoid this by using two li instructions
instead. */
- if (ISA_HAS_64BIT_REGS
+ if (ISA_HAS_64BIT_REGS
&& ! TARGET_64BIT
&& ! FP_REG_P (regno0))
{
: "mt%0\t%.\n");
}
}
-
+
else if (code1 == CONST_INT && GET_MODE (op0) == DImode
&& GP_REG_P (regno0))
{
}
else if (double_memory_operand (op1, GET_MODE (op1)))
- {
- operands[2] = adj_offsettable_operand (op1, 4);
- ret = (reg_mentioned_p (op0, op1)
- ? "lw\t%D0,%2\n\tlw\t%0,%1"
- : "lw\t%0,%1\n\tlw\t%D0,%2");
- }
+ ret = (reg_mentioned_p (op0, op1)
+ ? "lw\t%D0,%D1\n\tlw\t%0,%1"
+ : "lw\t%0,%1\n\tlw\t%D0,%D1");
if (ret != 0 && MEM_VOLATILE_P (op1))
{
{
if (code1 == REG)
{
- int regno1 = REGNO (op1) + subreg_word1;
+ int regno1 = REGNO (op1) + subreg_offset1;
if (FP_REG_P (regno1))
ret = "s.d\t%1,%0";
}
else if (double_memory_operand (op0, GET_MODE (op0)))
- {
- operands[2] = adj_offsettable_operand (op0, 4);
- ret = "sw\t%1,%0\n\tsw\t%D1,%2";
- }
+ ret = "sw\t%1,%0\n\tsw\t%D1,%D0";
}
else if (((code1 == CONST_INT && INTVAL (op1) == 0)
if (TARGET_64BIT)
ret = "sd\t%.,%0";
else
- {
- operands[2] = adj_offsettable_operand (op0, 4);
- ret = "sw\t%.,%0\n\tsw\t%.,%2";
- }
+ ret = "sw\t%.,%0\n\tsw\t%.,%D0";
}
if (TARGET_STATS)
if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
abort ();
-
+
sprintf (volatile_buffer, "%%{%s%%}", ret);
ret = volatile_buffer;
}
return 4;
}
-/* Return nonzero if X is an address which needs a temporary register when
+/* Return nonzero if X is an address which needs a temporary register when
reloaded while generating PIC code. */
int
if (! TARGET_MIPS16)
{
convert_move (result, gen_rtx (GTU, mode, reg, const0_rtx), 0);
+ if (p_invert != NULL)
+ *p_invert = 0;
invert = 0;
}
else
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;
}
else if (cmp_code == NE)
cmp_code = EQ, move_code = EQ;
-
+
if (mode == SImode || mode == DImode)
cmp_mode = mode;
else if (mode == SFmode || mode == DFmode)
rtx src_reg; /* register holding source address */
unsigned int bytes; /* # bytes to move */
int align; /* alignment */
- rtx orig_dest; /* original dest for change_address */
+ rtx orig_dest; /* original dest */
rtx orig_src; /* original source for making a reg note */
{
- rtx dest_mem = change_address (orig_dest, BLKmode, dest_reg);
- rtx src_mem = change_address (orig_src, BLKmode, src_reg);
+ rtx dest_mem = replace_equiv_address (orig_dest, dest_reg);
+ rtx src_mem = replace_equiv_address (orig_src, src_reg);
rtx align_rtx = GEN_INT (align);
rtx label;
rtx final_src;
else if (constp && bytes <= (unsigned)2 * MAX_MOVE_BYTES
&& align == (unsigned) UNITS_PER_WORD)
move_by_pieces (orig_dest, orig_src, bytes, align * BITS_PER_WORD);
-
+
else if (constp && bytes <= (unsigned)2 * MAX_MOVE_BYTES)
- emit_insn (gen_movstrsi_internal (change_address (orig_dest, BLKmode,
- dest_reg),
- change_address (orig_src, BLKmode,
- src_reg),
+ emit_insn (gen_movstrsi_internal (replace_equiv_address (orig_dest,
+ dest_reg),
+ replace_equiv_address (orig_src,
+ src_reg),
bytes_rtx, align_rtx));
else if (constp && align >= (unsigned) UNITS_PER_WORD && optimize)
/* Bytes at the end of the loop. */
if (leftover)
- emit_insn (gen_movstrsi_internal (change_address (orig_dest, BLKmode,
- dest_reg),
- change_address (orig_src, BLKmode,
- src_reg),
+ emit_insn (gen_movstrsi_internal (replace_equiv_address (orig_dest,
+ dest_reg),
+ replace_equiv_address (orig_src,
+ src_reg),
GEN_INT (leftover),
GEN_INT (align)));
}
block_move_call (dest_reg, src_reg, bytes_rtx);
}
\f
-/* Emit load/stores for a small constant block_move.
+/* Emit load/stores for a small constant block_move.
operands[0] is the memory address of the destination.
operands[1] is the memory address of the source.
fprintf (stderr, HOST_PTR_PRINTF, (const PTR) type);
fprintf (stderr, ", %d ) = ", named);
}
-
+
cum->last_arg_fp = 0;
switch (mode)
regno + FP_ARG_FIRST - GP_ARG_FIRST);
else
reg = gen_rtx_REG (word_mode, regno);
-
- XVECEXP (ret, 0, i)
+
+ XVECEXP (ret, 0, i)
= gen_rtx_EXPR_LIST (VOIDmode, reg,
GEN_INT (bitpos / BITS_PER_UNIT));
\f
/* Create the va_list data type.
We keep 3 pointers, and two offsets.
- Two pointers are to the overflow area, which starts at the CFA.
+ Two pointers are to the overflow area, which starts at the CFA.
One of these is constant, for addressing into the GPR save area below it.
The other is advanced up the stack through the overflow region.
The third pointer is to the GPR save area. Since the FPR save area
is just below it, we can address FPR slots off this pointer.
We also keep two one-byte offsets, which are to be subtracted from the
constant pointers to yield addresses in the GPR and FPR save areas.
- These are downcounted as float or non-float arguments are used,
- and when they get to zero, the argument must be obtained from the
+ These are downcounted as float or non-float arguments are used,
+ and when they get to zero, the argument must be obtained from the
overflow region.
If TARGET_SOFT_FLOAT or TARGET_SINGLE_FLOAT, then no FPR save area exists,
and a single pointer is enough. It's started at the GPR save area,
if (!TARGET_SOFT_FLOAT && !TARGET_SINGLE_FLOAT)
{
- tree f_ovfl, f_gtop, f_ftop, f_goff, f_foff;
- tree ovfl, gtop, ftop, goff, foff;
+ tree f_ovfl, f_gtop, f_ftop, f_goff, f_foff;
+ tree ovfl, gtop, ftop, goff, foff;
tree gprv;
int float_formals, fpr_offset, size_excess, floats_passed_in_regs;
int fpr_save_offset;
8 byte boundary. This means that the above calculation should
take into account the exact sequence of floats and non-floats
which make up the excess. That calculation should be rolled
- into the code which sets the current_function_args_info struct.
+ into the code which sets the current_function_args_info struct.
The above then reduces to a fetch from that struct. */
fpr_save_offset += 4;
}
if (fpr_save_offset)
- gprv = build (PLUS_EXPR, TREE_TYPE (ftop), gprv,
+ gprv = build (PLUS_EXPR, TREE_TYPE (ftop), gprv,
build_int_2 (-fpr_save_offset,-1));
t = build (MODIFY_EXPR, TREE_TYPE (ftop), ftop, gprv);
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
{
int indirect;
rtx r, lab_over = NULL_RTX, lab_false;
- tree f_ovfl, f_gtop, f_ftop, f_goff, f_foff;
- tree ovfl, gtop, ftop, goff, foff;
+ tree f_ovfl, f_gtop, f_ftop, f_goff, f_foff;
+ tree ovfl, gtop, ftop, goff, foff;
indirect
= function_arg_pass_by_reference (NULL, TYPE_MODE (type), type, 0);
{
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,
+ 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);
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
}
- t = build (POSTINCREMENT_EXPR, TREE_TYPE (gpr), gpr,
+ t = build (POSTINCREMENT_EXPR, TREE_TYPE (gpr), gpr,
size_int (rsize));
r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
if (r != addr_rtx)
if (indirect)
{
r = gen_rtx_MEM (Pmode, addr_rtx);
- MEM_ALIAS_SET (r) = get_varargs_alias_set ();
+ set_mem_alias_set (r, get_varargs_alias_set ());
emit_move_insn (addr_rtx, r);
}
else
if (r != addr_rtx)
emit_move_insn (addr_rtx, r);
- /* Emit code for foff-=8.
+ /* Emit code for foff-=8.
Advances the offset up FPR save area by one double */
t = build (MINUS_EXPR, TREE_TYPE (foff), foff, build_int_2 (8, 0));
t = build (MODIFY_EXPR, TREE_TYPE (foff), foff, t);
emit_jump (lab_over);
emit_barrier ();
emit_label (lab_false);
-
- if (!TARGET_64BIT)
+
+ if (!TARGET_64BIT)
{
/* For mips2, the overflow area contains mixed size items.
If a 4-byte int is followed by an 8-byte float, then
/* Emit code for addr_rtx = the ovfl pointer into overflow area.
Regardless of mips2, postincrement the ovfl pointer by 8. */
- t = build (POSTINCREMENT_EXPR, TREE_TYPE(ovfl), ovfl,
+ t = build (POSTINCREMENT_EXPR, TREE_TYPE(ovfl), ovfl,
size_int (8));
r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
if (r != addr_rtx)
&& TREE_CODE (type) == INTEGER_TYPE
&& TYPE_PRECISION (type) == 64)
{
- /* In mips2, int takes 32 bits of the GPR save area, but
+ /* In mips2, int takes 32 bits of the GPR save area, but
longlong takes an aligned 64 bits. So, emit code
to zero the low order bits of goff, thus aligning
the later calculation of (gtop-goff) upwards. */
/* Emit code for goff = goff - step_size.
Advances the offset up GPR save area over the item. */
- t = build (MINUS_EXPR, TREE_TYPE (goff), goff,
+ t = build (MINUS_EXPR, TREE_TYPE (goff), goff,
build_int_2 (step_size, 0));
t = build (MODIFY_EXPR, TREE_TYPE (goff), goff, t);
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
emit_jump (lab_over);
emit_barrier ();
emit_label (lab_false);
-
+
/* Emit code for addr_rtx -> overflow area, postinc by step_size */
- t = build (POSTINCREMENT_EXPR, TREE_TYPE(ovfl), ovfl,
+ t = build (POSTINCREMENT_EXPR, TREE_TYPE(ovfl), ovfl,
size_int (step_size));
r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
if (r != addr_rtx)
if (indirect)
{
r = gen_rtx_MEM (Pmode, addr_rtx);
- MEM_ALIAS_SET (r) = get_varargs_alias_set ();
+ set_mem_alias_set (r, get_varargs_alias_set ());
emit_move_insn (addr_rtx, r);
}
else
/* Not EABI. */
int align;
- /* ??? The original va-mips.h did always align, despite the fact
+ /* ??? The original va-mips.h did always align, despite the fact
that alignments <= UNITS_PER_WORD are preserved by the va_arg
increment mechanism. */
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));
register int i, start;
register int regno;
register enum machine_mode mode;
+ register enum processor_type mips_cpu;
mips_section_threshold = g_switch_set ? g_switch_value : MIPS_DEFAULT_GVALUE;
/* If both single-float and soft-float are set, then clear the one that
was set by TARGET_DEFAULT, leaving the one that was set by the
- user. We assume here that the specs prevent both being set by the
+ user. We assume here that the specs prevent both being set by the
user. */
#ifdef TARGET_DEFAULT
if (TARGET_SINGLE_FLOAT && TARGET_SOFT_FLOAT)
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
+ if (mips_abi_string == 0 && mips_isa_string
&& mips_abi != ABI_EABI && mips_abi != ABI_O64)
{
if (! ISA_HAS_64BIT_REGS)
}
/* A specified ABI defaults the ISA if it was not specified. */
- else if (mips_isa_string == 0 && mips_abi_string
+ else if (mips_isa_string == 0 && mips_abi_string
&& mips_abi != ABI_EABI && mips_abi != ABI_O64)
{
if (mips_abi == ABI_32)
greater than that supported by the default processor, then the user gets
an error. Normally, the compiler will just default to the base level cpu
for the indicated isa. */
- if (mips_cpu_string == 0)
- mips_cpu_string = MIPS_CPU_STRING_DEFAULT;
+ if (mips_arch_string == 0)
+ mips_arch_string = MIPS_CPU_STRING_DEFAULT;
+ if (mips_tune_string == 0)
+ mips_tune_string = MIPS_CPU_STRING_DEFAULT;
#endif
/* Identify the processor type. */
- if (mips_cpu_string == 0
- || ! strcmp (mips_cpu_string, "default")
- || ! strcmp (mips_cpu_string, "DEFAULT"))
+
+ if (mips_cpu_string != 0)
+ {
+ mips_cpu = mips_parse_cpu (mips_cpu_string);
+ if (mips_cpu == PROCESSOR_DEFAULT)
+ {
+ error ("bad value (%s) for -mcpu= switch", mips_arch_string);
+ mips_cpu_string = "default";
+ }
+ mips_arch = mips_cpu;
+ mips_tune = mips_cpu;
+ }
+
+ if (mips_arch_string == 0
+ || ! strcmp (mips_arch_string, "default")
+ || ! strcmp (mips_arch_string, "DEFAULT"))
{
switch (mips_isa)
{
default:
- mips_cpu_string = "3000";
- mips_cpu = PROCESSOR_R3000;
+ mips_arch_string = "3000";
+ mips_arch = PROCESSOR_R3000;
break;
case 2:
- mips_cpu_string = "6000";
- mips_cpu = PROCESSOR_R6000;
+ mips_arch_string = "6000";
+ mips_arch = PROCESSOR_R6000;
break;
case 3:
- mips_cpu_string = "4000";
- mips_cpu = PROCESSOR_R4000;
+ mips_arch_string = "4000";
+ mips_arch = PROCESSOR_R4000;
break;
case 4:
- mips_cpu_string = "8000";
- mips_cpu = PROCESSOR_R8000;
+ mips_arch_string = "8000";
+ mips_arch = PROCESSOR_R8000;
break;
}
}
else
{
- const char *p = mips_cpu_string;
- int seen_v = 0;
-
- /* We need to cope with the various "vr" prefixes for the NEC 4300
- and 4100 processors. */
- if (*p == 'v' || *p == 'V')
- seen_v = 1, p++;
-
- if (*p == 'r' || *p == 'R')
- p++;
-
- /* Since there is no difference between a R2000 and R3000 in
- terms of the scheduler, we collapse them into just an R3000. */
-
- mips_cpu = PROCESSOR_DEFAULT;
- switch (*p)
+ mips_arch = mips_parse_cpu (mips_arch_string);
+ if (mips_arch == PROCESSOR_DEFAULT)
{
- case '2':
- if (!strcmp (p, "2000") || !strcmp (p, "2k") || !strcmp (p, "2K"))
- mips_cpu = PROCESSOR_R3000;
- break;
-
- case '3':
- if (!strcmp (p, "3000") || !strcmp (p, "3k") || !strcmp (p, "3K"))
- mips_cpu = PROCESSOR_R3000;
- else if (!strcmp (p, "3900"))
- mips_cpu = PROCESSOR_R3900;
- break;
-
- case '4':
- if (!strcmp (p, "4000") || !strcmp (p, "4k") || !strcmp (p, "4K"))
- mips_cpu = PROCESSOR_R4000;
- /* The vr4100 is a non-FP ISA III processor with some extra
- instructions. */
- else if (!strcmp (p, "4100"))
- {
- mips_cpu = PROCESSOR_R4100;
- target_flags |= MASK_SOFT_FLOAT ;
- }
- /* The vr4300 is a standard ISA III processor, but with a different
- pipeline. */
- else if (!strcmp (p, "4300"))
- mips_cpu = PROCESSOR_R4300;
- /* 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;
- else if (!strcmp (p, "4650"))
- mips_cpu = PROCESSOR_R4650;
- break;
-
- case '5':
- if (!strcmp (p, "5000") || !strcmp (p, "5k") || !strcmp (p, "5K"))
- mips_cpu = PROCESSOR_R5000;
+ error ("bad value (%s) for -march= switch", mips_arch_string);
+ mips_arch_string = "default";
+ }
+ }
+ if (mips_tune_string == 0
+ || ! strcmp (mips_tune_string, "default")
+ || ! strcmp (mips_tune_string, "DEFAULT"))
+ {
+ if (mips_arch != PROCESSOR_DEFAULT)
+ mips_tune = mips_arch;
+ else
+ switch (mips_isa)
+ {
+ default:
+ mips_tune_string = "3000";
+ mips_tune = PROCESSOR_R3000;
break;
-
- case '6':
- if (!strcmp (p, "6000") || !strcmp (p, "6k") || !strcmp (p, "6K"))
- mips_cpu = PROCESSOR_R6000;
+ case 2:
+ mips_tune_string = "6000";
+ mips_tune = PROCESSOR_R6000;
break;
-
- case '8':
- if (!strcmp (p, "8000"))
- mips_cpu = PROCESSOR_R8000;
+ case 3:
+ mips_tune_string = "4000";
+ mips_tune = PROCESSOR_R4000;
break;
-
- case 'o':
- if (!strcmp (p, "orion"))
- mips_cpu = PROCESSOR_R4600;
+ case 4:
+ mips_tune_string = "8000";
+ mips_tune = PROCESSOR_R8000;
break;
}
- if (seen_v
- && mips_cpu != PROCESSOR_R4300
- && mips_cpu != PROCESSOR_R4100
- && mips_cpu != PROCESSOR_R5000)
- mips_cpu = PROCESSOR_DEFAULT;
-
- if (mips_cpu == PROCESSOR_DEFAULT)
+ }
+ else
+ {
+ mips_tune = mips_parse_cpu (mips_tune_string);
+ if (mips_tune == PROCESSOR_DEFAULT)
{
- error ("bad value (%s) for -mcpu= switch", mips_cpu_string);
- mips_cpu_string = "default";
+ error ("bad value (%s) for -mtune= switch", mips_tune_string);
+ mips_tune_string = "default";
}
}
- if ((mips_cpu == PROCESSOR_R3000 && (mips_isa != 1))
- || (mips_cpu == PROCESSOR_R6000 && mips_isa != 1 && mips_isa != 2)
- || ((mips_cpu == PROCESSOR_R4000
- || mips_cpu == PROCESSOR_R4100
- || mips_cpu == PROCESSOR_R4300
- || mips_cpu == PROCESSOR_R4600
- || mips_cpu == PROCESSOR_R4650)
+ /* Handle processor configuration based on architecture. */
+ if (TARGET_MIPS4100 || TARGET_MIPS3900)
+ target_flags |= MASK_SOFT_FLOAT;
+
+
+ if ((mips_arch == PROCESSOR_R3000 && (mips_isa != 1))
+ || (mips_arch == PROCESSOR_R6000 && mips_isa != 1 && mips_isa != 2)
+ || ((mips_arch == PROCESSOR_R4000
+ || mips_arch == PROCESSOR_R4100
+ || mips_arch == PROCESSOR_R4300
+ || mips_arch == PROCESSOR_R4600
+ || mips_arch == PROCESSOR_R4650)
&& mips_isa != 1 && mips_isa != 2 && mips_isa != 3))
- error ("-mcpu=%s does not support -mips%d", mips_cpu_string, mips_isa);
+ error ("-march=%s does not support -mips%d", mips_arch_string, mips_isa);
/* make sure sizes of ints/longs/etc. are ok */
if (! ISA_HAS_64BIT_REGS)
/* Provide default values for align_* for 64-bit targets. */
if (TARGET_64BIT && !TARGET_MIPS16)
{
- if (align_loops == 0)
+ if (align_loops == 0)
align_loops = 8;
- if (align_jumps == 0)
+ if (align_jumps == 0)
align_jumps = 8;
- if (align_functions == 0)
+ if (align_functions == 0)
align_functions = 8;
}
'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
'd' output integer constant in decimal,
'z' if the operand is 0, use $0 instead of normal operand.
- 'D' print second register of double-word register operand.
+ 'D' print second part of double-word register or memory operand.
'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.
fputs (".set\tnoat\n\t", file);
break;
- case ']':
+ case ']':
if (set_noat == 0)
error ("internal error: %%] found without a %%[ in assembler pattern");
else if (--set_noat == 0)
}
else if (code == MEM)
- output_address (XEXP (op, 0));
+ {
+ if (letter == 'D')
+ output_address (plus_constant (XEXP (op, 0), 4));
+ else
+ output_address (XEXP (op, 0));
+ }
else if (code == CONST_DOUBLE
&& GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT)
fprintf (stream, "\n\t%s.loc\t%d %d\n",
(ignore_line_number) ? "#" : "",
num_source_filenames, line);
-
+
LABEL_AFTER_LOC (stream);
}
}
\f
+/* Output an ASCII string, in a space-saving way. */
+
+void
+mips_output_ascii (stream, string_param, len)
+ FILE *stream;
+ const char *string_param;
+ size_t len;
+{
+ size_t i;
+ int cur_pos = 17;
+ register const unsigned char *string =
+ (const unsigned char *)string_param;
+
+ fprintf (stream, "\t.ascii\t\"");
+ for (i = 0; i < len; i++)
+ {
+ register int c = string[i];
+
+ switch (c)
+ {
+ case '\"':
+ case '\\':
+ putc ('\\', stream);
+ putc (c, stream);
+ cur_pos += 2;
+ break;
+
+ case TARGET_NEWLINE:
+ fputs ("\\n", stream);
+ if (i+1 < len
+ && (((c = string[i+1]) >= '\040' && c <= '~')
+ || c == TARGET_TAB))
+ cur_pos = 32767; /* break right here */
+ else
+ cur_pos += 2;
+ break;
+
+ case TARGET_TAB:
+ fputs ("\\t", stream);
+ cur_pos += 2;
+ break;
+
+ case TARGET_FF:
+ fputs ("\\f", stream);
+ cur_pos += 2;
+ break;
+
+ case TARGET_BS:
+ fputs ("\\b", stream);
+ cur_pos += 2;
+ break;
+
+ case TARGET_CR:
+ fputs ("\\r", stream);
+ cur_pos += 2;
+ break;
+
+ default:
+ if (c >= ' ' && c < 0177)
+ {
+ putc (c, stream);
+ cur_pos++;
+ }
+ else
+ {
+ fprintf (stream, "\\%03o", c);
+ cur_pos += 4;
+ }
+ }
+
+ if (cur_pos > 72 && i+1 < len)
+ {
+ cur_pos = 17;
+ fprintf (stream, "\"\n\t.ascii\t\"");
+ }
+ }
+ fprintf (stream, "\"\n");
+}
+\f
/* If defined, a C statement to be executed just prior to the output of
assembler code for INSN, to modify the extracted operands so they will be
output differently.
asm_out_data_file = asm_out_text_file = stream;
if (flag_verbose_asm)
- fprintf (stream, "\n%s -G value = %d, Cpu = %s, ISA = %d\n",
+ fprintf (stream, "\n%s -G value = %d, Arch = %s, ISA = %d\n",
ASM_COMMENT_START,
- mips_section_threshold, mips_cpu_string, mips_isa);
+ mips_section_threshold, mips_arch_string, mips_isa);
}
\f
/* If we are optimizing the global pointer, emit the text section now and any
}
}
}
-
+
if (TARGET_FILE_SWITCHING && ! TARGET_MIPS16)
{
fprintf (file, "\n\t.text\n");
}
}
+ /* We need to restore these for the handler. */
+ if (current_function_calls_eh_return)
+ {
+ int i;
+ for (i = 0; ; ++i)
+ {
+ regno = EH_RETURN_DATA_REGNO (i);
+ if (regno == INVALID_REGNUM)
+ break;
+ gp_reg_size += GET_MODE_SIZE (gpr_mode);
+ mask |= 1L << (regno - GP_REG_FIRST);
+ }
+ }
+
/* Calculate space needed for fp registers. */
if (TARGET_FLOAT64 || TARGET_SINGLE_FLOAT)
{
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
+ if (total_size == extra_size
&& (mips_abi == ABI_32 || mips_abi == ABI_O64 || mips_abi == ABI_EABI)
&& ! profile_flag)
total_size = extra_size = 0;
insn = emit_move_insn (mem_rtx, reg_rtx);
RTX_FRAME_RELATED_P (insn) = 1;
}
- else if (!TARGET_ABICALLS
+ else if (!TARGET_ABICALLS
|| (mips_abi != ABI_32 && mips_abi != ABI_O64)
|| regno != (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
{
}
else
{
- if (store_p || !TARGET_ABICALLS
+ if (store_p || !TARGET_ABICALLS
|| (mips_abi != ABI_32 && mips_abi != ABI_O64)
|| regno != (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
{
? (store_p) ? "sd" : "ld"
: (store_p) ? "sw" : "lw"),
reg_names[r]);
- fprintf (file, HOST_WIDE_INT_PRINT_DEC,
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC,
gp_offset - base_offset);
fprintf (file, "(%s)\n", reg_names[REGNO(base_reg_rtx)]);
if (! store_p
\f
/* Set up the stack and frame (if desired) for the function. */
-void
-function_prologue (file, size)
+static void
+mips_output_function_prologue (file, size)
FILE *file;
HOST_WIDE_INT size ATTRIBUTE_UNUSED;
{
/* For arguments passed in registers, find the register number
of the first argument in the variable part of the argument list,
- otherwise GP_ARG_LAST+1. Note also if the last argument is
+ otherwise GP_ARG_LAST+1. Note also if the last argument is
the varargs special argument, and treat it as part of the
variable arguments.
-
+
This is only needed if store_args_on_stack is true. */
INIT_CUMULATIVE_ARGS (args_so_far, fntype, NULL_RTX, 0);
#define RA_MASK BITMASK_HIGH /* 1 << 31 */
#define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
-void
-function_epilogue (file, size)
+static void
+mips_output_function_epilogue (file, size)
FILE *file ATTRIBUTE_UNUSED;
HOST_WIDE_INT size ATTRIBUTE_UNUSED;
{
- const char *fnname;
+ const char *fnname = ""; /* FIXME: Correct initialisation? */
#ifndef FUNCTION_NAME_ALREADY_DECLARED
/* Get the function name the same way that toplev.c does before calling
g6_rtx));
tsize = 0;
}
-
+
if (tsize && tsize != orig_tsize)
tsize_rtx = GEN_INT (tsize);
}
if (tsize > 32767 && TARGET_MIPS16)
abort ();
+ if (current_function_calls_eh_return)
+ {
+ rtx eh_ofs = EH_RETURN_STACKADJ_RTX;
+ if (Pmode == DImode)
+ emit_insn (gen_adddi3 (eh_ofs, eh_ofs, tsize_rtx));
+ else
+ emit_insn (gen_addsi3 (eh_ofs, eh_ofs, tsize_rtx));
+ tsize_rtx = eh_ofs;
+ }
+
emit_insn (gen_blockage ());
- if (Pmode == DImode && tsize != 0)
- emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx,
- tsize_rtx));
- else if (tsize != 0)
- emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
- tsize_rtx));
+
+ if (tsize != 0 || current_function_calls_eh_return)
+ {
+ if (Pmode == DImode)
+ 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));
+ }
}
/* The mips16 loads the return address into $7, not $31. */
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));
{
/* For hosted applications, always put constants in small data if
possible, as this gives the best performance. */
-
+
if (GET_MODE_SIZE (mode) <= (unsigned) mips_section_threshold
&& mips_section_threshold > 0)
SMALL_DATA_SECTION ();
}
else if (TREE_CODE (valtype) == RECORD_TYPE
- && mips_abi != ABI_32
- && mips_abi != ABI_O64
+ && 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
fields[i++] = field;
}
-
+
/* Must check i, so that we reject structures with no elements. */
if (! field)
{
here hopefully is not relevant to mips_va_arg. */
if (cum && MUST_PASS_IN_STACK (mode, type))
{
- /* Don't pass the actual CUM to FUNCTION_ARG, because we would
- get double copies of any offsets generated for small structs
+ /* Don't pass the actual CUM to FUNCTION_ARG, because we would
+ get double copies of any offsets generated for small structs
passed in registers. */
CUMULATIVE_ARGS temp;
temp = *cum;
{
while (GET_CODE (x) == SUBREG)
{
- off += SUBREG_WORD (x);
+ off += subreg_regno_offset (REGNO (SUBREG_REG (x)),
+ GET_MODE (SUBREG_REG (x)),
+ SUBREG_BYTE (x),
+ GET_MODE (x));
x = SUBREG_REG (x);
}
&& strncmp (XSTR (fn, 0), "__mips16_", 9) == 0)
return 0;
- /* This code will only work for o32 and o64 abis. 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 && mips_abi != ABI_O64)
abort ();
emit_insn_after (gen_rtx (SET, VOIDmode, SET_DEST (set1),
force_const_mem (Pmode, sym)),
next);
-
+
PUT_CODE (insn, NOTE);
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (insn) = 0;
constants = NULL;
first_constant_ref = -1;
}
-
+
if (constants != NULL
- && (NEXT_INSN (insn) == NULL
- || (first_constant_ref >= 0
+ && (NEXT_INSN (insn) == NULL
+ || (first_constant_ref >= 0
&& (((addr - first_constant_ref)
+ 2 /* for alignment */
+ 2 /* for a short jump insn */
emit a barrier now. */
rtx label, jump, barrier;
-
+
label = gen_label_rtx ();
jump = emit_jump_insn_after (gen_jump (label), insn);
JUMP_LABEL (jump) = label;
|| code == ROTATE);
}
-/* Return the length of INSN. LENGTH is the initial length computed by
+/* Return the length of INSN. LENGTH is the initial length computed by
attributes in the machine-description file. */
int
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
+ || (!TARGET_MIPS16 && (GET_CODE (insn) == JUMP_INSN
|| GET_CODE (insn) == CALL_INSN)))
length += 4;
return length;
}
-/* Output assembly instructions to peform a conditional branch.
+/* 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
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,
+mips_output_conditional_branch (insn,
+ operands,
two_operands_p,
float_p,
inverted_p,
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
+ /* For comparisons against zero, the zero is not provided
explicitly. */
if (need_z_p)
op2 = "";
strcat to add to it. */
buffer[0] = '\0';
- switch (length)
+ switch (length)
{
case 4:
case 8:
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
+ 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
+ /* Generate the reversed comparision. This takes four
bytes. */
if (float_p)
sprintf (c, "%%*b%s\t%%Z2%s",
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'.
+ to give for `x'.
So, we resort to using the explicit relocation syntax
available in the assembler and do:
anything. */
/* The target of the reversed branch. */
- const char *target
+ 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];
strcpy (buffer, "%(%<%[");
c = strchr (buffer, '\0');
- /* Generate the reversed comparision. This takes four
+ /* Generate the reversed comparision. This takes four
bytes. */
if (float_p)
sprintf (c, "%%*b%s\t%%Z2%s",
ggc_add_rtx_root (&embedded_pic_fnaddr_rtx, 1);
ggc_add_rtx_root (&mips16_gp_pseudo_rtx, 1);
}
+
+static enum processor_type
+mips_parse_cpu (cpu_string)
+ const char *cpu_string;
+{
+ const char *p = cpu_string;
+ int seen_v = 0;
+ enum processor_type cpu;
+
+ /* We need to cope with the various "vr" prefixes for the NEC 4300
+ and 4100 processors. */
+ if (*p == 'v' || *p == 'V')
+ seen_v = 1, p++;
+
+ if (*p == 'r' || *p == 'R')
+ p++;
+
+ /* Since there is no difference between a R2000 and R3000 in
+ terms of the scheduler, we collapse them into just an R3000. */
+
+ cpu = PROCESSOR_DEFAULT;
+ switch (*p)
+ {
+ case '2':
+ if (!strcmp (p, "2000") || !strcmp (p, "2k") || !strcmp (p, "2K"))
+ cpu = PROCESSOR_R3000;
+ break;
+
+ case '3':
+ if (!strcmp (p, "3000") || !strcmp (p, "3k") || !strcmp (p, "3K"))
+ cpu = PROCESSOR_R3000;
+ else if (!strcmp (p, "3900"))
+ cpu = PROCESSOR_R3900;
+ break;
+
+ case '4':
+ if (!strcmp (p, "4000") || !strcmp (p, "4k") || !strcmp (p, "4K"))
+ cpu = PROCESSOR_R4000;
+ /* The vr4100 is a non-FP ISA III processor with some extra
+ instructions. */
+ else if (!strcmp (p, "4100"))
+ cpu = PROCESSOR_R4100;
+ /* The vr4300 is a standard ISA III processor, but with a different
+ pipeline. */
+ else if (!strcmp (p, "4300"))
+ cpu = PROCESSOR_R4300;
+ /* The r4400 is exactly the same as the r4000 from the compiler's
+ viewpoint. */
+ else if (!strcmp (p, "4400"))
+ cpu = PROCESSOR_R4000;
+ else if (!strcmp (p, "4600"))
+ cpu = PROCESSOR_R4600;
+ else if (!strcmp (p, "4650"))
+ cpu = PROCESSOR_R4650;
+ break;
+
+ case '5':
+ if (!strcmp (p, "5000") || !strcmp (p, "5k") || !strcmp (p, "5K"))
+ cpu = PROCESSOR_R5000;
+ break;
+
+ case '6':
+ if (!strcmp (p, "6000") || !strcmp (p, "6k") || !strcmp (p, "6K"))
+ cpu = PROCESSOR_R6000;
+ break;
+
+ case '8':
+ if (!strcmp (p, "8000"))
+ cpu = PROCESSOR_R8000;
+ break;
+
+ case 'o':
+ if (!strcmp (p, "orion"))
+ cpu = PROCESSOR_R4600;
+ break;
+ }
+
+ if (seen_v
+ && cpu != PROCESSOR_R4300
+ && cpu != PROCESSOR_R4100
+ && cpu != PROCESSOR_R5000)
+ cpu = PROCESSOR_DEFAULT;
+
+ return cpu;
+}