include/opcode/

* mips.h (mips_decode_reg_operand): New function.
	(INSN_WRITE_SHIFT, INSN_WRITE_1, INSN_WRITE_2, INSN_WRITE_ALL)
	(INSN_READ_SHIFT, INSN_READ_1, INSN_READ_2, INSN_READ_3, INSN_READ_4)
	(INSN_READ_ALL, INSN_READ_GPR_24, INSN_WRITE_GPR_24, INSN_UDI):
	New macros.
	(INSN_WRITE_GPR_D, INSN_WRITE_GPR_T, INSN_WRITE_FPR_D)
	(INSN_WRITE_FPR_S, INSN_WRITE_FPR_T, INSN_READ_GPR_S, INSN_READ_GPR_T)
	(INSN_READ_FPR_S, INSN_READ_FPR_T, INSN_READ_FPR_R, INSN_WRITE_GPR_S)
	(INSN2_WRITE_GPR_Z, INSN2_WRITE_FPR_Z, INSN2_READ_GPR_Z)
	(INSN2_READ_FPR_Z, INSN2_READ_GPR_D, INSN2_READ_FPR_D)
	(INSN2_WRITE_GPR_MB, INSN2_READ_GPR_MC, INSN2_MOD_GPR_MD)
	(INSN2_READ_GPR_ME, INSN2_MOD_GPR_MF, INSN2_READ_GPR_MG)
	(INSN2_READ_GPR_MJ, INSN2_WRITE_GPR_MJ, INSN2_READ_GPR_MP)
	(INSN2_WRITE_GPR_MP, INSN2_READ_GPR_MQ, INSN2_READ_GP)
	(INSN2_WRITE_GPR_MH, INSN2_READ_GPR_MMN): Delete.  Renumber other
	macros to cover the gaps.
	(INSN2_MOD_SP): Replace with...
	(INSN2_WRITE_SP, INSN2_READ_SP): ...these new macros.
	(MIPS16_INSN_WRITE_X, MIPS16_INSN_WRITE_Y, MIPS16_INSN_WRITE_Z)
	(MIPS16_INSN_WRITE_T, MIPS16_INSN_WRITE_31, MIPS16_INSN_WRITE_GPR_Y)
	(MIPS16_INSN_READ_X, MIPS16_INSN_READ_Y, MIPS16_INSN_READ_Z)
	(MIPS16_INSN_READ_T, MIPS16_INSN_READ_SP, MIPS16_INSN_READ_GPR_X):
	Delete.

opcodes/
	* mips-opc.c (WR_1, WR_2, RD_1, RD_2, RD_3, RD_4, MOD_1, MOD_2, UDI):
	New macros.
	(WR_d, WR_t, WR_D, WR_T, WR_S, RD_s, RD_b, RD_t, RD_S, RD_T, RD_R)
	(WR_z, WR_Z, RD_z, RD_Z, RD_d): Delete.
	(mips_builtin_opcodes): Use the new position-based read-write flags
	instead of field-based ones.  Use UDI for "udi..." instructions.
	* mips16-opc.c (WR_1, WR_2, RD_1, RD_2, RD_3, RD_4, MOD_1, MOD_2):
	New macros.
	(WR_x, WR_y, WR_z, WR_Y, RD_x, RD_y, RD_Z, RD_X): Delete.
	(RD_T, WR_T, WR_31): Redefine using generic INSN_* flags.
	(WR_SP, RD_16): New macros.
	(RD_SP): Redefine as an INSN2_* flag.
	(MOD_SP): Redefine in terms of RD_SP and WR_SP.
	(mips16_opcodes): Use the new position-based read-write flags
	instead of field-based ones.  Use RD_16 for "nop".  Move RD_SP to
	pinfo2 field.
	* micromips-opc.c (WR_1, WR_2, RD_1, RD_2, RD_3, RD_4, MOD_1, MOD_2):
	New macros.
	(WR_mb, RD_mc, RD_md, WR_md, RD_me, RD_mf, WR_mf, RD_mg, WR_mh, RD_mj)
	(WR_mj, RD_ml, RD_mmn, RD_mp, WR_mp, RD_mq, RD_gp, WR_d, WR_t, WR_D)
	(WR_T, WR_S, RD_s, RD_b, RD_t, RD_T, RD_S, RD_R, RD_D): Delete.
	(RD_sp, WR_sp): Redefine to INSN2_READ_SP and INSN2_WRITE_SP.
	(micromips_opcodes): Use the new position-based read-write flags
	instead of field-based ones.
	* mips-dis.c (print_insn_arg): Use mips_decode_reg_operand.
	(print_insn_mips, print_insn_micromips): Use INSN_WRITE_1 instead
	of field-based flags.

gas/
	* config/tc-mips.c (MAX_OPERANDS): New macro.
	(mips_operand_array): New structure.
	(mips_operands, mips16_operands, micromips_operands): New arrays.
	(micromips_to_32_reg_b_map, micromips_to_32_reg_c_map)
	(micromips_to_32_reg_e_map, micromips_to_32_reg_f_map)
	(micromips_to_32_reg_g_map, micromips_to_32_reg_l_map)
	(micromips_to_32_reg_q_map): Delete.
	(insn_operands, insn_opno, insn_extract_operand): New functions.
	(validate_mips_insn): Take a mips_operand_array as argument and
	use it to build up a list of operands.  Extend to handle INSN_MACRO
	and MIPS16.
	(validate_mips16_insn): New function.
	(validate_micromips_insn): Take a mips_operand_array as argument.
	Handle INSN_MACRO.
	(md_begin): Initialize mips_operands, mips16_operands and
	micromips_operands.  Call validate_mips_insn and
	validate_micromips_insn for macro instructions too.
	Call validate_mips16_insn for MIPS16 instructions.
	(insn_read_mask, insn_write_mask, operand_reg_mask, insn_reg_mask):
	New functions.
	(gpr_read_mask, gpr_write_mask, fpr_read_mask, fpr_write_mask): Use
	them.  Handle INSN_UDI.
	(get_append_method): Use gpr_read_mask.
This commit is contained in:
Richard Sandiford 2013-08-01 20:55:25 +00:00
parent 265459441c
commit fc76e73056
9 changed files with 2974 additions and 2907 deletions

View File

@ -1,3 +1,29 @@
2013-08-01 Richard Sandiford <rdsandiford@googlemail.com>
* config/tc-mips.c (MAX_OPERANDS): New macro.
(mips_operand_array): New structure.
(mips_operands, mips16_operands, micromips_operands): New arrays.
(micromips_to_32_reg_b_map, micromips_to_32_reg_c_map)
(micromips_to_32_reg_e_map, micromips_to_32_reg_f_map)
(micromips_to_32_reg_g_map, micromips_to_32_reg_l_map)
(micromips_to_32_reg_q_map): Delete.
(insn_operands, insn_opno, insn_extract_operand): New functions.
(validate_mips_insn): Take a mips_operand_array as argument and
use it to build up a list of operands. Extend to handle INSN_MACRO
and MIPS16.
(validate_mips16_insn): New function.
(validate_micromips_insn): Take a mips_operand_array as argument.
Handle INSN_MACRO.
(md_begin): Initialize mips_operands, mips16_operands and
micromips_operands. Call validate_mips_insn and
validate_micromips_insn for macro instructions too.
Call validate_mips16_insn for MIPS16 instructions.
(insn_read_mask, insn_write_mask, operand_reg_mask, insn_reg_mask):
New functions.
(gpr_read_mask, gpr_write_mask, fpr_read_mask, fpr_write_mask): Use
them. Handle INSN_UDI.
(get_append_method): Use gpr_read_mask.
2013-08-01 Richard Sandiford <rdsandiford@googlemail.com>
* config/tc-mips.c (compact_branch_p, uncond_branch_p): Use the same

View File

