* 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> 2005-03-08 Daniel Jacobowitz <dan@codesourcery.com>
* doc/Makefile.am: Update as.info dependencies. * doc/Makefile.am: Update as.info dependencies.

View File

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

View File

@ -79,15 +79,6 @@ enum mips_pic_level
extern enum mips_pic_level mips_pic; 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); extern int tc_get_register (int frame);
#define md_after_parse_args() mips_after_parse_args() #define md_after_parse_args() mips_after_parse_args()