/* 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, 2009, 2010
+ 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
Free Software Foundation, Inc.
Contributed by the OSF and Ralph Campbell.
Written by Keith Knowles and Ralph Campbell, working independently.
/* The opcode's entry in mips_opcodes or mips16_opcodes. */
const struct mips_opcode *insn_mo;
- /* True if this is a mips16 instruction and if we want the extended
- form of INSN_MO. */
- bfd_boolean use_extend;
-
- /* The 16-bit extension instruction to use when USE_EXTEND is true. */
- unsigned short extend;
-
/* The 16-bit or 32-bit bitstring of the instruction itself. This is
- a copy of INSN_MO->match with the operands filled in. */
+ a copy of INSN_MO->match with the operands filled in. If we have
+ decided to use an extended MIPS16 instruction, this includes the
+ extension. */
unsigned long insn_opcode;
/* The frag that contains the instruction. */
int ase_dsp;
int ase_dspr2;
int ase_mt;
+ int ase_mcu;
/* Whether we are assembling for the mips16 processor. 0 if we are
not, 1 if we are, and -1 if the value has not been initialized.
Changed by `.set mips16' and `.set nomips16', and the -mips16 and
{
/* isa */ ISA_UNKNOWN, /* ase_mips3d */ -1, /* ase_mdmx */ -1,
/* ase_smartmips */ 0, /* ase_dsp */ -1, /* ase_dspr2 */ -1, /* ase_mt */ -1,
- /* mips16 */ -1, /* micromips */ -1, /* noreorder */ 0, /* at */ ATREG,
- /* warn_about_macros */ 0, /* nomove */ 0, /* nobopt */ 0,
+ /* ase_mcu */ -1, /* mips16 */ -1, /* micromips */ -1, /* noreorder */ 0,
+ /* at */ ATREG, /* warn_about_macros */ 0, /* nomove */ 0, /* nobopt */ 0,
/* noautoextend */ 0, /* gp32 */ 0, /* fp32 */ 0, /* arch */ CPU_UNKNOWN,
/* sym32 */ FALSE, /* soft_float */ FALSE, /* single_float */ FALSE
};
static int file_ase_dsp;
#define ISA_SUPPORTS_DSP_ASE (mips_opts.isa == ISA_MIPS32R2 \
- || mips_opts.isa == ISA_MIPS64R2)
+ || mips_opts.isa == ISA_MIPS64R2 \
+ || mips_opts.micromips)
#define ISA_SUPPORTS_DSP64_ASE (mips_opts.isa == ISA_MIPS64R2)
static int file_ase_dspr2;
#define ISA_SUPPORTS_DSPR2_ASE (mips_opts.isa == ISA_MIPS32R2 \
- || mips_opts.isa == ISA_MIPS64R2)
+ || mips_opts.isa == ISA_MIPS64R2 \
+ || mips_opts.micromips)
/* True if -mmt was passed or implied by arguments passed on the
command line (e.g., by -march). */
#define ISA_SUPPORTS_MT_ASE (mips_opts.isa == ISA_MIPS32R2 \
|| mips_opts.isa == ISA_MIPS64R2)
+#define ISA_SUPPORTS_MCU_ASE (mips_opts.isa == ISA_MIPS32R2 \
+ || mips_opts.isa == ISA_MIPS64R2 \
+ || mips_opts.micromips)
+
/* The argument of the -march= flag. The architecture we are assembling. */
static int file_mips_arch = CPU_UNKNOWN;
static const char *mips_arch_string;
(strncmp (TARGET_CPU, "mips16", sizeof ("mips16") - 1) == 0 \
|| strncmp (TARGET_CANONICAL, "mips-lsi-elf", sizeof ("mips-lsi-elf") - 1) == 0)
-/* Return true if the given CPU supports microMIPS. */
+/* Return true if the given CPU supports the microMIPS ASE. */
#define CPU_HAS_MICROMIPS(cpu) 0
/* True if CPU has a dror instruction. */
/* 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 is in the Octeon family */
+#define CPU_IS_OCTEON(CPU) ((CPU) == CPU_OCTEON || (CPU) == CPU_OCTEONP || (CPU) == CPU_OCTEON2)
-/* 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 CPU has seq/sne and seqi/snei instructions. */
+#define CPU_HAS_SEQ(CPU) (CPU_IS_OCTEON (CPU))
/* True if mflo and mfhi can be immediately followed by instructions
which write to the HI and LO registers.
#define MF_HILO_INSN(PINFO) \
((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)))
-
/* Whether code compression (either of the MIPS16 or the microMIPS ASEs)
has been selected. This implies, in particular, that addresses of text
labels have their LSB set. */
The information we store for this type of relaxation is the argument
code found in the opcode file for this relocation, the register
- selected as the assembler temporary, whether the user explicitly
- requested a 16-bit form, whether the branch is unconditional, whether
- it is compact, whether it stores the link address implicitly in $ra,
- whether relaxation of out-of-range 32-bit branches to a sequence of
- instructions is enabled, and whether the displacement of a branch is
- too large to fit as an immediate argument of a 16-bit and a 32-bit
- branch, respectively. */
-#define RELAX_MICROMIPS_ENCODE(type, at, u16bit, uncond, compact, link, \
- relax32, toofar16, toofar32) \
- (0x40000000 \
- | ((type) & 0xff) \
- | (((at) & 0x1f) << 8) \
- | ((u16bit) ? 0x2000 : 0) \
- | ((uncond) ? 0x4000 : 0) \
- | ((compact) ? 0x8000 : 0) \
- | ((link) ? 0x10000 : 0) \
- | ((relax32) ? 0x20000 : 0) \
- | ((toofar16) ? 0x40000 : 0) \
- | ((toofar32) ? 0x80000 : 0))
+ selected as the assembler temporary, whether the branch is
+ unconditional, whether it is compact, whether it stores the link
+ address implicitly in $ra, whether relaxation of out-of-range 32-bit
+ branches to a sequence of instructions is enabled, and whether the
+ displacement of a branch is too large to fit as an immediate argument
+ of a 16-bit and a 32-bit branch, respectively. */
+#define RELAX_MICROMIPS_ENCODE(type, at, uncond, compact, link, \
+ relax32, toofar16, toofar32) \
+ (0x40000000 \
+ | ((type) & 0xff) \
+ | (((at) & 0x1f) << 8) \
+ | ((uncond) ? 0x2000 : 0) \
+ | ((compact) ? 0x4000 : 0) \
+ | ((link) ? 0x8000 : 0) \
+ | ((relax32) ? 0x10000 : 0) \
+ | ((toofar16) ? 0x20000 : 0) \
+ | ((toofar32) ? 0x40000 : 0))
#define RELAX_MICROMIPS_P(i) (((i) & 0xc0000000) == 0x40000000)
#define RELAX_MICROMIPS_TYPE(i) ((i) & 0xff)
#define RELAX_MICROMIPS_AT(i) (((i) >> 8) & 0x1f)
-#define RELAX_MICROMIPS_U16BIT(i) (((i) & 0x2000) != 0)
-#define RELAX_MICROMIPS_UNCOND(i) (((i) & 0x4000) != 0)
-#define RELAX_MICROMIPS_COMPACT(i) (((i) & 0x8000) != 0)
-#define RELAX_MICROMIPS_LINK(i) (((i) & 0x10000) != 0)
-#define RELAX_MICROMIPS_RELAX32(i) (((i) & 0x20000) != 0)
-
-#define RELAX_MICROMIPS_TOOFAR16(i) (((i) & 0x40000) != 0)
-#define RELAX_MICROMIPS_MARK_TOOFAR16(i) ((i) | 0x40000)
-#define RELAX_MICROMIPS_CLEAR_TOOFAR16(i) ((i) & ~0x40000)
-#define RELAX_MICROMIPS_TOOFAR32(i) (((i) & 0x80000) != 0)
-#define RELAX_MICROMIPS_MARK_TOOFAR32(i) ((i) | 0x80000)
-#define RELAX_MICROMIPS_CLEAR_TOOFAR32(i) ((i) & ~0x80000)
+#define RELAX_MICROMIPS_UNCOND(i) (((i) & 0x2000) != 0)
+#define RELAX_MICROMIPS_COMPACT(i) (((i) & 0x4000) != 0)
+#define RELAX_MICROMIPS_LINK(i) (((i) & 0x8000) != 0)
+#define RELAX_MICROMIPS_RELAX32(i) (((i) & 0x10000) != 0)
+
+#define RELAX_MICROMIPS_TOOFAR16(i) (((i) & 0x20000) != 0)
+#define RELAX_MICROMIPS_MARK_TOOFAR16(i) ((i) | 0x20000)
+#define RELAX_MICROMIPS_CLEAR_TOOFAR16(i) ((i) & ~0x20000)
+#define RELAX_MICROMIPS_TOOFAR32(i) (((i) & 0x40000) != 0)
+#define RELAX_MICROMIPS_MARK_TOOFAR32(i) ((i) | 0x40000)
+#define RELAX_MICROMIPS_CLEAR_TOOFAR32(i) ((i) & ~0x40000)
+
+/* Sign-extend 16-bit value X. */
+#define SEXT_16BIT(X) ((((X) + 0x8000) & 0xffff) - 0x8000)
/* Is the given value a sign-extended 32-bit value? */
#define IS_SEXT_32BIT_NUM(x) \
EXTRACT_BITS ((INSN).insn_opcode, \
MIPS16OP_MASK_##FIELD, \
MIPS16OP_SH_##FIELD)
+
+/* The MIPS16 EXTEND opcode, shifted left 16 places. */
+#define MIPS16_EXTEND (0xf000U << 16)
\f
/* Whether or not we are emitting a branch-likely macro. */
static bfd_boolean emit_branch_likely_macro = FALSE;
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
- (char *, unsigned int, int, offsetT, bfd_boolean, bfd_boolean, bfd_boolean,
- unsigned long *, bfd_boolean *, unsigned short *);
+ (char *, unsigned int, int, bfd_reloc_code_real_type, offsetT,
+ unsigned int, unsigned long *);
static size_t my_getSmallExpression
(expressionS *, bfd_reloc_code_real_type *, char *);
static void my_getExpression (expressionS *, char *);
static void s_cpreturn (int);
static void s_dtprelword (int);
static void s_dtpreldword (int);
+static void s_tprelword (int);
+static void s_tpreldword (int);
static void s_gpvalue (int);
static void s_gpword (int);
static void s_gpdword (int);
#define MIPS_CPU_ASE_MIPS3D 0x0010 /* CPU implements MIPS-3D ASE */
#define MIPS_CPU_ASE_MDMX 0x0020 /* CPU implements MDMX ASE */
#define MIPS_CPU_ASE_DSPR2 0x0040 /* CPU implements DSP R2 ASE */
+#define MIPS_CPU_ASE_MCU 0x0080 /* CPU implements MCU ASE */
static const struct mips_cpu_info *mips_parse_cpu (const char *, const char *);
static const struct mips_cpu_info *mips_cpu_info_from_isa (int);
{"cpreturn", s_cpreturn, 0},
{"dtprelword", s_dtprelword, 0},
{"dtpreldword", s_dtpreldword, 0},
+ {"tprelword", s_tprelword, 0},
+ {"tpreldword", s_tpreldword, 0},
{"gpvalue", s_gpvalue, 0},
{"gpword", s_gpword, 0},
{"gpdword", s_gpdword, 0},
static unsigned int forced_insn_length;
+/* True if we are assembling an instruction. All dot symbols defined during
+ this time should be treated as code labels. */
+
+static bfd_boolean mips_assembling_insn;
+
#ifdef OBJ_ELF
/* The pdr segment for per procedure frame/regmask info. Not used for
ECOFF debugging. */
return (mo->mask >> 16) == 0 ? 2 : 4;
}
+/* Return the length of MIPS16 instruction OPCODE. */
+
+static inline unsigned int
+mips16_opcode_length (unsigned long opcode)
+{
+ return (opcode >> 16) == 0 ? 2 : 4;
+}
+
/* Return the length of instruction INSN. */
static inline unsigned int
if (mips_opts.micromips)
return micromips_insn_length (insn->insn_mo);
else if (mips_opts.mips16)
- return insn->mips16_absolute_jump_p || insn->use_extend ? 4 : 2;
+ return mips16_opcode_length (insn->insn_opcode);
else
return 4;
}
size_t i;
insn->insn_mo = mo;
- insn->use_extend = FALSE;
- insn->extend = 0;
insn->insn_opcode = mo->match;
insn->frag = NULL;
insn->where = 0;
si->tc_segment_info_data.micromips = mips_opts.micromips;
}
+/* Read a standard MIPS instruction from BUF. */
+
+static unsigned long
+read_insn (char *buf)
+{
+ if (target_big_endian)
+ return bfd_getb32 ((bfd_byte *) buf);
+ else
+ return bfd_getl32 ((bfd_byte *) buf);
+}
+
+/* Write standard MIPS instruction INSN to BUF. Return a pointer to
+ the next byte. */
+
+static char *
+write_insn (char *buf, unsigned int insn)
+{
+ md_number_to_chars (buf, insn, 4);
+ return buf + 4;
+}
+
+/* Read a microMIPS or MIPS16 opcode from BUF, given that it
+ has length LENGTH. */
+
+static unsigned long
+read_compressed_insn (char *buf, unsigned int length)
+{
+ unsigned long insn;
+ unsigned int i;
+
+ insn = 0;
+ for (i = 0; i < length; i += 2)
+ {
+ insn <<= 16;
+ if (target_big_endian)
+ insn |= bfd_getb16 ((char *) buf);
+ else
+ insn |= bfd_getl16 ((char *) buf);
+ buf += 2;
+ }
+ return insn;
+}
+
+/* Write microMIPS or MIPS16 instruction INSN to BUF, given that the
+ instruction is LENGTH bytes long. Return a pointer to the next byte. */
+
+static char *
+write_compressed_insn (char *buf, unsigned int insn, unsigned int length)
+{
+ unsigned int i;
+
+ for (i = 0; i < length; i += 2)
+ md_number_to_chars (buf + i, insn >> ((length - i - 2) * 8), 2);
+ return buf + length;
+}
+
/* Install INSN at the location specified by its "frag" and "where" fields. */
static void
install_insn (const struct mips_cl_insn *insn)
{
char *f = insn->frag->fr_literal + insn->where;
- if (!HAVE_CODE_COMPRESSION)
- md_number_to_chars (f, insn->insn_opcode, 4);
- else if (mips_opts.micromips)
- {
- unsigned int length = insn_length (insn);
- if (length == 2)
- md_number_to_chars (f, insn->insn_opcode, 2);
- else if (length == 4)
- {
- md_number_to_chars (f, insn->insn_opcode >> 16, 2);
- f += 2;
- md_number_to_chars (f, insn->insn_opcode & 0xffff, 2);
- }
- else
- as_bad (_("48-bit microMIPS instructions are not supported"));
- }
- else if (insn->mips16_absolute_jump_p)
- {
- md_number_to_chars (f, insn->insn_opcode >> 16, 2);
- md_number_to_chars (f + 2, insn->insn_opcode & 0xffff, 2);
- }
+ if (HAVE_CODE_COMPRESSION)
+ write_compressed_insn (f, insn->insn_opcode, insn_length (insn));
else
- {
- if (insn->use_extend)
- {
- md_number_to_chars (f, 0xf000 | insn->extend, 2);
- f += 2;
- }
- md_number_to_chars (f, insn->insn_opcode, 2);
- }
+ write_insn (f, insn->insn_opcode);
mips_record_compressed_mode ();
}
}
}
-/* Emit a nop instruction, recording it in the history buffer. */
-
-static void
-emit_nop (void)
-{
- add_fixed_insn (NOP_INSN);
- insert_into_history (0, 1, NOP_INSN);
-}
-
/* Initialize vr4120_conflicts. There is a bit of duplication here:
the idea is to make it obvious at a glance that each errata is
included. */
As a special exception if one of s0-s7 registers is specified as
the range's lower delimiter and s8 (fp) is its upper one, then no
registers whose numbers place them between s7 and s8 (i.e. $24-$29)
- are selected; they have to be named separately if needed. */
+ are selected; they have to be listed separately if needed. */
static int
reglist_lookup (char **s, unsigned int types, unsigned int *reglistp)
unsigned int lastregno;
bfd_boolean ok = TRUE;
unsigned int regmask;
- unsigned int regno;
+ char *s_endlist = *s;
char *s_reset = *s;
- char *s_end_of_list = *s;
+ unsigned int regno;
while (reg_lookup (s, types, ®no))
{
regmask ^= (1 << regno) - 1;
reglist |= regmask;
- s_end_of_list = *s;
+ s_endlist = *s;
if (**s != ',')
break;
(*s)++;
}
if (ok)
- *s = s_end_of_list;
+ *s = s_endlist;
else
*s = s_reset;
if (reglistp)
isa |= INSN_MIPS3D;
if (mips_opts.ase_smartmips)
isa |= INSN_SMARTMIPS;
+ if (mips_opts.ase_mcu)
+ isa |= INSN_MCU;
- /* 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))
+ if (!opcode_is_member (mo, isa, mips_opts.arch))
return FALSE;
/* Check whether the instruction or macro requires single-precision or
static bfd_boolean
is_opcode_valid_16 (const struct mips_opcode *mo)
{
- return OPCODE_IS_MEMBER (mo, mips_opts.isa, mips_opts.arch) ? TRUE : FALSE;
+ return opcode_is_member (mo, mips_opts.isa, mips_opts.arch);
}
/* Return TRUE if the size of the microMIPS opcode MO matches one
}
/* Return TRUE if the microMIPS opcode MO is valid for the delay slot
- of the preceding instruction. Always TRUE in the standard MIPS mode. */
+ of the preceding instruction. Always TRUE in the standard MIPS mode.
+
+ We don't accept macros in 16-bit delay slots to avoid a case where
+ a macro expansion fails because it relies on a preceding 32-bit real
+ instruction to have matched and does not handle the operands correctly.
+ The only macros that may expand to 16-bit instructions are JAL that
+ cannot be placed in a delay slot anyway, and corner cases of BALIGN
+ and BGT (that likewise cannot be placed in a delay slot) that decay to
+ a NOP. In all these cases the macros precede any corresponding real
+ instruction definitions in the opcode table, so they will match in the
+ second pass where the size of the delay slot is ignored and therefore
+ produce correct code. */
static bfd_boolean
is_delay_slot_valid (const struct mips_opcode *mo)
return TRUE;
if (mo->pinfo == INSN_MACRO)
- return TRUE;
+ return (history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_16BIT) == 0;
if ((history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT) != 0
&& micromips_insn_length (mo) != 4)
return FALSE;
offset_reloc[1] = BFD_RELOC_UNUSED;
offset_reloc[2] = BFD_RELOC_UNUSED;
+ mips_mark_labels ();
+ mips_assembling_insn = TRUE;
+
if (mips_opts.mips16)
mips16_ip (str, &insn);
else
}
if (insn_error)
- {
- as_bad ("%s `%s'", insn_error, str);
- return;
- }
-
- if (insn.insn_mo->pinfo == INSN_MACRO)
+ as_bad ("%s `%s'", insn_error, str);
+ else if (insn.insn_mo->pinfo == INSN_MACRO)
{
macro_start ();
if (mips_opts.mips16)
else
append_insn (&insn, NULL, unused_reloc, FALSE);
}
+
+ mips_assembling_insn = FALSE;
}
/* Convenience functions for abstracting away the differences between
}
}
+static inline bfd_boolean
+jmp_reloc_p (bfd_reloc_code_real_type reloc)
+{
+ return reloc == BFD_RELOC_MIPS_JMP || reloc == BFD_RELOC_MICROMIPS_JMP;
+}
+
static inline bfd_boolean
got16_reloc_p (bfd_reloc_code_real_type reloc)
{
- return (reloc == BFD_RELOC_MIPS_GOT16
- || reloc == BFD_RELOC_MIPS16_GOT16
+ return (reloc == BFD_RELOC_MIPS_GOT16 || reloc == BFD_RELOC_MIPS16_GOT16
|| reloc == BFD_RELOC_MICROMIPS_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
+ return (reloc == BFD_RELOC_HI16_S || reloc == BFD_RELOC_MIPS16_HI16_S
|| reloc == BFD_RELOC_MICROMIPS_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 (reloc == BFD_RELOC_LO16 || reloc == BFD_RELOC_MIPS16_LO16
|| reloc == BFD_RELOC_MICROMIPS_LO16);
}
-static inline bfd_boolean
-jmp_reloc_p (bfd_reloc_code_real_type reloc)
-{
- return (reloc == BFD_RELOC_MIPS_JMP
- || reloc == BFD_RELOC_MICROMIPS_JMP);
-}
-
static inline bfd_boolean
jalr_reloc_p (bfd_reloc_code_real_type reloc)
{
- return (reloc == BFD_RELOC_MIPS_JALR
- || reloc == BFD_RELOC_MICROMIPS_JALR);
+ return reloc == BFD_RELOC_MIPS_JALR || reloc == BFD_RELOC_MICROMIPS_JALR;
}
/* Return true if the given relocation might need a matching %lo().
return 0;
}
-/* Move all labels in insn_labels to the current insertion point. */
+/* Move all labels in LABELS to the current insertion point. TEXT_P
+ says whether the labels refer to text or data. */
static void
-mips_move_labels (void)
+mips_move_labels (struct insn_label_list *labels, bfd_boolean text_p)
{
- segment_info_type *si = seg_info (now_seg);
struct insn_label_list *l;
valueT val;
- for (l = si->label_list; l != NULL; l = l->next)
+ for (l = labels; l != NULL; l = l->next)
{
gas_assert (S_GET_SEGMENT (l->label) == now_seg);
symbol_set_frag (l->label, frag_now);
val = (valueT) frag_now_fix ();
/* MIPS16/microMIPS text labels are stored as odd. */
- if (HAVE_CODE_COMPRESSION)
+ if (text_p && HAVE_CODE_COMPRESSION)
++val;
S_SET_VALUE (l->label, val);
}
}
+/* Move all labels in insn_labels to the current insertion point
+ and treat them as text labels. */
+
+static void
+mips_move_text_labels (void)
+{
+ mips_move_labels (seg_info (now_seg)->label_list, TRUE);
+}
+
static bfd_boolean
s_is_linkonce (symbolS *sym, segT from_seg)
{
return linkonce;
}
-/* Mark instruction labels in MIPS16/microMIPS mode. This permits the
+/* Mark MIPS16 or microMIPS instruction label LABEL. This permits the
linker to handle them specially, such as generating jalx instructions
when needed. We also make them odd for the duration of the assembly,
in order to generate the right sort of code. We will make them even
to make them odd again. */
static void
-mips_compressed_mark_labels (void)
+mips_compressed_mark_label (symbolS *label)
{
- segment_info_type *si = seg_info (now_seg);
- struct insn_label_list *l;
-
gas_assert (HAVE_CODE_COMPRESSION);
- for (l = si->label_list; l != NULL; l = l->next)
- {
- symbolS *label = l->label;
-
#if defined(OBJ_ELF) || defined(OBJ_MAYBE_ELF)
- if (IS_ELF)
- {
- if (mips_opts.mips16)
- S_SET_OTHER (label, ELF_ST_SET_MIPS16 (S_GET_OTHER (label)));
- else
- S_SET_OTHER (label, ELF_ST_SET_MICROMIPS (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
- in a link-once section, since we'll be emitting symbol reloc
- references to it which will be patched up by the linker, and
- the final value of the symbol may or may not be MIPS16/microMIPS. */
- && ! S_IS_WEAK (label)
- && ! S_IS_EXTERNAL (label)
- && ! s_is_linkonce (label, now_seg))
- S_SET_VALUE (label, S_GET_VALUE (label) | 1);
+ if (IS_ELF)
+ {
+ if (mips_opts.mips16)
+ S_SET_OTHER (label, ELF_ST_SET_MIPS16 (S_GET_OTHER (label)));
+ else
+ S_SET_OTHER (label, ELF_ST_SET_MICROMIPS (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
+ in a link-once section, since we'll be emitting symbol reloc
+ references to it which will be patched up by the linker, and
+ the final value of the symbol may or may not be MIPS16/microMIPS. */
+ && !S_IS_WEAK (label)
+ && !S_IS_EXTERNAL (label)
+ && !s_is_linkonce (label, now_seg))
+ S_SET_VALUE (label, S_GET_VALUE (label) | 1);
+}
+
+/* Mark preceding MIPS16 or microMIPS instruction labels. */
+
+static void
+mips_compressed_mark_labels (void)
+{
+ struct insn_label_list *l;
+
+ for (l = seg_info (now_seg)->label_list; l != NULL; l = l->next)
+ mips_compressed_mark_label (l->label);
}
/* End the current frag. Make it a variant frag and record the
mips_relax.sequence = 0;
}
-/* Return the mask of core registers that instruction IP may
- read or write. */
+/* Return true if IP is a delayed branch or jump. */
+
+static inline bfd_boolean
+delayed_branch_p (const struct mips_cl_insn *ip)
+{
+ return (ip->insn_mo->pinfo & (INSN_UNCOND_BRANCH_DELAY
+ | INSN_COND_BRANCH_DELAY
+ | INSN_COND_BRANCH_LIKELY)) != 0;
+}
+
+/* Return true if IP is a compact branch or jump. */
+
+static inline bfd_boolean
+compact_branch_p (const struct mips_cl_insn *ip)
+{
+ if (mips_opts.mips16)
+ return (ip->insn_mo->pinfo & (MIPS16_INSN_UNCOND_BRANCH
+ | MIPS16_INSN_COND_BRANCH)) != 0;
+ else
+ return (ip->insn_mo->pinfo2 & (INSN2_UNCOND_BRANCH
+ | INSN2_COND_BRANCH)) != 0;
+}
+
+/* Return true if IP is an unconditional branch or jump. */
+
+static inline bfd_boolean
+uncond_branch_p (const struct mips_cl_insn *ip)
+{
+ return ((ip->insn_mo->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0
+ || (mips_opts.mips16
+ ? (ip->insn_mo->pinfo & MIPS16_INSN_UNCOND_BRANCH) != 0
+ : (ip->insn_mo->pinfo2 & INSN2_UNCOND_BRANCH) != 0));
+}
+
+/* Return true if IP is a branch-likely instruction. */
+
+static inline bfd_boolean
+branch_likely_p (const struct mips_cl_insn *ip)
+{
+ return (ip->insn_mo->pinfo & INSN_COND_BRANCH_LIKELY) != 0;
+}
+
+/* Return the type of nop that should be used to fill the delay slot
+ of delayed branch IP. */
+
+static struct mips_cl_insn *
+get_delay_slot_nop (const struct mips_cl_insn *ip)
+{
+ if (mips_opts.micromips
+ && (ip->insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT))
+ return µmips_nop32_insn;
+ return NOP_INSN;
+}
+
+/* Return the mask of core registers that IP reads or writes. */
static unsigned int
gpr_mod_mask (const struct mips_cl_insn *ip)
{
- unsigned long pinfo, pinfo2;
+ unsigned long pinfo2;
unsigned int mask;
mask = 0;
- pinfo = ip->insn_mo->pinfo;
pinfo2 = ip->insn_mo->pinfo2;
if (mips_opts.micromips)
{
- if (pinfo2 & INSN2_MOD_GPR_MB)
- mask |= 1 << micromips_to_32_reg_b_map[EXTRACT_OPERAND (1, MB, *ip)];
- if (pinfo2 & INSN2_MOD_GPR_MC)
- mask |= 1 << micromips_to_32_reg_c_map[EXTRACT_OPERAND (1, MC, *ip)];
if (pinfo2 & INSN2_MOD_GPR_MD)
mask |= 1 << micromips_to_32_reg_d_map[EXTRACT_OPERAND (1, MD, *ip)];
- if (pinfo2 & INSN2_MOD_GPR_ME)
- mask |= 1 << micromips_to_32_reg_e_map[EXTRACT_OPERAND (1, ME, *ip)];
if (pinfo2 & INSN2_MOD_GPR_MF)
mask |= 1 << micromips_to_32_reg_f_map[EXTRACT_OPERAND (1, MF, *ip)];
- if (pinfo2 & INSN2_MOD_GPR_MG)
- mask |= 1 << micromips_to_32_reg_g_map[EXTRACT_OPERAND (1, MG, *ip)];
- if (pinfo2 & INSN2_MOD_GPR_MHI)
- {
- mask |= 1 << micromips_to_32_reg_h_map[EXTRACT_OPERAND (1, MH, *ip)];
- mask |= 1 << micromips_to_32_reg_i_map[EXTRACT_OPERAND (1, MI, *ip)];
- }
- if (pinfo2 & INSN2_MOD_GPR_MJ)
- mask |= 1 << EXTRACT_OPERAND (1, MJ, *ip);
- if (pinfo2 & INSN2_MOD_GPR_MM)
- mask |= 1 << micromips_to_32_reg_m_map[EXTRACT_OPERAND (1, MM, *ip)];
- if (pinfo2 & INSN2_MOD_GPR_MN)
- mask |= 1 << micromips_to_32_reg_n_map[EXTRACT_OPERAND (1, MN, *ip)];
- if (pinfo2 & INSN2_MOD_GPR_MP)
- mask |= 1 << EXTRACT_OPERAND (1, MP, *ip);
- if (pinfo2 & INSN2_MOD_GPR_MQ)
- mask |= 1 << micromips_to_32_reg_q_map[EXTRACT_OPERAND (1, MQ, *ip)];
if (pinfo2 & INSN2_MOD_SP)
mask |= 1 << SP;
}
if (pinfo & MIPS16_INSN_READ_GPR_X)
mask |= 1 << MIPS16_EXTRACT_OPERAND (REGR32, *ip);
}
- else if (mips_opts.micromips)
+ else
{
+ if (pinfo2 & INSN2_READ_GPR_D)
+ mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RD, *ip);
if (pinfo & INSN_READ_GPR_T)
- mask |= 1 << EXTRACT_OPERAND (1, RT, *ip);
+ mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RT, *ip);
if (pinfo & INSN_READ_GPR_S)
- mask |= 1 << EXTRACT_OPERAND (1, RS, *ip);
- if (pinfo2 & INSN2_READ_GPR_31)
- mask |= 1 << RA;
+ mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RS, *ip);
if (pinfo2 & INSN2_READ_GP)
mask |= 1 << GP;
+ if (pinfo2 & INSN2_READ_GPR_31)
+ mask |= 1 << RA;
+ if (pinfo2 & INSN2_READ_GPR_Z)
+ mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RZ, *ip);
}
- else
+ if (mips_opts.micromips)
{
- if (pinfo2 & INSN2_READ_GPR_D)
- mask |= 1 << EXTRACT_OPERAND (0, RD, *ip);
- if (pinfo & INSN_READ_GPR_T)
- mask |= 1 << EXTRACT_OPERAND (0, RT, *ip);
- if (pinfo & INSN_READ_GPR_S)
- mask |= 1 << EXTRACT_OPERAND (0, RS, *ip);
- if (pinfo2 & INSN2_READ_GPR_Z)
- mask |= 1 << EXTRACT_OPERAND (0, RZ, *ip);
+ if (pinfo2 & INSN2_READ_GPR_MC)
+ mask |= 1 << micromips_to_32_reg_c_map[EXTRACT_OPERAND (1, MC, *ip)];
+ if (pinfo2 & INSN2_READ_GPR_ME)
+ mask |= 1 << micromips_to_32_reg_e_map[EXTRACT_OPERAND (1, ME, *ip)];
+ if (pinfo2 & INSN2_READ_GPR_MG)
+ mask |= 1 << micromips_to_32_reg_g_map[EXTRACT_OPERAND (1, MG, *ip)];
+ if (pinfo2 & INSN2_READ_GPR_MJ)
+ mask |= 1 << EXTRACT_OPERAND (1, MJ, *ip);
+ if (pinfo2 & INSN2_READ_GPR_MMN)
+ {
+ mask |= 1 << micromips_to_32_reg_m_map[EXTRACT_OPERAND (1, MM, *ip)];
+ mask |= 1 << micromips_to_32_reg_n_map[EXTRACT_OPERAND (1, MN, *ip)];
+ }
+ if (pinfo2 & INSN2_READ_GPR_MP)
+ mask |= 1 << EXTRACT_OPERAND (1, MP, *ip);
+ if (pinfo2 & INSN2_READ_GPR_MQ)
+ mask |= 1 << micromips_to_32_reg_q_map[EXTRACT_OPERAND (1, MQ, *ip)];
}
/* Don't include register 0. */
return mask & ~1;
if (pinfo & MIPS16_INSN_WRITE_GPR_Y)
mask |= 1 << MIPS16OP_EXTRACT_REG32R (ip->insn_opcode);
}
- else if (mips_opts.micromips)
- {
- if (pinfo & INSN_WRITE_GPR_D)
- mask |= 1 << EXTRACT_OPERAND (1, RD, *ip);
- if (pinfo & INSN_WRITE_GPR_T)
- mask |= 1 << EXTRACT_OPERAND (1, RT, *ip);
- if (pinfo2 & INSN2_WRITE_GPR_S)
- mask |= 1 << EXTRACT_OPERAND (1, RS, *ip);
- if (pinfo & INSN_WRITE_GPR_31)
- mask |= 1 << RA;
- }
else
{
if (pinfo & INSN_WRITE_GPR_D)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RD, *ip);
if (pinfo & INSN_WRITE_GPR_T)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RT, *ip);
+ if (pinfo & INSN_WRITE_GPR_S)
+ mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RS, *ip);
if (pinfo & INSN_WRITE_GPR_31)
mask |= 1 << RA;
if (pinfo2 & INSN2_WRITE_GPR_Z)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RZ, *ip);
}
+ if (mips_opts.micromips)
+ {
+ if (pinfo2 & INSN2_WRITE_GPR_MB)
+ mask |= 1 << micromips_to_32_reg_b_map[EXTRACT_OPERAND (1, MB, *ip)];
+ if (pinfo2 & INSN2_WRITE_GPR_MHI)
+ {
+ mask |= 1 << micromips_to_32_reg_h_map[EXTRACT_OPERAND (1, MH, *ip)];
+ mask |= 1 << micromips_to_32_reg_i_map[EXTRACT_OPERAND (1, MI, *ip)];
+ }
+ if (pinfo2 & INSN2_WRITE_GPR_MJ)
+ mask |= 1 << EXTRACT_OPERAND (1, MJ, *ip);
+ if (pinfo2 & INSN2_WRITE_GPR_MP)
+ mask |= 1 << EXTRACT_OPERAND (1, MP, *ip);
+ }
/* Don't include register 0. */
return mask & ~1;
}
mask = 0;
pinfo = ip->insn_mo->pinfo;
pinfo2 = ip->insn_mo->pinfo2;
- if (mips_opts.micromips)
+ if (!mips_opts.mips16)
{
if (pinfo2 & INSN2_READ_FPR_D)
- mask |= 1 << EXTRACT_OPERAND (1, FD, *ip);
- if (pinfo & INSN_READ_FPR_S)
- mask |= 1 << EXTRACT_OPERAND (1, FS, *ip);
- if (pinfo & INSN_READ_FPR_T)
- mask |= 1 << EXTRACT_OPERAND (1, FT, *ip);
- if (pinfo & INSN_READ_FPR_R)
- mask |= 1 << EXTRACT_OPERAND (1, FR, *ip);
- }
- else if (!mips_opts.mips16)
- {
+ mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FD, *ip);
if (pinfo & INSN_READ_FPR_S)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FS, *ip);
if (pinfo & INSN_READ_FPR_T)
mask = 0;
pinfo = ip->insn_mo->pinfo;
pinfo2 = ip->insn_mo->pinfo2;
- if (mips_opts.micromips)
- {
- if (pinfo2 & INSN_WRITE_FPR_D)
- mask |= 1 << EXTRACT_OPERAND (1, FD, *ip);
- if (pinfo & INSN_WRITE_FPR_S)
- mask |= 1 << EXTRACT_OPERAND (1, FS, *ip);
- if (pinfo & INSN_WRITE_FPR_T)
- mask |= 1 << EXTRACT_OPERAND (1, FT, *ip);
- }
- else if (!mips_opts.mips16)
+ if (!mips_opts.mips16)
{
if (pinfo & INSN_WRITE_FPR_D)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FD, *ip);
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)
+ || delayed_branch_p (insn2))
return 1;
}
}
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))
+ if (delayed_branch_p (insn))
{
tmp_nops = nops_for_sequence (2, ignore ? ignore + 2 : 0,
- hist, insn, NOP_INSN);
+ hist, insn, get_delay_slot_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)))
+ else if (compact_branch_p (insn))
{
tmp_nops = nops_for_sequence (1, ignore ? ignore + 1 : 0, hist, insn);
if (tmp_nops > nops)
static bfd_boolean
can_swap_branch_p (struct mips_cl_insn *ip)
{
- unsigned long pinfo, pinfo2, prev_pinfo;
+ unsigned long pinfo, pinfo2, prev_pinfo, prev_pinfo2;
unsigned int gpr_read, gpr_write, prev_gpr_read, prev_gpr_write;
- /* For microMIPS, disable reordering. */
- if (mips_opts.micromips)
- return FALSE;
-
/* -O2 and above is required for this optimization. */
if (mips_optimize < 2)
return FALSE;
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 the previous instruction had a fixup in mips16 mode, we can not swap.
+ This means that the previous instruction was a 4-byte one anyhow. */
if (mips_opts.mips16 && history[0].fixp[0])
return FALSE;
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 (!HAVE_CODE_COMPRESSION
+ branch's one, we cannot do the swap. This does not apply to
+ MIPS16 code, which uses variant frags for different purposes. */
+ if (!mips_opts.mips16
&& history[0].frag
&& history[0].frag->fr_type == rs_machine_dependent)
return FALSE;
return FALSE;
/* If the previous instruction uses the PC, we can not swap. */
+ prev_pinfo2 = history[0].insn_mo->pinfo2;
if (mips_opts.mips16 && (prev_pinfo & MIPS16_INSN_READ_PC))
return FALSE;
+ if (mips_opts.micromips && (prev_pinfo2 & INSN2_READ_PC))
+ return FALSE;
/* If the previous instruction has an incorrect size for a fixed
branch delay slot in microMIPS mode, we cannot swap. */
- if (mips_opts.micromips)
- {
- pinfo2 = ip->insn_mo->pinfo;
- if ((pinfo2 & INSN2_BRANCH_DELAY_16BIT)
- && insn_length (history) != 2)
- return FALSE;
-
- if ((pinfo2 & INSN2_BRANCH_DELAY_32BIT)
- && insn_length (history) != 4)
- return FALSE;
- }
+ pinfo2 = ip->insn_mo->pinfo2;
+ if (mips_opts.micromips
+ && (pinfo2 & INSN2_BRANCH_DELAY_16BIT)
+ && insn_length (history) != 2)
+ return FALSE;
+ if (mips_opts.micromips
+ && (pinfo2 & INSN2_BRANCH_DELAY_32BIT)
+ && insn_length (history) != 4)
+ return FALSE;
+
return TRUE;
}
return APPEND_ADD;
/* 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 (delayed_branch_p (ip))
{
- if (can_swap_branch_p (ip))
+ if (!branch_likely_p (ip) && can_swap_branch_p (ip))
return APPEND_SWAP;
+ pinfo = ip->insn_mo->pinfo;
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;
return APPEND_ADD_WITH_NOP;
}
- /* 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;
-
return APPEND_ADD;
}
#if defined(OBJ_ELF) || defined(OBJ_MAYBE_ELF)
if (IS_ELF)
S_SET_OTHER (s, ELF_ST_SET_MICROMIPS (S_GET_OTHER (s)));
+#else
+ (void) s;
#endif
}
return reloc;
}
+/* Try to resolve relocation RELOC against constant OPERAND at assembly time.
+ Return true on success, storing the resolved value in RESULT. */
+
+static bfd_boolean
+calculate_reloc (bfd_reloc_code_real_type reloc, offsetT operand,
+ offsetT *result)
+{
+ switch (reloc)
+ {
+ case BFD_RELOC_MIPS_HIGHEST:
+ case BFD_RELOC_MICROMIPS_HIGHEST:
+ *result = ((operand + 0x800080008000ull) >> 48) & 0xffff;
+ return TRUE;
+
+ case BFD_RELOC_MIPS_HIGHER:
+ case BFD_RELOC_MICROMIPS_HIGHER:
+ *result = ((operand + 0x80008000ull) >> 32) & 0xffff;
+ return TRUE;
+
+ case BFD_RELOC_HI16_S:
+ case BFD_RELOC_MICROMIPS_HI16_S:
+ case BFD_RELOC_MIPS16_HI16_S:
+ *result = ((operand + 0x8000) >> 16) & 0xffff;
+ return TRUE;
+
+ case BFD_RELOC_HI16:
+ case BFD_RELOC_MICROMIPS_HI16:
+ case BFD_RELOC_MIPS16_HI16:
+ *result = (operand >> 16) & 0xffff;
+ return TRUE;
+
+ case BFD_RELOC_LO16:
+ case BFD_RELOC_MICROMIPS_LO16:
+ case BFD_RELOC_MIPS16_LO16:
+ *result = operand & 0xffff;
+ return TRUE;
+
+ case BFD_RELOC_UNUSED:
+ *result = operand;
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+}
+
/* Output an instruction. IP is the instruction information.
ADDRESS_EXPR is an operand of the instruction to be used with
RELOC_TYPE. EXPANSIONP is true if the instruction is part of
append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
bfd_reloc_code_real_type *reloc_type, bfd_boolean expansionp)
{
- unsigned long prev_pinfo, prev_pinfo2, pinfo, pinfo2;
+ unsigned long prev_pinfo2, pinfo;
bfd_boolean relaxed_branch = FALSE;
- bfd_boolean relax32;
enum append_method method;
+ bfd_boolean relax32;
+ int branch_disp;
- if (mips_fix_loongson2f && !mips_opts.micromips)
+ if (mips_fix_loongson2f && !HAVE_CODE_COMPRESSION)
fix_loongson2f (ip);
- mips_mark_labels ();
-
file_ase_mips16 |= mips_opts.mips16;
file_ase_micromips |= mips_opts.micromips;
- prev_pinfo = history[0].insn_mo->pinfo;
prev_pinfo2 = history[0].insn_mo->pinfo2;
pinfo = ip->insn_mo->pinfo;
- pinfo2 = ip->insn_mo->pinfo2;
if (mips_opts.micromips
&& !expansionp
if (address_expr == NULL)
ip->complete_p = 1;
- else if (*reloc_type <= BFD_RELOC_UNUSED
+ else if (reloc_type[0] <= BFD_RELOC_UNUSED
+ && reloc_type[1] == BFD_RELOC_UNUSED
+ && reloc_type[2] == 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:
{
int shift;
(unsigned long) address_expr->X_add_number);
ip->insn_opcode |= ((address_expr->X_add_number >> shift)
& 0x3ffffff);
- ip->complete_p = 0;
+ ip->complete_p = 1;
}
break;
(((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;
+ ip->complete_p = 1;
break;
case BFD_RELOC_16_PCREL_S2:
ip->insn_opcode |= ((address_expr->X_add_number >> shift)
& 0xffff);
}
- ip->complete_p = 0;
}
break;
default:
- internalError ();
- }
+ {
+ offsetT value;
+
+ if (calculate_reloc (*reloc_type, address_expr->X_add_number,
+ &value))
+ {
+ ip->insn_opcode |= value & 0xffff;
+ ip->complete_p = 1;
+ }
+ }
+ break;
+ }
}
if (mips_relax.sequence != 2 && !mips_opts.noreorder)
old_frag_offset = frag_now_fix ();
for (i = 0; i < nops; i++)
- emit_nop ();
+ add_fixed_insn (NOP_INSN);
+ insert_into_history (0, nops, NOP_INSN);
if (listing)
{
frag_grow (40);
}
- mips_move_labels ();
+ mips_move_text_labels ();
#ifndef NO_ECOFF_DEBUGGING
if (ECOFF_DEBUGGING)
}
method = get_append_method (ip);
+ branch_disp = method == APPEND_SWAP ? insn_length (history) : 0;
#ifdef OBJ_ELF
/* The value passed to dwarf2_emit_insn is the distance between
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/microMIPS 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 ((HAVE_CODE_COMPRESSION ? -1 : 0)
- + (method == APPEND_SWAP ? insn_length (history) : 0));
+ and for MIPS16/microMIPS 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 ((HAVE_CODE_COMPRESSION ? -1 : 0) + branch_disp);
#endif
relax32 = (mips_relax_branch
&& (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))
- /* Don't try 32-bit branch relaxation when users specify
- 16-bit/32-bit instructions. */
- && !forced_insn_length);
+ && !(ip->insn_mo->membership & (INSN_DSP64 | INSN_DSP)));
if (!HAVE_CODE_COMPRESSION
&& address_expr
&& relax32
&& *reloc_type == BFD_RELOC_16_PCREL_S2
- && (pinfo & INSN_UNCOND_BRANCH_DELAY || pinfo & INSN_COND_BRANCH_DELAY
- || pinfo & INSN_COND_BRANCH_LIKELY))
+ && delayed_branch_p (ip))
{
relaxed_branch = TRUE;
add_relaxed_insn (ip, (relaxed_branch_length
(NULL, NULL,
- (pinfo & INSN_UNCOND_BRANCH_DELAY) ? -1
- : (pinfo & INSN_COND_BRANCH_LIKELY) ? 1
+ uncond_branch_p (ip) ? -1
+ : branch_likely_p (ip) ? 1
: 0)), 4,
RELAX_BRANCH_ENCODE
(AT,
- pinfo & INSN_UNCOND_BRANCH_DELAY,
- pinfo & INSN_COND_BRANCH_LIKELY,
+ uncond_branch_p (ip),
+ branch_likely_p (ip),
pinfo & INSN_WRITE_GPR_31,
0),
address_expr->X_add_symbol,
&& address_expr
&& ((relax32 && *reloc_type == BFD_RELOC_16_PCREL_S2)
|| *reloc_type > BFD_RELOC_UNUSED)
- && (pinfo & INSN_UNCOND_BRANCH_DELAY
- || pinfo & INSN_COND_BRANCH_DELAY
- || (pinfo2 & ~INSN2_ALIAS) == INSN2_UNCOND_BRANCH
- || pinfo2 & INSN2_COND_BRANCH))
+ && (delayed_branch_p (ip) || compact_branch_p (ip))
+ /* Don't try branch relaxation when users specify
+ 16-bit/32-bit instructions. */
+ && !forced_insn_length)
{
bfd_boolean relax16 = *reloc_type > BFD_RELOC_UNUSED;
int type = relax16 ? *reloc_type - BFD_RELOC_UNUSED : 0;
- int uncond = (pinfo & INSN_UNCOND_BRANCH_DELAY
- || pinfo2 & INSN2_UNCOND_BRANCH) ? -1 : 0;
- int compact = pinfo2 & (INSN2_COND_BRANCH | INSN2_UNCOND_BRANCH);
+ int uncond = uncond_branch_p (ip) ? -1 : 0;
+ int compact = compact_branch_p (ip);
int al = pinfo & INSN_WRITE_GPR_31;
int length32;
gas_assert (address_expr != NULL);
gas_assert (!mips_relax.sequence);
+ relaxed_branch = TRUE;
length32 = relaxed_micromips_32bit_branch_length (NULL, NULL, uncond);
add_relaxed_insn (ip, relax32 ? length32 : 4, relax16 ? 2 : 4,
- RELAX_MICROMIPS_ENCODE (type, AT,
- forced_insn_length == 2,
- uncond, compact, al, relax32,
- 0, 0),
+ RELAX_MICROMIPS_ENCODE (type, AT, uncond, compact, al,
+ relax32, 0, 0),
address_expr->X_add_symbol,
address_expr->X_add_number);
*reloc_type = BFD_RELOC_UNUSED;
RELAX_MIPS16_ENCODE
(*reloc_type - BFD_RELOC_UNUSED,
forced_insn_length == 2, forced_insn_length == 4,
- prev_pinfo & INSN_UNCOND_BRANCH_DELAY,
+ delayed_branch_p (&history[0]),
history[0].mips16_absolute_jump_p),
make_expr_symbol (address_expr), 0);
}
- else if (mips_opts.mips16
- && ! ip->use_extend
- && *reloc_type != BFD_RELOC_MIPS16_JMP)
+ else if (mips_opts.mips16 && insn_length (ip) == 2)
{
- if ((pinfo & INSN_UNCOND_BRANCH_DELAY) == 0)
+ if (!delayed_branch_p (ip))
/* Make sure there is enough room to swap this instruction with
a following jump instruction. */
frag_grow (6);
{
if (mips_opts.mips16
&& mips_opts.noreorder
- && (prev_pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
+ && delayed_branch_p (&history[0]))
as_warn (_("extended instruction in delay slot"));
if (mips_relax.sequence)
if (!ip->complete_p && *reloc_type < BFD_RELOC_UNUSED)
{
bfd_reloc_code_real_type final_type[3];
+ reloc_howto_type *howto0;
reloc_howto_type *howto;
int i;
/* In a compound relocation, it is the final (outermost)
operator that determines the relocated field. */
- howto = bfd_reloc_type_lookup (stdoutput, final_type[i - 1]);
+ howto = howto0 = bfd_reloc_type_lookup (stdoutput, final_type[i - 1]);
+
if (howto == NULL)
{
/* To reproduce this failure try assembling gas/testsuites/
final_type[i - 1]);
howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_16);
}
-
- howto = bfd_reloc_type_lookup (stdoutput, final_type[0]);
+
+ if (i > 1)
+ howto0 = bfd_reloc_type_lookup (stdoutput, final_type[0]);
ip->fixp[0] = fix_new_exp (ip->frag, ip->where,
bfd_get_reloc_size (howto),
address_expr,
- howto->pc_relative, final_type[0]);
+ howto0 && howto0->pc_relative,
+ final_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)
+ if (final_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
|| lo16_reloc_p (reloc_type[0])))
ip->fixp[0]->fx_no_overflow = 1;
+ /* These relocations can have an addend that won't fit in 2 octets. */
+ if (reloc_type[0] == BFD_RELOC_MICROMIPS_7_PCREL_S1
+ || reloc_type[0] == BFD_RELOC_MICROMIPS_10_PCREL_S1)
+ ip->fixp[0]->fx_no_overflow = 1;
+
if (mips_relax.sequence)
{
if (mips_relax.first_fixup == 0)
break;
case APPEND_ADD_WITH_NOP:
- insert_into_history (0, 1, ip);
- if (mips_opts.micromips
- && (pinfo2 & INSN2_BRANCH_DELAY_32BIT))
- {
- add_fixed_insn (µmips_nop32_insn);
- insert_into_history (0, 1, µmips_nop32_insn);
- if (mips_relax.sequence)
- mips_relax.sizes[mips_relax.sequence - 1] += 4;
- }
- else
- {
- emit_nop ();
- if (mips_relax.sequence)
- mips_relax.sizes[mips_relax.sequence - 1] += NOP_INSN_SIZE;
- }
+ {
+ struct mips_cl_insn *nop;
+
+ insert_into_history (0, 1, ip);
+ nop = get_delay_slot_nop (ip);
+ add_fixed_insn (nop);
+ insert_into_history (0, 1, nop);
+ if (mips_relax.sequence)
+ mips_relax.sizes[mips_relax.sequence - 1] += insn_length (nop);
+ }
break;
case APPEND_ADD_COMPACT:
move_insn (ip, delay.frag, delay.where);
move_insn (&delay, ip->frag, ip->where + insn_length (ip));
}
- else if (mips_opts.micromips)
- {
- /* We don't reorder for micromips. */
- abort ();
- }
- else if (relaxed_branch)
+ else if (relaxed_branch || delay.frag != ip->frag)
{
/* 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;
+ delay.frag->fr_fix -= branch_disp;
if (delay.frag == ip->frag)
- move_insn (ip, ip->frag, ip->where - 4);
+ move_insn (ip, ip->frag, ip->where - branch_disp);
add_fixed_insn (&delay);
}
else
{
- move_insn (&delay, ip->frag, ip->where);
+ move_insn (&delay, ip->frag,
+ ip->where - branch_disp + insn_length (ip));
move_insn (ip, history[0].frag, history[0].where);
}
history[0] = *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)))
+ if ((delayed_branch_p (&history[1]) && uncond_branch_p (&history[1]))
+ || (compact_branch_p (&history[0]) && uncond_branch_p (&history[0])))
mips_no_prev_insn ();
/* We need to emit a label at the end of branch-likely macros. */
{
while (nops-- > 0)
add_fixed_insn (NOP_INSN);
- mips_move_labels ();
+ mips_move_text_labels ();
}
}
mips_no_prev_insn ();
decrease the size of prev_nop_frag. */
frag_wane (frag_now);
frag_new (0);
- mips_move_labels ();
+ mips_move_text_labels ();
}
mips_mark_labels ();
mips_clear_insn_labels ();
static void
end_noreorder (void)
{
-
mips_opts.noreorder--;
if (mips_opts.noreorder == 0 && prev_nop_frag != NULL)
{
sizeof (mips_macro_warning.first_insn_sizes));
memset (&mips_macro_warning.insns, 0, sizeof (mips_macro_warning.insns));
mips_macro_warning.delay_slot_p = (mips_opts.noreorder
- && (history[0].insn_mo->pinfo
- & (INSN_UNCOND_BRANCH_DELAY
- | INSN_COND_BRANCH_DELAY
- | INSN_COND_BRANCH_LIKELY)) != 0);
+ && delayed_branch_p (&history[0]));
switch (history[0].insn_mo->pinfo2
& (INSN2_BRANCH_DELAY_32BIT | INSN2_BRANCH_DELAY_16BIT))
{
continue;
case '2':
- gas_assert (!mips_opts.micromips);
- INSERT_OPERAND (0, BP, insn, va_arg (args, int));
+ INSERT_OPERAND (mips_opts.micromips, BP, insn, va_arg (args, int));
continue;
case 'n':
INSERT_OPERAND (1, OFFSET10, insn, va_arg (args, int));
continue;
+ case '\\':
+ INSERT_OPERAND (mips_opts.micromips,
+ 3BITPOS, insn, va_arg (args, unsigned int));
+ continue;
+
case '~':
- gas_assert (mips_opts.micromips);
- INSERT_OPERAND (1, OFFSET12, insn, va_arg (args, unsigned long));
+ INSERT_OPERAND (mips_opts.micromips,
+ OFFSET12, insn, va_arg (args, unsigned long));
continue;
case 'N':
case 'p':
case 'q':
{
+ offsetT value;
+
gas_assert (ep != NULL);
if (ep->X_op != O_constant)
*r = (int) BFD_RELOC_UNUSED + c;
- else
+ else if (calculate_reloc (*r, ep->X_add_number, &value))
{
- mips16_immed (NULL, 0, c, ep->X_add_number, FALSE, FALSE,
- FALSE, &insn.insn_opcode, &insn.use_extend,
- &insn.extend);
+ mips16_immed (NULL, 0, c, *r, value, 0, &insn.insn_opcode);
ep = NULL;
*r = BFD_RELOC_UNUSED;
}
frag_grow (8);
f = frag_more (0);
}
- if (!mips_opts.micromips)
- macro_build (NULL, "jalr", "d,s", RA, PIC_CALL_REG);
- else
+ if (mips_opts.micromips)
{
jalr = mips_opts.noreorder && !cprestore ? "jalr" : "jalrs";
- if (MIPS_JALR_HINT_P (ep))
+ if (MIPS_JALR_HINT_P (ep)
+ || (history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT))
macro_build (NULL, jalr, "t,s", RA, PIC_CALL_REG);
else
macro_build (NULL, jalr, "mj", PIC_CALL_REG);
}
+ else
+ macro_build (NULL, "jalr", "d,s", RA, PIC_CALL_REG);
if (MIPS_JALR_HINT_P (ep))
fix_new_exp (frag_now, f - frag_now->fr_literal, 4, ep, FALSE, jalr_reloc);
}
instruction specifically requires a 32-bit one. */
if (mips_opts.micromips
&& !(history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT))
- macro_build (NULL, "move", "mp,mj", dest, source );
+ macro_build (NULL, "move", "mp,mj", dest, source);
else
macro_build (NULL, HAVE_32BIT_GPRS ? "addu" : "daddu", "d,v,t",
dest, source, 0);
int ust = 0;
int lp = 0;
int ab = 0;
+ int off0 = 0;
int off;
offsetT maxnum;
bfd_reloc_code_real_type r;
case 2:
macro_build (NULL, "packrl.ph", "d,s,t", treg, treg, sreg);
break;
- default:
+ case 1:
+ case 3:
macro_build (NULL, "balign", "t,s,2", treg, sreg,
(int) imm_expr.X_add_number);
break;
+ default:
+ as_bad (_("BALIGN immediate not 0, 1, 2 or 3 (%lu)"),
+ (unsigned long) imm_expr.X_add_number);
+ break;
}
break;
{
expr1.X_add_number = offset_expr.X_add_number;
offset_expr.X_add_number =
- ((offset_expr.X_add_number + 0x8000) & 0xffff) - 0x8000;
+ SEXT_16BIT (offset_expr.X_add_number);
load_got_offset (tempreg, &offset_expr);
offset_expr.X_add_number = expr1.X_add_number;
/* If we are going to add in a base register, and the
used_at = 1;
}
- offset_expr.X_add_number =
- ((expr1.X_add_number + 0x8000) & 0xffff) - 0x8000;
+ offset_expr.X_add_number = SEXT_16BIT (expr1.X_add_number);
relax_switch ();
if (gpdelay)
if (mips_pic == NO_PIC)
{
s = jals ? "jalrs" : "jalr";
- if (mips_opts.micromips && dreg == RA)
+ if (mips_opts.micromips
+ && dreg == RA
+ && !(history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT))
macro_build (NULL, s, "mj", sreg);
else
macro_build (NULL, s, JALR_FMT, dreg, sreg);
s = (mips_opts.micromips && (!mips_opts.noreorder || cprestore)
? "jalrs" : "jalr");
- if (mips_opts.micromips && dreg == RA)
+ if (mips_opts.micromips
+ && dreg == RA
+ && !(history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT))
macro_build (NULL, s, "mj", sreg);
else
macro_build (NULL, s, JALR_FMT, dreg, sreg);
break;
+ case M_ACLR_AB:
+ ab = 1;
+ case M_ACLR_OB:
+ s = "aclr";
+ treg = EXTRACT_OPERAND (mips_opts.micromips, 3BITPOS, *ip);
+ fmt = "\\,~(b)";
+ off12 = 1;
+ goto ld_st;
+ case M_ASET_AB:
+ ab = 1;
+ case M_ASET_OB:
+ s = "aset";
+ treg = EXTRACT_OPERAND (mips_opts.micromips, 3BITPOS, *ip);
+ fmt = "\\,~(b)";
+ off12 = 1;
+ goto ld_st;
case M_LB_AB:
ab = 1;
s = "lb";
tempreg = AT;
used_at = 1;
ld_noat:
- 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;
- }
-
if (offset_expr.X_op != O_constant
&& offset_expr.X_op != O_symbol)
{
tempreg, tempreg, breg);
breg = tempreg;
}
- if (!off12)
+ if (off0)
+ {
+ if (offset_expr.X_add_number == 0)
+ tempreg = breg;
+ else
+ macro_build (&offset_expr, ADDRESS_ADDI_INSN,
+ "t,r,j", tempreg, breg, BFD_RELOC_LO16);
+ macro_build (NULL, s, fmt, treg, tempreg);
+ }
+ else if (!off12)
macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16, breg);
else
macro_build (NULL, s, fmt,
treg, (unsigned long) offset_expr.X_add_number, breg);
}
- else if (off12)
+ else if (off12 || off0)
{
- /* A 12-bit offset field is too narrow to be used for a low-part
- relocation, so load the whole address into the auxillary
- register. In the case of "A(b)" addresses, we first load
- absolute address "A" into the register and then add base
- register "b". In the case of "o(b)" addresses, we simply
- need to add 16-bit offset "o" to base register "b", and
+ /* A 12-bit or 0-bit offset field is too narrow to be used
+ for a low-part relocation, so load the whole address into
+ the auxillary register. In the case of "A(b)" addresses,
+ we first load absolute address "A" into the register and
+ then add base register "b". In the case of "o(b)" addresses,
+ we simply need to add 16-bit offset "o" to base register "b", and
offset_reloc already contains the relocations associated
with "o". */
if (ab)
tempreg, breg, -1,
offset_reloc[0], offset_reloc[1], offset_reloc[2]);
expr1.X_add_number = 0;
- macro_build (NULL, s, fmt,
- treg, (unsigned long) expr1.X_add_number, tempreg);
+ if (off0)
+ macro_build (NULL, s, fmt, treg, tempreg);
+ else
+ macro_build (NULL, s, fmt,
+ treg, (unsigned long) expr1.X_add_number, tempreg);
}
else if (mips_pic == NO_PIC)
{
}
break;
+
+ case M_SAA_AB:
+ ab = 1;
+ case M_SAA_OB:
+ s = "saa";
+ off0 = 1;
+ fmt = "t,(b)";
+ goto ld_st;
+ case M_SAAD_AB:
+ ab = 1;
+ case M_SAAD_OB:
+ s = "saad";
+ off0 = 1;
+ fmt = "t,(b)";
+ goto ld_st;
+
/* New code added to support COPZ instructions.
This code builds table entries out of the macros in mip_opcodes.
R4000 uses interlocks to handle coproc delays.
s = "c3";
copz:
gas_assert (!mips_opts.micromips);
- 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);
case '$': USE_BITS (OP_MASK_MT_H, OP_SH_MT_H); break;
case '*': USE_BITS (OP_MASK_MTACC_T, OP_SH_MTACC_T); break;
case '&': USE_BITS (OP_MASK_MTACC_D, OP_SH_MTACC_D); break;
+ case '\\': USE_BITS (OP_MASK_3BITPOS, OP_SH_3BITPOS); break;
+ case '~': USE_BITS (OP_MASK_OFFSET12, OP_SH_OFFSET12); break;
case 'g': USE_BITS (OP_MASK_RD, OP_SH_RD); break;
default:
as_bad (_("internal: bad mips opcode (unknown operand type `%c'): %s %s"),
break;
case '.': USE_BITS (OFFSET10); break;
case '1': USE_BITS (STYPE); break;
+ case '2': USE_BITS (BP); break;
+ case '3': USE_BITS (SA3); break;
+ case '4': USE_BITS (SA4); break;
+ case '5': USE_BITS (IMM8); break;
+ case '6': USE_BITS (RS); break;
+ case '7': USE_BITS (DSPACC); break;
+ case '8': USE_BITS (WRDSP); break;
+ case '0': USE_BITS (DSPSFT); break;
case '<': USE_BITS (SHAMT); break;
case '>': USE_BITS (SHAMT); break;
+ case '@': USE_BITS (IMM10); break;
case 'B': USE_BITS (CODE10); break;
case 'C': USE_BITS (COPZ); break;
case 'D': USE_BITS (FD); break;
case 'E': USE_BITS (RT); break;
case 'G': USE_BITS (RS); break;
- case 'H': USE_BITS (SEL); break;
+ case 'H': USE_BITS (SEL); break;
case 'K': USE_BITS (RS); break;
case 'M': USE_BITS (CCC); break;
case 'N': USE_BITS (BCC); break;
case 'S': USE_BITS (FS); break;
case 'T': USE_BITS (FT); break;
case 'V': USE_BITS (FS); break;
+ case '\\': USE_BITS (3BITPOS); break;
+ case '^': USE_BITS (RD); break;
case 'a': USE_BITS (TARGET); break;
case 'b': USE_BITS (RS); break;
case 'c': USE_BITS (CODE); break;
return;
if (!ok)
- sprintf (buf, _("opcode not supported on this processor: %s (%s)"),
+ sprintf (buf, _("Opcode not supported on this processor: %s (%s)"),
mips_cpu_info_from_arch (mips_opts.arch)->name,
mips_cpu_info_from_isa (mips_opts.isa)->name);
else
return;
break;
- case '2': /* DSP 2-bit unsigned immediate in bit 11. */
- gas_assert (!mips_opts.micromips);
+ case '2':
+ /* DSP 2-bit unsigned immediate in bit 11 (for standard MIPS
+ code) or 14 (for microMIPS code). */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if ((unsigned long) imm_expr.X_add_number != 1
as_bad (_("BALIGN immediate not 1 or 3 (%lu)"),
(unsigned long) imm_expr.X_add_number);
}
- INSERT_OPERAND (0, BP, *ip, imm_expr.X_add_number);
+ INSERT_OPERAND (mips_opts.micromips,
+ BP, *ip, imm_expr.X_add_number);
imm_expr.X_op = O_absent;
s = expr_end;
continue;
- case '3': /* DSP 3-bit unsigned immediate in bit 21. */
- gas_assert (!mips_opts.micromips);
- my_getExpression (&imm_expr, s);
- check_absolute_expr (ip, &imm_expr);
- if (imm_expr.X_add_number & ~OP_MASK_SA3)
- {
- as_bad (_("DSP immediate not in range 0..%d (%lu)"),
- OP_MASK_SA3, (unsigned long) imm_expr.X_add_number);
- }
- INSERT_OPERAND (0, SA3, *ip, imm_expr.X_add_number);
- imm_expr.X_op = O_absent;
- s = expr_end;
+ case '3':
+ /* DSP 3-bit unsigned immediate in bit 13 (for standard MIPS
+ code) or 21 (for microMIPS code). */
+ {
+ unsigned long mask = (mips_opts.micromips
+ ? MICROMIPSOP_MASK_SA3 : OP_MASK_SA3);
+
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ if ((unsigned long) imm_expr.X_add_number > mask)
+ as_bad (_("DSP immediate not in range 0..%lu (%lu)"),
+ mask, (unsigned long) imm_expr.X_add_number);
+ INSERT_OPERAND (mips_opts.micromips,
+ SA3, *ip, imm_expr.X_add_number);
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ }
continue;
- case '4': /* DSP 4-bit unsigned immediate in bit 21. */
- gas_assert (!mips_opts.micromips);
- my_getExpression (&imm_expr, s);
- check_absolute_expr (ip, &imm_expr);
- if (imm_expr.X_add_number & ~OP_MASK_SA4)
- {
- as_bad (_("DSP immediate not in range 0..%d (%lu)"),
- OP_MASK_SA4, (unsigned long) imm_expr.X_add_number);
- }
- INSERT_OPERAND (0, SA4, *ip, imm_expr.X_add_number);
- imm_expr.X_op = O_absent;
- s = expr_end;
+ case '4':
+ /* DSP 4-bit unsigned immediate in bit 12 (for standard MIPS
+ code) or 21 (for microMIPS code). */
+ {
+ unsigned long mask = (mips_opts.micromips
+ ? MICROMIPSOP_MASK_SA4 : OP_MASK_SA4);
+
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ if ((unsigned long) imm_expr.X_add_number > mask)
+ as_bad (_("DSP immediate not in range 0..%lu (%lu)"),
+ mask, (unsigned long) imm_expr.X_add_number);
+ INSERT_OPERAND (mips_opts.micromips,
+ SA4, *ip, imm_expr.X_add_number);
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ }
continue;
- case '5': /* DSP 8-bit unsigned immediate in bit 16. */
- gas_assert (!mips_opts.micromips);
- my_getExpression (&imm_expr, s);
- check_absolute_expr (ip, &imm_expr);
- if (imm_expr.X_add_number & ~OP_MASK_IMM8)
- {
- as_bad (_("DSP immediate not in range 0..%d (%lu)"),
- OP_MASK_IMM8, (unsigned long) imm_expr.X_add_number);
- }
- INSERT_OPERAND (0, IMM8, *ip, imm_expr.X_add_number);
- imm_expr.X_op = O_absent;
- s = expr_end;
+ case '5':
+ /* DSP 8-bit unsigned immediate in bit 13 (for standard MIPS
+ code) or 16 (for microMIPS code). */
+ {
+ unsigned long mask = (mips_opts.micromips
+ ? MICROMIPSOP_MASK_IMM8 : OP_MASK_IMM8);
+
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ if ((unsigned long) imm_expr.X_add_number > mask)
+ as_bad (_("DSP immediate not in range 0..%lu (%lu)"),
+ mask, (unsigned long) imm_expr.X_add_number);
+ INSERT_OPERAND (mips_opts.micromips,
+ IMM8, *ip, imm_expr.X_add_number);
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ }
continue;
- case '6': /* DSP 5-bit unsigned immediate in bit 21. */
- gas_assert (!mips_opts.micromips);
- my_getExpression (&imm_expr, s);
- check_absolute_expr (ip, &imm_expr);
- if (imm_expr.X_add_number & ~OP_MASK_RS)
- {
- as_bad (_("DSP immediate not in range 0..%d (%lu)"),
- OP_MASK_RS, (unsigned long) imm_expr.X_add_number);
- }
- INSERT_OPERAND (0, RS, *ip, imm_expr.X_add_number);
- imm_expr.X_op = O_absent;
- s = expr_end;
+ case '6':
+ /* DSP 5-bit unsigned immediate in bit 16 (for standard MIPS
+ code) or 21 (for microMIPS code). */
+ {
+ unsigned long mask = (mips_opts.micromips
+ ? MICROMIPSOP_MASK_RS : OP_MASK_RS);
+
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ if ((unsigned long) imm_expr.X_add_number > mask)
+ as_bad (_("DSP immediate not in range 0..%lu (%lu)"),
+ mask, (unsigned long) imm_expr.X_add_number);
+ INSERT_OPERAND (mips_opts.micromips,
+ RS, *ip, imm_expr.X_add_number);
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ }
continue;
case '7': /* Four DSP accumulators in bits 11,12. */
- gas_assert (!mips_opts.micromips);
- if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
- s[3] >= '0' && s[3] <= '3')
+ if (s[0] == '$' && s[1] == 'a' && s[2] == 'c'
+ && s[3] >= '0' && s[3] <= '3')
{
regno = s[3] - '0';
s += 4;
- INSERT_OPERAND (0, DSPACC, *ip, regno);
+ INSERT_OPERAND (mips_opts.micromips, DSPACC, *ip, regno);
continue;
}
else
as_bad (_("Invalid dsp acc register"));
break;
- case '8': /* DSP 6-bit unsigned immediate in bit 11. */
- gas_assert (!mips_opts.micromips);
- my_getExpression (&imm_expr, s);
- check_absolute_expr (ip, &imm_expr);
- if (imm_expr.X_add_number & ~OP_MASK_WRDSP)
- {
- as_bad (_("DSP immediate not in range 0..%d (%lu)"),
- OP_MASK_WRDSP,
- (unsigned long) imm_expr.X_add_number);
- }
- INSERT_OPERAND (0, WRDSP, *ip, imm_expr.X_add_number);
- imm_expr.X_op = O_absent;
- s = expr_end;
+ case '8':
+ /* DSP 6-bit unsigned immediate in bit 11 (for standard MIPS
+ code) or 14 (for microMIPS code). */
+ {
+ unsigned long mask = (mips_opts.micromips
+ ? MICROMIPSOP_MASK_WRDSP
+ : OP_MASK_WRDSP);
+
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ if ((unsigned long) imm_expr.X_add_number > mask)
+ as_bad (_("DSP immediate not in range 0..%lu (%lu)"),
+ mask, (unsigned long) imm_expr.X_add_number);
+ INSERT_OPERAND (mips_opts.micromips,
+ WRDSP, *ip, imm_expr.X_add_number);
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ }
continue;
case '9': /* Four DSP accumulators in bits 21,22. */
gas_assert (!mips_opts.micromips);
- if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
- s[3] >= '0' && s[3] <= '3')
+ if (s[0] == '$' && s[1] == 'a' && s[2] == 'c'
+ && s[3] >= '0' && s[3] <= '3')
{
regno = s[3] - '0';
s += 4;
as_bad (_("Invalid dsp acc register"));
break;
- case '0': /* DSP 6-bit signed immediate in bit 20. */
- gas_assert (!mips_opts.micromips);
- my_getExpression (&imm_expr, s);
- check_absolute_expr (ip, &imm_expr);
- min_range = -((OP_MASK_DSPSFT + 1) >> 1);
- max_range = ((OP_MASK_DSPSFT + 1) >> 1) - 1;
- if (imm_expr.X_add_number < min_range ||
- imm_expr.X_add_number > max_range)
- {
+ case '0':
+ /* DSP 6-bit signed immediate in bit 16 (for standard MIPS
+ code) or 20 (for microMIPS code). */
+ {
+ long mask = (mips_opts.micromips
+ ? MICROMIPSOP_MASK_DSPSFT : OP_MASK_DSPSFT);
+
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ min_range = -((mask + 1) >> 1);
+ max_range = ((mask + 1) >> 1) - 1;
+ if (imm_expr.X_add_number < min_range
+ || imm_expr.X_add_number > max_range)
as_bad (_("DSP immediate not in range %ld..%ld (%ld)"),
- (long) min_range, (long) max_range,
- (long) imm_expr.X_add_number);
- }
- INSERT_OPERAND (0, DSPSFT, *ip, imm_expr.X_add_number);
- imm_expr.X_op = O_absent;
- s = expr_end;
+ (long) min_range, (long) max_range,
+ (long) imm_expr.X_add_number);
+ INSERT_OPERAND (mips_opts.micromips,
+ DSPSFT, *ip, imm_expr.X_add_number);
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ }
continue;
case '\'': /* DSP 6-bit unsigned immediate in bit 16. */
continue;
case '@': /* DSP 10-bit signed immediate in bit 16. */
- gas_assert (!mips_opts.micromips);
- my_getExpression (&imm_expr, s);
- check_absolute_expr (ip, &imm_expr);
- min_range = -((OP_MASK_IMM10 + 1) >> 1);
- max_range = ((OP_MASK_IMM10 + 1) >> 1) - 1;
- if (imm_expr.X_add_number < min_range ||
- imm_expr.X_add_number > max_range)
- {
+ {
+ long mask = (mips_opts.micromips
+ ? MICROMIPSOP_MASK_IMM10 : OP_MASK_IMM10);
+
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ min_range = -((mask + 1) >> 1);
+ max_range = ((mask + 1) >> 1) - 1;
+ if (imm_expr.X_add_number < min_range
+ || imm_expr.X_add_number > max_range)
as_bad (_("DSP immediate not in range %ld..%ld (%ld)"),
(long) min_range, (long) max_range,
(long) imm_expr.X_add_number);
- }
- INSERT_OPERAND (0, IMM10, *ip, imm_expr.X_add_number);
+ INSERT_OPERAND (mips_opts.micromips,
+ IMM10, *ip, imm_expr.X_add_number);
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ }
+ continue;
+
+ case '^': /* DSP 5-bit unsigned immediate in bit 11. */
+ gas_assert (mips_opts.micromips);
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ if (imm_expr.X_add_number & ~MICROMIPSOP_MASK_RD)
+ as_bad (_("DSP immediate not in range 0..%d (%lu)"),
+ MICROMIPSOP_MASK_RD,
+ (unsigned long) imm_expr.X_add_number);
+ INSERT_OPERAND (1, RD, *ip, imm_expr.X_add_number);
imm_expr.X_op = O_absent;
s = expr_end;
continue;
as_bad (_("Invalid dsp/smartmips acc register"));
break;
+ case '\\': /* 3-bit bit position. */
+ {
+ unsigned long mask = (mips_opts.micromips
+ ? MICROMIPSOP_MASK_3BITPOS
+ : OP_MASK_3BITPOS);
+
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ if ((unsigned long) imm_expr.X_add_number > mask)
+ as_warn (_("Bit position for %s not in range 0..%lu (%lu)"),
+ ip->insn_mo->name,
+ mask, (unsigned long) imm_expr.X_add_number);
+ INSERT_OPERAND (mips_opts.micromips,
+ 3BITPOS, *ip, imm_expr.X_add_number);
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ }
+ continue;
+
case ',':
++argnum;
if (*s++ == *args)
break;
case '.': /* 10-bit offset. */
- case '~': /* 12-bit offset. */
gas_assert (mips_opts.micromips);
+ case '~': /* 12-bit offset. */
{
int shift = *args == '.' ? 9 : 11;
size_t i;
if (shift == 9)
INSERT_OPERAND (1, OFFSET10, *ip, imm_expr.X_add_number);
else
- INSERT_OPERAND (1, OFFSET12, *ip, imm_expr.X_add_number);
+ INSERT_OPERAND (mips_opts.micromips,
+ OFFSET12, *ip, imm_expr.X_add_number);
imm_expr.X_op = O_absent;
s = expr_end;
}
if (offset_expr.X_op == O_register)
break;
- *offset_reloc = (int) BFD_RELOC_UNUSED + c;
+ if (!forced_insn_length)
+ *offset_reloc = (int) BFD_RELOC_UNUSED + c;
+ else if (c == 'D')
+ *offset_reloc = BFD_RELOC_MICROMIPS_10_PCREL_S1;
+ else
+ *offset_reloc = BFD_RELOC_MICROMIPS_7_PCREL_S1;
s = expr_end;
continue;
{
static char buf[100];
sprintf (buf,
- _("opcode not supported on this processor: %s (%s)"),
+ _("Opcode not supported on this processor: %s (%s)"),
mips_cpu_info_from_arch (mips_opts.arch)->name,
mips_cpu_info_from_isa (mips_opts.isa)->name);
insn_error = buf;
case '\0':
if (*s == '\0')
{
+ offsetT value;
+
/* 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)
+ && insn->pinfo != INSN_MACRO
+ && calculate_reloc (*offset_reloc,
+ imm_expr.X_add_number, &value))
{
- valueT tmp;
-
- switch (*offset_reloc)
- {
- case BFD_RELOC_MIPS16_HI16_S:
- tmp = (imm_expr.X_add_number + 0x8000) >> 16;
- break;
-
- case BFD_RELOC_MIPS16_HI16:
- tmp = imm_expr.X_add_number >> 16;
- break;
-
- case BFD_RELOC_MIPS16_LO16:
- tmp = ((imm_expr.X_add_number + 0x8000) & 0xffff)
- - 0x8000;
- break;
-
- case BFD_RELOC_UNUSED:
- tmp = imm_expr.X_add_number;
- break;
-
- default:
- internalError ();
- }
- *offset_reloc = BFD_RELOC_UNUSED;
-
mips16_immed (NULL, 0, *imm_reloc - BFD_RELOC_UNUSED,
- tmp, TRUE, forced_insn_length == 2,
- forced_insn_length == 4, &ip->insn_opcode,
- &ip->use_extend, &ip->extend);
+ *offset_reloc, value, forced_insn_length,
+ &ip->insn_opcode);
imm_expr.X_op = O_absent;
*imm_reloc = BFD_RELOC_UNUSED;
+ *offset_reloc = BFD_RELOC_UNUSED;
}
return;
if (imm_expr.X_op != O_constant)
{
forced_insn_length = 4;
- ip->use_extend = TRUE;
- ip->extend = 0;
+ ip->insn_opcode |= MIPS16_EXTEND;
}
else
{
case 'm': /* Register list for save insn. */
case 'M': /* Register list for restore insn. */
{
- int opcode = 0;
+ int opcode = ip->insn_opcode;
int framesz = 0, seen_framesz = 0;
int nargs = 0, statics = 0, sregs = 0;
/* Finally build the instruction. */
if ((opcode >> 16) != 0 || framesz == 0)
- {
- ip->use_extend = TRUE;
- ip->extend = opcode >> 16;
- }
- ip->insn_opcode |= opcode & 0x7f;
+ opcode |= MIPS16_EXTEND;
+ ip->insn_opcode = opcode;
}
continue;
#define MIPS16_NUM_IMMED \
(sizeof mips16_immed_operands / sizeof mips16_immed_operands[0])
-/* Handle a mips16 instruction with an immediate value. This or's the
- small immediate value into *INSN. It sets *USE_EXTEND to indicate
- whether an extended value is needed; if one is needed, it sets
- *EXTEND to the value. The argument type is TYPE. The value is VAL.
- If SMALL is true, an unextended opcode was explicitly requested.
- If EXT is true, an extended opcode was explicitly requested. If
- WARN is true, warn if EXT does not match reality. */
+/* Marshal immediate value VAL for an extended MIPS16 instruction.
+ NBITS is the number of significant bits in VAL. */
+
+static unsigned long
+mips16_immed_extend (offsetT val, unsigned int nbits)
+{
+ int extval;
+ if (nbits == 16)
+ {
+ extval = ((val >> 11) & 0x1f) | (val & 0x7e0);
+ val &= 0x1f;
+ }
+ else if (nbits == 15)
+ {
+ extval = ((val >> 11) & 0xf) | (val & 0x7f0);
+ val &= 0xf;
+ }
+ else
+ {
+ extval = ((val & 0x1f) << 6) | (val & 0x20);
+ val = 0;
+ }
+ return (extval << 16) | val;
+}
+
+/* Install immediate value VAL into MIPS16 instruction *INSN,
+ extending it if necessary. The instruction in *INSN may
+ already be extended.
+
+ RELOC is the relocation that produced VAL, or BFD_RELOC_UNUSED
+ if none. In the former case, VAL is a 16-bit number with no
+ defined signedness.
+
+ TYPE is the type of the immediate field. USER_INSN_LENGTH
+ is the length that the user requested, or 0 if none. */
static void
-mips16_immed (char *file, unsigned int line, int type, offsetT val,
- bfd_boolean warn, bfd_boolean small, bfd_boolean ext,
- unsigned long *insn, bfd_boolean *use_extend,
- unsigned short *extend)
+mips16_immed (char *file, unsigned int line, int type,
+ bfd_reloc_code_real_type reloc, offsetT val,
+ unsigned int user_insn_length, unsigned long *insn)
{
const struct mips16_immed_operand *op;
int mintiny, maxtiny;
- bfd_boolean needext;
op = mips16_immed_operands;
while (op->type != type)
mintiny = 0;
maxtiny = (1 << op->nbits) - 1;
}
+ if (reloc != BFD_RELOC_UNUSED)
+ val &= 0xffff;
}
else
{
mintiny = - (1 << (op->nbits - 1));
maxtiny = (1 << (op->nbits - 1)) - 1;
+ if (reloc != BFD_RELOC_UNUSED)
+ val = SEXT_16BIT (val);
}
/* Branch offsets have an implicit 0 in the lowest bit. */
if ((val & ((1 << op->shift) - 1)) != 0
|| val < (mintiny << op->shift)
|| val > (maxtiny << op->shift))
- needext = TRUE;
- else
- needext = FALSE;
-
- if (warn && ext && ! needext)
- as_warn_where (file, line,
- _("extended operand requested but not required"));
- if (small && needext)
- as_bad_where (file, line, _("invalid unextended operand value"));
+ {
+ /* We need an extended instruction. */
+ if (user_insn_length == 2)
+ as_bad_where (file, line, _("invalid unextended operand value"));
+ else
+ *insn |= MIPS16_EXTEND;
+ }
+ else if (user_insn_length == 4)
+ {
+ /* The operand doesn't force an unextended instruction to be extended.
+ Warn if the user wanted an extended instruction anyway. */
+ *insn |= MIPS16_EXTEND;
+ as_warn_where (file, line,
+ _("extended operand requested but not required"));
+ }
- if (small || (! ext && ! needext))
+ if (mips16_opcode_length (*insn) == 2)
{
int insnval;
- *use_extend = FALSE;
insnval = ((val >> op->shift) & ((1 << op->nbits) - 1));
insnval <<= op->op_shift;
*insn |= insnval;
else
{
long minext, maxext;
- int extval;
-
- if (op->extu)
- {
- minext = 0;
- maxext = (1 << op->extbits) - 1;
- }
- else
- {
- minext = - (1 << (op->extbits - 1));
- maxext = (1 << (op->extbits - 1)) - 1;
- }
- if (val < minext || val > maxext)
- as_bad_where (file, line,
- _("operand value out of range for instruction"));
- *use_extend = TRUE;
- if (op->extbits == 16)
+ if (reloc == BFD_RELOC_UNUSED)
{
- extval = ((val >> 11) & 0x1f) | (val & 0x7e0);
- val &= 0x1f;
- }
- else if (op->extbits == 15)
- {
- extval = ((val >> 11) & 0xf) | (val & 0x7f0);
- val &= 0xf;
- }
- else
- {
- extval = ((val & 0x1f) << 6) | (val & 0x20);
- val = 0;
+ if (op->extu)
+ {
+ minext = 0;
+ maxext = (1 << op->extbits) - 1;
+ }
+ else
+ {
+ minext = - (1 << (op->extbits - 1));
+ maxext = (1 << (op->extbits - 1)) - 1;
+ }
+ if (val < minext || val > maxext)
+ as_bad_where (file, line,
+ _("operand value out of range for instruction"));
}
- *extend = (unsigned short) extval;
- *insn |= val;
+ *insn |= mips16_immed_extend (val, op->extbits);
}
}
\f
{"%gprel", BFD_RELOC_MIPS16_GPREL},
{"%got", BFD_RELOC_MIPS16_GOT16},
{"%call16", BFD_RELOC_MIPS16_CALL16},
- {"%hi", BFD_RELOC_MIPS16_HI16_S}
+ {"%hi", BFD_RELOC_MIPS16_HI16_S},
+ {"%tlsgd", BFD_RELOC_MIPS16_TLS_GD},
+ {"%tlsldm", BFD_RELOC_MIPS16_TLS_LDM},
+ {"%dtprel_hi", BFD_RELOC_MIPS16_TLS_DTPREL_HI16},
+ {"%dtprel_lo", BFD_RELOC_MIPS16_TLS_DTPREL_LO16},
+ {"%tprel_hi", BFD_RELOC_MIPS16_TLS_TPREL_HI16},
+ {"%tprel_lo", BFD_RELOC_MIPS16_TLS_TPREL_LO16},
+ {"%gottprel", BFD_RELOC_MIPS16_TLS_GOTTPREL}
};
OPTION_NO_DSPR2,
OPTION_MICROMIPS,
OPTION_NO_MICROMIPS,
+ OPTION_MCU,
+ OPTION_NO_MCU,
OPTION_COMPAT_ARCH_BASE,
OPTION_M4650,
OPTION_NO_M4650,
{"mno-dspr2", no_argument, NULL, OPTION_NO_DSPR2},
{"mmicromips", no_argument, NULL, OPTION_MICROMIPS},
{"mno-micromips", no_argument, NULL, OPTION_NO_MICROMIPS},
+ {"mmcu", no_argument, NULL, OPTION_MCU},
+ {"mno-mcu", no_argument, NULL, OPTION_NO_MCU},
/* Old-style architecture options. Don't add more of these. */
{"m4650", no_argument, NULL, OPTION_M4650},
mips_opts.ase_mt = 0;
break;
+ case OPTION_MCU:
+ mips_opts.ase_mcu = 1;
+ break;
+
+ case OPTION_NO_MCU:
+ mips_opts.ase_mcu = 0;
+ break;
+
case OPTION_MICROMIPS:
if (mips_opts.mips16 == 1)
{
}
if (arch_info == 0)
- arch_info = mips_parse_cpu ("default CPU", MIPS_CPU_STRING_DEFAULT);
+ {
+ arch_info = mips_parse_cpu ("default CPU", MIPS_CPU_STRING_DEFAULT);
+ gas_assert (arch_info);
+ }
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_warn (_("%s ISA does not support MT ASE"),
mips_cpu_info_from_isa (mips_opts.isa)->name);
+ if (mips_opts.ase_mcu == -1)
+ mips_opts.ase_mcu = (arch_info->flags & MIPS_CPU_ASE_MCU) ? 1 : 0;
+ if (mips_opts.ase_mcu && !ISA_SUPPORTS_MCU_ASE)
+ as_warn (_("%s ISA does not support MCU ASE"),
+ mips_cpu_info_from_isa (mips_opts.isa)->name);
+
file_mips_isa = mips_opts.isa;
file_ase_mips3d = mips_opts.ase_mips3d;
file_ase_mdmx = mips_opts.ase_mdmx;
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. */
+ there isn't supposed to be a matching LO. Ignore %gots against
+ constants; we'll report an error for those later. */
if (got16_reloc_p (l->fixp->fx_r_type)
- && !pic_need_relax (l->fixp->fx_addsy, l->seg))
+ && !(l->fixp->fx_addsy
+ && pic_need_relax (l->fixp->fx_addsy, l->seg)))
continue;
/* Check quickly whether the next fixup happens to be a matching %lo. */
}
}
-/* We may have combined relocations without symbols in the N32/N64 ABI.
- We have to prevent gas from dropping them. */
-
int
mips_force_relocation (fixS *fixp)
{
|| fixp->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1)
return 1;
- if (HAVE_NEWABI
- && S_GET_SEGMENT (fixp->fx_addsy) == bfd_abs_section_ptr
- && (fixp->fx_r_type == BFD_RELOC_MIPS_SUB
- || hi16_reloc_p (fixp->fx_r_type)
- || lo16_reloc_p (fixp->fx_r_type)))
- return 1;
-
return 0;
}
+/* Read the instruction associated with RELOC from BUF. */
+
+static unsigned int
+read_reloc_insn (char *buf, bfd_reloc_code_real_type reloc)
+{
+ if (mips16_reloc_p (reloc) || micromips_reloc_p (reloc))
+ return read_compressed_insn (buf, 4);
+ else
+ return read_insn (buf);
+}
+
+/* Write instruction INSN to BUF, given that it has been relocated
+ by RELOC. */
+
+static void
+write_reloc_insn (char *buf, bfd_reloc_code_real_type reloc,
+ unsigned long insn)
+{
+ if (mips16_reloc_p (reloc) || micromips_reloc_p (reloc))
+ write_compressed_insn (buf, insn, 4);
+ else
+ write_insn (buf, insn);
+}
+
/* Apply a fixup to the object file. */
void
md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
{
- bfd_byte *buf;
- long insn;
+ char *buf;
+ unsigned long insn;
reloc_howto_type *howto;
/* We ignore generic BFD relocations we don't know about. */
|| 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);
+ buf = fixP->fx_frag->fr_literal + fixP->fx_where;
gas_assert (!fixP->fx_pcrel || fixP->fx_r_type == BFD_RELOC_16_PCREL_S2
|| fixP->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
case BFD_RELOC_MIPS_TLS_DTPREL_HI16:
case BFD_RELOC_MIPS_TLS_DTPREL_LO16:
case BFD_RELOC_MIPS_TLS_GOTTPREL:
+ case BFD_RELOC_MIPS_TLS_TPREL32:
+ case BFD_RELOC_MIPS_TLS_TPREL64:
case BFD_RELOC_MIPS_TLS_TPREL_HI16:
case BFD_RELOC_MIPS_TLS_TPREL_LO16:
case BFD_RELOC_MICROMIPS_TLS_GD:
case BFD_RELOC_MICROMIPS_TLS_GOTTPREL:
case BFD_RELOC_MICROMIPS_TLS_TPREL_HI16:
case BFD_RELOC_MICROMIPS_TLS_TPREL_LO16:
+ case BFD_RELOC_MIPS16_TLS_GD:
+ case BFD_RELOC_MIPS16_TLS_LDM:
+ case BFD_RELOC_MIPS16_TLS_DTPREL_HI16:
+ case BFD_RELOC_MIPS16_TLS_DTPREL_LO16:
+ case BFD_RELOC_MIPS16_TLS_GOTTPREL:
+ case BFD_RELOC_MIPS16_TLS_TPREL_HI16:
+ case BFD_RELOC_MIPS16_TLS_TPREL_LO16:
+ if (!fixP->fx_addsy)
+ {
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("TLS relocation against a constant"));
+ break;
+ }
S_SET_THREAD_LOCAL (fixP->fx_addsy);
/* fall through */
case BFD_RELOC_MIPS_JALR:
case BFD_RELOC_HI16:
case BFD_RELOC_HI16_S:
+ case BFD_RELOC_LO16:
case BFD_RELOC_GPREL16:
case BFD_RELOC_MIPS_LITERAL:
case BFD_RELOC_MIPS_CALL16:
case BFD_RELOC_MIPS16_CALL16:
case BFD_RELOC_MIPS16_HI16:
case BFD_RELOC_MIPS16_HI16_S:
+ case BFD_RELOC_MIPS16_LO16:
case BFD_RELOC_MIPS16_JMP:
case BFD_RELOC_MICROMIPS_JMP:
case BFD_RELOC_MICROMIPS_GOT_DISP:
case BFD_RELOC_MICROMIPS_JALR:
case BFD_RELOC_MICROMIPS_HI16:
case BFD_RELOC_MICROMIPS_HI16_S:
+ case BFD_RELOC_MICROMIPS_LO16:
case BFD_RELOC_MICROMIPS_GPREL16:
case BFD_RELOC_MICROMIPS_LITERAL:
case BFD_RELOC_MICROMIPS_CALL16:
case BFD_RELOC_MICROMIPS_GOT_LO16:
case BFD_RELOC_MICROMIPS_CALL_HI16:
case BFD_RELOC_MICROMIPS_CALL_LO16:
- /* Nothing needed to do. The value comes from the reloc entry. */
+ if (fixP->fx_done)
+ {
+ offsetT value;
+
+ if (calculate_reloc (fixP->fx_r_type, *valP, &value))
+ {
+ insn = read_reloc_insn (buf, fixP->fx_r_type);
+ if (mips16_reloc_p (fixP->fx_r_type))
+ insn |= mips16_immed_extend (value, 16);
+ else
+ insn |= (value & 0xffff);
+ write_reloc_insn (buf, fixP->fx_r_type, insn);
+ }
+ else
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("Unsupported constant in relocation"));
+ }
break;
case BFD_RELOC_64:
if (fixP->fx_done)
{
if (8 <= sizeof (valueT))
- md_number_to_chars ((char *) buf, *valP, 8);
+ md_number_to_chars (buf, *valP, 8);
else
{
valueT hiv;
hiv = 0xffffffff;
else
hiv = 0;
- md_number_to_chars ((char *)(buf + (target_big_endian ? 4 : 0)),
- *valP, 4);
- md_number_to_chars ((char *)(buf + (target_big_endian ? 0 : 4)),
- hiv, 4);
+ md_number_to_chars (buf + (target_big_endian ? 4 : 0), *valP, 4);
+ md_number_to_chars (buf + (target_big_endian ? 0 : 4), hiv, 4);
}
}
break;
value now. This can happen if we have a .word which is not
resolved when it appears but is later defined. */
if (fixP->fx_done)
- md_number_to_chars ((char *) buf, *valP, fixP->fx_size);
- break;
-
- case BFD_RELOC_LO16:
- case BFD_RELOC_MIPS16_LO16:
- case BFD_RELOC_MICROMIPS_LO16:
- /* FIXME: Now that embedded-PIC is gone, some of this code/comment
- may be safe to remove, but if so it's not obvious. */
- /* When handling an embedded PIC switch statement, we can wind
- up deleting a LO16 reloc. See the 'o' case in mips_ip. */
- if (fixP->fx_done)
- {
- if (*valP + 0x8000 > 0xffff)
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("relocation overflow"));
- /* 32-bit microMIPS instructions are divided into two halfwords.
- Relocations always refer to the second halfword, regardless
- of endianness. */
- if (target_big_endian || fixP->fx_r_type == BFD_RELOC_MICROMIPS_LO16)
- buf += 2;
- md_number_to_chars ((char *) buf, *valP, 2);
- }
+ md_number_to_chars (buf, *valP, fixP->fx_size);
break;
case BFD_RELOC_16_PCREL_S2:
break;
/* Update old instruction data. */
- if (target_big_endian)
- insn = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
- else
- insn = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+ insn = read_insn (buf);
if (*valP + 0x20000 <= 0x3ffff)
{
insn |= (*valP >> 2) & 0xffff;
- md_number_to_chars ((char *) buf, insn, 4);
+ write_insn (buf, insn);
}
else if (mips_pic == NO_PIC
&& fixP->fx_done
fixP->fx_done = 0;
fixP->fx_addsy = section_symbol (text_section);
*valP += md_pcrel_from (fixP);
- md_number_to_chars ((char *) buf, insn, 4);
+ write_insn (buf, insn);
}
else
{
fill byte should be used, FILL points to an integer that contains
that byte, otherwise FILL is null.
- The MIPS assembler also automatically adjusts any preceding
- label. */
+ This function used to have the comment:
+
+ The MIPS assembler also automatically adjusts any preceding label.
+
+ The implementation therefore applied the adjustment to a maximum of
+ one label. However, other label adjustments are applied to batches
+ of labels, and adjusting just one caused problems when new labels
+ were added for the sake of debugging or unwind information.
+ We therefore adjust all preceding labels (given as LABELS) instead. */
static void
-mips_align (int to, int *fill, symbolS *label)
+mips_align (int to, int *fill, struct insn_label_list *labels)
{
mips_emit_delays ();
mips_record_compressed_mode ();
else
frag_align (to, fill ? *fill : 0, 0);
record_alignment (now_seg, to);
- if (label != NULL)
- {
- gas_assert (S_GET_SEGMENT (label) == now_seg);
- symbol_set_frag (label, frag_now);
- S_SET_VALUE (label, (valueT) frag_now_fix ());
- }
+ mips_move_labels (labels, FALSE);
}
/* Align to a given power of two. .align 0 turns off the automatic
struct insn_label_list *l = si->label_list;
/* Auto alignment should be switched on by next section change. */
auto_align = 1;
- mips_align (temp, fill_ptr, l != NULL ? l->label : NULL);
+ mips_align (temp, fill_ptr, l);
}
else
{
{
segment_info_type *si = seg_info (now_seg);
struct insn_label_list *l = si->label_list;
- symbolS *label;
- label = l != NULL ? l->label : NULL;
mips_emit_delays ();
if (log_size > 0 && auto_align)
- mips_align (log_size, 0, label);
+ mips_align (log_size, 0, l);
cons (1 << log_size);
mips_clear_insn_labels ();
}
{
segment_info_type *si = seg_info (now_seg);
struct insn_label_list *l = si->label_list;
- symbolS *label;
-
- label = l != NULL ? l->label : NULL;
mips_emit_delays ();
if (auto_align)
{
if (type == 'd')
- mips_align (3, 0, label);
+ mips_align (3, 0, l);
else
- mips_align (2, 0, label);
+ mips_align (2, 0, l);
}
float_cons (type);
mips_pic = NO_PIC;
else if (i == 2)
{
- mips_pic = SVR4_PIC;
+ mips_pic = SVR4_PIC;
mips_abicalls = TRUE;
}
else
}
else if (strcmp (name, "nomt") == 0)
mips_opts.ase_mt = 0;
+ else if (strcmp (name, "mcu") == 0)
+ mips_opts.ase_mcu = 1;
+ else if (strcmp (name, "nomcu") == 0)
+ mips_opts.ase_mcu = 0;
else if (strncmp (name, "mips", 4) == 0 || strncmp (name, "arch=", 5) == 0)
{
int reset = 0;
return;
}
+ if (mips_opts.mips16)
+ {
+ as_bad (_("%s not supported in MIPS16 mode"), ".cpload");
+ ignore_rest_of_line ();
+ return;
+ }
+
/* .cpload should be in a .set noreorder section. */
if (mips_opts.noreorder == 0)
as_warn (_(".cpload not in noreorder section"));
return;
}
+ if (mips_opts.mips16)
+ {
+ as_bad (_("%s not supported in MIPS16 mode"), ".cpsetup");
+ ignore_rest_of_line ();
+ return;
+ }
+
reg1 = tc_get_register (0);
SKIP_WHITESPACE ();
if (*input_line_pointer != ',')
return;
}
+ if (mips_opts.mips16)
+ {
+ as_bad (_("%s not supported in MIPS16 mode"), ".cplocal");
+ ignore_rest_of_line ();
+ return;
+ }
+
mips_gp_register = tc_get_register (0);
demand_empty_rest_of_line ();
}
return;
}
+ if (mips_opts.mips16)
+ {
+ as_bad (_("%s not supported in MIPS16 mode"), ".cprestore");
+ ignore_rest_of_line ();
+ return;
+ }
+
mips_cprestore_offset = get_absolute_expression ();
mips_cprestore_valid = 1;
return;
}
+ if (mips_opts.mips16)
+ {
+ as_bad (_("%s not supported in MIPS16 mode"), ".cpreturn");
+ ignore_rest_of_line ();
+ return;
+ }
+
macro_start ();
if (mips_cpreturn_register == -1)
{
demand_empty_rest_of_line ();
}
-/* Handle the .dtprelword and .dtpreldword pseudo-ops. They generate
- a 32-bit or 64-bit DTP-relative relocation (BYTES says which) for
- use in DWARF debug information. */
+/* Handle a .dtprelword, .dtpreldword, .tprelword, or .tpreldword
+ pseudo-op; DIRSTR says which. The pseudo-op generates a BYTES-size
+ DTP- or TP-relative relocation of type RTYPE, for use in either DWARF
+ debug information or MIPS16 TLS. */
static void
-s_dtprel_internal (size_t bytes)
+s_tls_rel_directive (const size_t bytes, const char *dirstr,
+ bfd_reloc_code_real_type rtype)
{
expressionS ex;
char *p;
if (ex.X_op != O_symbol)
{
- as_bad (_("Unsupported use of %s"), (bytes == 8
- ? ".dtpreldword"
- : ".dtprelword"));
+ as_bad (_("Unsupported use of %s"), dirstr);
ignore_rest_of_line ();
}
p = frag_more (bytes);
md_number_to_chars (p, 0, bytes);
- fix_new_exp (frag_now, p - frag_now->fr_literal, bytes, &ex, FALSE,
- (bytes == 8
- ? BFD_RELOC_MIPS_TLS_DTPREL64
- : BFD_RELOC_MIPS_TLS_DTPREL32));
-
+ fix_new_exp (frag_now, p - frag_now->fr_literal, bytes, &ex, FALSE, rtype);
demand_empty_rest_of_line ();
+ mips_clear_insn_labels ();
}
/* Handle .dtprelword. */
static void
s_dtprelword (int ignore ATTRIBUTE_UNUSED)
{
- s_dtprel_internal (4);
+ s_tls_rel_directive (4, ".dtprelword", BFD_RELOC_MIPS_TLS_DTPREL32);
}
/* Handle .dtpreldword. */
static void
s_dtpreldword (int ignore ATTRIBUTE_UNUSED)
{
- s_dtprel_internal (8);
+ s_tls_rel_directive (8, ".dtpreldword", BFD_RELOC_MIPS_TLS_DTPREL64);
+}
+
+/* Handle .tprelword. */
+
+static void
+s_tprelword (int ignore ATTRIBUTE_UNUSED)
+{
+ s_tls_rel_directive (4, ".tprelword", BFD_RELOC_MIPS_TLS_TPREL32);
+}
+
+/* Handle .tpreldword. */
+
+static void
+s_tpreldword (int ignore ATTRIBUTE_UNUSED)
+{
+ s_tls_rel_directive (8, ".tpreldword", BFD_RELOC_MIPS_TLS_TPREL64);
}
/* Handle the .gpvalue pseudo-op. This is used when generating NewABI PIC
{
segment_info_type *si;
struct insn_label_list *l;
- symbolS *label;
expressionS ex;
char *p;
si = seg_info (now_seg);
l = si->label_list;
- label = l != NULL ? l->label : NULL;
mips_emit_delays ();
if (auto_align)
- mips_align (2, 0, label);
+ mips_align (2, 0, l);
expression (&ex);
mips_clear_insn_labels ();
{
segment_info_type *si;
struct insn_label_list *l;
- symbolS *label;
expressionS ex;
char *p;
si = seg_info (now_seg);
l = si->label_list;
- label = l != NULL ? l->label : NULL;
mips_emit_delays ();
if (auto_align)
- mips_align (3, 0, label);
+ mips_align (3, 0, l);
expression (&ex);
mips_clear_insn_labels ();
symsec = S_GET_SEGMENT (sym);
/* This must duplicate the test in adjust_reloc_syms. */
- return (symsec != &bfd_und_section
- && symsec != &bfd_abs_section
+ return (!bfd_is_und_section (symsec)
+ && !bfd_is_abs_section (symsec)
&& !bfd_is_com_section (symsec)
&& !s_is_linkonce (sym, segtype)
#ifdef OBJ_ELF
{
bfd_boolean toofar;
- if (RELAX_MICROMIPS_U16BIT (fragp->fr_subtype))
- return 2;
-
if (fragp
&& S_IS_DEFINED (fragp->fr_symbol)
&& sec == S_GET_SEGMENT (fragp->fr_symbol))
{
if (RELAX_BRANCH_P (fragp->fr_subtype))
{
- bfd_byte *buf;
+ char *buf;
unsigned long insn;
expressionS exp;
fixS *fixp;
- buf = (bfd_byte *)fragp->fr_literal + fragp->fr_fix;
-
- if (target_big_endian)
- insn = bfd_getb32 (buf);
- else
- insn = bfd_getl32 (buf);
+ buf = fragp->fr_literal + fragp->fr_fix;
+ insn = read_insn (buf);
if (!RELAX_BRANCH_TOOFAR (fragp->fr_subtype))
{
exp.X_add_symbol = fragp->fr_symbol;
exp.X_add_number = fragp->fr_offset;
- fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
- 4, &exp, TRUE, BFD_RELOC_16_PCREL_S2);
+ fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp, TRUE,
+ BFD_RELOC_16_PCREL_S2);
fixp->fx_file = fragp->fr_file;
fixp->fx_line = fragp->fr_line;
- md_number_to_chars ((char *) buf, insn, 4);
- buf += 4;
+ buf = write_insn (buf, insn);
}
else
{
else
{
/* How many bytes in instructions we've already emitted? */
- i = buf - (bfd_byte *)fragp->fr_literal - fragp->fr_fix;
+ i = buf - fragp->fr_literal - fragp->fr_fix;
/* How many bytes in instructions from here to the end? */
i = fragp->fr_var - i;
}
i--;
insn |= i;
/* Branch over the jump. */
- md_number_to_chars ((char *) buf, insn, 4);
- buf += 4;
+ buf = write_insn (buf, insn);
/* nop */
- md_number_to_chars ((char *) buf, 0, 4);
- buf += 4;
+ buf = write_insn (buf, 0);
if (RELAX_BRANCH_LIKELY (fragp->fr_subtype))
{
/* Compute the PC offset from the current instruction to
the end of the variable frag. */
/* How many bytes in instructions we've already emitted? */
- i = buf - (bfd_byte *)fragp->fr_literal - fragp->fr_fix;
+ i = buf - fragp->fr_literal - fragp->fr_fix;
/* How many bytes in instructions from here to the end? */
i = fragp->fr_var - i;
/* Convert to instruction count. */
i >>= 2;
/* Don't decrement i, because we want to branch over the
delay slot. */
-
insn |= i;
- md_number_to_chars ((char *) buf, insn, 4);
- buf += 4;
- md_number_to_chars ((char *) buf, 0, 4);
- buf += 4;
+ buf = write_insn (buf, insn);
+ buf = write_insn (buf, 0);
}
uncond:
exp.X_add_symbol = fragp->fr_symbol;
exp.X_add_number = fragp->fr_offset;
- fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
- 4, &exp, FALSE, BFD_RELOC_MIPS_JMP);
+ fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp,
+ FALSE, BFD_RELOC_MIPS_JMP);
fixp->fx_file = fragp->fr_file;
fixp->fx_line = fragp->fr_line;
- md_number_to_chars ((char *) buf, insn, 4);
- buf += 4;
+ buf = write_insn (buf, insn);
}
else
{
exp.X_add_number = 0;
}
- fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
- 4, &exp, FALSE, BFD_RELOC_MIPS_GOT16);
+ fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp,
+ FALSE, BFD_RELOC_MIPS_GOT16);
fixp->fx_file = fragp->fr_file;
fixp->fx_line = fragp->fr_line;
- md_number_to_chars ((char *) buf, insn, 4);
- buf += 4;
+ buf = write_insn (buf, insn);
if (mips_opts.isa == ISA_MIPS1)
- {
- /* nop */
- md_number_to_chars ((char *) buf, 0, 4);
- buf += 4;
- }
+ /* nop */
+ buf = write_insn (buf, 0);
/* d/addiu $at, $at, <sym> R_MIPS_LO16 */
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);
+ fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp,
+ FALSE, BFD_RELOC_LO16);
fixp->fx_file = fragp->fr_file;
fixp->fx_line = fragp->fr_line;
- md_number_to_chars ((char *) buf, insn, 4);
- buf += 4;
+ buf = write_insn (buf, insn);
/* j(al)r $at. */
if (RELAX_BRANCH_LINK (fragp->fr_subtype))
insn = 0x00000008;
insn |= at << OP_SH_RS;
- md_number_to_chars ((char *) buf, insn, 4);
- buf += 4;
+ buf = write_insn (buf, insn);
}
}
- gas_assert (buf == (bfd_byte *)fragp->fr_literal
- + fragp->fr_fix + fragp->fr_var);
-
fragp->fr_fix += fragp->fr_var;
-
+ gas_assert (buf == fragp->fr_literal + fragp->fr_fix);
return;
}
/* Relax microMIPS branches. */
if (RELAX_MICROMIPS_P (fragp->fr_subtype))
{
- bfd_byte *buf = (bfd_byte *) (fragp->fr_literal + fragp->fr_fix);
+ char *buf = fragp->fr_literal + fragp->fr_fix;
bfd_boolean compact = RELAX_MICROMIPS_COMPACT (fragp->fr_subtype);
bfd_boolean al = RELAX_MICROMIPS_LINK (fragp->fr_subtype);
int type = RELAX_MICROMIPS_TYPE (fragp->fr_subtype);
- unsigned long jal, jalr, jr;
-
+ bfd_boolean short_ds;
unsigned long insn;
expressionS exp;
fixS *fixp;
because if there is linker relaxation, we're going to
need the relocations. */
if (type == 'D')
- fixp = fix_new_exp (fragp,
- buf - (bfd_byte *) fragp->fr_literal,
- 2, &exp, TRUE,
+ fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 2, &exp, TRUE,
BFD_RELOC_MICROMIPS_10_PCREL_S1);
else if (type == 'E')
- fixp = fix_new_exp (fragp,
- buf - (bfd_byte *) fragp->fr_literal,
- 2, &exp, TRUE,
+ fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 2, &exp, TRUE,
BFD_RELOC_MICROMIPS_7_PCREL_S1);
else
abort ();
return;
}
- /* Handle 32-bit branches that fit or forced to fit. */
+ /* Handle 32-bit branches that fit or are forced to fit. */
if (!RELAX_MICROMIPS_RELAX32 (fragp->fr_subtype)
|| !RELAX_MICROMIPS_TOOFAR32 (fragp->fr_subtype))
{
/* We generate a fixup instead of applying it right now,
because if there is linker relaxation, we're going to
need the relocations. */
- fixp = fix_new_exp (fragp, buf - (bfd_byte *) fragp->fr_literal,
- 4, &exp, TRUE, BFD_RELOC_MICROMIPS_16_PCREL_S1);
+ fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp, TRUE,
+ BFD_RELOC_MICROMIPS_16_PCREL_S1);
fixp->fx_file = fragp->fr_file;
fixp->fx_line = fragp->fr_line;
/* Relax 16-bit branches to 32-bit branches. */
if (type != 0)
{
- if (target_big_endian)
- insn = bfd_getb16 (buf);
- else
- insn = bfd_getl16 (buf);
+ insn = read_compressed_insn (buf, 2);
if ((insn & 0xfc00) == 0xcc00) /* b16 */
insn = 0x94000000; /* beq */
if (!RELAX_MICROMIPS_RELAX32 (fragp->fr_subtype)
|| !RELAX_MICROMIPS_TOOFAR32 (fragp->fr_subtype))
{
- md_number_to_chars ((char *) buf, insn >> 16, 2);
- buf += 2;
- md_number_to_chars ((char *) buf, insn & 0xffff, 2);
- buf += 2;
-
- gas_assert (buf == ((bfd_byte *) fragp->fr_literal
- + fragp->fr_fix));
+ buf = write_compressed_insn (buf, insn, 4);
+ gas_assert (buf == fragp->fr_literal + fragp->fr_fix);
return;
}
}
else
- {
- unsigned long next;
-
- if (target_big_endian)
- {
- insn = bfd_getb16 (buf);
- next = bfd_getb16 (buf + 2);
- }
- else
- {
- insn = bfd_getl16 (buf);
- next = bfd_getl16 (buf + 2);
- }
- insn = (insn << 16) | next;
- }
+ insn = read_compressed_insn (buf, 4);
/* Relax 32-bit branches to a sequence of instructions. */
as_warn_where (fragp->fr_file, fragp->fr_line,
_("Relaxed out-of-range branch into a jump"));
- /* Check the short-delay-slot bit. */
- if (al && (insn & 0x02000000) != 0)
- {
- jal = 0x74000000; /* jals */
- jalr = 0x45e0; /* jalrs */
- }
- else
- {
- jal = 0xf4000000; /* jal */
- jalr = 0x45c0; /* jalr */
- }
- jr = compact ? 0x45a0 : 0x4580; /* jr/c */
+ /* Set the short-delay-slot bit. */
+ short_ds = al && (insn & 0x02000000) != 0;
if (!RELAX_MICROMIPS_UNCOND (fragp->fr_subtype))
{
#endif
/* Refer to it. */
- fixp = fix_new (fragp, buf - (bfd_byte *) fragp->fr_literal,
- 4, l, 0, TRUE, BFD_RELOC_MICROMIPS_16_PCREL_S1);
+ fixp = fix_new (fragp, buf - fragp->fr_literal, 4, l, 0, TRUE,
+ BFD_RELOC_MICROMIPS_16_PCREL_S1);
fixp->fx_file = fragp->fr_file;
fixp->fx_line = fragp->fr_line;
/* Branch over the jump. */
- md_number_to_chars ((char *) buf, insn >> 16, 2);
- buf += 2;
- md_number_to_chars ((char *) buf, insn & 0xffff, 2);
- buf += 2;
-
+ buf = write_compressed_insn (buf, insn, 4);
if (!compact)
- {
- /* nop */
- insn = 0x0c00;
- md_number_to_chars ((char *) buf, insn, 2);
- buf += 2;
- }
+ /* nop */
+ buf = write_compressed_insn (buf, 0x0c00, 2);
}
if (mips_pic == NO_PIC)
{
+ unsigned long jal = short_ds ? 0x74000000 : 0xf4000000; /* jal/s */
+
/* j/jal/jals <sym> R_MICROMIPS_26_S1 */
insn = al ? jal : 0xd4000000;
- fixp = fix_new_exp (fragp, buf - (bfd_byte *) fragp->fr_literal,
- 4, &exp, FALSE, BFD_RELOC_MICROMIPS_JMP);
+ fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp, FALSE,
+ BFD_RELOC_MICROMIPS_JMP);
fixp->fx_file = fragp->fr_file;
fixp->fx_line = fragp->fr_line;
- md_number_to_chars ((char *) buf, insn >> 16, 2);
- buf += 2;
- md_number_to_chars ((char *) buf, insn & 0xffff, 2);
- buf += 2;
-
+ buf = write_compressed_insn (buf, insn, 4);
if (compact)
- {
- /* nop */
- insn = 0x0c00;
- md_number_to_chars ((char *) buf, insn, 2);
- buf += 2;
- }
+ /* nop */
+ buf = write_compressed_insn (buf, 0x0c00, 2);
}
else
{
unsigned long at = RELAX_MICROMIPS_AT (fragp->fr_subtype);
+ unsigned long jalr = short_ds ? 0x45e0 : 0x45c0; /* jalr/s */
+ unsigned long jr = compact ? 0x45a0 : 0x4580; /* jr/c */
/* lw/ld $at, <sym>($gp) R_MICROMIPS_GOT16 */
insn = HAVE_64BIT_ADDRESSES ? 0xdc1c0000 : 0xfc1c0000;
exp.X_add_number = 0;
}
- fixp = fix_new_exp (fragp, buf - (bfd_byte *) fragp->fr_literal,
- 4, &exp, FALSE, BFD_RELOC_MICROMIPS_GOT16);
+ fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp, FALSE,
+ BFD_RELOC_MICROMIPS_GOT16);
fixp->fx_file = fragp->fr_file;
fixp->fx_line = fragp->fr_line;
- md_number_to_chars ((char *) buf, insn >> 16, 2);
- buf += 2;
- md_number_to_chars ((char *) buf, insn & 0xffff, 2);
- buf += 2;
+ buf = write_compressed_insn (buf, insn, 4);
/* d/addiu $at, $at, <sym> R_MICROMIPS_LO16 */
insn = HAVE_64BIT_ADDRESSES ? 0x5c000000 : 0x30000000;
insn |= at << MICROMIPSOP_SH_RT | at << MICROMIPSOP_SH_RS;
- fixp = fix_new_exp (fragp, buf - (bfd_byte *) fragp->fr_literal,
- 4, &exp, FALSE, BFD_RELOC_MICROMIPS_LO16);
+ fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp, FALSE,
+ BFD_RELOC_MICROMIPS_LO16);
fixp->fx_file = fragp->fr_file;
fixp->fx_line = fragp->fr_line;
- md_number_to_chars ((char *) buf, insn >> 16, 2);
- buf += 2;
- md_number_to_chars ((char *) buf, insn & 0xffff, 2);
- buf += 2;
+ buf = write_compressed_insn (buf, insn, 4);
/* jr/jrc/jalr/jalrs $at */
insn = al ? jalr : jr;
insn |= at << MICROMIPSOP_SH_MJ;
- md_number_to_chars ((char *) buf, insn & 0xffff, 2);
- buf += 2;
+ buf = write_compressed_insn (buf, insn, 2);
}
- gas_assert (buf == (bfd_byte *) fragp->fr_literal + fragp->fr_fix);
+ gas_assert (buf == fragp->fr_literal + fragp->fr_fix);
return;
}
{
int type;
const struct mips16_immed_operand *op;
- bfd_boolean small, ext;
offsetT val;
- bfd_byte *buf;
+ char *buf;
+ unsigned int user_length, length;
unsigned long insn;
- bfd_boolean use_extend;
- unsigned short extend;
+ bfd_boolean ext;
type = RELAX_MIPS16_TYPE (fragp->fr_subtype);
op = mips16_immed_operands;
while (op->type != type)
++op;
- if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
- {
- small = FALSE;
- ext = TRUE;
- }
- else
- {
- small = TRUE;
- ext = FALSE;
- }
-
+ ext = RELAX_MIPS16_EXTENDED (fragp->fr_subtype);
val = resolve_symbol_value (fragp->fr_symbol);
if (op->pcrel)
{
as_warn_where (fragp->fr_file, fragp->fr_line,
_("extended instruction in delay slot"));
- buf = (bfd_byte *) (fragp->fr_literal + fragp->fr_fix);
+ buf = fragp->fr_literal + fragp->fr_fix;
- if (target_big_endian)
- insn = bfd_getb16 (buf);
- else
- insn = bfd_getl16 (buf);
+ insn = read_compressed_insn (buf, 2);
+ if (ext)
+ insn |= MIPS16_EXTEND;
- mips16_immed (fragp->fr_file, fragp->fr_line, type, val,
- RELAX_MIPS16_USER_EXT (fragp->fr_subtype),
- small, ext, &insn, &use_extend, &extend);
+ if (RELAX_MIPS16_USER_EXT (fragp->fr_subtype))
+ user_length = 4;
+ else if (RELAX_MIPS16_USER_SMALL (fragp->fr_subtype))
+ user_length = 2;
+ else
+ user_length = 0;
- if (use_extend)
- {
- md_number_to_chars ((char *) buf, 0xf000 | extend, 2);
- fragp->fr_fix += 2;
- buf += 2;
- }
+ mips16_immed (fragp->fr_file, fragp->fr_line, type,
+ BFD_RELOC_UNUSED, val, user_length, &insn);
- md_number_to_chars ((char *) buf, insn, 2);
- fragp->fr_fix += 2;
- buf += 2;
+ length = (ext ? 4 : 2);
+ gas_assert (mips16_opcode_length (insn) == length);
+ write_compressed_insn (buf, insn, length);
+ fragp->fr_fix += length;
}
else
{
| RELAX_DELAY_SLOT_SIZE_SECOND);
msg = macro_warning (s);
if (msg != NULL)
- as_warn_where (fragp->fr_file, fragp->fr_line, msg);
+ as_warn_where (fragp->fr_file, fragp->fr_line, "%s", msg);
subtype &= ~s;
}
& (RELAX_SECOND_LONGER | RELAX_NOMACRO | RELAX_DELAY_SLOT));
msg = macro_warning (s);
if (msg != NULL)
- as_warn_where (fragp->fr_file, fragp->fr_line, msg);
+ as_warn_where (fragp->fr_file, fragp->fr_line, "%s", msg);
subtype &= ~s;
}
move it. This also bumps the value of the symbol by 1 in compressed
code. */
-void
+static void
mips_record_label (symbolS *sym)
{
segment_info_type *si = seg_info (now_seg);
dwarf2_emit_label (sym);
#endif
}
+
+/* This function is called by tc_new_dot_label whenever a new dot symbol
+ is defined. */
+
+void
+mips_add_dot_label (symbolS *sym)
+{
+ mips_record_label (sym);
+ if (mips_assembling_insn && HAVE_CODE_COMPRESSION)
+ mips_compressed_mark_label (sym);
+}
\f
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
elf_elfheader (stdoutput)->e_flags |= EF_MIPS_NOREORDER;
if (mips_pic != NO_PIC)
{
- elf_elfheader (stdoutput)->e_flags |= EF_MIPS_PIC;
+ elf_elfheader (stdoutput)->e_flags |= EF_MIPS_PIC;
elf_elfheader (stdoutput)->e_flags |= EF_MIPS_CPIC;
}
if (mips_abicalls)
case 2:
if (nop_opcode == NOP_OPCODE_MICROMIPS)
{
- md_number_to_chars (p, micromips_nop16_insn.insn_opcode, 2);
- p += 2;
+ p = write_compressed_insn (p, micromips_nop16_insn.insn_opcode, 2);
break;
}
*p++ = '\0';
{ "4ksd", MIPS_CPU_ASE_SMARTMIPS, ISA_MIPS32R2, CPU_MIPS32R2 },
{ "m4k", 0, ISA_MIPS32R2, CPU_MIPS32R2 },
{ "m4kp", 0, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "m14k", MIPS_CPU_ASE_MCU, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "m14kc", MIPS_CPU_ASE_MCU, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "m14ke", MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_DSPR2 | MIPS_CPU_ASE_MCU,
+ ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "m14kec", MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_DSPR2 | MIPS_CPU_ASE_MCU,
+ ISA_MIPS32R2, CPU_MIPS32R2 },
{ "24kc", 0, ISA_MIPS32R2, CPU_MIPS32R2 },
{ "24kf2_1", 0, ISA_MIPS32R2, CPU_MIPS32R2 },
{ "24kf", 0, ISA_MIPS32R2, CPU_MIPS32R2 },
ISA_MIPS32R2, CPU_MIPS32R2 },
{ "34kx", MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
ISA_MIPS32R2, CPU_MIPS32R2 },
+ /* 34Kn is a 34kc without DSP. */
+ { "34kn", MIPS_CPU_ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
/* 74K with DSP and DSPR2 ASE, other ASEs are optional. */
{ "74kc", MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_DSPR2,
ISA_MIPS32R2, CPU_MIPS32R2 },
/* Cavium Networks Octeon CPU core */
{ "octeon", 0, ISA_MIPS64R2, CPU_OCTEON },
+ { "octeon+", 0, ISA_MIPS64R2, CPU_OCTEONP },
+ { "octeon2", 0, ISA_MIPS64R2, CPU_OCTEON2 },
/* RMI Xlr */
{ "xlr", 0, ISA_MIPS64, CPU_XLR },
+ /* Broadcom XLP.
+ XLP is mostly like XLR, with the prominent exception that it is
+ MIPS64R2 rather than MIPS64. */
+ { "xlp", 0, ISA_MIPS64R2, CPU_XLR },
+
/* End marker */
{ NULL, 0, 0, 0 }
};
-mmt generate MT instructions\n\
-mno-mt do not generate MT instructions\n"));
fprintf (stream, _("\
+-mmcu generate MCU instructions\n\
+-mno-mcu do not generate MCU 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\