/* tc-mips.c -- assemble code for a MIPS chip.
Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+ 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ Free Software Foundation, Inc.
Contributed by the OSF and Ralph Campbell.
Written by Keith Knowles and Ralph Campbell, working independently.
Modified for ECOFF and R4000 support by Ian Lance Taylor of Cygnus
? ".rodata" \
: (abort (), ""))
+/* Ways in which an instruction can be "appended" to the output. */
+enum append_method {
+ /* Just add it normally. */
+ APPEND_ADD,
+
+ /* Add it normally and then add a nop. */
+ APPEND_ADD_WITH_NOP,
+
+ /* Turn an instruction with a delay slot into a "compact" version. */
+ APPEND_ADD_COMPACT,
+
+ /* Insert the instruction before the last one. */
+ APPEND_SWAP
+};
+
/* Information about an instruction, including its format, operands
and fixups. */
struct mips_cl_insn
/* True for mips16 instructions that jump to an absolute address. */
unsigned int mips16_absolute_jump_p : 1;
+
+ /* True if this instruction is complete. */
+ unsigned int complete_p : 1;
};
/* The ABI to use. */
/* MIPS ISA we are using for this output file. */
static int file_mips_isa = ISA_UNKNOWN;
-/* True if -mips16 was passed or implied by arguments passed on the
- command line (e.g., by -march). */
+/* True if any MIPS16 code was produced. */
static int file_ase_mips16;
#define ISA_SUPPORTS_MIPS16E (mips_opts.isa == ISA_MIPS32 \
|| mips_opts.isa == ISA_MIPS64 \
|| mips_opts.isa == ISA_MIPS64R2)
+/* True if we want to create R_MIPS_JALR for jalr $25. */
+#ifdef TE_IRIX
+#define MIPS_JALR_HINT_P(EXPR) HAVE_NEWABI
+#else
+/* As a GNU extension, we use R_MIPS_JALR for o32 too. However,
+ because there's no place for any addend, the only acceptable
+ expression is a bare symbol. */
+#define MIPS_JALR_HINT_P(EXPR) \
+ (!HAVE_IN_PLACE_ADDENDS \
+ || ((EXPR)->X_op == O_symbol && (EXPR)->X_add_number == 0))
+#endif
+
/* True if -mips3d was passed or implied by arguments passed on the
command line (e.g., by -march). */
static int file_ase_mips3d;
/* True if CPU has a ror instruction. */
#define CPU_HAS_ROR(CPU) CPU_HAS_DROR (CPU)
+/* True if CPU has seq/sne and seqi/snei instructions. */
+#define CPU_HAS_SEQ(CPU) ((CPU) == CPU_OCTEON)
+
+/* True if CPU does not implement the all the coprocessor insns. For these
+ CPUs only those COP insns are accepted that are explicitly marked to be
+ available on the CPU. ISA membership for COP insns is ignored. */
+#define NO_ISA_COP(CPU) ((CPU) == CPU_OCTEON)
+
/* True if mflo and mfhi can be immediately followed by instructions
which write to the HI and LO registers.
|| mips_opts.arch == CPU_R4010 \
|| mips_opts.arch == CPU_R10000 \
|| mips_opts.arch == CPU_R12000 \
+ || mips_opts.arch == CPU_R14000 \
+ || mips_opts.arch == CPU_R16000 \
|| mips_opts.arch == CPU_RM7000 \
|| mips_opts.arch == CPU_VR5500 \
)
/* Is this a mfhi or mflo instruction? */
#define MF_HILO_INSN(PINFO) \
- ((PINFO & INSN_READ_HI) || (PINFO & INSN_READ_LO))
+ ((PINFO & INSN_READ_HI) || (PINFO & INSN_READ_LO))
+
+/* Returns true for a (non floating-point) coprocessor instruction. Reading
+ or writing the condition code is only possible on the coprocessors and
+ these insns are not marked with INSN_COP. Thus for these insns use the
+ condition-code flags. */
+#define COP_INSN(PINFO) \
+ (PINFO != INSN_MACRO \
+ && ((PINFO) & (FP_S | FP_D)) == 0 \
+ && ((PINFO) & (INSN_COP | INSN_READ_COND_CODE | INSN_WRITE_COND_CODE)))
/* MIPS PIC level. */
/* Classifies the kind of instructions we're interested in when
implementing -mfix-vr4120. */
-enum fix_vr4120_class {
+enum fix_vr4120_class
+{
FIX_VR4120_MACC,
FIX_VR4120_DMACC,
FIX_VR4120_MULT,
NUM_FIX_VR4120_CLASSES
};
+/* ...likewise -mfix-loongson2f-jump. */
+static bfd_boolean mips_fix_loongson2f_jump;
+
+/* ...likewise -mfix-loongson2f-nop. */
+static bfd_boolean mips_fix_loongson2f_nop;
+
+/* True if -mfix-loongson2f-nop or -mfix-loongson2f-jump passed. */
+static bfd_boolean mips_fix_loongson2f;
+
/* Given two FIX_VR4120_* values X and Y, bit Y of element X is set if
there must be at least one other instruction between an instruction
of type X and an instruction of type Y. */
/* ...likewise -mfix-vr4130. */
static int mips_fix_vr4130;
+/* ...likewise -mfix-24k. */
+static int mips_fix_24k;
+
+/* ...likewise -mfix-cn63xxp1 */
+static bfd_boolean mips_fix_cn63xxp1;
+
/* We don't relax branches by default, since this causes us to expand
`la .l2 - .l1' if there's a branch between .l1 and .l2, because we
fail to compute the offset before expanding the macro to the most
but it's not clear that it would actually improve performance. */
-#define RELAX_BRANCH_ENCODE(uncond, likely, link, toofar) \
- ((relax_substateT) \
- (0xc0000000 \
- | ((toofar) ? 1 : 0) \
- | ((link) ? 2 : 0) \
- | ((likely) ? 4 : 0) \
- | ((uncond) ? 8 : 0)))
+#define RELAX_BRANCH_ENCODE(at, uncond, likely, link, toofar) \
+ ((relax_substateT) \
+ (0xc0000000 \
+ | ((at) & 0x1f) \
+ | ((toofar) ? 0x20 : 0) \
+ | ((link) ? 0x40 : 0) \
+ | ((likely) ? 0x80 : 0) \
+ | ((uncond) ? 0x100 : 0)))
#define RELAX_BRANCH_P(i) (((i) & 0xf0000000) == 0xc0000000)
-#define RELAX_BRANCH_UNCOND(i) (((i) & 8) != 0)
-#define RELAX_BRANCH_LIKELY(i) (((i) & 4) != 0)
-#define RELAX_BRANCH_LINK(i) (((i) & 2) != 0)
-#define RELAX_BRANCH_TOOFAR(i) (((i) & 1) != 0)
+#define RELAX_BRANCH_UNCOND(i) (((i) & 0x100) != 0)
+#define RELAX_BRANCH_LIKELY(i) (((i) & 0x80) != 0)
+#define RELAX_BRANCH_LINK(i) (((i) & 0x40) != 0)
+#define RELAX_BRANCH_TOOFAR(i) (((i) & 0x20) != 0)
+#define RELAX_BRANCH_AT(i) ((i) & 0x1f)
/* For mips16 code, we use an entirely different form of relaxation.
mips16 supports two versions of most instructions which take
enum mips_regclass { MIPS_GR_REG, MIPS_FP_REG, MIPS16_REG };
static void append_insn
- (struct mips_cl_insn *ip, expressionS *p, bfd_reloc_code_real_type *r);
+ (struct mips_cl_insn *, expressionS *, bfd_reloc_code_real_type *);
static void mips_no_prev_insn (void);
+static void macro_build (expressionS *, const char *, const char *, ...);
static void mips16_macro_build
- (expressionS *, const char *, const char *, va_list);
+ (expressionS *, const char *, const char *, va_list *);
static void load_register (int, expressionS *, int);
static void macro_start (void);
static void macro_end (void);
static void macro (struct mips_cl_insn * ip);
static void mips16_macro (struct mips_cl_insn * ip);
-#ifdef LOSING_COMPILER
-static void macro2 (struct mips_cl_insn * ip);
-#endif
static void mips_ip (char *str, struct mips_cl_insn * ip);
static void mips16_ip (char *str, struct mips_cl_insn * ip);
static void mips16_immed
{"origin", s_org, 0},
{"repeat", s_rept, 0},
+ /* For MIPS this is non-standard, but we define it for consistency. */
+ {"sbss", s_change_sec, 'B'},
+
/* These pseudo-ops are defined in read.c, but must be overridden
here for one reason or another. */
{"align", s_align, 0},
{ NULL, NULL, 0 },
};
+/* Export the ABI address size for use by TC_ADDRESS_BYTES for the
+ purpose of the `.dc.a' internal pseudo-op. */
+
+int
+mips_address_bytes (void)
+{
+ return HAVE_64BIT_ADDRESSES ? 8 : 4;
+}
+
extern void pop_insert (const pseudo_typeS *);
void
/* The default target format to use. */
+#if defined (TE_FreeBSD)
+#define ELF_TARGET(PREFIX, ENDIAN) PREFIX "trad" ENDIAN "mips-freebsd"
+#elif defined (TE_TMIPS)
+#define ELF_TARGET(PREFIX, ENDIAN) PREFIX "trad" ENDIAN "mips"
+#else
+#define ELF_TARGET(PREFIX, ENDIAN) PREFIX ENDIAN "mips"
+#endif
+
const char *
mips_target_format (void)
{
? "elf32-bigmips-vxworks"
: "elf32-littlemips-vxworks");
#endif
-#ifdef TE_TMIPS
- /* This is traditional mips. */
- return (target_big_endian
- ? (HAVE_64BIT_OBJECTS
- ? "elf64-tradbigmips"
- : (HAVE_NEWABI
- ? "elf32-ntradbigmips" : "elf32-tradbigmips"))
- : (HAVE_64BIT_OBJECTS
- ? "elf64-tradlittlemips"
- : (HAVE_NEWABI
- ? "elf32-ntradlittlemips" : "elf32-tradlittlemips")));
-#else
return (target_big_endian
? (HAVE_64BIT_OBJECTS
- ? "elf64-bigmips"
+ ? ELF_TARGET ("elf64-", "big")
: (HAVE_NEWABI
- ? "elf32-nbigmips" : "elf32-bigmips"))
+ ? ELF_TARGET ("elf32-n", "big")
+ : ELF_TARGET ("elf32-", "big")))
: (HAVE_64BIT_OBJECTS
- ? "elf64-littlemips"
+ ? ELF_TARGET ("elf64-", "little")
: (HAVE_NEWABI
- ? "elf32-nlittlemips" : "elf32-littlemips")));
-#endif
+ ? ELF_TARGET ("elf32-n", "little")
+ : ELF_TARGET ("elf32-", "little"))));
default:
abort ();
return NULL;
insn->fixed_p = (mips_opts.noreorder > 0);
insn->noreorder_p = (mips_opts.noreorder > 0);
insn->mips16_absolute_jump_p = 0;
+ insn->complete_p = 0;
}
/* Record the current MIPS16 mode in now_seg. */
if (reg >= 0)
*s = e;
else if (types & RWARN)
- as_warn ("Unrecognized register name `%s'", *s);
+ as_warn (_("Unrecognized register name `%s'"), *s);
*e = save_c;
if (regnop)
}
/* Return TRUE if opcode MO is valid on the currently selected ISA and
- architecture. If EXPANSIONP is TRUE then this check is done while
- expanding a macro. Use is_opcode_valid_16 for MIPS16 opcodes. */
+ architecture. Use is_opcode_valid_16 for MIPS16 opcodes. */
static bfd_boolean
-is_opcode_valid (const struct mips_opcode *mo, bfd_boolean expansionp)
+is_opcode_valid (const struct mips_opcode *mo)
{
int isa = mips_opts.isa;
int fp_s, fp_d;
if (mips_opts.ase_smartmips)
isa |= INSN_SMARTMIPS;
- /* For user code we don't check for mips_opts.mips16 since we want
- to allow jalx if -mips16 was specified on the command line. */
- if (expansionp ? mips_opts.mips16 : file_ase_mips16)
- isa |= INSN_MIPS16;
+ /* Don't accept instructions based on the ISA if the CPU does not implement
+ all the coprocessor insns. */
+ if (NO_ISA_COP (mips_opts.arch)
+ && COP_INSN (mo->pinfo))
+ isa = 0;
if (!OPCODE_IS_MEMBER (mo, isa, mips_opts.arch))
return FALSE;
if (nop_insn.insn_mo == NULL && strcmp (name, "nop") == 0)
{
create_insn (&nop_insn, mips_opcodes + i);
+ if (mips_fix_loongson2f_nop)
+ nop_insn.insn_opcode = LOONGSON2F_NOP_INSN;
nop_insn.fixed_p = 1;
}
}
helps us detect invalid uses of them. */
for (i = 0; reg_names[i].name; i++)
symbol_table_insert (symbol_new (reg_names[i].name, reg_section,
- reg_names[i].num, // & RNUM_MASK,
+ reg_names[i].num, /* & RNUM_MASK, */
&zero_address_frag));
if (HAVE_NEWABI)
for (i = 0; reg_names_n32n64[i].name; i++)
symbol_table_insert (symbol_new (reg_names_n32n64[i].name, reg_section,
- reg_names_n32n64[i].num, // & RNUM_MASK,
+ reg_names_n32n64[i].num, /* & RNUM_MASK, */
&zero_address_frag));
else
for (i = 0; reg_names_o32[i].name; i++)
symbol_table_insert (symbol_new (reg_names_o32[i].name, reg_section,
- reg_names_o32[i].num, // & RNUM_MASK,
+ reg_names_o32[i].num, /* & RNUM_MASK, */
&zero_address_frag));
mips_no_prev_insn ();
void
md_mips_end (void)
{
+ mips_emit_delays ();
if (! ECOFF_DEBUGGING)
md_obj_end ();
}
}
}
+/* Convenience functions for abstracting away the differences between
+ MIPS16 and non-MIPS16 relocations. */
+
+static inline bfd_boolean
+mips16_reloc_p (bfd_reloc_code_real_type reloc)
+{
+ switch (reloc)
+ {
+ case BFD_RELOC_MIPS16_JMP:
+ case BFD_RELOC_MIPS16_GPREL:
+ case BFD_RELOC_MIPS16_GOT16:
+ case BFD_RELOC_MIPS16_CALL16:
+ case BFD_RELOC_MIPS16_HI16_S:
+ case BFD_RELOC_MIPS16_HI16:
+ case BFD_RELOC_MIPS16_LO16:
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+}
+
+static inline bfd_boolean
+got16_reloc_p (bfd_reloc_code_real_type reloc)
+{
+ return reloc == BFD_RELOC_MIPS_GOT16 || reloc == BFD_RELOC_MIPS16_GOT16;
+}
+
+static inline bfd_boolean
+hi16_reloc_p (bfd_reloc_code_real_type reloc)
+{
+ return reloc == BFD_RELOC_HI16_S || reloc == BFD_RELOC_MIPS16_HI16_S;
+}
+
+static inline bfd_boolean
+lo16_reloc_p (bfd_reloc_code_real_type reloc)
+{
+ return reloc == BFD_RELOC_LO16 || reloc == BFD_RELOC_MIPS16_LO16;
+}
+
/* Return true if the given relocation might need a matching %lo().
This is only "might" because SVR4 R_MIPS_GOT16 relocations only
need a matching %lo() when applied to local symbols. */
reloc_needs_lo_p (bfd_reloc_code_real_type reloc)
{
return (HAVE_IN_PLACE_ADDENDS
- && (reloc == BFD_RELOC_HI16_S
- || reloc == BFD_RELOC_MIPS16_HI16_S
+ && (hi16_reloc_p (reloc)
/* VxWorks R_MIPS_GOT16 relocs never need a matching %lo();
all GOT16 relocations evaluate to "G". */
- || (reloc == BFD_RELOC_MIPS_GOT16 && mips_pic != VXWORKS_PIC)));
+ || (got16_reloc_p (reloc) && mips_pic != VXWORKS_PIC)));
+}
+
+/* Return the type of %lo() reloc needed by RELOC, given that
+ reloc_needs_lo_p. */
+
+static inline bfd_reloc_code_real_type
+matching_lo_reloc (bfd_reloc_code_real_type reloc)
+{
+ return mips16_reloc_p (reloc) ? BFD_RELOC_MIPS16_LO16 : BFD_RELOC_LO16;
}
/* Return true if the given fixup is followed by a matching R_MIPS_LO16
fixup_has_matching_lo_p (fixS *fixp)
{
return (fixp->fx_next != NULL
- && (fixp->fx_next->fx_r_type == BFD_RELOC_LO16
- || fixp->fx_next->fx_r_type == BFD_RELOC_MIPS16_LO16)
+ && fixp->fx_next->fx_r_type == matching_lo_reloc (fixp->fx_r_type)
&& fixp->fx_addsy == fixp->fx_next->fx_addsy
&& fixp->fx_offset == fixp->fx_next->fx_offset);
}
-/* See whether instruction IP reads register REG. CLASS is the type
- of register. */
-
-static int
-insn_uses_reg (const struct mips_cl_insn *ip, unsigned int reg,
- enum mips_regclass class)
-{
- if (class == MIPS16_REG)
- {
- assert (mips_opts.mips16);
- reg = mips16_to_32_reg_map[reg];
- class = MIPS_GR_REG;
- }
-
- /* Don't report on general register ZERO, since it never changes. */
- if (class == MIPS_GR_REG && reg == ZERO)
- return 0;
-
- if (class == MIPS_FP_REG)
- {
- assert (! mips_opts.mips16);
- /* If we are called with either $f0 or $f1, we must check $f0.
- This is not optimal, because it will introduce an unnecessary
- NOP between "lwc1 $f0" and "swc1 $f1". To fix this we would
- need to distinguish reading both $f0 and $f1 or just one of
- them. Note that we don't have to check the other way,
- because there is no instruction that sets both $f0 and $f1
- and requires a delay. */
- if ((ip->insn_mo->pinfo & INSN_READ_FPR_S)
- && ((EXTRACT_OPERAND (FS, *ip) & ~(unsigned) 1)
- == (reg &~ (unsigned) 1)))
- return 1;
- if ((ip->insn_mo->pinfo & INSN_READ_FPR_T)
- && ((EXTRACT_OPERAND (FT, *ip) & ~(unsigned) 1)
- == (reg &~ (unsigned) 1)))
- return 1;
- }
- else if (! mips_opts.mips16)
- {
- if ((ip->insn_mo->pinfo & INSN_READ_GPR_S)
- && EXTRACT_OPERAND (RS, *ip) == reg)
- return 1;
- if ((ip->insn_mo->pinfo & INSN_READ_GPR_T)
- && EXTRACT_OPERAND (RT, *ip) == reg)
- return 1;
- }
- else
- {
- if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_X)
- && mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RX, *ip)] == reg)
- return 1;
- if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_Y)
- && mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RY, *ip)] == reg)
- return 1;
- if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_Z)
- && (mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (MOVE32Z, *ip)]
- == reg))
- return 1;
- if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_T) && reg == TREG)
- return 1;
- if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_SP) && reg == SP)
- return 1;
- if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_31) && reg == RA)
- return 1;
- if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_GPR_X)
- && MIPS16_EXTRACT_OPERAND (REGR32, *ip) == reg)
- return 1;
- }
-
- return 0;
-}
-
/* This function returns true if modifying a register requires a
delay. */
for (l = si->label_list; l != NULL; l = l->next)
{
- assert (S_GET_SEGMENT (l->label) == now_seg);
+ gas_assert (S_GET_SEGMENT (l->label) == now_seg);
symbol_set_frag (l->label, frag_now);
val = (valueT) frag_now_fix ();
/* mips16 text labels are stored as odd. */
#if defined(OBJ_ELF) || defined(OBJ_MAYBE_ELF)
if (IS_ELF)
- S_SET_OTHER (label, STO_MIPS16);
+ S_SET_OTHER (label, ELF_ST_SET_MIPS16 (S_GET_OTHER (label)));
#endif
if ((S_GET_VALUE (label) & 1) == 0
/* Don't adjust the address if the label is global or weak, or
static void
relax_start (symbolS *symbol)
{
- assert (mips_relax.sequence == 0);
+ gas_assert (mips_relax.sequence == 0);
mips_relax.sequence = 1;
mips_relax.symbol = symbol;
}
static void
relax_switch (void)
{
- assert (mips_relax.sequence == 1);
+ gas_assert (mips_relax.sequence == 1);
mips_relax.sequence = 2;
}
static void
relax_end (void)
{
- assert (mips_relax.sequence == 2);
+ gas_assert (mips_relax.sequence == 2);
relax_close_frag ();
mips_relax.sequence = 0;
}
+/* Return the mask of core registers that IP reads. */
+
+static unsigned int
+gpr_read_mask (const struct mips_cl_insn *ip)
+{
+ unsigned long pinfo, pinfo2;
+ unsigned int mask;
+
+ mask = 0;
+ pinfo = ip->insn_mo->pinfo;
+ pinfo2 = ip->insn_mo->pinfo2;
+ if (mips_opts.mips16)
+ {
+ if (pinfo & MIPS16_INSN_READ_X)
+ mask |= 1 << mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RX, *ip)];
+ if (pinfo & MIPS16_INSN_READ_Y)
+ mask |= 1 << mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RY, *ip)];
+ if (pinfo & MIPS16_INSN_READ_T)
+ mask |= 1 << TREG;
+ if (pinfo & MIPS16_INSN_READ_SP)
+ mask |= 1 << SP;
+ if (pinfo & MIPS16_INSN_READ_31)
+ mask |= 1 << RA;
+ if (pinfo & MIPS16_INSN_READ_Z)
+ mask |= 1 << (mips16_to_32_reg_map
+ [MIPS16_EXTRACT_OPERAND (MOVE32Z, *ip)]);
+ if (pinfo & MIPS16_INSN_READ_GPR_X)
+ mask |= 1 << MIPS16_EXTRACT_OPERAND (REGR32, *ip);
+ }
+ else
+ {
+ if (pinfo2 & INSN2_READ_GPR_D)
+ mask |= 1 << EXTRACT_OPERAND (RD, *ip);
+ if (pinfo & INSN_READ_GPR_T)
+ mask |= 1 << EXTRACT_OPERAND (RT, *ip);
+ if (pinfo & INSN_READ_GPR_S)
+ mask |= 1 << EXTRACT_OPERAND (RS, *ip);
+ if (pinfo2 & INSN2_READ_GPR_Z)
+ mask |= 1 << EXTRACT_OPERAND (RZ, *ip);
+ }
+ /* Don't include register 0. */
+ return mask & ~1;
+}
+
+/* Return the mask of core registers that IP writes. */
+
+static unsigned int
+gpr_write_mask (const struct mips_cl_insn *ip)
+{
+ unsigned long pinfo, pinfo2;
+ unsigned int mask;
+
+ mask = 0;
+ pinfo = ip->insn_mo->pinfo;
+ pinfo2 = ip->insn_mo->pinfo2;
+ if (mips_opts.mips16)
+ {
+ if (pinfo & MIPS16_INSN_WRITE_X)
+ mask |= 1 << mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RX, *ip)];
+ if (pinfo & MIPS16_INSN_WRITE_Y)
+ mask |= 1 << mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RY, *ip)];
+ if (pinfo & MIPS16_INSN_WRITE_Z)
+ mask |= 1 << mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RZ, *ip)];
+ if (pinfo & MIPS16_INSN_WRITE_T)
+ mask |= 1 << TREG;
+ if (pinfo & MIPS16_INSN_WRITE_SP)
+ mask |= 1 << SP;
+ if (pinfo & MIPS16_INSN_WRITE_31)
+ mask |= 1 << RA;
+ if (pinfo & MIPS16_INSN_WRITE_GPR_Y)
+ mask |= 1 << MIPS16OP_EXTRACT_REG32R (ip->insn_opcode);
+ }
+ else
+ {
+ if (pinfo & INSN_WRITE_GPR_D)
+ mask |= 1 << EXTRACT_OPERAND (RD, *ip);
+ if (pinfo & INSN_WRITE_GPR_T)
+ mask |= 1 << EXTRACT_OPERAND (RT, *ip);
+ if (pinfo & INSN_WRITE_GPR_31)
+ mask |= 1 << RA;
+ if (pinfo2 & INSN2_WRITE_GPR_Z)
+ mask |= 1 << EXTRACT_OPERAND (RZ, *ip);
+ }
+ /* Don't include register 0. */
+ return mask & ~1;
+}
+
+/* Return the mask of floating-point registers that IP reads. */
+
+static unsigned int
+fpr_read_mask (const struct mips_cl_insn *ip)
+{
+ unsigned long pinfo, pinfo2;
+ unsigned int mask;
+
+ mask = 0;
+ pinfo = ip->insn_mo->pinfo;
+ pinfo2 = ip->insn_mo->pinfo2;
+ if (!mips_opts.mips16)
+ {
+ if (pinfo & INSN_READ_FPR_S)
+ mask |= 1 << EXTRACT_OPERAND (FS, *ip);
+ if (pinfo & INSN_READ_FPR_T)
+ mask |= 1 << EXTRACT_OPERAND (FT, *ip);
+ if (pinfo & INSN_READ_FPR_R)
+ mask |= 1 << EXTRACT_OPERAND (FR, *ip);
+ if (pinfo2 & INSN2_READ_FPR_Z)
+ mask |= 1 << EXTRACT_OPERAND (FZ, *ip);
+ }
+ /* Conservatively treat all operands to an FP_D instruction are doubles.
+ (This is overly pessimistic for things like cvt.d.s.) */
+ if (HAVE_32BIT_FPRS && (pinfo & FP_D))
+ mask |= mask << 1;
+ return mask;
+}
+
+/* Return the mask of floating-point registers that IP writes. */
+
+static unsigned int
+fpr_write_mask (const struct mips_cl_insn *ip)
+{
+ unsigned long pinfo, pinfo2;
+ unsigned int mask;
+
+ mask = 0;
+ pinfo = ip->insn_mo->pinfo;
+ pinfo2 = ip->insn_mo->pinfo2;
+ if (!mips_opts.mips16)
+ {
+ if (pinfo & INSN_WRITE_FPR_D)
+ mask |= 1 << EXTRACT_OPERAND (FD, *ip);
+ if (pinfo & INSN_WRITE_FPR_S)
+ mask |= 1 << EXTRACT_OPERAND (FS, *ip);
+ if (pinfo & INSN_WRITE_FPR_T)
+ mask |= 1 << EXTRACT_OPERAND (FT, *ip);
+ if (pinfo2 & INSN2_WRITE_FPR_Z)
+ mask |= 1 << EXTRACT_OPERAND (FZ, *ip);
+ }
+ /* Conservatively treat all operands to an FP_D instruction are doubles.
+ (This is overly pessimistic for things like cvt.s.d.) */
+ if (HAVE_32BIT_FPRS && (pinfo & FP_D))
+ mask |= mask << 1;
+ return mask;
+}
+
/* Classify an instruction according to the FIX_VR4120_* enumeration.
Return NUM_FIX_VR4120_CLASSES if the instruction isn't affected
by VR4120 errata. */
return NUM_FIX_VR4120_CLASSES;
}
+#define INSN_ERET 0x42000018
+#define INSN_DERET 0x4200001f
+
/* Return the number of instructions that must separate INSN1 and INSN2,
where INSN1 is the earlier instruction. Return the worst-case value
for any INSN2 if INSN2 is null. */
const struct mips_cl_insn *insn2)
{
unsigned long pinfo1, pinfo2;
+ unsigned int mask;
/* This function needs to know which pinfo flags are set for INSN2
and which registers INSN2 uses. The former is stored in PINFO2 and
- the latter is tested via INSN2_USES_REG. If INSN2 is null, PINFO2
- will have every flag set and INSN2_USES_REG will always return true. */
+ the latter is tested via INSN2_USES_GPR. If INSN2 is null, PINFO2
+ will have every flag set and INSN2_USES_GPR will always return true. */
pinfo1 = insn1->insn_mo->pinfo;
pinfo2 = insn2 ? insn2->insn_mo->pinfo : ~0U;
-#define INSN2_USES_REG(REG, CLASS) \
- (insn2 == NULL || insn_uses_reg (insn2, REG, CLASS))
+#define INSN2_USES_GPR(REG) \
+ (insn2 == NULL || (gpr_read_mask (insn2) & (1U << (REG))) != 0)
/* For most targets, write-after-read dependencies on the HI and LO
registers must be separated by at least two instructions. */
between an mfhi or mflo and any instruction that uses the result. */
if (mips_7000_hilo_fix
&& MF_HILO_INSN (pinfo1)
- && INSN2_USES_REG (EXTRACT_OPERAND (RD, *insn1), MIPS_GR_REG))
+ && INSN2_USES_GPR (EXTRACT_OPERAND (RD, *insn1)))
return 2;
+ /* If we're working around 24K errata, one instruction is required
+ if an ERET or DERET is followed by a branch instruction. */
+ if (mips_fix_24k)
+ {
+ if (insn1->insn_opcode == INSN_ERET
+ || insn1->insn_opcode == INSN_DERET)
+ {
+ if (insn2 == NULL
+ || insn2->insn_opcode == INSN_ERET
+ || insn2->insn_opcode == INSN_DERET
+ || (insn2->insn_mo->pinfo
+ & (INSN_UNCOND_BRANCH_DELAY
+ | INSN_COND_BRANCH_DELAY
+ | INSN_COND_BRANCH_LIKELY)) != 0)
+ return 1;
+ }
+ }
+
/* If working around VR4120 errata, check for combinations that need
a single intervening instruction. */
if (mips_fix_vr4120)
|| (!cop_interlocks && (pinfo1 & INSN_LOAD_COPROC_DELAY)))
{
know (pinfo1 & INSN_WRITE_GPR_T);
- if (INSN2_USES_REG (EXTRACT_OPERAND (RT, *insn1), MIPS_GR_REG))
+ if (INSN2_USES_GPR (EXTRACT_OPERAND (RT, *insn1)))
return 1;
}
/* Handle cases where INSN1 writes to a known general coprocessor
register. There must be a one instruction delay before INSN2
if INSN2 reads that register, otherwise no delay is needed. */
- if (pinfo1 & INSN_WRITE_FPR_T)
- {
- if (INSN2_USES_REG (EXTRACT_OPERAND (FT, *insn1), MIPS_FP_REG))
- return 1;
- }
- else if (pinfo1 & INSN_WRITE_FPR_S)
+ mask = fpr_write_mask (insn1);
+ if (mask != 0)
{
- if (INSN2_USES_REG (EXTRACT_OPERAND (FS, *insn1), MIPS_FP_REG))
+ if (!insn2 || (mask & fpr_read_mask (insn2)) != 0)
return 1;
}
else
return 1;
}
-#undef INSN2_USES_REG
+#undef INSN2_USES_GPR
return 0;
}
/* Return the number of nops that would be needed to work around the
VR4130 mflo/mfhi errata if instruction INSN immediately followed
- the MAX_VR4130_NOPS instructions described by HISTORY. */
+ the MAX_VR4130_NOPS instructions described by HIST. Ignore hazards
+ that are contained within the first IGNORE instructions of HIST. */
static int
-nops_for_vr4130 (const struct mips_cl_insn *history,
+nops_for_vr4130 (int ignore, const struct mips_cl_insn *hist,
const struct mips_cl_insn *insn)
{
- int i, j, reg;
+ int i, j;
+ unsigned int mask;
/* Check if the instruction writes to HI or LO. MTHI and MTLO
are not affected by the errata. */
/* Search for the first MFLO or MFHI. */
for (i = 0; i < MAX_VR4130_NOPS; i++)
- if (!history[i].noreorder_p && MF_HILO_INSN (history[i].insn_mo->pinfo))
+ if (MF_HILO_INSN (hist[i].insn_mo->pinfo))
{
/* Extract the destination register. */
- if (mips_opts.mips16)
- reg = mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RX, history[i])];
- else
- reg = EXTRACT_OPERAND (RD, history[i]);
+ mask = gpr_write_mask (&hist[i]);
/* No nops are needed if INSN reads that register. */
- if (insn != NULL && insn_uses_reg (insn, reg, MIPS_GR_REG))
+ if (insn != NULL && (gpr_read_mask (insn) & mask) != 0)
return 0;
/* ...or if any of the intervening instructions do. */
for (j = 0; j < i; j++)
- if (insn_uses_reg (&history[j], reg, MIPS_GR_REG))
+ if (gpr_read_mask (&hist[j]) & mask)
return 0;
- return MAX_VR4130_NOPS - i;
+ if (i >= ignore)
+ return MAX_VR4130_NOPS - i;
}
return 0;
}
-/* Return the number of nops that would be needed if instruction INSN
- immediately followed the MAX_NOPS instructions given by HISTORY,
- where HISTORY[0] is the most recent instruction. If INSN is null,
- return the worse-case number of nops for any instruction. */
+#define BASE_REG_EQ(INSN1, INSN2) \
+ ((((INSN1) >> OP_SH_RS) & OP_MASK_RS) \
+ == (((INSN2) >> OP_SH_RS) & OP_MASK_RS))
+
+/* Return the minimum alignment for this store instruction. */
+
+static int
+fix_24k_align_to (const struct mips_opcode *mo)
+{
+ if (strcmp (mo->name, "sh") == 0)
+ return 2;
+
+ if (strcmp (mo->name, "swc1") == 0
+ || strcmp (mo->name, "swc2") == 0
+ || strcmp (mo->name, "sw") == 0
+ || strcmp (mo->name, "sc") == 0
+ || strcmp (mo->name, "s.s") == 0)
+ return 4;
+
+ if (strcmp (mo->name, "sdc1") == 0
+ || strcmp (mo->name, "sdc2") == 0
+ || strcmp (mo->name, "s.d") == 0)
+ return 8;
+
+ /* sb, swl, swr */
+ return 1;
+}
+
+struct fix_24k_store_info
+ {
+ /* Immediate offset, if any, for this store instruction. */
+ short off;
+ /* Alignment required by this store instruction. */
+ int align_to;
+ /* True for register offsets. */
+ int register_offset;
+ };
+
+/* Comparison function used by qsort. */
+
+static int
+fix_24k_sort (const void *a, const void *b)
+{
+ const struct fix_24k_store_info *pos1 = a;
+ const struct fix_24k_store_info *pos2 = b;
+
+ return (pos1->off - pos2->off);
+}
+
+/* INSN is a store instruction. Try to record the store information
+ in STINFO. Return false if the information isn't known. */
+
+static bfd_boolean
+fix_24k_record_store_info (struct fix_24k_store_info *stinfo,
+ const struct mips_cl_insn *insn)
+{
+ /* The instruction must have a known offset. */
+ if (!insn->complete_p || !strstr (insn->insn_mo->args, "o("))
+ return FALSE;
+
+ stinfo->off = (insn->insn_opcode >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE;
+ stinfo->align_to = fix_24k_align_to (insn->insn_mo);
+ return TRUE;
+}
+
+/* Return the number of nops that would be needed to work around the 24k
+ "lost data on stores during refill" errata if instruction INSN
+ immediately followed the 2 instructions described by HIST.
+ Ignore hazards that are contained within the first IGNORE
+ instructions of HIST.
+
+ Problem: The FSB (fetch store buffer) acts as an intermediate buffer
+ for the data cache refills and store data. The following describes
+ the scenario where the store data could be lost.
+
+ * A data cache miss, due to either a load or a store, causing fill
+ data to be supplied by the memory subsystem
+ * The first three doublewords of fill data are returned and written
+ into the cache
+ * A sequence of four stores occurs in consecutive cycles around the
+ final doubleword of the fill:
+ * Store A
+ * Store B
+ * Store C
+ * Zero, One or more instructions
+ * Store D
+
+ The four stores A-D must be to different doublewords of the line that
+ is being filled. The fourth instruction in the sequence above permits
+ the fill of the final doubleword to be transferred from the FSB into
+ the cache. In the sequence above, the stores may be either integer
+ (sb, sh, sw, swr, swl, sc) or coprocessor (swc1/swc2, sdc1/sdc2,
+ swxc1, sdxc1, suxc1) stores, as long as the four stores are to
+ different doublewords on the line. If the floating point unit is
+ running in 1:2 mode, it is not possible to create the sequence above
+ using only floating point store instructions.
+
+ In this case, the cache line being filled is incorrectly marked
+ invalid, thereby losing the data from any store to the line that
+ occurs between the original miss and the completion of the five
+ cycle sequence shown above.
+
+ The workarounds are:
+
+ * Run the data cache in write-through mode.
+ * Insert a non-store instruction between
+ Store A and Store B or Store B and Store C. */
+
+static int
+nops_for_24k (int ignore, const struct mips_cl_insn *hist,
+ const struct mips_cl_insn *insn)
+{
+ struct fix_24k_store_info pos[3];
+ int align, i, base_offset;
+
+ if (ignore >= 2)
+ return 0;
+
+ /* If the previous instruction wasn't a store, there's nothing to
+ worry about. */
+ if ((hist[0].insn_mo->pinfo & INSN_STORE_MEMORY) == 0)
+ return 0;
+
+ /* If the instructions after the previous one are unknown, we have
+ to assume the worst. */
+ if (!insn)
+ return 1;
+
+ /* Check whether we are dealing with three consecutive stores. */
+ if ((insn->insn_mo->pinfo & INSN_STORE_MEMORY) == 0
+ || (hist[1].insn_mo->pinfo & INSN_STORE_MEMORY) == 0)
+ return 0;
+
+ /* If we don't know the relationship between the store addresses,
+ assume the worst. */
+ if (!BASE_REG_EQ (insn->insn_opcode, hist[0].insn_opcode)
+ || !BASE_REG_EQ (insn->insn_opcode, hist[1].insn_opcode))
+ return 1;
+
+ if (!fix_24k_record_store_info (&pos[0], insn)
+ || !fix_24k_record_store_info (&pos[1], &hist[0])
+ || !fix_24k_record_store_info (&pos[2], &hist[1]))
+ return 1;
+
+ qsort (&pos, 3, sizeof (struct fix_24k_store_info), fix_24k_sort);
+
+ /* Pick a value of ALIGN and X such that all offsets are adjusted by
+ X bytes and such that the base register + X is known to be aligned
+ to align bytes. */
+
+ if (((insn->insn_opcode >> OP_SH_RS) & OP_MASK_RS) == SP)
+ align = 8;
+ else
+ {
+ align = pos[0].align_to;
+ base_offset = pos[0].off;
+ for (i = 1; i < 3; i++)
+ if (align < pos[i].align_to)
+ {
+ align = pos[i].align_to;
+ base_offset = pos[i].off;
+ }
+ for (i = 0; i < 3; i++)
+ pos[i].off -= base_offset;
+ }
+
+ pos[0].off &= ~align + 1;
+ pos[1].off &= ~align + 1;
+ pos[2].off &= ~align + 1;
+
+ /* If any two stores write to the same chunk, they also write to the
+ same doubleword. The offsets are still sorted at this point. */
+ if (pos[0].off == pos[1].off || pos[1].off == pos[2].off)
+ return 0;
+
+ /* A range of at least 9 bytes is needed for the stores to be in
+ non-overlapping doublewords. */
+ if (pos[2].off - pos[0].off <= 8)
+ return 0;
+
+ if (pos[2].off - pos[1].off >= 24
+ || pos[1].off - pos[0].off >= 24
+ || pos[2].off - pos[0].off >= 32)
+ return 0;
+
+ return 1;
+}
+
+/* Return the number of nops that would be needed if instruction INSN
+ immediately followed the MAX_NOPS instructions given by HIST,
+ where HIST[0] is the most recent instruction. Ignore hazards
+ between INSN and the first IGNORE instructions in HIST.
+
+ If INSN is null, return the worse-case number of nops for any
+ instruction. */
+
+static int
+nops_for_insn (int ignore, const struct mips_cl_insn *hist,
+ const struct mips_cl_insn *insn)
+{
+ int i, nops, tmp_nops;
+
+ nops = 0;
+ for (i = ignore; i < MAX_DELAY_NOPS; i++)
+ {
+ tmp_nops = insns_between (hist + i, insn) - i;
+ if (tmp_nops > nops)
+ nops = tmp_nops;
+ }
+
+ if (mips_fix_vr4130)
+ {
+ tmp_nops = nops_for_vr4130 (ignore, hist, insn);
+ if (tmp_nops > nops)
+ nops = tmp_nops;
+ }
+
+ if (mips_fix_24k)
+ {
+ tmp_nops = nops_for_24k (ignore, hist, insn);
+ if (tmp_nops > nops)
+ nops = tmp_nops;
+ }
+
+ return nops;
+}
+
+/* The variable arguments provide NUM_INSNS extra instructions that
+ might be added to HIST. Return the largest number of nops that
+ would be needed after the extended sequence, ignoring hazards
+ in the first IGNORE instructions. */
+
+static int
+nops_for_sequence (int num_insns, int ignore,
+ const struct mips_cl_insn *hist, ...)
+{
+ va_list args;
+ struct mips_cl_insn buffer[MAX_NOPS];
+ struct mips_cl_insn *cursor;
+ int nops;
+
+ va_start (args, hist);
+ cursor = buffer + num_insns;
+ memcpy (cursor, hist, (MAX_NOPS - num_insns) * sizeof (*cursor));
+ while (cursor > buffer)
+ *--cursor = *va_arg (args, const struct mips_cl_insn *);
+
+ nops = nops_for_insn (ignore, buffer, NULL);
+ va_end (args);
+ return nops;
+}
+
+/* Like nops_for_insn, but if INSN is a branch, take into account the
+ worst-case delay for the branch target. */
+
+static int
+nops_for_insn_or_target (int ignore, const struct mips_cl_insn *hist,
+ const struct mips_cl_insn *insn)
+{
+ int nops, tmp_nops;
+
+ nops = nops_for_insn (ignore, hist, insn);
+ if (insn->insn_mo->pinfo & (INSN_UNCOND_BRANCH_DELAY
+ | INSN_COND_BRANCH_DELAY
+ | INSN_COND_BRANCH_LIKELY))
+ {
+ tmp_nops = nops_for_sequence (2, ignore ? ignore + 2 : 0,
+ hist, insn, NOP_INSN);
+ if (tmp_nops > nops)
+ nops = tmp_nops;
+ }
+ else if (mips_opts.mips16
+ && (insn->insn_mo->pinfo & (MIPS16_INSN_UNCOND_BRANCH
+ | MIPS16_INSN_COND_BRANCH)))
+ {
+ tmp_nops = nops_for_sequence (1, ignore ? ignore + 1 : 0, hist, insn);
+ if (tmp_nops > nops)
+ nops = tmp_nops;
+ }
+ return nops;
+}
+
+/* Fix NOP issue: Replace nops by "or at,at,zero". */
+
+static void
+fix_loongson2f_nop (struct mips_cl_insn * ip)
+{
+ if (strcmp (ip->insn_mo->name, "nop") == 0)
+ ip->insn_opcode = LOONGSON2F_NOP_INSN;
+}
+
+/* Fix Jump Issue: Eliminate instruction fetch from outside 256M region
+ jr target pc &= 'hffff_ffff_cfff_ffff. */
+
+static void
+fix_loongson2f_jump (struct mips_cl_insn * ip)
+{
+ if (strcmp (ip->insn_mo->name, "j") == 0
+ || strcmp (ip->insn_mo->name, "jr") == 0
+ || strcmp (ip->insn_mo->name, "jalr") == 0)
+ {
+ int sreg;
+ expressionS ep;
+
+ if (! mips_opts.at)
+ return;
+
+ sreg = EXTRACT_OPERAND (RS, *ip);
+ if (sreg == ZERO || sreg == KT0 || sreg == KT1 || sreg == ATREG)
+ return;
+
+ ep.X_op = O_constant;
+ ep.X_add_number = 0xcfff0000;
+ macro_build (&ep, "lui", "t,u", ATREG, BFD_RELOC_HI16);
+ ep.X_add_number = 0xffff;
+ macro_build (&ep, "ori", "t,r,i", ATREG, ATREG, BFD_RELOC_LO16);
+ macro_build (NULL, "and", "d,v,t", sreg, sreg, ATREG);
+ }
+}
+
+static void
+fix_loongson2f (struct mips_cl_insn * ip)
+{
+ if (mips_fix_loongson2f_nop)
+ fix_loongson2f_nop (ip);
+
+ if (mips_fix_loongson2f_jump)
+ fix_loongson2f_jump (ip);
+}
+
+/* IP is a branch that has a delay slot, and we need to fill it
+ automatically. Return true if we can do that by swapping IP
+ with the previous instruction. */
+
+static bfd_boolean
+can_swap_branch_p (struct mips_cl_insn *ip)
+{
+ unsigned long pinfo, prev_pinfo;
+ unsigned int gpr_read, gpr_write, prev_gpr_read, prev_gpr_write;
+
+ /* -O2 and above is required for this optimization. */
+ if (mips_optimize < 2)
+ return FALSE;
+
+ /* If we have seen .set volatile or .set nomove, don't optimize. */
+ if (mips_opts.nomove)
+ return FALSE;
+
+ /* We can't swap if the previous instruction's position is fixed. */
+ if (history[0].fixed_p)
+ return FALSE;
+
+ /* If the previous previous insn was in a .set noreorder, we can't
+ swap. Actually, the MIPS assembler will swap in this situation.
+ However, gcc configured -with-gnu-as will generate code like
+
+ .set noreorder
+ lw $4,XXX
+ .set reorder
+ INSN
+ bne $4,$0,foo
+
+ in which we can not swap the bne and INSN. If gcc is not configured
+ -with-gnu-as, it does not output the .set pseudo-ops. */
+ if (history[1].noreorder_p)
+ return FALSE;
+
+ /* If the previous instruction had a fixup in mips16 mode, we can not
+ swap. This normally means that the previous instruction was a 4
+ byte branch anyhow. */
+ if (mips_opts.mips16 && history[0].fixp[0])
+ return FALSE;
+
+ /* If the branch is itself the target of a branch, we can not swap.
+ We cheat on this; all we check for is whether there is a label on
+ this instruction. If there are any branches to anything other than
+ a label, users must use .set noreorder. */
+ if (seg_info (now_seg)->label_list)
+ return FALSE;
+
+ /* If the previous instruction is in a variant frag other than this
+ branch's one, we cannot do the swap. This does not apply to the
+ mips16, which uses variant frags for different purposes. */
+ if (!mips_opts.mips16
+ && history[0].frag
+ && history[0].frag->fr_type == rs_machine_dependent)
+ return FALSE;
+
+ /* We do not swap with instructions that cannot architecturally
+ be placed in a branch delay slot, such as SYNC or ERET. We
+ also refrain from swapping with a trap instruction, since it
+ complicates trap handlers to have the trap instruction be in
+ a delay slot. */
+ prev_pinfo = history[0].insn_mo->pinfo;
+ if (prev_pinfo & INSN_NO_DELAY_SLOT)
+ return FALSE;
+
+ /* Check for conflicts between the branch and the instructions
+ before the candidate delay slot. */
+ if (nops_for_insn (0, history + 1, ip) > 0)
+ return FALSE;
+
+ /* Check for conflicts between the swapped sequence and the
+ target of the branch. */
+ if (nops_for_sequence (2, 0, history + 1, ip, history) > 0)
+ return FALSE;
+
+ /* If the branch reads a register that the previous
+ instruction sets, we can not swap. */
+ gpr_read = gpr_read_mask (ip);
+ prev_gpr_write = gpr_write_mask (&history[0]);
+ if (gpr_read & prev_gpr_write)
+ return FALSE;
+
+ /* If the branch writes a register that the previous
+ instruction sets, we can not swap. */
+ gpr_write = gpr_write_mask (ip);
+ if (gpr_write & prev_gpr_write)
+ return FALSE;
+
+ /* If the branch writes a register that the previous
+ instruction reads, we can not swap. */
+ prev_gpr_read = gpr_read_mask (&history[0]);
+ if (gpr_write & prev_gpr_read)
+ return FALSE;
+
+ /* If one instruction sets a condition code and the
+ other one uses a condition code, we can not swap. */
+ pinfo = ip->insn_mo->pinfo;
+ if ((pinfo & INSN_READ_COND_CODE)
+ && (prev_pinfo & INSN_WRITE_COND_CODE))
+ return FALSE;
+ if ((pinfo & INSN_WRITE_COND_CODE)
+ && (prev_pinfo & INSN_READ_COND_CODE))
+ return FALSE;
+
+ /* If the previous instruction uses the PC, we can not swap. */
+ if (mips_opts.mips16 && (prev_pinfo & MIPS16_INSN_READ_PC))
+ return FALSE;
+
+ return TRUE;
+}
+
+/* Decide how we should add IP to the instruction stream. */
-static int
-nops_for_insn (const struct mips_cl_insn *history,
- const struct mips_cl_insn *insn)
+static enum append_method
+get_append_method (struct mips_cl_insn *ip)
{
- int i, nops, tmp_nops;
+ unsigned long pinfo;
- nops = 0;
- for (i = 0; i < MAX_DELAY_NOPS; i++)
- if (!history[i].noreorder_p)
- {
- tmp_nops = insns_between (history + i, insn) - i;
- if (tmp_nops > nops)
- nops = tmp_nops;
- }
+ /* The relaxed version of a macro sequence must be inherently
+ hazard-free. */
+ if (mips_relax.sequence == 2)
+ return APPEND_ADD;
- if (mips_fix_vr4130)
- {
- tmp_nops = nops_for_vr4130 (history, insn);
- if (tmp_nops > nops)
- nops = tmp_nops;
- }
+ /* We must not dabble with instructions in a ".set norerorder" block. */
+ if (mips_opts.noreorder)
+ return APPEND_ADD;
- return nops;
-}
+ /* Otherwise, it's our responsibility to fill branch delay slots. */
+ pinfo = ip->insn_mo->pinfo;
+ if ((pinfo & INSN_UNCOND_BRANCH_DELAY)
+ || (pinfo & INSN_COND_BRANCH_DELAY))
+ {
+ if (can_swap_branch_p (ip))
+ return APPEND_SWAP;
-/* The variable arguments provide NUM_INSNS extra instructions that
- might be added to HISTORY. Return the largest number of nops that
- would be needed after the extended sequence. */
+ if (mips_opts.mips16
+ && ISA_SUPPORTS_MIPS16E
+ && (pinfo & INSN_UNCOND_BRANCH_DELAY)
+ && (pinfo & (MIPS16_INSN_READ_X | MIPS16_INSN_READ_31)))
+ return APPEND_ADD_COMPACT;
-static int
-nops_for_sequence (int num_insns, const struct mips_cl_insn *history, ...)
-{
- va_list args;
- struct mips_cl_insn buffer[MAX_NOPS];
- struct mips_cl_insn *cursor;
- int nops;
+ return APPEND_ADD_WITH_NOP;
+ }
- va_start (args, history);
- cursor = buffer + num_insns;
- memcpy (cursor, history, (MAX_NOPS - num_insns) * sizeof (*cursor));
- while (cursor > buffer)
- *--cursor = *va_arg (args, const struct mips_cl_insn *);
+ /* We don't bother trying to track the target of branches, so there's
+ nothing we can use to fill a branch-likely slot. */
+ if (pinfo & INSN_COND_BRANCH_LIKELY)
+ return APPEND_ADD_WITH_NOP;
- nops = nops_for_insn (buffer, NULL);
- va_end (args);
- return nops;
+ return APPEND_ADD;
}
-/* Like nops_for_insn, but if INSN is a branch, take into account the
- worst-case delay for the branch target. */
+/* IP is a MIPS16 instruction whose opcode we have just changed.
+ Point IP->insn_mo to the new opcode's definition. */
-static int
-nops_for_insn_or_target (const struct mips_cl_insn *history,
- const struct mips_cl_insn *insn)
+static void
+find_altered_mips16_opcode (struct mips_cl_insn *ip)
{
- int nops, tmp_nops;
+ const struct mips_opcode *mo, *end;
- nops = nops_for_insn (history, insn);
- if (insn->insn_mo->pinfo & (INSN_UNCOND_BRANCH_DELAY
- | INSN_COND_BRANCH_DELAY
- | INSN_COND_BRANCH_LIKELY))
- {
- tmp_nops = nops_for_sequence (2, history, insn, NOP_INSN);
- if (tmp_nops > nops)
- nops = tmp_nops;
- }
- else if (mips_opts.mips16 && (insn->insn_mo->pinfo & MIPS16_INSN_BRANCH))
- {
- tmp_nops = nops_for_sequence (1, history, insn);
- if (tmp_nops > nops)
- nops = tmp_nops;
- }
- return nops;
+ end = &mips16_opcodes[bfd_mips16_num_opcodes];
+ for (mo = ip->insn_mo; mo < end; mo++)
+ if ((ip->insn_opcode & mo->mask) == mo->match)
+ {
+ ip->insn_mo = mo;
+ return;
+ }
+ abort ();
}
/* Output an instruction. IP is the instruction information.
bfd_reloc_code_real_type *reloc_type)
{
unsigned long prev_pinfo, pinfo;
- relax_stateT prev_insn_frag_type = 0;
bfd_boolean relaxed_branch = FALSE;
- segment_info_type *si = seg_info (now_seg);
+ enum append_method method;
+
+ if (mips_fix_loongson2f)
+ fix_loongson2f (ip);
/* Mark instruction labels in mips16 mode. */
mips16_mark_labels ();
+ file_ase_mips16 |= mips_opts.mips16;
+
prev_pinfo = history[0].insn_mo->pinfo;
pinfo = ip->insn_mo->pinfo;
+ if (address_expr == NULL)
+ ip->complete_p = 1;
+ else if (*reloc_type <= BFD_RELOC_UNUSED
+ && address_expr->X_op == O_constant)
+ {
+ unsigned int tmp;
+
+ ip->complete_p = 1;
+ switch (*reloc_type)
+ {
+ case BFD_RELOC_32:
+ ip->insn_opcode |= address_expr->X_add_number;
+ break;
+
+ case BFD_RELOC_MIPS_HIGHEST:
+ tmp = (address_expr->X_add_number + 0x800080008000ull) >> 48;
+ ip->insn_opcode |= tmp & 0xffff;
+ break;
+
+ case BFD_RELOC_MIPS_HIGHER:
+ tmp = (address_expr->X_add_number + 0x80008000ull) >> 32;
+ ip->insn_opcode |= tmp & 0xffff;
+ break;
+
+ case BFD_RELOC_HI16_S:
+ tmp = (address_expr->X_add_number + 0x8000) >> 16;
+ ip->insn_opcode |= tmp & 0xffff;
+ break;
+
+ case BFD_RELOC_HI16:
+ ip->insn_opcode |= (address_expr->X_add_number >> 16) & 0xffff;
+ break;
+
+ case BFD_RELOC_UNUSED:
+ case BFD_RELOC_LO16:
+ case BFD_RELOC_MIPS_GOT_DISP:
+ ip->insn_opcode |= address_expr->X_add_number & 0xffff;
+ break;
+
+ case BFD_RELOC_MIPS_JMP:
+ if ((address_expr->X_add_number & 3) != 0)
+ as_bad (_("jump to misaligned address (0x%lx)"),
+ (unsigned long) address_expr->X_add_number);
+ ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0x3ffffff;
+ ip->complete_p = 0;
+ break;
+
+ case BFD_RELOC_MIPS16_JMP:
+ if ((address_expr->X_add_number & 3) != 0)
+ as_bad (_("jump to misaligned address (0x%lx)"),
+ (unsigned long) address_expr->X_add_number);
+ ip->insn_opcode |=
+ (((address_expr->X_add_number & 0x7c0000) << 3)
+ | ((address_expr->X_add_number & 0xf800000) >> 7)
+ | ((address_expr->X_add_number & 0x3fffc) >> 2));
+ ip->complete_p = 0;
+ break;
+
+ case BFD_RELOC_16_PCREL_S2:
+ if ((address_expr->X_add_number & 3) != 0)
+ as_bad (_("branch to misaligned address (0x%lx)"),
+ (unsigned long) address_expr->X_add_number);
+ if (!mips_relax_branch)
+ {
+ if ((address_expr->X_add_number + 0x20000) & ~0x3ffff)
+ as_bad (_("branch address range overflow (0x%lx)"),
+ (unsigned long) address_expr->X_add_number);
+ ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0xffff;
+ }
+ ip->complete_p = 0;
+ break;
+
+ default:
+ internalError ();
+ }
+ }
+
if (mips_relax.sequence != 2 && !mips_opts.noreorder)
{
/* There are a lot of optimizations we could do that we don't.
benefit hand written assembly code, and does not seem worth
it. */
int nops = (mips_optimize == 0
- ? nops_for_insn (history, NULL)
- : nops_for_insn_or_target (history, ip));
+ ? nops_for_insn (0, history, NULL)
+ : nops_for_insn_or_target (0, history, ip));
if (nops > 0)
{
fragS *old_frag;
}
else if (mips_relax.sequence != 2 && prev_nop_frag != NULL)
{
- /* Work out how many nops in prev_nop_frag are needed by IP. */
- int nops = nops_for_insn_or_target (history, ip);
- assert (nops <= prev_nop_frag_holds);
+ int nops;
+
+ /* Work out how many nops in prev_nop_frag are needed by IP,
+ ignoring hazards generated by the first prev_nop_frag_since
+ instructions. */
+ nops = nops_for_insn_or_target (prev_nop_frag_since, history, ip);
+ gas_assert (nops <= prev_nop_frag_holds);
/* Enforce NOPS as a minimum. */
if (nops > prev_nop_frag_required)
}
}
+ method = get_append_method (ip);
+
#ifdef OBJ_ELF
/* The value passed to dwarf2_emit_insn is the distance between
the beginning of the current instruction and the address that
- should be recorded in the debug tables. For MIPS16 debug info
- we want to use ISA-encoded addresses, so we pass -1 for an
- address higher by one than the current. */
- dwarf2_emit_insn (mips_opts.mips16 ? -1 : 0);
+ should be recorded in the debug tables. This is normally the
+ current address.
+
+ For MIPS16 debug info we want to use ISA-encoded addresses,
+ so we use -1 for an address higher by one than the current one.
+
+ If the instruction produced is a branch that we will swap with
+ the preceding instruction, then we add the displacement by which
+ the branch will be moved backwards. This is more appropriate
+ and for MIPS16 code also prevents a debugger from placing a
+ breakpoint in the middle of the branch (and corrupting code if
+ software breakpoints are used). */
+ dwarf2_emit_insn ((mips_opts.mips16 ? -1 : 0)
+ + (method == APPEND_SWAP ? insn_length (history) : 0));
#endif
- /* Record the frag type before frag_var. */
- if (history[0].frag)
- prev_insn_frag_type = history[0].frag->fr_type;
-
if (address_expr
&& *reloc_type == BFD_RELOC_16_PCREL_S2
&& (pinfo & INSN_UNCOND_BRANCH_DELAY || pinfo & INSN_COND_BRANCH_DELAY
out that the branch was out-of-range, we'll get an error. */
&& !mips_opts.warn_about_macros
&& (mips_opts.at || mips_pic == NO_PIC)
+ /* Don't relax BPOSGE32/64 as they have no complementing branches. */
+ && !(ip->insn_mo->membership & (INSN_DSP64 | INSN_DSP))
&& !mips_opts.mips16)
{
relaxed_branch = TRUE;
: (pinfo & INSN_COND_BRANCH_LIKELY) ? 1
: 0)), 4,
RELAX_BRANCH_ENCODE
- (pinfo & INSN_UNCOND_BRANCH_DELAY,
+ (AT,
+ pinfo & INSN_UNCOND_BRANCH_DELAY,
pinfo & INSN_COND_BRANCH_LIKELY,
pinfo & INSN_WRITE_GPR_31,
0),
else if (*reloc_type > BFD_RELOC_UNUSED)
{
/* We need to set up a variant frag. */
- assert (mips_opts.mips16 && address_expr != NULL);
+ gas_assert (mips_opts.mips16 && address_expr != NULL);
add_relaxed_insn (ip, 4, 0,
RELAX_MIPS16_ENCODE
(*reloc_type - BFD_RELOC_UNUSED,
add_fixed_insn (ip);
}
- if (address_expr != NULL && *reloc_type <= BFD_RELOC_UNUSED)
+ if (!ip->complete_p && *reloc_type < BFD_RELOC_UNUSED)
{
- if (address_expr->X_op == O_constant)
- {
- unsigned int tmp;
-
- switch (*reloc_type)
- {
- case BFD_RELOC_32:
- ip->insn_opcode |= address_expr->X_add_number;
- break;
-
- case BFD_RELOC_MIPS_HIGHEST:
- tmp = (address_expr->X_add_number + 0x800080008000ull) >> 48;
- ip->insn_opcode |= tmp & 0xffff;
- break;
-
- case BFD_RELOC_MIPS_HIGHER:
- tmp = (address_expr->X_add_number + 0x80008000ull) >> 32;
- ip->insn_opcode |= tmp & 0xffff;
- break;
-
- case BFD_RELOC_HI16_S:
- tmp = (address_expr->X_add_number + 0x8000) >> 16;
- ip->insn_opcode |= tmp & 0xffff;
- break;
-
- case BFD_RELOC_HI16:
- ip->insn_opcode |= (address_expr->X_add_number >> 16) & 0xffff;
- break;
-
- case BFD_RELOC_UNUSED:
- case BFD_RELOC_LO16:
- case BFD_RELOC_MIPS_GOT_DISP:
- ip->insn_opcode |= address_expr->X_add_number & 0xffff;
- break;
-
- case BFD_RELOC_MIPS_JMP:
- if ((address_expr->X_add_number & 3) != 0)
- as_bad (_("jump to misaligned address (0x%lx)"),
- (unsigned long) address_expr->X_add_number);
- ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0x3ffffff;
- break;
+ reloc_howto_type *howto;
+ int i;
- case BFD_RELOC_MIPS16_JMP:
- if ((address_expr->X_add_number & 3) != 0)
- as_bad (_("jump to misaligned address (0x%lx)"),
- (unsigned long) address_expr->X_add_number);
- ip->insn_opcode |=
- (((address_expr->X_add_number & 0x7c0000) << 3)
- | ((address_expr->X_add_number & 0xf800000) >> 7)
- | ((address_expr->X_add_number & 0x3fffc) >> 2));
- break;
+ /* In a compound relocation, it is the final (outermost)
+ operator that determines the relocated field. */
+ for (i = 1; i < 3; i++)
+ if (reloc_type[i] == BFD_RELOC_UNUSED)
+ break;
- case BFD_RELOC_16_PCREL_S2:
- if ((address_expr->X_add_number & 3) != 0)
- as_bad (_("branch to misaligned address (0x%lx)"),
- (unsigned long) address_expr->X_add_number);
- if (mips_relax_branch)
- goto need_reloc;
- if ((address_expr->X_add_number + 0x20000) & ~0x3ffff)
- as_bad (_("branch address range overflow (0x%lx)"),
- (unsigned long) address_expr->X_add_number);
- ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0xffff;
- break;
+ howto = bfd_reloc_type_lookup (stdoutput, reloc_type[i - 1]);
+ if (howto == NULL)
+ {
+ /* To reproduce this failure try assembling gas/testsuites/
+ gas/mips/mips16-intermix.s with a mips-ecoff targeted
+ assembler. */
+ as_bad (_("Unsupported MIPS relocation number %d"), reloc_type[i - 1]);
+ howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_16);
+ }
+
+ ip->fixp[0] = fix_new_exp (ip->frag, ip->where,
+ bfd_get_reloc_size (howto),
+ address_expr,
+ reloc_type[0] == BFD_RELOC_16_PCREL_S2,
+ reloc_type[0]);
+
+ /* Tag symbols that have a R_MIPS16_26 relocation against them. */
+ if (reloc_type[0] == BFD_RELOC_MIPS16_JMP
+ && ip->fixp[0]->fx_addsy)
+ *symbol_get_tc (ip->fixp[0]->fx_addsy) = 1;
+
+ /* These relocations can have an addend that won't fit in
+ 4 octets for 64bit assembly. */
+ if (HAVE_64BIT_GPRS
+ && ! howto->partial_inplace
+ && (reloc_type[0] == BFD_RELOC_16
+ || reloc_type[0] == BFD_RELOC_32
+ || reloc_type[0] == BFD_RELOC_MIPS_JMP
+ || reloc_type[0] == BFD_RELOC_GPREL16
+ || reloc_type[0] == BFD_RELOC_MIPS_LITERAL
+ || reloc_type[0] == BFD_RELOC_GPREL32
+ || reloc_type[0] == BFD_RELOC_64
+ || reloc_type[0] == BFD_RELOC_CTOR
+ || reloc_type[0] == BFD_RELOC_MIPS_SUB
+ || reloc_type[0] == BFD_RELOC_MIPS_HIGHEST
+ || reloc_type[0] == BFD_RELOC_MIPS_HIGHER
+ || reloc_type[0] == BFD_RELOC_MIPS_SCN_DISP
+ || reloc_type[0] == BFD_RELOC_MIPS_REL16
+ || reloc_type[0] == BFD_RELOC_MIPS_RELGOT
+ || reloc_type[0] == BFD_RELOC_MIPS16_GPREL
+ || hi16_reloc_p (reloc_type[0])
+ || lo16_reloc_p (reloc_type[0])))
+ ip->fixp[0]->fx_no_overflow = 1;
- default:
- internalError ();
- }
+ if (mips_relax.sequence)
+ {
+ if (mips_relax.first_fixup == 0)
+ mips_relax.first_fixup = ip->fixp[0];
}
- else if (*reloc_type < BFD_RELOC_UNUSED)
- need_reloc:
+ else if (reloc_needs_lo_p (*reloc_type))
{
- reloc_howto_type *howto;
- int i;
-
- /* In a compound relocation, it is the final (outermost)
- operator that determines the relocated field. */
- for (i = 1; i < 3; i++)
- if (reloc_type[i] == BFD_RELOC_UNUSED)
- break;
-
- howto = bfd_reloc_type_lookup (stdoutput, reloc_type[i - 1]);
- ip->fixp[0] = fix_new_exp (ip->frag, ip->where,
- bfd_get_reloc_size (howto),
- address_expr,
- reloc_type[0] == BFD_RELOC_16_PCREL_S2,
- reloc_type[0]);
-
- /* Tag symbols that have a R_MIPS16_26 relocation against them. */
- if (reloc_type[0] == BFD_RELOC_MIPS16_JMP
- && ip->fixp[0]->fx_addsy)
- *symbol_get_tc (ip->fixp[0]->fx_addsy) = 1;
-
- /* These relocations can have an addend that won't fit in
- 4 octets for 64bit assembly. */
- if (HAVE_64BIT_GPRS
- && ! howto->partial_inplace
- && (reloc_type[0] == BFD_RELOC_16
- || reloc_type[0] == BFD_RELOC_32
- || reloc_type[0] == BFD_RELOC_MIPS_JMP
- || reloc_type[0] == BFD_RELOC_HI16_S
- || reloc_type[0] == BFD_RELOC_LO16
- || reloc_type[0] == BFD_RELOC_GPREL16
- || reloc_type[0] == BFD_RELOC_MIPS_LITERAL
- || reloc_type[0] == BFD_RELOC_GPREL32
- || reloc_type[0] == BFD_RELOC_64
- || reloc_type[0] == BFD_RELOC_CTOR
- || reloc_type[0] == BFD_RELOC_MIPS_SUB
- || reloc_type[0] == BFD_RELOC_MIPS_HIGHEST
- || reloc_type[0] == BFD_RELOC_MIPS_HIGHER
- || reloc_type[0] == BFD_RELOC_MIPS_SCN_DISP
- || reloc_type[0] == BFD_RELOC_MIPS_REL16
- || reloc_type[0] == BFD_RELOC_MIPS_RELGOT
- || reloc_type[0] == BFD_RELOC_MIPS16_GPREL
- || reloc_type[0] == BFD_RELOC_MIPS16_HI16_S
- || reloc_type[0] == BFD_RELOC_MIPS16_LO16))
- ip->fixp[0]->fx_no_overflow = 1;
+ struct mips_hi_fixup *hi_fixup;
- if (mips_relax.sequence)
- {
- if (mips_relax.first_fixup == 0)
- mips_relax.first_fixup = ip->fixp[0];
- }
- else if (reloc_needs_lo_p (*reloc_type))
+ /* Reuse the last entry if it already has a matching %lo. */
+ hi_fixup = mips_hi_fixup_list;
+ if (hi_fixup == 0
+ || !fixup_has_matching_lo_p (hi_fixup->fixp))
{
- struct mips_hi_fixup *hi_fixup;
-
- /* Reuse the last entry if it already has a matching %lo. */
- hi_fixup = mips_hi_fixup_list;
- if (hi_fixup == 0
- || !fixup_has_matching_lo_p (hi_fixup->fixp))
- {
- hi_fixup = ((struct mips_hi_fixup *)
- xmalloc (sizeof (struct mips_hi_fixup)));
- hi_fixup->next = mips_hi_fixup_list;
- mips_hi_fixup_list = hi_fixup;
- }
- hi_fixup->fixp = ip->fixp[0];
- hi_fixup->seg = now_seg;
+ hi_fixup = ((struct mips_hi_fixup *)
+ xmalloc (sizeof (struct mips_hi_fixup)));
+ hi_fixup->next = mips_hi_fixup_list;
+ mips_hi_fixup_list = hi_fixup;
}
+ hi_fixup->fixp = ip->fixp[0];
+ hi_fixup->seg = now_seg;
+ }
- /* Add fixups for the second and third relocations, if given.
- Note that the ABI allows the second relocation to be
- against RSS_UNDEF, RSS_GP, RSS_GP0 or RSS_LOC. At the
- moment we only use RSS_UNDEF, but we could add support
- for the others if it ever becomes necessary. */
- for (i = 1; i < 3; i++)
- if (reloc_type[i] != BFD_RELOC_UNUSED)
- {
- ip->fixp[i] = fix_new (ip->frag, ip->where,
- ip->fixp[0]->fx_size, NULL, 0,
- FALSE, reloc_type[i]);
+ /* Add fixups for the second and third relocations, if given.
+ Note that the ABI allows the second relocation to be
+ against RSS_UNDEF, RSS_GP, RSS_GP0 or RSS_LOC. At the
+ moment we only use RSS_UNDEF, but we could add support
+ for the others if it ever becomes necessary. */
+ for (i = 1; i < 3; i++)
+ if (reloc_type[i] != BFD_RELOC_UNUSED)
+ {
+ ip->fixp[i] = fix_new (ip->frag, ip->where,
+ ip->fixp[0]->fx_size, NULL, 0,
+ FALSE, reloc_type[i]);
- /* Use fx_tcbit to mark compound relocs. */
- ip->fixp[0]->fx_tcbit = 1;
- ip->fixp[i]->fx_tcbit = 1;
- }
- }
+ /* Use fx_tcbit to mark compound relocs. */
+ ip->fixp[0]->fx_tcbit = 1;
+ ip->fixp[i]->fx_tcbit = 1;
+ }
}
install_insn (ip);
/* Update the register mask information. */
- if (! mips_opts.mips16)
- {
- if (pinfo & INSN_WRITE_GPR_D)
- mips_gprmask |= 1 << EXTRACT_OPERAND (RD, *ip);
- if ((pinfo & (INSN_WRITE_GPR_T | INSN_READ_GPR_T)) != 0)
- mips_gprmask |= 1 << EXTRACT_OPERAND (RT, *ip);
- if (pinfo & INSN_READ_GPR_S)
- mips_gprmask |= 1 << EXTRACT_OPERAND (RS, *ip);
- if (pinfo & INSN_WRITE_GPR_31)
- mips_gprmask |= 1 << RA;
- if (pinfo & INSN_WRITE_FPR_D)
- mips_cprmask[1] |= 1 << EXTRACT_OPERAND (FD, *ip);
- if ((pinfo & (INSN_WRITE_FPR_S | INSN_READ_FPR_S)) != 0)
- mips_cprmask[1] |= 1 << EXTRACT_OPERAND (FS, *ip);
- if ((pinfo & (INSN_WRITE_FPR_T | INSN_READ_FPR_T)) != 0)
- mips_cprmask[1] |= 1 << EXTRACT_OPERAND (FT, *ip);
- if ((pinfo & INSN_READ_FPR_R) != 0)
- mips_cprmask[1] |= 1 << EXTRACT_OPERAND (FR, *ip);
- if (pinfo & INSN_COP)
- {
- /* We don't keep enough information to sort these cases out.
- The itbl support does keep this information however, although
- we currently don't support itbl fprmats as part of the cop
- instruction. May want to add this support in the future. */
- }
- /* Never set the bit for $0, which is always zero. */
- mips_gprmask &= ~1 << 0;
- }
- else
- {
- if (pinfo & (MIPS16_INSN_WRITE_X | MIPS16_INSN_READ_X))
- mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (RX, *ip);
- if (pinfo & (MIPS16_INSN_WRITE_Y | MIPS16_INSN_READ_Y))
- mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (RY, *ip);
- if (pinfo & MIPS16_INSN_WRITE_Z)
- mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (RZ, *ip);
- if (pinfo & (MIPS16_INSN_WRITE_T | MIPS16_INSN_READ_T))
- mips_gprmask |= 1 << TREG;
- if (pinfo & (MIPS16_INSN_WRITE_SP | MIPS16_INSN_READ_SP))
- mips_gprmask |= 1 << SP;
- if (pinfo & (MIPS16_INSN_WRITE_31 | MIPS16_INSN_READ_31))
- mips_gprmask |= 1 << RA;
- if (pinfo & MIPS16_INSN_WRITE_GPR_Y)
- mips_gprmask |= 1 << MIPS16OP_EXTRACT_REG32R (ip->insn_opcode);
- if (pinfo & MIPS16_INSN_READ_Z)
- mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (MOVE32Z, *ip);
- if (pinfo & MIPS16_INSN_READ_GPR_X)
- mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (REGR32, *ip);
- }
+ mips_gprmask |= gpr_read_mask (ip) | gpr_write_mask (ip);
+ mips_cprmask[1] |= fpr_read_mask (ip) | fpr_write_mask (ip);
- if (mips_relax.sequence != 2 && !mips_opts.noreorder)
+ switch (method)
{
- /* Filling the branch delay slot is more complex. We try to
- switch the branch with the previous instruction, which we can
- do if the previous instruction does not set up a condition
- that the branch tests and if the branch is not itself the
- target of any branch. */
- if ((pinfo & INSN_UNCOND_BRANCH_DELAY)
- || (pinfo & INSN_COND_BRANCH_DELAY))
- {
- if (mips_optimize < 2
- /* If we have seen .set volatile or .set nomove, don't
- optimize. */
- || mips_opts.nomove != 0
- /* We can't swap if the previous instruction's position
- is fixed. */
- || history[0].fixed_p
- /* If the previous previous insn was in a .set
- noreorder, we can't swap. Actually, the MIPS
- assembler will swap in this situation. However, gcc
- configured -with-gnu-as will generate code like
- .set noreorder
- lw $4,XXX
- .set reorder
- INSN
- bne $4,$0,foo
- in which we can not swap the bne and INSN. If gcc is
- not configured -with-gnu-as, it does not output the
- .set pseudo-ops. */
- || history[1].noreorder_p
- /* If the branch is itself the target of a branch, we
- can not swap. We cheat on this; all we check for is
- whether there is a label on this instruction. If
- there are any branches to anything other than a
- label, users must use .set noreorder. */
- || si->label_list != NULL
- /* If the previous instruction is in a variant frag
- other than this branch's one, we cannot do the swap.
- This does not apply to the mips16, which uses variant
- frags for different purposes. */
- || (! mips_opts.mips16
- && prev_insn_frag_type == rs_machine_dependent)
- /* Check for conflicts between the branch and the instructions
- before the candidate delay slot. */
- || nops_for_insn (history + 1, ip) > 0
- /* Check for conflicts between the swapped sequence and the
- target of the branch. */
- || nops_for_sequence (2, history + 1, ip, history) > 0
- /* We do not swap with a trap instruction, since it
- complicates trap handlers to have the trap
- instruction be in a delay slot. */
- || (prev_pinfo & INSN_TRAP)
- /* If the branch reads a register that the previous
- instruction sets, we can not swap. */
- || (! mips_opts.mips16
- && (prev_pinfo & INSN_WRITE_GPR_T)
- && insn_uses_reg (ip, EXTRACT_OPERAND (RT, history[0]),
- MIPS_GR_REG))
- || (! mips_opts.mips16
- && (prev_pinfo & INSN_WRITE_GPR_D)
- && insn_uses_reg (ip, EXTRACT_OPERAND (RD, history[0]),
- MIPS_GR_REG))
- || (mips_opts.mips16
- && (((prev_pinfo & MIPS16_INSN_WRITE_X)
- && (insn_uses_reg
- (ip, MIPS16_EXTRACT_OPERAND (RX, history[0]),
- MIPS16_REG)))
- || ((prev_pinfo & MIPS16_INSN_WRITE_Y)
- && (insn_uses_reg
- (ip, MIPS16_EXTRACT_OPERAND (RY, history[0]),
- MIPS16_REG)))
- || ((prev_pinfo & MIPS16_INSN_WRITE_Z)
- && (insn_uses_reg
- (ip, MIPS16_EXTRACT_OPERAND (RZ, history[0]),
- MIPS16_REG)))
- || ((prev_pinfo & MIPS16_INSN_WRITE_T)
- && insn_uses_reg (ip, TREG, MIPS_GR_REG))
- || ((prev_pinfo & MIPS16_INSN_WRITE_31)
- && insn_uses_reg (ip, RA, MIPS_GR_REG))
- || ((prev_pinfo & MIPS16_INSN_WRITE_GPR_Y)
- && insn_uses_reg (ip,
- MIPS16OP_EXTRACT_REG32R
- (history[0].insn_opcode),
- MIPS_GR_REG))))
- /* If the branch writes a register that the previous
- instruction sets, we can not swap (we know that
- branches write only to RD or to $31). */
- || (! mips_opts.mips16
- && (prev_pinfo & INSN_WRITE_GPR_T)
- && (((pinfo & INSN_WRITE_GPR_D)
- && (EXTRACT_OPERAND (RT, history[0])
- == EXTRACT_OPERAND (RD, *ip)))
- || ((pinfo & INSN_WRITE_GPR_31)
- && EXTRACT_OPERAND (RT, history[0]) == RA)))
- || (! mips_opts.mips16
- && (prev_pinfo & INSN_WRITE_GPR_D)
- && (((pinfo & INSN_WRITE_GPR_D)
- && (EXTRACT_OPERAND (RD, history[0])
- == EXTRACT_OPERAND (RD, *ip)))
- || ((pinfo & INSN_WRITE_GPR_31)
- && EXTRACT_OPERAND (RD, history[0]) == RA)))
- || (mips_opts.mips16
- && (pinfo & MIPS16_INSN_WRITE_31)
- && ((prev_pinfo & MIPS16_INSN_WRITE_31)
- || ((prev_pinfo & MIPS16_INSN_WRITE_GPR_Y)
- && (MIPS16OP_EXTRACT_REG32R (history[0].insn_opcode)
- == RA))))
- /* If the branch writes a register that the previous
- instruction reads, we can not swap (we know that
- branches only write to RD or to $31). */
- || (! mips_opts.mips16
- && (pinfo & INSN_WRITE_GPR_D)
- && insn_uses_reg (&history[0],
- EXTRACT_OPERAND (RD, *ip),
- MIPS_GR_REG))
- || (! mips_opts.mips16
- && (pinfo & INSN_WRITE_GPR_31)
- && insn_uses_reg (&history[0], RA, MIPS_GR_REG))
- || (mips_opts.mips16
- && (pinfo & MIPS16_INSN_WRITE_31)
- && insn_uses_reg (&history[0], RA, MIPS_GR_REG))
- /* If one instruction sets a condition code and the
- other one uses a condition code, we can not swap. */
- || ((pinfo & INSN_READ_COND_CODE)
- && (prev_pinfo & INSN_WRITE_COND_CODE))
- || ((pinfo & INSN_WRITE_COND_CODE)
- && (prev_pinfo & INSN_READ_COND_CODE))
- /* If the previous instruction uses the PC, we can not
- swap. */
- || (mips_opts.mips16
- && (prev_pinfo & MIPS16_INSN_READ_PC))
- /* If the previous instruction had a fixup in mips16
- mode, we can not swap. This normally means that the
- previous instruction was a 4 byte branch anyhow. */
- || (mips_opts.mips16 && history[0].fixp[0])
- /* If the previous instruction is a sync, sync.l, or
- sync.p, we can not swap. */
- || (prev_pinfo & INSN_SYNC))
- {
- if (mips_opts.mips16
- && (pinfo & INSN_UNCOND_BRANCH_DELAY)
- && (pinfo & (MIPS16_INSN_READ_X | MIPS16_INSN_READ_31))
- && ISA_SUPPORTS_MIPS16E)
- {
- /* Convert MIPS16 jr/jalr into a "compact" jump. */
- ip->insn_opcode |= 0x0080;
- install_insn (ip);
- insert_into_history (0, 1, ip);
- }
- else
- {
- /* We could do even better for unconditional branches to
- portions of this object file; we could pick up the
- instruction at the destination, put it in the delay
- slot, and bump the destination address. */
- insert_into_history (0, 1, ip);
- emit_nop ();
- }
-
- if (mips_relax.sequence)
- mips_relax.sizes[mips_relax.sequence - 1] += 4;
- }
- else
- {
- /* It looks like we can actually do the swap. */
- struct mips_cl_insn delay = history[0];
- if (mips_opts.mips16)
- {
- know (delay.frag == ip->frag);
- move_insn (ip, delay.frag, delay.where);
- move_insn (&delay, ip->frag, ip->where + insn_length (ip));
- }
- else if (relaxed_branch)
- {
- /* Add the delay slot instruction to the end of the
- current frag and shrink the fixed part of the
- original frag. If the branch occupies the tail of
- the latter, move it backwards to cover the gap. */
- delay.frag->fr_fix -= 4;
- if (delay.frag == ip->frag)
- move_insn (ip, ip->frag, ip->where - 4);
- add_fixed_insn (&delay);
- }
- else
- {
- move_insn (&delay, ip->frag, ip->where);
- move_insn (ip, history[0].frag, history[0].where);
- }
- history[0] = *ip;
- delay.fixed_p = 1;
- insert_into_history (0, 1, &delay);
- }
+ case APPEND_ADD:
+ insert_into_history (0, 1, ip);
+ break;
- /* If that was an unconditional branch, forget the previous
- insn information. */
- if (pinfo & INSN_UNCOND_BRANCH_DELAY)
- mips_no_prev_insn ();
- }
- else if (pinfo & INSN_COND_BRANCH_LIKELY)
- {
- /* We don't yet optimize a branch likely. What we should do
- is look at the target, copy the instruction found there
- into the delay slot, and increment the branch to jump to
- the next instruction. */
- insert_into_history (0, 1, ip);
- emit_nop ();
- }
- else
- insert_into_history (0, 1, ip);
+ case APPEND_ADD_WITH_NOP:
+ insert_into_history (0, 1, ip);
+ emit_nop ();
+ if (mips_relax.sequence)
+ mips_relax.sizes[mips_relax.sequence - 1] += 4;
+ break;
+
+ case APPEND_ADD_COMPACT:
+ /* Convert MIPS16 jr/jalr into a "compact" jump. */
+ gas_assert (mips_opts.mips16);
+ ip->insn_opcode |= 0x0080;
+ find_altered_mips16_opcode (ip);
+ install_insn (ip);
+ insert_into_history (0, 1, ip);
+ break;
+
+ case APPEND_SWAP:
+ {
+ struct mips_cl_insn delay = history[0];
+ if (mips_opts.mips16)
+ {
+ know (delay.frag == ip->frag);
+ move_insn (ip, delay.frag, delay.where);
+ move_insn (&delay, ip->frag, ip->where + insn_length (ip));
+ }
+ else if (relaxed_branch)
+ {
+ /* Add the delay slot instruction to the end of the
+ current frag and shrink the fixed part of the
+ original frag. If the branch occupies the tail of
+ the latter, move it backwards to cover the gap. */
+ delay.frag->fr_fix -= 4;
+ if (delay.frag == ip->frag)
+ move_insn (ip, ip->frag, ip->where - 4);
+ add_fixed_insn (&delay);
+ }
+ else
+ {
+ move_insn (&delay, ip->frag, ip->where);
+ move_insn (ip, history[0].frag, history[0].where);
+ }
+ history[0] = *ip;
+ delay.fixed_p = 1;
+ insert_into_history (0, 1, &delay);
+ }
+ break;
}
- else
- insert_into_history (0, 1, ip);
+
+ /* If we have just completed an unconditional branch, clear the history. */
+ if ((history[1].insn_mo->pinfo & INSN_UNCOND_BRANCH_DELAY)
+ || (mips_opts.mips16
+ && (history[0].insn_mo->pinfo & MIPS16_INSN_UNCOND_BRANCH)))
+ mips_no_prev_insn ();
/* We just output an insn, so the next one doesn't have a label. */
mips_clear_insn_labels ();
{
if (! mips_opts.noreorder)
{
- int nops = nops_for_insn (history, NULL);
+ int nops = nops_for_insn (0, history, NULL);
if (nops > 0)
{
while (nops-- > 0)
/* Insert any nops that might be needed between the .set noreorder
block and the previous instructions. We will later remove any
nops that turn out not to be needed. */
- nops = nops_for_insn (history, NULL);
+ nops = nops_for_insn (0, history, NULL);
if (nops > 0)
{
if (mips_optimize != 0)
static void
end_noreorder (void)
{
+
mips_opts.noreorder--;
if (mips_opts.noreorder == 0 && prev_nop_frag != NULL)
{
warning now. */
const char *msg = macro_warning (subtype);
if (msg != 0)
- as_warn (msg);
+ as_warn ("%s", msg);
}
else
{
if (mips_opts.mips16)
{
- mips16_macro_build (ep, name, fmt, args);
+ mips16_macro_build (ep, name, fmt, &args);
va_end (args);
return;
}
r[1] = BFD_RELOC_UNUSED;
r[2] = BFD_RELOC_UNUSED;
mo = (struct mips_opcode *) hash_find (op_hash, name);
- assert (mo);
- assert (strcmp (name, mo->name) == 0);
+ gas_assert (mo);
+ gas_assert (strcmp (name, mo->name) == 0);
while (1)
{
macros will never generate MDMX, MIPS-3D, or MT instructions. */
if (strcmp (fmt, mo->args) == 0
&& mo->pinfo != INSN_MACRO
- && is_opcode_valid (mo, TRUE))
+ && is_opcode_valid (mo))
break;
++mo;
- assert (mo->name);
- assert (strcmp (name, mo->name) == 0);
+ gas_assert (mo->name);
+ gas_assert (strcmp (name, mo->name) == 0);
}
create_insn (&insn, mo);
INSERT_OPERAND (EXTMSBD, insn, va_arg (args, int));
continue;
+ case 'Q':
+ INSERT_OPERAND (SEQI, insn, va_arg (args, int));
+ continue;
+
default:
internalError ();
}
case 'i':
case 'j':
+ macro_read_relocs (&args, r);
+ gas_assert (*r == BFD_RELOC_GPREL16
+ || *r == BFD_RELOC_MIPS_HIGHER
+ || *r == BFD_RELOC_HI16_S
+ || *r == BFD_RELOC_LO16
+ || *r == BFD_RELOC_MIPS_GOT_OFST);
+ continue;
+
case 'o':
macro_read_relocs (&args, r);
- assert (*r == BFD_RELOC_GPREL16
- || *r == BFD_RELOC_MIPS_LITERAL
- || *r == BFD_RELOC_MIPS_HIGHER
- || *r == BFD_RELOC_HI16_S
- || *r == BFD_RELOC_LO16
- || *r == BFD_RELOC_MIPS_GOT16
- || *r == BFD_RELOC_MIPS_CALL16
- || *r == BFD_RELOC_MIPS_GOT_DISP
- || *r == BFD_RELOC_MIPS_GOT_PAGE
- || *r == BFD_RELOC_MIPS_GOT_OFST
- || *r == BFD_RELOC_MIPS_GOT_LO16
- || *r == BFD_RELOC_MIPS_CALL_LO16);
continue;
case 'u':
macro_read_relocs (&args, r);
- assert (ep != NULL
- && (ep->X_op == O_constant
- || (ep->X_op == O_symbol
- && (*r == BFD_RELOC_MIPS_HIGHEST
- || *r == BFD_RELOC_HI16_S
- || *r == BFD_RELOC_HI16
- || *r == BFD_RELOC_GPREL16
- || *r == BFD_RELOC_MIPS_GOT_HI16
- || *r == BFD_RELOC_MIPS_CALL_HI16))));
+ gas_assert (ep != NULL
+ && (ep->X_op == O_constant
+ || (ep->X_op == O_symbol
+ && (*r == BFD_RELOC_MIPS_HIGHEST
+ || *r == BFD_RELOC_HI16_S
+ || *r == BFD_RELOC_HI16
+ || *r == BFD_RELOC_GPREL16
+ || *r == BFD_RELOC_MIPS_GOT_HI16
+ || *r == BFD_RELOC_MIPS_CALL_HI16))));
continue;
case 'p':
- assert (ep != NULL);
+ gas_assert (ep != NULL);
/*
* This allows macro() to pass an immediate expression for
continue;
case 'a':
- assert (ep != NULL);
+ gas_assert (ep != NULL);
*r = BFD_RELOC_MIPS_JMP;
continue;
break;
}
va_end (args);
- assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
+ gas_assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
append_insn (&insn, ep, r);
}
static void
mips16_macro_build (expressionS *ep, const char *name, const char *fmt,
- va_list args)
+ va_list *args)
{
struct mips_opcode *mo;
struct mips_cl_insn insn;
= {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
mo = (struct mips_opcode *) hash_find (mips16_op_hash, name);
- assert (mo);
- assert (strcmp (name, mo->name) == 0);
+ gas_assert (mo);
+ gas_assert (strcmp (name, mo->name) == 0);
while (strcmp (fmt, mo->args) != 0 || mo->pinfo == INSN_MACRO)
{
++mo;
- assert (mo->name);
- assert (strcmp (name, mo->name) == 0);
+ gas_assert (mo->name);
+ gas_assert (strcmp (name, mo->name) == 0);
}
create_insn (&insn, mo);
case 'y':
case 'w':
- MIPS16_INSERT_OPERAND (RY, insn, va_arg (args, int));
+ MIPS16_INSERT_OPERAND (RY, insn, va_arg (*args, int));
continue;
case 'x':
case 'v':
- MIPS16_INSERT_OPERAND (RX, insn, va_arg (args, int));
+ MIPS16_INSERT_OPERAND (RX, insn, va_arg (*args, int));
continue;
case 'z':
- MIPS16_INSERT_OPERAND (RZ, insn, va_arg (args, int));
+ MIPS16_INSERT_OPERAND (RZ, insn, va_arg (*args, int));
continue;
case 'Z':
- MIPS16_INSERT_OPERAND (MOVE32Z, insn, va_arg (args, int));
+ MIPS16_INSERT_OPERAND (MOVE32Z, insn, va_arg (*args, int));
continue;
case '0':
continue;
case 'X':
- MIPS16_INSERT_OPERAND (REGR32, insn, va_arg (args, int));
+ MIPS16_INSERT_OPERAND (REGR32, insn, va_arg (*args, int));
continue;
case 'Y':
{
int regno;
- regno = va_arg (args, int);
+ regno = va_arg (*args, int);
regno = ((regno & 7) << 2) | ((regno & 0x18) >> 3);
MIPS16_INSERT_OPERAND (REG32R, insn, regno);
}
case 'p':
case 'q':
{
- assert (ep != NULL);
+ gas_assert (ep != NULL);
if (ep->X_op != O_constant)
*r = (int) BFD_RELOC_UNUSED + c;
continue;
case '6':
- MIPS16_INSERT_OPERAND (IMM6, insn, va_arg (args, int));
+ MIPS16_INSERT_OPERAND (IMM6, insn, va_arg (*args, int));
continue;
}
break;
}
- assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
+ gas_assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
append_insn (&insn, ep, r);
}
{
char *f = NULL;
- if (HAVE_NEWABI)
+ if (MIPS_JALR_HINT_P (ep))
{
frag_grow (8);
f = frag_more (0);
}
macro_build (NULL, "jalr", "d,s", RA, PIC_CALL_REG);
- if (HAVE_NEWABI)
+ if (MIPS_JALR_HINT_P (ep))
fix_new_exp (frag_now, f - frag_now->fr_literal,
4, ep, FALSE, BFD_RELOC_MIPS_JALR);
}
const char *name = "lui";
const char *fmt = "t,u";
- assert (! mips_opts.mips16);
+ gas_assert (! mips_opts.mips16);
high_expr = *ep;
}
else
{
- assert (ep->X_op == O_symbol);
+ gas_assert (ep->X_op == O_symbol);
/* _gp_disp is a special case, used from s_cpload.
__gnu_local_gp is used if mips_no_shared. */
- assert (mips_pic == NO_PIC
+ gas_assert (mips_pic == NO_PIC
|| (! HAVE_NEWABI
&& strcmp (S_GET_NAME (ep->X_add_symbol), "_gp_disp") == 0)
|| (! mips_in_shared
}
mo = hash_find (op_hash, name);
- assert (strcmp (name, mo->name) == 0);
- assert (strcmp (fmt, mo->args) == 0);
+ gas_assert (strcmp (name, mo->name) == 0);
+ gas_assert (strcmp (fmt, mo->args) == 0);
create_insn (&insn, mo);
insn.insn_opcode = insn.insn_mo->match;
macro_build_ldst_constoffset (expressionS *ep, const char *op,
int treg, int breg, int dbl)
{
- assert (ep->X_op == O_constant);
+ gas_assert (ep->X_op == O_constant);
/* Sign-extending 32-bit constants makes their handling easier. */
if (!dbl)
if (ep->X_op != O_big)
{
- assert (ep->X_op == O_constant);
+ gas_assert (ep->X_op == O_constant);
/* Sign-extending 32-bit constants makes their handling easier. */
if (!dbl)
}
else
{
- assert (ep->X_add_number > 2);
+ gas_assert (ep->X_add_number > 2);
if (ep->X_add_number == 3)
generic_bignum[3] = 0;
else if (ep->X_add_number > 4)
bfd_reloc_code_real_type r;
int hold_mips_optimize;
- assert (! mips_opts.mips16);
+ gas_assert (! mips_opts.mips16);
- treg = (ip->insn_opcode >> 16) & 0x1f;
- dreg = (ip->insn_opcode >> 11) & 0x1f;
- sreg = breg = (ip->insn_opcode >> 21) & 0x1f;
+ treg = EXTRACT_OPERAND (RT, *ip);
+ dreg = EXTRACT_OPERAND (RD, *ip);
+ sreg = breg = EXTRACT_OPERAND (RS, *ip);
mask = ip->insn_mo->mask;
expr1.X_op = O_constant;
expr1.X_add_number = 8;
macro_build (&expr1, "bgez", "s,p", sreg);
if (dreg == sreg)
- macro_build (NULL, "nop", "", 0);
+ macro_build (NULL, "nop", "");
else
move_register (dreg, sreg);
macro_build (NULL, dbl ? "dsub" : "sub", "d,v,t", dreg, 0, sreg);
break;
default:
macro_build (NULL, "balign", "t,s,2", treg, sreg,
- (int)imm_expr.X_add_number);
+ (int) imm_expr.X_add_number);
break;
}
break;
beq_i:
if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
{
- macro_build (&offset_expr, s, "s,t,p", sreg, 0);
+ macro_build (&offset_expr, s, "s,t,p", sreg, ZERO);
break;
}
used_at = 1;
}
used_at = 1;
macro_build (NULL, "slt", "d,v,t", AT, sreg, treg);
- macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
+ macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, ZERO);
break;
case M_BGTL_I:
likely = 1;
case M_BGT_I:
- /* check for > max integer */
+ /* Check for > max integer. */
maxnum = 0x7fffffff;
if (HAVE_64BIT_GPRS && sizeof (maxnum) > 4)
{
&& (HAVE_32BIT_GPRS || sizeof (maxnum) > 4))
{
do_false:
- /* result is always false */
+ /* Result is always false. */
if (! likely)
- macro_build (NULL, "nop", "", 0);
+ macro_build (NULL, "nop", "");
else
- macro_build (&offset_expr, "bnel", "s,t,p", 0, 0);
+ macro_build (&offset_expr, "bnel", "s,t,p", ZERO, ZERO);
break;
}
if (imm_expr.X_op != O_constant)
}
used_at = 1;
set_at (sreg, 0);
- macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
+ macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, ZERO);
break;
case M_BGEUL:
if (sreg == 0)
{
macro_build (&offset_expr, likely ? "beql" : "beq",
- "s,t,p", 0, treg);
+ "s,t,p", ZERO, treg);
break;
}
used_at = 1;
macro_build (NULL, "sltu", "d,v,t", AT, sreg, treg);
- macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
+ macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, ZERO);
break;
case M_BGTUL_I:
if (sreg == 0
|| (HAVE_32BIT_GPRS
&& imm_expr.X_op == O_constant
- && imm_expr.X_add_number == (offsetT) 0xffffffff))
+ && imm_expr.X_add_number == -1))
goto do_false;
if (imm_expr.X_op != O_constant)
as_bad (_("Unsupported large constant"));
if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
{
macro_build (&offset_expr, likely ? "bnel" : "bne",
- "s,t,p", sreg, 0);
+ "s,t,p", sreg, ZERO);
break;
}
used_at = 1;
set_at (sreg, 1);
- macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
+ macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, ZERO);
break;
case M_BGTL:
}
used_at = 1;
macro_build (NULL, "slt", "d,v,t", AT, treg, sreg);
- macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
+ macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, ZERO);
break;
case M_BGTUL:
if (treg == 0)
{
macro_build (&offset_expr, likely ? "bnel" : "bne",
- "s,t,p", sreg, 0);
+ "s,t,p", sreg, ZERO);
break;
}
if (sreg == 0)
goto do_false;
used_at = 1;
macro_build (NULL, "sltu", "d,v,t", AT, treg, sreg);
- macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
+ macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, ZERO);
break;
case M_BLEL:
}
used_at = 1;
macro_build (NULL, "slt", "d,v,t", AT, treg, sreg);
- macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
+ macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, ZERO);
break;
case M_BLEL_I:
}
used_at = 1;
set_at (sreg, 0);
- macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
+ macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, ZERO);
break;
case M_BLEUL:
if (treg == 0)
{
macro_build (&offset_expr, likely ? "beql" : "beq",
- "s,t,p", sreg, 0);
+ "s,t,p", sreg, ZERO);
break;
}
if (sreg == 0)
goto do_true;
used_at = 1;
macro_build (NULL, "sltu", "d,v,t", AT, treg, sreg);
- macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
+ macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, ZERO);
break;
case M_BLEUL_I:
if (sreg == 0
|| (HAVE_32BIT_GPRS
&& imm_expr.X_op == O_constant
- && imm_expr.X_add_number == (offsetT) 0xffffffff))
+ && imm_expr.X_add_number == -1))
goto do_true;
if (imm_expr.X_op != O_constant)
as_bad (_("Unsupported large constant"));
if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
{
macro_build (&offset_expr, likely ? "beql" : "beq",
- "s,t,p", sreg, 0);
+ "s,t,p", sreg, ZERO);
break;
}
used_at = 1;
set_at (sreg, 1);
- macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
+ macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, ZERO);
break;
case M_BLTL:
}
used_at = 1;
macro_build (NULL, "slt", "d,v,t", AT, sreg, treg);
- macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
+ macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, ZERO);
break;
case M_BLTUL:
if (sreg == 0)
{
macro_build (&offset_expr, likely ? "bnel" : "bne",
- "s,t,p", 0, treg);
+ "s,t,p", ZERO, treg);
break;
}
used_at = 1;
macro_build (NULL, "sltu", "d,v,t", AT, sreg, treg);
- macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
+ macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, ZERO);
break;
case M_DEXT:
{
- unsigned long pos;
- unsigned long size;
+ /* Use unsigned arithmetic. */
+ addressT pos;
+ addressT size;
- if (imm_expr.X_op != O_constant || imm2_expr.X_op != O_constant)
+ if (imm_expr.X_op != O_constant || imm2_expr.X_op != O_constant)
{
as_bad (_("Unsupported large constant"));
pos = size = 1;
}
else
{
- pos = (unsigned long) imm_expr.X_add_number;
- size = (unsigned long) imm2_expr.X_add_number;
+ pos = imm_expr.X_add_number;
+ size = imm2_expr.X_add_number;
}
if (pos > 63)
{
- as_bad (_("Improper position (%lu)"), pos);
+ as_bad (_("Improper position (%lu)"), (unsigned long) pos);
pos = 1;
}
- if (size == 0 || size > 64
- || (pos + size - 1) > 63)
+ if (size == 0 || size > 64 || (pos + size - 1) > 63)
{
as_bad (_("Improper extract size (%lu, position %lu)"),
- size, pos);
+ (unsigned long) size, (unsigned long) pos);
size = 1;
}
s = "dextm";
fmt = "t,r,+A,+G";
}
- macro_build ((expressionS *) NULL, s, fmt, treg, sreg, pos, size - 1);
+ macro_build ((expressionS *) NULL, s, fmt, treg, sreg, (int) pos,
+ (int) (size - 1));
}
break;
case M_DINS:
{
- unsigned long pos;
- unsigned long size;
+ /* Use unsigned arithmetic. */
+ addressT pos;
+ addressT size;
- if (imm_expr.X_op != O_constant || imm2_expr.X_op != O_constant)
+ if (imm_expr.X_op != O_constant || imm2_expr.X_op != O_constant)
{
as_bad (_("Unsupported large constant"));
pos = size = 1;
}
else
{
- pos = (unsigned long) imm_expr.X_add_number;
- size = (unsigned long) imm2_expr.X_add_number;
+ pos = imm_expr.X_add_number;
+ size = imm2_expr.X_add_number;
}
if (pos > 63)
{
- as_bad (_("Improper position (%lu)"), pos);
+ as_bad (_("Improper position (%lu)"), (unsigned long) pos);
pos = 1;
}
- if (size == 0 || size > 64
- || (pos + size - 1) > 63)
+ if (size == 0 || size > 64 || (pos + size - 1) > 63)
{
as_bad (_("Improper insert size (%lu, position %lu)"),
- size, pos);
+ (unsigned long) size, (unsigned long) pos);
size = 1;
}
s = "dinsm";
fmt = "t,r,+A,+F";
}
- macro_build ((expressionS *) NULL, s, fmt, treg, sreg, pos,
- pos + size - 1);
+ macro_build ((expressionS *) NULL, s, fmt, treg, sreg, (int) pos,
+ (int) (pos + size - 1));
}
break;
{
as_warn (_("Divide by zero."));
if (mips_trap)
- macro_build (NULL, "teq", "s,t,q", 0, 0, 7);
+ macro_build (NULL, "teq", "s,t,q", ZERO, ZERO, 7);
else
macro_build (NULL, "break", "c", 7);
break;
start_noreorder ();
if (mips_trap)
{
- macro_build (NULL, "teq", "s,t,q", treg, 0, 7);
+ macro_build (NULL, "teq", "s,t,q", treg, ZERO, 7);
macro_build (NULL, dbl ? "ddiv" : "div", "z,s,t", sreg, treg);
}
else
{
expr1.X_add_number = 8;
- macro_build (&expr1, "bne", "s,t,p", treg, 0);
+ macro_build (&expr1, "bne", "s,t,p", treg, ZERO);
macro_build (NULL, dbl ? "ddiv" : "div", "z,s,t", sreg, treg);
macro_build (NULL, "break", "c", 7);
}
{
expr1.X_add_number = 8;
macro_build (&expr1, "bne", "s,t,p", sreg, AT);
- macro_build (NULL, "nop", "", 0);
+ macro_build (NULL, "nop", "");
/* We want to close the noreorder block as soon as possible, so
that later insns are available for delay slot filling. */
{
as_warn (_("Divide by zero."));
if (mips_trap)
- macro_build (NULL, "teq", "s,t,q", 0, 0, 7);
+ macro_build (NULL, "teq", "s,t,q", ZERO, ZERO, 7);
else
macro_build (NULL, "break", "c", 7);
break;
if (strcmp (s2, "mflo") == 0)
move_register (dreg, sreg);
else
- move_register (dreg, 0);
+ move_register (dreg, ZERO);
break;
}
if (imm_expr.X_op == O_constant
macro_build (NULL, dbl ? "dneg" : "neg", "d,w", dreg, sreg);
}
else
- move_register (dreg, 0);
+ move_register (dreg, ZERO);
break;
}
start_noreorder ();
if (mips_trap)
{
- macro_build (NULL, "teq", "s,t,q", treg, 0, 7);
+ macro_build (NULL, "teq", "s,t,q", treg, ZERO, 7);
macro_build (NULL, s, "z,s,t", sreg, treg);
/* We want to close the noreorder block as soon as possible, so
that later insns are available for delay slot filling. */
else
{
expr1.X_add_number = 8;
- macro_build (&expr1, "bne", "s,t,p", treg, 0);
+ macro_build (&expr1, "bne", "s,t,p", treg, ZERO);
macro_build (NULL, s, "z,s,t", sreg, treg);
/* We want to close the noreorder block as soon as possible, so
if (dbl && HAVE_32BIT_GPRS)
as_warn (_("dla used to load 32-bit register"));
- if (! dbl && HAVE_64BIT_OBJECTS)
+ if (!dbl && HAVE_64BIT_OBJECTS)
as_warn (_("la used to load 64-bit address"));
if (offset_expr.X_op == O_constant
if (offset_expr.X_op != O_symbol
&& offset_expr.X_op != O_constant)
{
- as_bad (_("expression too complex"));
+ as_bad (_("Expression too complex"));
offset_expr.X_op = O_constant;
}
relax_switch ();
}
if (!IS_SEXT_32BIT_NUM (offset_expr.X_add_number))
- as_bad (_("offset too large"));
+ as_bad (_("Offset too large"));
macro_build_lui (&offset_expr, tempreg);
macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
tempreg, tempreg, BFD_RELOC_LO16);
}
else if (IS_SEXT_32BIT_NUM (expr1.X_add_number + 0x8000))
{
- int dreg;
-
/* If we are going to add in a base register, and the
target register and the base register are the same,
then we are using AT as a temporary register. Since
dreg = tempreg;
else
{
- assert (tempreg == AT);
+ gas_assert (tempreg == AT);
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
treg, AT, breg);
dreg = treg;
}
else
{
- int dreg;
-
/* If we are going to add in a base register, and the
target register and the base register are the same,
then we are using AT as a temporary register. Since
dreg = tempreg;
else
{
- assert (tempreg == AT);
+ gas_assert (tempreg == AT);
load_delay_nop ();
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
treg, AT, breg);
{
/* We must add in the base register now, as in the
external symbol case. */
- assert (tempreg == AT);
+ gas_assert (tempreg == AT);
load_delay_nop ();
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
treg, AT, breg);
}
else if (IS_SEXT_32BIT_NUM (expr1.X_add_number + 0x8000))
{
- int dreg;
-
/* If we are going to add in a base register, and the
target register and the base register are the same,
then we are using AT as a temporary register. Since
dreg = tempreg;
else
{
- assert (tempreg == AT);
+ gas_assert (tempreg == AT);
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
treg, AT, breg);
dreg = treg;
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", treg, tempreg, breg);
break;
+ case M_MSGSND:
+ {
+ unsigned long temp = (treg << 16) | (0x01);
+ macro_build (NULL, "c2", "C", temp);
+ }
+ break;
+
+ case M_MSGLD:
+ {
+ unsigned long temp = (0x02);
+ macro_build (NULL, "c2", "C", temp);
+ }
+ break;
+
+ case M_MSGLD_T:
+ {
+ unsigned long temp = (treg << 16) | (0x02);
+ macro_build (NULL, "c2", "C", temp);
+ }
+ break;
+
+ case M_MSGWAIT:
+ macro_build (NULL, "c2", "C", 3);
+ break;
+
+ case M_MSGWAIT_T:
+ {
+ unsigned long temp = (treg << 16) | 0x03;
+ macro_build (NULL, "c2", "C", temp);
+ }
+ break;
+
case M_J_A:
/* The j instruction may not be used in PIC code, since it
requires an absolute address. We convert it to a b
as_warn (_("No .cprestore pseudo-op used in PIC code"));
else
{
- if (! mips_frame_reg_valid)
+ if (!mips_frame_reg_valid)
{
as_warn (_("No .frame pseudo-op used in PIC code"));
/* Quiet this warning. */
mips_frame_reg_valid = 1;
}
- if (! mips_cprestore_valid)
+ if (!mips_cprestore_valid)
{
as_warn (_("No .cprestore pseudo-op used in PIC code"));
/* Quiet this warning. */
mips_cprestore_valid = 1;
}
+ if (mips_opts.noreorder)
+ macro_build (NULL, "nop", "");
expr1.X_add_number = mips_cprestore_offset;
macro_build_ldst_constoffset (&expr1, ADDRESS_LOAD_INSN,
mips_gp_register,
GOT_DISP. */
if (HAVE_NEWABI)
{
- if (! mips_big_got)
+ if (!mips_big_got)
{
relax_start (offset_expr.X_add_symbol);
macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
else
{
relax_start (offset_expr.X_add_symbol);
- if (! mips_big_got)
+ if (!mips_big_got)
{
macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
PIC_CALL_REG, BFD_RELOC_MIPS_CALL16,
as_warn (_("No .cprestore pseudo-op used in PIC code"));
else
{
- if (! mips_frame_reg_valid)
+ if (!mips_frame_reg_valid)
{
as_warn (_("No .frame pseudo-op used in PIC code"));
/* Quiet this warning. */
mips_frame_reg_valid = 1;
}
- if (! mips_cprestore_valid)
+ if (!mips_cprestore_valid)
{
as_warn (_("No .cprestore pseudo-op used in PIC code"));
/* Quiet this warning. */
case M_CACHE_AB:
s = "cache";
goto st;
+ case M_PREF_AB:
+ s = "pref";
+ goto st;
case M_SDC1_AB:
s = "sdc1";
coproc = 1;
tempreg = AT;
used_at = 1;
ld_st:
+ if (coproc
+ && NO_ISA_COP (mips_opts.arch)
+ && (ip->insn_mo->pinfo2 & (INSN2_M_FP_S | INSN2_M_FP_D)) == 0)
+ {
+ as_bad (_("Opcode not supported on this processor: %s"),
+ mips_cpu_info_from_arch (mips_opts.arch)->name);
+ break;
+ }
+
/* Itbl support may require additional care here. */
if (mask == M_LWC1_AB
|| mask == M_SWC1_AB
|| mask == M_L_DAB
|| mask == M_S_DAB)
fmt = "T,o(b)";
- else if (mask == M_CACHE_AB)
+ else if (mask == M_CACHE_AB || mask == M_PREF_AB)
fmt = "k,o(b)";
else if (coproc)
fmt = "E,o(b)";
if (offset_expr.X_op != O_constant
&& offset_expr.X_op != O_symbol)
{
- as_bad (_("expression too complex"));
+ as_bad (_("Expression too complex"));
offset_expr.X_op = O_constant;
}
is in non PIC code. */
if (offset_expr.X_op == O_constant)
{
- expr1.X_add_number = ((offset_expr.X_add_number + 0x8000)
- & ~(bfd_vma) 0xffff);
+ expr1.X_add_number = offset_expr.X_add_number;
normalize_address_expr (&expr1);
- load_register (tempreg, &expr1, HAVE_64BIT_ADDRESSES);
- if (breg != 0)
- macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
- tempreg, tempreg, breg);
- macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16, tempreg);
+ if (!IS_SEXT_16BIT_NUM (expr1.X_add_number))
+ {
+ expr1.X_add_number = ((expr1.X_add_number + 0x8000)
+ & ~(bfd_vma) 0xffff);
+ load_register (tempreg, &expr1, HAVE_64BIT_ADDRESSES);
+ if (breg != 0)
+ macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
+ tempreg, tempreg, breg);
+ breg = tempreg;
+ }
+ macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16, breg);
}
else if (mips_pic == NO_PIC)
{
16 bits, because we have no way to load the upper 16 bits
(actually, we could handle them for the subset of cases
in which we are not using $at). */
- assert (offset_expr.X_op == O_symbol);
+ gas_assert (offset_expr.X_op == O_symbol);
if (HAVE_NEWABI)
{
macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
16 bits, because we have no way to load the upper 16 bits
(actually, we could handle them for the subset of cases
in which we are not using $at). */
- assert (offset_expr.X_op == O_symbol);
+ gas_assert (offset_expr.X_op == O_symbol);
expr1.X_add_number = offset_expr.X_add_number;
offset_expr.X_add_number = 0;
if (expr1.X_add_number < -0x8000
Otherwise, for local symbols, we want:
lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT_PAGE)
<op> $treg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_OFST) */
- assert (offset_expr.X_op == O_symbol);
+ gas_assert (offset_expr.X_op == O_symbol);
expr1.X_add_number = offset_expr.X_add_number;
offset_expr.X_add_number = 0;
if (expr1.X_add_number < -0x8000
}
else
{
- assert (offset_expr.X_op == O_symbol
- && strcmp (segment_name (S_GET_SEGMENT
- (offset_expr.X_add_symbol)),
- ".lit4") == 0
- && offset_expr.X_add_number == 0);
+ gas_assert (offset_expr.X_op == O_symbol
+ && strcmp (segment_name (S_GET_SEGMENT
+ (offset_expr.X_add_symbol)),
+ ".lit4") == 0
+ && offset_expr.X_add_number == 0);
macro_build (&offset_expr, "lwc1", "T,o(b)", treg,
BFD_RELOC_MIPS_LITERAL, mips_gp_register);
break;
move_register (lreg, 0);
else
{
- assert (offset_expr.X_op == O_constant);
+ gas_assert (offset_expr.X_op == O_constant);
load_register (lreg, &offset_expr, 0);
}
}
load_register (AT, &imm_expr, HAVE_64BIT_FPRS);
if (HAVE_64BIT_FPRS)
{
- assert (HAVE_64BIT_GPRS);
+ gas_assert (HAVE_64BIT_GPRS);
macro_build (NULL, "dmtc1", "t,S", AT, treg);
}
else
macro_build (NULL, "mtc1", "t,G", 0, treg);
else
{
- assert (offset_expr.X_op == O_constant);
+ gas_assert (offset_expr.X_op == O_constant);
load_register (AT, &offset_expr, 0);
macro_build (NULL, "mtc1", "t,G", AT, treg);
}
break;
}
- assert (offset_expr.X_op == O_symbol
- && offset_expr.X_add_number == 0);
+ gas_assert (offset_expr.X_op == O_symbol
+ && offset_expr.X_add_number == 0);
s = segment_name (S_GET_SEGMENT (offset_expr.X_add_symbol));
if (strcmp (s, ".lit8") == 0)
{
}
else
{
- assert (strcmp (s, RDATA_SECTION_NAME) == 0);
+ gas_assert (strcmp (s, RDATA_SECTION_NAME) == 0);
used_at = 1;
if (mips_pic != NO_PIC)
macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", AT,
to adjust when loading from memory. */
r = BFD_RELOC_LO16;
dob:
- assert (mips_opts.isa == ISA_MIPS1);
+ gas_assert (mips_opts.isa == ISA_MIPS1);
macro_build (&offset_expr, "lwc1", "T,o(b)",
target_big_endian ? treg + 1 : treg, r, breg);
/* FIXME: A possible overflow which I don't know how to deal
target_big_endian ? treg : treg + 1, r, breg);
break;
+ case M_S_DOB:
+ gas_assert (mips_opts.isa == ISA_MIPS1);
+ /* Even on a big endian machine $fn comes before $fn+1. We have
+ to adjust when storing to memory. */
+ macro_build (&offset_expr, "swc1", "T,o(b)",
+ target_big_endian ? treg + 1 : treg, BFD_RELOC_LO16, breg);
+ offset_expr.X_add_number += 4;
+ macro_build (&offset_expr, "swc1", "T,o(b)",
+ target_big_endian ? treg : treg + 1, BFD_RELOC_LO16, breg);
+ break;
+
case M_L_DAB:
/*
* The MIPS assembler seems to check for X_add_number not
if (offset_expr.X_op != O_symbol
&& offset_expr.X_op != O_constant)
{
- as_bad (_("expression too complex"));
+ as_bad (_("Expression too complex"));
offset_expr.X_op = O_constant;
}
to adjust when loading from memory. We set coproc if we must
load $fn+1 first. */
/* Itbl support may require additional care here. */
- if (! target_big_endian)
+ if (!target_big_endian)
coproc = 0;
- if (mips_pic == NO_PIC
- || offset_expr.X_op == O_constant)
+ if (mips_pic == NO_PIC || offset_expr.X_op == O_constant)
{
/* If this is a reference to a GP relative symbol, we want
<op> $treg,<sym>($gp) (BFD_RELOC_GPREL16)
mips_optimize = hold_mips_optimize;
relax_switch ();
-
- /* We just generated two relocs. When tc_gen_reloc
- handles this case, it will skip the first reloc and
- handle the second. The second reloc already has an
- extra addend of 4, which we added above. We must
- subtract it out, and then subtract another 4 to make
- the first reloc come out right. The second reloc
- will come out right because we are going to add 4 to
- offset_expr when we build its instruction below.
-
- If we have a symbol, then we don't want to include
- the offset, because it will wind up being included
- when we generate the reloc. */
-
- if (offset_expr.X_op == O_constant)
- offset_expr.X_add_number -= 8;
- else
- {
- offset_expr.X_add_number = -4;
- offset_expr.X_op = O_constant;
- }
+
+ offset_expr.X_add_number -= 4;
}
used_at = 1;
macro_build_lui (&offset_expr, AT);
break;
case M_LD_OB:
- s = "lw";
+ s = HAVE_64BIT_GPRS ? "ld" : "lw";
goto sd_ob;
case M_SD_OB:
- s = "sw";
+ s = HAVE_64BIT_GPRS ? "sd" : "sw";
sd_ob:
- assert (HAVE_32BIT_ADDRESSES);
- macro_build (&offset_expr, s, "t,o(b)", treg, BFD_RELOC_LO16, breg);
- offset_expr.X_add_number += 4;
- macro_build (&offset_expr, s, "t,o(b)", treg + 1, BFD_RELOC_LO16, breg);
+ macro_build (&offset_expr, s, "t,o(b)", treg,
+ -1, offset_reloc[0], offset_reloc[1], offset_reloc[2],
+ breg);
+ if (!HAVE_64BIT_GPRS)
+ {
+ offset_expr.X_add_number += 4;
+ macro_build (&offset_expr, s, "t,o(b)", treg + 1,
+ -1, offset_reloc[0], offset_reloc[1], offset_reloc[2],
+ breg);
+ }
break;
/* New code added to support COPZ instructions.
case M_COP3:
s = "c3";
copz:
+ if (NO_ISA_COP (mips_opts.arch)
+ && (ip->insn_mo->pinfo2 & INSN2_M_FP_S) == 0)
+ {
+ as_bad (_("opcode not supported on this processor: %s"),
+ mips_cpu_info_from_arch (mips_opts.arch)->name);
+ break;
+ }
+
/* For now we just do C (same as Cz). The parameter will be
stored in insn_opcode by mips_ip. */
macro_build (NULL, s, "C", ip->insn_opcode);
move_register (dreg, sreg);
break;
-#ifdef LOSING_COMPILER
- default:
- /* Try and see if this is a new itbl instruction.
- This code builds table entries out of the macros in mip_opcodes.
- FIXME: For now we just assemble the expression and pass it's
- value along as a 32-bit immediate.
- We may want to have the assembler assemble this value,
- so that we gain the assembler's knowledge of delay slots,
- symbols, etc.
- Would it be more efficient to use mask (id) here? */
- if (itbl_have_entries
- && (immed_expr = itbl_assemble (ip->insn_mo->name, "")))
- {
- s = ip->insn_mo->name;
- s2 = "cop3";
- coproc = ITBL_DECODE_PNUM (immed_expr);;
- macro_build (&immed_expr, s, "C");
- break;
- }
- macro2 (ip);
- break;
- }
- if (!mips_opts.at && used_at)
- as_bad (_("Macro used $at after \".set noat\""));
-}
-
-static void
-macro2 (struct mips_cl_insn *ip)
-{
- unsigned int treg, sreg, dreg, breg;
- unsigned int tempreg;
- int mask;
- int used_at;
- expressionS expr1;
- const char *s;
- const char *s2;
- const char *fmt;
- int likely = 0;
- int dbl = 0;
- int coproc = 0;
- int lr = 0;
- int imm = 0;
- int off;
- offsetT maxnum;
- bfd_reloc_code_real_type r;
-
- treg = (ip->insn_opcode >> 16) & 0x1f;
- dreg = (ip->insn_opcode >> 11) & 0x1f;
- sreg = breg = (ip->insn_opcode >> 21) & 0x1f;
- mask = ip->insn_mo->mask;
-
- expr1.X_op = O_constant;
- expr1.X_op_symbol = NULL;
- expr1.X_add_symbol = NULL;
- expr1.X_add_number = 1;
-
- switch (mask)
- {
-#endif /* LOSING_COMPILER */
-
case M_DMUL:
dbl = 1;
case M_MUL:
{
expr1.X_add_number = 8;
macro_build (&expr1, "beq", "s,t,p", dreg, AT);
- macro_build (NULL, "nop", "", 0);
+ macro_build (NULL, "nop", "");
macro_build (NULL, "break", "c", 6);
}
end_noreorder ();
macro_build (NULL, "mfhi", "d", AT);
macro_build (NULL, "mflo", "d", dreg);
if (mips_trap)
- macro_build (NULL, "tne", "s,t,q", AT, 0, 6);
+ macro_build (NULL, "tne", "s,t,q", AT, ZERO, 6);
else
{
expr1.X_add_number = 8;
- macro_build (&expr1, "beq", "s,t,p", AT, 0);
- macro_build (NULL, "nop", "", 0);
+ macro_build (&expr1, "beq", "s,t,p", AT, ZERO);
+ macro_build (NULL, "nop", "");
macro_build (NULL, "break", "c", 6);
}
end_noreorder ();
break;
}
used_at = 1;
- macro_build (NULL, "dsubu", "d,v,t", AT, 0, treg);
+ macro_build (NULL, "dsubu", "d,v,t", AT, ZERO, treg);
macro_build (NULL, "dsrlv", "d,t,s", AT, sreg, AT);
macro_build (NULL, "dsllv", "d,t,s", dreg, sreg, treg);
macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
break;
}
used_at = 1;
- macro_build (NULL, "subu", "d,v,t", AT, 0, treg);
+ macro_build (NULL, "subu", "d,v,t", AT, ZERO, treg);
macro_build (NULL, "srlv", "d,t,s", AT, sreg, AT);
macro_build (NULL, "sllv", "d,t,s", dreg, sreg, treg);
macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
case M_DROL_I:
{
unsigned int rot;
- char *l, *r;
+ char *l;
+ char *rr;
if (imm_expr.X_op != O_constant)
as_bad (_("Improper rotate count"));
break;
}
l = (rot < 0x20) ? "dsll" : "dsll32";
- r = ((0x40 - rot) < 0x20) ? "dsrl" : "dsrl32";
+ rr = ((0x40 - rot) < 0x20) ? "dsrl" : "dsrl32";
rot &= 0x1f;
used_at = 1;
macro_build (NULL, l, "d,w,<", AT, sreg, rot);
- macro_build (NULL, r, "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
+ macro_build (NULL, rr, "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
}
break;
break;
}
used_at = 1;
- macro_build (NULL, "dsubu", "d,v,t", AT, 0, treg);
+ macro_build (NULL, "dsubu", "d,v,t", AT, ZERO, treg);
macro_build (NULL, "dsllv", "d,t,s", AT, sreg, AT);
macro_build (NULL, "dsrlv", "d,t,s", dreg, sreg, treg);
macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
break;
}
used_at = 1;
- macro_build (NULL, "subu", "d,v,t", AT, 0, treg);
+ macro_build (NULL, "subu", "d,v,t", AT, ZERO, treg);
macro_build (NULL, "sllv", "d,t,s", AT, sreg, AT);
macro_build (NULL, "srlv", "d,t,s", dreg, sreg, treg);
macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
case M_DROR_I:
{
unsigned int rot;
- char *l, *r;
+ char *l;
+ char *rr;
if (imm_expr.X_op != O_constant)
as_bad (_("Improper rotate count"));
macro_build (NULL, "dsrl", "d,w,<", dreg, sreg, 0);
break;
}
- r = (rot < 0x20) ? "dsrl" : "dsrl32";
+ rr = (rot < 0x20) ? "dsrl" : "dsrl32";
l = ((0x40 - rot) < 0x20) ? "dsll" : "dsll32";
rot &= 0x1f;
used_at = 1;
- macro_build (NULL, r, "d,w,<", AT, sreg, rot);
+ macro_build (NULL, rr, "d,w,<", AT, sreg, rot);
macro_build (NULL, l, "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
}
}
break;
- case M_S_DOB:
- assert (mips_opts.isa == ISA_MIPS1);
- /* Even on a big endian machine $fn comes before $fn+1. We have
- to adjust when storing to memory. */
- macro_build (&offset_expr, "swc1", "T,o(b)",
- target_big_endian ? treg + 1 : treg, BFD_RELOC_LO16, breg);
- offset_expr.X_add_number += 4;
- macro_build (&offset_expr, "swc1", "T,o(b)",
- target_big_endian ? treg : treg + 1, BFD_RELOC_LO16, breg);
- break;
-
case M_SEQ:
if (sreg == 0)
macro_build (&expr1, "sltiu", "t,r,j", dreg, treg, BFD_RELOC_LO16);
move_register (dreg, 0);
break;
}
+ if (CPU_HAS_SEQ (mips_opts.arch)
+ && -512 <= imm_expr.X_add_number
+ && imm_expr.X_add_number < 512)
+ {
+ macro_build (NULL, "seqi", "t,r,+Q", dreg, sreg,
+ (int) imm_expr.X_add_number);
+ break;
+ }
if (imm_expr.X_op == O_constant
&& imm_expr.X_add_number >= 0
&& imm_expr.X_add_number < 0x10000)
macro_build (&imm_expr, HAVE_32BIT_GPRS ? "addiu" : "daddiu",
"t,r,j", dreg, sreg, BFD_RELOC_LO16);
}
+ else if (CPU_HAS_SEQ (mips_opts.arch))
+ {
+ used_at = 1;
+ load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+ macro_build (NULL, "seq", "d,v,t", dreg, sreg, AT);
+ break;
+ }
else
{
load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
dreg, 0, BFD_RELOC_LO16);
break;
}
+ if (CPU_HAS_SEQ (mips_opts.arch)
+ && -512 <= imm_expr.X_add_number
+ && imm_expr.X_add_number < 512)
+ {
+ macro_build (NULL, "snei", "t,r,+Q", dreg, sreg,
+ (int) imm_expr.X_add_number);
+ break;
+ }
if (imm_expr.X_op == O_constant
&& imm_expr.X_add_number >= 0
&& imm_expr.X_add_number < 0x10000)
macro_build (&imm_expr, HAVE_32BIT_GPRS ? "addiu" : "daddiu",
"t,r,j", dreg, sreg, BFD_RELOC_LO16);
}
+ else if (CPU_HAS_SEQ (mips_opts.arch))
+ {
+ used_at = 1;
+ load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+ macro_build (NULL, "sne", "d,v,t", dreg, sreg, AT);
+ break;
+ }
else
{
load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
case M_TRUNCWS:
case M_TRUNCWD:
- assert (mips_opts.isa == ISA_MIPS1);
+ gas_assert (mips_opts.isa == ISA_MIPS1);
used_at = 1;
sreg = (ip->insn_opcode >> 11) & 0x1f; /* floating reg */
dreg = (ip->insn_opcode >> 06) & 0x1f; /* floating reg */
ulh:
used_at = 1;
if (offset_expr.X_add_number >= 0x7fff)
- as_bad (_("operand overflow"));
- if (! target_big_endian)
+ as_bad (_("Operand overflow"));
+ if (!target_big_endian)
++offset_expr.X_add_number;
macro_build (&offset_expr, s, "t,o(b)", AT, BFD_RELOC_LO16, breg);
- if (! target_big_endian)
+ if (!target_big_endian)
--offset_expr.X_add_number;
else
++offset_expr.X_add_number;
off = 3;
ulw:
if (offset_expr.X_add_number >= 0x8000 - off)
- as_bad (_("operand overflow"));
+ as_bad (_("Operand overflow"));
if (treg != breg)
tempreg = treg;
else
used_at = 1;
tempreg = AT;
}
- if (! target_big_endian)
+ if (!target_big_endian)
offset_expr.X_add_number += off;
macro_build (&offset_expr, s, "t,o(b)", tempreg, BFD_RELOC_LO16, breg);
- if (! target_big_endian)
+ if (!target_big_endian)
offset_expr.X_add_number -= off;
else
offset_expr.X_add_number += off;
macro_build (&offset_expr, s2, "t,o(b)", tempreg, BFD_RELOC_LO16, breg);
- /* If necessary, move the result in tempreg the final destination. */
+ /* If necessary, move the result in tempreg to the final destination. */
if (treg == tempreg)
break;
/* Protect second load's delay slot. */
load_address (AT, &offset_expr, &used_at);
if (breg != 0)
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, AT, breg);
- if (! target_big_endian)
+ if (!target_big_endian)
expr1.X_add_number = off;
else
expr1.X_add_number = 0;
macro_build (&expr1, s, "t,o(b)", treg, BFD_RELOC_LO16, AT);
- if (! target_big_endian)
+ if (!target_big_endian)
expr1.X_add_number = 0;
else
expr1.X_add_number = off;
case M_USH:
used_at = 1;
if (offset_expr.X_add_number >= 0x7fff)
- as_bad (_("operand overflow"));
+ as_bad (_("Operand overflow"));
if (target_big_endian)
++offset_expr.X_add_number;
macro_build (&offset_expr, "sb", "t,o(b)", treg, BFD_RELOC_LO16, breg);
off = 3;
usw:
if (offset_expr.X_add_number >= 0x8000 - off)
- as_bad (_("operand overflow"));
- if (! target_big_endian)
+ as_bad (_("Operand overflow"));
+ if (!target_big_endian)
offset_expr.X_add_number += off;
macro_build (&offset_expr, s, "t,o(b)", treg, BFD_RELOC_LO16, breg);
- if (! target_big_endian)
+ if (!target_big_endian)
offset_expr.X_add_number -= off;
else
offset_expr.X_add_number += off;
load_address (AT, &offset_expr, &used_at);
if (breg != 0)
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, AT, breg);
- if (! target_big_endian)
+ if (!target_big_endian)
expr1.X_add_number = off;
else
expr1.X_add_number = 0;
macro_build (&expr1, s, "t,o(b)", treg, BFD_RELOC_LO16, AT);
- if (! target_big_endian)
+ if (!target_big_endian)
expr1.X_add_number = 0;
else
expr1.X_add_number = off;
load_address (AT, &offset_expr, &used_at);
if (breg != 0)
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, AT, breg);
- if (! target_big_endian)
+ if (!target_big_endian)
expr1.X_add_number = 0;
macro_build (&expr1, "sb", "t,o(b)", treg, BFD_RELOC_LO16, AT);
macro_build (NULL, "srl", "d,w,<", treg, treg, 8);
- if (! target_big_endian)
+ if (!target_big_endian)
expr1.X_add_number = 1;
else
expr1.X_add_number = 0;
macro_build (&expr1, "sb", "t,o(b)", treg, BFD_RELOC_LO16, AT);
- if (! target_big_endian)
+ if (!target_big_endian)
expr1.X_add_number = 0;
else
expr1.X_add_number = 1;
case 'X': USE_BITS (OP_MASK_BBITIND, OP_SH_BBITIND); break;
case 'p': USE_BITS (OP_MASK_CINSPOS, OP_SH_CINSPOS); break;
case 'P': USE_BITS (OP_MASK_CINSPOS, OP_SH_CINSPOS); break;
+ case 'Q': USE_BITS (OP_MASK_SEQI, OP_SH_SEQI); break;
case 's': USE_BITS (OP_MASK_CINSLM1, OP_SH_CINSLM1); break;
case 'S': USE_BITS (OP_MASK_CINSLM1, OP_SH_CINSLM1); break;
+ case 'z': USE_BITS (OP_MASK_RZ, OP_SH_RZ); break;
+ case 'Z': USE_BITS (OP_MASK_FZ, OP_SH_FZ); break;
+ case 'a': USE_BITS (OP_MASK_OFFSET_A, OP_SH_OFFSET_A); break;
+ case 'b': USE_BITS (OP_MASK_OFFSET_B, OP_SH_OFFSET_B); break;
+ case 'c': USE_BITS (OP_MASK_OFFSET_C, OP_SH_OFFSET_C); break;
default:
as_bad (_("internal: bad mips opcode (unknown extension operand type `+%c'): %s %s"),
case '%': USE_BITS (OP_MASK_VECALIGN, OP_SH_VECALIGN); break;
case '[': break;
case ']': break;
+ case '1': USE_BITS (OP_MASK_SHAMT, OP_SH_SHAMT); break;
case '2': USE_BITS (OP_MASK_BP, OP_SH_BP); break;
case '3': USE_BITS (OP_MASK_SA3, OP_SH_SA3); break;
case '4': USE_BITS (OP_MASK_SA4, OP_SH_SA4); break;
struct mips_opcode *insn;
char *argsStart;
unsigned int regno;
- unsigned int lastregno = 0;
+ unsigned int lastregno;
unsigned int lastpos = 0;
unsigned int limlo, limhi;
char *s_reset;
/* If we did not find a '.', then we can quit now. */
if (*s != '.')
{
- insn_error = "unrecognized opcode";
+ insn_error = _("Unrecognized opcode");
return;
}
*s++ = '\0';
if ((insn = (struct mips_opcode *) hash_find (op_hash, str)) == NULL)
{
- insn_error = "unrecognized opcode";
+ insn_error = _("Unrecognized opcode");
return;
}
}
{
bfd_boolean ok;
- assert (strcmp (insn->name, str) == 0);
+ gas_assert (strcmp (insn->name, str) == 0);
- ok = is_opcode_valid (insn, FALSE);
+ ok = is_opcode_valid (insn);
if (! ok)
{
if (insn + 1 < &mips_opcodes[NUMOPCODES]
create_insn (ip, insn);
insn_error = NULL;
argnum = 1;
+ lastregno = 0xffffffff;
for (args = insn->args;; ++args)
{
int is_mdmx;
return;
break;
- case '2': /* dsp 2-bit unsigned immediate in bit 11 */
+ case '2': /* DSP 2-bit unsigned immediate in bit 11. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if ((unsigned long) imm_expr.X_add_number != 1
s = expr_end;
continue;
- case '3': /* dsp 3-bit unsigned immediate in bit 21 */
+ case '3': /* DSP 3-bit unsigned immediate in bit 21. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if (imm_expr.X_add_number & ~OP_MASK_SA3)
s = expr_end;
continue;
- case '4': /* dsp 4-bit unsigned immediate in bit 21 */
+ case '4': /* DSP 4-bit unsigned immediate in bit 21. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if (imm_expr.X_add_number & ~OP_MASK_SA4)
s = expr_end;
continue;
- case '5': /* dsp 8-bit unsigned immediate in bit 16 */
+ case '5': /* DSP 8-bit unsigned immediate in bit 16. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if (imm_expr.X_add_number & ~OP_MASK_IMM8)
s = expr_end;
continue;
- case '6': /* dsp 5-bit unsigned immediate in bit 21 */
+ case '6': /* DSP 5-bit unsigned immediate in bit 21. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if (imm_expr.X_add_number & ~OP_MASK_RS)
s = expr_end;
continue;
- case '7': /* four dsp accumulators in bits 11,12 */
+ case '7': /* Four DSP accumulators in bits 11,12. */
if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
s[3] >= '0' && s[3] <= '3')
{
as_bad (_("Invalid dsp acc register"));
break;
- case '8': /* dsp 6-bit unsigned immediate in bit 11 */
+ case '8': /* DSP 6-bit unsigned immediate in bit 11. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if (imm_expr.X_add_number & ~OP_MASK_WRDSP)
s = expr_end;
continue;
- case '9': /* four dsp accumulators in bits 21,22 */
+ case '9': /* Four DSP accumulators in bits 21,22. */
if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
s[3] >= '0' && s[3] <= '3')
{
as_bad (_("Invalid dsp acc register"));
break;
- case '0': /* dsp 6-bit signed immediate in bit 20 */
+ case '0': /* DSP 6-bit signed immediate in bit 20. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
min_range = -((OP_MASK_DSPSFT + 1) >> 1);
s = expr_end;
continue;
- case '\'': /* dsp 6-bit unsigned immediate in bit 16 */
+ case '\'': /* DSP 6-bit unsigned immediate in bit 16. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if (imm_expr.X_add_number & ~OP_MASK_RDDSP)
s = expr_end;
continue;
- case ':': /* dsp 7-bit signed immediate in bit 19 */
+ case ':': /* DSP 7-bit signed immediate in bit 19. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
min_range = -((OP_MASK_DSPSFT_7 + 1) >> 1);
s = expr_end;
continue;
- case '@': /* dsp 10-bit signed immediate in bit 16 */
+ case '@': /* DSP 10-bit signed immediate in bit 16. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
min_range = -((OP_MASK_IMM10 + 1) >> 1);
s = expr_end;
continue;
- case '*': /* four dsp accumulators in bits 18,19 */
+ case '*': /* Four DSP accumulators in bits 18,19. */
if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
s[3] >= '0' && s[3] <= '3')
{
as_bad (_("Invalid dsp/smartmips acc register"));
break;
- case '&': /* four dsp accumulators in bits 13,14 */
+ case '&': /* Four DSP accumulators in bits 13,14. */
if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
s[3] >= '0' && s[3] <= '3')
{
we must have a left paren. */
/* This is dependent on the next operand specifier
is a base register specification. */
- assert (args[1] == 'b' || args[1] == '5'
- || args[1] == '-' || args[1] == '4');
+ gas_assert (args[1] == 'b');
if (*s == '\0')
return;
- case ')': /* these must match exactly */
+ case ')': /* These must match exactly. */
case '[':
case ']':
if (*s++ == *args)
imm->desc ? imm->desc : ip->insn_mo->name,
(unsigned long) imm_expr.X_add_number,
(unsigned long) imm_expr.X_add_number);
- imm_expr.X_add_number &= imm->mask;
+ imm_expr.X_add_number &= imm->mask;
}
ip->insn_opcode |= ((unsigned long) imm_expr.X_add_number
<< imm->shift);
s = expr_end;
}
continue;
-
+
case 'A': /* ins/ext position, becomes LSB. */
limlo = 0;
limhi = 31;
limlo = 32;
limhi = 63;
goto do_lsb;
-do_lsb:
+ do_lsb:
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if ((unsigned long) imm_expr.X_add_number < limlo
limlo = 33;
limhi = 64;
goto do_msb;
-do_msb:
+ do_msb:
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
/* Check for negative input so that small negative numbers
limlo = 33;
limhi = 64;
goto do_msbd;
-do_msbd:
+ do_msbd:
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
/* Check for negative input so that small negative numbers
s = expr_end;
continue;
+ case 'Q':
+ /* seqi/snei immediate field. */
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ if ((long) imm_expr.X_add_number < -512
+ || (long) imm_expr.X_add_number >= 512)
+ {
+ as_bad (_("Improper immediate (%ld)"),
+ (long) imm_expr.X_add_number);
+ imm_expr.X_add_number = 0;
+ }
+ INSERT_OPERAND (SEQI, *ip, imm_expr.X_add_number);
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+
+ case 'a': /* 8-bit signed offset in bit 6 */
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ min_range = -((OP_MASK_OFFSET_A + 1) >> 1);
+ max_range = ((OP_MASK_OFFSET_A + 1) >> 1) - 1;
+ if (imm_expr.X_add_number < min_range
+ || imm_expr.X_add_number > max_range)
+ {
+ as_bad (_("Offset not in range %ld..%ld (%ld)"),
+ (long) min_range, (long) max_range,
+ (long) imm_expr.X_add_number);
+ }
+ INSERT_OPERAND (OFFSET_A, *ip, imm_expr.X_add_number);
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+
+ case 'b': /* 8-bit signed offset in bit 3 */
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ min_range = -((OP_MASK_OFFSET_B + 1) >> 1);
+ max_range = ((OP_MASK_OFFSET_B + 1) >> 1) - 1;
+ if (imm_expr.X_add_number < min_range
+ || imm_expr.X_add_number > max_range)
+ {
+ as_bad (_("Offset not in range %ld..%ld (%ld)"),
+ (long) min_range, (long) max_range,
+ (long) imm_expr.X_add_number);
+ }
+ INSERT_OPERAND (OFFSET_B, *ip, imm_expr.X_add_number);
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+
+ case 'c': /* 9-bit signed offset in bit 6 */
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ min_range = -((OP_MASK_OFFSET_C + 1) >> 1);
+ max_range = ((OP_MASK_OFFSET_C + 1) >> 1) - 1;
+ /* We check the offset range before adjusted. */
+ min_range <<= 4;
+ max_range <<= 4;
+ if (imm_expr.X_add_number < min_range
+ || imm_expr.X_add_number > max_range)
+ {
+ as_bad (_("Offset not in range %ld..%ld (%ld)"),
+ (long) min_range, (long) max_range,
+ (long) imm_expr.X_add_number);
+ }
+ if (imm_expr.X_add_number & 0xf)
+ {
+ as_bad (_("Offset not 16 bytes alignment (%ld)"),
+ (long) imm_expr.X_add_number);
+ }
+ /* Right shift 4 bits to adjust the offset operand. */
+ INSERT_OPERAND (OFFSET_C, *ip, imm_expr.X_add_number >> 4);
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+
+ case 'z':
+ if (!reg_lookup (&s, RTYPE_NUM | RTYPE_GP, ®no))
+ break;
+ if (regno == AT && mips_opts.at)
+ {
+ if (mips_opts.at == ATREG)
+ as_warn (_("used $at without \".set noat\""));
+ else
+ as_warn (_("used $%u with \".set at=$%u\""),
+ regno, mips_opts.at);
+ }
+ INSERT_OPERAND (RZ, *ip, regno);
+ continue;
+
+ case 'Z':
+ if (!reg_lookup (&s, RTYPE_FPU, ®no))
+ break;
+ INSERT_OPERAND (FZ, *ip, regno);
+ continue;
+
default:
- as_bad (_("internal: bad mips opcode (unknown extension operand type `+%c'): %s %s"),
- *args, insn->name, insn->args);
+ as_bad (_("Internal error: bad mips opcode "
+ "(unknown extension operand type `+%c'): %s %s"),
+ *args, insn->name, insn->args);
/* Further processing is fruitless. */
return;
}
s = expr_end;
continue;
- case 'k': /* cache code */
- case 'h': /* prefx code */
+ case 'k': /* CACHE code. */
+ case 'h': /* PREFX code. */
+ case '1': /* SYNC type. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if ((unsigned long) imm_expr.X_add_number > 31)
ip->insn_mo->name,
(unsigned long) imm_expr.X_add_number);
if (*args == 'k')
- INSERT_OPERAND (CACHE, *ip, imm_expr.X_add_number);
- else
+ {
+ if (mips_fix_cn63xxp1 && strcmp ("pref", insn->name) == 0)
+ switch (imm_expr.X_add_number)
+ {
+ case 5:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31: /* These are ok. */
+ break;
+
+ default: /* The rest must be changed to 28. */
+ imm_expr.X_add_number = 28;
+ break;
+ }
+ INSERT_OPERAND (CACHE, *ip, imm_expr.X_add_number);
+ }
+ else if (*args == 'h')
INSERT_OPERAND (PREFX, *ip, imm_expr.X_add_number);
+ else
+ INSERT_OPERAND (SHAMT, *ip, imm_expr.X_add_number);
imm_expr.X_op = O_absent;
s = expr_end;
continue;
- case 'c': /* break code */
+ case 'c': /* BREAK code. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE)
s = expr_end;
continue;
- case 'q': /* lower break code */
+ case 'q': /* Lower BREAK code. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE2)
s = expr_end;
continue;
- case 'B': /* 20-bit syscall/break code. */
+ case 'B': /* 20-bit SYSCALL/BREAK code. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE20)
s = expr_end;
continue;
- case 'C': /* Coprocessor code */
+ case 'C': /* Coprocessor code. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if ((unsigned long) imm_expr.X_add_number > OP_MASK_COPZ)
s = expr_end;
continue;
- case 'J': /* 19-bit wait code. */
+ case 'J': /* 19-bit WAIT code. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE19)
else
break;
- case 'b': /* base register */
- case 'd': /* destination register */
- case 's': /* source register */
- case 't': /* target register */
- case 'r': /* both target and source */
- case 'v': /* both dest and source */
- case 'w': /* both dest and target */
- case 'E': /* coprocessor target register */
- case 'K': /* 'rdhwr' destination register */
- case 'x': /* ignore register name */
- case 'z': /* must be zero register */
- case 'U': /* destination register (clo/clz). */
- case 'g': /* coprocessor destination register */
- s_reset = s;
+ case 'b': /* Base register. */
+ case 'd': /* Destination register. */
+ case 's': /* Source register. */
+ case 't': /* Target register. */
+ case 'r': /* Both target and source. */
+ case 'v': /* Both dest and source. */
+ case 'w': /* Both dest and target. */
+ case 'E': /* Coprocessor target register. */
+ case 'K': /* RDHWR destination register. */
+ case 'x': /* Ignore register name. */
+ case 'z': /* Must be zero register. */
+ case 'U': /* Destination register (CLO/CLZ). */
+ case 'g': /* Coprocessor destination register. */
+ s_reset = s;
if (*args == 'E' || *args == 'K')
ok = reg_lookup (&s, RTYPE_NUM, ®no);
else
if (regno == AT && mips_opts.at)
{
if (mips_opts.at == ATREG)
- as_warn (_("used $at without \".set noat\""));
+ as_warn (_("Used $at without \".set noat\""));
else
- as_warn (_("used $%u with \".set at=$%u\""),
+ as_warn (_("Used $%u with \".set at=$%u\""),
regno, mips_opts.at);
}
}
if (c == 'z' && regno != 0)
break;
- if (c == 's' && !strcmp (ip->insn_mo->name, "jalr"))
+ if (c == 's' && !strncmp (ip->insn_mo->name, "jalr", 4))
{
if (regno == lastregno)
- {
- insn_error = _("source and destinationations must be different");
+ {
+ insn_error
+ = _("Source and destination must be different");
continue;
- }
- if (regno == 31 && lastregno == 0)
- {
- insn_error = _("a destination register must be supplied");
+ }
+ if (regno == 31 && lastregno == 0xffffffff)
+ {
+ insn_error
+ = _("A destination register must be supplied");
continue;
- }
+ }
}
- /* Now that we have assembled one operand, we use the args string
- * to figure out where it goes in the instruction. */
+ /* Now that we have assembled one operand, we use the args
+ string to figure out where it goes in the instruction. */
switch (c)
{
case 'r':
INSERT_OPERAND (RS, *ip, regno);
break;
case 'd':
- case 'G':
case 'K':
case 'g':
INSERT_OPERAND (RD, *ip, regno);
is $0. This only matches $0, and is checked
outside the switch. */
break;
- case 'D':
- /* Itbl operand; not yet implemented. FIXME ?? */
- break;
- /* What about all other operands like 'i', which
- can be specified in the opcode table? */
}
lastregno = regno;
continue;
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if ((unsigned long) imm_expr.X_add_number > OP_MASK_ALN)
- as_warn ("Improper align amount (%ld), using low bits",
+ as_warn (_("Improper align amount (%ld), using low bits"),
(long) imm_expr.X_add_number);
INSERT_OPERAND (ALN, *ip, imm_expr.X_add_number);
imm_expr.X_op = O_absent;
case 'Y': /* MDMX source register. */
case 'Z': /* MDMX target register. */
is_mdmx = 1;
- case 'D': /* floating point destination register */
- case 'S': /* floating point source register */
- case 'T': /* floating point target register */
- case 'R': /* floating point source register */
+ case 'D': /* Floating point destination register. */
+ case 'S': /* Floating point source register. */
+ case 'T': /* Floating point target register. */
+ case 'R': /* Floating point source register. */
case 'V':
case 'W':
rtype = RTYPE_FPU;
{
if ((regno & 1) != 0
&& HAVE_32BIT_FPRS
- && ! mips_oddfpreg_ok (ip->insn_mo, argnum))
+ && !mips_oddfpreg_ok (ip->insn_mo, argnum))
as_warn (_("Float register should be even, was %d"),
regno);
check_absolute_expr (ip, &imm_expr);
s = expr_end;
if (imm_expr.X_add_number > max_el)
- as_bad(_("Bad element selector %ld"),
- (long) imm_expr.X_add_number);
+ as_bad (_("Bad element selector %ld"),
+ (long) imm_expr.X_add_number);
imm_expr.X_add_number &= max_el;
ip->insn_opcode |= (imm_expr.X_add_number
<< (OP_SH_VSEL +
(is_qh ? 2 : 1)));
imm_expr.X_op = O_absent;
if (*s != ']')
- as_warn(_("Expecting ']' found '%s'"), s);
+ as_warn (_("Expecting ']' found '%s'"), s);
else
s++;
}
ip->insn_opcode |= (MDMX_FMTSEL_VEC_OB <<
OP_SH_VSEL);
}
- /* Fall through */
+ /* Fall through. */
case 'W':
case 'T':
case 'Z':
length = f64 ? 8 : 4;
}
- assert (length == (unsigned) (f64 ? 8 : 4));
+ gas_assert (length == (unsigned) (f64 ? 8 : 4));
if (*args == 'f'
|| (*args == 'l'
|| (temp[2] == 0 && temp[3] == 0))))
{
imm_expr.X_op = O_constant;
- if (! target_big_endian)
+ if (!target_big_endian)
imm_expr.X_add_number = bfd_getl32 (temp);
else
imm_expr.X_add_number = bfd_getb32 (temp);
}
else if (length > 4
- && ! mips_disable_float_construction
+ && !mips_disable_float_construction
/* Constants can only be constructed in GPRs and
copied to FPRs if the GPRs are at least as wide
as the FPRs. Force the constant into memory if
we are using 64-bit FPRs but the GPRs are only
32 bits wide. */
&& (using_gprs
- || ! (HAVE_64BIT_FPRS && HAVE_32BIT_GPRS))
+ || !(HAVE_64BIT_FPRS && HAVE_32BIT_GPRS))
&& ((temp[0] == 0 && temp[1] == 0)
|| (temp[2] == 0 && temp[3] == 0))
&& ((temp[4] == 0 && temp[5] == 0)
|| (temp[6] == 0 && temp[7] == 0)))
{
/* The value is simple enough to load with a couple of
- instructions. If using 32-bit registers, set
- imm_expr to the high order 32 bits and offset_expr to
- the low order 32 bits. Otherwise, set imm_expr to
- the entire 64 bit constant. */
+ instructions. If using 32-bit registers, set
+ imm_expr to the high order 32 bits and offset_expr to
+ the low order 32 bits. Otherwise, set imm_expr to
+ the entire 64 bit constant. */
if (using_gprs ? HAVE_32BIT_GPRS : HAVE_32BIT_FPRS)
{
imm_expr.X_op = O_constant;
offset_expr.X_op = O_constant;
- if (! target_big_endian)
+ if (!target_big_endian)
{
imm_expr.X_add_number = bfd_getl32 (temp + 4);
offset_expr.X_add_number = bfd_getl32 (temp);
else if (sizeof (imm_expr.X_add_number) > 4)
{
imm_expr.X_op = O_constant;
- if (! target_big_endian)
+ if (!target_big_endian)
imm_expr.X_add_number = bfd_getl64 (temp);
else
imm_expr.X_add_number = bfd_getb64 (temp);
{
imm_expr.X_op = O_big;
imm_expr.X_add_number = 4;
- if (! target_big_endian)
+ if (!target_big_endian)
{
generic_bignum[0] = bfd_getl16 (temp);
generic_bignum[1] = bfd_getl16 (temp + 2);
newname = RDATA_SECTION_NAME;
break;
case 'l':
- assert (g_switch_value >= 4);
+ gas_assert (g_switch_value >= 4);
newname = ".lit4";
break;
}
/* Set the argument to the current address in the
section. */
offset_expr.X_op = O_symbol;
- offset_expr.X_add_symbol =
- symbol_new ("L0\001", now_seg,
- (valueT) frag_now_fix (), frag_now);
+ offset_expr.X_add_symbol = symbol_temp_new_now ();
offset_expr.X_add_number = 0;
/* Put the floating point number into the section. */
}
continue;
- case 'i': /* 16 bit unsigned immediate */
- case 'j': /* 16 bit signed immediate */
+ case 'i': /* 16-bit unsigned immediate. */
+ case 'j': /* 16-bit signed immediate. */
*imm_reloc = BFD_RELOC_LO16;
if (my_getSmallExpression (&imm_expr, imm_reloc, s) == 0)
{
break;
if (imm_expr.X_op == O_constant
|| imm_expr.X_op == O_big)
- as_bad (_("expression out of range"));
+ as_bad (_("Expression out of range"));
}
}
s = expr_end;
continue;
- case 'o': /* 16 bit offset */
+ case 'o': /* 16-bit offset. */
+ offset_reloc[0] = BFD_RELOC_LO16;
+ offset_reloc[1] = BFD_RELOC_UNUSED;
+ offset_reloc[2] = BFD_RELOC_UNUSED;
+
/* Check whether there is only a single bracketed expression
left. If so, it must be the base register and the
constant must be zero. */
s = expr_end;
continue;
- case 'p': /* pc relative offset */
+ case 'p': /* PC-relative offset. */
*offset_reloc = BFD_RELOC_16_PCREL_S2;
my_getExpression (&offset_expr, s);
s = expr_end;
continue;
- case 'u': /* upper 16 bits */
+ case 'u': /* Upper 16 bits. */
if (my_getSmallExpression (&imm_expr, imm_reloc, s) == 0
&& imm_expr.X_op == O_constant
&& (imm_expr.X_add_number < 0
|| imm_expr.X_add_number >= 0x10000))
- as_bad (_("lui expression not in range 0..65535"));
+ as_bad (_("lui expression (%lu) not in range 0..65535"),
+ (unsigned long) imm_expr.X_add_number);
s = expr_end;
continue;
- case 'a': /* 26 bit address */
+ case 'a': /* 26-bit address. */
my_getExpression (&offset_expr, s);
s = expr_end;
*offset_reloc = BFD_RELOC_MIPS_JMP;
continue;
- case 'N': /* 3 bit branch condition code */
- case 'M': /* 3 bit compare condition code */
+ case 'N': /* 3-bit branch condition code. */
+ case 'M': /* 3-bit compare condition code. */
rtype = RTYPE_CCC;
- if (ip->insn_mo->pinfo & (FP_D| FP_S))
+ if (ip->insn_mo->pinfo & (FP_D | FP_S))
rtype |= RTYPE_FCC;
if (!reg_lookup (&s, rtype, ®no))
break;
- if ((strcmp(str + strlen(str) - 3, ".ps") == 0
- || strcmp(str + strlen(str) - 5, "any2f") == 0
- || strcmp(str + strlen(str) - 5, "any2t") == 0)
+ if ((strcmp (str + strlen (str) - 3, ".ps") == 0
+ || strcmp (str + strlen (str) - 5, "any2f") == 0
+ || strcmp (str + strlen (str) - 5, "any2t") == 0)
&& (regno & 1) != 0)
- as_warn(_("Condition code register should be even for %s, was %d"),
- str, regno);
- if ((strcmp(str + strlen(str) - 5, "any4f") == 0
- || strcmp(str + strlen(str) - 5, "any4t") == 0)
+ as_warn (_("Condition code register should be even for %s, "
+ "was %d"),
+ str, regno);
+ if ((strcmp (str + strlen (str) - 5, "any4f") == 0
+ || strcmp (str + strlen (str) - 5, "any4t") == 0)
&& (regno & 3) != 0)
- as_warn(_("Condition code register should be 0 or 4 for %s, was %d"),
- str, regno);
+ as_warn (_("Condition code register should be 0 or 4 for %s, "
+ "was %d"),
+ str, regno);
if (*args == 'N')
INSERT_OPERAND (BCC, *ip, regno);
else
c = 8; /* Invalid sel value. */
if (c > 7)
- as_bad (_("invalid coprocessor sub-selection value (0-7)"));
+ as_bad (_("Invalid coprocessor sub-selection value (0-7)"));
ip->insn_opcode |= c;
continue;
continue;
default:
- as_bad (_("bad char = '%c'\n"), *args);
+ as_bad (_("Bad char = '%c'\n"), *args);
internalError ();
}
break;
{
++insn;
s = argsStart;
- insn_error = _("illegal operands");
+ insn_error = _("Illegal operands");
continue;
}
if (save_c)
- *(--s) = save_c;
- insn_error = _("illegal operands");
+ *(--argsStart) = save_c;
+ insn_error = _("Illegal operands");
return;
}
}
{
bfd_boolean ok;
- assert (strcmp (insn->name, str) == 0);
+ gas_assert (strcmp (insn->name, str) == 0);
ok = is_opcode_valid_16 (insn);
if (! ok)
/* Stuff the immediate value in now, if we can. */
if (imm_expr.X_op == O_constant
&& *imm_reloc > BFD_RELOC_UNUSED
+ && *imm_reloc != BFD_RELOC_MIPS16_GOT16
+ && *imm_reloc != BFD_RELOC_MIPS16_CALL16
&& insn->pinfo != INSN_MACRO)
{
valueT tmp;
{
int opcode = 0;
int framesz = 0, seen_framesz = 0;
- int args = 0, statics = 0, sregs = 0;
+ int nargs = 0, statics = 0, sregs = 0;
while (*s != '\0')
{
{
if (!seen_framesz)
/* args $a0-$a3 */
- args |= 1 << (reg1 - 4);
+ nargs |= 1 << (reg1 - 4);
else
/* statics $a0-$a3 */
statics |= 1 << (reg1 - 4);
}
/* Encode args/statics combination. */
- if (args & statics)
+ if (nargs & statics)
as_bad (_("arg/static registers overlap"));
- else if (args == 0xf)
+ else if (nargs == 0xf)
/* All $a0-$a3 are args. */
opcode |= MIPS16_ALL_ARGS << 16;
else if (statics == 0xf)
int narg = 0, nstat = 0;
/* Count arg registers. */
- while (args & 0x1)
+ while (nargs & 0x1)
{
- args >>= 1;
+ nargs >>= 1;
narg++;
}
- if (args != 0)
+ if (nargs != 0)
as_bad (_("invalid arg register list"));
/* Count static registers. */
while (op->type != type)
{
++op;
- assert (op < mips16_immed_operands + MIPS16_NUM_IMMED);
+ gas_assert (op < mips16_immed_operands + MIPS16_NUM_IMMED);
}
if (op->unsp)
{
{"%lo", BFD_RELOC_MIPS16_LO16},
{"%gprel", BFD_RELOC_MIPS16_GPREL},
+ {"%got", BFD_RELOC_MIPS16_GOT16},
+ {"%call16", BFD_RELOC_MIPS16_CALL16},
{"%hi", BFD_RELOC_MIPS16_HI16_S}
};
If not, issue an error and fall back on something safe. */
if (!bfd_reloc_type_lookup (stdoutput, percent_op[i].reloc))
{
- as_bad ("relocation %s isn't supported by the current ABI",
+ as_bad (_("relocation %s isn't supported by the current ABI"),
percent_op[i].str);
*reloc = BFD_RELOC_UNUSED;
}
crux_depth--;
if (crux_depth > 0)
- as_bad ("unclosed '('");
+ as_bad (_("unclosed '('"));
expr_end = str;
my_getExpression (expressionS *ep, char *str)
{
char *save_in;
- valueT val;
save_in = input_line_pointer;
input_line_pointer = str;
expression (ep);
expr_end = input_line_pointer;
input_line_pointer = save_in;
-
- /* If we are in mips16 mode, and this is an expression based on `.',
- then we bump the value of the symbol by 1 since that is how other
- text symbols are handled. We don't bother to handle complex
- expressions, just `.' plus or minus a constant. */
- if (mips_opts.mips16
- && ep->X_op == O_symbol
- && strcmp (S_GET_NAME (ep->X_add_symbol), FAKE_LABEL_NAME) == 0
- && S_GET_SEGMENT (ep->X_add_symbol) == now_seg
- && symbol_get_frag (ep->X_add_symbol) == frag_now
- && symbol_constant_p (ep->X_add_symbol)
- && (val = S_GET_VALUE (ep->X_add_symbol)) == frag_now_fix ())
- S_SET_VALUE (ep->X_add_symbol, val + 1);
}
char *
list = bfd_target_list ();
for (l = list; *l != NULL; l++)
-#ifdef TE_TMIPS
- /* This is traditional mips */
- if (strcmp (*l, "elf64-tradbigmips") == 0
- || strcmp (*l, "elf64-tradlittlemips") == 0)
-#else
- if (strcmp (*l, "elf64-bigmips") == 0
- || strcmp (*l, "elf64-littlemips") == 0)
-#endif
+ if (strcmp (*l, ELF_TARGET ("elf64-", "big")) == 0
+ || strcmp (*l, ELF_TARGET ("elf64-", "little")) == 0)
break;
yes = (*l != NULL);
free (list);
const char *md_shortopts = "O::g::G:";
+enum options
+ {
+ OPTION_MARCH = OPTION_MD_BASE,
+ OPTION_MTUNE,
+ OPTION_MIPS1,
+ OPTION_MIPS2,
+ OPTION_MIPS3,
+ OPTION_MIPS4,
+ OPTION_MIPS5,
+ OPTION_MIPS32,
+ OPTION_MIPS64,
+ OPTION_MIPS32R2,
+ OPTION_MIPS64R2,
+ OPTION_MIPS16,
+ OPTION_NO_MIPS16,
+ OPTION_MIPS3D,
+ OPTION_NO_MIPS3D,
+ OPTION_MDMX,
+ OPTION_NO_MDMX,
+ OPTION_DSP,
+ OPTION_NO_DSP,
+ OPTION_MT,
+ OPTION_NO_MT,
+ OPTION_SMARTMIPS,
+ OPTION_NO_SMARTMIPS,
+ OPTION_DSPR2,
+ OPTION_NO_DSPR2,
+ OPTION_COMPAT_ARCH_BASE,
+ OPTION_M4650,
+ OPTION_NO_M4650,
+ OPTION_M4010,
+ OPTION_NO_M4010,
+ OPTION_M4100,
+ OPTION_NO_M4100,
+ OPTION_M3900,
+ OPTION_NO_M3900,
+ OPTION_M7000_HILO_FIX,
+ OPTION_MNO_7000_HILO_FIX,
+ OPTION_FIX_24K,
+ OPTION_NO_FIX_24K,
+ OPTION_FIX_LOONGSON2F_JUMP,
+ OPTION_NO_FIX_LOONGSON2F_JUMP,
+ OPTION_FIX_LOONGSON2F_NOP,
+ OPTION_NO_FIX_LOONGSON2F_NOP,
+ OPTION_FIX_VR4120,
+ OPTION_NO_FIX_VR4120,
+ OPTION_FIX_VR4130,
+ OPTION_NO_FIX_VR4130,
+ OPTION_FIX_CN63XXP1,
+ OPTION_NO_FIX_CN63XXP1,
+ OPTION_TRAP,
+ OPTION_BREAK,
+ OPTION_EB,
+ OPTION_EL,
+ OPTION_FP32,
+ OPTION_GP32,
+ OPTION_CONSTRUCT_FLOATS,
+ OPTION_NO_CONSTRUCT_FLOATS,
+ OPTION_FP64,
+ OPTION_GP64,
+ OPTION_RELAX_BRANCH,
+ OPTION_NO_RELAX_BRANCH,
+ OPTION_MSHARED,
+ OPTION_MNO_SHARED,
+ OPTION_MSYM32,
+ OPTION_MNO_SYM32,
+ OPTION_SOFT_FLOAT,
+ OPTION_HARD_FLOAT,
+ OPTION_SINGLE_FLOAT,
+ OPTION_DOUBLE_FLOAT,
+ OPTION_32,
+#ifdef OBJ_ELF
+ OPTION_CALL_SHARED,
+ OPTION_CALL_NONPIC,
+ OPTION_NON_SHARED,
+ OPTION_XGOT,
+ OPTION_MABI,
+ OPTION_N32,
+ OPTION_64,
+ OPTION_MDEBUG,
+ OPTION_NO_MDEBUG,
+ OPTION_PDR,
+ OPTION_NO_PDR,
+ OPTION_MVXWORKS_PIC,
+#endif /* OBJ_ELF */
+ OPTION_END_OF_ENUM
+ };
+
struct option md_longopts[] =
{
/* Options which specify architecture. */
-#define OPTION_ARCH_BASE (OPTION_MD_BASE)
-#define OPTION_MARCH (OPTION_ARCH_BASE + 0)
{"march", required_argument, NULL, OPTION_MARCH},
-#define OPTION_MTUNE (OPTION_ARCH_BASE + 1)
{"mtune", required_argument, NULL, OPTION_MTUNE},
-#define OPTION_MIPS1 (OPTION_ARCH_BASE + 2)
{"mips0", no_argument, NULL, OPTION_MIPS1},
{"mips1", no_argument, NULL, OPTION_MIPS1},
-#define OPTION_MIPS2 (OPTION_ARCH_BASE + 3)
{"mips2", no_argument, NULL, OPTION_MIPS2},
-#define OPTION_MIPS3 (OPTION_ARCH_BASE + 4)
{"mips3", no_argument, NULL, OPTION_MIPS3},
-#define OPTION_MIPS4 (OPTION_ARCH_BASE + 5)
{"mips4", no_argument, NULL, OPTION_MIPS4},
-#define OPTION_MIPS5 (OPTION_ARCH_BASE + 6)
{"mips5", no_argument, NULL, OPTION_MIPS5},
-#define OPTION_MIPS32 (OPTION_ARCH_BASE + 7)
{"mips32", no_argument, NULL, OPTION_MIPS32},
-#define OPTION_MIPS64 (OPTION_ARCH_BASE + 8)
{"mips64", no_argument, NULL, OPTION_MIPS64},
-#define OPTION_MIPS32R2 (OPTION_ARCH_BASE + 9)
{"mips32r2", no_argument, NULL, OPTION_MIPS32R2},
-#define OPTION_MIPS64R2 (OPTION_ARCH_BASE + 10)
{"mips64r2", no_argument, NULL, OPTION_MIPS64R2},
/* Options which specify Application Specific Extensions (ASEs). */
-#define OPTION_ASE_BASE (OPTION_ARCH_BASE + 11)
-#define OPTION_MIPS16 (OPTION_ASE_BASE + 0)
{"mips16", no_argument, NULL, OPTION_MIPS16},
-#define OPTION_NO_MIPS16 (OPTION_ASE_BASE + 1)
{"no-mips16", no_argument, NULL, OPTION_NO_MIPS16},
-#define OPTION_MIPS3D (OPTION_ASE_BASE + 2)
{"mips3d", no_argument, NULL, OPTION_MIPS3D},
-#define OPTION_NO_MIPS3D (OPTION_ASE_BASE + 3)
{"no-mips3d", no_argument, NULL, OPTION_NO_MIPS3D},
-#define OPTION_MDMX (OPTION_ASE_BASE + 4)
{"mdmx", no_argument, NULL, OPTION_MDMX},
-#define OPTION_NO_MDMX (OPTION_ASE_BASE + 5)
{"no-mdmx", no_argument, NULL, OPTION_NO_MDMX},
-#define OPTION_DSP (OPTION_ASE_BASE + 6)
{"mdsp", no_argument, NULL, OPTION_DSP},
-#define OPTION_NO_DSP (OPTION_ASE_BASE + 7)
{"mno-dsp", no_argument, NULL, OPTION_NO_DSP},
-#define OPTION_MT (OPTION_ASE_BASE + 8)
{"mmt", no_argument, NULL, OPTION_MT},
-#define OPTION_NO_MT (OPTION_ASE_BASE + 9)
{"mno-mt", no_argument, NULL, OPTION_NO_MT},
-#define OPTION_SMARTMIPS (OPTION_ASE_BASE + 10)
{"msmartmips", no_argument, NULL, OPTION_SMARTMIPS},
-#define OPTION_NO_SMARTMIPS (OPTION_ASE_BASE + 11)
{"mno-smartmips", no_argument, NULL, OPTION_NO_SMARTMIPS},
-#define OPTION_DSPR2 (OPTION_ASE_BASE + 12)
{"mdspr2", no_argument, NULL, OPTION_DSPR2},
-#define OPTION_NO_DSPR2 (OPTION_ASE_BASE + 13)
{"mno-dspr2", no_argument, NULL, OPTION_NO_DSPR2},
/* Old-style architecture options. Don't add more of these. */
-#define OPTION_COMPAT_ARCH_BASE (OPTION_ASE_BASE + 14)
-#define OPTION_M4650 (OPTION_COMPAT_ARCH_BASE + 0)
{"m4650", no_argument, NULL, OPTION_M4650},
-#define OPTION_NO_M4650 (OPTION_COMPAT_ARCH_BASE + 1)
{"no-m4650", no_argument, NULL, OPTION_NO_M4650},
-#define OPTION_M4010 (OPTION_COMPAT_ARCH_BASE + 2)
{"m4010", no_argument, NULL, OPTION_M4010},
-#define OPTION_NO_M4010 (OPTION_COMPAT_ARCH_BASE + 3)
{"no-m4010", no_argument, NULL, OPTION_NO_M4010},
-#define OPTION_M4100 (OPTION_COMPAT_ARCH_BASE + 4)
{"m4100", no_argument, NULL, OPTION_M4100},
-#define OPTION_NO_M4100 (OPTION_COMPAT_ARCH_BASE + 5)
{"no-m4100", no_argument, NULL, OPTION_NO_M4100},
-#define OPTION_M3900 (OPTION_COMPAT_ARCH_BASE + 6)
{"m3900", no_argument, NULL, OPTION_M3900},
-#define OPTION_NO_M3900 (OPTION_COMPAT_ARCH_BASE + 7)
{"no-m3900", no_argument, NULL, OPTION_NO_M3900},
/* Options which enable bug fixes. */
-#define OPTION_FIX_BASE (OPTION_COMPAT_ARCH_BASE + 8)
-#define OPTION_M7000_HILO_FIX (OPTION_FIX_BASE + 0)
{"mfix7000", no_argument, NULL, OPTION_M7000_HILO_FIX},
-#define OPTION_MNO_7000_HILO_FIX (OPTION_FIX_BASE + 1)
{"no-fix-7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
{"mno-fix7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
-#define OPTION_FIX_VR4120 (OPTION_FIX_BASE + 2)
-#define OPTION_NO_FIX_VR4120 (OPTION_FIX_BASE + 3)
+ {"mfix-loongson2f-jump", no_argument, NULL, OPTION_FIX_LOONGSON2F_JUMP},
+ {"mno-fix-loongson2f-jump", no_argument, NULL, OPTION_NO_FIX_LOONGSON2F_JUMP},
+ {"mfix-loongson2f-nop", no_argument, NULL, OPTION_FIX_LOONGSON2F_NOP},
+ {"mno-fix-loongson2f-nop", no_argument, NULL, OPTION_NO_FIX_LOONGSON2F_NOP},
{"mfix-vr4120", no_argument, NULL, OPTION_FIX_VR4120},
{"mno-fix-vr4120", no_argument, NULL, OPTION_NO_FIX_VR4120},
-#define OPTION_FIX_VR4130 (OPTION_FIX_BASE + 4)
-#define OPTION_NO_FIX_VR4130 (OPTION_FIX_BASE + 5)
{"mfix-vr4130", no_argument, NULL, OPTION_FIX_VR4130},
{"mno-fix-vr4130", no_argument, NULL, OPTION_NO_FIX_VR4130},
+ {"mfix-24k", no_argument, NULL, OPTION_FIX_24K},
+ {"mno-fix-24k", no_argument, NULL, OPTION_NO_FIX_24K},
+ {"mfix-cn63xxp1", no_argument, NULL, OPTION_FIX_CN63XXP1},
+ {"mno-fix-cn63xxp1", no_argument, NULL, OPTION_NO_FIX_CN63XXP1},
/* Miscellaneous options. */
-#define OPTION_MISC_BASE (OPTION_FIX_BASE + 6)
-#define OPTION_TRAP (OPTION_MISC_BASE + 0)
{"trap", no_argument, NULL, OPTION_TRAP},
{"no-break", no_argument, NULL, OPTION_TRAP},
-#define OPTION_BREAK (OPTION_MISC_BASE + 1)
{"break", no_argument, NULL, OPTION_BREAK},
{"no-trap", no_argument, NULL, OPTION_BREAK},
-#define OPTION_EB (OPTION_MISC_BASE + 2)
{"EB", no_argument, NULL, OPTION_EB},
-#define OPTION_EL (OPTION_MISC_BASE + 3)
{"EL", no_argument, NULL, OPTION_EL},
-#define OPTION_FP32 (OPTION_MISC_BASE + 4)
{"mfp32", no_argument, NULL, OPTION_FP32},
-#define OPTION_GP32 (OPTION_MISC_BASE + 5)
{"mgp32", no_argument, NULL, OPTION_GP32},
-#define OPTION_CONSTRUCT_FLOATS (OPTION_MISC_BASE + 6)
{"construct-floats", no_argument, NULL, OPTION_CONSTRUCT_FLOATS},
-#define OPTION_NO_CONSTRUCT_FLOATS (OPTION_MISC_BASE + 7)
{"no-construct-floats", no_argument, NULL, OPTION_NO_CONSTRUCT_FLOATS},
-#define OPTION_FP64 (OPTION_MISC_BASE + 8)
{"mfp64", no_argument, NULL, OPTION_FP64},
-#define OPTION_GP64 (OPTION_MISC_BASE + 9)
{"mgp64", no_argument, NULL, OPTION_GP64},
-#define OPTION_RELAX_BRANCH (OPTION_MISC_BASE + 10)
-#define OPTION_NO_RELAX_BRANCH (OPTION_MISC_BASE + 11)
{"relax-branch", no_argument, NULL, OPTION_RELAX_BRANCH},
{"no-relax-branch", no_argument, NULL, OPTION_NO_RELAX_BRANCH},
-#define OPTION_MSHARED (OPTION_MISC_BASE + 12)
-#define OPTION_MNO_SHARED (OPTION_MISC_BASE + 13)
{"mshared", no_argument, NULL, OPTION_MSHARED},
{"mno-shared", no_argument, NULL, OPTION_MNO_SHARED},
-#define OPTION_MSYM32 (OPTION_MISC_BASE + 14)
-#define OPTION_MNO_SYM32 (OPTION_MISC_BASE + 15)
{"msym32", no_argument, NULL, OPTION_MSYM32},
{"mno-sym32", no_argument, NULL, OPTION_MNO_SYM32},
-#define OPTION_SOFT_FLOAT (OPTION_MISC_BASE + 16)
-#define OPTION_HARD_FLOAT (OPTION_MISC_BASE + 17)
{"msoft-float", no_argument, NULL, OPTION_SOFT_FLOAT},
{"mhard-float", no_argument, NULL, OPTION_HARD_FLOAT},
-#define OPTION_SINGLE_FLOAT (OPTION_MISC_BASE + 18)
-#define OPTION_DOUBLE_FLOAT (OPTION_MISC_BASE + 19)
{"msingle-float", no_argument, NULL, OPTION_SINGLE_FLOAT},
{"mdouble-float", no_argument, NULL, OPTION_DOUBLE_FLOAT},
+
+ /* Strictly speaking this next option is ELF specific,
+ but we allow it for other ports as well in order to
+ make testing easier. */
+ {"32", no_argument, NULL, OPTION_32},
/* ELF-specific options. */
#ifdef OBJ_ELF
-#define OPTION_ELF_BASE (OPTION_MISC_BASE + 20)
-#define OPTION_CALL_SHARED (OPTION_ELF_BASE + 0)
{"KPIC", no_argument, NULL, OPTION_CALL_SHARED},
{"call_shared", no_argument, NULL, OPTION_CALL_SHARED},
-#define OPTION_NON_SHARED (OPTION_ELF_BASE + 1)
+ {"call_nonpic", no_argument, NULL, OPTION_CALL_NONPIC},
{"non_shared", no_argument, NULL, OPTION_NON_SHARED},
-#define OPTION_XGOT (OPTION_ELF_BASE + 2)
{"xgot", no_argument, NULL, OPTION_XGOT},
-#define OPTION_MABI (OPTION_ELF_BASE + 3)
{"mabi", required_argument, NULL, OPTION_MABI},
-#define OPTION_32 (OPTION_ELF_BASE + 4)
- {"32", no_argument, NULL, OPTION_32},
-#define OPTION_N32 (OPTION_ELF_BASE + 5)
{"n32", no_argument, NULL, OPTION_N32},
-#define OPTION_64 (OPTION_ELF_BASE + 6)
{"64", no_argument, NULL, OPTION_64},
-#define OPTION_MDEBUG (OPTION_ELF_BASE + 7)
{"mdebug", no_argument, NULL, OPTION_MDEBUG},
-#define OPTION_NO_MDEBUG (OPTION_ELF_BASE + 8)
{"no-mdebug", no_argument, NULL, OPTION_NO_MDEBUG},
-#define OPTION_PDR (OPTION_ELF_BASE + 9)
{"mpdr", no_argument, NULL, OPTION_PDR},
-#define OPTION_NO_PDR (OPTION_ELF_BASE + 10)
{"mno-pdr", no_argument, NULL, OPTION_NO_PDR},
-#define OPTION_MVXWORKS_PIC (OPTION_ELF_BASE + 11)
{"mvxworks-pic", no_argument, NULL, OPTION_MVXWORKS_PIC},
#endif /* OBJ_ELF */
mips_opts.ase_smartmips = 0;
break;
+ case OPTION_FIX_24K:
+ mips_fix_24k = 1;
+ break;
+
+ case OPTION_NO_FIX_24K:
+ mips_fix_24k = 0;
+ break;
+
+ case OPTION_FIX_LOONGSON2F_JUMP:
+ mips_fix_loongson2f_jump = TRUE;
+ break;
+
+ case OPTION_NO_FIX_LOONGSON2F_JUMP:
+ mips_fix_loongson2f_jump = FALSE;
+ break;
+
+ case OPTION_FIX_LOONGSON2F_NOP:
+ mips_fix_loongson2f_nop = TRUE;
+ break;
+
+ case OPTION_NO_FIX_LOONGSON2F_NOP:
+ mips_fix_loongson2f_nop = FALSE;
+ break;
+
case OPTION_FIX_VR4120:
mips_fix_vr4120 = 1;
break;
mips_fix_vr4130 = 0;
break;
+ case OPTION_FIX_CN63XXP1:
+ mips_fix_cn63xxp1 = TRUE;
+ break;
+
+ case OPTION_NO_FIX_CN63XXP1:
+ mips_fix_cn63xxp1 = FALSE;
+ break;
+
case OPTION_RELAX_BRANCH:
mips_relax_branch = 1;
break;
mips_abicalls = TRUE;
break;
+ case OPTION_CALL_NONPIC:
+ if (!IS_ELF)
+ {
+ as_bad (_("-call_nonpic is supported only for ELF format"));
+ return 0;
+ }
+ mips_pic = NO_PIC;
+ mips_abicalls = TRUE;
+ break;
+
case OPTION_NON_SHARED:
if (!IS_ELF)
{
g_switch_seen = 1;
break;
-#ifdef OBJ_ELF
/* The -32, -n32 and -64 options are shortcuts for -mabi=32, -mabi=n32
and -mabi=64. */
case OPTION_32:
- if (!IS_ELF)
- {
- as_bad (_("-32 is supported for ELF format only"));
- return 0;
- }
- mips_abi = O32_ABI;
+ if (IS_ELF)
+ mips_abi = O32_ABI;
+ /* We silently ignore -32 for non-ELF targets. This greatly
+ simplifies the construction of the MIPS GAS test cases. */
break;
+#ifdef OBJ_ELF
case OPTION_N32:
if (!IS_ELF)
{
return 0;
}
+ mips_fix_loongson2f = mips_fix_loongson2f_nop || mips_fix_loongson2f_jump;
+
return 1;
}
\f
arch_info = mips_parse_cpu ("default CPU", MIPS_CPU_STRING_DEFAULT);
if (ABI_NEEDS_64BIT_REGS (mips_abi) && !ISA_HAS_64BIT_REGS (arch_info->isa))
- as_bad ("-march=%s is not compatible with the selected ABI",
+ as_bad (_("-march=%s is not compatible with the selected ABI"),
arch_info->name);
mips_set_architecture (arch_info);
if (mips_opts.ase_smartmips == -1)
mips_opts.ase_smartmips = (arch_info->flags & MIPS_CPU_ASE_SMARTMIPS) ? 1 : 0;
if (mips_opts.ase_smartmips && !ISA_SUPPORTS_SMARTMIPS)
- as_warn ("%s ISA does not support SmartMIPS",
- mips_cpu_info_from_isa (mips_opts.isa)->name);
+ as_warn (_("%s ISA does not support SmartMIPS"),
+ mips_cpu_info_from_isa (mips_opts.isa)->name);
if (mips_opts.ase_dsp == -1)
mips_opts.ase_dsp = (arch_info->flags & MIPS_CPU_ASE_DSP) ? 1 : 0;
if (mips_opts.ase_dsp && !ISA_SUPPORTS_DSP_ASE)
- as_warn ("%s ISA does not support DSP ASE",
- mips_cpu_info_from_isa (mips_opts.isa)->name);
+ as_warn (_("%s ISA does not support DSP ASE"),
+ mips_cpu_info_from_isa (mips_opts.isa)->name);
if (mips_opts.ase_dspr2 == -1)
{
mips_opts.ase_dsp = (arch_info->flags & MIPS_CPU_ASE_DSP) ? 1 : 0;
}
if (mips_opts.ase_dspr2 && !ISA_SUPPORTS_DSPR2_ASE)
- as_warn ("%s ISA does not support DSP R2 ASE",
- mips_cpu_info_from_isa (mips_opts.isa)->name);
+ as_warn (_("%s ISA does not support DSP R2 ASE"),
+ mips_cpu_info_from_isa (mips_opts.isa)->name);
if (mips_opts.ase_mt == -1)
mips_opts.ase_mt = (arch_info->flags & MIPS_CPU_ASE_MT) ? 1 : 0;
if (mips_opts.ase_mt && !ISA_SUPPORTS_MT_ASE)
- as_warn ("%s ISA does not support MT ASE",
- mips_cpu_info_from_isa (mips_opts.isa)->name);
+ as_warn (_("%s ISA does not support MT ASE"),
+ mips_cpu_info_from_isa (mips_opts.isa)->name);
file_mips_isa = mips_opts.isa;
- file_ase_mips16 = mips_opts.mips16;
file_ase_mips3d = mips_opts.ase_mips3d;
file_ase_mdmx = mips_opts.ase_mdmx;
file_ase_smartmips = mips_opts.ase_smartmips;
bfd_boolean matched_lo_p;
fixS **hi_pos, **lo_pos, **pos;
- assert (reloc_needs_lo_p (l->fixp->fx_r_type));
+ gas_assert (reloc_needs_lo_p (l->fixp->fx_r_type));
/* If a GOT16 relocation turns out to be against a global symbol,
there isn't supposed to be a matching LO. */
- if (l->fixp->fx_r_type == BFD_RELOC_MIPS_GOT16
+ if (got16_reloc_p (l->fixp->fx_r_type)
&& !pic_need_relax (l->fixp->fx_addsy, l->seg))
continue;
hi_pos = NULL;
lo_pos = NULL;
matched_lo_p = FALSE;
-
- if (l->fixp->fx_r_type == BFD_RELOC_MIPS16_HI16
- || l->fixp->fx_r_type == BFD_RELOC_MIPS16_HI16_S)
- looking_for_rtype = BFD_RELOC_MIPS16_LO16;
- else
- looking_for_rtype = BFD_RELOC_LO16;
+ looking_for_rtype = matching_lo_reloc (l->fixp->fx_r_type);
for (pos = &seginfo->fix_root; *pos != NULL; pos = &(*pos)->fx_next)
{
hi_pos = pos;
if ((*pos)->fx_r_type == looking_for_rtype
- && (*pos)->fx_addsy == l->fixp->fx_addsy
+ && symbol_same_p ((*pos)->fx_addsy, l->fixp->fx_addsy)
&& (*pos)->fx_offset >= l->fixp->fx_offset
&& (lo_pos == NULL
|| (*pos)->fx_offset < (*lo_pos)->fx_offset
if (HAVE_NEWABI
&& S_GET_SEGMENT (fixp->fx_addsy) == bfd_abs_section_ptr
&& (fixp->fx_r_type == BFD_RELOC_MIPS_SUB
- || fixp->fx_r_type == BFD_RELOC_HI16_S
- || fixp->fx_r_type == BFD_RELOC_LO16))
+ || hi16_reloc_p (fixp->fx_r_type)
+ || lo16_reloc_p (fixp->fx_r_type)))
return 1;
return 0;
if (! howto)
return;
- assert (fixP->fx_size == 4
- || fixP->fx_r_type == BFD_RELOC_16
- || fixP->fx_r_type == BFD_RELOC_64
- || fixP->fx_r_type == BFD_RELOC_CTOR
- || fixP->fx_r_type == BFD_RELOC_MIPS_SUB
- || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
- || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY
- || fixP->fx_r_type == BFD_RELOC_MIPS_TLS_DTPREL64);
+ gas_assert (fixP->fx_size == 4
+ || fixP->fx_r_type == BFD_RELOC_16
+ || fixP->fx_r_type == BFD_RELOC_64
+ || fixP->fx_r_type == BFD_RELOC_CTOR
+ || fixP->fx_r_type == BFD_RELOC_MIPS_SUB
+ || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+ || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY
+ || fixP->fx_r_type == BFD_RELOC_MIPS_TLS_DTPREL64);
buf = (bfd_byte *) (fixP->fx_frag->fr_literal + fixP->fx_where);
- assert (!fixP->fx_pcrel || fixP->fx_r_type == BFD_RELOC_16_PCREL_S2);
+ gas_assert (!fixP->fx_pcrel || fixP->fx_r_type == BFD_RELOC_16_PCREL_S2);
/* Don't treat parts of a composite relocation as done. There are two
reasons for this:
case BFD_RELOC_MIPS_CALL_HI16:
case BFD_RELOC_MIPS_CALL_LO16:
case BFD_RELOC_MIPS16_GPREL:
+ case BFD_RELOC_MIPS16_GOT16:
+ case BFD_RELOC_MIPS16_CALL16:
case BFD_RELOC_MIPS16_HI16:
case BFD_RELOC_MIPS16_HI16_S:
case BFD_RELOC_MIPS16_JMP:
record_alignment (now_seg, to);
if (label != NULL)
{
- assert (S_GET_SEGMENT (label) == now_seg);
+ gas_assert (S_GET_SEGMENT (label) == now_seg);
symbol_set_frag (label, frag_now);
S_SET_VALUE (label, (valueT) frag_now_fix ());
}
#endif
mips_emit_delays ();
+
switch (sec)
{
case 't':
}
demand_empty_rest_of_line ();
break;
+
+ case 'B':
+ seg = subseg_new (".sbss", (subsegT) get_absolute_expression ());
+ if (IS_ELF)
+ {
+ bfd_set_section_flags (stdoutput, seg, SEC_ALLOC);
+ if (strncmp (TARGET_OS, "elf", 3) != 0)
+ record_alignment (seg, 4);
+ }
+ demand_empty_rest_of_line ();
+ break;
}
auto_align = 1;
section_alignment = get_absolute_expression ();
else
section_alignment = 0;
+ /* FIXME: really ignore? */
+ (void) section_alignment;
section_name = xstrdup (section_name);
mips_emit_delays ();
if (log_size > 0 && auto_align)
mips_align (log_size, 0, label);
- mips_clear_insn_labels ();
cons (1 << log_size);
+ mips_clear_insn_labels ();
}
static void
mips_align (2, 0, label);
}
- mips_clear_insn_labels ();
-
float_cons (type);
+ mips_clear_insn_labels ();
}
/* Handle .globl. We need to override it because on Irix 5 you are
else if (strcmp (name, "gp=64") == 0)
{
if (!ISA_HAS_64BIT_REGS (mips_opts.isa))
- as_warn ("%s isa does not support 64-bit registers",
+ as_warn (_("%s isa does not support 64-bit registers"),
mips_cpu_info_from_isa (mips_opts.isa)->name);
mips_opts.gp32 = 0;
}
else if (strcmp (name, "fp=64") == 0)
{
if (!ISA_HAS_64BIT_FPRS (mips_opts.isa))
- as_warn ("%s isa does not support 64-bit floating point registers",
+ as_warn (_("%s isa does not support 64-bit floating point registers"),
mips_cpu_info_from_isa (mips_opts.isa)->name);
mips_opts.fp32 = 0;
}
else if (strcmp (name, "smartmips") == 0)
{
if (!ISA_SUPPORTS_SMARTMIPS)
- as_warn ("%s ISA does not support SmartMIPS ASE",
+ as_warn (_("%s ISA does not support SmartMIPS ASE"),
mips_cpu_info_from_isa (mips_opts.isa)->name);
mips_opts.ase_smartmips = 1;
}
else if (strcmp (name, "dsp") == 0)
{
if (!ISA_SUPPORTS_DSP_ASE)
- as_warn ("%s ISA does not support DSP ASE",
+ as_warn (_("%s ISA does not support DSP ASE"),
mips_cpu_info_from_isa (mips_opts.isa)->name);
mips_opts.ase_dsp = 1;
mips_opts.ase_dspr2 = 0;
else if (strcmp (name, "dspr2") == 0)
{
if (!ISA_SUPPORTS_DSPR2_ASE)
- as_warn ("%s ISA does not support DSP R2 ASE",
+ as_warn (_("%s ISA does not support DSP R2 ASE"),
mips_cpu_info_from_isa (mips_opts.isa)->name);
mips_opts.ase_dspr2 = 1;
mips_opts.ase_dsp = 1;
else if (strcmp (name, "mt") == 0)
{
if (!ISA_SUPPORTS_MT_ASE)
- as_warn ("%s ISA does not support MT ASE",
+ as_warn (_("%s ISA does not support MT ASE"),
mips_cpu_info_from_isa (mips_opts.isa)->name);
mips_opts.ase_mt = 1;
}
mips_emit_delays ();
if (auto_align)
mips_align (2, 0, label);
- mips_clear_insn_labels ();
expression (&ex);
+ mips_clear_insn_labels ();
if (ex.X_op != O_symbol || ex.X_add_number != 0)
{
mips_emit_delays ();
if (auto_align)
mips_align (3, 0, label);
- mips_clear_insn_labels ();
expression (&ex);
+ mips_clear_insn_labels ();
if (ex.X_op != O_symbol || ex.X_add_number != 0)
{
{
if (S_IS_DEFINED (symbolP))
{
- as_bad ("ignoring attempt to redefine symbol %s",
+ as_bad (_("ignoring attempt to redefine symbol %s"),
S_GET_NAME (symbolP));
ignore_rest_of_line ();
return;
expression (&exp);
if (exp.X_op != O_symbol)
{
- as_bad ("bad .weakext directive");
+ as_bad (_("bad .weakext directive"));
ignore_rest_of_line ();
return;
}
const char *segname;
segname = segment_name (S_GET_SEGMENT (sym));
- assert (strcmp (segname, ".lit8") != 0
+ gas_assert (strcmp (segname, ".lit8") != 0
&& strcmp (segname, ".lit4") != 0);
change = (strcmp (segname, ".sdata") != 0
&& strcmp (segname, ".sbss") != 0
while (op->type != type)
{
++op;
- assert (op < mips16_immed_operands + MIPS16_NUM_IMMED);
+ gas_assert (op < mips16_immed_operands + MIPS16_NUM_IMMED);
}
if (op->unsp)
if (fragp && update && toofar != RELAX_BRANCH_TOOFAR (fragp->fr_subtype))
fragp->fr_subtype
- = RELAX_BRANCH_ENCODE (RELAX_BRANCH_UNCOND (fragp->fr_subtype),
+ = RELAX_BRANCH_ENCODE (RELAX_BRANCH_AT (fragp->fr_subtype),
+ RELAX_BRANCH_UNCOND (fragp->fr_subtype),
RELAX_BRANCH_LIKELY (fragp->fr_subtype),
RELAX_BRANCH_LINK (fragp->fr_subtype),
toofar);
placed anywhere. Rather than break backwards compatibility by changing
this, it seems better not to force the issue, and instead keep the
original symbol. This will work with either linker behavior. */
- if ((fixp->fx_r_type == BFD_RELOC_LO16
- || fixp->fx_r_type == BFD_RELOC_MIPS16_LO16
+ if ((lo16_reloc_p (fixp->fx_r_type)
|| reloc_needs_lo_p (fixp->fx_r_type))
&& HAVE_IN_PLACE_ADDENDS
&& (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_MERGE) != 0)
return 0;
+ /* There is no place to store an in-place offset for JALR relocations.
+ Likewise an in-range offset of PC-relative relocations may overflow
+ the in-place relocatable field if recalculated against the start
+ address of the symbol's containing section. */
+ if (HAVE_IN_PLACE_ADDENDS
+ && (fixp->fx_pcrel || fixp->fx_r_type == BFD_RELOC_MIPS_JALR))
+ return 0;
+
#ifdef OBJ_ELF
/* R_MIPS16_26 relocations against non-MIPS16 functions might resolve
to a floating-point stub. The same is true for non-R_MIPS16_26
that we have for MIPS16 symbols. */
if (IS_ELF
&& fixp->fx_subsy == NULL
- && (S_GET_OTHER (fixp->fx_addsy) == STO_MIPS16
+ && (ELF_ST_IS_MIPS16 (S_GET_OTHER (fixp->fx_addsy))
|| *symbol_get_tc (fixp->fx_addsy)))
return 0;
#endif
if (fixp->fx_pcrel)
{
- assert (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2);
+ gas_assert (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2);
/* At this point, fx_addnumber is "symbol offset - pcrel address".
Relocations want only the symbol offset. */
int i;
as_warn_where (fragp->fr_file, fragp->fr_line,
- _("relaxed out-of-range branch into a jump"));
+ _("Relaxed out-of-range branch into a jump"));
if (RELAX_BRANCH_UNCOND (fragp->fr_subtype))
goto uncond;
/* bc[0-3][tf]l? and bc1any[24][ft] instructions can
have the condition reversed by tweaking a single
bit, and their opcodes all have 0x4???????. */
- assert ((insn & 0xf1000000) == 0x41000000);
+ gas_assert ((insn & 0xf1000000) == 0x41000000);
insn ^= 0x00010000;
break;
case 0:
/* bltz 0x04000000 bgez 0x04010000
bltzal 0x04100000 bgezal 0x04110000 */
- assert ((insn & 0xfc0e0000) == 0x04000000);
+ gas_assert ((insn & 0xfc0e0000) == 0x04000000);
insn ^= 0x00010000;
break;
if (RELAX_BRANCH_LINK (fragp->fr_subtype))
{
/* Clear the and-link bit. */
- assert ((insn & 0xfc1c0000) == 0x04100000);
+ gas_assert ((insn & 0xfc1c0000) == 0x04100000);
/* bltzal 0x04100000 bgezal 0x04110000
bltzall 0x04120000 bgezall 0x04130000 */
}
else
{
+ unsigned long at = RELAX_BRANCH_AT (fragp->fr_subtype);
+
/* lw/ld $at, <sym>($gp) R_MIPS_GOT16 */
- insn = HAVE_64BIT_ADDRESSES ? 0xdf810000 : 0x8f810000;
+ insn = HAVE_64BIT_ADDRESSES ? 0xdf800000 : 0x8f800000;
+ insn |= at << OP_SH_RT;
exp.X_op = O_symbol;
exp.X_add_symbol = fragp->fr_symbol;
exp.X_add_number = fragp->fr_offset;
}
/* d/addiu $at, $at, <sym> R_MIPS_LO16 */
- insn = HAVE_64BIT_ADDRESSES ? 0x64210000 : 0x24210000;
+ insn = HAVE_64BIT_ADDRESSES ? 0x64000000 : 0x24000000;
+ insn |= at << OP_SH_RS | at << OP_SH_RT;
fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
4, &exp, FALSE, BFD_RELOC_LO16);
/* j(al)r $at. */
if (RELAX_BRANCH_LINK (fragp->fr_subtype))
- insn = 0x0020f809;
+ insn = 0x0000f809;
else
- insn = 0x00200008;
+ insn = 0x00000008;
+ insn |= at << OP_SH_RS;
md_number_to_chars ((char *) buf, insn, 4);
buf += 4;
}
}
- assert (buf == (bfd_byte *)fragp->fr_literal
+ gas_assert (buf == (bfd_byte *)fragp->fr_literal
+ fragp->fr_fix + fragp->fr_var);
fragp->fr_fix += fragp->fr_var;
ext = FALSE;
}
- resolve_symbol_value (fragp->fr_symbol);
- val = S_GET_VALUE (fragp->fr_symbol);
+ val = resolve_symbol_value (fragp->fr_symbol);
if (op->pcrel)
{
addressT addr;
{
const char *msg = macro_warning (fragp->fr_subtype);
if (msg != 0)
- as_warn_where (fragp->fr_file, fragp->fr_line, msg);
+ as_warn_where (fragp->fr_file, fragp->fr_line, "%s", msg);
}
/* Go through all the fixups for the first sequence. Disable them
count = bfd_get_symcount (stdoutput);
for (i = 0; i < count; i++, syms++)
{
- if (elf_symbol (*syms)->internal_elf_sym.st_other == STO_MIPS16
+ if (ELF_ST_IS_MIPS16 (elf_symbol (*syms)->internal_elf_sym.st_other)
&& ((*syms)->value & 1) != 0)
{
(*syms)->value &= ~1;
#endif
-/* This function is called whenever a label is defined. It is used
- when handling branch delays; if a branch has a label, we assume we
- can not move it. */
+/* This function is called whenever a label is defined, including fake
+ labels instantiated off the dot special symbol. It is used when
+ handling branch delays; if a branch has a label, we assume we cannot
+ move it. This also bumps the value of the symbol by 1 in compressed
+ code. */
void
-mips_define_label (symbolS *sym)
+mips_record_label (symbolS *sym)
{
segment_info_type *si = seg_info (now_seg);
struct insn_label_list *l;
l->label = sym;
l->next = si->label_list;
si->label_list = l;
+}
+
+/* This function is called as tc_frob_label() whenever a label is defined
+ and adds a DWARF-2 record we only want for true labels. */
+void
+mips_define_label (symbolS *sym)
+{
+ mips_record_label (sym);
#ifdef OBJ_ELF
dwarf2_emit_label (sym);
#endif
mips_handle_align (fragS *fragp)
{
char *p;
+ int bytes, size, excess;
+ valueT opcode;
if (fragp->fr_type != rs_align_code)
return;
p = fragp->fr_literal + fragp->fr_fix;
if (*p)
{
- int bytes;
+ opcode = mips16_nop_insn.insn_opcode;
+ size = 2;
+ }
+ else
+ {
+ opcode = nop_insn.insn_opcode;
+ size = 4;
+ }
- bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
- if (bytes & 1)
- {
- *p++ = 0;
- fragp->fr_fix++;
- }
- md_number_to_chars (p, mips16_nop_insn.insn_opcode, 2);
- fragp->fr_var = 2;
+ bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
+ excess = bytes % size;
+ if (excess != 0)
+ {
+ /* If we're not inserting a whole number of instructions,
+ pad the end of the fixed part of the frag with zeros. */
+ memset (p, 0, excess);
+ p += excess;
+ fragp->fr_fix += excess;
}
+
+ md_number_to_chars (p, opcode, size);
+ fragp->fr_var = size;
}
static void
if (p != NULL)
{
- assert (S_GET_NAME (p));
+ gas_assert (S_GET_NAME (p));
if (strcmp (S_GET_NAME (p), S_GET_NAME (cur_proc_ptr->func_sym)))
as_warn (_(".end symbol does not match .ent symbol."));
{
segT saved_seg = now_seg;
subsegT saved_subseg = now_subseg;
- valueT dot;
expressionS exp;
char *fragp;
- dot = frag_now_fix ();
-
#ifdef md_flush_pending_output
md_flush_pending_output ();
#endif
- assert (pdr_seg);
+ gas_assert (pdr_seg);
subseg_set (pdr_seg, 0);
/* Write the symbol. */
cur_proc_ptr->func_sym = symbolP;
- symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
-
++numprocs;
if (debug_type == DEBUG_STABS)
S_GET_NAME (symbolP));
}
+ symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
+
demand_empty_rest_of_line ();
}
{ "r8000", 0, ISA_MIPS4, CPU_R8000 },
{ "r10000", 0, ISA_MIPS4, CPU_R10000 },
{ "r12000", 0, ISA_MIPS4, CPU_R12000 },
+ { "r14000", 0, ISA_MIPS4, CPU_R14000 },
+ { "r16000", 0, ISA_MIPS4, CPU_R16000 },
{ "vr5000", 0, ISA_MIPS4, CPU_R5000 },
{ "vr5400", 0, ISA_MIPS4, CPU_VR5400 },
{ "vr5500", 0, ISA_MIPS4, CPU_VR5500 },
ISA_MIPS32R2, CPU_MIPS32R2 },
{ "74kx", MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_DSPR2,
ISA_MIPS32R2, CPU_MIPS32R2 },
+ /* 1004K cores are multiprocessor versions of the 34K. */
+ { "1004kc", MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
+ ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "1004kf2_1", MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
+ ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "1004kf", MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
+ ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "1004kf1_1", MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
+ ISA_MIPS32R2, CPU_MIPS32R2 },
/* MIPS 64 */
{ "5kc", 0, ISA_MIPS64, CPU_MIPS64 },
{ "20kc", MIPS_CPU_ASE_MIPS3D, ISA_MIPS64, CPU_MIPS64 },
{ "25kf", MIPS_CPU_ASE_MIPS3D, ISA_MIPS64, CPU_MIPS64 },
- /* MIPS 64 Release 2 */
-
/* Broadcom SB-1 CPU core */
{ "sb1", MIPS_CPU_ASE_MIPS3D | MIPS_CPU_ASE_MDMX,
ISA_MIPS64, CPU_SB1 },
/* Broadcom SB-1A CPU core */
{ "sb1a", MIPS_CPU_ASE_MIPS3D | MIPS_CPU_ASE_MDMX,
ISA_MIPS64, CPU_SB1 },
+
+ { "loongson3a", 0, ISA_MIPS64, CPU_LOONGSON_3A },
+
+ /* MIPS 64 Release 2 */
/* Cavium Networks Octeon CPU core */
{ "octeon", 0, ISA_MIPS64R2, CPU_OCTEON },
+ /* RMI Xlr */
+ { "xlr", 0, ISA_MIPS64, CPU_XLR },
+
/* End marker */
{ NULL, 0, 0, 0 }
};
if (mips_matching_cpu_name_p (p->name, cpu_string))
return p;
- as_bad ("Bad value (%s) for %s", cpu_string, option);
+ as_bad (_("Bad value (%s) for %s"), cpu_string, option);
return 0;
}
-mmt generate MT instructions\n\
-mno-mt do not generate MT instructions\n"));
fprintf (stream, _("\
+-mfix-loongson2f-jump work around Loongson2F JUMP instructions\n\
+-mfix-loongson2f-nop work around Loongson2F NOP errata\n\
-mfix-vr4120 work around certain VR4120 errata\n\
-mfix-vr4130 work around VR4130 mflo/mfhi errata\n\
+-mfix-24k insert a nop after ERET and DERET instructions\n\
+-mfix-cn63xxp1 work around CN63XXP1 PREF errata\n\
-mgp32 use 32-bit GPRs, regardless of the chosen ISA\n\
-mfp32 use 32-bit FPRs, regardless of the chosen ISA\n\
-msym32 assume all symbols have 32-bit values\n\
#ifdef OBJ_ELF
fprintf (stream, _("\
-KPIC, -call_shared generate SVR4 position independent code\n\
+-call_nonpic generate non-PIC code that can operate with DSOs\n\
-mvxworks-pic generate VxWorks position independent code\n\
--non_shared do not generate position independent code\n\
+-non_shared do not generate code that can operate with DSOs\n\
-xgot assume a 32 bit GOT\n\
-mpdr, -mno-pdr enable/disable creation of .pdr sections\n\
-mshared, -mno-shared disable/enable .cpload optimization for\n\
#endif
}
+#ifdef TE_IRIX
enum dwarf2_format
-mips_dwarf2_format (void)
+mips_dwarf2_format (asection *sec ATTRIBUTE_UNUSED)
{
if (HAVE_64BIT_SYMBOLS)
- {
-#ifdef TE_IRIX
- return dwarf2_format_64bit_irix;
-#else
- return dwarf2_format_64bit;
-#endif
- }
+ return dwarf2_format_64bit_irix;
else
return dwarf2_format_32bit;
}
+#endif
int
mips_dwarf2_addr_size (void)
{
- if (HAVE_64BIT_SYMBOLS)
+ if (HAVE_64BIT_OBJECTS)
return 8;
else
return 4;