/* 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
Free Software Foundation, Inc.
Contributed by the OSF and Ralph Campbell.
Written by Keith Knowles and Ralph Campbell, working independently.
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
};
#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;
/* True if CPU has a ror instruction. */
#define CPU_HAS_ROR(CPU) CPU_HAS_DROR (CPU)
+/* 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 has seq/sne and seqi/snei instructions. */
-#define CPU_HAS_SEQ(CPU) ((CPU) == CPU_OCTEON)
+#define CPU_HAS_SEQ(CPU) (CPU_IS_OCTEON (CPU))
/* 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)
+#define NO_ISA_COP(CPU) (CPU_IS_OCTEON (CPU))
/* True if mflo and mfhi can be immediately followed by instructions
which write to the HI and LO registers.
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)
/* Is the given value a sign-extended 32-bit value? */
#define IS_SEXT_32BIT_NUM(x) \
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},
}
}
-/* 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. */
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. */
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)
{
mips_relax.sequence = 0;
}
+/* 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
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 (pinfo2 & INSN2_READ_GPR_Z)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RZ, *ip);
}
+ if (mips_opts.micromips)
+ {
+ 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;
}
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 (pinfo2 & INSN2_WRITE_GPR_S)
+ 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;
}
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;
/* 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
- MIPS16/microMIPS code, which uses variant frags for different
- purposes. */
- if (!HAVE_CODE_COMPRESSION
+ 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. */
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
}
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;
enum append_method method;
bfd_boolean relax32;
+ int branch_disp;
if (mips_fix_loongson2f && !HAVE_CODE_COMPRESSION)
fix_loongson2f (ip);
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
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
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));
+ 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);
}
&& ! ip->use_extend
&& *reloc_type != BFD_RELOC_MIPS16_JMP)
{
- 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)
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)
{
/* 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))
{
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':
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))
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;
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, 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.
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"),
+ as_bad (_("Opcode not supported on this processor: %s"),
mips_cpu_info_from_arch (mips_opts.arch)->name);
break;
}
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"),
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 '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
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;
{"%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)
{
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;
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:
S_SET_THREAD_LOCAL (fixP->fx_addsy);
/* fall through */
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;
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 ();
{
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))
| 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;
}
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)
{ "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 },
/* 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\