* 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.
This commit is contained in:
parent
bf12938eac
commit
1e91584932
@ -1,3 +1,20 @@
|
||||
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)
|
||||
|
@ -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);
|
||||
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. */
|
||||
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)),
|
||||
/* 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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user