* config/tc-mips.h (mips_cl_insn): Move definition to...

* config/tc-mips.c (mips_cl_insn): ...here.  Add new fields:
	frag, where, fixp, reloc_type, valid_p, noreorder_p, delay_slot_p
	and extended_p.
	(history): New variable.
	(prev_insn, prev_prev_insn, prev_insn_valid, prev_insn_frag)
	(prev_insn_where, prev_insn_reloc_type, prev_insn_fixp)
	(prev_insn_is_delay_slot, prev_insn_unreordered, prev_insn_extended)
	(prev_prev_insn_unreordered): Delete.
	(reg_needs_delay, append_insn, mips_no_prev_insn, mips_emit_delays)
	(macro_start): Replace uses of prev_insn* with the equivalent history[]
	field.
This commit is contained in:
Richard Sandiford 2005-03-09 09:12:29 +00:00
parent 5b5464adf1
commit 47e39b9d3f
3 changed files with 238 additions and 197 deletions

View File

@ -1,3 +1,18 @@
2005-03-09 Richard Sandiford <rsandifo@redhat.com>
* config/tc-mips.h (mips_cl_insn): Move definition to...
* config/tc-mips.c (mips_cl_insn): ...here. Add new fields:
frag, where, fixp, reloc_type, valid_p, noreorder_p, delay_slot_p
and extended_p.
(history): New variable.
(prev_insn, prev_prev_insn, prev_insn_valid, prev_insn_frag)
(prev_insn_where, prev_insn_reloc_type, prev_insn_fixp)
(prev_insn_is_delay_slot, prev_insn_unreordered, prev_insn_extended)
(prev_prev_insn_unreordered): Delete.
(reg_needs_delay, append_insn, mips_no_prev_insn, mips_emit_delays)
(macro_start): Replace uses of prev_insn* with the equivalent history[]
field.
2005-03-08 Daniel Jacobowitz <dan@codesourcery.com>
* doc/Makefile.am: Update as.info dependencies.

View File