@ -689,6 +689,15 @@ static int mips_debug = 0;
fill a branch delay slot. */
static struct mips_cl_insn history[1 + MAX_NOPS];
/* Arrays of operands for each instruction. */
#define MAX_OPERANDS 5
struct mips_operand_array {
const struct mips_operand *operand[MAX_OPERANDS];
};
static struct mips_operand_array *mips_operands;
static struct mips_operand_array *mips16_operands;
static struct mips_operand_array *micromips_operands;
/* Nop instructions used by emit_nop. */
static struct mips_cl_insn nop_insn;
static struct mips_cl_insn mips16_nop_insn;
@ -764,12 +773,7 @@ static const unsigned int mips16_to_32_reg_map[] =
/* Map microMIPS register numbers to normal MIPS register numbers. */
#define micromips_to_32_reg_b_map mips16_to_32_reg_map
#define micromips_to_32_reg_c_map mips16_to_32_reg_map
#define micromips_to_32_reg_d_map mips16_to_32_reg_map
#define micromips_to_32_reg_e_map mips16_to_32_reg_map
#define micromips_to_32_reg_f_map mips16_to_32_reg_map
#define micromips_to_32_reg_g_map mips16_to_32_reg_map
/* The microMIPS registers with type h. */
static const unsigned int micromips_to_32_reg_h_map1[] =
@ -781,8 +785,6 @@ static const unsigned int micromips_to_32_reg_h_map2[] =
6, 7, 7, 21, 22, 5, 6, 7
};
#define micromips_to_32_reg_l_map mips16_to_32_reg_map
/* The microMIPS registers with type m. */
static const unsigned int micromips_to_32_reg_m_map[] =
{
@ -791,12 +793,6 @@ static const unsigned int micromips_to_32_reg_m_map[] =
#define micromips_to_32_reg_n_map micromips_to_32_reg_m_map
/* The microMIPS registers with type q. */
static const unsigned int micromips_to_32_reg_q_map[] =
{
0, 17, 2, 3, 4, 5, 6, 7
};
/* Classifies the kind of instructions we're interested in when
implementing -mfix-vr4120. */
enum fix_vr4120_class
@ -1966,6 +1962,39 @@ create_insn (struct mips_cl_insn *insn, const struct mips_opcode *mo)
insn->cleared_p = 0;
}
/* Get a list of all the operands in INSN. */
static const struct mips_operand_array *
insn_operands (const struct mips_cl_insn *insn)
{
if (insn->insn_mo >= &mips_opcodes[0]
&& insn->insn_mo < &mips_opcodes[NUMOPCODES])
return &mips_operands[insn->insn_mo - &mips_opcodes[0]];
if (insn->insn_mo >= &mips16_opcodes[0]
&& insn->insn_mo < &mips16_opcodes[bfd_mips16_num_opcodes])
return &mips16_operands[insn->insn_mo - &mips16_opcodes[0]];
if (insn->insn_mo >= &micromips_opcodes[0]
&& insn->insn_mo < &micromips_opcodes[bfd_micromips_num_opcodes])
return &micromips_operands[insn->insn_mo - &micromips_opcodes[0]];
abort ();
}
/* Get a description of operand OPNO of INSN. */
static const struct mips_operand *
insn_opno (const struct mips_cl_insn *insn, unsigned opno)
{
const struct mips_operand_array *operands;
operands = insn_operands (insn);
if (opno >= MAX_OPERANDS || !operands->operand[opno])
abort ();
return operands->operand[opno];
}
/* Install UVAL as the value of OPERAND in INSN. */
static inline void
@ -1975,6 +2004,15 @@ insn_insert_operand (struct mips_cl_insn *insn,
insn->insn_opcode = mips_insert_operand (operand, insn->insn_opcode, uval);
}
/* Extract the value of OPERAND from INSN. */
static inline unsigned
insn_extract_operand (const struct mips_cl_insn *insn,
const struct mips_operand *operand)
{
return mips_extract_operand (operand, insn->insn_opcode);
}
/* Record the current MIPS16/microMIPS mode in now_seg. */
static void
@ -2831,28 +2869,34 @@ is_delay_slot_valid (const struct mips_opcode *mo)
return TRUE;
}
/* For consistency checking, verify that all bits of OPCODE are
specified either by the match/mask part of the instruction
definition, or by the operand list. INSN_BITS says which
bits of the instruction are significant and DECODE_OPERAND
provides the mips_operand description of each operand. */
/* For consistency checking, verify that all bits of OPCODE are specified
either by the match/mask part of the instruction definition, or by the
operand list. Also build up a list of operands in OPERANDS.
INSN_BITS says which bits of the instruction are significant.
If OPCODE is a standard or microMIPS instruction, DECODE_OPERAND
provides the mips_operand description of each operand. DECODE_OPERAND
is null for MIPS16 instructions. */
static int
validate_mips_insn (const struct mips_opcode *opcode,
unsigned long insn_bits,
const struct mips_operand *(*decode_operand) (const char *))
const struct mips_operand *(*decode_operand) (const char *),
struct mips_operand_array *operands)
{
const char *s;
unsigned long used_bits, doubled, undefined;
unsigned long used_bits, doubled, undefined, opno, mask;
const struct mips_operand *operand;
if ((opcode->mask & opcode->match) != opcode->match)
mask = (opcode->pinfo == INSN_MACRO ? 0 : opcode->mask);
if ((mask & opcode->match) != opcode->match)
{
as_bad (_("internal: bad mips opcode (mask error): %s %s"),
opcode->name, opcode->args);
return 0;
}
used_bits = 0;
opno = 0;
for (s = opcode->args; *s; ++s)
switch (*s)
{
@ -2862,33 +2906,44 @@ validate_mips_insn (const struct mips_opcode *opcode,
break;
default:
operand = decode_operand (s);
if (!operand)
if (!decode_operand)
operand = decode_mips16_operand (*s, FALSE);
else
operand = decode_operand (s);
if (!operand && opcode->pinfo != INSN_MACRO)
{
as_bad (_("internal: unknown operand type: %s %s"),
opcode->name, opcode->args);
return 0;
}
used_bits |= ((1 << operand->size) - 1) << operand->lsb;
if (operand->type == OP_MDMX_IMM_REG)
/* Bit 5 is the format selector (OB vs QH). The opcode table
has separate entries for each format. */
used_bits &= ~(1 << (operand->lsb + 5));
gas_assert (opno < MAX_OPERANDS);
operands->operand[opno] = operand;
if (operand)
{
used_bits |= ((1 << operand->size) - 1) << operand->lsb;
if (operand->type == OP_MDMX_IMM_REG)
/* Bit 5 is the format selector (OB vs QH). The opcode table
has separate entries for each format. */
used_bits &= ~(1 << (operand->lsb + 5));
if (operand->type == OP_ENTRY_EXIT_LIST)
used_bits &= ~(mask & 0x700);
}
/* Skip prefix characters. */
if (*s == '+' || *s == 'm')
if (decode_operand && (*s == '+' || *s == 'm'))
++s;
opno += 1;
break;
}
doubled = used_bits & opcode->mask & insn_bits;
doubled = used_bits & mask & insn_bits;
if (doubled)
{
as_bad (_("internal: bad mips opcode (bits 0x%08lx doubly defined):"
" %s %s"), doubled, opcode->name, opcode->args);
return 0;
}
used_bits |= opcode->mask;
used_bits |= mask;
undefined = ~used_bits & insn_bits;
if (undefined)
if (opcode->pinfo != INSN_MACRO && undefined)
{
as_bad (_("internal: bad mips opcode (bits 0x%08lx undefined): %s %s"),
undefined, opcode->name, opcode->args);
@ -2904,15 +2959,40 @@ validate_mips_insn (const struct mips_opcode *opcode,
return 1;
}
/* The MIPS16 version of validate_mips_insn. */
static int
validate_mips16_insn (const struct mips_opcode *opcode,
struct mips_operand_array *operands)
{
if (opcode->args[0] == 'a' || opcode->args[0] == 'i')
{
/* In this case OPCODE defines the first 16 bits in a 32-bit jump
instruction. Use TMP to describe the full instruction. */
struct mips_opcode tmp;
tmp = *opcode;
tmp.match <<= 16;
tmp.mask <<= 16;
return validate_mips_insn (&tmp, 0xffffffff, 0, operands);
}
return validate_mips_insn (opcode, 0xffff, 0, operands);
}
/* The microMIPS version of validate_mips_insn. */
static int
validate_micromips_insn (const struct mips_opcode *opc)
validate_micromips_insn (const struct mips_opcode *opc,
struct mips_operand_array *operands)
{
unsigned long insn_bits;
unsigned long major;
unsigned int length;
if (opc->pinfo == INSN_MACRO)
return validate_mips_insn (opc, 0xffffffff, decode_micromips_operand,
operands);
length = micromips_insn_length (opc);
if (length != 2 && length != 4)
{
@ -2933,7 +3013,8 @@ validate_micromips_insn (const struct mips_opcode *opc)
insn_bits = 1 << 4 * length;
insn_bits <<= 4 * length;
insn_bits -= 1;
return validate_mips_insn (opc, insn_bits, decode_micromips_operand);
return validate_mips_insn (opc, insn_bits, decode_micromips_operand,
operands);
}
/* This function is called once, at assembler startup time. It should set up
@ -2958,6 +3039,7 @@ md_begin (void)
op_hash = hash_new ();
mips_operands = XCNEWVEC (struct mips_operand_array, NUMOPCODES);
for (i = 0; i < NUMOPCODES;)
{
const char *name = mips_opcodes[i].name;
@ -2972,18 +3054,15 @@ md_begin (void)
}
do
{
if (mips_opcodes[i].pinfo != INSN_MACRO)
if (!validate_mips_insn (&mips_opcodes[i], 0xffffffff,
decode_mips_operand, &mips_operands[i]))
broken = 1;
if (nop_insn.insn_mo == NULL && strcmp (name, "nop") == 0)
{
if (!validate_mips_insn (&mips_opcodes[i], 0xffffffff,
decode_mips_operand))
broken = 1;
if (nop_insn.insn_mo == NULL && strcmp (name, "nop") == 0)
{
create_insn (&nop_insn, mips_opcodes + i);
if (mips_fix_loongson2f_nop)
nop_insn.insn_opcode = LOONGSON2F_NOP_INSN;
nop_insn.fixed_p = 1;
}
create_insn (&nop_insn, mips_opcodes + i);
if (mips_fix_loongson2f_nop)
nop_insn.insn_opcode = LOONGSON2F_NOP_INSN;
nop_insn.fixed_p = 1;
}
++i;
}
@ -2991,6 +3070,8 @@ md_begin (void)
}
mips16_op_hash = hash_new ();
mips16_operands = XCNEWVEC (struct mips_operand_array,
bfd_mips16_num_opcodes);
i = 0;
while (i < bfd_mips16_num_opcodes)
@ -3003,14 +3084,8 @@ md_begin (void)
mips16_opcodes[i].name, retval);
do
{
if (mips16_opcodes[i].pinfo != INSN_MACRO
&& ((mips16_opcodes[i].match & mips16_opcodes[i].mask)
!= mips16_opcodes[i].match))
{
fprintf (stderr, _("internal error: bad mips16 opcode: %s %s\n"),
mips16_opcodes[i].name, mips16_opcodes[i].args);
broken = 1;
}
if (!validate_mips16_insn (&mips16_opcodes[i], &mips16_operands[i]))
broken = 1;
if (mips16_nop_insn.insn_mo == NULL && strcmp (name, "nop") == 0)
{
create_insn (&mips16_nop_insn, mips16_opcodes + i);
@ -3023,6 +3098,8 @@ md_begin (void)
}
micromips_op_hash = hash_new ();
micromips_operands = XCNEWVEC (struct mips_operand_array,
bfd_micromips_num_opcodes);
i = 0;
while (i < bfd_micromips_num_opcodes)
@ -3035,27 +3112,30 @@ md_begin (void)
as_fatal (_("internal: can't hash `%s': %s"),
micromips_opcodes[i].name, retval);
do
if (micromips_opcodes[i].pinfo != INSN_MACRO)
{
struct mips_cl_insn *micromips_nop_insn;
{
struct mips_cl_insn *micromips_nop_insn;
if (!validate_micromips_insn (&micromips_opcodes[i]))
broken = 1;
if (!validate_micromips_insn (&micromips_opcodes[i],
&micromips_operands[i]))
broken = 1;
if (micromips_insn_length (micromips_opcodes + i) == 2)
micromips_nop_insn = &micromips_nop16_insn;
else if (micromips_insn_length (micromips_opcodes + i) == 4)
micromips_nop_insn = &micromips_nop32_insn;
else
continue;
if (micromips_opcodes[i].pinfo != INSN_MACRO)
{
if (micromips_insn_length (micromips_opcodes + i) == 2)
micromips_nop_insn = &micromips_nop16_insn;
else if (micromips_insn_length (micromips_opcodes + i) == 4)
micromips_nop_insn = &micromips_nop32_insn;
else
continue;
if (micromips_nop_insn->insn_mo == NULL
&& strcmp (name, "nop") == 0)
{
create_insn (micromips_nop_insn, micromips_opcodes + i);
micromips_nop_insn->fixed_p = 1;
}
}
if (micromips_nop_insn->insn_mo == NULL
&& strcmp (name, "nop") == 0)
{
create_insn (micromips_nop_insn, micromips_opcodes + i);
micromips_nop_insn->fixed_p = 1;
}
}
}
while (++i < bfd_micromips_num_opcodes
&& strcmp (micromips_opcodes[i].name, name) == 0);
}
@ -3580,26 +3660,116 @@ get_delay_slot_nop (const struct mips_cl_insn *ip)
return NOP_INSN;
}
/* Return the mask of core registers that IP reads or writes. */
/* Return a mask that has bit N set if OPCODE reads the register(s)
in operand N. */
static unsigned int
gpr_mod_mask (const struct mips_cl_insn *ip)
insn_read_mask (const struct mips_opcode *opcode)
{
unsigned long pinfo2;
unsigned int mask;
return (opcode->pinfo & INSN_READ_ALL) >> INSN_READ_SHIFT;
}
mask = 0;
pinfo2 = ip->insn_mo->pinfo2;
if (mips_opts.micromips)
/* Return a mask that has bit N set if OPCODE writes to the register(s)
in operand N. */
static unsigned int
insn_write_mask (const struct mips_opcode *opcode)
{
return (opcode->pinfo & INSN_WRITE_ALL) >> INSN_WRITE_SHIFT;
}
/* Return a mask of the registers specified by operand OPERAND of INSN.
Ignore registers of type OP_REG_<t> unless bit OP_REG_<t> of TYPE_MASK
is set. */
static unsigned int
operand_reg_mask (const struct mips_cl_insn *insn,
const struct mips_operand *operand,
unsigned int type_mask)
{
unsigned int uval, vsel;
switch (operand->type)
{
if (pinfo2 & INSN2_MOD_GPR_MD)
mask |= 1 << micromips_to_32_reg_d_map[EXTRACT_OPERAND (1, MD, *ip)];
if (pinfo2 & INSN2_MOD_GPR_MF)
mask |= 1 << micromips_to_32_reg_f_map[EXTRACT_OPERAND (1, MF, *ip)];
case OP_INT:
case OP_MAPPED_INT:
case OP_MSB:
case OP_PCREL:
case OP_PERF_REG:
case OP_ADDIUSP_INT:
case OP_ENTRY_EXIT_LIST:
case OP_REPEAT_DEST_REG:
case OP_REPEAT_PREV_REG:
case OP_PC:
abort ();
case OP_REG:
{
const struct mips_reg_operand *reg_op;
reg_op = (const struct mips_reg_operand *) operand;
if (!(type_mask & (1 << reg_op->reg_type)))
return 0;
uval = insn_extract_operand (insn, operand);
return 1 << mips_decode_reg_operand (reg_op, uval);
}
case OP_REG_PAIR:
{
const struct mips_reg_pair_operand *pair_op;
pair_op = (const struct mips_reg_pair_operand *) operand;
if (!(type_mask & (1 << pair_op->reg_type)))
return 0;
uval = insn_extract_operand (insn, operand);
return (1 << pair_op->reg1_map[uval]) | (1 << pair_op->reg2_map[uval]);
}
case OP_CLO_CLZ_DEST:
if (!(type_mask & (1 << OP_REG_GP)))
return 0;
uval = insn_extract_operand (insn, operand);
return (1 << (uval & 31)) | (1 << (uval >> 5));
case OP_LWM_SWM_LIST:
abort ();
case OP_SAVE_RESTORE_LIST:
abort ();
case OP_MDMX_IMM_REG:
if (!(type_mask & (1 << OP_REG_VEC)))
return 0;
uval = insn_extract_operand (insn, operand);
vsel = uval >> 5;
if ((vsel & 0x18) == 0x18)
return 0;
return 1 << (uval & 31);
}
if (pinfo2 & INSN2_MOD_SP)
mask |= 1 << SP;
return mask;
abort ();
}
/* Return a mask of the registers specified by operands OPNO_MASK of INSN,
where bit N of OPNO_MASK is set if operand N should be included.
Ignore registers of type OP_REG_<t> unless bit OP_REG_<t> of TYPE_MASK
is set. */
static unsigned int
insn_reg_mask (const struct mips_cl_insn *insn,
unsigned int type_mask, unsigned int opno_mask)
{
unsigned int opno, reg_mask;
opno = 0;
reg_mask = 0;
while (opno_mask != 0)
{
if (opno_mask & 1)
reg_mask |= operand_reg_mask (insn, insn_opno (insn, opno), type_mask);
opno_mask >>= 1;
opno += 1;
}
return reg_mask;
}
/* Return the mask of core registers that IP reads. */
@ -3610,60 +3780,24 @@ gpr_read_mask (const struct mips_cl_insn *ip)
unsigned long pinfo, pinfo2;
unsigned int mask;
mask = gpr_mod_mask (ip);
mask = insn_reg_mask (ip, 1 << OP_REG_GP, insn_read_mask (ip->insn_mo));
pinfo = ip->insn_mo->pinfo;
pinfo2 = ip->insn_mo->pinfo2;
if (mips_opts.mips16)
if (pinfo & INSN_UDI)
{
if (pinfo & MIPS16_INSN_READ_X)
mask |= 1 << mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RX, *ip)];
if (pinfo & MIPS16_INSN_READ_Y)
mask |= 1 << mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RY, *ip)];
if (pinfo & MIPS16_INSN_READ_T)
mask |= 1 << TREG;
if (pinfo & MIPS16_INSN_READ_SP)
mask |= 1 << SP;
if (pinfo & MIPS16_INSN_READ_Z)
mask |= 1 << (mips16_to_32_reg_map
[MIPS16_EXTRACT_OPERAND (MOVE32Z, *ip)]);
if (pinfo & MIPS16_INSN_READ_GPR_X)
mask |= 1 << MIPS16_EXTRACT_OPERAND (REGR32, *ip);
}
else
{
if (pinfo2 & INSN2_READ_GPR_D)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RD, *ip);
if (pinfo & INSN_READ_GPR_T)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RT, *ip);
if (pinfo & INSN_READ_GPR_S)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RS, *ip);
if (pinfo2 & INSN2_READ_GP)
mask |= 1 << GP;
if (pinfo2 & INSN2_READ_GPR_Z)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RZ, *ip);
/* UDI instructions have traditionally been assumed to read RS
and RT. */
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RT, *ip);
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RS, *ip);
}
if (pinfo & INSN_READ_GPR_24)
mask |= 1 << 24;
if (pinfo2 & INSN2_READ_GPR_16)
mask |= 1 << 16;
if (pinfo2 & INSN2_READ_SP)
mask |= 1 << SP;
if (pinfo2 & INSN2_READ_GPR_31)
mask |= 1 << RA;
if (mips_opts.micromips)
{
if (pinfo2 & INSN2_READ_GPR_MC)
mask |= 1 << micromips_to_32_reg_c_map[EXTRACT_OPERAND (1, MC, *ip)];
if (pinfo2 & INSN2_READ_GPR_ME)
mask |= 1 << micromips_to_32_reg_e_map[EXTRACT_OPERAND (1, ME, *ip)];
if (pinfo2 & INSN2_READ_GPR_MG)
mask |= 1 << micromips_to_32_reg_g_map[EXTRACT_OPERAND (1, MG, *ip)];
if (pinfo2 & INSN2_READ_GPR_MJ)
mask |= 1 << EXTRACT_OPERAND (1, MJ, *ip);
if (pinfo2 & INSN2_READ_GPR_MMN)
{
mask |= 1 << micromips_to_32_reg_m_map[EXTRACT_OPERAND (1, MM, *ip)];
mask |= 1 << micromips_to_32_reg_n_map[EXTRACT_OPERAND (1, MN, *ip)];
}
if (pinfo2 & INSN2_READ_GPR_MP)
mask |= 1 << EXTRACT_OPERAND (1, MP, *ip);
if (pinfo2 & INSN2_READ_GPR_MQ)
mask |= 1 << micromips_to_32_reg_q_map[EXTRACT_OPERAND (1, MQ, *ip)];
}
mask |= 1 << 31;
/* Don't include register 0. */
return mask & ~1;
}
@ -3676,51 +3810,18 @@ gpr_write_mask (const struct mips_cl_insn *ip)
unsigned long pinfo, pinfo2;
unsigned int mask;
mask = gpr_mod_mask (ip);
mask = insn_reg_mask (ip, 1 << OP_REG_GP, insn_write_mask (ip->insn_mo));
pinfo = ip->insn_mo->pinfo;
pinfo2 = ip->insn_mo->pinfo2;
if (mips_opts.mips16)
{
if (pinfo & MIPS16_INSN_WRITE_X)
mask |= 1 << mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RX, *ip)];
if (pinfo & MIPS16_INSN_WRITE_Y)
mask |= 1 << mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RY, *ip)];
if (pinfo & MIPS16_INSN_WRITE_Z)
mask |= 1 << mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RZ, *ip)];
if (pinfo & MIPS16_INSN_WRITE_T)
mask |= 1 << TREG;
if (pinfo & MIPS16_INSN_WRITE_31)
mask |= 1 << RA;
if (pinfo & MIPS16_INSN_WRITE_GPR_Y)
mask |= 1 << MIPS16OP_EXTRACT_REG32R (ip->insn_opcode);
}
else
{
if (pinfo & INSN_WRITE_GPR_D)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RD, *ip);
if (pinfo & INSN_WRITE_GPR_T)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RT, *ip);
if (pinfo & INSN_WRITE_GPR_S)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RS, *ip);
if (pinfo & INSN_WRITE_GPR_31)
mask |= 1 << RA;
if (pinfo2 & INSN2_WRITE_GPR_Z)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RZ, *ip);
}
if (mips_opts.micromips)
{
if (pinfo2 & INSN2_WRITE_GPR_MB)
mask |= 1 << micromips_to_32_reg_b_map[EXTRACT_OPERAND (1, MB, *ip)];
if (pinfo2 & INSN2_WRITE_GPR_MH)
{
mask |= 1 << micromips_to_32_reg_h_map1[EXTRACT_OPERAND (1, MH, *ip)];
mask |= 1 << micromips_to_32_reg_h_map2[EXTRACT_OPERAND (1, MH, *ip)];
}
if (pinfo2 & INSN2_WRITE_GPR_MJ)
mask |= 1 << EXTRACT_OPERAND (1, MJ, *ip);
if (pinfo2 & INSN2_WRITE_GPR_MP)
mask |= 1 << EXTRACT_OPERAND (1, MP, *ip);
}
if (pinfo & INSN_WRITE_GPR_24)
mask |= 1 << 24;
if (pinfo & INSN_WRITE_GPR_31)
mask |= 1 << 31;
if (pinfo & INSN_UDI)
/* UDI instructions have traditionally been assumed to write to RD. */
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RD, *ip);
if (pinfo2 & INSN2_WRITE_SP)
mask |= 1 << SP;
/* Don't include register 0. */
return mask & ~1;
}
@ -3730,25 +3831,12 @@ gpr_write_mask (const struct mips_cl_insn *ip)
static unsigned int
fpr_read_mask (const struct mips_cl_insn *ip)
{
unsigned long pinfo, pinfo2;
unsigned long pinfo;
unsigned int mask;
mask = 0;
mask = insn_reg_mask (ip, (1 << OP_REG_FP) | (1 << OP_REG_VEC),
insn_read_mask (ip->insn_mo));
pinfo = ip->insn_mo->pinfo;
pinfo2 = ip->insn_mo->pinfo2;
if (!mips_opts.mips16)
{
if (pinfo2 & INSN2_READ_FPR_D)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FD, *ip);
if (pinfo & INSN_READ_FPR_S)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FS, *ip);
if (pinfo & INSN_READ_FPR_T)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FT, *ip);
if (pinfo & INSN_READ_FPR_R)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FR, *ip);
if (pinfo2 & INSN2_READ_FPR_Z)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FZ, *ip);
}
/* Conservatively treat all operands to an FP_D instruction are doubles.
(This is overly pessimistic for things like cvt.d.s.) */
if (HAVE_32BIT_FPRS && (pinfo & FP_D))
@ -3761,23 +3849,12 @@ fpr_read_mask (const struct mips_cl_insn *ip)
static unsigned int
fpr_write_mask (const struct mips_cl_insn *ip)
{
unsigned long pinfo, pinfo2;
unsigned long pinfo;
unsigned int mask;
mask = 0;
mask = insn_reg_mask (ip, (1 << OP_REG_FP) | (1 << OP_REG_VEC),
insn_write_mask (ip->insn_mo));
pinfo = ip->insn_mo->pinfo;
pinfo2 = ip->insn_mo->pinfo2;
if (!mips_opts.mips16)
{
if (pinfo & INSN_WRITE_FPR_D)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FD, *ip);
if (pinfo & INSN_WRITE_FPR_S)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FS, *ip);
if (pinfo & INSN_WRITE_FPR_T)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FT, *ip);
if (pinfo2 & INSN2_WRITE_FPR_Z)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FZ, *ip);
}
/* Conservatively treat all operands to an FP_D instruction are doubles.
(This is overly pessimistic for things like cvt.s.d.) */
if (HAVE_32BIT_FPRS && (pinfo & FP_D))
@ -5769,8 +5846,6 @@ static enum append_method
get_append_method (struct mips_cl_insn *ip, expressionS *address_expr,
bfd_reloc_code_real_type *reloc_type)
{
unsigned long pinfo, pinfo2;
/* The relaxed version of a macro sequence must be inherently
hazard-free. */
if (mips_relax.sequence == 2)
@ -5787,12 +5862,9 @@ get_append_method (struct mips_cl_insn *ip, expressionS *address_expr,
&& can_swap_branch_p (ip, address_expr, reloc_type))
return APPEND_SWAP;
pinfo = ip->insn_mo->pinfo;
pinfo2 = ip->insn_mo->pinfo2;
if (mips_opts.mips16
&& ISA_SUPPORTS_MIPS16E
&& ((pinfo & MIPS16_INSN_READ_X) != 0
|| (pinfo2 & INSN2_READ_GPR_31) != 0))
&& gpr_read_mask (ip) != 0)
return APPEND_ADD_COMPACT;
return APPEND_ADD_WITH_NOP;

