#include "recog.h"
#include "toplev.h"
#include "output.h"
-
#include "tree.h"
#include "function.h"
#include "expr.h"
#include "tm_p.h"
#include "ggc.h"
#include "gstab.h"
+#include "hashtab.h"
+#include "debug.h"
#include "target.h"
#include "target-def.h"
+#ifdef HALF_PIC_DEBUG
+#include "halfpic.h"
+#endif
+
#ifdef __GNU_STAB__
#define STAB_CODE_TYPE enum __stab_debug_code
#else
/* Enumeration for all of the relational tests, so that we can build
arrays indexed by the test type, and not worry about the order
- of EQ, NE, etc. */
+ of EQ, NE, etc. */
enum internal_test {
ITEST_EQ,
int,
rtx, rtx));
static void block_move_call PARAMS ((rtx, rtx, rtx));
-static FILE *mips_make_temp_file PARAMS ((void));
+static rtx mips_add_large_offset_to_sp PARAMS ((HOST_WIDE_INT,
+ FILE *));
+static void mips_annotate_frame_insn PARAMS ((rtx, rtx));
+static rtx mips_frame_set PARAMS ((enum machine_mode,
+ int, int));
+static void mips_emit_frame_related_store PARAMS ((rtx, rtx,
+ HOST_WIDE_INT));
static void save_restore_insns PARAMS ((int, rtx,
long, FILE *));
static void mips16_output_gp_offset PARAMS ((FILE *, rtx));
ATTRIBUTE_NORETURN;
static int symbolic_expression_p PARAMS ((rtx));
static void mips_add_gc_roots PARAMS ((void));
+static bool mips_assemble_integer PARAMS ((rtx, unsigned int, int));
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 *));
+static void copy_file_data PARAMS ((FILE *, FILE *));
+#ifdef TARGET_IRIX6
+static void iris6_asm_named_section_1 PARAMS ((const char *,
+ unsigned int,
+ unsigned int));
+static void iris6_asm_named_section PARAMS ((const char *,
+ unsigned int));
+static int iris_section_align_entry_eq PARAMS ((const PTR, const PTR));
+static hashval_t iris_section_align_entry_hash PARAMS ((const PTR));
+static int iris6_section_align_1 PARAMS ((void **, void *));
+#endif
+static int mips_adjust_cost PARAMS ((rtx, rtx, rtx, int));
/* Global variables for machine-dependent things. */
start and end boundaries). */
int sdb_label_count = 0;
-/* Next label # for each statement for Silicon Graphics IRIS systems. */
+/* Next label # for each statement for Silicon Graphics IRIS systems. */
int sym_lineno = 0;
/* Non-zero if inside of a function, because the stupid MIPS asm can't
/* The target cpu for optimization and scheduling. */
enum processor_type mips_tune;
-/* Historical option for code generation and scheduling. */
-enum processor_type mips_cpu;
-
/* which instruction set architecture to use. */
int mips_isa;
-#ifdef MIPS_ABI_DEFAULT
-/* Which ABI to use. This is defined to a constant in mips.h if the target
- doesn't support multiple ABIs. */
+/* which abi to use. */
int mips_abi;
-#endif
/* Strings to hold which cpu and instruction set architecture to use. */
const char *mips_cpu_string; /* for -mcpu=<xxx> */
/* 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. */
+ 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
avoid using up another bit in target_flags. */
const char *mips_entry_string;
+const char *mips_cache_flush_func = CACHE_FLUSH_FUNC;
+
/* Whether we should entry and exit pseudo-ops in mips16 mode. */
int mips_entry;
/* Zero structure to initialize current_frame_info. */
struct mips_frame_info zero_frame_info;
-/* Temporary filename used to buffer .text until end of program
- for -mgpopt. */
-static char *temp_filename;
-
/* Pseudo-reg holding the address of the current function when
generating embedded PIC code. Created by LEGITIMIZE_ADDRESS, used
by mips_finalize_pic if it was created. */
/* Mips software names for the registers, used to overwrite the
mips_reg_names array. */
-char mips_sw_reg_names[][8] =
+static const char mips_sw_reg_names[][8] =
{
"$zero","$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3",
"$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7",
};
/* Map hard register number to register class */
-enum reg_class mips_regno_to_class[] =
+const enum reg_class mips_regno_to_class[] =
{
GR_REGS, GR_REGS, M16_NA_REGS, M16_NA_REGS,
M16_REGS, M16_REGS, M16_REGS, M16_REGS,
};
\f
/* Initialize the GCC target structure. */
+#undef TARGET_ASM_ALIGNED_HI_OP
+#define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
+#undef TARGET_ASM_ALIGNED_SI_OP
+#define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
+#undef TARGET_ASM_INTEGER
+#define TARGET_ASM_INTEGER mips_assemble_integer
+
+#if TARGET_IRIX5 && !TARGET_IRIX6
+#undef TARGET_ASM_UNALIGNED_HI_OP
+#define TARGET_ASM_UNALIGNED_HI_OP "\t.align 0\n\t.half\t"
+#undef TARGET_ASM_UNALIGNED_SI_OP
+#define TARGET_ASM_UNALIGNED_SI_OP "\t.align 0\n\t.word\t"
+#endif
+
#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
+#undef TARGET_SCHED_ADJUST_COST
+#define TARGET_SCHED_ADJUST_COST mips_adjust_cost
+
struct gcc_target targetm = TARGET_INITIALIZER;
\f
/* Return truth value of whether OP can be used as an operands
return register_operand (op, mode);
}
-/* Return truth value of whether OP is a integer which fits in 16 bits */
+/* Return truth value of whether OP is an integer which fits in 16 bits. */
int
small_int (op, mode)
}
/* Return truth value of whether OP is a register or the constant 0,
- even in mips16 mode. */
+ even in mips16 mode. */
int
true_reg_or_0_operand (op, mode)
if (GET_CODE (op) != SYMBOL_REF)
return 0;
- /* let's be paranoid.... */
+ /* let's be paranoid.... */
if (! SMALL_INT (offset))
return 0;
}
return 1;
/* Similarly, we accept a case where the memory address is
- itself on the stack, and will be reloaded. */
+ itself on the stack, and will be reloaded. */
if (GET_CODE (addr) == MEM)
{
rtx maddr;
}
/* Check for constant before stripping off SUBREG, so that we don't
- accept (subreg (const_int)) which will fail to reload. */
+ 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)))
|| 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))
+ the assembler will sign-extend the constant "foo"
+ in "la x, foo(x)" yielding the wrong result for:
+ (set (blah:DI) (plus x y)). */
+ && (!TARGET_64BIT
+ || (code1 == CONST_INT
+ && trunc_int_for_mode (INTVAL (xplus1),
+ SImode) == INTVAL (xplus1)))
&& !TARGET_MIPS16)
return 1;
}
if (ret == 0)
{
- abort_with_insn (insn, "Bad move");
+ abort_with_insn (insn, "bad move");
return 0;
}
if (TARGET_FLOAT64)
{
if (!TARGET_64BIT)
- abort_with_insn (insn, "Bad move");
+ abort_with_insn (insn, "bad move");
#ifdef TARGET_FP_CALL_32
if (FP_CALL_GP_REG_P (regno1))
if (TARGET_FLOAT64)
{
if (!TARGET_64BIT)
- abort_with_insn (insn, "Bad move");
+ abort_with_insn (insn, "bad move");
#ifdef TARGET_FP_CALL_32
if (FP_CALL_GP_REG_P (regno0))
}
else if (double_memory_operand (op1, GET_MODE (op1)))
- {
- operands[2] = adjust_address (op1, SImode, 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))
{
}
else if (double_memory_operand (op0, GET_MODE (op0)))
- {
- operands[2] = adjust_address (op0, SImode, 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] = adjust_address (op0, SImode, 4);
- ret = "sw\t%.,%0\n\tsw\t%.,%2";
- }
+ ret = "sw\t%.,%0\n\tsw\t%.,%D0";
}
if (TARGET_STATS)
if (ret == 0)
{
- abort_with_insn (insn, "Bad move");
+ abort_with_insn (insn, "bad move");
return 0;
}
return 2;
}
- /* ... fall through ... */
+ /* ... fall through ... */
case SYMBOL_REF:
return SYMBOL_REF_FLAG (addr) ? 1 : 2;
if (! TARGET_MIPS16)
{
convert_move (result, gen_rtx (GTU, mode, reg, const0_rtx), 0);
+ if (p_invert != NULL)
+ *p_invert = 0;
invert = 0;
}
else
The block move type can be one of the following:
BLOCK_MOVE_NORMAL Do all of the block move.
BLOCK_MOVE_NOT_LAST Do all but the last store.
- BLOCK_MOVE_LAST Do just the last store. */
+ BLOCK_MOVE_LAST Do just the last store. */
const char *
output_block_move (insn, operands, num_regs, move_type)
constant addresses into registers when generating N32/N64 code, just
in case we might emit an unaligned load instruction. */
if (num_regs > 2 && (bytes > 2 * align || move_type != BLOCK_MOVE_NORMAL
- || mips_abi == ABI_N32 || mips_abi == ABI_64))
+ || mips_abi == ABI_MEABI
+ || mips_abi == ABI_N32
+ || mips_abi == ABI_64))
{
if (CONSTANT_P (src_reg))
{
else if (num_regs < 1)
abort_with_insn (insn,
- "Cannot do block move, not enough scratch registers");
+ "cannot do block move, not enough scratch registers");
while (bytes > 0)
{
}
*cum = zero_cum;
+ cum->prototype = (fntype && TYPE_ARG_TYPES (fntype));
/* Determine if this function has variable arguments. This is
indicated by the last argument being 'void_type_mode' if there
are no variable arguments. The standard MIPS calling sequence
- passes all arguments in the general purpose registers in this case. */
+ passes all arguments in the general purpose registers in this case. */
for (param = fntype ? TYPE_ARG_TYPES (fntype) : 0;
param != 0; param = next_param)
arg_words = &cum->fp_arg_words;
regbase = FP_ARG_FIRST;
}
+ /* The MIPS eabi says only structures containing doubles get passed in a
+ fp register, so force a structure containing a float to be passed in
+ the integer registers. */
+ else if (mips_abi == ABI_MEABI && struct_p)
+ regbase = GP_ARG_FIRST;
else
regbase = (TARGET_SOFT_FLOAT || ! named ? GP_ARG_FIRST : FP_ARG_FIRST);
break;
if (regbase == -1)
abort ();
- if (! type || TREE_CODE (type) != RECORD_TYPE || mips_abi == ABI_32
- || mips_abi == ABI_EABI || mips_abi == ABI_O64 || ! named
+ if (! type || TREE_CODE (type) != RECORD_TYPE
+ || mips_abi == ABI_32 || mips_abi == ABI_EABI
+ || mips_abi == ABI_O64 || mips_abi == ABI_MEABI
+ || ! named
|| ! TYPE_SIZE_UNIT (type)
|| ! host_integerp (TYPE_SIZE_UNIT (type), 1))
- ret = gen_rtx_REG (mode, regbase + *arg_words + bias);
+ {
+
+ unsigned int arg_reg = (regbase + *arg_words + bias);
+ ret = gen_rtx_REG (mode, arg_reg);
+ if (mips_abi == ABI_MEABI
+ && regbase == FP_ARG_FIRST
+ && ! cum->prototype)
+ {
+ /* To make K&R varargs work we need to pass floating
+ point arguments in both integer and FP registers. */
+ ret = gen_rtx_PARALLEL (mode,
+ gen_rtvec (2,
+ gen_rtx_EXPR_LIST (VOIDmode,
+ gen_rtx_REG (mode,
+ arg_reg + GP_ARG_FIRST - FP_ARG_FIRST),
+ const0_rtx), gen_rtx_EXPR_LIST (VOIDmode, ret, const0_rtx)));
+ }
+ }
else
{
/* The Irix 6 n32/n64 ABIs say that if any 64 bit chunk of the
if (field
&& int_bit_position (field) == bitpos
&& TREE_CODE (TREE_TYPE (field)) == REAL_TYPE
+ && !TARGET_SOFT_FLOAT
&& TYPE_PRECISION (TREE_TYPE (field)) == BITS_PER_WORD)
reg = gen_rtx_REG (DFmode,
regno + FP_ARG_FIRST - GP_ARG_FIRST);
calling convention for now. */
if (struct_p && int_size_in_bytes (type) < UNITS_PER_WORD
- && ! TARGET_64BIT && mips_abi != ABI_EABI)
+ && ! TARGET_64BIT
+ && mips_abi != ABI_EABI
+ && mips_abi != ABI_MEABI)
{
rtx amount = GEN_INT (BITS_PER_WORD
- int_size_in_bytes (type) * BITS_PER_UNIT);
Note that the GPR save area is not constant size, due to optimization
in the prologue. Hence, we can't use a design with two pointers
and two offsets, although we could have designed this with two pointers
- and three offsets. */
+ and three offsets. */
tree
if (mips_abi == ABI_EABI)
{
int gpr_save_area_size;
- /* Note UNITS_PER_WORD is 4 bytes or 8, depending on TARGET_64BIT. */
+ /* Note UNITS_PER_WORD is 4 bytes or 8, depending on TARGET_64BIT. */
if (int_arg_words < 8 )
/* Adjust for the prologue's economy measure */
gpr_save_area_size = (8 - int_arg_words) * UNITS_PER_WORD;
/* Emit code setting a pointer into the overflow (shared-stack) area.
If there were more than 8 non-float formals, or more than 8
float formals, then this pointer isn't to the base of the area.
- In that case, it must point to where the first vararg is. */
+ In that case, it must point to where the first vararg is. */
size_excess = 0;
if (float_formals > floats_passed_in_regs)
size_excess += (float_formals-floats_passed_in_regs) * 8;
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.
- The above then reduces to a fetch from that struct. */
+ The above then reduces to a fetch from that struct. */
t = make_tree (TREE_TYPE (ovfl), virtual_incoming_args_rtx);
t = build (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t);
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
- /* Emit code setting a ptr to the base of the overflow area. */
+ /* Emit code setting a ptr to the base of the overflow area. */
t = make_tree (TREE_TYPE (gtop), virtual_incoming_args_rtx);
t = build (MODIFY_EXPR, TREE_TYPE (gtop), gtop, t);
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
If mips4, this is gpr_save_area_size below the overflow area.
If mips2, also round down to an 8-byte boundary, since the FPR
save area is 8-byte aligned, and GPR is 4-byte-aligned.
- Therefore there can be a 4-byte gap between the save areas. */
+ Therefore there can be a 4-byte gap between the save areas. */
gprv = make_tree (TREE_TYPE (ftop), virtual_incoming_args_rtx);
fpr_save_offset = gpr_save_area_size;
if (!TARGET_64BIT)
/* TARGET_SOFT_FLOAT or TARGET_SINGLE_FLOAT */
/* Everything is in the GPR save area, or in the overflow
- area which is contiguous with it. */
+ area which is contiguous with it. */
int offset = -gpr_save_area_size;
if (gpr_save_area_size == 0)
and both iris5.h and iris6.h define _MIPS_SIM. */
if (mips_abi == ABI_N32 || mips_abi == ABI_64)
ofs = (int_arg_words >= 8 ? -UNITS_PER_WORD : 0);
+ else if (mips_abi == ABI_MEABI)
+ ofs = (int_arg_words >= 8 ? -UNITS_PER_WORD : 0);
else
ofs = -UNITS_PER_WORD;
}
if (TARGET_SOFT_FLOAT || TARGET_SINGLE_FLOAT)
{
/* Case of all args in a merged stack. No need to check bounds,
- just advance valist along the stack. */
+ just advance valist along the stack. */
tree gpr = valist;
if (! indirect
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
return addr_rtx;
}
- /* Not a simple merged stack. Need ptrs and indexes left by va_start. */
+ /* Not a simple merged stack. Need ptrs and indexes left by va_start. */
f_ovfl = TYPE_FIELDS (va_list_type_node);
f_gtop = TREE_CHAIN (f_ovfl);
if (TREE_CODE (type) == REAL_TYPE)
{
- /* Emit code to branch if foff == 0. */
+ /* Emit code to branch if foff == 0. */
r = expand_expr (foff, NULL_RTX, TYPE_MODE (TREE_TYPE (foff)),
EXPAND_NORMAL);
- emit_cmp_and_jump_insns (r, const0_rtx, EQ,
- const1_rtx, GET_MODE (r), 1, 1, lab_false);
+ emit_cmp_and_jump_insns (r, const0_rtx, EQ, const1_rtx, GET_MODE (r),
+ 1, lab_false);
/* Emit code for addr_rtx = ftop - foff */
t = build (MINUS_EXPR, TREE_TYPE (ftop), ftop, foff );
/* For mips2, the overflow area contains mixed size items.
If a 4-byte int is followed by an 8-byte float, then
natural alignment causes a 4 byte gap.
- So, dynamically adjust ovfl up to a multiple of 8. */
+ So, dynamically adjust ovfl up to a multiple of 8. */
t = build (BIT_AND_EXPR, TREE_TYPE (ovfl), ovfl,
build_int_2 (7, 0));
t = build (PLUS_EXPR, TREE_TYPE (ovfl), ovfl, t);
}
/* Emit code for addr_rtx = the ovfl pointer into overflow area.
- Regardless of mips2, postincrement the ovfl pointer by 8. */
+ Regardless of mips2, postincrement the ovfl pointer by 8. */
t = build (POSTINCREMENT_EXPR, TREE_TYPE(ovfl), ovfl,
size_int (8));
r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
/* 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. */
+ the later calculation of (gtop-goff) upwards. */
t = build (BIT_AND_EXPR, TREE_TYPE (goff), goff,
build_int_2 (-8, -1));
t = build (MODIFY_EXPR, TREE_TYPE (goff), goff, t);
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
}
- /* Emit code to branch if goff == 0. */
+ /* Emit code to branch if goff == 0. */
r = expand_expr (goff, NULL_RTX, TYPE_MODE (TREE_TYPE (goff)),
EXPAND_NORMAL);
- emit_cmp_and_jump_insns (r, const0_rtx, EQ,
- const1_rtx, GET_MODE (r), 1, 1, lab_false);
+ emit_cmp_and_jump_insns (r, const0_rtx, EQ, const1_rtx, GET_MODE (r),
+ 1, lab_false);
- /* Emit code for addr_rtx = gtop - goff. */
+ /* Emit code for addr_rtx = gtop - goff. */
t = build (MINUS_EXPR, TREE_TYPE (gtop), gtop, goff);
r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
if (r != addr_rtx)
emit_move_insn (addr_rtx, r);
- /* Note that mips2 int is 32 bit, but mips2 longlong is 64. */
+ /* Note that mips2 int is 32 bit, but mips2 longlong is 64. */
if (! TARGET_64BIT && TYPE_PRECISION (type) == 64)
step_size = 8;
else
step_size = UNITS_PER_WORD;
/* Emit code for goff = goff - step_size.
- Advances the offset up GPR save area over the item. */
+ Advances the offset up GPR save area over the item. */
t = build (MINUS_EXPR, TREE_TYPE (goff), goff,
build_int_2 (step_size, 0));
t = build (MODIFY_EXPR, TREE_TYPE (goff), goff, t);
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
}
else
{
- /* Not EABI. */
+ /* Not EABI. */
int align;
/* ??? The original va-mips.h did always align, despite the fact
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. */
+ user. */
#ifdef TARGET_DEFAULT
if (TARGET_SINGLE_FLOAT && TARGET_SOFT_FLOAT)
target_flags &= ~((TARGET_DEFAULT) & (MASK_SOFT_FLOAT | MASK_SINGLE_FLOAT));
mips_isa = MIPS_ISA_DEFAULT;
}
}
- else if (mips_isa < 1 || mips_isa > 4)
+ else if (mips_isa < 1
+ || (mips_isa > 4
+ && mips_isa != 32
+ && mips_isa != 64))
{
error ("-mips%d not supported", mips_isa);
mips_isa = 1;
}
#ifdef MIPS_ABI_DEFAULT
- /* Get the ABI to use. */
+ /* Get the ABI to use. */
if (mips_abi_string == (char *) 0)
mips_abi = MIPS_ABI_DEFAULT;
else if (! strcmp (mips_abi_string, "32"))
mips_abi = ABI_64;
else if (! strcmp (mips_abi_string, "eabi"))
mips_abi = ABI_EABI;
+ else if (! strcmp (mips_abi_string, "meabi"))
+ mips_abi = ABI_MEABI;
else
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 && mips_abi != ABI_O64)
+ && mips_abi != ABI_EABI
+ && mips_abi != ABI_O64
+ && mips_abi != ABI_MEABI)
{
- if (! ISA_HAS_64BIT_REGS)
- mips_abi = ABI_32;
+ if (mips_isa == 64)
+ mips_abi = ABI_O64;
else
- mips_abi = ABI_64;
+ {
+ if (! ISA_HAS_64BIT_REGS)
+ mips_abi = ABI_32;
+ else
+ mips_abi = ABI_64;
+ }
}
+#ifdef MIPS_CPU_STRING_DEFAULT
/* A specified ABI defaults the ISA if it was not specified. */
else if (mips_isa_string == 0 && mips_abi_string
&& mips_abi != ABI_EABI && mips_abi != ABI_O64)
else
mips_isa = 4;
}
+#endif
/* If both ABI and ISA were specified, check for conflicts. */
else if (mips_isa_string && mips_abi_string)
{
- if ((! ISA_HAS_64BIT_REGS && (mips_abi == ABI_N32 || mips_abi == ABI_64
+ if (! ISA_HAS_64BIT_REGS && (mips_abi == ABI_N32 || mips_abi == ABI_64
|| mips_abi == ABI_O64))
- || (ISA_HAS_64BIT_REGS && mips_abi == ABI_32))
error ("-mabi=%s does not support -mips%d", mips_abi_string, mips_isa);
}
|| mips_abi == ABI_64))
target_flags |= MASK_LONG64;
- /* ??? This doesn't work yet, so don't let people try to use it. */
- if (mips_abi == ABI_32)
- error ("The -mabi=32 support does not work yet.");
-
#else
if (mips_abi_string)
- error ("This target does not support the -mabi switch.");
+ error ("this target does not support the -mabi switch");
#endif
#ifdef MIPS_CPU_STRING_DEFAULT
mips_arch_string = "8000";
mips_arch = PROCESSOR_R8000;
break;
+ case 32:
+ mips_arch_string = "4kc";
+ mips_arch = PROCESSOR_R4KC;
+ break;
+ case 64:
+ mips_arch_string = "5kc";
+ mips_arch = PROCESSOR_R5KC;
+ break;
}
}
else
mips_tune_string = "8000";
mips_tune = PROCESSOR_R8000;
break;
+ case 32:
+ mips_tune_string = "4kc";
+ mips_tune = PROCESSOR_R4KC;
+ break;
+ case 64:
+ mips_tune_string = "5kc";
+ mips_tune = PROCESSOR_R5KC;
+ break;
}
}
}
}
- /* 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_R4KC && mips_isa != 32)
+ || ((mips_arch == PROCESSOR_R5KC
+ || mips_arch == PROCESSOR_R20KC) && mips_isa != 64)
|| (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_R4100
+ || mips_arch == PROCESSOR_R4300
|| mips_arch == PROCESSOR_R4600
|| mips_arch == PROCESSOR_R4650)
&& mips_isa != 1 && mips_isa != 2 && mips_isa != 3))
if (mips_entry_string != NULL)
{
if (*mips_entry_string != '\0')
- error ("Invalid option `entry%s'", mips_entry_string);
+ error ("invalid option `entry%s'", mips_entry_string);
if (! TARGET_MIPS16)
warning ("-mentry is only meaningful with -mips-16");
temp = ((regno & 1) == 0 || size <= UNITS_PER_WORD);
else if (FP_REG_P (regno))
- temp = ((TARGET_FLOAT64 || ((regno & 1) == 0))
+ temp = ((TARGET_FLOAT64 || ((regno & 1) == 0)
+ /* I think this change is OK regardless of abi, but
+ I'm being cautions untill I can test this more.
+ HARD_REGNO_MODE_OK is about whether or not you
+ can move to and from a register without changing
+ the value, not about whether math works on the
+ register. */
+ || (mips_abi == ABI_MEABI && size <= 4))
&& (class == MODE_FLOAT
|| class == MODE_COMPLEX_FLOAT
|| (TARGET_DEBUG_H_MODE && class == MODE_INT))
/* sdbout_parms does not want this to crash for unrecognized cases. */
#if 0
else if (reg != arg_pointer_rtx)
- abort_with_insn (addr, "mips_debugger_offset called with non stack/frame/arg pointer.");
+ abort_with_insn (addr, "mips_debugger_offset called with non stack/frame/arg pointer");
#endif
return offset;
'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.
break;
default:
- error ("PRINT_OPERAND: Unknown punctuation '%c'", letter);
+ error ("PRINT_OPERAND: unknown punctuation '%c'", letter);
break;
}
}
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)
{
case REG:
if (! TARGET_MIPS16 && REGNO (addr) == ARG_POINTER_REGNUM)
- abort_with_insn (addr, "Arg pointer not eliminated.");
+ abort_with_insn (addr, "arg pointer not eliminated");
fprintf (file, "0(%s)", reg_names [REGNO (addr)]);
break;
register rtx arg1 = XEXP (addr, 1);
if (! mips_split_addresses)
- abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, Spurious LO_SUM.");
+ abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, Spurious LO_SUM");
if (GET_CODE (arg0) != REG)
abort_with_insn (addr,
- "PRINT_OPERAND_ADDRESS, LO_SUM with #1 not REG.");
+ "PRINT_OPERAND_ADDRESS, LO_SUM with #1 not REG");
fprintf (file, "%%lo(");
print_operand_address (file, arg1);
abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, invalid insn #2");
if (REGNO (reg) == ARG_POINTER_REGNUM)
- abort_with_insn (addr, "Arg pointer not eliminated.");
+ abort_with_insn (addr, "arg pointer not eliminated");
if (TARGET_MIPS16
&& GET_CODE (offset) == CONST
break;
}
}
+\f
+/* Target hook for assembling integer objects. It appears that the Irix
+ 6 assembler can't handle 64-bit decimal integers, so avoid printing
+ such an integer here. */
+static bool
+mips_assemble_integer (x, size, aligned_p)
+ rtx x;
+ unsigned int size;
+ int aligned_p;
+{
+ if ((TARGET_64BIT || TARGET_GAS) && size == 8 && aligned_p)
+ {
+ fputs ("\t.dword\t", asm_out_file);
+ if (HOST_BITS_PER_WIDE_INT < 64 || GET_CODE (x) != CONST_INT)
+ output_addr_const (asm_out_file, x);
+ else
+ print_operand (asm_out_file, x, 'X');
+ fputc ('\n', asm_out_file);
+ return true;
+ }
+ return default_assemble_integer (x, size, aligned_p);
+}
\f
/* If optimizing for the global pointer, keep track of all of the externs, so
that at the end of the file, we can emit the appropriate .extern
#ifdef ASM_OUTPUT_UNDEF_FUNCTION
int
mips_output_external_libcall (file, name)
- FILE *file;
+ FILE *file ATTRIBUTE_UNUSED;
const char *name;
{
register struct extern_list *p;
}
#endif
\f
-/* Compute a string to use as a temporary file name. */
-
-static FILE *
-mips_make_temp_file ()
-{
- FILE *stream;
-
- temp_filename = make_temp_file (0);
- stream = fopen (temp_filename, "w+");
- if (!stream)
- fatal_io_error ("can't open %s", temp_filename);
- return stream;
-}
-\f
/* Emit a new filename to a stream. If this is MIPS ECOFF, watch out
for .file's that start within a function. If we are smuggling stabs, try to
put out a MIPS ECOFF file and a stab. */
LOCAL_LABEL_PREFIX, sym_lineno, ASM_STABN_OP, N_SLINE, line,
LOCAL_LABEL_PREFIX, sym_lineno);
}
-
else
{
fprintf (stream, "\n\t%s.loc\t%d %d\n",
if (TARGET_MIPS_AS && optimize && flag_delayed_branch)
fprintf (stream, "\t.set\tnobopt\n");
+ if (TARGET_GAS)
+ {
+#if defined(OBJECT_FORMAT_ELF)
+ /* Generate a special section to describe the ABI switches used to
+ produce the resultant binary. This used to be done by the assembler
+ setting bits in the ELF header's flags field, but we have run out of
+ bits. GDB needs this information in order to be able to correctly
+ debug these binaries. See the function mips_gdbarch_init() in
+ gdb/mips-tdep.c. */
+ const char * abi_string = NULL;
+
+ switch (mips_abi)
+ {
+ case ABI_32: abi_string = "abi32"; break;
+ case ABI_N32: abi_string = "abiN32"; break;
+ case ABI_64: abi_string = "abi64"; break;
+ case ABI_O64: abi_string = "abiO64"; break;
+ case ABI_EABI: abi_string = TARGET_64BIT ? "eabi64" : "eabi32"; break;
+ case ABI_MEABI:abi_string = TARGET_64BIT ? "meabi64" : "meabi32"; break;
+ default:
+ abort ();
+ }
+ /* Note - we use fprintf directly rather than called named_section()
+ because in this way we can avoid creating an allocated section. We
+ do not want this section to take up any space in the running
+ executable. */
+ fprintf (stream, "\t.section .mdebug.%s\n", abi_string);
+
+ /* Restore the default section. */
+ fprintf (stream, "\t.previous\n");
+#endif
+ }
+
+
+
/* Generate the pseudo ops that System V.4 wants. */
#ifndef ABICALLS_ASM_OP
#define ABICALLS_ASM_OP "\t.abicalls"
if (TARGET_MIPS16)
fprintf (stream, "\t.set\tmips16\n");
- /* 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_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
references. This is necessary for the MIPS assembler's global pointer
optimizations to work. */
- if (TARGET_FILE_SWITCHING && ! TARGET_MIPS16)
+ if (TARGET_FILE_SWITCHING)
{
asm_out_data_file = stream;
- asm_out_text_file = mips_make_temp_file ();
+ asm_out_text_file = tmpfile ();
}
-
else
asm_out_data_file = asm_out_text_file = stream;
mips_asm_file_end (file)
FILE *file;
{
- char buffer[8192];
tree name_tree;
struct extern_list *p;
- int len;
if (HALF_PIC_P ())
{
}
}
- if (TARGET_FILE_SWITCHING && ! TARGET_MIPS16)
+ if (TARGET_FILE_SWITCHING)
{
fprintf (file, "\n\t.text\n");
- rewind (asm_out_text_file);
- if (ferror (asm_out_text_file))
- fatal_io_error ("can't rewind %s", temp_filename);
+ copy_file_data (file, asm_out_text_file);
+ }
+}
- while ((len = fread (buffer, 1, sizeof (buffer), asm_out_text_file)) > 0)
- if ((int) fwrite (buffer, 1, len, file) != len)
- fatal_io_error ("can't write to %s", asm_file_name);
+static void
+copy_file_data (to, from)
+ FILE *to, *from;
+{
+ char buffer[8192];
+ size_t len;
+ rewind (from);
+ if (ferror (from))
+ fatal_io_error ("can't rewind temp file");
- if (len < 0)
- fatal_io_error ("can't read from %s", temp_filename);
+ while ((len = fread (buffer, 1, sizeof (buffer), from)) > 0)
+ if (fwrite (buffer, 1, len, to) != len)
+ fatal_io_error ("can't write to output file");
- if (fclose (asm_out_text_file) != 0)
- fatal_io_error ("can't close %s", temp_filename);
+ if (ferror (from))
+ fatal_io_error ("can't read from temp file");
- unlink (temp_filename);
- free (temp_filename);
- }
+ if (fclose (from))
+ fatal_io_error ("can't close temp file");
}
/* Emit either a label, .comm, or .lcomm directive, and mark that the symbol
}
}
\f
-/* Output a double precision value to the assembler. If both the
- host and target are IEEE, emit the values in hex. */
-
-void
-mips_output_double (stream, value)
- FILE *stream;
- REAL_VALUE_TYPE value;
-{
-#ifdef REAL_VALUE_TO_TARGET_DOUBLE
- long value_long[2];
- REAL_VALUE_TO_TARGET_DOUBLE (value, value_long);
-
- fprintf (stream, "\t.word\t0x%08lx\t\t# %.20g\n\t.word\t0x%08lx\n",
- value_long[0], value, value_long[1]);
-#else
- fprintf (stream, "\t.double\t%.20g\n", value);
-#endif
-}
-
-/* Output a single precision value to the assembler. If both the
- host and target are IEEE, emit the values in hex. */
-
-void
-mips_output_float (stream, value)
- FILE *stream;
- REAL_VALUE_TYPE value;
-{
-#ifdef REAL_VALUE_TO_TARGET_SINGLE
- long value_long;
- REAL_VALUE_TO_TARGET_SINGLE (value, value_long);
-
- fprintf (stream, "\t.word\t0x%08lx\t\t# %.12g (float)\n", value_long, value);
-#else
- fprintf (stream, "\t.float\t%.12g\n", value);
-#endif
-}
-\f
/* Return the bytes needed to compute the frame pointer from the current
stack pointer.
compute_frame_size (size)
HOST_WIDE_INT size; /* # of var. bytes allocated */
{
- int regno;
+ unsigned int regno;
HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up */
HOST_WIDE_INT var_size; /* # bytes that variables take up */
HOST_WIDE_INT args_size; /* # bytes that outgoing arguments take up */
/* We need to restore these for the handler. */
if (current_function_calls_eh_return)
{
- int i;
+ unsigned int i;
for (i = 0; ; ++i)
{
regno = EH_RETURN_DATA_REGNO (i);
call to mcount. */
if (total_size == extra_size
&& (mips_abi == ABI_32 || mips_abi == ABI_O64 || mips_abi == ABI_EABI)
- && ! profile_flag)
+ && ! current_function_profile)
total_size = extra_size = 0;
else if (TARGET_ABICALLS)
{
#define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)
+/* Emit instructions to load the value (SP + OFFSET) into MIPS_TEMP2_REGNUM
+ and return an rtl expression for the register. Write the assembly
+ instructions directly to FILE if it is not null, otherwise emit them as
+ rtl.
+
+ This function is a subroutine of save_restore_insns. It is used when
+ OFFSET is too large to add in a single instruction. */
+
+static rtx
+mips_add_large_offset_to_sp (offset, file)
+ HOST_WIDE_INT offset;
+ FILE *file;
+{
+ rtx reg = gen_rtx_REG (Pmode, MIPS_TEMP2_REGNUM);
+ if (file == 0)
+ {
+ rtx offset_rtx = GEN_INT (offset);
+
+ emit_move_insn (reg, offset_rtx);
+ if (Pmode == DImode)
+ emit_insn (gen_adddi3 (reg, reg, stack_pointer_rtx));
+ else
+ emit_insn (gen_addsi3 (reg, reg, stack_pointer_rtx));
+ }
+ else
+ {
+ fprintf (file, "\tli\t%s,0x%.08lx\t# ",
+ reg_names[MIPS_TEMP2_REGNUM], (long) offset);
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, 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]);
+ }
+ return reg;
+}
+
+/* Make INSN frame related and note that it performs the frame-related
+ operation DWARF_PATTERN. */
+
+static void
+mips_annotate_frame_insn (insn, dwarf_pattern)
+ rtx insn, dwarf_pattern;
+{
+ RTX_FRAME_RELATED_P (insn) = 1;
+ REG_NOTES (insn) = alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+ dwarf_pattern,
+ REG_NOTES (insn));
+}
+
+/* Return a frame-related rtx that stores register REGNO at (SP + OFFSET).
+ The expression should only be used to store single registers. */
+
+static rtx
+mips_frame_set (mode, regno, offset)
+ enum machine_mode mode;
+ int regno;
+ int offset;
+{
+ rtx address = plus_constant (stack_pointer_rtx, offset);
+ rtx set = gen_rtx_SET (mode,
+ gen_rtx_MEM (mode, address),
+ gen_rtx_REG (mode, regno));
+ RTX_FRAME_RELATED_P (set) = 1;
+ return set;
+}
+
+
+/* Emit a move instruction that stores REG in MEM. Make the instruction
+ frame related and note that it stores REG at (SP + OFFSET). This
+ function may be asked to store an FPR pair. */
+
+static void
+mips_emit_frame_related_store (mem, reg, offset)
+ rtx mem;
+ rtx reg;
+ HOST_WIDE_INT offset;
+{
+ rtx dwarf_expr;
+
+ if (GET_MODE (reg) == DFmode && ! TARGET_FLOAT64)
+ {
+ /* Two registers are being stored, so the frame-related expression
+ must be a PARALLEL rtx with one SET for each register. The
+ higher numbered register is stored in the lower address on
+ big-endian targets. */
+ int regno1 = TARGET_BIG_ENDIAN ? REGNO (reg) + 1 : REGNO (reg);
+ int regno2 = TARGET_BIG_ENDIAN ? REGNO (reg) : REGNO (reg) + 1;
+ rtx set1 = mips_frame_set (SFmode, regno1, offset);
+ rtx set2 = mips_frame_set (SFmode, regno2, offset + UNITS_PER_FPREG);
+ dwarf_expr = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set1, set2));
+ }
+ else
+ dwarf_expr = mips_frame_set (GET_MODE (reg), REGNO (reg), offset);
+
+ mips_annotate_frame_insn (emit_move_insn (mem, reg), dwarf_expr);
+}
+
static void
save_restore_insns (store_p, large_reg, large_offset, file)
int store_p; /* true if this is prologue */
{
long mask = current_frame_info.mask;
long fmask = current_frame_info.fmask;
+ long real_mask = mask;
int regno;
rtx base_reg_rtx;
HOST_WIDE_INT base_offset;
&& ! BITSET_P (mask, HARD_FRAME_POINTER_REGNUM - GP_REG_FIRST))
abort ();
+ /* Do not restore GP under certain conditions. */
+ if (! store_p
+ && TARGET_ABICALLS
+ && (mips_abi == ABI_32 || mips_abi == ABI_O64))
+ mask &= ~(1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST));
+
if (mask == 0 && fmask == 0)
return;
if (gp_offset < 0 || end_offset < 0)
internal_error
- ("gp_offset (%ld) or end_offset (%ld) is less than zero.",
+ ("gp_offset (%ld) or end_offset (%ld) is less than zero",
(long) gp_offset, (long) end_offset);
/* If we see a large frame in mips16 mode, we save the registers
else
insn = emit_insn (gen_addsi3 (base_reg_rtx, large_reg,
stack_pointer_rtx));
- if (store_p)
- RTX_FRAME_RELATED_P (insn) = 1;
}
else
fprintf (file, "\t%s\t%s,%s,%s\n",
reg_names[REGNO (large_reg)],
reg_names[STACK_POINTER_REGNUM]);
}
-
else
{
- base_reg_rtx = gen_rtx_REG (Pmode, MIPS_TEMP2_REGNUM);
base_offset = gp_offset;
- if (file == 0)
- {
- rtx gp_offset_rtx = GEN_INT (gp_offset);
-
- /* Instruction splitting doesn't preserve the RTX_FRAME_RELATED_P
- bit, so make sure that we don't emit anything that can be
- split. */
- /* ??? There is no DImode ori immediate pattern, so we can only
- do this for 32 bit code. */
- if (large_int (gp_offset_rtx, GET_MODE (gp_offset_rtx))
- && GET_MODE (base_reg_rtx) == SImode)
- {
- insn = emit_move_insn (base_reg_rtx,
- GEN_INT (gp_offset & BITMASK_UPPER16));
- if (store_p)
- RTX_FRAME_RELATED_P (insn) = 1;
- insn
- = emit_insn (gen_iorsi3 (base_reg_rtx, base_reg_rtx,
- GEN_INT (gp_offset
- & BITMASK_LOWER16)));
- if (store_p)
- RTX_FRAME_RELATED_P (insn) = 1;
- }
- else
- {
- insn = emit_move_insn (base_reg_rtx, gp_offset_rtx);
- if (store_p)
- RTX_FRAME_RELATED_P (insn) = 1;
- }
-
- if (Pmode == DImode)
- insn = emit_insn (gen_adddi3 (base_reg_rtx, base_reg_rtx,
- stack_pointer_rtx));
- else
- insn = emit_insn (gen_addsi3 (base_reg_rtx, base_reg_rtx,
- stack_pointer_rtx));
- if (store_p)
- RTX_FRAME_RELATED_P (insn) = 1;
- }
- else
- {
- 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]);
- }
+ base_reg_rtx = mips_add_large_offset_to_sp (base_offset, file);
}
/* When we restore the registers in MIPS16 mode, then if we are
gen_rtx (PLUS, Pmode, base_reg_rtx,
GEN_INT (gp_offset - base_offset)));
- RTX_UNCHANGING_P (mem_rtx) = 1;
+ if (! current_function_calls_eh_return)
+ RTX_UNCHANGING_P (mem_rtx) = 1;
/* The mips16 does not have an instruction to load
$31, so we load $7 instead, and work things out
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 && mips_abi != ABI_O64)
- || regno != (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
+ mips_emit_frame_related_store (mem_rtx, reg_rtx, gp_offset);
+ else
{
emit_move_insn (reg_rtx, mem_rtx);
if (TARGET_MIPS16
}
else
{
- if (store_p || !TARGET_ABICALLS
- || (mips_abi != ABI_32 && mips_abi != ABI_O64)
- || regno != (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
+ int r = regno;
+
+ /* The mips16 does not have an instruction to
+ load $31, so we load $7 instead, and work
+ things out in the caller. */
+ if (TARGET_MIPS16 && ! store_p && r == GP_REG_FIRST + 31)
+ r = GP_REG_FIRST + 7;
+ /* The mips16 sometimes needs to save $18. */
+ if (TARGET_MIPS16
+ && regno != GP_REG_FIRST + 31
+ && ! M16_REG_P (regno))
{
- int r = regno;
-
- /* The mips16 does not have an instruction to
- load $31, so we load $7 instead, and work
- things out in the caller. */
- if (TARGET_MIPS16 && ! store_p && r == GP_REG_FIRST + 31)
- r = GP_REG_FIRST + 7;
- /* The mips16 sometimes needs to save $18. */
- if (TARGET_MIPS16
- && regno != GP_REG_FIRST + 31
- && ! M16_REG_P (regno))
+ if (! store_p)
+ r = GP_REG_FIRST + 6;
+ else
{
- if (! store_p)
- r = GP_REG_FIRST + 6;
- else
- {
- r = GP_REG_FIRST + 3;
- fprintf (file, "\tmove\t%s,%s\n",
- reg_names[r], reg_names[regno]);
- }
+ r = GP_REG_FIRST + 3;
+ fprintf (file, "\tmove\t%s,%s\n",
+ reg_names[r], reg_names[regno]);
}
- fprintf (file, "\t%s\t%s,",
- (TARGET_64BIT
- ? (store_p) ? "sd" : "ld"
- : (store_p) ? "sw" : "lw"),
- 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
- && ! M16_REG_P (regno))
- fprintf (file, "\tmove\t%s,%s\n",
- reg_names[regno], reg_names[r]);
}
-
+ fprintf (file, "\t%s\t%s,",
+ (TARGET_64BIT
+ ? (store_p) ? "sd" : "ld"
+ : (store_p) ? "sw" : "lw"),
+ 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
+ && ! M16_REG_P (regno))
+ fprintf (file, "\tmove\t%s,%s\n",
+ reg_names[regno], reg_names[r]);
}
gp_offset -= GET_MODE_SIZE (gpr_mode);
}
+ /* If the restore is being supressed, still take into account
+ the offset at which it is stored. */
+ else if (BITSET_P (real_mask, regno - GP_REG_FIRST))
+ {
+ gp_offset -= GET_MODE_SIZE (gpr_mode);
+ }
}
else
base_reg_rtx = 0, base_offset = 0;
if (fp_offset < 0 || end_offset < 0)
internal_error
- ("fp_offset (%ld) or end_offset (%ld) is less than zero.",
+ ("fp_offset (%ld) or end_offset (%ld) is less than zero",
(long) fp_offset, (long) end_offset);
else if (fp_offset < 32768)
else
insn = emit_insn (gen_addsi3 (base_reg_rtx, large_reg,
stack_pointer_rtx));
- if (store_p)
- RTX_FRAME_RELATED_P (insn) = 1;
}
else
reg_names[REGNO (large_reg)],
reg_names[STACK_POINTER_REGNUM]);
}
-
else
{
- base_reg_rtx = gen_rtx_REG (Pmode, MIPS_TEMP2_REGNUM);
base_offset = fp_offset;
- if (file == 0)
- {
- rtx fp_offset_rtx = GEN_INT (fp_offset);
-
- /* Instruction splitting doesn't preserve the RTX_FRAME_RELATED_P
- bit, so make sure that we don't emit anything that can be
- split. */
- /* ??? There is no DImode ori immediate pattern, so we can only
- do this for 32 bit code. */
- if (large_int (fp_offset_rtx, GET_MODE (fp_offset_rtx))
- && GET_MODE (base_reg_rtx) == SImode)
- {
- insn = emit_move_insn (base_reg_rtx,
- GEN_INT (fp_offset & BITMASK_UPPER16));
- if (store_p)
- RTX_FRAME_RELATED_P (insn) = 1;
- insn = emit_insn (gen_iorsi3 (base_reg_rtx, base_reg_rtx,
- GEN_INT (fp_offset
- & BITMASK_LOWER16)));
- if (store_p)
- RTX_FRAME_RELATED_P (insn) = 1;
- }
- else
- {
- insn = emit_move_insn (base_reg_rtx, fp_offset_rtx);
- if (store_p)
- RTX_FRAME_RELATED_P (insn) = 1;
- }
-
- if (store_p)
- RTX_FRAME_RELATED_P (insn) = 1;
- if (Pmode == DImode)
- insn = emit_insn (gen_adddi3 (base_reg_rtx, base_reg_rtx,
- stack_pointer_rtx));
- else
- insn = emit_insn (gen_addsi3 (base_reg_rtx, base_reg_rtx,
- stack_pointer_rtx));
- if (store_p)
- RTX_FRAME_RELATED_P (insn) = 1;
- }
- else
- {
- 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]);
- }
+ base_reg_rtx = mips_add_large_offset_to_sp (fp_offset, file);
}
/* This loop must iterate over the same space as its companion in
gen_rtx (PLUS, Pmode, base_reg_rtx,
GEN_INT (fp_offset
- base_offset)));
- RTX_UNCHANGING_P (mem_rtx) = 1;
+ if (! current_function_calls_eh_return)
+ RTX_UNCHANGING_P (mem_rtx) = 1;
if (store_p)
- {
- insn = emit_move_insn (mem_rtx, reg_rtx);
- RTX_FRAME_RELATED_P (insn) = 1;
- }
+ mips_emit_frame_related_store (mem_rtx, reg_rtx, fp_offset);
else
emit_move_insn (reg_rtx, mem_rtx);
}
#ifndef FUNCTION_NAME_ALREADY_DECLARED
const char *fnname;
#endif
- long tsize = current_frame_info.total_size;
+ HOST_WIDE_INT tsize = current_frame_info.total_size;
ASM_OUTPUT_SOURCE_FILENAME (file, DECL_SOURCE_FILE (current_function_decl));
(reg_names[(frame_pointer_needed)
? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
((frame_pointer_needed && TARGET_MIPS16)
- ? (tsize - current_function_outgoing_args_size)
- : tsize),
- reg_names[31 + GP_REG_FIRST],
+ ? ((long) tsize - current_function_outgoing_args_size)
+ : (long) tsize),
+ reg_names[GP_REG_FIRST + 31],
current_frame_info.var_size,
current_frame_info.num_gp,
current_frame_info.num_fp,
/* Require:
OLD_SP == *FRAMEREG + FRAMESIZE => can find old_sp from nominated FP reg.
- HIGHEST_GP_SAVED == *FRAMEREG + FRAMESIZE + GPOFFSET => can find saved regs. */
+ HIGHEST_GP_SAVED == *FRAMEREG + FRAMESIZE + GPOFFSET => can find saved regs. */
}
if (mips_entry && ! mips_can_use_return_insn ())
|| GET_CODE (offset) != CONST_INT)
continue;
if (REGNO (base) == (unsigned) STACK_POINTER_REGNUM
- && (unsigned HOST_WIDE_INT) INTVAL (offset)
- == tsize + (REGNO (src) - 4) * UNITS_PER_WORD)
+ && INTVAL (offset) == tsize + (REGNO (src) - 4) * UNITS_PER_WORD)
;
else if (REGNO (base) == (unsigned) HARD_FRAME_POINTER_REGNUM
- && ((unsigned HOST_WIDE_INT) INTVAL (offset)
+ && (INTVAL (offset)
== (tsize
+ (REGNO (src) - 4) * UNITS_PER_WORD
- current_function_outgoing_args_size)))
{
fprintf (file, "\t%s\t%s,%s,%ld\n",
(Pmode == DImode ? "dsubu" : "subu"),
- sp_str, sp_str, tsize);
+ sp_str, sp_str, (long) tsize);
fprintf (file, "\t.cprestore %ld\n", current_frame_info.args_size);
}
the varargs special argument, and treat it as part of the
variable arguments.
- This is only needed if store_args_on_stack is true. */
+ This is only needed if store_args_on_stack is true. */
INIT_CUMULATIVE_ARGS (args_so_far, fntype, NULL_RTX, 0);
regno = GP_ARG_FIRST;
pattern = RTVEC_ELT (adjust, i);
if (GET_CODE (pattern) != SET
|| GET_CODE (SET_SRC (pattern)) != ASHIFT)
- abort_with_insn (pattern, "Insn is not a shift");
+ abort_with_insn (pattern, "insn is not a shift");
PUT_CODE (SET_SRC (pattern), ASHIFTRT);
insn = emit_insn (pattern);
int offset = (regno - GP_ARG_FIRST) * UNITS_PER_WORD;
rtx ptr = stack_pointer_rtx;
- /* If we are doing svr4-abi, sp has already been decremented by tsize. */
+ /* If we are doing svr4-abi, sp has already been decremented by tsize. */
if (TARGET_ABICALLS)
offset += tsize;
if ((!TARGET_ABICALLS || (mips_abi != ABI_32 && mips_abi != ABI_O64))
&& (!TARGET_MIPS16 || tsize <= 32767))
{
- rtx insn;
+ rtx adjustment_rtx, insn, dwarf_pattern;
if (tsize > 32767)
{
- tmp_rtx = gen_rtx (REG, Pmode, MIPS_TEMP1_REGNUM);
-
- /* Instruction splitting doesn't preserve the RTX_FRAME_RELATED_P
- bit, so make sure that we don't emit anything that can be
- 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 (tsize_rtx))
- && GET_MODE (tmp_rtx) == SImode)
- {
- insn = emit_move_insn (tmp_rtx,
- GEN_INT (tsize & BITMASK_UPPER16));
- RTX_FRAME_RELATED_P (insn) = 1;
- insn = emit_insn (gen_iorsi3 (tmp_rtx, tmp_rtx,
- GEN_INT (tsize
- & BITMASK_LOWER16)));
- RTX_FRAME_RELATED_P (insn) = 1;
- }
- else
- {
- insn = emit_move_insn (tmp_rtx, tsize_rtx);
- RTX_FRAME_RELATED_P (insn) = 1;
- }
-
- tsize_rtx = tmp_rtx;
+ adjustment_rtx = gen_rtx (REG, Pmode, MIPS_TEMP1_REGNUM);
+ emit_move_insn (adjustment_rtx, tsize_rtx);
}
+ else
+ adjustment_rtx = tsize_rtx;
if (Pmode == DImode)
insn = emit_insn (gen_subdi3 (stack_pointer_rtx, stack_pointer_rtx,
- tsize_rtx));
+ adjustment_rtx));
else
insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
- tsize_rtx));
+ adjustment_rtx));
+
+ dwarf_pattern = gen_rtx_SET (Pmode, stack_pointer_rtx,
+ plus_constant (stack_pointer_rtx,
+ -tsize));
- RTX_FRAME_RELATED_P (insn) = 1;
+ mips_annotate_frame_insn (insn, dwarf_pattern);
}
if (! mips_entry)
/* If we are profiling, make sure no instructions are scheduled before
the call to mcount. */
- if (profile_flag || profile_block_flag)
+ if (current_function_profile)
emit_insn (gen_blockage ());
}
\f
/* Do any necessary cleanup after a function to restore stack, frame,
- and regs. */
+ and regs. */
#define RA_MASK BITMASK_HIGH /* 1 << 31 */
#define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
/* Restore the output file if optimizing the GP (optimizing the GP causes
the text to be diverted to a tempfile, so that data decls come before
references to the data). */
-
- if (TARGET_GP_OPT && ! TARGET_MIPS16 && ! TARGET_GAS)
- asm_out_file = asm_out_data_file;
+ if (TARGET_FILE_SWITCHING)
+ {
+ asm_out_file = asm_out_data_file;
+ data_section ();
+ }
}
\f
/* Expand the epilogue into a bunch of separate insns. */
if (! reload_completed)
return 0;
- if (regs_ever_live[31] || profile_flag)
+ if (regs_ever_live[31] || current_function_profile)
return 0;
/* In mips16 mode, a function which returns a floating point value
just as PROMOTE_MODE does. */
mode = promote_mode (valtype, mode, &unsignedp, 1);
- /* ??? How should we return complex float? */
- if (mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT)
+ if (mclass == MODE_FLOAT)
{
if (TARGET_SINGLE_FLOAT
&& (mclass == MODE_FLOAT
reg = FP_RETURN;
}
+ else if (mclass == MODE_COMPLEX_FLOAT)
+ {
+ if (TARGET_FLOAT64)
+ reg = FP_RETURN;
+ else if (mode == SCmode)
+ {
+ /* When FP registers are 32 bits, we can't directly reference
+ the odd numbered ones, so let's make a pair of evens. */
+
+ enum machine_mode cmode = TYPE_MODE (TREE_TYPE (valtype));
+
+ return gen_rtx_PARALLEL
+ (VOIDmode,
+ gen_rtvec (2,
+ gen_rtx_EXPR_LIST (VOIDmode,
+ gen_rtx_REG (cmode,
+ FP_RETURN),
+ GEN_INT (0)),
+ gen_rtx_EXPR_LIST (VOIDmode,
+ gen_rtx_REG (cmode,
+ FP_RETURN + 2),
+ GEN_INT (4))));
+ }
+ else
+ reg = FP_RETURN;
+ }
+
else if (TREE_CODE (valtype) == RECORD_TYPE
&& mips_abi != ABI_32
&& mips_abi != ABI_O64
to prevent it, or add code to function.c to properly handle the case. */
/* ??? cum can be NULL when called from mips_va_arg. The problem handled
here hopefully is not relevant to mips_va_arg. */
- if (cum && MUST_PASS_IN_STACK (mode, type))
+ if (cum && MUST_PASS_IN_STACK (mode, type)
+ && mips_abi != ABI_MEABI)
{
/* 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. */
+ passed in registers. */
CUMULATIVE_ARGS temp;
temp = *cum;
if (FUNCTION_ARG (temp, mode, type, named) != 0)
/* We build the stub code by hand. That's the only way we can
do it, since we can't generate 32 bit code during a 16 bit
- compilation. */
+ compilation. */
/* We don't want the assembler to insert any nops here. */
fprintf (asm_out_file, "\t.set\tnoreorder\n");
{
/* 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. */
+ emit a barrier now. */
rtx label, jump, barrier;
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 *
+const char *
mips_output_conditional_branch (insn,
operands,
two_operands_p,
operand. */
const char *op2 = (two_operands_p ? ",%z3" : ",%.");
/* The operand-printing string for the comparison. */
- const char *comp = (float_p ? "%F0" : "%C0");
+ const char *const comp = (float_p ? "%F0" : "%C0");
/* The operand-printing string for the inverted comparison. */
- const char *inverted_comp = (float_p ? "%W0" : "%N0");
+ const char *const 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
break;
case LTU:
- /* A condition which will always be false. */
+ /* A condition which will always be false. */
code = NE;
op1 = "%.";
break;
.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
+ rtx orig_target;
+ rtx target = gen_label_rtx ();
+
+ output_asm_insn ("%(%<", 0);
+ orig_target = operands[1];
+ operands[1] = target;
+ /* Generate the reversed comparison. This takes four
bytes. */
if (float_p)
- sprintf (c, "%%*b%s\t%%Z2%s",
- inverted_p ? comp : inverted_comp,
- target);
+ sprintf (buffer, "%%*b%s\t%%Z2%%1",
+ inverted_p ? comp : inverted_comp);
else
- sprintf (c, "%%*b%s%s\t%s%s,%s",
+ sprintf (buffer, "%%*b%s%s\t%s%s,%%1",
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;
+ op2);
+ output_asm_insn (buffer, operands);
+ operands[1] = orig_target;
+
+ output_asm_insn ("nop\n\tj\t%1", operands);
+
+ if (length == 16)
+ output_asm_insn ("nop", 0);
+ else
+ {
+ /* Output delay slot instruction. */
+ rtx insn = final_sequence;
+ final_scan_insn (XVECEXP (insn, 0, 1), asm_out_file,
+ optimize, 0, 1);
+ INSN_DELETED_P (XVECEXP (insn, 0, 1)) = 1;
+ }
+ output_asm_insn ("%>%)", 0);
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+ CODE_LABEL_NUMBER (target));
+ return "";
}
/* We do not currently use this code. It handles jumps to
anything. */
/* The target of the reversed branch. */
- const char *target
+ const char *const 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];
case '2':
if (!strcmp (p, "2000") || !strcmp (p, "2k") || !strcmp (p, "2K"))
cpu = PROCESSOR_R3000;
+ else if (!strcmp (p, "20kc") || !strcmp (p, "20Kc") )
+ cpu = PROCESSOR_R20KC;
break;
case '3':
cpu = PROCESSOR_R4600;
else if (!strcmp (p, "4650"))
cpu = PROCESSOR_R4650;
+ /* The 4kc and 4kp processor cores are the same for
+ scheduling purposes; they both implement the MIPS32
+ ISA and only differ in their memory management
+ methods. */
+ else if (!strcmp (p, "4kc") || !strcmp (p, "4Kc")
+ || !strcmp (p, "4kp") || !strcmp (p, "4Kp") )
+ cpu = PROCESSOR_R4KC;
break;
case '5':
if (!strcmp (p, "5000") || !strcmp (p, "5k") || !strcmp (p, "5K"))
cpu = PROCESSOR_R5000;
+ else if (!strcmp (p, "5kc") || !strcmp (p, "5Kc") )
+ cpu = PROCESSOR_R5KC;
break;
case '6':
return cpu;
}
+
+/* Adjust the cost of INSN based on the relationship between INSN that
+ is dependent on DEP_INSN through the dependence LINK. The default
+ is to make no adjustment to COST.
+
+ On the MIPS, ignore the cost of anti- and output-dependencies. */
+static int
+mips_adjust_cost (insn, link, dep, cost)
+ rtx insn ATTRIBUTE_UNUSED;
+ rtx link;
+ rtx dep ATTRIBUTE_UNUSED;
+ int cost;
+{
+ if (REG_NOTE_KIND (link) != 0)
+ return 0; /* Anti or output dependence. */
+ return cost;
+}
+
+/* Cover function for UNIQUE_SECTION. */
+
+void
+mips_unique_section (decl, reloc)
+ tree decl;
+ int reloc;
+{
+ int len, size, sec;
+ const char *name, *prefix;
+ char *string;
+ static const char *const prefixes[4][2] = {
+ { ".text.", ".gnu.linkonce.t." },
+ { ".rodata.", ".gnu.linkonce.r." },
+ { ".data.", ".gnu.linkonce.d." },
+ { ".sdata.", ".gnu.linkonce.s." }
+ };
+
+ name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+ size = int_size_in_bytes (TREE_TYPE (decl));
+
+ /* Determine the base section we are interested in:
+ 0=text, 1=rodata, 2=data, 3=sdata, [4=bss]. */
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ sec = 0;
+ else if (DECL_INITIAL (decl) == 0
+ || DECL_INITIAL (decl) == error_mark_node)
+ sec = 2;
+ else if ((TARGET_EMBEDDED_PIC || TARGET_MIPS16)
+ && TREE_CODE (decl) == STRING_CST
+ && !flag_writable_strings)
+ {
+ /* For embedded position independent code, put constant
+ strings in the text section, because the data section
+ is limited to 64K in size. For mips16 code, put
+ strings in the text section so that a PC relative load
+ instruction can be used to get their address. */
+ sec = 0;
+ }
+ else if (TARGET_EMBEDDED_DATA)
+ {
+ /* For embedded applications, always put an object in
+ read-only data if possible, in order to reduce RAM
+ usage. */
+
+ if (DECL_READONLY_SECTION (decl, reloc))
+ sec = 1;
+ else if (size > 0 && size <= mips_section_threshold)
+ sec = 3;
+ else
+ sec = 2;
+ }
+ else
+ {
+ /* For hosted applications, always put an object in
+ small data if possible, as this gives the best
+ performance. */
+
+ if (size > 0 && size <= mips_section_threshold)
+ sec = 3;
+ else if (DECL_READONLY_SECTION (decl, reloc))
+ sec = 1;
+ else
+ sec = 2;
+ }
+
+ prefix = prefixes[sec][DECL_ONE_ONLY (decl)];
+ len = strlen (name) + strlen (prefix);
+ string = alloca (len + 1);
+ sprintf (string, "%s%s", prefix, name);
+
+ DECL_SECTION_NAME (decl) = build_string (len, string);
+}
+
+unsigned int
+mips_hard_regno_nregs (regno, mode)
+ int regno;
+ enum machine_mode mode;
+{
+ if (! FP_REG_P (regno))
+ return ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD);
+ else
+ return ((GET_MODE_SIZE (mode) + UNITS_PER_FPREG - 1) / UNITS_PER_FPREG);
+}
+
+\f
+#ifdef TARGET_IRIX6
+/* Output assembly to switch to section NAME with attribute FLAGS. */
+
+static void
+iris6_asm_named_section_1 (name, flags, align)
+ const char *name;
+ unsigned int flags;
+ unsigned int align;
+{
+ unsigned int sh_type, sh_flags, sh_entsize;
+
+ sh_flags = 0;
+ if (!(flags & SECTION_DEBUG))
+ sh_flags |= 2; /* SHF_ALLOC */
+ if (flags & SECTION_WRITE)
+ sh_flags |= 1; /* SHF_WRITE */
+ if (flags & SECTION_CODE)
+ sh_flags |= 4; /* SHF_EXECINSTR */
+ if (flags & SECTION_SMALL)
+ sh_flags |= 0x10000000; /* SHF_MIPS_GPREL */
+ if (strcmp (name, ".debug_frame") == 0)
+ sh_flags |= 0x08000000; /* SHF_MIPS_NOSTRIP */
+ if (flags & SECTION_DEBUG)
+ sh_type = 0x7000001e; /* SHT_MIPS_DWARF */
+ else if (flags & SECTION_BSS)
+ sh_type = 8; /* SHT_NOBITS */
+ else
+ sh_type = 1; /* SHT_PROGBITS */
+
+ if (flags & SECTION_CODE)
+ sh_entsize = 4;
+ else
+ sh_entsize = 0;
+
+ fprintf (asm_out_file, "\t.section %s,%#x,%#x,%u,%u\n",
+ name, sh_type, sh_flags, sh_entsize, align);
+}
+
+static void
+iris6_asm_named_section (name, flags)
+ const char *name;
+ unsigned int flags;
+{
+ if (TARGET_FILE_SWITCHING && (flags & SECTION_CODE))
+ asm_out_file = asm_out_text_file;
+ iris6_asm_named_section_1 (name, flags, 0);
+}
+
+/* In addition to emitting a .align directive, record the maximum
+ alignment requested for the current section. */
+
+struct iris_section_align_entry
+{
+ const char *name;
+ unsigned int log;
+ unsigned int flags;
+};
+
+static htab_t iris_section_align_htab;
+static FILE *iris_orig_asm_out_file;
+
+static int
+iris_section_align_entry_eq (p1, p2)
+ const PTR p1;
+ const PTR p2;
+{
+ const struct iris_section_align_entry *old = p1;
+ const char *new = p2;
+
+ return strcmp (old->name, new) == 0;
+}
+
+static hashval_t
+iris_section_align_entry_hash (p)
+ const PTR p;
+{
+ const struct iris_section_align_entry *old = p;
+ return htab_hash_string (old->name);
+}
+
+void
+iris6_asm_output_align (file, log)
+ FILE *file;
+ unsigned int log;
+{
+ const char *section = current_section_name ();
+ struct iris_section_align_entry **slot, *entry;
+
+ if (! section)
+ abort ();
+
+ slot = (struct iris_section_align_entry **)
+ htab_find_slot_with_hash (iris_section_align_htab, section,
+ htab_hash_string (section), INSERT);
+ entry = *slot;
+ if (! entry)
+ {
+ entry = (struct iris_section_align_entry *)
+ xmalloc (sizeof (struct iris_section_align_entry));
+ *slot = entry;
+ entry->name = section;
+ entry->log = log;
+ entry->flags = current_section_flags ();
+ }
+ else if (entry->log < log)
+ entry->log = log;
+
+ fprintf (file, "\t.align\t%u\n", log);
+}
+
+/* The Iris assembler does not record alignment from .align directives,
+ but takes it from the first .section directive seen. Play yet more
+ file switching games so that we can emit a .section directive at the
+ beginning of the file with the proper alignment attached. */
+
+void
+iris6_asm_file_start (stream)
+ FILE *stream;
+{
+ mips_asm_file_start (stream);
+
+ iris_orig_asm_out_file = asm_out_file;
+ stream = tmpfile ();
+ asm_out_file = stream;
+ asm_out_data_file = stream;
+ if (! TARGET_FILE_SWITCHING)
+ asm_out_text_file = stream;
+
+ iris_section_align_htab = htab_create (31, iris_section_align_entry_hash,
+ iris_section_align_entry_eq, NULL);
+}
+
+static int
+iris6_section_align_1 (slot, data)
+ void **slot;
+ void *data ATTRIBUTE_UNUSED;
+{
+ const struct iris_section_align_entry *entry
+ = *(const struct iris_section_align_entry **) slot;
+
+ iris6_asm_named_section_1 (entry->name, entry->flags, 1 << entry->log);
+ return 1;
+}
+
+void
+iris6_asm_file_end (stream)
+ FILE *stream;
+{
+ /* Emit section directives with the proper alignment at the top of the
+ real output file. */
+ asm_out_file = iris_orig_asm_out_file;
+ htab_traverse (iris_section_align_htab, iris6_section_align_1, NULL);
+
+ /* Copy the data emitted to the temp file to the real output file. */
+ copy_file_data (asm_out_file, stream);
+
+ mips_asm_file_end (stream);
+}
+#endif /* TARGET_IRIX6 */