@ -119,6 +119,50 @@ extern int target_big_endian;
? ".rodata" \
: (abort (), ""))
/* Information about an instruction, including its format, operands
and fixups. */
struct mips_cl_insn
{
/* The opcode's entry in mips_opcodes or mips16_opcodes. */
const struct mips_opcode *insn_mo;
/* True if this is a mips16 instruction and if we want the extended
form of INSN_MO. */
bfd_boolean use_extend;
/* The 16-bit extension instruction to use when USE_EXTEND is true. */
unsigned short extend;
/* The 16-bit or 32-bit bitstring of the instruction itself. This is
a copy of INSN_MO->match with the operands filled in. */
unsigned long insn_opcode;
/* The frag that contains the instruction. */
struct frag *frag;
/* The offset into FRAG of the first instruction byte. */
long where;
/* The relocs associated with the instruction, if any. */
fixS *fixp[3];
/* The reloc types associated with the instruction. */
bfd_reloc_code_real_type reloc_type[3];
/* True if this entry describes a real instruction. */
unsigned int valid_p : 1;
/* True if this instruction occured in a .set noreorder block. */
unsigned int noreorder_p : 1;
/* True if this instruction corresponds to an assembler-filled
delay slot. Always false if noreorder_p. */
unsigned int delay_slot_p : 1;
/* True for extended mips16 instructions. */
unsigned int extended_p : 1;
};
/* The ABI to use. */
enum mips_abi_level
{
@ -520,45 +564,13 @@ static int mips_optimize = 2;
equivalent to seeing no -g option at all. */
static int mips_debug = 0;
/* The previous instruction. */
static struct mips_cl_insn prev_insn;
/* A list of previous instructions, with index 0 being the most recent. */
static struct mips_cl_insn history[2];
/* The instruction before prev_insn. */
static struct mips_cl_insn prev_prev_insn;
/* If we don't want information for prev_insn or prev_prev_insn, we
/* 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 };
/* Non-zero if prev_insn is valid. */
static int prev_insn_valid;
/* The frag for the previous instruction. */
static struct frag *prev_insn_frag;
/* The offset into prev_insn_frag for the previous instruction. */
static long prev_insn_where;
/* The reloc type for the previous instruction, if any. */
static bfd_reloc_code_real_type prev_insn_reloc_type[3];
/* The reloc for the previous instruction, if any. */
static fixS *prev_insn_fixp[3];
/* Non-zero if the previous instruction was in a delay slot. */
static int prev_insn_is_delay_slot;
/* Non-zero if the previous instruction was in a .set noreorder. */
static int prev_insn_unreordered;
/* Non-zero if the previous instruction uses an extend opcode (if
mips16). */
static int prev_insn_extended;
/* Non-zero if the previous previous instruction was in a .set
noreorder. */
static int prev_prev_insn_unreordered;
/* If this is set, it points to a frag holding nop instructions which
were inserted before the start of a noreorder section. If those
nops turn out to be unnecessary, the size of the frag can be
@ -1515,7 +1527,7 @@ reg_needs_delay (unsigned int reg)
{
unsigned long prev_pinfo;
prev_pinfo = prev_insn.insn_mo->pinfo;
prev_pinfo = history[0].insn_mo->pinfo;
if (! mips_opts.noreorder
&& (((prev_pinfo & INSN_LOAD_MEMORY_DELAY)
&& ! gpr_interlocks)
@ -1526,7 +1538,7 @@ reg_needs_delay (unsigned int reg)
delay the use of general register rt for one instruction. */
/* Itbl support may require additional care here. */
know (prev_pinfo & INSN_WRITE_GPR_T);
if (reg == ((prev_insn.insn_opcode >> OP_SH_RT) & OP_MASK_RT))
if (reg == ((history[0].insn_opcode >> OP_SH_RT) & OP_MASK_RT))
return 1;
}
@ -1627,7 +1639,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
/* Mark instruction labels in mips16 mode. */
mips16_mark_labels ();
prev_pinfo = prev_insn.insn_mo->pinfo;
prev_pinfo = history[0].insn_mo->pinfo;
pinfo = ip->insn_mo->pinfo;
if (mips_relax.sequence != 2
@ -1676,7 +1688,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
know (prev_pinfo & INSN_WRITE_GPR_T);
if (mips_optimize == 0
|| insn_uses_reg (ip,
((prev_insn.insn_opcode >> OP_SH_RT)
((history[0].insn_opcode >> OP_SH_RT)
& OP_MASK_RT),
MIPS_GR_REG))
++nops;
@ -1705,7 +1717,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
{
if (mips_optimize == 0
|| insn_uses_reg (ip,
((prev_insn.insn_opcode >> OP_SH_FT)
((history[0].insn_opcode >> OP_SH_FT)
& OP_MASK_FT),
MIPS_FP_REG))
++nops;
@ -1714,7 +1726,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
{
if (mips_optimize == 0
|| insn_uses_reg (ip,
((prev_insn.insn_opcode >> OP_SH_FS)
((history[0].insn_opcode >> OP_SH_FS)
& OP_MASK_FS),
MIPS_FP_REG))
++nops;
@ -1758,7 +1770,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
else if (mips_7000_hilo_fix
&& MF_HILO_INSN (prev_pinfo)
&& insn_uses_reg (ip, ((prev_insn.insn_opcode >> OP_SH_RD)
&& insn_uses_reg (ip, ((history[0].insn_opcode >> OP_SH_RD)
& OP_MASK_RD),
MIPS_GR_REG))
{
@ -1771,8 +1783,8 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
insert one nop. */
else if (mips_7000_hilo_fix
&& MF_HILO_INSN (prev_prev_insn.insn_opcode)
&& insn_uses_reg (ip, ((prev_prev_insn.insn_opcode >> OP_SH_RD)
&& MF_HILO_INSN (history[1].insn_opcode)
&& insn_uses_reg (ip, ((history[1].insn_opcode >> OP_SH_RD)
& OP_MASK_RD),
MIPS_GR_REG))
@ -1805,7 +1817,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
|| (pinfo & MIPS16_INSN_BRANCH)))
++nops;
}
else if (prev_insn.insn_mo->pinfo & INSN_READ_HI)
else if (history[0].insn_mo->pinfo & INSN_READ_HI)
{
/* The previous instruction reads the HI register; if the
current instruction writes to the HI register, we must
@ -1831,7 +1843,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
/* If the previous instruction was in a noreorder section, then
we don't want to insert the nop after all. */
/* Itbl support may require additional care here. */
if (prev_insn_unreordered)
if (history[0].noreorder_p)
nops = 0;
/* There are two cases which require two intervening
@ -1843,15 +1855,15 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
instruction, we must check for these cases compared to the
instruction previous to the previous instruction. */
if ((! mips_opts.mips16
&& (prev_prev_insn.insn_mo->pinfo & INSN_COPROC_MOVE_DELAY)
&& (prev_prev_insn.insn_mo->pinfo & INSN_WRITE_COND_CODE)
&& (history[1].insn_mo->pinfo & INSN_COPROC_MOVE_DELAY)
&& (history[1].insn_mo->pinfo & INSN_WRITE_COND_CODE)
&& (pinfo & INSN_READ_COND_CODE)
&& ! cop_interlocks)
|| ((prev_prev_insn.insn_mo->pinfo & INSN_READ_LO)
|| ((history[1].insn_mo->pinfo & INSN_READ_LO)
&& (pinfo & INSN_WRITE_LO)
&& ! (hilo_interlocks
|| (mips_opts.arch == CPU_R3900 && (pinfo & INSN_MULT))))
|| ((prev_prev_insn.insn_mo->pinfo & INSN_READ_HI)
|| ((history[1].insn_mo->pinfo & INSN_READ_HI)
&& (pinfo & INSN_WRITE_HI)
&& ! (hilo_interlocks
|| (mips_opts.arch == CPU_R3900 && (pinfo & INSN_MULT)))))
@ -1859,19 +1871,19 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
else
prev_prev_nop = 0;
if (prev_prev_insn_unreordered)
if (history[1].noreorder_p)
prev_prev_nop = 0;
if (prev_prev_nop && nops == 0)
++nops;
if (mips_fix_vr4120 && prev_insn.insn_mo->name)
if (mips_fix_vr4120 && history[0].insn_mo->name)
{
/* We're out of bits in pinfo, so we must resort to string
ops here. Shortcuts are selected based on opcodes being
limited to the VR4120 instruction set. */
int min_nops = 0;
const char *pn = prev_insn.insn_mo->name;
const char *pn = history[0].insn_mo->name;
const char *tn = ip->insn_mo->name;
if (strncmp (pn, "macc", 4) == 0
|| strncmp (pn, "dmacc", 5) == 0)
@ -2024,8 +2036,8 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
#endif
/* Record the frag type before frag_var. */
if (prev_insn_frag)
prev_insn_frag_type = prev_insn_frag->fr_type;
if (history[0].frag)
prev_insn_frag_type = history[0].frag->fr_type;
if (address_expr
&& *reloc_type == BFD_RELOC_16_PCREL_S2
@ -2064,7 +2076,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
mips16_small, mips16_ext,
(prev_pinfo
& INSN_UNCOND_BRANCH_DELAY),
(*prev_insn_reloc_type
(*history[0].reloc_type
== BFD_RELOC_MIPS16_JMP)),
make_expr_symbol (address_expr), 0, NULL);
}
@ -2348,10 +2360,10 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
|| nops != 0
/* If we don't even know the previous insn, we can not
swap. */
|| ! prev_insn_valid
|| ! history[0].valid_p
/* If the previous insn is already in a branch delay
slot, then we can not swap. */
|| prev_insn_is_delay_slot
|| history[0].delay_slot_p
/* If the previous previous insn was in a .set
noreorder, we can't swap. Actually, the MIPS
assembler will swap in this situation. However, gcc
@ -2364,11 +2376,11 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
in which we can not swap the bne and INSN. If gcc is
not configured -with-gnu-as, it does not output the
.set pseudo-ops. We don't have to check
prev_insn_unreordered, because prev_insn_valid will
history[0].noreorder_p, because history[0].valid_p will
be 0 in that case. We don't want to use
prev_prev_insn_valid, because we do want to be able
history[1].valid_p, because we do want to be able
to swap at the start of a function. */
|| prev_prev_insn_unreordered
|| history[1].noreorder_p
/* If the branch is itself the target of a branch, we
can not swap. We cheat on this; all we check for is
whether there is a label on this instruction. If
@ -2428,31 +2440,31 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
|| (! mips_opts.mips16
&& (prev_pinfo & INSN_WRITE_GPR_T)
&& insn_uses_reg (ip,
((prev_insn.insn_opcode >> OP_SH_RT)
((history[0].insn_opcode >> OP_SH_RT)
& OP_MASK_RT),
MIPS_GR_REG))
|| (! mips_opts.mips16
&& (prev_pinfo & INSN_WRITE_GPR_D)
&& insn_uses_reg (ip,
((prev_insn.insn_opcode >> OP_SH_RD)
((history[0].insn_opcode >> OP_SH_RD)
& OP_MASK_RD),
MIPS_GR_REG))
|| (mips_opts.mips16
&& (((prev_pinfo & MIPS16_INSN_WRITE_X)
&& insn_uses_reg (ip,
((prev_insn.insn_opcode
((history[0].insn_opcode
>> MIPS16OP_SH_RX)
& MIPS16OP_MASK_RX),
MIPS16_REG))
|| ((prev_pinfo & MIPS16_INSN_WRITE_Y)
&& insn_uses_reg (ip,
((prev_insn.insn_opcode
((history[0].insn_opcode
>> MIPS16OP_SH_RY)
& MIPS16OP_MASK_RY),
MIPS16_REG))
|| ((prev_pinfo & MIPS16_INSN_WRITE_Z)
&& insn_uses_reg (ip,
((prev_insn.insn_opcode
((history[0].insn_opcode
>> MIPS16OP_SH_RZ)
& MIPS16OP_MASK_RZ),
MIPS16_REG))
@ -2462,8 +2474,8 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
&& insn_uses_reg (ip, RA, MIPS_GR_REG))
|| ((prev_pinfo & MIPS16_INSN_WRITE_GPR_Y)
&& insn_uses_reg (ip,
MIPS16OP_EXTRACT_REG32R (prev_insn.
insn_opcode),
MIPS16OP_EXTRACT_REG32R
(history[0].insn_opcode),
MIPS_GR_REG))))
/* If the branch writes a register that the previous
instruction sets, we can not swap (we know that
@ -2471,54 +2483,54 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
|| (! mips_opts.mips16
&& (prev_pinfo & INSN_WRITE_GPR_T)
&& (((pinfo & INSN_WRITE_GPR_D)
&& (((prev_insn.insn_opcode >> OP_SH_RT) & OP_MASK_RT)
&& (((history[0].insn_opcode >> OP_SH_RT) & OP_MASK_RT)
== ((ip->insn_opcode >> OP_SH_RD) & OP_MASK_RD)))
|| ((pinfo & INSN_WRITE_GPR_31)
&& (((prev_insn.insn_opcode >> OP_SH_RT)
&& (((history[0].insn_opcode >> OP_SH_RT)
& OP_MASK_RT)
== RA))))
|| (! mips_opts.mips16
&& (prev_pinfo & INSN_WRITE_GPR_D)
&& (((pinfo & INSN_WRITE_GPR_D)
&& (((prev_insn.insn_opcode >> OP_SH_RD) & OP_MASK_RD)
&& (((history[0].insn_opcode >> OP_SH_RD) & OP_MASK_RD)
== ((ip->insn_opcode >> OP_SH_RD) & OP_MASK_RD)))
|| ((pinfo & INSN_WRITE_GPR_31)
&& (((prev_insn.insn_opcode >> OP_SH_RD)
&& (((history[0].insn_opcode >> OP_SH_RD)
& OP_MASK_RD)
== RA))))
|| (mips_opts.mips16
&& (pinfo & MIPS16_INSN_WRITE_31)
&& ((prev_pinfo & MIPS16_INSN_WRITE_31)
|| ((prev_pinfo & MIPS16_INSN_WRITE_GPR_Y)
&& (MIPS16OP_EXTRACT_REG32R (prev_insn.insn_opcode)
&& (MIPS16OP_EXTRACT_REG32R (history[0].insn_opcode)
== RA))))
/* If the branch writes a register that the previous
instruction reads, we can not swap (we know that
branches only write to RD or to $31). */
|| (! mips_opts.mips16
&& (pinfo & INSN_WRITE_GPR_D)
&& insn_uses_reg (&prev_insn,
&& insn_uses_reg (&history[0],
((ip->insn_opcode >> OP_SH_RD)
& OP_MASK_RD),
MIPS_GR_REG))
|| (! mips_opts.mips16
&& (pinfo & INSN_WRITE_GPR_31)
&& insn_uses_reg (&prev_insn, RA, MIPS_GR_REG))
&& insn_uses_reg (&history[0], RA, MIPS_GR_REG))
|| (mips_opts.mips16
&& (pinfo & MIPS16_INSN_WRITE_31)
&& insn_uses_reg (&prev_insn, RA, MIPS_GR_REG))
&& insn_uses_reg (&history[0], RA, MIPS_GR_REG))
/* If the previous previous instruction has a load
delay, and sets a register that the branch reads, we
can not swap. */
|| (! mips_opts.mips16
/* Itbl support may require additional care here. */
&& (((prev_prev_insn.insn_mo->pinfo & INSN_LOAD_COPROC_DELAY)
&& (((history[1].insn_mo->pinfo & INSN_LOAD_COPROC_DELAY)
&& ! cop_interlocks)
|| ((prev_prev_insn.insn_mo->pinfo
|| ((history[1].insn_mo->pinfo
& INSN_LOAD_MEMORY_DELAY)
&& ! gpr_interlocks))
&& insn_uses_reg (ip,
((prev_prev_insn.insn_opcode >> OP_SH_RT)
((history[1].insn_opcode >> OP_SH_RT)
& OP_MASK_RT),
MIPS_GR_REG))
/* If one instruction sets a condition code and the
@ -2533,11 +2545,11 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
&& (prev_pinfo & MIPS16_INSN_READ_PC))
/* If the previous instruction was extended, we can not
swap. */
|| (mips_opts.mips16 && prev_insn_extended)
|| (mips_opts.mips16 && history[0].extended_p)
/* If the previous instruction had a fixup in mips16
mode, we can not swap. This normally means that the
previous instruction was a 4 byte branch anyhow. */
|| (mips_opts.mips16 && prev_insn_fixp[0])
|| (mips_opts.mips16 && history[0].fixp[0])
/* If the previous instruction is a sync, sync.l, or
sync.p, we can not swap. */
|| (prev_pinfo & INSN_SYNC))
@ -2550,8 +2562,11 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
if (mips_relax.sequence)
mips_relax.sizes[mips_relax.sequence - 1] += 4;
/* Update the previous insn information. */
prev_prev_insn = *ip;
prev_insn.insn_mo = &dummy_opcode;
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
{
@ -2561,7 +2576,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
char *prev_f;
char temp[4];
prev_f = prev_insn_frag->fr_literal + prev_insn_where;
prev_f = history[0].frag->fr_literal + history[0].where;
if (!relaxed_branch)
{
/* If this is not a relaxed branch, then just
@ -2580,31 +2595,31 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
into the space freed by the moved instruction. */
f = frag_more (4);
memcpy (f, prev_f, 4);
prev_insn_frag->fr_fix -= 4;
if (prev_insn_frag->fr_type == rs_machine_dependent)
memmove (prev_f, prev_f + 4, prev_insn_frag->fr_var);
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 (prev_insn_fixp[0])
if (history[0].fixp[0])
{
prev_insn_fixp[0]->fx_frag = frag_now;
prev_insn_fixp[0]->fx_where = f - frag_now->fr_literal;
history[0].fixp[0]->fx_frag = frag_now;
history[0].fixp[0]->fx_where = f - frag_now->fr_literal;
}
if (prev_insn_fixp[1])
if (history[0].fixp[1])
{
prev_insn_fixp[1]->fx_frag = frag_now;
prev_insn_fixp[1]->fx_where = f - frag_now->fr_literal;
history[0].fixp[1]->fx_frag = frag_now;
history[0].fixp[1]->fx_where = f - frag_now->fr_literal;
}
if (prev_insn_fixp[2])
if (history[0].fixp[2])
{
prev_insn_fixp[2]->fx_frag = frag_now;
prev_insn_fixp[2]->fx_where = f - frag_now->fr_literal;
history[0].fixp[2]->fx_frag = frag_now;
history[0].fixp[2]->fx_where = f - frag_now->fr_literal;
}
if (prev_insn_fixp[0] && HAVE_NEWABI
&& prev_insn_frag != frag_now
&& (prev_insn_fixp[0]->fx_r_type
if (history[0].fixp[0] && HAVE_NEWABI
&& history[0].frag != frag_now
&& (history[0].fixp[0]->fx_r_type
== BFD_RELOC_MIPS_GOT_DISP
|| (prev_insn_fixp[0]->fx_r_type
|| (history[0].fixp[0]->fx_r_type
== BFD_RELOC_MIPS_CALL16)))
{
/* To avoid confusion in tc_gen_reloc, we must
@ -2617,21 +2632,21 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
{
if (fixp[0])
{
fixp[0]->fx_frag = prev_insn_frag;
fixp[0]->fx_where = prev_insn_where;
fixp[0]->fx_frag = history[0].frag;
fixp[0]->fx_where = history[0].where;
}
if (fixp[1])
{
fixp[1]->fx_frag = prev_insn_frag;
fixp[1]->fx_where = prev_insn_where;
fixp[1]->fx_frag = history[0].frag;
fixp[1]->fx_where = history[0].where;
}
if (fixp[2])
{
fixp[2]->fx_frag = prev_insn_frag;
fixp[2]->fx_where = prev_insn_where;
fixp[2]->fx_frag = history[0].frag;
fixp[2]->fx_where = history[0].where;
}
}
else if (prev_insn_frag->fr_type == rs_machine_dependent)
else if (history[0].frag->fr_type == rs_machine_dependent)
{
if (fixp[0])
fixp[0]->fx_where -= 4;
@ -2646,10 +2661,10 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
char *prev_f;
char temp[2];
assert (prev_insn_fixp[0] == NULL);
assert (prev_insn_fixp[1] == NULL);
assert (prev_insn_fixp[2] == NULL);
prev_f = prev_insn_frag->fr_literal + prev_insn_where;
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)
@ -2664,42 +2679,45 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
}
if (fixp[0])
{
fixp[0]->fx_frag = prev_insn_frag;
fixp[0]->fx_where = prev_insn_where;
fixp[0]->fx_frag = history[0].frag;
fixp[0]->fx_where = history[0].where;
}
if (fixp[1])
{
fixp[1]->fx_frag = prev_insn_frag;
fixp[1]->fx_where = prev_insn_where;
fixp[1]->fx_frag = history[0].frag;
fixp[1]->fx_where = history[0].where;
}
if (fixp[2])
{
fixp[2]->fx_frag = prev_insn_frag;
fixp[2]->fx_where = prev_insn_where;
fixp[2]->fx_frag = history[0].frag;
fixp[2]->fx_where = history[0].where;
}
}
/* Update the previous insn information; leave prev_insn
/* Update the previous insn information; leave history[0]
unchanged. */
prev_prev_insn = *ip;
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;
}
prev_insn_is_delay_slot = 1;
history[0].delay_slot_p = 1;
/* If that was an unconditional branch, forget the previous
insn information. */
if (pinfo & INSN_UNCOND_BRANCH_DELAY)
{
prev_prev_insn.insn_mo = &dummy_opcode;
prev_insn.insn_mo = &dummy_opcode;
history[1].insn_mo = &dummy_opcode;
history[0].insn_mo = &dummy_opcode;
}
prev_insn_fixp[0] = NULL;
prev_insn_fixp[1] = NULL;
prev_insn_fixp[2] = NULL;
prev_insn_reloc_type[0] = BFD_RELOC_UNUSED;
prev_insn_reloc_type[1] = BFD_RELOC_UNUSED;
prev_insn_reloc_type[2] = BFD_RELOC_UNUSED;
prev_insn_extended = 0;
history[0].fixp[0] = NULL;
history[0].fixp[1] = NULL;
history[0].fixp[2] = NULL;
history[0].reloc_type[0] = BFD_RELOC_UNUSED;
history[0].reloc_type[1] = BFD_RELOC_UNUSED;
history[0].reloc_type[2] = BFD_RELOC_UNUSED;
history[0].extended_p = 0;
}
else if (pinfo & INSN_COND_BRANCH_LIKELY)
{
@ -2709,60 +2727,77 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
the next instruction. */
emit_nop ();
/* Update the previous insn information. */
prev_prev_insn = *ip;
prev_insn.insn_mo = &dummy_opcode;
prev_insn_fixp[0] = NULL;
prev_insn_fixp[1] = NULL;
prev_insn_fixp[2] = NULL;
prev_insn_reloc_type[0] = BFD_RELOC_UNUSED;
prev_insn_reloc_type[1] = BFD_RELOC_UNUSED;
prev_insn_reloc_type[2] = BFD_RELOC_UNUSED;
prev_insn_extended = 0;
prev_insn_is_delay_slot = 1;
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].reloc_type[0] = BFD_RELOC_UNUSED;
history[0].reloc_type[1] = BFD_RELOC_UNUSED;
history[0].reloc_type[2] = BFD_RELOC_UNUSED;
history[0].extended_p = 0;
history[0].delay_slot_p = 1;
}
else
{
/* Update the previous insn information. */
if (nops > 0)
prev_prev_insn.insn_mo = &dummy_opcode;
history[1].insn_mo = &dummy_opcode;
else
prev_prev_insn = prev_insn;
prev_insn = *ip;
{
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;
/* Any time we see a branch, we always fill the delay slot
immediately; since this insn is not a branch, we know it
is not in a delay slot. */
prev_insn_is_delay_slot = 0;
history[0].delay_slot_p = 0;
prev_insn_fixp[0] = fixp[0];
prev_insn_fixp[1] = fixp[1];
prev_insn_fixp[2] = fixp[2];
prev_insn_reloc_type[0] = reloc_type[0];
prev_insn_reloc_type[1] = reloc_type[1];
prev_insn_reloc_type[2] = reloc_type[2];
history[0].fixp[0] = fixp[0];
history[0].fixp[1] = fixp[1];
history[0].fixp[2] = fixp[2];
history[0].reloc_type[0] = reloc_type[0];
history[0].reloc_type[1] = reloc_type[1];
history[0].reloc_type[2] = reloc_type[2];
if (mips_opts.mips16)
prev_insn_extended = (ip->use_extend
|| *reloc_type > BFD_RELOC_UNUSED);
history[0].extended_p = (ip->use_extend
|| *reloc_type > BFD_RELOC_UNUSED);
}
prev_prev_insn_unreordered = prev_insn_unreordered;
prev_insn_unreordered = 0;
prev_insn_frag = frag_now;
prev_insn_where = f - frag_now->fr_literal;
prev_insn_valid = 1;
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;
history[0].valid_p = 1;
}
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. */
prev_prev_insn = prev_insn;
prev_insn = *ip;
prev_insn_reloc_type[0] = reloc_type[0];
prev_insn_reloc_type[1] = reloc_type[1];
prev_insn_reloc_type[2] = reloc_type[2];
prev_prev_insn_unreordered = prev_insn_unreordered;
prev_insn_unreordered = 1;
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].reloc_type[0] = reloc_type[0];
history[0].reloc_type[1] = reloc_type[1];
history[0].reloc_type[2] = reloc_type[2];
history[1].noreorder_p = history[0].noreorder_p;
history[0].noreorder_p = 1;
}
/* We just output an insn, so the next one doesn't have a label. */
@ -2778,21 +2813,21 @@ mips_no_prev_insn (int preserve)
{
if (! preserve)
{
prev_insn.insn_mo = &dummy_opcode;
prev_prev_insn.insn_mo = &dummy_opcode;
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;
}
prev_insn_valid = 0;
prev_insn_is_delay_slot = 0;
prev_insn_unreordered = 0;
prev_insn_extended = 0;
prev_insn_reloc_type[0] = BFD_RELOC_UNUSED;
prev_insn_reloc_type[1] = BFD_RELOC_UNUSED;
prev_insn_reloc_type[2] = BFD_RELOC_UNUSED;
prev_prev_insn_unreordered = 0;
history[0].valid_p = 0;
history[0].delay_slot_p = 0;
history[0].noreorder_p = 0;
history[0].extended_p = 0;
history[0].reloc_type[0] = BFD_RELOC_UNUSED;
history[0].reloc_type[1] = BFD_RELOC_UNUSED;
history[0].reloc_type[2] = BFD_RELOC_UNUSED;
history[1].noreorder_p = 0;
mips_clear_insn_labels ();
}
@ -2811,51 +2846,51 @@ mips_emit_delays (bfd_boolean insns)
nops = 0;
if ((! mips_opts.mips16
&& ((prev_insn.insn_mo->pinfo
&& ((history[0].insn_mo->pinfo
& (INSN_LOAD_COPROC_DELAY
| INSN_COPROC_MOVE_DELAY
| INSN_WRITE_COND_CODE))
&& ! cop_interlocks))
|| (! hilo_interlocks
&& (prev_insn.insn_mo->pinfo
&& (history[0].insn_mo->pinfo
& (INSN_READ_LO
| INSN_READ_HI)))
|| (! mips_opts.mips16
&& (prev_insn.insn_mo->pinfo & INSN_LOAD_MEMORY_DELAY)
&& (history[0].insn_mo->pinfo & INSN_LOAD_MEMORY_DELAY)
&& ! gpr_interlocks)
|| (! mips_opts.mips16
&& (prev_insn.insn_mo->pinfo & INSN_COPROC_MEMORY_DELAY)
&& (history[0].insn_mo->pinfo & INSN_COPROC_MEMORY_DELAY)
&& ! cop_mem_interlocks))
{
/* Itbl support may require additional care here. */
++nops;
if ((! mips_opts.mips16
&& ((prev_insn.insn_mo->pinfo & INSN_WRITE_COND_CODE)
&& ((history[0].insn_mo->pinfo & INSN_WRITE_COND_CODE)
&& ! cop_interlocks))
|| (! hilo_interlocks
&& ((prev_insn.insn_mo->pinfo & INSN_READ_HI)
|| (prev_insn.insn_mo->pinfo & INSN_READ_LO))))
&& ((history[0].insn_mo->pinfo & INSN_READ_HI)
|| (history[0].insn_mo->pinfo & INSN_READ_LO))))
++nops;
if (prev_insn_unreordered)
if (history[0].noreorder_p)
nops = 0;
}
else if ((! mips_opts.mips16
&& ((prev_prev_insn.insn_mo->pinfo & INSN_WRITE_COND_CODE)
&& ((history[1].insn_mo->pinfo & INSN_WRITE_COND_CODE)
&& ! cop_interlocks))
|| (! hilo_interlocks
&& ((prev_prev_insn.insn_mo->pinfo & INSN_READ_HI)
|| (prev_prev_insn.insn_mo->pinfo & INSN_READ_LO))))
&& ((history[1].insn_mo->pinfo & INSN_READ_HI)
|| (history[1].insn_mo->pinfo & INSN_READ_LO))))
{
/* Itbl support may require additional care here. */
if (! prev_prev_insn_unreordered)
if (! history[1].noreorder_p)
++nops;
}
if (mips_fix_vr4120 && prev_insn.insn_mo->name)
if (mips_fix_vr4120 && history[0].insn_mo->name)
{
int min_nops = 0;
const char *pn = prev_insn.insn_mo->name;
const char *pn = history[0].insn_mo->name;
if (strncmp (pn, "macc", 4) == 0
|| strncmp (pn, "dmacc", 5) == 0
|| strncmp (pn, "dmult", 5) == 0
@ -2920,7 +2955,7 @@ macro_start (void)
{
memset (&mips_macro_warning.sizes, 0, sizeof (mips_macro_warning.sizes));
mips_macro_warning.delay_slot_p = (mips_opts.noreorder
&& (prev_insn.insn_mo->pinfo
&& (history[0].insn_mo->pinfo
& (INSN_UNCOND_BRANCH_DELAY
| INSN_COND_BRANCH_DELAY
| INSN_COND_BRANCH_LIKELY)) != 0);

View File

@ -79,15 +79,6 @@ enum mips_pic_level
extern enum mips_pic_level mips_pic;
struct mips_cl_insn
{
unsigned long insn_opcode;
const struct mips_opcode *insn_mo;
/* The next two fields are used when generating mips16 code. */
bfd_boolean use_extend;
unsigned short extend;
};
extern int tc_get_register (int frame);
#define md_after_parse_args() mips_after_parse_args()