aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
authorRichard Sandiford <rdsandiford@googlemail.com>2005-03-09 09:17:02 +0000
committerRichard Sandiford <rdsandiford@googlemail.com>2005-03-09 09:17:02 +0000
commit1e91584932efd70020c8c98037d0cb93a0552a20 (patch)
treed2d8e07813c116ab49d9afc0eac38d8e50e8020f /gas
parentbf12938eac60c7a1207ac699627b582ffed0848b (diff)
downloadbinutils-1e91584932efd70020c8c98037d0cb93a0552a20.zip
binutils-1e91584932efd70020c8c98037d0cb93a0552a20.tar.gz
binutils-1e91584932efd70020c8c98037d0cb93a0552a20.tar.bz2
* config/tc-mips.c (dummy_opcode): Delete.
(nop_insn, mips16_nop_insn): New variables. (NOP_INSN): New macro. (insn_length, create_insn, install_insn, move_insn, add_fixed_insn) (add_relaxed_insn, insert_into_history, emit_nop): New functions. (md_begin): Initialize nop_insn and mips16_nop_insn. (append_insn): Use the new emit_nop function to add nops, recording them in the history buffer. Use add_fixed_insn or add_relaxed_insn to reserve room for the instruction and install_insn to install the final form. Use insert_into_history to record the instruction in the history buffer. Use move_insn to do delay slot filling. (mips_emit_delays): Use add_fixed_insn instead of the emit_nop macro. (macro_build, mips16_macro_build, macro_build_lui, mips_ip) (mips16_ip): Use create_insn to initialize mips_cl_insns.
Diffstat (limited to 'gas')
-rw-r--r--gas/ChangeLog17
-rw-r--r--gas/config/tc-mips.c564
2 files changed, 269 insertions, 312 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 266c97b..e2efc11 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,5 +1,22 @@
2005-03-09 Richard Sandiford <rsandifo@redhat.com>
+ * config/tc-mips.c (dummy_opcode): Delete.
+ (nop_insn, mips16_nop_insn): New variables.
+ (NOP_INSN): New macro.
+ (insn_length, create_insn, install_insn, move_insn, add_fixed_insn)
+ (add_relaxed_insn, insert_into_history, emit_nop): New functions.
+ (md_begin): Initialize nop_insn and mips16_nop_insn.
+ (append_insn): Use the new emit_nop function to add nops, recording
+ them in the history buffer. Use add_fixed_insn or add_relaxed_insn
+ to reserve room for the instruction and install_insn to install the
+ final form. Use insert_into_history to record the instruction in
+ the history buffer. Use move_insn to do delay slot filling.
+ (mips_emit_delays): Use add_fixed_insn instead of the emit_nop macro.
+ (macro_build, mips16_macro_build, macro_build_lui, mips_ip)
+ (mips16_ip): Use create_insn to initialize mips_cl_insns.
+
+2005-03-09 Richard Sandiford <rsandifo@redhat.com>
+
* config/tc-mips.c (INSERT_BITS, EXTRACT_BITS, INSERT_OPERAND)
(EXTRACT_OPERAND, MIPS16_INSERT_OPERAND, MIPS16_EXTRACT_OPERAND): New.
(insn_uses_reg, reg_needs_delay, append_insn, macro_build)
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c
index 792226f..5a3deda 100644
--- a/gas/config/tc-mips.c
+++ b/gas/config/tc-mips.c
@@ -560,9 +560,11 @@ static int mips_debug = 0;
/* A list of previous instructions, with index 0 being the most recent. */
static struct mips_cl_insn history[2];
-/* If we don't want information for a history[] entry, we
- point the insn_mo field at this dummy integer. */
-static const struct mips_opcode dummy_opcode = { NULL, NULL, 0, 0, 0, 0, 0 };
+/* Nop instructions used by emit_nop. */
+static struct mips_cl_insn nop_insn, mips16_nop_insn;
+
+/* The appropriate nop for the current mode. */
+#define NOP_INSN (mips_opts.mips16 ? &mips16_nop_insn : &nop_insn)
/* If this is set, it points to a frag holding nop instructions which
were inserted before the start of a noreorder section. If those
@@ -1159,6 +1161,130 @@ mips_target_format (void)
}
}
+/* Return the length of instruction INSN. */
+
+static inline unsigned int
+insn_length (const struct mips_cl_insn *insn)
+{
+ if (!mips_opts.mips16)
+ return 4;
+ return insn->mips16_absolute_jump_p || insn->use_extend ? 4 : 2;
+}
+
+/* Initialise INSN from opcode entry MO. Leave its position unspecified. */
+
+static void
+create_insn (struct mips_cl_insn *insn, const struct mips_opcode *mo)
+{
+ 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;
+ for (i = 0; i < ARRAY_SIZE (insn->fixp); i++)
+ insn->fixp[i] = NULL;
+ insn->fixed_p = (mips_opts.noreorder > 0);
+ insn->noreorder_p = (mips_opts.noreorder > 0);
+ insn->mips16_absolute_jump_p = 0;
+}
+
+/* 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 (!mips_opts.mips16)
+ md_number_to_chars (f, insn->insn_opcode, 4);
+ 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);
+ }
+ 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);
+ }
+}
+
+/* Move INSN to offset WHERE in FRAG. Adjust the fixups accordingly
+ and install the opcode in the new location. */
+
+static void
+move_insn (struct mips_cl_insn *insn, fragS *frag, long where)
+{
+ size_t i;
+
+ insn->frag = frag;
+ insn->where = where;
+ for (i = 0; i < ARRAY_SIZE (insn->fixp); i++)
+ if (insn->fixp[i] != NULL)
+ {
+ insn->fixp[i]->fx_frag = frag;
+ insn->fixp[i]->fx_where = where;
+ }
+ install_insn (insn);
+}
+
+/* Add INSN to the end of the output. */
+
+static void
+add_fixed_insn (struct mips_cl_insn *insn)
+{
+ char *f = frag_more (insn_length (insn));
+ move_insn (insn, frag_now, f - frag_now->fr_literal);
+}
+
+/* Start a variant frag and move INSN to the start of the variant part,
+ marking it as fixed. The other arguments are as for frag_var. */
+
+static void
+add_relaxed_insn (struct mips_cl_insn *insn, int max_chars, int var,
+ relax_substateT subtype, symbolS *symbol, offsetT offset)
+{
+ frag_grow (max_chars);
+ move_insn (insn, frag_now, frag_more (0) - frag_now->fr_literal);
+ insn->fixed_p = 1;
+ frag_var (rs_machine_dependent, max_chars, var,
+ subtype, symbol, offset, NULL);
+}
+
+/* Insert N copies of INSN into the history buffer, starting at
+ position FIRST. Neither FIRST nor N need to be clipped. */
+
+static void
+insert_into_history (unsigned int first, unsigned int n,
+ const struct mips_cl_insn *insn)
+{
+ if (mips_relax.sequence != 2)
+ {
+ unsigned int i;
+
+ for (i = ARRAY_SIZE (history); i-- > first;)
+ if (i >= first + n)
+ history[i] = history[i - n];
+ else
+ history[i] = *insn;
+ }
+}
+
+/* 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);
+}
+
/* This function is called once, at assembler startup time. It should
set up all the tables, etc. that the MD part of the assembler will need. */
@@ -1192,6 +1318,11 @@ md_begin (void)
{
if (!validate_mips_insn (&mips_opcodes[i]))
broken = 1;
+ if (nop_insn.insn_mo == NULL && strcmp (name, "nop") == 0)
+ {
+ create_insn (&nop_insn, mips_opcodes + i);
+ nop_insn.fixed_p = 1;
+ }
}
++i;
}
@@ -1219,6 +1350,11 @@ md_begin (void)
mips16_opcodes[i].name, mips16_opcodes[i].args);
broken = 1;
}
+ if (mips16_nop_insn.insn_mo == NULL && strcmp (name, "nop") == 0)
+ {
+ create_insn (&mips16_nop_insn, mips16_opcodes + i);
+ mips16_nop_insn.fixed_p = 1;
+ }
++i;
}
while (i < bfd_mips16_num_opcodes
@@ -1646,12 +1782,9 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
bfd_reloc_code_real_type *reloc_type)
{
register unsigned long prev_pinfo, pinfo;
- char *f;
- fixS *fixp[3];
int nops = 0;
relax_stateT prev_insn_frag_type = 0;
bfd_boolean relaxed_branch = FALSE;
- bfd_boolean force_new_frag = FALSE;
/* Mark instruction labels in mips16 mode. */
mips16_mark_labels ();
@@ -1684,12 +1817,6 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
benefit hand written assembly code, and does not seem worth
it. */
- /* This is how a NOP is emitted. */
-#define emit_nop() \
- (mips_opts.mips16 \
- ? md_number_to_chars (frag_more (2), 0x6500, 2) \
- : md_number_to_chars (frag_more (4), 0, 4))
-
/* The previous insn might require a delay slot, depending upon
the contents of the current insn. */
if (! mips_opts.mips16
@@ -2061,32 +2188,31 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
&& !mips_opts.mips16)
{
relaxed_branch = TRUE;
- f = frag_var (rs_machine_dependent,
- relaxed_branch_length
- (NULL, NULL,
- (pinfo & INSN_UNCOND_BRANCH_DELAY) ? -1
- : (pinfo & INSN_COND_BRANCH_LIKELY) ? 1 : 0), 4,
- RELAX_BRANCH_ENCODE
- (pinfo & INSN_UNCOND_BRANCH_DELAY,
- pinfo & INSN_COND_BRANCH_LIKELY,
- pinfo & INSN_WRITE_GPR_31,
- 0),
- address_expr->X_add_symbol,
- address_expr->X_add_number,
- 0);
+ add_relaxed_insn (ip, (relaxed_branch_length
+ (NULL, NULL,
+ (pinfo & INSN_UNCOND_BRANCH_DELAY) ? -1
+ : (pinfo & INSN_COND_BRANCH_LIKELY) ? 1
+ : 0)), 4,
+ RELAX_BRANCH_ENCODE
+ (pinfo & INSN_UNCOND_BRANCH_DELAY,
+ pinfo & INSN_COND_BRANCH_LIKELY,
+ pinfo & INSN_WRITE_GPR_31,
+ 0),
+ address_expr->X_add_symbol,
+ address_expr->X_add_number);
*reloc_type = BFD_RELOC_UNUSED;
}
else if (*reloc_type > BFD_RELOC_UNUSED)
{
/* We need to set up a variant frag. */
assert (mips_opts.mips16 && address_expr != NULL);
- f = frag_var (rs_machine_dependent, 4, 0,
- RELAX_MIPS16_ENCODE (*reloc_type - BFD_RELOC_UNUSED,
- mips16_small, mips16_ext,
- (prev_pinfo
- & INSN_UNCOND_BRANCH_DELAY),
- history[0].mips16_absolute_jump_p),
- make_expr_symbol (address_expr), 0, NULL);
+ add_relaxed_insn (ip, 4, 0,
+ RELAX_MIPS16_ENCODE
+ (*reloc_type - BFD_RELOC_UNUSED,
+ mips16_small, mips16_ext,
+ prev_pinfo & INSN_UNCOND_BRANCH_DELAY,
+ history[0].mips16_absolute_jump_p),
+ make_expr_symbol (address_expr), 0);
}
else if (mips_opts.mips16
&& ! ip->use_extend
@@ -2095,7 +2221,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
/* Make sure there is enough room to swap this instruction with
a following jump instruction. */
frag_grow (6);
- f = frag_more (2);
+ add_fixed_insn (ip);
}
else
{
@@ -2119,10 +2245,14 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
if (mips_relax.sequence != 1)
mips_macro_warning.sizes[1] += 4;
- f = frag_more (4);
+ if (mips_opts.mips16)
+ {
+ ip->fixed_p = 1;
+ ip->mips16_absolute_jump_p = (*reloc_type == BFD_RELOC_MIPS16_JMP);
+ }
+ add_fixed_insn (ip);
}
- fixp[0] = fixp[1] = fixp[2] = NULL;
if (address_expr != NULL && *reloc_type <= BFD_RELOC_UNUSED)
{
if (address_expr->X_op == O_constant)
@@ -2203,11 +2333,11 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
break;
howto = bfd_reloc_type_lookup (stdoutput, reloc_type[i - 1]);
- fixp[0] = fix_new_exp (frag_now, f - frag_now->fr_literal,
- bfd_get_reloc_size(howto),
- address_expr,
- reloc_type[0] == BFD_RELOC_16_PCREL_S2,
- reloc_type[0]);
+ ip->fixp[0] = fix_new_exp (ip->frag, ip->where,
+ bfd_get_reloc_size (howto),
+ address_expr,
+ reloc_type[0] == BFD_RELOC_16_PCREL_S2,
+ reloc_type[0]);
/* These relocations can have an addend that won't fit in
4 octets for 64bit assembly. */
@@ -2232,12 +2362,12 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
|| reloc_type[0] == BFD_RELOC_MIPS16_GPREL
|| reloc_type[0] == BFD_RELOC_MIPS16_HI16_S
|| reloc_type[0] == BFD_RELOC_MIPS16_LO16))
- fixp[0]->fx_no_overflow = 1;
+ ip->fixp[0]->fx_no_overflow = 1;
if (mips_relax.sequence)
{
if (mips_relax.first_fixup == 0)
- mips_relax.first_fixup = fixp[0];
+ mips_relax.first_fixup = ip->fixp[0];
}
else if (reloc_needs_lo_p (*reloc_type))
{
@@ -2253,7 +2383,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
hi_fixup->next = mips_hi_fixup_list;
mips_hi_fixup_list = hi_fixup;
}
- hi_fixup->fixp = fixp[0];
+ hi_fixup->fixp = ip->fixp[0];
hi_fixup->seg = now_seg;
}
@@ -2265,33 +2395,17 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
for (i = 1; i < 3; i++)
if (reloc_type[i] != BFD_RELOC_UNUSED)
{
- fixp[i] = fix_new (frag_now, fixp[0]->fx_where,
- fixp[0]->fx_size, NULL, 0,
- FALSE, reloc_type[i]);
+ ip->fixp[i] = fix_new (ip->frag, ip->where,
+ ip->fixp[0]->fx_size, NULL, 0,
+ FALSE, reloc_type[i]);
/* Use fx_tcbit to mark compound relocs. */
- fixp[0]->fx_tcbit = 1;
- fixp[i]->fx_tcbit = 1;
+ ip->fixp[0]->fx_tcbit = 1;
+ ip->fixp[i]->fx_tcbit = 1;
}
}
}
-
- if (! mips_opts.mips16)
- md_number_to_chars (f, ip->insn_opcode, 4);
- else if (*reloc_type == BFD_RELOC_MIPS16_JMP)
- {
- md_number_to_chars (f, ip->insn_opcode >> 16, 2);
- md_number_to_chars (f + 2, ip->insn_opcode & 0xffff, 2);
- }
- else
- {
- if (ip->use_extend)
- {
- md_number_to_chars (f, 0xf000 | ip->extend, 2);
- f += 2;
- }
- md_number_to_chars (f, ip->insn_opcode, 2);
- }
+ install_insn (ip);
/* Update the register mask information. */
if (! mips_opts.mips16)
@@ -2534,163 +2648,46 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
portions of this object file; we could pick up the
instruction at the destination, put it in the delay
slot, and bump the destination address. */
+ insert_into_history (0, 1, ip);
emit_nop ();
if (mips_relax.sequence)
mips_relax.sizes[mips_relax.sequence - 1] += 4;
- /* Update the previous insn information. */
- history[1].insn_mo = ip->insn_mo;
- history[1].use_extend = ip->use_extend;
- history[1].extend = ip->extend;
- history[1].insn_opcode = ip->insn_opcode;
- history[0].insn_mo = &dummy_opcode;
}
else
{
/* It looks like we can actually do the swap. */
- if (! mips_opts.mips16)
+ struct mips_cl_insn delay = history[0];
+ if (mips_opts.mips16)
{
- char *prev_f;
- char temp[4];
-
- prev_f = history[0].frag->fr_literal + history[0].where;
- if (!relaxed_branch)
- {
- /* If this is not a relaxed branch, then just
- swap the instructions. */
- memcpy (temp, prev_f, 4);
- memcpy (prev_f, f, 4);
- memcpy (f, temp, 4);
- }
- else
- {
- /* If this is a relaxed branch, then we move the
- instruction to be placed in the delay slot to
- the current frag, shrinking the fixed part of
- the originating frag. If the branch occupies
- the tail of the latter, we move it backwards,
- into the space freed by the moved instruction. */
- f = frag_more (4);
- memcpy (f, prev_f, 4);
- history[0].frag->fr_fix -= 4;
- if (history[0].frag->fr_type == rs_machine_dependent)
- memmove (prev_f, prev_f + 4, history[0].frag->fr_var);
- }
-
- if (history[0].fixp[0])
- {
- history[0].fixp[0]->fx_frag = frag_now;
- history[0].fixp[0]->fx_where = f - frag_now->fr_literal;
- }
- if (history[0].fixp[1])
- {
- history[0].fixp[1]->fx_frag = frag_now;
- history[0].fixp[1]->fx_where = f - frag_now->fr_literal;
- }
- if (history[0].fixp[2])
- {
- history[0].fixp[2]->fx_frag = frag_now;
- history[0].fixp[2]->fx_where = f - frag_now->fr_literal;
- }
- if (history[0].fixp[0] && HAVE_NEWABI
- && history[0].frag != frag_now
- && (history[0].fixp[0]->fx_r_type
- == BFD_RELOC_MIPS_GOT_DISP
- || (history[0].fixp[0]->fx_r_type
- == BFD_RELOC_MIPS_CALL16)))
- {
- /* To avoid confusion in tc_gen_reloc, we must
- ensure that this does not become a variant
- frag. */
- force_new_frag = TRUE;
- }
-
- if (!relaxed_branch)
- {
- if (fixp[0])
- {
- fixp[0]->fx_frag = history[0].frag;
- fixp[0]->fx_where = history[0].where;
- }
- if (fixp[1])
- {
- fixp[1]->fx_frag = history[0].frag;
- fixp[1]->fx_where = history[0].where;
- }
- if (fixp[2])
- {
- fixp[2]->fx_frag = history[0].frag;
- fixp[2]->fx_where = history[0].where;
- }
- }
- else if (history[0].frag->fr_type == rs_machine_dependent)
- {
- if (fixp[0])
- fixp[0]->fx_where -= 4;
- if (fixp[1])
- fixp[1]->fx_where -= 4;
- if (fixp[2])
- fixp[2]->fx_where -= 4;
- }
+ know (delay.frag == ip->frag);
+ move_insn (ip, delay.frag, delay.where);
+ move_insn (&delay, ip->frag, ip->where + insn_length (ip));
+ }
+ else if (relaxed_branch)
+ {
+ /* Add the delay slot instruction to the end of the
+ current frag and shrink the fixed part of the
+ original frag. If the branch occupies the tail of
+ the latter, move it backwards to cover the gap. */
+ delay.frag->fr_fix -= 4;
+ if (delay.frag == ip->frag)
+ move_insn (ip, ip->frag, ip->where - 4);
+ add_fixed_insn (&delay);
}
else
{
- char *prev_f;
- char temp[2];
-
- assert (history[0].fixp[0] == NULL);
- assert (history[0].fixp[1] == NULL);
- assert (history[0].fixp[2] == NULL);
- prev_f = history[0].frag->fr_literal + history[0].where;
- memcpy (temp, prev_f, 2);
- memcpy (prev_f, f, 2);
- if (*reloc_type != BFD_RELOC_MIPS16_JMP)
- {
- assert (*reloc_type == BFD_RELOC_UNUSED);
- memcpy (f, temp, 2);
- }
- else
- {
- memcpy (f, f + 2, 2);
- memcpy (f + 2, temp, 2);
- }
- if (fixp[0])
- {
- fixp[0]->fx_frag = history[0].frag;
- fixp[0]->fx_where = history[0].where;
- }
- if (fixp[1])
- {
- fixp[1]->fx_frag = history[0].frag;
- fixp[1]->fx_where = history[0].where;
- }
- if (fixp[2])
- {
- fixp[2]->fx_frag = history[0].frag;
- fixp[2]->fx_where = history[0].where;
- }
+ move_insn (&delay, ip->frag, ip->where);
+ move_insn (ip, history[0].frag, history[0].where);
}
-
- /* Update the previous insn information; leave history[0]
- unchanged. */
- history[1].insn_mo = ip->insn_mo;
- history[1].use_extend = ip->use_extend;
- history[1].extend = ip->extend;
- history[1].insn_opcode = ip->insn_opcode;
+ history[0] = *ip;
+ delay.fixed_p = 1;
+ insert_into_history (0, 1, &delay);
}
- history[0].fixed_p = 1;
/* If that was an unconditional branch, forget the previous
insn information. */
if (pinfo & INSN_UNCOND_BRANCH_DELAY)
- {
- history[1].insn_mo = &dummy_opcode;
- history[0].insn_mo = &dummy_opcode;
- }
-
- history[0].fixp[0] = NULL;
- history[0].fixp[1] = NULL;
- history[0].fixp[2] = NULL;
- history[0].mips16_absolute_jump_p = 0;
+ mips_no_prev_insn (FALSE);
}
else if (pinfo & INSN_COND_BRANCH_LIKELY)
{
@@ -2698,69 +2695,14 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
is look at the target, copy the instruction found there
into the delay slot, and increment the branch to jump to
the next instruction. */
+ insert_into_history (0, 1, ip);
emit_nop ();
- /* Update the previous insn information. */
- history[1].insn_mo = ip->insn_mo;
- history[1].use_extend = ip->use_extend;
- history[1].extend = ip->extend;
- history[1].insn_opcode = ip->insn_opcode;
- history[0].insn_mo = &dummy_opcode;
- history[0].fixp[0] = NULL;
- history[0].fixp[1] = NULL;
- history[0].fixp[2] = NULL;
- history[0].mips16_absolute_jump_p = 0;
- history[0].fixed_p = 1;
}
else
- {
- /* Update the previous insn information. */
- if (nops > 0)
- history[1].insn_mo = &dummy_opcode;
- else
- {
- history[1].insn_mo = history[0].insn_mo;
- history[1].use_extend = history[0].use_extend;
- history[1].extend = history[0].extend;
- history[1].insn_opcode = history[0].insn_opcode;
- }
- history[0].insn_mo = ip->insn_mo;
- history[0].use_extend = ip->use_extend;
- history[0].extend = ip->extend;
- history[0].insn_opcode = ip->insn_opcode;
- history[0].fixed_p = (mips_opts.mips16
- && (ip->use_extend
- || *reloc_type > BFD_RELOC_UNUSED));
- history[0].fixp[0] = fixp[0];
- history[0].fixp[1] = fixp[1];
- history[0].fixp[2] = fixp[2];
- history[0].mips16_absolute_jump_p = (reloc_type[0]
- == BFD_RELOC_MIPS16_JMP);
- }
-
- history[1].noreorder_p = history[0].noreorder_p;
- history[0].noreorder_p = 0;
- history[0].frag = frag_now;
- history[0].where = f - frag_now->fr_literal;
- }
- else if (mips_relax.sequence != 2)
- {
- /* We need to record a bit of information even when we are not
- reordering, in order to determine the base address for mips16
- PC relative relocs. */
- history[1].insn_mo = history[0].insn_mo;
- history[1].use_extend = history[0].use_extend;
- history[1].extend = history[0].extend;
- history[1].insn_opcode = history[0].insn_opcode;
- history[0].insn_mo = ip->insn_mo;
- history[0].use_extend = ip->use_extend;
- history[0].extend = ip->extend;
- history[0].insn_opcode = ip->insn_opcode;
- history[0].mips16_absolute_jump_p = (reloc_type[0]
- == BFD_RELOC_MIPS16_JMP);
- history[1].noreorder_p = history[0].noreorder_p;
- history[0].noreorder_p = 1;
- history[0].fixed_p = 1;
+ insert_into_history (0, 1, ip);
}
+ else
+ insert_into_history (0, 1, ip);
/* We just output an insn, so the next one doesn't have a label. */
mips_clear_insn_labels ();
@@ -2773,19 +2715,24 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
static void
mips_no_prev_insn (int preserve)
{
+ size_t i;
+
if (! preserve)
{
- history[0].insn_mo = &dummy_opcode;
- history[1].insn_mo = &dummy_opcode;
prev_nop_frag = NULL;
prev_nop_frag_holds = 0;
prev_nop_frag_required = 0;
prev_nop_frag_since = 0;
+ for (i = 0; i < ARRAY_SIZE (history); i++)
+ history[i] = (mips_opts.mips16 ? mips16_nop_insn : nop_insn);
}
- history[0].fixed_p = 1;
- history[0].noreorder_p = 0;
- history[0].mips16_absolute_jump_p = 0;
- history[1].noreorder_p = 0;
+ else
+ for (i = 0; i < ARRAY_SIZE (history); i++)
+ {
+ history[i].fixed_p = 1;
+ history[i].noreorder_p = 0;
+ history[i].mips16_absolute_jump_p = 0;
+ }
mips_clear_insn_labels ();
}
@@ -2874,7 +2821,7 @@ mips_emit_delays (bfd_boolean insns)
}
for (; nops > 0; --nops)
- emit_nop ();
+ add_fixed_insn (NOP_INSN);
if (insns)
{
@@ -2997,6 +2944,7 @@ macro_read_relocs (va_list *args, bfd_reloc_code_real_type *r)
static void
macro_build (expressionS *ep, const char *name, const char *fmt, ...)
{
+ const struct mips_opcode *mo;
struct mips_cl_insn insn;
bfd_reloc_code_real_type r[3];
va_list args;
@@ -3013,30 +2961,26 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
r[0] = BFD_RELOC_UNUSED;
r[1] = BFD_RELOC_UNUSED;
r[2] = BFD_RELOC_UNUSED;
- insn.insn_mo = (struct mips_opcode *) hash_find (op_hash, name);
- assert (insn.insn_mo);
- assert (strcmp (name, insn.insn_mo->name) == 0);
-
- /* Search until we get a match for NAME. */
- while (1)
- {
- /* It is assumed here that macros will never generate
- MDMX or MIPS-3D instructions. */
- if (strcmp (fmt, insn.insn_mo->args) == 0
- && insn.insn_mo->pinfo != INSN_MACRO
- && OPCODE_IS_MEMBER (insn.insn_mo,
- (mips_opts.isa
- | (file_ase_mips16 ? INSN_MIPS16 : 0)),
+ mo = (struct mips_opcode *) hash_find (op_hash, name);
+ assert (mo);
+ assert (strcmp (name, mo->name) == 0);
+
+ /* Search until we get a match for NAME. It is assumed here that
+ macros will never generate MDMX or MIPS-3D instructions. */
+ while (strcmp (fmt, mo->args) != 0
+ || mo->pinfo == INSN_MACRO
+ || !OPCODE_IS_MEMBER (mo,
+ (mips_opts.isa
+ | (file_ase_mips16 ? INSN_MIPS16 : 0)),
mips_opts.arch)
- && (mips_opts.arch != CPU_R4650 || (insn.insn_mo->pinfo & FP_D) == 0))
- break;
-
- ++insn.insn_mo;
- assert (insn.insn_mo->name);
- assert (strcmp (name, insn.insn_mo->name) == 0);
+ || (mips_opts.arch == CPU_R4650 && (mo->pinfo & FP_D) != 0))
+ {
+ ++mo;
+ assert (mo->name);
+ assert (strcmp (name, mo->name) == 0);
}
- insn.insn_opcode = insn.insn_mo->match;
+ create_insn (&insn, mo);
for (;;)
{
switch (*fmt++)
@@ -3219,25 +3163,23 @@ static void
mips16_macro_build (expressionS *ep, const char *name, const char *fmt,
va_list args)
{
+ struct mips_opcode *mo;
struct mips_cl_insn insn;
bfd_reloc_code_real_type r[3]
= {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
- insn.insn_mo = (struct mips_opcode *) hash_find (mips16_op_hash, name);
- assert (insn.insn_mo);
- assert (strcmp (name, insn.insn_mo->name) == 0);
+ mo = (struct mips_opcode *) hash_find (mips16_op_hash, name);
+ assert (mo);
+ assert (strcmp (name, mo->name) == 0);
- while (strcmp (fmt, insn.insn_mo->args) != 0
- || insn.insn_mo->pinfo == INSN_MACRO)
+ while (strcmp (fmt, mo->args) != 0 || mo->pinfo == INSN_MACRO)
{
- ++insn.insn_mo;
- assert (insn.insn_mo->name);
- assert (strcmp (name, insn.insn_mo->name) == 0);
+ ++mo;
+ assert (mo->name);
+ assert (strcmp (name, mo->name) == 0);
}
- insn.insn_opcode = insn.insn_mo->match;
- insn.use_extend = FALSE;
-
+ create_insn (&insn, mo);
for (;;)
{
int c;
@@ -3363,6 +3305,7 @@ static void
macro_build_lui (expressionS *ep, int regnum)
{
expressionS high_expr;
+ const struct mips_opcode *mo;
struct mips_cl_insn insn;
bfd_reloc_code_real_type r[3]
= {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
@@ -3394,10 +3337,10 @@ macro_build_lui (expressionS *ep, int regnum)
*r = BFD_RELOC_HI16_S;
}
- insn.insn_mo = (struct mips_opcode *) hash_find (op_hash, name);
- assert (insn.insn_mo);
- assert (strcmp (name, insn.insn_mo->name) == 0);
- assert (strcmp (fmt, insn.insn_mo->args) == 0);
+ mo = hash_find (op_hash, name);
+ assert (strcmp (name, mo->name) == 0);
+ assert (strcmp (fmt, mo->args) == 0);
+ create_insn (&insn, mo);
insn.insn_opcode = insn.insn_mo->match;
INSERT_OPERAND (RT, insn, regnum);
@@ -8018,8 +7961,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
}
}
- ip->insn_mo = insn;
- ip->insn_opcode = insn->match;
+ create_insn (ip, insn);
insn_error = NULL;
for (args = insn->args;; ++args)
{
@@ -9123,9 +9065,7 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
{
assert (strcmp (insn->name, str) == 0);
- ip->insn_mo = insn;
- ip->insn_opcode = insn->match;
- ip->use_extend = FALSE;
+ create_insn (ip, insn);
imm_expr.X_op = O_absent;
imm_reloc[0] = BFD_RELOC_UNUSED;
imm_reloc[1] = BFD_RELOC_UNUSED;