mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-27 22:48:57 +08:00
gas/
* config/tc-mips.c (mips_arg_info): Replace allow_nonconst and lax_max with lax_match. (match_int_operand): Update accordingly. Don't report an error for !lax_match-only cases. (match_insn): Replace more_alts with lax_match and use it to initialize the mips_arg_info field. Add a complete_p parameter. Handle implicit VU0 suffixes here. (match_invalid_for_isa, match_insns, match_mips16_insns): New functions. (mips_ip, mips16_ip): Use them.
This commit is contained in:
@ -1,3 +1,16 @@
|
|||||||
|
2013-08-19 Richard Sandiford <rdsandiford@googlemail.com>
|
||||||
|
|
||||||
|
* config/tc-mips.c (mips_arg_info): Replace allow_nonconst and
|
||||||
|
lax_max with lax_match.
|
||||||
|
(match_int_operand): Update accordingly. Don't report an error
|
||||||
|
for !lax_match-only cases.
|
||||||
|
(match_insn): Replace more_alts with lax_match and use it to
|
||||||
|
initialize the mips_arg_info field. Add a complete_p parameter.
|
||||||
|
Handle implicit VU0 suffixes here.
|
||||||
|
(match_invalid_for_isa, match_insns, match_mips16_insns): New
|
||||||
|
functions.
|
||||||
|
(mips_ip, mips16_ip): Use them.
|
||||||
|
|
||||||
2013-08-19 Richard Sandiford <rdsandiford@googlemail.com>
|
2013-08-19 Richard Sandiford <rdsandiford@googlemail.com>
|
||||||
|
|
||||||
* config/tc-mips.c (match_expression): Report uses of registers here.
|
* config/tc-mips.c (match_expression): Report uses of registers here.
|
||||||
|
@ -4271,14 +4271,11 @@ struct mips_arg_info
|
|||||||
where it gives the lsb position. */
|
where it gives the lsb position. */
|
||||||
unsigned int last_op_int;
|
unsigned int last_op_int;
|
||||||
|
|
||||||
/* If true, the OP_INT match routine should treat plain symbolic operands
|
/* If true, match routines should assume that no later instruction
|
||||||
as if a relocation operator like %lo(...) had been used. This is only
|
alternative matches and should therefore be as accomodating as
|
||||||
ever true if the operand can be relocated. */
|
possible. Match routines should not report errors if something
|
||||||
bfd_boolean allow_nonconst;
|
is only invalid for !LAX_MATCH. */
|
||||||
|
bfd_boolean lax_match;
|
||||||
/* When true, the OP_INT match routine should allow unsigned N-bit
|
|
||||||
arguments to be used where a signed N-bit operand is expected. */
|
|
||||||
bfd_boolean lax_max;
|
|
||||||
|
|
||||||
/* True if a reference to the current AT register was seen. */
|
/* True if a reference to the current AT register was seen. */
|
||||||
bfd_boolean seen_at;
|
bfd_boolean seen_at;
|
||||||
@ -4559,8 +4556,6 @@ match_int_operand (struct mips_arg_info *arg,
|
|||||||
factor = 1 << operand->shift;
|
factor = 1 << operand->shift;
|
||||||
min_val = mips_int_operand_min (operand);
|
min_val = mips_int_operand_min (operand);
|
||||||
max_val = mips_int_operand_max (operand);
|
max_val = mips_int_operand_max (operand);
|
||||||
if (arg->lax_max)
|
|
||||||
max_val = ((1 << operand_base->size) - 1) << operand->shift;
|
|
||||||
|
|
||||||
if (operand_base->lsb == 0
|
if (operand_base->lsb == 0
|
||||||
&& operand_base->size == 16
|
&& operand_base->size == 16
|
||||||
@ -4580,13 +4575,10 @@ match_int_operand (struct mips_arg_info *arg,
|
|||||||
|
|
||||||
if (offset_expr.X_op != O_constant)
|
if (offset_expr.X_op != O_constant)
|
||||||
{
|
{
|
||||||
/* If non-constant operands are allowed then leave them for
|
/* Accept non-constant operands if no later alternative matches,
|
||||||
the caller to process, otherwise fail the match. */
|
leaving it for the caller to process. */
|
||||||
if (!arg->allow_nonconst)
|
if (!arg->lax_match)
|
||||||
{
|
return FALSE;
|
||||||
match_not_constant (arg);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
offset_reloc[0] = BFD_RELOC_LO16;
|
offset_reloc[0] = BFD_RELOC_LO16;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@ -4595,6 +4587,16 @@ match_int_operand (struct mips_arg_info *arg,
|
|||||||
ourselves. */
|
ourselves. */
|
||||||
sval = offset_expr.X_add_number;
|
sval = offset_expr.X_add_number;
|
||||||
offset_expr.X_op = O_absent;
|
offset_expr.X_op = O_absent;
|
||||||
|
|
||||||
|
/* For compatibility with older assemblers, we accept
|
||||||
|
0x8000-0xffff as signed 16-bit numbers when only
|
||||||
|
signed numbers are allowed. */
|
||||||
|
if (sval > max_val)
|
||||||
|
{
|
||||||
|
max_val = ((1 << operand_base->size) - 1) << operand->shift;
|
||||||
|
if (!arg->lax_match && sval <= max_val)
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -7047,7 +7049,7 @@ normalize_address_expr (expressionS *ex)
|
|||||||
static bfd_boolean
|
static bfd_boolean
|
||||||
match_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode,
|
match_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode,
|
||||||
struct mips_operand_token *tokens, unsigned int opcode_extra,
|
struct mips_operand_token *tokens, unsigned int opcode_extra,
|
||||||
bfd_boolean more_alts)
|
bfd_boolean lax_match, bfd_boolean complete_p)
|
||||||
{
|
{
|
||||||
const char *args;
|
const char *args;
|
||||||
struct mips_arg_info arg;
|
struct mips_arg_info arg;
|
||||||
@ -7062,13 +7064,18 @@ match_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode,
|
|||||||
offset_reloc[2] = BFD_RELOC_UNUSED;
|
offset_reloc[2] = BFD_RELOC_UNUSED;
|
||||||
|
|
||||||
create_insn (insn, opcode);
|
create_insn (insn, opcode);
|
||||||
insn->insn_opcode |= opcode_extra;
|
/* When no opcode suffix is specified, assume ".xyzw". */
|
||||||
|
if ((opcode->pinfo2 & INSN2_VU0_CHANNEL_SUFFIX) != 0 && opcode_extra == 0)
|
||||||
|
insn->insn_opcode |= 0xf << mips_vu0_channel_mask.lsb;
|
||||||
|
else
|
||||||
|
insn->insn_opcode |= opcode_extra;
|
||||||
memset (&arg, 0, sizeof (arg));
|
memset (&arg, 0, sizeof (arg));
|
||||||
arg.insn = insn;
|
arg.insn = insn;
|
||||||
arg.token = tokens;
|
arg.token = tokens;
|
||||||
arg.argnum = 1;
|
arg.argnum = 1;
|
||||||
arg.last_regno = ILLEGAL_REG;
|
arg.last_regno = ILLEGAL_REG;
|
||||||
arg.dest_regno = ILLEGAL_REG;
|
arg.dest_regno = ILLEGAL_REG;
|
||||||
|
arg.lax_match = lax_match;
|
||||||
for (args = opcode->args;; ++args)
|
for (args = opcode->args;; ++args)
|
||||||
{
|
{
|
||||||
if (arg.token->type == OT_END)
|
if (arg.token->type == OT_END)
|
||||||
@ -7107,6 +7114,8 @@ match_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/* Successful match. */
|
/* Successful match. */
|
||||||
|
if (!complete_p)
|
||||||
|
return TRUE;
|
||||||
clear_insn_error ();
|
clear_insn_error ();
|
||||||
if (arg.dest_regno == arg.last_regno
|
if (arg.dest_regno == arg.last_regno
|
||||||
&& strncmp (insn->insn_mo->name, "jalr", 4) == 0)
|
&& strncmp (insn->insn_mo->name, "jalr", 4) == 0)
|
||||||
@ -7148,7 +7157,6 @@ match_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode,
|
|||||||
/* Handle special macro operands. Work out the properties of
|
/* Handle special macro operands. Work out the properties of
|
||||||
other operands. */
|
other operands. */
|
||||||
arg.opnum += 1;
|
arg.opnum += 1;
|
||||||
arg.lax_max = FALSE;
|
|
||||||
switch (*args)
|
switch (*args)
|
||||||
{
|
{
|
||||||
case '+':
|
case '+':
|
||||||
@ -7219,32 +7227,6 @@ match_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* ??? This is the traditional behavior, but is flaky if
|
|
||||||
there are alternative versions of the same instruction
|
|
||||||
for different subarchitectures. The next alternative
|
|
||||||
might not be suitable. */
|
|
||||||
case 'j':
|
|
||||||
/* For compatibility with older assemblers, we accept
|
|
||||||
0x8000-0xffff as signed 16-bit numbers when only
|
|
||||||
signed numbers are allowed. */
|
|
||||||
arg.lax_max = !more_alts;
|
|
||||||
case 'i':
|
|
||||||
/* Only accept non-constant operands if this is the
|
|
||||||
final alternative. Later alternatives might include
|
|
||||||
a macro implementation. */
|
|
||||||
arg.allow_nonconst = !more_alts;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'u':
|
|
||||||
/* There are no macro implementations for out-of-range values. */
|
|
||||||
arg.allow_nonconst = TRUE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'o':
|
|
||||||
/* There should always be a macro implementation. */
|
|
||||||
arg.allow_nonconst = FALSE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
*offset_reloc = BFD_RELOC_16_PCREL_S2;
|
*offset_reloc = BFD_RELOC_16_PCREL_S2;
|
||||||
break;
|
break;
|
||||||
@ -7479,6 +7461,141 @@ match_mips16_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Record that the current instruction is invalid for the current ISA. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
match_invalid_for_isa (void)
|
||||||
|
{
|
||||||
|
set_insn_error_ss
|
||||||
|
(0, _("Opcode not supported on this processor: %s (%s)"),
|
||||||
|
mips_cpu_info_from_arch (mips_opts.arch)->name,
|
||||||
|
mips_cpu_info_from_isa (mips_opts.isa)->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try to match TOKENS against a series of opcode entries, starting at FIRST.
|
||||||
|
Return true if a definite match or failure was found, storing any match
|
||||||
|
in INSN. OPCODE_EXTRA is a value that should be ORed into the opcode
|
||||||
|
(to handle things like VU0 suffixes). LAX_MATCH is true if we have already
|
||||||
|
tried and failed to match under normal conditions and now want to try a
|
||||||
|
more relaxed match. */
|
||||||
|
|
||||||
|
static bfd_boolean
|
||||||
|
match_insns (struct mips_cl_insn *insn, const struct mips_opcode *first,
|
||||||
|
const struct mips_opcode *past, struct mips_operand_token *tokens,
|
||||||
|
int opcode_extra, bfd_boolean lax_match)
|
||||||
|
{
|
||||||
|
const struct mips_opcode *opcode;
|
||||||
|
const struct mips_opcode *invalid_delay_slot;
|
||||||
|
bfd_boolean seen_valid_for_isa, seen_valid_for_size;
|
||||||
|
|
||||||
|
/* Search for a match, ignoring alternatives that don't satisfy the
|
||||||
|
current ISA or forced_length. */
|
||||||
|
invalid_delay_slot = 0;
|
||||||
|
seen_valid_for_isa = FALSE;
|
||||||
|
seen_valid_for_size = FALSE;
|
||||||
|
opcode = first;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
gas_assert (strcmp (opcode->name, first->name) == 0);
|
||||||
|
if (is_opcode_valid (opcode))
|
||||||
|
{
|
||||||
|
seen_valid_for_isa = TRUE;
|
||||||
|
if (is_size_valid (opcode))
|
||||||
|
{
|
||||||
|
bfd_boolean delay_slot_ok;
|
||||||
|
|
||||||
|
seen_valid_for_size = TRUE;
|
||||||
|
delay_slot_ok = is_delay_slot_valid (opcode);
|
||||||
|
if (match_insn (insn, opcode, tokens, opcode_extra,
|
||||||
|
lax_match, delay_slot_ok))
|
||||||
|
{
|
||||||
|
if (!delay_slot_ok)
|
||||||
|
{
|
||||||
|
if (!invalid_delay_slot)
|
||||||
|
invalid_delay_slot = opcode;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++opcode;
|
||||||
|
}
|
||||||
|
while (opcode < past && strcmp (opcode->name, first->name) == 0);
|
||||||
|
|
||||||
|
/* If the only matches we found had the wrong length for the delay slot,
|
||||||
|
pick the first such match. We'll issue an appropriate warning later. */
|
||||||
|
if (invalid_delay_slot)
|
||||||
|
{
|
||||||
|
if (match_insn (insn, invalid_delay_slot, tokens, opcode_extra,
|
||||||
|
lax_match, TRUE))
|
||||||
|
return TRUE;
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle the case where we didn't try to match an instruction because
|
||||||
|
all the alternatives were incompatible with the current ISA. */
|
||||||
|
if (!seen_valid_for_isa)
|
||||||
|
{
|
||||||
|
match_invalid_for_isa ();
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle the case where we didn't try to match an instruction because
|
||||||
|
all the alternatives were of the wrong size. */
|
||||||
|
if (!seen_valid_for_size)
|
||||||
|
{
|
||||||
|
if (mips_opts.insn32)
|
||||||
|
set_insn_error (0, _("Opcode not supported in the `insn32' mode"));
|
||||||
|
else
|
||||||
|
set_insn_error_i
|
||||||
|
(0, _("Unrecognized %d-bit version of microMIPS opcode"),
|
||||||
|
8 * forced_insn_length);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Like match_insns, but for MIPS16. */
|
||||||
|
|
||||||
|
static bfd_boolean
|
||||||
|
match_mips16_insns (struct mips_cl_insn *insn, const struct mips_opcode *first,
|
||||||
|
struct mips_operand_token *tokens)
|
||||||
|
{
|
||||||
|
const struct mips_opcode *opcode;
|
||||||
|
bfd_boolean seen_valid_for_isa;
|
||||||
|
|
||||||
|
/* Search for a match, ignoring alternatives that don't satisfy the
|
||||||
|
current ISA. There are no separate entries for extended forms so
|
||||||
|
we deal with forced_length later. */
|
||||||
|
seen_valid_for_isa = FALSE;
|
||||||
|
opcode = first;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
gas_assert (strcmp (opcode->name, first->name) == 0);
|
||||||
|
if (is_opcode_valid_16 (opcode))
|
||||||
|
{
|
||||||
|
seen_valid_for_isa = TRUE;
|
||||||
|
if (match_mips16_insn (insn, opcode, tokens))
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
++opcode;
|
||||||
|
}
|
||||||
|
while (opcode < &mips16_opcodes[bfd_mips16_num_opcodes]
|
||||||
|
&& strcmp (opcode->name, first->name) == 0);
|
||||||
|
|
||||||
|
/* Handle the case where we didn't try to match an instruction because
|
||||||
|
all the alternatives were incompatible with the current ISA. */
|
||||||
|
if (!seen_valid_for_isa)
|
||||||
|
{
|
||||||
|
match_invalid_for_isa ();
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set up global variables for the start of a new macro. */
|
/* Set up global variables for the start of a new macro. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -12952,14 +13069,10 @@ mips_lookup_insn (struct hash_control *hash, const char *start,
|
|||||||
to offset_expr. */
|
to offset_expr. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mips_ip (char *str, struct mips_cl_insn *ip)
|
mips_ip (char *str, struct mips_cl_insn *insn)
|
||||||
{
|
{
|
||||||
bfd_boolean wrong_delay_slot_insns = FALSE;
|
const struct mips_opcode *first, *past;
|
||||||
bfd_boolean need_delay_slot_ok = TRUE;
|
|
||||||
struct mips_opcode *firstinsn = NULL;
|
|
||||||
const struct mips_opcode *past;
|
|
||||||
struct hash_control *hash;
|
struct hash_control *hash;
|
||||||
struct mips_opcode *first, *insn;
|
|
||||||
char format;
|
char format;
|
||||||
size_t end;
|
size_t end;
|
||||||
struct mips_operand_token *tokens;
|
struct mips_operand_token *tokens;
|
||||||
@ -12976,26 +13089,22 @@ mips_ip (char *str, struct mips_cl_insn *ip)
|
|||||||
past = &mips_opcodes[NUMOPCODES];
|
past = &mips_opcodes[NUMOPCODES];
|
||||||
}
|
}
|
||||||
forced_insn_length = 0;
|
forced_insn_length = 0;
|
||||||
insn = NULL;
|
|
||||||
opcode_extra = 0;
|
opcode_extra = 0;
|
||||||
|
|
||||||
/* We first try to match an instruction up to a space or to the end. */
|
/* We first try to match an instruction up to a space or to the end. */
|
||||||
for (end = 0; str[end] != '\0' && !ISSPACE (str[end]); end++)
|
for (end = 0; str[end] != '\0' && !ISSPACE (str[end]); end++)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
first = insn = mips_lookup_insn (hash, str, end, &opcode_extra);
|
first = mips_lookup_insn (hash, str, end, &opcode_extra);
|
||||||
if (insn == NULL)
|
if (first == NULL)
|
||||||
{
|
{
|
||||||
set_insn_error (0, _("Unrecognized opcode"));
|
set_insn_error (0, _("Unrecognized opcode"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* When no opcode suffix is specified, assume ".xyzw". */
|
|
||||||
if ((insn->pinfo2 & INSN2_VU0_CHANNEL_SUFFIX) != 0 && opcode_extra == 0)
|
|
||||||
opcode_extra = 0xf << mips_vu0_channel_mask.lsb;
|
|
||||||
|
|
||||||
if (strcmp (insn->name, "li.s") == 0)
|
if (strcmp (first->name, "li.s") == 0)
|
||||||
format = 'f';
|
format = 'f';
|
||||||
else if (strcmp (insn->name, "li.d") == 0)
|
else if (strcmp (first->name, "li.d") == 0)
|
||||||
format = 'd';
|
format = 'd';
|
||||||
else
|
else
|
||||||
format = 0;
|
format = 0;
|
||||||
@ -13003,84 +13112,10 @@ mips_ip (char *str, struct mips_cl_insn *ip)
|
|||||||
if (!tokens)
|
if (!tokens)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* For microMIPS instructions placed in a fixed-length branch delay slot
|
if (!match_insns (insn, first, past, tokens, opcode_extra, FALSE)
|
||||||
we make up to two passes over the relevant fragment of the opcode
|
&& !match_insns (insn, first, past, tokens, opcode_extra, TRUE))
|
||||||
table. First we try instructions that meet the delay slot's length
|
set_insn_error (0, _("Illegal operands"));
|
||||||
requirement. If none matched, then we retry with the remaining ones
|
|
||||||
and if one matches, then we use it and then issue an appropriate
|
|
||||||
warning later on. */
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
bfd_boolean delay_slot_ok;
|
|
||||||
bfd_boolean size_ok;
|
|
||||||
bfd_boolean ok;
|
|
||||||
bfd_boolean more_alts;
|
|
||||||
|
|
||||||
gas_assert (strcmp (insn->name, first->name) == 0);
|
|
||||||
|
|
||||||
ok = is_opcode_valid (insn);
|
|
||||||
size_ok = is_size_valid (insn);
|
|
||||||
delay_slot_ok = is_delay_slot_valid (insn);
|
|
||||||
if (!delay_slot_ok && !wrong_delay_slot_insns)
|
|
||||||
{
|
|
||||||
firstinsn = insn;
|
|
||||||
wrong_delay_slot_insns = TRUE;
|
|
||||||
}
|
|
||||||
more_alts = (insn + 1 < past
|
|
||||||
&& strcmp (insn[0].name, insn[1].name) == 0);
|
|
||||||
if (!ok || !size_ok || delay_slot_ok != need_delay_slot_ok)
|
|
||||||
{
|
|
||||||
if (more_alts)
|
|
||||||
{
|
|
||||||
++insn;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (wrong_delay_slot_insns && need_delay_slot_ok)
|
|
||||||
{
|
|
||||||
gas_assert (firstinsn);
|
|
||||||
need_delay_slot_ok = FALSE;
|
|
||||||
past = insn + 1;
|
|
||||||
insn = firstinsn;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ok)
|
|
||||||
set_insn_error_ss
|
|
||||||
(0, _("Opcode not supported on this processor: %s (%s)"),
|
|
||||||
mips_cpu_info_from_arch (mips_opts.arch)->name,
|
|
||||||
mips_cpu_info_from_isa (mips_opts.isa)->name);
|
|
||||||
else if (mips_opts.insn32)
|
|
||||||
set_insn_error
|
|
||||||
(0, _("Opcode not supported in the `insn32' mode"));
|
|
||||||
else
|
|
||||||
set_insn_error_i
|
|
||||||
(0, _("Unrecognized %d-bit version of microMIPS opcode"),
|
|
||||||
8 * forced_insn_length);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (match_insn (ip, insn, tokens, opcode_extra,
|
|
||||||
more_alts || (wrong_delay_slot_insns
|
|
||||||
&& need_delay_slot_ok)))
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Args don't match. */
|
|
||||||
set_insn_error (0, _("Illegal operands"));
|
|
||||||
if (more_alts)
|
|
||||||
{
|
|
||||||
++insn;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (wrong_delay_slot_insns && need_delay_slot_ok)
|
|
||||||
{
|
|
||||||
gas_assert (firstinsn);
|
|
||||||
need_delay_slot_ok = FALSE;
|
|
||||||
past = insn + 1;
|
|
||||||
insn = firstinsn;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
obstack_free (&mips_operand_tokens, tokens);
|
obstack_free (&mips_operand_tokens, tokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -13089,10 +13124,10 @@ mips_ip (char *str, struct mips_cl_insn *ip)
|
|||||||
bytes if the user explicitly requested a small or extended instruction. */
|
bytes if the user explicitly requested a small or extended instruction. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mips16_ip (char *str, struct mips_cl_insn *ip)
|
mips16_ip (char *str, struct mips_cl_insn *insn)
|
||||||
{
|
{
|
||||||
char *end, *s, c;
|
char *end, *s, c;
|
||||||
struct mips_opcode *insn, *first;
|
struct mips_opcode *first;
|
||||||
struct mips_operand_token *tokens;
|
struct mips_operand_token *tokens;
|
||||||
|
|
||||||
forced_insn_length = 0;
|
forced_insn_length = 0;
|
||||||
@ -13133,10 +13168,10 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
|
|||||||
forced_insn_length = 2;
|
forced_insn_length = 2;
|
||||||
|
|
||||||
*end = 0;
|
*end = 0;
|
||||||
first = insn = (struct mips_opcode *) hash_find (mips16_op_hash, str);
|
first = (struct mips_opcode *) hash_find (mips16_op_hash, str);
|
||||||
*end = c;
|
*end = c;
|
||||||
|
|
||||||
if (!insn)
|
if (!first)
|
||||||
{
|
{
|
||||||
set_insn_error (0, _("Unrecognized opcode"));
|
set_insn_error (0, _("Unrecognized opcode"));
|
||||||
return;
|
return;
|
||||||
@ -13146,45 +13181,9 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
|
|||||||
if (!tokens)
|
if (!tokens)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (;;)
|
if (!match_mips16_insns (insn, first, tokens))
|
||||||
{
|
set_insn_error (0, _("Illegal operands"));
|
||||||
bfd_boolean ok;
|
|
||||||
bfd_boolean more_alts;
|
|
||||||
|
|
||||||
gas_assert (strcmp (insn->name, first->name) == 0);
|
|
||||||
|
|
||||||
ok = is_opcode_valid_16 (insn);
|
|
||||||
more_alts = (insn + 1 < &mips16_opcodes[bfd_mips16_num_opcodes]
|
|
||||||
&& strcmp (insn[0].name, insn[1].name) == 0);
|
|
||||||
if (! ok)
|
|
||||||
{
|
|
||||||
if (more_alts)
|
|
||||||
{
|
|
||||||
++insn;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
set_insn_error_ss
|
|
||||||
(0, _("Opcode not supported on this processor: %s (%s)"),
|
|
||||||
mips_cpu_info_from_arch (mips_opts.arch)->name,
|
|
||||||
mips_cpu_info_from_isa (mips_opts.isa)->name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (match_mips16_insn (ip, insn, tokens))
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Args don't match. */
|
|
||||||
set_insn_error (0, _("Illegal operands"));
|
|
||||||
if (more_alts)
|
|
||||||
{
|
|
||||||
++insn;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
obstack_free (&mips_operand_tokens, tokens);
|
obstack_free (&mips_operand_tokens, tokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user