View File

@ -1,3 +1,29 @@
2013-08-01 Richard Sandiford <rdsandiford@googlemail.com>
* mips.h (mips_decode_reg_operand): New function.
(INSN_WRITE_SHIFT, INSN_WRITE_1, INSN_WRITE_2, INSN_WRITE_ALL)
(INSN_READ_SHIFT, INSN_READ_1, INSN_READ_2, INSN_READ_3, INSN_READ_4)
(INSN_READ_ALL, INSN_READ_GPR_24, INSN_WRITE_GPR_24, INSN_UDI):
New macros.
(INSN_WRITE_GPR_D, INSN_WRITE_GPR_T, INSN_WRITE_FPR_D)
(INSN_WRITE_FPR_S, INSN_WRITE_FPR_T, INSN_READ_GPR_S, INSN_READ_GPR_T)
(INSN_READ_FPR_S, INSN_READ_FPR_T, INSN_READ_FPR_R, INSN_WRITE_GPR_S)
(INSN2_WRITE_GPR_Z, INSN2_WRITE_FPR_Z, INSN2_READ_GPR_Z)
(INSN2_READ_FPR_Z, INSN2_READ_GPR_D, INSN2_READ_FPR_D)
(INSN2_WRITE_GPR_MB, INSN2_READ_GPR_MC, INSN2_MOD_GPR_MD)
(INSN2_READ_GPR_ME, INSN2_MOD_GPR_MF, INSN2_READ_GPR_MG)
(INSN2_READ_GPR_MJ, INSN2_WRITE_GPR_MJ, INSN2_READ_GPR_MP)
(INSN2_WRITE_GPR_MP, INSN2_READ_GPR_MQ, INSN2_READ_GP)
(INSN2_WRITE_GPR_MH, INSN2_READ_GPR_MMN): Delete. Renumber other
macros to cover the gaps.
(INSN2_MOD_SP): Replace with...
(INSN2_WRITE_SP, INSN2_READ_SP): ...these new macros.
(MIPS16_INSN_WRITE_X, MIPS16_INSN_WRITE_Y, MIPS16_INSN_WRITE_Z)
(MIPS16_INSN_WRITE_T, MIPS16_INSN_WRITE_31, MIPS16_INSN_WRITE_GPR_Y)
(MIPS16_INSN_READ_X, MIPS16_INSN_READ_Y, MIPS16_INSN_READ_Z)
(MIPS16_INSN_READ_T, MIPS16_INSN_READ_SP, MIPS16_INSN_READ_GPR_X):
Delete.
2013-08-01 Richard Sandiford <rdsandiford@googlemail.com>
* mips.h (MIPS16_INSN_WRITE_SP, MIPS16_INSN_READ_31)

