2011-04-20 Catherine Moore <clm@codesourcery.com>
David Ung <davidu@mips.com> * config/mips.c (mips_cl_insn): Add new field complete_p. (create_insn): Initialize complete_p to zero. (BASE_REG_EQ): New. (fix_24k_align_to): New. (fix_24k_store_info): Declare. (fix_24k_sort): New. (fix_24k_record_store_info): New. (nops_for_24k): New. (nops_for_insn): Call nops_for_24k. (append_insn): Move O_constant expression handling.
This commit is contained in:
parent
17b09558c0
commit
15be625dff
2 changed files with 286 additions and 69 deletions
|
@ -1,3 +1,17 @@
|
||||||
|
2011-04-20 Catherine Moore <clm@codesourcery.com>
|
||||||
|
David Ung <davidu@mips.com>
|
||||||
|
|
||||||
|
* config/mips.c (mips_cl_insn): Add new field complete_p.
|
||||||
|
(create_insn): Initialize complete_p to zero.
|
||||||
|
(BASE_REG_EQ): New.
|
||||||
|
(fix_24k_align_to): New.
|
||||||
|
(fix_24k_store_info): Declare.
|
||||||
|
(fix_24k_sort): New.
|
||||||
|
(fix_24k_record_store_info): New.
|
||||||
|
(nops_for_24k): New.
|
||||||
|
(nops_for_insn): Call nops_for_24k.
|
||||||
|
(append_insn): Move O_constant expression handling.
|
||||||
|
|
||||||
2011-04-20 Alan Modra <amodra@gmail.com>
|
2011-04-20 Alan Modra <amodra@gmail.com>
|
||||||
|
|
||||||
* hash.c (set_gas_hash_table_size): Use bfd_hash_set_default_size.
|
* hash.c (set_gas_hash_table_size): Use bfd_hash_set_default_size.
|
||||||
|
|
|
@ -156,6 +156,9 @@ struct mips_cl_insn
|
||||||
|
|
||||||
/* True for mips16 instructions that jump to an absolute address. */
|
/* True for mips16 instructions that jump to an absolute address. */
|
||||||
unsigned int mips16_absolute_jump_p : 1;
|
unsigned int mips16_absolute_jump_p : 1;
|
||||||
|
|
||||||
|
/* True if this instruction is complete. */
|
||||||
|
unsigned int complete_p : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The ABI to use. */
|
/* The ABI to use. */
|
||||||
|
@ -1384,6 +1387,7 @@ create_insn (struct mips_cl_insn *insn, const struct mips_opcode *mo)
|
||||||
insn->fixed_p = (mips_opts.noreorder > 0);
|
insn->fixed_p = (mips_opts.noreorder > 0);
|
||||||
insn->noreorder_p = (mips_opts.noreorder > 0);
|
insn->noreorder_p = (mips_opts.noreorder > 0);
|
||||||
insn->mips16_absolute_jump_p = 0;
|
insn->mips16_absolute_jump_p = 0;
|
||||||
|
insn->complete_p = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Record the current MIPS16 mode in now_seg. */
|
/* Record the current MIPS16 mode in now_seg. */
|
||||||
|
@ -2680,6 +2684,189 @@ nops_for_vr4130 (const struct mips_cl_insn *hist,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define BASE_REG_EQ(INSN1, INSN2) \
|
||||||
|
((((INSN1) >> OP_SH_RS) & OP_MASK_RS) \
|
||||||
|
== (((INSN2) >> OP_SH_RS) & OP_MASK_RS))
|
||||||
|
|
||||||
|
/* Return the minimum alignment for this store instruction. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
fix_24k_align_to (const struct mips_opcode *mo)
|
||||||
|
{
|
||||||
|
if (strcmp (mo->name, "sh") == 0)
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
if (strcmp (mo->name, "swc1") == 0
|
||||||
|
|| strcmp (mo->name, "swc2") == 0
|
||||||
|
|| strcmp (mo->name, "sw") == 0
|
||||||
|
|| strcmp (mo->name, "sc") == 0
|
||||||
|
|| strcmp (mo->name, "s.s") == 0)
|
||||||
|
return 4;
|
||||||
|
|
||||||
|
if (strcmp (mo->name, "sdc1") == 0
|
||||||
|
|| strcmp (mo->name, "sdc2") == 0
|
||||||
|
|| strcmp (mo->name, "s.d") == 0)
|
||||||
|
return 8;
|
||||||
|
|
||||||
|
/* sb, swl, swr */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct fix_24k_store_info
|
||||||
|
{
|
||||||
|
/* Immediate offset, if any, for this store instruction. */
|
||||||
|
short off;
|
||||||
|
/* Alignment required by this store instruction. */
|
||||||
|
int align_to;
|
||||||
|
/* True for register offsets. */
|
||||||
|
int register_offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Comparison function used by qsort. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
fix_24k_sort (const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const struct fix_24k_store_info *pos1 = a;
|
||||||
|
const struct fix_24k_store_info *pos2 = b;
|
||||||
|
|
||||||
|
return (pos1->off - pos2->off);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* INSN is a store instruction. Try to record the store information
|
||||||
|
in STINFO. Return false if the information isn't known. */
|
||||||
|
|
||||||
|
static bfd_boolean
|
||||||
|
fix_24k_record_store_info (struct fix_24k_store_info *stinfo,
|
||||||
|
const struct mips_cl_insn *insn)
|
||||||
|
{
|
||||||
|
/* The instruction must have a known offset. */
|
||||||
|
if (!insn->complete_p || !strstr (insn->insn_mo->args, "o("))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
stinfo->off = (insn->insn_opcode >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE;
|
||||||
|
stinfo->align_to = fix_24k_align_to (insn->insn_mo);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 24K Errata: Lost Data on Stores During Refill.
|
||||||
|
|
||||||
|
Problem: The FSB (fetch store buffer) acts as an intermediate buffer
|
||||||
|
for the data cache refills and store data. The following describes
|
||||||
|
the scenario where the store data could be lost.
|
||||||
|
|
||||||
|
* A data cache miss, due to either a load or a store, causing fill
|
||||||
|
data to be supplied by the memory subsystem
|
||||||
|
* The first three doublewords of fill data are returned and written
|
||||||
|
into the cache
|
||||||
|
* A sequence of four stores occurs in consecutive cycles around the
|
||||||
|
final doubleword of the fill:
|
||||||
|
* Store A
|
||||||
|
* Store B
|
||||||
|
* Store C
|
||||||
|
* Zero, One or more instructions
|
||||||
|
* Store D
|
||||||
|
|
||||||
|
The four stores A-D must be to different doublewords of the line that
|
||||||
|
is being filled. The fourth instruction in the sequence above permits
|
||||||
|
the fill of the final doubleword to be transferred from the FSB into
|
||||||
|
the cache. In the sequence above, the stores may be either integer
|
||||||
|
(sb, sh, sw, swr, swl, sc) or coprocessor (swc1/swc2, sdc1/sdc2,
|
||||||
|
swxc1, sdxc1, suxc1) stores, as long as the four stores are to
|
||||||
|
different doublewords on the line. If the floating point unit is
|
||||||
|
running in 1:2 mode, it is not possible to create the sequence above
|
||||||
|
using only floating point store instructions.
|
||||||
|
|
||||||
|
In this case, the cache line being filled is incorrectly marked
|
||||||
|
invalid, thereby losing the data from any store to the line that
|
||||||
|
occurs between the original miss and the completion of the five
|
||||||
|
cycle sequence shown above.
|
||||||
|
|
||||||
|
The workarounds are:
|
||||||
|
|
||||||
|
* Run the data cache in write-through mode.
|
||||||
|
* Insert a non-store instruction between
|
||||||
|
Store A and Store B or Store B and Store C. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
nops_for_24k (const struct mips_cl_insn *hist,
|
||||||
|
const struct mips_cl_insn *insn)
|
||||||
|
{
|
||||||
|
struct fix_24k_store_info pos[3];
|
||||||
|
int align, i, base_offset;
|
||||||
|
|
||||||
|
/* If INSN is definitely not a store, there's nothing to worry about. */
|
||||||
|
if (insn && (insn->insn_mo->pinfo & INSN_STORE_MEMORY) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Likewise, the previous instruction wasn't a store. */
|
||||||
|
if ((hist[0].insn_mo->pinfo & INSN_STORE_MEMORY) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* If we don't know what came before, assume the worst. */
|
||||||
|
if (hist[1].frag == NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* If the instruction was not a store, there's nothing to worry about. */
|
||||||
|
if ((hist[1].insn_mo->pinfo & INSN_STORE_MEMORY) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* If we don't know the relationship between the store addresses,
|
||||||
|
assume the worst. */
|
||||||
|
if (insn == NULL
|
||||||
|
|| !BASE_REG_EQ (insn->insn_opcode, hist[0].insn_opcode)
|
||||||
|
|| !BASE_REG_EQ (insn->insn_opcode, hist[1].insn_opcode))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (!fix_24k_record_store_info (&pos[0], insn)
|
||||||
|
|| !fix_24k_record_store_info (&pos[1], &hist[0])
|
||||||
|
|| !fix_24k_record_store_info (&pos[2], &hist[1]))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
qsort (&pos, 3, sizeof (struct fix_24k_store_info), fix_24k_sort);
|
||||||
|
|
||||||
|
/* Pick a value of ALIGN and X such that all offsets are adjusted by
|
||||||
|
X bytes and such that the base register + X is known to be aligned
|
||||||
|
to align bytes. */
|
||||||
|
|
||||||
|
if (((insn->insn_opcode >> OP_SH_RS) & OP_MASK_RS) == SP)
|
||||||
|
align = 8;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
align = pos[0].align_to;
|
||||||
|
base_offset = pos[0].off;
|
||||||
|
for (i = 1; i < 3; i++)
|
||||||
|
if (align < pos[i].align_to)
|
||||||
|
{
|
||||||
|
align = pos[i].align_to;
|
||||||
|
base_offset = pos[i].off;
|
||||||
|
}
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
pos[i].off -= base_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos[0].off &= ~align + 1;
|
||||||
|
pos[1].off &= ~align + 1;
|
||||||
|
pos[2].off &= ~align + 1;
|
||||||
|
|
||||||
|
/* If any two stores write to the same chunk, they also write to the
|
||||||
|
same doubleword. The offsets are still sorted at this point. */
|
||||||
|
if (pos[0].off == pos[1].off || pos[1].off == pos[2].off)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* A range of at least 9 bytes is needed for the stores to be in
|
||||||
|
non-overlapping doublewords. */
|
||||||
|
if (pos[2].off - pos[0].off <= 8)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (pos[2].off - pos[1].off >= 24
|
||||||
|
|| pos[1].off - pos[0].off >= 24
|
||||||
|
|| pos[2].off - pos[0].off >= 32)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Return the number of nops that would be needed if instruction INSN
|
/* Return the number of nops that would be needed if instruction INSN
|
||||||
immediately followed the MAX_NOPS instructions given by HIST,
|
immediately followed the MAX_NOPS instructions given by HIST,
|
||||||
where HIST[0] is the most recent instruction. If INSN is null,
|
where HIST[0] is the most recent instruction. If INSN is null,
|
||||||
|
@ -2706,6 +2893,13 @@ nops_for_insn (const struct mips_cl_insn *hist,
|
||||||
nops = tmp_nops;
|
nops = tmp_nops;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mips_fix_24k)
|
||||||
|
{
|
||||||
|
tmp_nops = nops_for_24k (hist, insn);
|
||||||
|
if (tmp_nops > nops)
|
||||||
|
nops = tmp_nops;
|
||||||
|
}
|
||||||
|
|
||||||
return nops;
|
return nops;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2836,6 +3030,82 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
|
||||||
pinfo = ip->insn_mo->pinfo;
|
pinfo = ip->insn_mo->pinfo;
|
||||||
pinfo2 = ip->insn_mo->pinfo2;
|
pinfo2 = ip->insn_mo->pinfo2;
|
||||||
|
|
||||||
|
if (address_expr == NULL)
|
||||||
|
ip->complete_p = 1;
|
||||||
|
else if (*reloc_type <= BFD_RELOC_UNUSED
|
||||||
|
&& address_expr->X_op == O_constant)
|
||||||
|
{
|
||||||
|
unsigned int tmp;
|
||||||
|
|
||||||
|
ip->complete_p = 1;
|
||||||
|
switch (*reloc_type)
|
||||||
|
{
|
||||||
|
case BFD_RELOC_32:
|
||||||
|
ip->insn_opcode |= address_expr->X_add_number;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BFD_RELOC_MIPS_HIGHEST:
|
||||||
|
tmp = (address_expr->X_add_number + 0x800080008000ull) >> 48;
|
||||||
|
ip->insn_opcode |= tmp & 0xffff;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BFD_RELOC_MIPS_HIGHER:
|
||||||
|
tmp = (address_expr->X_add_number + 0x80008000ull) >> 32;
|
||||||
|
ip->insn_opcode |= tmp & 0xffff;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BFD_RELOC_HI16_S:
|
||||||
|
tmp = (address_expr->X_add_number + 0x8000) >> 16;
|
||||||
|
ip->insn_opcode |= tmp & 0xffff;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BFD_RELOC_HI16:
|
||||||
|
ip->insn_opcode |= (address_expr->X_add_number >> 16) & 0xffff;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BFD_RELOC_UNUSED:
|
||||||
|
case BFD_RELOC_LO16:
|
||||||
|
case BFD_RELOC_MIPS_GOT_DISP:
|
||||||
|
ip->insn_opcode |= address_expr->X_add_number & 0xffff;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BFD_RELOC_MIPS_JMP:
|
||||||
|
if ((address_expr->X_add_number & 3) != 0)
|
||||||
|
as_bad (_("jump to misaligned address (0x%lx)"),
|
||||||
|
(unsigned long) address_expr->X_add_number);
|
||||||
|
ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0x3ffffff;
|
||||||
|
ip->complete_p = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BFD_RELOC_MIPS16_JMP:
|
||||||
|
if ((address_expr->X_add_number & 3) != 0)
|
||||||
|
as_bad (_("jump to misaligned address (0x%lx)"),
|
||||||
|
(unsigned long) address_expr->X_add_number);
|
||||||
|
ip->insn_opcode |=
|
||||||
|
(((address_expr->X_add_number & 0x7c0000) << 3)
|
||||||
|
| ((address_expr->X_add_number & 0xf800000) >> 7)
|
||||||
|
| ((address_expr->X_add_number & 0x3fffc) >> 2));
|
||||||
|
ip->complete_p = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BFD_RELOC_16_PCREL_S2:
|
||||||
|
if ((address_expr->X_add_number & 3) != 0)
|
||||||
|
as_bad (_("branch to misaligned address (0x%lx)"),
|
||||||
|
(unsigned long) address_expr->X_add_number);
|
||||||
|
if (mips_relax_branch)
|
||||||
|
goto need_reloc;
|
||||||
|
if ((address_expr->X_add_number + 0x20000) & ~0x3ffff)
|
||||||
|
as_bad (_("branch address range overflow (0x%lx)"),
|
||||||
|
(unsigned long) address_expr->X_add_number);
|
||||||
|
ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0xffff;
|
||||||
|
ip->complete_p = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
internalError ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mips_relax.sequence != 2 && !mips_opts.noreorder)
|
if (mips_relax.sequence != 2 && !mips_opts.noreorder)
|
||||||
{
|
{
|
||||||
/* There are a lot of optimizations we could do that we don't.
|
/* There are a lot of optimizations we could do that we don't.
|
||||||
|
@ -3007,75 +3277,8 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
|
||||||
|
|
||||||
if (address_expr != NULL && *reloc_type <= BFD_RELOC_UNUSED)
|
if (address_expr != NULL && *reloc_type <= BFD_RELOC_UNUSED)
|
||||||
{
|
{
|
||||||
if (address_expr->X_op == O_constant)
|
if (!ip->complete_p
|
||||||
{
|
&& *reloc_type < BFD_RELOC_UNUSED)
|
||||||
unsigned int tmp;
|
|
||||||
|
|
||||||
switch (*reloc_type)
|
|
||||||
{
|
|
||||||
case BFD_RELOC_32:
|
|
||||||
ip->insn_opcode |= address_expr->X_add_number;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BFD_RELOC_MIPS_HIGHEST:
|
|
||||||
tmp = (address_expr->X_add_number + 0x800080008000ull) >> 48;
|
|
||||||
ip->insn_opcode |= tmp & 0xffff;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BFD_RELOC_MIPS_HIGHER:
|
|
||||||
tmp = (address_expr->X_add_number + 0x80008000ull) >> 32;
|
|
||||||
ip->insn_opcode |= tmp & 0xffff;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BFD_RELOC_HI16_S:
|
|
||||||
tmp = (address_expr->X_add_number + 0x8000) >> 16;
|
|
||||||
ip->insn_opcode |= tmp & 0xffff;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BFD_RELOC_HI16:
|
|
||||||
ip->insn_opcode |= (address_expr->X_add_number >> 16) & 0xffff;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BFD_RELOC_UNUSED:
|
|
||||||
case BFD_RELOC_LO16:
|
|
||||||
case BFD_RELOC_MIPS_GOT_DISP:
|
|
||||||
ip->insn_opcode |= address_expr->X_add_number & 0xffff;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BFD_RELOC_MIPS_JMP:
|
|
||||||
if ((address_expr->X_add_number & 3) != 0)
|
|
||||||
as_bad (_("jump to misaligned address (0x%lx)"),
|
|
||||||
(unsigned long) address_expr->X_add_number);
|
|
||||||
ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0x3ffffff;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BFD_RELOC_MIPS16_JMP:
|
|
||||||
if ((address_expr->X_add_number & 3) != 0)
|
|
||||||
as_bad (_("jump to misaligned address (0x%lx)"),
|
|
||||||
(unsigned long) address_expr->X_add_number);
|
|
||||||
ip->insn_opcode |=
|
|
||||||
(((address_expr->X_add_number & 0x7c0000) << 3)
|
|
||||||
| ((address_expr->X_add_number & 0xf800000) >> 7)
|
|
||||||
| ((address_expr->X_add_number & 0x3fffc) >> 2));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BFD_RELOC_16_PCREL_S2:
|
|
||||||
if ((address_expr->X_add_number & 3) != 0)
|
|
||||||
as_bad (_("branch to misaligned address (0x%lx)"),
|
|
||||||
(unsigned long) address_expr->X_add_number);
|
|
||||||
if (mips_relax_branch)
|
|
||||||
goto need_reloc;
|
|
||||||
if ((address_expr->X_add_number + 0x20000) & ~0x3ffff)
|
|
||||||
as_bad (_("branch address range overflow (0x%lx)"),
|
|
||||||
(unsigned long) address_expr->X_add_number);
|
|
||||||
ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0xffff;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
internalError ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (*reloc_type < BFD_RELOC_UNUSED)
|
|
||||||
need_reloc:
|
need_reloc:
|
||||||
{
|
{
|
||||||
reloc_howto_type *howto;
|
reloc_howto_type *howto;
|
||||||
|
|
Loading…
Reference in a new issue