View File

@ -604,6 +604,17 @@ mips_decode_int_operand (const struct mips_int_operand *operand,
return uval;
}
/* Return the register that OPERAND encodes as UVAL. */
static inline int
mips_decode_reg_operand (const struct mips_reg_operand *operand,
unsigned int uval)
{
if (operand->reg_map)
uval = operand->reg_map[uval];
return uval;
}
/* PC-relative operand OPERAND has value UVAL and is relative to BASE_PC.
Return the address that it encodes. */
@ -836,71 +847,67 @@ struct mips_opcode
/* These are the bits which may be set in the pinfo field of an
instructions, if it is not equal to INSN_MACRO. */
/* Modifies the general purpose register in OP_*_RD. */
#define INSN_WRITE_GPR_D 0x00000001
/* Modifies the general purpose register in OP_*_RT. */
#define INSN_WRITE_GPR_T 0x00000002
/* Writes to operand number N. */
#define INSN_WRITE_SHIFT 0
#define INSN_WRITE_1 0x00000001
#define INSN_WRITE_2 0x00000002
#define INSN_WRITE_ALL 0x00000003
/* Reads from operand number N. */
#define INSN_READ_SHIFT 2
#define INSN_READ_1 0x00000004
#define INSN_READ_2 0x00000008
#define INSN_READ_3 0x00000010
#define INSN_READ_4 0x00000020
#define INSN_READ_ALL 0x0000003c
/* Modifies general purpose register 31. */
#define INSN_WRITE_GPR_31 0x00000004
/* Modifies the floating point register in OP_*_FD. */
#define INSN_WRITE_FPR_D 0x00000008
/* Modifies the floating point register in OP_*_FS. */
#define INSN_WRITE_FPR_S 0x00000010
/* Modifies the floating point register in OP_*_FT. */
#define INSN_WRITE_FPR_T 0x00000020
/* Reads the general purpose register in OP_*_RS. */
#define INSN_READ_GPR_S 0x00000040
/* Reads the general purpose register in OP_*_RT. */
#define INSN_READ_GPR_T 0x00000080
/* Reads the floating point register in OP_*_FS. */
#define INSN_READ_FPR_S 0x00000100
/* Reads the floating point register in OP_*_FT. */
#define INSN_READ_FPR_T 0x00000200
/* Reads the floating point register in OP_*_FR. */
#define INSN_READ_FPR_R 0x00000400
#define INSN_WRITE_GPR_31 0x00000040
/* Modifies coprocessor condition code. */
#define INSN_WRITE_COND_CODE 0x00000800
#define INSN_WRITE_COND_CODE 0x00000080
/* Reads coprocessor condition code. */
#define INSN_READ_COND_CODE 0x00001000
#define INSN_READ_COND_CODE 0x00000100
/* TLB operation. */
#define INSN_TLB 0x00002000
#define INSN_TLB 0x00000200
/* Reads coprocessor register other than floating point register. */
#define INSN_COP 0x00004000
#define INSN_COP 0x00000400
/* Instruction loads value from memory, requiring delay. */
#define INSN_LOAD_MEMORY_DELAY 0x00008000
#define INSN_LOAD_MEMORY_DELAY 0x00000800
/* Instruction loads value from coprocessor, requiring delay. */
#define INSN_LOAD_COPROC_DELAY 0x00010000
#define INSN_LOAD_COPROC_DELAY 0x00001000
/* Instruction has unconditional branch delay slot. */
#define INSN_UNCOND_BRANCH_DELAY 0x00020000
#define INSN_UNCOND_BRANCH_DELAY 0x00002000
/* Instruction has conditional branch delay slot. */
#define INSN_COND_BRANCH_DELAY 0x00040000
#define INSN_COND_BRANCH_DELAY 0x00004000
/* Conditional branch likely: if branch not taken, insn nullified. */
#define INSN_COND_BRANCH_LIKELY 0x00080000
#define INSN_COND_BRANCH_LIKELY 0x00008000
/* Moves to coprocessor register, requiring delay. */
#define INSN_COPROC_MOVE_DELAY 0x00100000
#define INSN_COPROC_MOVE_DELAY 0x00010000
/* Loads coprocessor register from memory, requiring delay. */
#define INSN_COPROC_MEMORY_DELAY 0x00200000
#define INSN_COPROC_MEMORY_DELAY 0x00020000
/* Reads the HI register. */
#define INSN_READ_HI 0x00400000
#define INSN_READ_HI 0x00040000
/* Reads the LO register. */
#define INSN_READ_LO 0x00800000
#define INSN_READ_LO 0x00080000
/* Modifies the HI register. */
#define INSN_WRITE_HI 0x01000000
#define INSN_WRITE_HI 0x00100000
/* Modifies the LO register. */
#define INSN_WRITE_LO 0x02000000
#define INSN_WRITE_LO 0x00200000
/* Not to be placed in a branch delay slot, either architecturally
or for ease of handling (such as with instructions that take a trap). */
#define INSN_NO_DELAY_SLOT 0x04000000
#define INSN_NO_DELAY_SLOT 0x00400000
/* Instruction stores value into memory. */
#define INSN_STORE_MEMORY 0x08000000
#define INSN_STORE_MEMORY 0x00800000
/* Instruction uses single precision floating point. */
#define FP_S 0x10000000
#define FP_S 0x01000000
/* Instruction uses double precision floating point. */
#define FP_D 0x20000000
#define FP_D 0x02000000
/* Instruction is part of the tx39's integer multiply family. */
#define INSN_MULT 0x40000000
/* Modifies the general purpose register in MICROMIPSOP_*_RS. */
#define INSN_WRITE_GPR_S 0x80000000
#define INSN_MULT 0x04000000
/* Reads general purpose register 24. */
#define INSN_READ_GPR_24 0x08000000
/* Writes to general purpose register 24. */
#define INSN_WRITE_GPR_24 0x10000000
/* A user-defined instruction. */
#define INSN_UDI 0x20000000
/* Instruction is actually a macro. It should be ignored by the
disassembler, and requires special treatment by the assembler. */
#define INSN_MACRO 0xffffffff
@ -922,62 +929,24 @@ struct mips_opcode
only be set for macros. For instructions, FP_D in pinfo carries the
same information. */
#define INSN2_M_FP_D 0x00000010
/* Modifies the general purpose register in OP_*_RZ. */
#define INSN2_WRITE_GPR_Z 0x00000020
/* Modifies the floating point register in OP_*_FZ. */
#define INSN2_WRITE_FPR_Z 0x00000040
/* Reads the general purpose register in OP_*_RZ. */
#define INSN2_READ_GPR_Z 0x00000080
/* Reads the floating point register in OP_*_FZ. */
#define INSN2_READ_FPR_Z 0x00000100
/* Reads the general purpose register in OP_*_RD. */
#define INSN2_READ_GPR_D 0x00000200
/* Instruction has a branch delay slot that requires a 16-bit instruction. */
#define INSN2_BRANCH_DELAY_16BIT 0x00000400
#define INSN2_BRANCH_DELAY_16BIT 0x00000020
/* Instruction has a branch delay slot that requires a 32-bit instruction. */
#define INSN2_BRANCH_DELAY_32BIT 0x00000800
/* Reads the floating point register in MICROMIPSOP_*_FD. */
#define INSN2_READ_FPR_D 0x00001000
/* Modifies the general purpose register in MICROMIPSOP_*_MB. */
#define INSN2_WRITE_GPR_MB 0x00002000
/* Reads the general purpose register in MICROMIPSOP_*_MC. */
#define INSN2_READ_GPR_MC 0x00004000
/* Reads/writes the general purpose register in MICROMIPSOP_*_MD. */
#define INSN2_MOD_GPR_MD 0x00008000
/* Reads the general purpose register in MICROMIPSOP_*_ME. */
#define INSN2_READ_GPR_ME 0x00010000
/* Reads/writes the general purpose register in MICROMIPSOP_*_MF. */
#define INSN2_MOD_GPR_MF 0x00020000
/* Reads the general purpose register in MICROMIPSOP_*_MG. */
#define INSN2_READ_GPR_MG 0x00040000
/* Reads the general purpose register in MICROMIPSOP_*_MJ. */
#define INSN2_READ_GPR_MJ 0x00080000
/* Modifies the general purpose register in MICROMIPSOP_*_MJ. */
#define INSN2_WRITE_GPR_MJ 0x00100000
/* Reads the general purpose register in MICROMIPSOP_*_MP. */
#define INSN2_READ_GPR_MP 0x00200000
/* Modifies the general purpose register in MICROMIPSOP_*_MP. */
#define INSN2_WRITE_GPR_MP 0x00400000
/* Reads the general purpose register in MICROMIPSOP_*_MQ. */
#define INSN2_READ_GPR_MQ 0x00800000
/* Reads/Writes the stack pointer ($29). */
#define INSN2_MOD_SP 0x01000000
#define INSN2_BRANCH_DELAY_32BIT 0x00000040
/* Writes to the stack pointer ($29). */
#define INSN2_WRITE_SP 0x00000080
/* Reads from the stack pointer ($29). */
#define INSN2_READ_SP 0x00000100
/* Reads the RA ($31) register. */
#define INSN2_READ_GPR_31 0x02000000
/* Reads the global pointer ($28). */
#define INSN2_READ_GP 0x04000000
#define INSN2_READ_GPR_31 0x00000200
/* Reads the program counter ($pc). */
#define INSN2_READ_PC 0x08000000
#define INSN2_READ_PC 0x00000400
/* Is an unconditional branch insn. */
#define INSN2_UNCOND_BRANCH 0x10000000
#define INSN2_UNCOND_BRANCH 0x00000800
/* Is a conditional branch insn. */
#define INSN2_COND_BRANCH 0x20000000
/* Modifies the general purpose registers in MICROMIPSOP_*_MH. */
#define INSN2_WRITE_GPR_MH 0x40000000
/* Reads the general purpose registers in MICROMIPSOP_*_MM/N. */
#define INSN2_READ_GPR_MMN 0x80000000
#define INSN2_COND_BRANCH 0x00001000
/* Reads from $16. This is true of the MIPS16 0x6500 nop. */
#define INSN2_READ_GPR_16 0x00002000
/* Masks used to mark instructions to indicate which MIPS ISA level
they were introduced in. INSN_ISA_MASK masks an enumeration that
@ -1633,34 +1602,6 @@ extern int bfd_mips_num_opcodes;
#define MIPS16_ALL_ARGS 0xe
#define MIPS16_ALL_STATICS 0xb
/* For the mips16, we use the same opcode table format and a few of
the same flags. However, most of the flags are different. */
/* Modifies the register in MIPS16OP_*_RX. */
#define MIPS16_INSN_WRITE_X 0x00000001
/* Modifies the register in MIPS16OP_*_RY. */
#define MIPS16_INSN_WRITE_Y 0x00000002
/* Modifies the register in MIPS16OP_*_RZ. */
#define MIPS16_INSN_WRITE_Z 0x00000004
/* Modifies the T ($24) register. */
#define MIPS16_INSN_WRITE_T 0x00000008
/* Modifies the RA ($31) register. */
#define MIPS16_INSN_WRITE_31 0x00000020
/* Modifies the general purpose register in MIPS16OP_*_REG32R. */
#define MIPS16_INSN_WRITE_GPR_Y 0x00000040
/* Reads the register in MIPS16OP_*_RX. */
#define MIPS16_INSN_READ_X 0x00000080
/* Reads the register in MIPS16OP_*_RY. */
#define MIPS16_INSN_READ_Y 0x00000100
/* Reads the register in MIPS16OP_*_MOVE32Z. */
#define MIPS16_INSN_READ_Z 0x00000200
/* Reads the T ($24) register. */
#define MIPS16_INSN_READ_T 0x00000400
/* Reads the SP ($29) register. */
#define MIPS16_INSN_READ_SP 0x00000800
/* Reads the general purpose register in MIPS16OP_*_REGR32. */
#define MIPS16_INSN_READ_GPR_X 0x00004000
/* The following flags have the same value for the mips16 opcode
table:

View File

@ -1,3 +1,33 @@
2013-08-01 Richard Sandiford <rdsandiford@googlemail.com>
* mips-opc.c (WR_1, WR_2, RD_1, RD_2, RD_3, RD_4, MOD_1, MOD_2, UDI):
New macros.
(WR_d, WR_t, WR_D, WR_T, WR_S, RD_s, RD_b, RD_t, RD_S, RD_T, RD_R)
(WR_z, WR_Z, RD_z, RD_Z, RD_d): Delete.
(mips_builtin_opcodes): Use the new position-based read-write flags
instead of field-based ones. Use UDI for "udi..." instructions.
* mips16-opc.c (WR_1, WR_2, RD_1, RD_2, RD_3, RD_4, MOD_1, MOD_2):
New macros.
(WR_x, WR_y, WR_z, WR_Y, RD_x, RD_y, RD_Z, RD_X): Delete.
(RD_T, WR_T, WR_31): Redefine using generic INSN_* flags.
(WR_SP, RD_16): New macros.
(RD_SP): Redefine as an INSN2_* flag.
(MOD_SP): Redefine in terms of RD_SP and WR_SP.
(mips16_opcodes): Use the new position-based read-write flags
instead of field-based ones. Use RD_16 for "nop". Move RD_SP to
pinfo2 field.
* micromips-opc.c (WR_1, WR_2, RD_1, RD_2, RD_3, RD_4, MOD_1, MOD_2):
New macros.
(WR_mb, RD_mc, RD_md, WR_md, RD_me, RD_mf, WR_mf, RD_mg, WR_mh, RD_mj)
(WR_mj, RD_ml, RD_mmn, RD_mp, WR_mp, RD_mq, RD_gp, WR_d, WR_t, WR_D)
(WR_T, WR_S, RD_s, RD_b, RD_t, RD_T, RD_S, RD_R, RD_D): Delete.
(RD_sp, WR_sp): Redefine to INSN2_READ_SP and INSN2_WRITE_SP.
(micromips_opcodes): Use the new position-based read-write flags
instead of field-based ones.
* mips-dis.c (print_insn_arg): Use mips_decode_reg_operand.
(print_insn_mips, print_insn_micromips): Use INSN_WRITE_1 instead
of field-based flags.
2013-08-01 Richard Sandiford <rdsandiford@googlemail.com>
* mips16-opc.c (UBR, CBR, RD_31, RD_PC): Redefine as INSN2_* flags.

File diff suppressed because it is too large Load Diff

View File

@ -1003,8 +1003,7 @@ print_insn_arg (struct disassemble_info *info,
const struct mips_reg_operand *reg_op;
reg_op = (const struct mips_reg_operand *) operand;
if (reg_op->reg_map)
uval = reg_op->reg_map[uval];
uval = mips_decode_reg_operand (reg_op, uval);
print_reg (info, opcode, reg_op->reg_type, uval);
state->last_reg_type = reg_op->reg_type;
@ -1346,8 +1345,7 @@ print_insn_mips (bfd_vma memaddr,
/* Figure out instruction type and branch delay information. */
if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
{
if ((op->pinfo & (INSN_WRITE_GPR_31
| INSN_WRITE_GPR_D)) != 0)
if ((op->pinfo & (INSN_WRITE_GPR_31 | INSN_WRITE_1)) != 0)
info->insn_type = dis_jsr;
else
info->insn_type = dis_branch;
@ -1894,7 +1892,7 @@ print_insn_micromips (bfd_vma memaddr, struct disassemble_info *info)
if (((op->pinfo & INSN_UNCOND_BRANCH_DELAY)
| (op->pinfo2 & INSN2_UNCOND_BRANCH)) != 0)
{
if ((op->pinfo & (INSN_WRITE_GPR_31 | INSN_WRITE_GPR_T)) != 0)
if ((op->pinfo & (INSN_WRITE_GPR_31 | INSN_WRITE_1)) != 0)
info->insn_type = dis_jsr;
else
info->insn_type = dis_branch;

File diff suppressed because it is too large Load Diff

View File

@ -144,19 +144,18 @@ decode_mips16_operand (char type, bfd_boolean extended_p)
#define UBD INSN_UNCOND_BRANCH_DELAY
#define WR_x MIPS16_INSN_WRITE_X
#define WR_y MIPS16_INSN_WRITE_Y
#define WR_z MIPS16_INSN_WRITE_Z
#define WR_T MIPS16_INSN_WRITE_T
#define WR_31 MIPS16_INSN_WRITE_31
#define WR_Y MIPS16_INSN_WRITE_GPR_Y
#define WR_1 INSN_WRITE_1
#define WR_2 INSN_WRITE_2
#define RD_1 INSN_READ_1
#define RD_2 INSN_READ_2
#define RD_3 INSN_READ_3
#define RD_4 INSN_READ_4
#define MOD_1 (WR_1|RD_1)
#define MOD_2 (WR_2|RD_2)
#define RD_x MIPS16_INSN_READ_X
#define RD_y MIPS16_INSN_READ_Y
#define RD_Z MIPS16_INSN_READ_Z
#define RD_T MIPS16_INSN_READ_T
#define RD_SP MIPS16_INSN_READ_SP
#define RD_X MIPS16_INSN_READ_GPR_X
#define RD_T INSN_READ_GPR_24
#define WR_T INSN_WRITE_GPR_24
#define WR_31 INSN_WRITE_GPR_31
#define WR_HI INSN_WRITE_HI
#define WR_LO INSN_WRITE_LO
@ -166,7 +165,10 @@ decode_mips16_operand (char type, bfd_boolean extended_p)
#define NODS INSN_NO_DELAY_SLOT
#define TRAP INSN_NO_DELAY_SLOT
#define MOD_SP INSN2_MOD_SP
#define RD_16 INSN2_READ_GPR_16
#define RD_SP INSN2_READ_SP
#define WR_SP INSN2_WRITE_SP
#define MOD_SP (RD_SP|WR_SP)
#define RD_31 INSN2_READ_GPR_31
#define RD_PC INSN2_READ_PC
#define UBR INSN2_UNCOND_BRANCH
@ -181,27 +183,27 @@ decode_mips16_operand (char type, bfd_boolean extended_p)
const struct mips_opcode mips16_opcodes[] =
{
/* name, args, match, mask, pinfo, pinfo2, membership */
{"nop", "", 0x6500, 0xffff, RD_Z, 0, I1, 0, 0 }, /* move $0,$Z */
{"la", "x,A", 0x0800, 0xf800, WR_x, RD_PC, I1, 0, 0 },
{"nop", "", 0x6500, 0xffff, 0, RD_16, I1, 0, 0 }, /* move $0,$Z */
{"la", "x,A", 0x0800, 0xf800, WR_1, RD_PC, I1, 0, 0 },
{"abs", "x,w", 0, (int) M_ABS, INSN_MACRO, 0, I1, 0, 0 },
{"addiu", "y,x,4", 0x4000, 0xf810, WR_y|RD_x, 0, I1, 0, 0 },
{"addiu", "x,k", 0x4800, 0xf800, WR_x|RD_x, 0, I1, 0, 0 },
{"addiu", "y,x,4", 0x4000, 0xf810, WR_1|RD_2, 0, I1, 0, 0 },
{"addiu", "x,k", 0x4800, 0xf800, MOD_1, 0, I1, 0, 0 },
{"addiu", "S,K", 0x6300, 0xff00, 0, MOD_SP, I1, 0, 0 },
{"addiu", "S,S,K", 0x6300, 0xff00, 0, MOD_SP, I1, 0, 0 },
{"addiu", "x,P,V", 0x0800, 0xf800, WR_x, RD_PC, I1, 0, 0 },
{"addiu", "x,S,V", 0x0000, 0xf800, WR_x|RD_SP, 0, I1, 0, 0 },
{"addu", "z,v,y", 0xe001, 0xf803, WR_z|RD_x|RD_y, 0, I1, 0, 0 },
{"addu", "y,x,4", 0x4000, 0xf810, WR_y|RD_x, 0, I1, 0, 0 },
{"addu", "x,k", 0x4800, 0xf800, WR_x|RD_x, 0, I1, 0, 0 },
{"addiu", "x,P,V", 0x0800, 0xf800, WR_1, RD_PC, I1, 0, 0 },
{"addiu", "x,S,V", 0x0000, 0xf800, WR_1, RD_SP, I1, 0, 0 },
{"addu", "z,v,y", 0xe001, 0xf803, WR_1|RD_2|RD_3, 0, I1, 0, 0 },
{"addu", "y,x,4", 0x4000, 0xf810, WR_1|RD_2, 0, I1, 0, 0 },
{"addu", "x,k", 0x4800, 0xf800, MOD_1, 0, I1, 0, 0 },
{"addu", "S,K", 0x6300, 0xff00, 0, MOD_SP, I1, 0, 0 },
{"addu", "S,S,K", 0x6300, 0xff00, 0, MOD_SP, I1, 0, 0 },
{"addu", "x,P,V", 0x0800, 0xf800, WR_x, RD_PC, I1, 0, 0 },
{"addu", "x,S,V", 0x0000, 0xf800, WR_x|RD_SP, 0, I1, 0, 0 },
{"and", "x,y", 0xe80c, 0xf81f, WR_x|RD_x|RD_y, 0, I1, 0, 0 },
{"addu", "x,P,V", 0x0800, 0xf800, WR_1, RD_PC, I1, 0, 0 },
{"addu", "x,S,V", 0x0000, 0xf800, WR_1, RD_SP, I1, 0, 0 },
{"and", "x,y", 0xe80c, 0xf81f, MOD_1|RD_2, 0, I1, 0, 0 },
{"b", "q", 0x1000, 0xf800, 0, UBR, I1, 0, 0 },
{"beq", "x,y,p", 0, (int) M_BEQ, INSN_MACRO, 0, I1, 0, 0 },
{"beq", "x,I,p", 0, (int) M_BEQ_I, INSN_MACRO, 0, I1, 0, 0 },
{"beqz", "x,p", 0x2000, 0xf800, RD_x, CBR, I1, 0, 0 },
{"beqz", "x,p", 0x2000, 0xf800, RD_1, CBR, I1, 0, 0 },
{"bge", "x,y,p", 0, (int) M_BGE, INSN_MACRO, 0, I1, 0, 0 },
{"bge", "x,I,p", 0, (int) M_BGE_I, INSN_MACRO, 0, I1, 0, 0 },
{"bgeu", "x,y,p", 0, (int) M_BGEU, INSN_MACRO, 0, I1, 0, 0 },
@ -220,52 +222,52 @@ const struct mips_opcode mips16_opcodes[] =
{"bltu", "x,I,p", 0, (int) M_BLTU_I, INSN_MACRO, 0, I1, 0, 0 },
{"bne", "x,y,p", 0, (int) M_BNE, INSN_MACRO, 0, I1, 0, 0 },
{"bne", "x,I,p", 0, (int) M_BNE_I, INSN_MACRO, 0, I1, 0, 0 },
{"bnez", "x,p", 0x2800, 0xf800, RD_x, CBR, I1, 0, 0 },
{"bnez", "x,p", 0x2800, 0xf800, RD_1, CBR, I1, 0, 0 },
{"break", "6", 0xe805, 0xf81f, TRAP, 0, I1, 0, 0 },
{"bteqz", "p", 0x6000, 0xff00, RD_T, CBR, I1, 0, 0 },
{"btnez", "p", 0x6100, 0xff00, RD_T, CBR, I1, 0, 0 },
{"cmpi", "x,U", 0x7000, 0xf800, WR_T|RD_x, 0, I1, 0, 0 },
{"cmp", "x,y", 0xe80a, 0xf81f, WR_T|RD_x|RD_y, 0, I1, 0, 0 },
{"cmp", "x,U", 0x7000, 0xf800, WR_T|RD_x, 0, I1, 0, 0 },
{"dla", "y,E", 0xfe00, 0xff00, WR_y, RD_PC, I3, 0, 0 },
{"daddiu", "y,x,4", 0x4010, 0xf810, WR_y|RD_x, 0, I3, 0, 0 },
{"daddiu", "y,j", 0xfd00, 0xff00, WR_y|RD_y, 0, I3, 0, 0 },
{"cmpi", "x,U", 0x7000, 0xf800, RD_1|WR_T, 0, I1, 0, 0 },
{"cmp", "x,y", 0xe80a, 0xf81f, RD_1|RD_2|WR_T, 0, I1, 0, 0 },
{"cmp", "x,U", 0x7000, 0xf800, RD_1|WR_T, 0, I1, 0, 0 },
{"dla", "y,E", 0xfe00, 0xff00, WR_1, RD_PC, I3, 0, 0 },
{"daddiu", "y,x,4", 0x4010, 0xf810, WR_1|RD_2, 0, I3, 0, 0 },
{"daddiu", "y,j", 0xfd00, 0xff00, MOD_1, 0, I3, 0, 0 },
{"daddiu", "S,K", 0xfb00, 0xff00, 0, MOD_SP, I3, 0, 0 },
{"daddiu", "S,S,K", 0xfb00, 0xff00, 0, MOD_SP, I3, 0, 0 },
{"daddiu", "y,P,W", 0xfe00, 0xff00, WR_y, RD_PC, I3, 0, 0 },
{"daddiu", "y,S,W", 0xff00, 0xff00, WR_y|RD_SP, 0, I3, 0, 0 },
{"daddu", "z,v,y", 0xe000, 0xf803, WR_z|RD_x|RD_y, 0, I3, 0, 0 },
{"daddu", "y,x,4", 0x4010, 0xf810, WR_y|RD_x, 0, I3, 0, 0 },
{"daddu", "y,j", 0xfd00, 0xff00, WR_y|RD_y, 0, I3, 0, 0 },
{"daddiu", "y,P,W", 0xfe00, 0xff00, WR_1, RD_PC, I3, 0, 0 },
{"daddiu", "y,S,W", 0xff00, 0xff00, WR_1, RD_SP, I3, 0, 0 },
{"daddu", "z,v,y", 0xe000, 0xf803, WR_1|RD_2|RD_3, 0, I3, 0, 0 },
{"daddu", "y,x,4", 0x4010, 0xf810, WR_1|RD_2, 0, I3, 0, 0 },
{"daddu", "y,j", 0xfd00, 0xff00, MOD_1, 0, I3, 0, 0 },
{"daddu", "S,K", 0xfb00, 0xff00, 0, MOD_SP, I3, 0, 0 },
{"daddu", "S,S,K", 0xfb00, 0xff00, 0, MOD_SP, I3, 0, 0 },
{"daddu", "y,P,W", 0xfe00, 0xff00, WR_y, RD_PC, I3, 0, 0 },
{"daddu", "y,S,W", 0xff00, 0xff00, WR_y|RD_SP, 0, I3, 0, 0 },
{"ddiv", "0,x,y", 0xe81e, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I3, 0, 0 },
{"daddu", "y,P,W", 0xfe00, 0xff00, WR_1, RD_PC, I3, 0, 0 },
{"daddu", "y,S,W", 0xff00, 0xff00, WR_1, RD_SP, I3, 0, 0 },
{"ddiv", "0,x,y", 0xe81e, 0xf81f, RD_2|RD_3|WR_HI|WR_LO, 0, I3, 0, 0 },
{"ddiv", "z,v,y", 0, (int) M_DDIV_3, INSN_MACRO, 0, I1, 0, 0 },
{"ddivu", "0,x,y", 0xe81f, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I3, 0, 0 },
{"ddivu", "0,x,y", 0xe81f, 0xf81f, RD_2|RD_3|WR_HI|WR_LO, 0, I3, 0, 0 },
{"ddivu", "z,v,y", 0, (int) M_DDIVU_3, INSN_MACRO, 0, I1, 0, 0 },
{"div", "0,x,y", 0xe81a, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I1, 0, 0 },
{"div", "0,x,y", 0xe81a, 0xf81f, RD_2|RD_3|WR_HI|WR_LO, 0, I1, 0, 0 },
{"div", "z,v,y", 0, (int) M_DIV_3, INSN_MACRO, 0, I1, 0, 0 },
{"divu", "0,x,y", 0xe81b, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I1, 0, 0 },
{"divu", "0,x,y", 0xe81b, 0xf81f, RD_2|RD_3|WR_HI|WR_LO, 0, I1, 0, 0 },
{"divu", "z,v,y", 0, (int) M_DIVU_3, INSN_MACRO, 0, I1, 0, 0 },
{"dmul", "z,v,y", 0, (int) M_DMUL, INSN_MACRO, 0, I3, 0, 0 },
{"dmult", "x,y", 0xe81c, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I3, 0, 0 },
{"dmultu", "x,y", 0xe81d, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I3, 0, 0 },
{"drem", "0,x,y", 0xe81e, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I3, 0, 0 },
{"dmult", "x,y", 0xe81c, 0xf81f, RD_1|RD_2|WR_HI|WR_LO, 0, I3, 0, 0 },
{"dmultu", "x,y", 0xe81d, 0xf81f, RD_1|RD_2|WR_HI|WR_LO, 0, I3, 0, 0 },
{"drem", "0,x,y", 0xe81e, 0xf81f, RD_2|RD_3|WR_HI|WR_LO, 0, I3, 0, 0 },
{"drem", "z,v,y", 0, (int) M_DREM_3, INSN_MACRO, 0, I1, 0, 0 },
{"dremu", "0,x,y", 0xe81f, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I3, 0, 0 },
{"dremu", "0,x,y", 0xe81f, 0xf81f, RD_2|RD_3|WR_HI|WR_LO, 0, I3, 0, 0 },
{"dremu", "z,v,y", 0, (int) M_DREMU_3, INSN_MACRO, 0, I1, 0, 0 },
{"dsllv", "y,x", 0xe814, 0xf81f, WR_y|RD_y|RD_x, 0, I3, 0, 0 },
{"dsll", "x,w,[", 0x3001, 0xf803, WR_x|RD_y, 0, I3, 0, 0 },
{"dsll", "y,x", 0xe814, 0xf81f, WR_y|RD_y|RD_x, 0, I3, 0, 0 },
{"dsrav", "y,x", 0xe817, 0xf81f, WR_y|RD_y|RD_x, 0, I3, 0, 0 },
{"dsra", "y,]", 0xe813, 0xf81f, WR_y|RD_y, 0, I3, 0, 0 },
{"dsra", "y,x", 0xe817, 0xf81f, WR_y|RD_y|RD_x, 0, I3, 0, 0 },
{"dsrlv", "y,x", 0xe816, 0xf81f, WR_y|RD_y|RD_x, 0, I3, 0, 0 },
{"dsrl", "y,]", 0xe808, 0xf81f, WR_y|RD_y, 0, I3, 0, 0 },
{"dsrl", "y,x", 0xe816, 0xf81f, WR_y|RD_y|RD_x, 0, I3, 0, 0 },
{"dsubu", "z,v,y", 0xe002, 0xf803, WR_z|RD_x|RD_y, 0, I3, 0, 0 },
{"dsllv", "y,x", 0xe814, 0xf81f, MOD_1|RD_2, 0, I3, 0, 0 },
{"dsll", "x,w,[", 0x3001, 0xf803, WR_1|RD_2, 0, I3, 0, 0 },
{"dsll", "y,x", 0xe814, 0xf81f, MOD_1|RD_2, 0, I3, 0, 0 },
{"dsrav", "y,x", 0xe817, 0xf81f, MOD_1|RD_2, 0, I3, 0, 0 },
{"dsra", "y,]", 0xe813, 0xf81f, MOD_1, 0, I3, 0, 0 },
{"dsra", "y,x", 0xe817, 0xf81f, MOD_1|RD_2, 0, I3, 0, 0 },
{"dsrlv", "y,x", 0xe816, 0xf81f, MOD_1|RD_2, 0, I3, 0, 0 },
{"dsrl", "y,]", 0xe808, 0xf81f, MOD_1, 0, I3, 0, 0 },
{"dsrl", "y,x", 0xe816, 0xf81f, MOD_1|RD_2, 0, I3, 0, 0 },
{"dsubu", "z,v,y", 0xe002, 0xf803, WR_1|RD_2|RD_3, 0, I3, 0, 0 },
{"dsubu", "y,x,I", 0, (int) M_DSUBU_I, INSN_MACRO, 0, I1, 0, 0 },
{"dsubu", "y,I", 0, (int) M_DSUBU_I_2, INSN_MACRO, 0, I1, 0, 0 },
{"exit", "L", 0xed09, 0xff1f, TRAP, 0, I1, 0, 0 },
@ -275,88 +277,88 @@ const struct mips_opcode mips16_opcodes[] =
{"entry", "", 0xe809, 0xffff, TRAP, 0, I1, 0, 0 },
{"entry", "l", 0xe809, 0xf81f, TRAP, 0, I1, 0, 0 },
{"extend", "e", 0xf000, 0xf800, 0, 0, I1, 0, 0 },
{"jalr", "x", 0xe840, 0xf8ff, UBD|WR_31|RD_x, 0, I1, 0, 0 },
{"jalr", "R,x", 0xe840, 0xf8ff, UBD|WR_31|RD_x, 0, I1, 0, 0 },
{"jal", "x", 0xe840, 0xf8ff, UBD|WR_31|RD_x, 0, I1, 0, 0 },
{"jal", "R,x", 0xe840, 0xf8ff, UBD|WR_31|RD_x, 0, I1, 0, 0 },
{"jal", "a", 0x1800, 0xfc00, UBD|WR_31, 0, I1, 0, 0 },
{"jalx", "i", 0x1c00, 0xfc00, UBD|WR_31, 0, I1, 0, 0 },
{"jr", "x", 0xe800, 0xf8ff, UBD|RD_x, 0, I1, 0, 0 },
{"jalr", "x", 0xe840, 0xf8ff, RD_1|WR_31|UBD, 0, I1, 0, 0 },
{"jalr", "R,x", 0xe840, 0xf8ff, RD_2|WR_31|UBD, 0, I1, 0, 0 },
{"jal", "x", 0xe840, 0xf8ff, RD_1|WR_31|UBD, 0, I1, 0, 0 },
{"jal", "R,x", 0xe840, 0xf8ff, RD_2|WR_31|UBD, 0, I1, 0, 0 },
{"jal", "a", 0x1800, 0xfc00, WR_31|UBD, 0, I1, 0, 0 },
{"jalx", "i", 0x1c00, 0xfc00, WR_31|UBD, 0, I1, 0, 0 },
{"jr", "x", 0xe800, 0xf8ff, RD_1|UBD, 0, I1, 0, 0 },
{"jr", "R", 0xe820, 0xffff, UBD, RD_31, I1, 0, 0 },
{"j", "x", 0xe800, 0xf8ff, UBD|RD_x, 0, I1, 0, 0 },
{"j", "x", 0xe800, 0xf8ff, RD_1|UBD, 0, I1, 0, 0 },
{"j", "R", 0xe820, 0xffff, UBD, RD_31, I1, 0, 0 },
/* MIPS16e compact branches. We keep them near the ordinary branches
so that we easily find them when converting a normal branch to a
compact one. */
{"jalrc", "x", 0xe8c0, 0xf8ff, WR_31|RD_x|NODS, UBR, I32, 0, 0 },
{"jalrc", "R,x", 0xe8c0, 0xf8ff, WR_31|RD_x|NODS, UBR, I32, 0, 0 },
{"jrc", "x", 0xe880, 0xf8ff, RD_x|NODS, UBR, I32, 0, 0 },
{"jrc", "R", 0xe8a0, 0xffff, NODS, UBR|RD_31, I32, 0, 0 },
{"lb", "y,5(x)", 0x8000, 0xf800, WR_y|RD_x, 0, I1, 0, 0 },
{"lbu", "y,5(x)", 0xa000, 0xf800, WR_y|RD_x, 0, I1, 0, 0 },
{"ld", "y,D(x)", 0x3800, 0xf800, WR_y|RD_x, 0, I3, 0, 0 },
{"ld", "y,B", 0xfc00, 0xff00, WR_y, RD_PC, I3, 0, 0 },
{"ld", "y,D(P)", 0xfc00, 0xff00, WR_y, RD_PC, I3, 0, 0 },
{"ld", "y,D(S)", 0xf800, 0xff00, WR_y|RD_SP, 0, I3, 0, 0 },
{"lh", "y,H(x)", 0x8800, 0xf800, WR_y|RD_x, 0, I1, 0, 0 },
{"lhu", "y,H(x)", 0xa800, 0xf800, WR_y|RD_x, 0, I1, 0, 0 },
{"li", "x,U", 0x6800, 0xf800, WR_x, 0, I1, 0, 0 },
{"lw", "y,W(x)", 0x9800, 0xf800, WR_y|RD_x, 0, I1, 0, 0 },
{"lw", "x,A", 0xb000, 0xf800, WR_x, RD_PC, I1, 0, 0 },
{"lw", "x,V(P)", 0xb000, 0xf800, WR_x, RD_PC, I1, 0, 0 },
{"lw", "x,V(S)", 0x9000, 0xf800, WR_x|RD_SP, 0, I1, 0, 0 },
{"lwu", "y,W(x)", 0xb800, 0xf800, WR_y|RD_x, 0, I3, 0, 0 },
{"mfhi", "x", 0xe810, 0xf8ff, WR_x|RD_HI, 0, I1, 0, 0 },
{"mflo", "x", 0xe812, 0xf8ff, WR_x|RD_LO, 0, I1, 0, 0 },
{"move", "y,X", 0x6700, 0xff00, WR_y|RD_X, 0, I1, 0, 0 },
{"move", "Y,Z", 0x6500, 0xff00, WR_Y|RD_Z, 0, I1, 0, 0 },
{"jalrc", "x", 0xe8c0, 0xf8ff, RD_1|WR_31|NODS, UBR, I32, 0, 0 },
{"jalrc", "R,x", 0xe8c0, 0xf8ff, RD_2|WR_31|NODS, UBR, I32, 0, 0 },
{"jrc", "x", 0xe880, 0xf8ff, RD_1|NODS, UBR, I32, 0, 0 },
{"jrc", "R", 0xe8a0, 0xffff, NODS, RD_31|UBR, I32, 0, 0 },
{"lb", "y,5(x)", 0x8000, 0xf800, WR_1|RD_3, 0, I1, 0, 0 },
{"lbu", "y,5(x)", 0xa000, 0xf800, WR_1|RD_3, 0, I1, 0, 0 },
{"ld", "y,D(x)", 0x3800, 0xf800, WR_1|RD_3, 0, I3, 0, 0 },
{"ld", "y,B", 0xfc00, 0xff00, WR_1, RD_PC, I3, 0, 0 },
{"ld", "y,D(P)", 0xfc00, 0xff00, WR_1, RD_PC, I3, 0, 0 },
{"ld", "y,D(S)", 0xf800, 0xff00, WR_1, RD_SP, I3, 0, 0 },
{"lh", "y,H(x)", 0x8800, 0xf800, WR_1|RD_3, 0, I1, 0, 0 },
{"lhu", "y,H(x)", 0xa800, 0xf800, WR_1|RD_3, 0, I1, 0, 0 },
{"li", "x,U", 0x6800, 0xf800, WR_1, 0, I1, 0, 0 },
{"lw", "y,W(x)", 0x9800, 0xf800, WR_1|RD_3, 0, I1, 0, 0 },
{"lw", "x,A", 0xb000, 0xf800, WR_1, RD_PC, I1, 0, 0 },
{"lw", "x,V(P)", 0xb000, 0xf800, WR_1, RD_PC, I1, 0, 0 },
{"lw", "x,V(S)", 0x9000, 0xf800, WR_1, RD_SP, I1, 0, 0 },
{"lwu", "y,W(x)", 0xb800, 0xf800, WR_1|RD_3, 0, I3, 0, 0 },
{"mfhi", "x", 0xe810, 0xf8ff, WR_1|RD_HI, 0, I1, 0, 0 },
{"mflo", "x", 0xe812, 0xf8ff, WR_1|RD_LO, 0, I1, 0, 0 },
{"move", "y,X", 0x6700, 0xff00, WR_1|RD_2, 0, I1, 0, 0 },
{"move", "Y,Z", 0x6500, 0xff00, WR_1|RD_2, 0, I1, 0, 0 },
{"mul", "z,v,y", 0, (int) M_MUL, INSN_MACRO, 0, I1, 0, 0 },
{"mult", "x,y", 0xe818, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I1, 0, 0 },
{"multu", "x,y", 0xe819, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I1, 0, 0 },
{"neg", "x,w", 0xe80b, 0xf81f, WR_x|RD_y, 0, I1, 0, 0 },
{"not", "x,w", 0xe80f, 0xf81f, WR_x|RD_y, 0, I1, 0, 0 },
{"or", "x,y", 0xe80d, 0xf81f, WR_x|RD_x|RD_y, 0, I1, 0, 0 },
{"rem", "0,x,y", 0xe81a, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I1, 0, 0 },
{"mult", "x,y", 0xe818, 0xf81f, RD_1|RD_2|WR_HI|WR_LO, 0, I1, 0, 0 },
{"multu", "x,y", 0xe819, 0xf81f, RD_1|RD_2|WR_HI|WR_LO, 0, I1, 0, 0 },
{"neg", "x,w", 0xe80b, 0xf81f, WR_1|RD_2, 0, I1, 0, 0 },
{"not", "x,w", 0xe80f, 0xf81f, WR_1|RD_2, 0, I1, 0, 0 },
{"or", "x,y", 0xe80d, 0xf81f, MOD_1|RD_2, 0, I1, 0, 0 },
{"rem", "0,x,y", 0xe81a, 0xf81f, RD_2|RD_3|WR_HI|WR_LO, 0, I1, 0, 0 },
{"rem", "z,v,y", 0, (int) M_REM_3, INSN_MACRO, 0, I1, 0, 0 },
{"remu", "0,x,y", 0xe81b, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I1, 0, 0 },
{"remu", "0,x,y", 0xe81b, 0xf81f, RD_2|RD_3|WR_HI|WR_LO, 0, I1, 0, 0 },
{"remu", "z,v,y", 0, (int) M_REMU_3, INSN_MACRO, 0, I1, 0, 0 },
{"sb", "y,5(x)", 0xc000, 0xf800, RD_y|RD_x, 0, I1, 0, 0 },
{"sd", "y,D(x)", 0x7800, 0xf800, RD_y|RD_x, 0, I3, 0, 0 },
{"sd", "y,D(S)", 0xf900, 0xff00, RD_y, RD_PC, I3, 0, 0 },
{"sd", "R,C(S)", 0xfa00, 0xff00, 0, RD_PC|RD_31, I1, 0, 0 },
{"sh", "y,H(x)", 0xc800, 0xf800, RD_y|RD_x, 0, I1, 0, 0 },
{"sllv", "y,x", 0xe804, 0xf81f, WR_y|RD_y|RD_x, 0, I1, 0, 0 },
{"sll", "x,w,<", 0x3000, 0xf803, WR_x|RD_y, 0, I1, 0, 0 },
{"sll", "y,x", 0xe804, 0xf81f, WR_y|RD_y|RD_x, 0, I1, 0, 0 },
{"slti", "x,8", 0x5000, 0xf800, WR_T|RD_x, 0, I1, 0, 0 },
{"slt", "x,y", 0xe802, 0xf81f, WR_T|RD_x|RD_y, 0, I1, 0, 0 },
{"slt", "x,8", 0x5000, 0xf800, WR_T|RD_x, 0, I1, 0, 0 },
{"sltiu", "x,8", 0x5800, 0xf800, WR_T|RD_x, 0, I1, 0, 0 },
{"sltu", "x,y", 0xe803, 0xf81f, WR_T|RD_x|RD_y, 0, I1, 0, 0 },
{"sltu", "x,8", 0x5800, 0xf800, WR_T|RD_x, 0, I1, 0, 0 },
{"srav", "y,x", 0xe807, 0xf81f, WR_y|RD_y|RD_x, 0, I1, 0, 0 },
{"sra", "x,w,<", 0x3003, 0xf803, WR_x|RD_y, 0, I1, 0, 0 },
{"sra", "y,x", 0xe807, 0xf81f, WR_y|RD_y|RD_x, 0, I1, 0, 0 },
{"srlv", "y,x", 0xe806, 0xf81f, WR_y|RD_y|RD_x, 0, I1, 0, 0 },
{"srl", "x,w,<", 0x3002, 0xf803, WR_x|RD_y, 0, I1, 0, 0 },
{"srl", "y,x", 0xe806, 0xf81f, WR_y|RD_y|RD_x, 0, I1, 0, 0 },
{"subu", "z,v,y", 0xe003, 0xf803, WR_z|RD_x|RD_y, 0, I1, 0, 0 },
{"sb", "y,5(x)", 0xc000, 0xf800, RD_1|RD_3, 0, I1, 0, 0 },
{"sd", "y,D(x)", 0x7800, 0xf800, RD_1|RD_3, 0, I3, 0, 0 },
{"sd", "y,D(S)", 0xf900, 0xff00, RD_1, RD_PC, I3, 0, 0 },
{"sd", "R,C(S)", 0xfa00, 0xff00, 0, RD_31|RD_PC, I1, 0, 0 },
{"sh", "y,H(x)", 0xc800, 0xf800, RD_1|RD_3, 0, I1, 0, 0 },
{"sllv", "y,x", 0xe804, 0xf81f, MOD_1|RD_2, 0, I1, 0, 0 },
{"sll", "x,w,<", 0x3000, 0xf803, WR_1|RD_2, 0, I1, 0, 0 },
{"sll", "y,x", 0xe804, 0xf81f, MOD_1|RD_2, 0, I1, 0, 0 },
{"slti", "x,8", 0x5000, 0xf800, RD_1|WR_T, 0, I1, 0, 0 },
{"slt", "x,y", 0xe802, 0xf81f, RD_1|RD_2|WR_T, 0, I1, 0, 0 },
{"slt", "x,8", 0x5000, 0xf800, RD_1|WR_T, 0, I1, 0, 0 },
{"sltiu", "x,8", 0x5800, 0xf800, RD_1|WR_T, 0, I1, 0, 0 },
{"sltu", "x,y", 0xe803, 0xf81f, RD_1|RD_2|WR_T, 0, I1, 0, 0 },
{"sltu", "x,8", 0x5800, 0xf800, RD_1|WR_T, 0, I1, 0, 0 },
{"srav", "y,x", 0xe807, 0xf81f, MOD_1|RD_2, 0, I1, 0, 0 },
{"sra", "x,w,<", 0x3003, 0xf803, WR_1|RD_2, 0, I1, 0, 0 },
{"sra", "y,x", 0xe807, 0xf81f, MOD_1|RD_2, 0, I1, 0, 0 },
{"srlv", "y,x", 0xe806, 0xf81f, MOD_1|RD_2, 0, I1, 0, 0 },
{"srl", "x,w,<", 0x3002, 0xf803, WR_1|RD_2, 0, I1, 0, 0 },
{"srl", "y,x", 0xe806, 0xf81f, MOD_1|RD_2, 0, I1, 0, 0 },
{"subu", "z,v,y", 0xe003, 0xf803, WR_1|RD_2|RD_3, 0, I1, 0, 0 },
{"subu", "y,x,I", 0, (int) M_SUBU_I, INSN_MACRO, 0, I1, 0, 0 },
{"subu", "x,I", 0, (int) M_SUBU_I_2, INSN_MACRO, 0, I1, 0, 0 },
{"sw", "y,W(x)", 0xd800, 0xf800, RD_y|RD_x, 0, I1, 0, 0 },
{"sw", "x,V(S)", 0xd000, 0xf800, RD_x|RD_SP, 0, I1, 0, 0 },
{"sw", "R,V(S)", 0x6200, 0xff00, RD_SP, RD_31, I1, 0, 0 },
{"xor", "x,y", 0xe80e, 0xf81f, WR_x|RD_x|RD_y, 0, I1, 0, 0 },
{"sw", "y,W(x)", 0xd800, 0xf800, RD_1|RD_3, 0, I1, 0, 0 },
{"sw", "x,V(S)", 0xd000, 0xf800, RD_1, RD_SP, I1, 0, 0 },
{"sw", "R,V(S)", 0x6200, 0xff00, 0, RD_31|RD_SP, I1, 0, 0 },
{"xor", "x,y", 0xe80e, 0xf81f, MOD_1|RD_2, 0, I1, 0, 0 },
/* MIPS16e additions */
{"restore", "M", 0x6400, 0xff80, WR_31|NODS, MOD_SP, I32, 0, 0 },
{"save", "m", 0x6480, 0xff80, NODS, MOD_SP|RD_31, I32, 0, 0 },
{"save", "m", 0x6480, 0xff80, NODS, RD_31|MOD_SP, I32, 0, 0 },
{"sdbbp", "6", 0xe801, 0xf81f, TRAP, 0, I32, 0, 0 },
{"seb", "x", 0xe891, 0xf8ff, WR_x|RD_x, 0, I32, 0, 0 },
{"seh", "x", 0xe8b1, 0xf8ff, WR_x|RD_x, 0, I32, 0, 0 },
{"sew", "x", 0xe8d1, 0xf8ff, WR_x|RD_x, 0, I64, 0, 0 },
{"zeb", "x", 0xe811, 0xf8ff, WR_x|RD_x, 0, I32, 0, 0 },
{"zeh", "x", 0xe831, 0xf8ff, WR_x|RD_x, 0, I32, 0, 0 },
{"zew", "x", 0xe851, 0xf8ff, WR_x|RD_x, 0, I64, 0, 0 },
{"seb", "x", 0xe891, 0xf8ff, MOD_1, 0, I32, 0, 0 },
{"seh", "x", 0xe8b1, 0xf8ff, MOD_1, 0, I32, 0, 0 },
{"sew", "x", 0xe8d1, 0xf8ff, MOD_1, 0, I64, 0, 0 },
{"zeb", "x", 0xe811, 0xf8ff, MOD_1, 0, I32, 0, 0 },
{"zeh", "x", 0xe831, 0xf8ff, MOD_1, 0, I32, 0, 0 },
{"zew", "x", 0xe851, 0xf8ff, MOD_1, 0, I64, 0, 0 },
};
const int bfd_mips16_num_opcodes =