but nothing is ideal around here.
*/
-static char *insn_error;
+/* Types of printf format used for instruction-related error messages.
+ "I" means int ("%d") and "S" means string ("%s"). */
+enum mips_insn_error_format {
+ ERR_FMT_PLAIN,
+ ERR_FMT_I,
+ ERR_FMT_SS,
+};
+
+/* Information about an error that was found while assembling the current
+ instruction. */
+struct mips_insn_error {
+ /* We sometimes need to match an instruction against more than one
+ opcode table entry. Errors found during this matching are reported
+ against a particular syntactic argument rather than against the
+ instruction as a whole. We grade these messages so that errors
+ against argument N have a greater priority than an error against
+ any argument < N, since the former implies that arguments up to N
+ were acceptable and that the opcode entry was therefore a closer match.
+ If several matches report an error against the same argument,
+ we only use that error if it is the same in all cases.
+
+ min_argnum is the minimum argument number for which an error message
+ should be accepted. It is 0 if MSG is against the instruction as
+ a whole. */
+ int min_argnum;
+
+ /* The printf()-style message, including its format and arguments. */
+ enum mips_insn_error_format format;
+ const char *msg;
+ union {
+ int i;
+ const char *ss[2];
+ } u;
+};
+
+/* The error that should be reported for the current instruction. */
+static struct mips_insn_error insn_error;
static int auto_align = 1;
static struct mips_cl_insn history[1 + MAX_NOPS];
/* Arrays of operands for each instruction. */
-#define MAX_OPERANDS 5
+#define MAX_OPERANDS 6
struct mips_operand_array {
const struct mips_operand *operand[MAX_OPERANDS];
};
\f
static char *expr_end;
-/* Expressions which appear in macro instructions. These are set by
- mips_ip and read by macro. */
+/* An expression in a macro instruction. This is set by mips_ip and
+ mips16_ip and when populated is always an O_constant. */
static expressionS imm_expr;
-static expressionS imm2_expr;
/* The relocatable field in an instruction and the relocs associated
with it. These variables are used for instructions like LUI and
base = mips_opts.micromips ? "microMIPS" : "MIPS";
size = ISA_HAS_64BIT_REGS (mips_opts.isa) ? 64 : 32;
if (min_rev < 0)
- as_warn (_("The %d-bit %s architecture does not support the"
+ as_warn (_("the %d-bit %s architecture does not support the"
" `%s' extension"), size, base, ase->name);
else
- as_warn (_("The `%s' extension requires %s%d revision %d or greater"),
+ as_warn (_("the `%s' extension requires %s%d revision %d or greater"),
ase->name, base, size, min_rev);
}
if ((ase->flags & FP64_ASES)
&& (warned_fp32 & ase->flags) != ase->flags)
{
warned_fp32 |= ase->flags;
- as_warn (_("The `%s' extension requires 64-bit FPRs"), ase->name);
+ as_warn (_("the `%s' extension requires 64-bit FPRs"), ase->name);
}
}
}
}
+/* Clear the error in insn_error. */
+
+static void
+clear_insn_error (void)
+{
+ memset (&insn_error, 0, sizeof (insn_error));
+}
+
+/* Possibly record error message MSG for the current instruction.
+ If the error is about a particular argument, ARGNUM is the 1-based
+ number of that argument, otherwise it is 0. FORMAT is the format
+ of MSG. Return true if MSG was used, false if the current message
+ was kept. */
+
+static bfd_boolean
+set_insn_error_format (int argnum, enum mips_insn_error_format format,
+ const char *msg)
+{
+ if (argnum == 0)
+ {
+ /* Give priority to errors against specific arguments, and to
+ the first whole-instruction message. */
+ if (insn_error.msg)
+ return FALSE;
+ }
+ else
+ {
+ /* Keep insn_error if it is against a later argument. */
+ if (argnum < insn_error.min_argnum)
+ return FALSE;
+
+ /* If both errors are against the same argument but are different,
+ give up on reporting a specific error for this argument.
+ See the comment about mips_insn_error for details. */
+ if (argnum == insn_error.min_argnum
+ && insn_error.msg
+ && strcmp (insn_error.msg, msg) != 0)
+ {
+ insn_error.msg = 0;
+ insn_error.min_argnum += 1;
+ return FALSE;
+ }
+ }
+ insn_error.min_argnum = argnum;
+ insn_error.format = format;
+ insn_error.msg = msg;
+ return TRUE;
+}
+
+/* Record an instruction error with no % format fields. ARGNUM and MSG are
+ as for set_insn_error_format. */
+
+static void
+set_insn_error (int argnum, const char *msg)
+{
+ set_insn_error_format (argnum, ERR_FMT_PLAIN, msg);
+}
+
+/* Record an instruction error with one %d field I. ARGNUM and MSG are
+ as for set_insn_error_format. */
+
+static void
+set_insn_error_i (int argnum, const char *msg, int i)
+{
+ if (set_insn_error_format (argnum, ERR_FMT_I, msg))
+ insn_error.u.i = i;
+}
+
+/* Record an instruction error with two %s fields S1 and S2. ARGNUM and MSG
+ are as for set_insn_error_format. */
+
+static void
+set_insn_error_ss (int argnum, const char *msg, const char *s1, const char *s2)
+{
+ if (set_insn_error_format (argnum, ERR_FMT_SS, msg))
+ {
+ insn_error.u.ss[0] = s1;
+ insn_error.u.ss[1] = s2;
+ }
+}
+
+/* Report the error in insn_error, which is against assembly code STR. */
+
+static void
+report_insn_error (const char *str)
+{
+ const char *msg;
+
+ msg = ACONCAT ((insn_error.msg, " `%s'", NULL));
+ switch (insn_error.format)
+ {
+ case ERR_FMT_PLAIN:
+ as_bad (msg, str);
+ break;
+
+ case ERR_FMT_I:
+ as_bad (msg, insn_error.u.i, str);
+ break;
+
+ case ERR_FMT_SS:
+ as_bad (msg, insn_error.u.ss[0], insn_error.u.ss[1], str);
+ break;
+ }
+}
+
/* Initialize vr4120_conflicts. There is a bit of duplication here:
the idea is to make it obvious at a glance that each errata is
included. */
unsigned int num;
};
-#define RTYPE_MASK 0x1ff00
-#define RTYPE_NUM 0x00100
-#define RTYPE_FPU 0x00200
-#define RTYPE_FCC 0x00400
-#define RTYPE_VEC 0x00800
-#define RTYPE_GP 0x01000
-#define RTYPE_CP0 0x02000
-#define RTYPE_PC 0x04000
-#define RTYPE_ACC 0x08000
-#define RTYPE_CCC 0x10000
-#define RNUM_MASK 0x000ff
-#define RWARN 0x80000
+#define RNUM_MASK 0x00000ff
+#define RTYPE_MASK 0x0efff00
+#define RTYPE_NUM 0x0000100
+#define RTYPE_FPU 0x0000200
+#define RTYPE_FCC 0x0000400
+#define RTYPE_VEC 0x0000800
+#define RTYPE_GP 0x0001000
+#define RTYPE_CP0 0x0002000
+#define RTYPE_PC 0x0004000
+#define RTYPE_ACC 0x0008000
+#define RTYPE_CCC 0x0010000
+#define RTYPE_VI 0x0020000
+#define RTYPE_VF 0x0040000
+#define RTYPE_R5900_I 0x0080000
+#define RTYPE_R5900_Q 0x0100000
+#define RTYPE_R5900_R 0x0200000
+#define RTYPE_R5900_ACC 0x0400000
+#define RWARN 0x8000000
#define GENERIC_REGISTER_NUMBERS \
{"$0", RTYPE_NUM | 0}, \
{"$v30", RTYPE_VEC | 30}, \
{"$v31", RTYPE_VEC | 31}
+#define R5900_I_NAMES \
+ {"$I", RTYPE_R5900_I | 0}
+
+#define R5900_Q_NAMES \
+ {"$Q", RTYPE_R5900_Q | 0}
+
+#define R5900_R_NAMES \
+ {"$R", RTYPE_R5900_R | 0}
+
+#define R5900_ACC_NAMES \
+ {"$ACC", RTYPE_R5900_ACC | 0 }
+
#define MIPS_DSP_ACCUMULATOR_NAMES \
{"$ac0", RTYPE_ACC | 0}, \
{"$ac1", RTYPE_ACC | 1}, \
MIPS16_SPECIAL_REGISTER_NAMES,
MDMX_VECTOR_REGISTER_NAMES,
+ R5900_I_NAMES,
+ R5900_Q_NAMES,
+ R5900_R_NAMES,
+ R5900_ACC_NAMES,
MIPS_DSP_ACCUMULATOR_NAMES,
{0, 0}
};
return symval;
}
-/* Return true if the string at *SPTR is a valid register name. If so,
- move *SPTR past the register and store the register's symbol value
- in *SYMVAL. This symbol value includes the register number
- (RNUM_MASK) and register type (RTYPE_MASK). */
+/* Return true if string [S, E) is a valid register name, storing its
+ symbol value in *SYMVAL_PTR if so. */
static bfd_boolean
-mips_parse_register (char **sptr, unsigned int *symval)
+mips_parse_register_1 (char *s, char *e, unsigned int *symval_ptr)
{
- symbolS *symbol;
- char *s, *e;
char save_c;
-
- /* Find end of name. */
- s = e = *sptr;
- if (is_name_beginner (*e))
- ++e;
- while (is_part_of_name (*e))
- ++e;
+ symbolS *symbol;
/* Terminate name. */
save_c = *e;
if (!symbol || S_GET_SEGMENT (symbol) != reg_section)
return FALSE;
+ *symval_ptr = S_GET_VALUE (symbol);
+ return TRUE;
+}
+
+/* Return true if the string at *SPTR is a valid register name. Allow it
+ to have a VU0-style channel suffix of the form x?y?z?w? if CHANNELS_PTR
+ is nonnull.
+
+ When returning true, move *SPTR past the register, store the
+ register's symbol value in *SYMVAL_PTR and the channel mask in
+ *CHANNELS_PTR (if nonnull). The symbol value includes the register
+ number (RNUM_MASK) and register type (RTYPE_MASK). The channel mask
+ is a 4-bit value of the form XYZW and is 0 if no suffix was given. */
+
+static bfd_boolean
+mips_parse_register (char **sptr, unsigned int *symval_ptr,
+ unsigned int *channels_ptr)
+{
+ char *s, *e, *m;
+ const char *q;
+ unsigned int channels, symval, bit;
+
+ /* Find end of name. */
+ s = e = *sptr;
+ if (is_name_beginner (*e))
+ ++e;
+ while (is_part_of_name (*e))
+ ++e;
+
+ channels = 0;
+ if (!mips_parse_register_1 (s, e, &symval))
+ {
+ if (!channels_ptr)
+ return FALSE;
+
+ /* Eat characters from the end of the string that are valid
+ channel suffixes. The preceding register must be $ACC or
+ end with a digit, so there is no ambiguity. */
+ bit = 1;
+ m = e;
+ for (q = "wzyx"; *q; q++, bit <<= 1)
+ if (m > s && m[-1] == *q)
+ {
+ --m;
+ channels |= bit;
+ }
+
+ if (channels == 0
+ || !mips_parse_register_1 (s, m, &symval)
+ || (symval & (RTYPE_VI | RTYPE_VF | RTYPE_R5900_ACC)) == 0)
+ return FALSE;
+ }
+
*sptr = e;
- *symval = S_GET_VALUE (symbol);
+ *symval_ptr = symval;
+ if (channels_ptr)
+ *channels_ptr = channels;
return TRUE;
}
{
unsigned int regno;
- if (mips_parse_register (s, ®no))
+ if (mips_parse_register (s, ®no, NULL))
{
if (types & RTYPE_VEC)
regno = mips_prefer_vec_regno (regno);
else
{
if (types & RWARN)
- as_warn (_("Unrecognized register name `%s'"), *s);
+ as_warn (_("unrecognized register name `%s'"), *s);
regno = ~0;
}
if (regnop)
return regno <= RNUM_MASK;
}
+/* Parse a VU0 "x?y?z?w?" channel mask at S and store the associated
+ mask in *CHANNELS. Return a pointer to the first unconsumed character. */
+
+static char *
+mips_parse_vu0_channels (char *s, unsigned int *channels)
+{
+ unsigned int i;
+
+ *channels = 0;
+ for (i = 0; i < 4; i++)
+ if (*s == "xyzw"[i])
+ {
+ *channels |= 1 << (3 - i);
+ ++s;
+ }
+ return s;
+}
+
/* Token types for parsed operand lists. */
enum mips_operand_token_type {
/* A plain register, e.g. $f2. */
OT_REG,
+ /* A 4-bit XYZW channel mask. */
+ OT_CHANNELS,
+
/* An element of a vector, e.g. $v0[1]. */
OT_REG_ELEMENT,
before OT_REGs. */
OT_CHAR,
+ /* A doubled character, either "--" or "++". */
+ OT_DOUBLE_CHAR,
+
/* The end of the operand list. */
OT_END
};
/* The register symbol value for an OT_REG. */
unsigned int regno;
+ /* The 4-bit channel mask for an OT_CHANNEL_SUFFIX. */
+ unsigned int channels;
+
/* The register symbol value and index for an OT_REG_ELEMENT. */
struct {
unsigned int regno;
int length;
} flt;
- /* The character represented by an OT_CHAR. */
+ /* The character represented by an OT_CHAR or OT_DOUBLE_CHAR. */
char ch;
} u;
};
mips_parse_base_start (char *s)
{
struct mips_operand_token token;
- unsigned int regno;
+ unsigned int regno, channels;
+ bfd_boolean decrement_p;
if (*s != '(')
return 0;
++s;
SKIP_SPACE_TABS (s);
- if (!mips_parse_register (&s, ®no))
+
+ /* Only match "--" as part of a base expression. In other contexts "--X"
+ is a double negative. */
+ decrement_p = (s[0] == '-' && s[1] == '-');
+ if (decrement_p)
+ {
+ s += 2;
+ SKIP_SPACE_TABS (s);
+ }
+
+ /* Allow a channel specifier because that leads to better error messages
+ than treating something like "$vf0x++" as an expression. */
+ if (!mips_parse_register (&s, ®no, &channels))
return 0;
token.u.ch = '(';
mips_add_token (&token, OT_CHAR);
+ if (decrement_p)
+ {
+ token.u.ch = '-';
+ mips_add_token (&token, OT_DOUBLE_CHAR);
+ }
+
token.u.regno = regno;
mips_add_token (&token, OT_REG);
+ if (channels)
+ {
+ token.u.channels = channels;
+ mips_add_token (&token, OT_CHANNELS);
+ }
+
+ /* For consistency, only match "++" as part of base expressions too. */
+ SKIP_SPACE_TABS (s);
+ if (s[0] == '+' && s[1] == '+')
+ {
+ s += 2;
+ token.u.ch = '+';
+ mips_add_token (&token, OT_DOUBLE_CHAR);
+ }
+
return s;
}
mips_parse_argument_token (char *s, char float_format)
{
char *end, *save_in, *err;
- unsigned int regno1, regno2;
+ unsigned int regno1, regno2, channels;
struct mips_operand_token token;
/* First look for "($reg", since we want to treat that as an
}
/* Handle tokens that start with a register. */
- if (mips_parse_register (&s, ®no1))
+ if (mips_parse_register (&s, ®no1, &channels))
{
+ if (channels)
+ {
+ /* A register and a VU0 channel suffix. */
+ token.u.regno = regno1;
+ mips_add_token (&token, OT_REG);
+
+ token.u.channels = channels;
+ mips_add_token (&token, OT_CHANNELS);
+ return s;
+ }
+
SKIP_SPACE_TABS (s);
if (*s == '-')
{
/* A register range. */
++s;
SKIP_SPACE_TABS (s);
- if (!mips_parse_register (&s, ®no2))
+ if (!mips_parse_register (&s, ®no2, NULL))
{
- insn_error = _("Invalid register range");
+ set_insn_error (0, _("invalid register range"));
return 0;
}
my_getExpression (&element, s);
if (element.X_op != O_constant)
{
- insn_error = _("Vector element must be constant");
+ set_insn_error (0, _("vector element must be constant"));
return 0;
}
s = expr_end;
SKIP_SPACE_TABS (s);
if (*s != ']')
{
- insn_error = _("Missing `]'");
+ set_insn_error (0, _("missing `]'"));
return 0;
}
++s;
input_line_pointer = save_in;
if (err && *err)
{
- insn_error = err;
+ set_insn_error (0, err);
return 0;
}
if (s != end)
}
used_bits = 0;
opno = 0;
+ if (opcode->pinfo2 & INSN2_VU0_CHANNEL_SUFFIX)
+ used_bits = mips_insert_operand (&mips_vu0_channel_mask, used_bits, -1);
for (s = opcode->args; *s; ++s)
switch (*s)
{
case ')':
break;
+ case '#':
+ s++;
+ break;
+
default:
if (!decode_operand)
operand = decode_mips16_operand (*s, FALSE);
}
gas_assert (opno < MAX_OPERANDS);
operands->operand[opno] = operand;
- if (operand)
+ if (operand && operand->type != OP_VU0_MATCH_SUFFIX)
{
- used_bits |= ((1 << operand->size) - 1) << operand->lsb;
+ used_bits = mips_insert_operand (operand, used_bits, -1);
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. */
length = micromips_insn_length (opc);
if (length != 2 && length != 4)
{
- as_bad (_("Internal error: bad microMIPS opcode (incorrect length: %u): "
+ as_bad (_("internal error: bad microMIPS opcode (incorrect length: %u): "
"%s %s"), length, opc->name, opc->args);
return 0;
}
if ((length == 2 && (major & 7) != 1 && (major & 6) != 2)
|| (length == 4 && (major & 7) != 0 && (major & 4) != 4))
{
- as_bad (_("Internal error: bad microMIPS opcode "
+ as_bad (_("internal error: bad microMIPS opcode "
"(opcode/length mismatch): %s %s"), opc->name, opc->args);
return 0;
}
}
if (! bfd_set_arch_mach (stdoutput, bfd_arch_mips, file_mips_arch))
- as_warn (_("Could not set architecture and machine"));
+ as_warn (_("could not set architecture and machine"));
op_hash = hash_new ();
fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
mips_opcodes[i].name, retval);
/* Probably a memory allocation problem? Give up now. */
- as_fatal (_("Broken assembler. No assembly attempted."));
+ as_fatal (_("broken assembler, no assembly attempted"));
}
do
{
}
if (broken)
- as_fatal (_("Broken assembler. No assembly attempted."));
+ as_fatal (_("broken assembler, no assembly attempted"));
/* We add all the general register names to the symbol table. This
helps us detect invalid uses of them. */
reg_names_o32[i].num, /* & RNUM_MASK, */
&zero_address_frag));
+ for (i = 0; i < 32; i++)
+ {
+ char regname[7];
+
+ /* R5900 VU0 floating-point register. */
+ regname[sizeof (rename) - 1] = 0;
+ snprintf (regname, sizeof (regname) - 1, "$vf%d", i);
+ symbol_table_insert (symbol_new (regname, reg_section,
+ RTYPE_VF | i, &zero_address_frag));
+
+ /* R5900 VU0 integer register. */
+ snprintf (regname, sizeof (regname) - 1, "$vi%d", i);
+ symbol_table_insert (symbol_new (regname, reg_section,
+ RTYPE_VI | i, &zero_address_frag));
+
+ }
+
obstack_init (&mips_operand_tokens);
mips_no_prev_insn ();
= {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
imm_expr.X_op = O_absent;
- imm2_expr.X_op = O_absent;
offset_expr.X_op = O_absent;
offset_reloc[0] = BFD_RELOC_UNUSED;
offset_reloc[1] = BFD_RELOC_UNUSED;
mips_mark_labels ();
mips_assembling_insn = TRUE;
+ clear_insn_error ();
if (mips_opts.mips16)
mips16_ip (str, &insn);
str, insn.insn_opcode));
}
- if (insn_error)
- as_bad ("%s `%s'", insn_error, str);
+ if (insn_error.msg)
+ report_insn_error (str);
else if (insn.insn_mo->pinfo == INSN_MACRO)
{
macro_start ();
case OP_REPEAT_DEST_REG:
case OP_REPEAT_PREV_REG:
case OP_PC:
+ case OP_VU0_SUFFIX:
+ case OP_VU0_MATCH_SUFFIX:
abort ();
case OP_REG:
+ case OP_OPTIONAL_REG:
{
const struct mips_reg_operand *reg_op;
return FALSE;
}
-/* Report that user-supplied argument ARGNUM for INSN was VAL, but should
- have been in the range [MIN_VAL, MAX_VAL]. PRINT_HEX says whether
- this operand is normally printed in hex or decimal. */
-
-static void
-report_bad_range (struct mips_cl_insn *insn, int argnum,
- offsetT val, int min_val, int max_val,
- bfd_boolean print_hex)
-{
- if (print_hex && val >= 0)
- as_bad (_("Operand %d of `%s' must be in the range [0x%x, 0x%x],"
- " was 0x%lx."),
- argnum, insn->insn_mo->name, min_val, max_val, (unsigned long) val);
- else if (print_hex)
- as_bad (_("Operand %d of `%s' must be in the range [0x%x, 0x%x],"
- " was %ld."),
- argnum, insn->insn_mo->name, min_val, max_val, (unsigned long) val);
- else
- as_bad (_("Operand %d of `%s' must be in the range [%d, %d],"
- " was %ld."),
- argnum, insn->insn_mo->name, min_val, max_val, (unsigned long) val);
-}
-
-/* Report an invalid combination of position and size operands for a bitfield
- operation. POS and SIZE are the values that were given. */
-
-static void
-report_bad_field (offsetT pos, offsetT size)
-{
- as_bad (_("Invalid field specification (position %ld, size %ld)"),
- (unsigned long) pos, (unsigned long) size);
-}
-
/* Information about an instruction argument that we're trying to match. */
struct mips_arg_info
{
where it gives the lsb position. */
unsigned int last_op_int;
- /* If true, match routines should silently reject invalid arguments.
- If false, match routines can accept invalid arguments as long as
- they report an appropriate error. They still have the option of
- silently rejecting arguments, in which case a generic "Invalid operands"
- style of error will be used instead. */
- bfd_boolean soft_match;
-
- /* If true, the OP_INT match routine should treat plain symbolic operands
- as if a relocation operator like %lo(...) had been used. This is only
- ever true if the operand can be relocated. */
- bfd_boolean allow_nonconst;
-
- /* 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;
+ /* If true, match routines should assume that no later instruction
+ alternative matches and should therefore be as accomodating as
+ possible. Match routines should not report errors if something
+ is only invalid for !LAX_MATCH. */
+ bfd_boolean lax_match;
/* True if a reference to the current AT register was seen. */
bfd_boolean seen_at;
};
+/* Record that the argument is out of range. */
+
+static void
+match_out_of_range (struct mips_arg_info *arg)
+{
+ set_insn_error_i (arg->argnum, _("operand %d out of range"), arg->argnum);
+}
+
+/* Record that the argument isn't constant but needs to be. */
+
+static void
+match_not_constant (struct mips_arg_info *arg)
+{
+ set_insn_error_i (arg->argnum, _("operand %d must be constant"),
+ arg->argnum);
+}
+
/* Try to match an OT_CHAR token for character CH. Consume the token
and return true on success, otherwise return false. */
match_expression (struct mips_arg_info *arg, expressionS *value,
bfd_reloc_code_real_type *r)
{
- if (arg->token->type == OT_INTEGER)
+ /* If the next token is a '(' that was parsed as being part of a base
+ expression, assume we have an elided offset. The later match will fail
+ if this turns out to be wrong. */
+ if (arg->token->type == OT_CHAR && arg->token->u.ch == '(')
{
- *value = arg->token->u.integer.value;
- memcpy (r, arg->token->u.integer.relocs, 3 * sizeof (*r));
- ++arg->token;
+ value->X_op = O_constant;
+ value->X_add_number = 0;
+ r[0] = r[1] = r[2] = BFD_RELOC_UNUSED;
return TRUE;
}
- /* Error-reporting is more consistent if we treat registers as O_register
- rather than rejecting them outright. "$1", "($1)" and "(($1))" are
- then handled in the same way. */
- if (arg->token->type == OT_REG)
+ /* Reject register-based expressions such as "0+$2" and "(($2))".
+ For plain registers the default error seems more appropriate. */
+ if (arg->token->type == OT_INTEGER
+ && arg->token->u.integer.value.X_op == O_register)
{
- value->X_add_number = arg->token->u.regno;
- ++arg->token;
+ set_insn_error (arg->argnum, _("register value used as expression"));
+ return FALSE;
}
- else if (arg->token[0].type == OT_CHAR
- && arg->token[0].u.ch == '('
- && arg->token[1].type == OT_REG
- && arg->token[2].type == OT_CHAR
- && arg->token[2].u.ch == ')')
+
+ if (arg->token->type == OT_INTEGER)
{
- value->X_add_number = arg->token[1].u.regno;
- arg->token += 3;
+ *value = arg->token->u.integer.value;
+ memcpy (r, arg->token->u.integer.relocs, 3 * sizeof (*r));
+ ++arg->token;
+ return TRUE;
}
- else
- return FALSE;
- value->X_op = O_register;
- r[0] = r[1] = r[2] = BFD_RELOC_UNUSED;
- return TRUE;
+ set_insn_error_i
+ (arg->argnum, _("operand %d must be an immediate expression"),
+ arg->argnum);
+ return FALSE;
}
/* Try to get a constant expression from the next tokens in ARG. Consume
error. */
static bfd_boolean
-match_const_int (struct mips_arg_info *arg, offsetT *value, offsetT fallback)
+match_const_int (struct mips_arg_info *arg, offsetT *value)
{
expressionS ex;
bfd_reloc_code_real_type r[3];
*value = ex.X_add_number;
else
{
- if (arg->soft_match)
- return FALSE;
- as_bad (_("Operand %d of `%s' must be constant"),
- arg->argnum, arg->insn->insn_mo->name);
- *value = fallback;
+ match_not_constant (arg);
+ return FALSE;
}
return TRUE;
}
case OP_REG_HW:
return RTYPE_NUM;
+
+ case OP_REG_VI:
+ return RTYPE_NUM | RTYPE_VI;
+
+ case OP_REG_VF:
+ return RTYPE_NUM | RTYPE_VF;
+
+ case OP_REG_R5900_I:
+ return RTYPE_R5900_I;
+
+ case OP_REG_R5900_Q:
+ return RTYPE_R5900_Q;
+
+ case OP_REG_R5900_R:
+ return RTYPE_R5900_R;
+
+ case OP_REG_R5900_ACC:
+ return RTYPE_R5900_ACC;
}
abort ();
}
&& (regno & 1) != 0
&& HAVE_32BIT_FPRS
&& !mips_oddfpreg_ok (arg->insn->insn_mo, arg->opnum))
- as_warn (_("Float register should be even, was %d"), regno);
+ as_warn (_("float register should be even, was %d"), regno);
if (type == OP_REG_CCC)
{
if ((regno & 1) != 0
&& ((length >= 3 && strcmp (name + length - 3, ".ps") == 0)
|| (length >= 5 && strncmp (name + length - 5, "any2", 4) == 0)))
- as_warn (_("Condition code register should be even for %s, was %d"),
+ as_warn (_("condition code register should be even for %s, was %d"),
name, regno);
if ((regno & 3) != 0
&& (length >= 5 && strncmp (name + length - 5, "any4", 4) == 0))
- as_warn (_("Condition code register should be 0 or 4 for %s, was %d"),
+ as_warn (_("condition code register should be 0 or 4 for %s, was %d"),
name, regno);
}
}
unsigned int uval;
int min_val, max_val, factor;
offsetT sval;
- bfd_boolean print_hex;
operand = (const struct mips_int_operand *) operand_base;
factor = 1 << operand->shift;
min_val = mips_int_operand_min (operand);
max_val = mips_int_operand_max (operand);
- if (arg->lax_max)
- max_val = ((1 << operand_base->size) - 1) << operand->shift;
- if (arg->token->type == OT_CHAR && arg->token->u.ch == '(')
- /* Assume we have an elided offset. The later match will fail
- if this turns out to be wrong. */
- sval = 0;
- else if (operand_base->lsb == 0
- && operand_base->size == 16
- && operand->shift == 0
- && operand->bias == 0
- && (operand->max_val == 32767 || operand->max_val == 65535))
+ if (operand_base->lsb == 0
+ && operand_base->size == 16
+ && operand->shift == 0
+ && operand->bias == 0
+ && (operand->max_val == 32767 || operand->max_val == 65535))
{
/* The operand can be relocated. */
if (!match_expression (arg, &offset_expr, offset_reloc))
if (offset_expr.X_op != O_constant)
{
- /* If non-constant operands are allowed then leave them for
- the caller to process, otherwise fail the match. */
- if (!arg->allow_nonconst)
+ /* Accept non-constant operands if no later alternative matches,
+ leaving it for the caller to process. */
+ if (!arg->lax_match)
return FALSE;
offset_reloc[0] = BFD_RELOC_LO16;
return TRUE;
ourselves. */
sval = offset_expr.X_add_number;
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
{
- if (!match_const_int (arg, &sval, min_val))
+ if (!match_const_int (arg, &sval))
return FALSE;
}
arg->last_op_int = sval;
- /* Check the range. If there's a problem, record the lowest acceptable
- value in arg->last_op_int in order to prevent an unhelpful error
- from OP_MSB too.
-
- Bit counts have traditionally been printed in hex by the disassembler
- but printed as decimal in error messages. Only resort to hex if
- the operand is bigger than 6 bits. */
- print_hex = operand->print_hex && operand_base->size > 6;
- if (sval < min_val || sval > max_val)
- {
- if (arg->soft_match)
- return FALSE;
- report_bad_range (arg->insn, arg->argnum, sval, min_val, max_val,
- print_hex);
- arg->last_op_int = min_val;
- }
- else if (sval % factor)
+ if (sval < min_val || sval > max_val || sval % factor)
{
- if (arg->soft_match)
- return FALSE;
- as_bad (print_hex && sval >= 0
- ? _("Operand %d of `%s' must be a factor of %d, was 0x%lx.")
- : _("Operand %d of `%s' must be a factor of %d, was %ld."),
- arg->argnum, arg->insn->insn_mo->name, factor,
- (unsigned long) sval);
- arg->last_op_int = min_val;
+ match_out_of_range (arg);
+ return FALSE;
}
uval = (unsigned int) sval >> operand->shift;
offsetT sval;
operand = (const struct mips_mapped_int_operand *) operand_base;
- if (!match_const_int (arg, &sval, operand->int_map[0]))
+ if (!match_const_int (arg, &sval))
return FALSE;
num_vals = 1 << operand_base->size;
if (operand->int_map[uval] == sval)
break;
if (uval == num_vals)
- return FALSE;
+ {
+ match_out_of_range (arg);
+ return FALSE;
+ }
insn_insert_operand (arg->insn, operand_base, uval);
return TRUE;
max_val = min_val + (1 << operand_base->size) - 1;
max_high = operand->opsize;
- if (!match_const_int (arg, &size, 1))
+ if (!match_const_int (arg, &size))
return FALSE;
high = size + arg->last_op_int;
if (size < 0 || high > max_high || sval < min_val || sval > max_val)
{
- if (arg->soft_match)
- return FALSE;
- report_bad_field (arg->last_op_int, size);
- sval = min_val;
+ match_out_of_range (arg);
+ return FALSE;
}
insn_insert_operand (arg->insn, operand_base, sval - min_val);
return TRUE;
{
offsetT sval;
- if (!match_const_int (arg, &sval, 0))
+ if (!match_const_int (arg, &sval))
return FALSE;
if (sval != 0
&& (strcmp (arg->insn->insn_mo->name, "mfps") == 0
|| strcmp (arg->insn->insn_mo->name, "mtps") == 0))))
{
- if (arg->soft_match)
- return FALSE;
- as_bad (_("Invalid performance register (%ld)"), (unsigned long) sval);
+ set_insn_error (arg->argnum, _("invalid performance register"));
+ return FALSE;
}
insn_insert_operand (arg->insn, operand, sval);
offsetT sval;
unsigned int uval;
- if (!match_const_int (arg, &sval, -256))
+ if (!match_const_int (arg, &sval))
return FALSE;
if (sval % 4)
- return FALSE;
+ {
+ match_out_of_range (arg);
+ return FALSE;
+ }
sval /= 4;
if (!(sval >= -258 && sval <= 257) || (sval >= -2 && sval <= 1))
- return FALSE;
+ {
+ match_out_of_range (arg);
+ return FALSE;
+ }
uval = (unsigned int) sval;
uval = ((uval >> 1) & ~0xff) | (uval & 0xff);
unsigned int opcode, args, statics, sregs;
unsigned int num_frame_sizes, num_args, num_statics, num_sregs;
offsetT frame_size;
- const char *error;
- error = 0;
opcode = arg->insn->insn_opcode;
frame_size = 0;
num_frame_sizes = 0;
if (arg->token->type == OT_INTEGER)
{
/* Handle the frame size. */
- if (!match_const_int (arg, &frame_size, 0))
+ if (!match_const_int (arg, &frame_size))
return FALSE;
num_frame_sizes += 1;
}
/* Encode frame size. */
if (num_frame_sizes == 0)
- error = _("Missing frame size");
- else if (num_frame_sizes > 1)
- error = _("Frame size specified twice");
- else if ((frame_size & 7) != 0 || frame_size < 0 || frame_size > 0xff * 8)
- error = _("Invalid frame size");
- else if (frame_size != 128 || (opcode >> 16) != 0)
+ {
+ set_insn_error (arg->argnum, _("missing frame size"));
+ return FALSE;
+ }
+ if (num_frame_sizes > 1)
+ {
+ set_insn_error (arg->argnum, _("frame size specified twice"));
+ return FALSE;
+ }
+ if ((frame_size & 7) != 0 || frame_size < 0 || frame_size > 0xff * 8)
+ {
+ set_insn_error (arg->argnum, _("invalid frame size"));
+ return FALSE;
+ }
+ if (frame_size != 128 || (opcode >> 16) != 0)
{
frame_size /= 8;
opcode |= (((frame_size & 0xf0) << 16)
| (frame_size & 0x0f));
}
- if (error)
- {
- if (arg->soft_match)
- return FALSE;
- as_bad ("%s", error);
- }
-
/* Finally build the instruction. */
if ((opcode >> 16) != 0 || frame_size == 0)
opcode |= MIPS16_EXTEND;
if ((opcode->membership & INSN_5400)
&& strcmp (opcode->name, "rzu.ob") == 0)
{
- if (arg->soft_match)
- return FALSE;
- as_bad (_("Operand %d of `%s' must be an immediate"),
- arg->argnum, opcode->name);
+ set_insn_error_i (arg->argnum, _("operand %d must be an immediate"),
+ arg->argnum);
+ return FALSE;
}
/* Check whether this is a vector register or a broadcast of
return FALSE;
if (arg->token->u.reg_element.index > (is_qh ? 3 : 7))
{
- if (arg->soft_match)
- return FALSE;
- as_bad (_("Invalid element selector"));
+ set_insn_error (arg->argnum, _("invalid element selector"));
+ return FALSE;
}
else
uval |= arg->token->u.reg_element.index << (is_qh ? 2 : 1) << 5;
&& (strcmp (opcode->name, "sll.ob") == 0
|| strcmp (opcode->name, "srl.ob") == 0))
{
- if (arg->soft_match)
- return FALSE;
- as_bad (_("Operand %d of `%s' must be scalar"),
- arg->argnum, opcode->name);
+ set_insn_error_i (arg->argnum, _("operand %d must be scalar"),
+ arg->argnum);
+ return FALSE;
}
if (!match_regno (arg, OP_REG_VEC, arg->token->u.regno, ®no))
{
offsetT sval;
- if (!match_const_int (arg, &sval, 0))
+ if (!match_const_int (arg, &sval))
return FALSE;
if (sval < 0 || sval > 31)
{
- if (arg->soft_match)
- return FALSE;
- report_bad_range (arg->insn, arg->argnum, sval, 0, 31, FALSE);
+ match_out_of_range (arg);
+ return FALSE;
}
uval |= (sval & 31);
if (is_qh)
The .lit4 and .lit8 sections are only used if permitted by the
-G argument. */
if (arg->token->type != OT_FLOAT)
- return FALSE;
+ {
+ set_insn_error (arg->argnum, _("floating-point expression required"));
+ return FALSE;
+ }
gas_assert (arg->token->u.flt.length == length);
data = arg->token->u.flt.data;
else
record_alignment (new_seg, length == 4 ? 2 : 3);
if (seg == now_seg)
- as_bad (_("Can't use floating point insn in this section"));
+ as_bad (_("cannot use `%s' in this section"), arg->insn->insn_mo->name);
/* Set the argument to the current address in the section. */
imm->X_op = O_absent;
return TRUE;
}
+/* OP_VU0_SUFFIX and OP_VU0_MATCH_SUFFIX matcher; MATCH_P selects between
+ them. */
+
+static bfd_boolean
+match_vu0_suffix_operand (struct mips_arg_info *arg,
+ const struct mips_operand *operand,
+ bfd_boolean match_p)
+{
+ unsigned int uval;
+
+ /* The operand can be an XYZW mask or a single 2-bit channel index
+ (with X being 0). */
+ gas_assert (operand->size == 2 || operand->size == 4);
+
+ /* The suffix can be omitted when it is already part of the opcode. */
+ if (arg->token->type != OT_CHANNELS)
+ return match_p;
+
+ uval = arg->token->u.channels;
+ if (operand->size == 2)
+ {
+ /* Check that a single bit is set and convert it into a 2-bit index. */
+ if ((uval & -uval) != uval)
+ return FALSE;
+ uval = 4 - ffs (uval);
+ }
+
+ if (match_p && insn_extract_operand (arg->insn, operand) != uval)
+ return FALSE;
+
+ ++arg->token;
+ if (!match_p)
+ insn_insert_operand (arg->insn, operand, uval);
+ return TRUE;
+}
+
/* S is the text seen for ARG. Match it against OPERAND. Return the end
of the argument text if the match is successful, otherwise return null. */
return match_msb_operand (arg, operand);
case OP_REG:
+ case OP_OPTIONAL_REG:
return match_reg_operand (arg, operand);
case OP_REG_PAIR:
case OP_PC:
return match_pc_operand (arg);
+
+ case OP_VU0_SUFFIX:
+ return match_vu0_suffix_operand (arg, operand, FALSE);
+
+ case OP_VU0_MATCH_SUFFIX:
+ return match_vu0_suffix_operand (arg, operand, TRUE);
}
abort ();
}
if (arg->seen_at)
{
if (AT == ATREG)
- as_warn (_("Used $at without \".set noat\""));
+ as_warn (_("used $at without \".set noat\""));
else
- as_warn (_("Used $%u with \".set at=$%u\""), AT, AT);
+ as_warn (_("used $%u with \".set at=$%u\""), AT, AT);
}
}
&& micromips_insn_length (ip->insn_mo) != 2)
|| ((prev_pinfo2 & INSN2_BRANCH_DELAY_32BIT) != 0
&& micromips_insn_length (ip->insn_mo) != 4)))
- as_warn (_("Wrong size instruction in a %u-bit branch delay slot"),
+ as_warn (_("wrong size instruction in a %u-bit branch delay slot"),
(prev_pinfo2 & INSN2_BRANCH_DELAY_16BIT) != 0 ? 16 : 32);
if (address_expr == NULL)
}
}
-/* Set up global variables for the start of a new macro. */
+/* Sign-extend 32-bit mode constants that have bit 31 set and all
+ higher bits unset. */
static void
-macro_start (void)
+normalize_constant_expr (expressionS *ex)
+{
+ if (ex->X_op == O_constant
+ && IS_ZEXT_32BIT_NUM (ex->X_add_number))
+ ex->X_add_number = (((ex->X_add_number & 0xffffffff) ^ 0x80000000)
+ - 0x80000000);
+}
+
+/* Sign-extend 32-bit mode address offsets that have bit 31 set and
+ all higher bits unset. */
+
+static void
+normalize_address_expr (expressionS *ex)
+{
+ if (((ex->X_op == O_constant && HAVE_32BIT_ADDRESSES)
+ || (ex->X_op == O_symbol && HAVE_32BIT_SYMBOLS))
+ && IS_ZEXT_32BIT_NUM (ex->X_add_number))
+ ex->X_add_number = (((ex->X_add_number & 0xffffffff) ^ 0x80000000)
+ - 0x80000000);
+}
+
+/* Try to match TOKENS against OPCODE, storing the result in INSN.
+ Return true if the match was successful.
+
+ OPCODE_EXTRA is a value that should be ORed into the opcode
+ (used for VU0 channel suffixes, etc.). MORE_ALTS is true if
+ there are more alternatives after OPCODE and SOFT_MATCH is
+ as for mips_arg_info. */
+
+static bfd_boolean
+match_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode,
+ struct mips_operand_token *tokens, unsigned int opcode_extra,
+ bfd_boolean lax_match, bfd_boolean complete_p)
+{
+ const char *args;
+ struct mips_arg_info arg;
+ const struct mips_operand *operand;
+ char c;
+
+ imm_expr.X_op = O_absent;
+ offset_expr.X_op = O_absent;
+ offset_reloc[0] = BFD_RELOC_UNUSED;
+ offset_reloc[1] = BFD_RELOC_UNUSED;
+ offset_reloc[2] = BFD_RELOC_UNUSED;
+
+ create_insn (insn, opcode);
+ /* 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));
+ arg.insn = insn;
+ arg.token = tokens;
+ arg.argnum = 1;
+ arg.last_regno = ILLEGAL_REG;
+ arg.dest_regno = ILLEGAL_REG;
+ arg.lax_match = lax_match;
+ for (args = opcode->args;; ++args)
+ {
+ if (arg.token->type == OT_END)
+ {
+ /* Handle unary instructions in which only one operand is given.
+ The source is then the same as the destination. */
+ if (arg.opnum == 1 && *args == ',')
+ {
+ operand = (mips_opts.micromips
+ ? decode_micromips_operand (args + 1)
+ : decode_mips_operand (args + 1));
+ if (operand && mips_optional_operand_p (operand))
+ {
+ arg.token = tokens;
+ arg.argnum = 1;
+ continue;
+ }
+ }
+
+ /* Treat elided base registers as $0. */
+ if (strcmp (args, "(b)") == 0)
+ args += 3;
+
+ if (args[0] == '+')
+ switch (args[1])
+ {
+ case 'K':
+ case 'N':
+ /* The register suffix is optional. */
+ args += 2;
+ break;
+ }
+
+ /* Fail the match if there were too few operands. */
+ if (*args)
+ return FALSE;
+
+ /* Successful match. */
+ if (!complete_p)
+ return TRUE;
+ clear_insn_error ();
+ if (arg.dest_regno == arg.last_regno
+ && strncmp (insn->insn_mo->name, "jalr", 4) == 0)
+ {
+ if (arg.opnum == 2)
+ set_insn_error
+ (0, _("source and destination must be different"));
+ else if (arg.last_regno == 31)
+ set_insn_error
+ (0, _("a destination register must be supplied"));
+ }
+ else if (arg.last_regno == 31
+ && (strncmp (insn->insn_mo->name, "bltzal", 6) == 0
+ || strncmp (insn->insn_mo->name, "bgezal", 6) == 0))
+ set_insn_error (0, _("the source register must not be $31"));
+ check_completed_insn (&arg);
+ return TRUE;
+ }
+
+ /* Fail the match if the line has too many operands. */
+ if (*args == 0)
+ return FALSE;
+
+ /* Handle characters that need to match exactly. */
+ if (*args == '(' || *args == ')' || *args == ',')
+ {
+ if (match_char (&arg, *args))
+ continue;
+ return FALSE;
+ }
+ if (*args == '#')
+ {
+ ++args;
+ if (arg.token->type == OT_DOUBLE_CHAR
+ && arg.token->u.ch == *args)
+ {
+ ++arg.token;
+ continue;
+ }
+ return FALSE;
+ }
+
+ /* Handle special macro operands. Work out the properties of
+ other operands. */
+ arg.opnum += 1;
+ switch (*args)
+ {
+ case '+':
+ switch (args[1])
+ {
+ case 'i':
+ *offset_reloc = BFD_RELOC_MIPS_JMP;
+ break;
+ }
+ break;
+
+ case 'I':
+ if (!match_const_int (&arg, &imm_expr.X_add_number))
+ return FALSE;
+ imm_expr.X_op = O_constant;
+ if (HAVE_32BIT_GPRS)
+ normalize_constant_expr (&imm_expr);
+ continue;
+
+ case 'A':
+ if (arg.token->type == OT_CHAR && arg.token->u.ch == '(')
+ {
+ /* Assume that the offset has been elided and that what
+ we saw was a base register. The match will fail later
+ if that assumption turns out to be wrong. */
+ offset_expr.X_op = O_constant;
+ offset_expr.X_add_number = 0;
+ }
+ else
+ {
+ if (!match_expression (&arg, &offset_expr, offset_reloc))
+ return FALSE;
+ normalize_address_expr (&offset_expr);
+ }
+ continue;
+
+ case 'F':
+ if (!match_float_constant (&arg, &imm_expr, &offset_expr,
+ 8, TRUE))
+ return FALSE;
+ continue;
+
+ case 'L':
+ if (!match_float_constant (&arg, &imm_expr, &offset_expr,
+ 8, FALSE))
+ return FALSE;
+ continue;
+
+ case 'f':
+ if (!match_float_constant (&arg, &imm_expr, &offset_expr,
+ 4, TRUE))
+ return FALSE;
+ continue;
+
+ case 'l':
+ if (!match_float_constant (&arg, &imm_expr, &offset_expr,
+ 4, FALSE))
+ return FALSE;
+ continue;
+
+ case 'p':
+ *offset_reloc = BFD_RELOC_16_PCREL_S2;
+ break;
+
+ case 'a':
+ *offset_reloc = BFD_RELOC_MIPS_JMP;
+ break;
+
+ case 'm':
+ gas_assert (mips_opts.micromips);
+ c = args[1];
+ switch (c)
+ {
+ case 'D':
+ case 'E':
+ if (!forced_insn_length)
+ *offset_reloc = (int) BFD_RELOC_UNUSED + c;
+ else if (c == 'D')
+ *offset_reloc = BFD_RELOC_MICROMIPS_10_PCREL_S1;
+ else
+ *offset_reloc = BFD_RELOC_MICROMIPS_7_PCREL_S1;
+ break;
+ }
+ break;
+ }
+
+ operand = (mips_opts.micromips
+ ? decode_micromips_operand (args)
+ : decode_mips_operand (args));
+ if (!operand)
+ abort ();
+
+ /* Skip prefixes. */
+ if (*args == '+' || *args == 'm')
+ args++;
+
+ if (mips_optional_operand_p (operand)
+ && args[1] == ','
+ && (arg.token[0].type != OT_REG
+ || arg.token[1].type == OT_END))
+ {
+ /* Assume that the register has been elided and is the
+ same as the first operand. */
+ arg.token = tokens;
+ arg.argnum = 1;
+ }
+
+ if (!match_operand (&arg, operand))
+ return FALSE;
+ }
+}
+
+/* Like match_insn, but for MIPS16. */
+
+static bfd_boolean
+match_mips16_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode,
+ struct mips_operand_token *tokens)
+{
+ const char *args;
+ const struct mips_operand *operand;
+ const struct mips_operand *ext_operand;
+ struct mips_arg_info arg;
+ int relax_char;
+
+ create_insn (insn, opcode);
+ imm_expr.X_op = O_absent;
+ offset_expr.X_op = O_absent;
+ offset_reloc[0] = BFD_RELOC_UNUSED;
+ offset_reloc[1] = BFD_RELOC_UNUSED;
+ offset_reloc[2] = BFD_RELOC_UNUSED;
+ relax_char = 0;
+
+ memset (&arg, 0, sizeof (arg));
+ arg.insn = insn;
+ arg.token = tokens;
+ arg.argnum = 1;
+ arg.last_regno = ILLEGAL_REG;
+ arg.dest_regno = ILLEGAL_REG;
+ relax_char = 0;
+ for (args = opcode->args;; ++args)
+ {
+ int c;
+
+ if (arg.token->type == OT_END)
+ {
+ offsetT value;
+
+ /* Handle unary instructions in which only one operand is given.
+ The source is then the same as the destination. */
+ if (arg.opnum == 1 && *args == ',')
+ {
+ operand = decode_mips16_operand (args[1], FALSE);
+ if (operand && mips_optional_operand_p (operand))
+ {
+ arg.token = tokens;
+ arg.argnum = 1;
+ continue;
+ }
+ }
+
+ /* Fail the match if there were too few operands. */
+ if (*args)
+ return FALSE;
+
+ /* Successful match. Stuff the immediate value in now, if
+ we can. */
+ clear_insn_error ();
+ if (opcode->pinfo == INSN_MACRO)
+ {
+ gas_assert (relax_char == 0 || relax_char == 'p');
+ gas_assert (*offset_reloc == BFD_RELOC_UNUSED);
+ }
+ else if (relax_char
+ && offset_expr.X_op == O_constant
+ && calculate_reloc (*offset_reloc,
+ offset_expr.X_add_number,
+ &value))
+ {
+ mips16_immed (NULL, 0, relax_char, *offset_reloc, value,
+ forced_insn_length, &insn->insn_opcode);
+ offset_expr.X_op = O_absent;
+ *offset_reloc = BFD_RELOC_UNUSED;
+ }
+ else if (relax_char && *offset_reloc != BFD_RELOC_UNUSED)
+ {
+ if (forced_insn_length == 2)
+ set_insn_error (0, _("invalid unextended operand value"));
+ forced_insn_length = 4;
+ insn->insn_opcode |= MIPS16_EXTEND;
+ }
+ else if (relax_char)
+ *offset_reloc = (int) BFD_RELOC_UNUSED + relax_char;
+
+ check_completed_insn (&arg);
+ return TRUE;
+ }
+
+ /* Fail the match if the line has too many operands. */
+ if (*args == 0)
+ return FALSE;
+
+ /* Handle characters that need to match exactly. */
+ if (*args == '(' || *args == ')' || *args == ',')
+ {
+ if (match_char (&arg, *args))
+ continue;
+ return FALSE;
+ }
+
+ arg.opnum += 1;
+ c = *args;
+ switch (c)
+ {
+ case 'p':
+ case 'q':
+ case 'A':
+ case 'B':
+ case 'E':
+ relax_char = c;
+ break;
+
+ case 'I':
+ if (!match_const_int (&arg, &imm_expr.X_add_number))
+ return FALSE;
+ imm_expr.X_op = O_constant;
+ if (HAVE_32BIT_GPRS)
+ normalize_constant_expr (&imm_expr);
+ continue;
+
+ case 'a':
+ case 'i':
+ *offset_reloc = BFD_RELOC_MIPS16_JMP;
+ insn->insn_opcode <<= 16;
+ break;
+ }
+
+ operand = decode_mips16_operand (c, FALSE);
+ if (!operand)
+ abort ();
+
+ /* '6' is a special case. It is used for BREAK and SDBBP,
+ whose operands are only meaningful to the software that decodes
+ them. This means that there is no architectural reason why
+ they cannot be prefixed by EXTEND, but in practice,
+ exception handlers will only look at the instruction
+ itself. We therefore allow '6' to be extended when
+ disassembling but not when assembling. */
+ if (operand->type != OP_PCREL && c != '6')
+ {
+ ext_operand = decode_mips16_operand (c, TRUE);
+ if (operand != ext_operand)
+ {
+ if (arg.token->type == OT_CHAR && arg.token->u.ch == '(')
+ {
+ offset_expr.X_op = O_constant;
+ offset_expr.X_add_number = 0;
+ relax_char = c;
+ continue;
+ }
+
+ /* We need the OT_INTEGER check because some MIPS16
+ immediate variants are listed before the register ones. */
+ if (arg.token->type != OT_INTEGER
+ || !match_expression (&arg, &offset_expr, offset_reloc))
+ return FALSE;
+
+ /* '8' is used for SLTI(U) and has traditionally not
+ been allowed to take relocation operators. */
+ if (offset_reloc[0] != BFD_RELOC_UNUSED
+ && (ext_operand->size != 16 || c == '8'))
+ return FALSE;
+
+ relax_char = c;
+ continue;
+ }
+ }
+
+ if (mips_optional_operand_p (operand)
+ && args[1] == ','
+ && (arg.token[0].type != OT_REG
+ || arg.token[1].type == OT_END))
+ {
+ /* Assume that the register has been elided and is the
+ same as the first operand. */
+ arg.token = tokens;
+ arg.argnum = 1;
+ }
+
+ if (!match_operand (&arg, operand))
+ return FALSE;
+ }
+}
+
+/* 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. */
+
+static void
+macro_start (void)
{
memset (&mips_macro_warning.sizes, 0, sizeof (mips_macro_warning.sizes));
memset (&mips_macro_warning.first_insn_sizes, 0,
macro_warning (relax_substateT subtype)
{
if (subtype & RELAX_DELAY_SLOT)
- return _("Macro instruction expanded into multiple instructions"
+ return _("macro instruction expanded into multiple instructions"
" in a branch delay slot");
else if (subtype & RELAX_NOMACRO)
- return _("Macro instruction expanded into multiple instructions");
+ return _("macro instruction expanded into multiple instructions");
else if (subtype & (RELAX_DELAY_SLOT_SIZE_FIRST
| RELAX_DELAY_SLOT_SIZE_SECOND))
return ((subtype & RELAX_DELAY_SLOT_16BIT)
- ? _("Macro instruction expanded into a wrong size instruction"
+ ? _("macro instruction expanded into a wrong size instruction"
" in a 16-bit branch delay slot")
- : _("Macro instruction expanded into a wrong size instruction"
+ : _("macro instruction expanded into a wrong size instruction"
" in a 32-bit branch delay slot"));
else
return 0;
append_insn (&insn, ep, r, TRUE);
}
-/*
- * Sign-extend 32-bit mode constants that have bit 31 set and all
- * higher bits unset.
- */
-static void
-normalize_constant_expr (expressionS *ex)
-{
- if (ex->X_op == O_constant
- && IS_ZEXT_32BIT_NUM (ex->X_add_number))
- ex->X_add_number = (((ex->X_add_number & 0xffffffff) ^ 0x80000000)
- - 0x80000000);
-}
-
-/*
- * Sign-extend 32-bit mode address offsets that have bit 31 set and
- * all higher bits unset.
- */
-static void
-normalize_address_expr (expressionS *ex)
-{
- if (((ex->X_op == O_constant && HAVE_32BIT_ADDRESSES)
- || (ex->X_op == O_symbol && HAVE_32BIT_SYMBOLS))
- && IS_ZEXT_32BIT_NUM (ex->X_add_number))
- ex->X_add_number = (((ex->X_add_number & 0xffffffff) ^ 0x80000000)
- - 0x80000000);
-}
-
/*
* Generate a "jalr" instruction with a relocation hint to the called
* function. This occurs in NewABI PIC code.
macro_build (ep, op, "t,o(b)", treg, BFD_RELOC_LO16, AT);
if (!mips_opts.at)
- as_bad (_("Macro used $at after \".set noat\""));
+ as_bad (_("macro used $at after \".set noat\""));
}
}
static void
set_at (int reg, int unsignedp)
{
- if (imm_expr.X_op == O_constant
- && imm_expr.X_add_number >= -0x8000
+ if (imm_expr.X_add_number >= -0x8000
&& imm_expr.X_add_number < 0x8000)
macro_build (&imm_expr, unsignedp ? "sltiu" : "slti", "t,r,j",
AT, reg, BFD_RELOC_LO16);
char value[32];
sprintf_vma (value, ep->X_add_number);
- as_bad (_("Number (0x%s) larger than 32 bits"), value);
+ as_bad (_("number (0x%s) larger than 32 bits"), value);
macro_build (ep, "addiu", "t,r,j", reg, 0, BFD_RELOC_LO16);
return;
}
if (ep->X_add_number == 3)
generic_bignum[3] = 0;
else if (ep->X_add_number > 4)
- as_bad (_("Number larger than 64 bits"));
+ as_bad (_("number larger than 64 bits"));
lo32.X_op = O_constant;
lo32.X_add_number = generic_bignum[0] + (generic_bignum[1] << 16);
hi32.X_op = O_constant;
abort ();
if (!mips_opts.at && *used_at == 1)
- as_bad (_("Macro used $at after \".set noat\""));
+ as_bad (_("macro used $at after \".set noat\""));
}
/* Move the contents of register SOURCE into register DEST. */
static void
macro (struct mips_cl_insn *ip, char *str)
{
- unsigned int treg, sreg, dreg, breg;
+ const struct mips_operand_array *operands;
+ unsigned int breg, i;
unsigned int tempreg;
int mask;
int used_at = 0;
int off;
int hold_mips_optimize;
unsigned int align;
+ unsigned int op[MAX_OPERANDS];
gas_assert (! mips_opts.mips16);
- treg = EXTRACT_OPERAND (mips_opts.micromips, RT, *ip);
- dreg = EXTRACT_OPERAND (mips_opts.micromips, RD, *ip);
- sreg = breg = EXTRACT_OPERAND (mips_opts.micromips, RS, *ip);
+ operands = insn_operands (ip);
+ for (i = 0; i < MAX_OPERANDS; i++)
+ if (operands->operand[i])
+ op[i] = insn_extract_operand (ip, operands->operand[i]);
+ else
+ op[i] = -1;
+
mask = ip->insn_mo->mask;
label_expr.X_op = O_constant;
micromips_label_expr (&label_expr);
else
label_expr.X_add_number = 8;
- macro_build (&label_expr, "bgez", "s,p", sreg);
- if (dreg == sreg)
+ macro_build (&label_expr, "bgez", "s,p", op[1]);
+ if (op[0] == op[1])
macro_build (NULL, "nop", "");
else
- move_register (dreg, sreg);
- macro_build (NULL, dbl ? "dsub" : "sub", "d,v,t", dreg, 0, sreg);
+ move_register (op[0], op[1]);
+ macro_build (NULL, dbl ? "dsub" : "sub", "d,v,t", op[0], 0, op[1]);
if (mips_opts.micromips)
micromips_add_label ();
s2 = "dadd";
if (!mips_opts.micromips)
goto do_addi;
- if (imm_expr.X_op == O_constant
- && imm_expr.X_add_number >= -0x200
+ if (imm_expr.X_add_number >= -0x200
&& imm_expr.X_add_number < 0x200)
{
- macro_build (NULL, s, "t,r,.", treg, sreg, imm_expr.X_add_number);
+ macro_build (NULL, s, "t,r,.", op[0], op[1],
+ (int) imm_expr.X_add_number);
break;
}
goto do_addi_i;
s = "daddiu";
s2 = "daddu";
do_addi:
- if (imm_expr.X_op == O_constant
- && imm_expr.X_add_number >= -0x8000
+ if (imm_expr.X_add_number >= -0x8000
&& imm_expr.X_add_number < 0x8000)
{
- macro_build (&imm_expr, s, "t,r,j", treg, sreg, BFD_RELOC_LO16);
+ macro_build (&imm_expr, s, "t,r,j", op[0], op[1], BFD_RELOC_LO16);
break;
}
do_addi_i:
used_at = 1;
load_register (AT, &imm_expr, dbl);
- macro_build (NULL, s2, "d,v,t", treg, sreg, AT);
+ macro_build (NULL, s2, "d,v,t", op[0], op[1], AT);
break;
case M_AND_I:
s = "xori";
s2 = "xor";
do_bit:
- if (imm_expr.X_op == O_constant
- && imm_expr.X_add_number >= 0
+ if (imm_expr.X_add_number >= 0
&& imm_expr.X_add_number < 0x10000)
{
if (mask != M_NOR_I)
- macro_build (&imm_expr, s, "t,r,i", treg, sreg, BFD_RELOC_LO16);
+ macro_build (&imm_expr, s, "t,r,i", op[0], op[1], BFD_RELOC_LO16);
else
{
macro_build (&imm_expr, "ori", "t,r,i",
- treg, sreg, BFD_RELOC_LO16);
- macro_build (NULL, "nor", "d,v,t", treg, treg, 0);
+ op[0], op[1], BFD_RELOC_LO16);
+ macro_build (NULL, "nor", "d,v,t", op[0], op[0], 0);
}
break;
}
used_at = 1;
load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
- macro_build (NULL, s2, "d,v,t", treg, sreg, AT);
+ macro_build (NULL, s2, "d,v,t", op[0], op[1], AT);
break;
case M_BALIGN:
macro_build (NULL, "nop", "");
break;
case 2:
- macro_build (NULL, "packrl.ph", "d,s,t", treg, treg, sreg);
+ macro_build (NULL, "packrl.ph", "d,s,t", op[0], op[0], op[1]);
break;
case 1:
case 3:
- macro_build (NULL, "balign", "t,s,2", treg, sreg,
+ macro_build (NULL, "balign", "t,s,2", op[0], op[1],
(int) imm_expr.X_add_number);
break;
default:
case M_BEQL_I:
case M_BNE_I:
case M_BNEL_I:
- if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
- treg = 0;
+ if (imm_expr.X_add_number == 0)
+ op[1] = 0;
else
{
- treg = AT;
+ op[1] = AT;
used_at = 1;
- load_register (treg, &imm_expr, HAVE_64BIT_GPRS);
+ load_register (op[1], &imm_expr, HAVE_64BIT_GPRS);
}
/* Fall through. */
case M_BEQL:
case M_BNEL:
- macro_build_branch_rsrt (mask, &offset_expr, sreg, treg);
+ macro_build_branch_rsrt (mask, &offset_expr, op[0], op[1]);
break;
case M_BGEL:
likely = 1;
case M_BGE:
- if (treg == 0)
- macro_build_branch_rs (likely ? M_BGEZL : M_BGEZ, &offset_expr, sreg);
- else if (sreg == 0)
- macro_build_branch_rs (likely ? M_BLEZL : M_BLEZ, &offset_expr, treg);
+ if (op[1] == 0)
+ macro_build_branch_rs (likely ? M_BGEZL : M_BGEZ, &offset_expr, op[0]);
+ else if (op[0] == 0)
+ macro_build_branch_rs (likely ? M_BLEZL : M_BLEZ, &offset_expr, op[1]);
else
{
used_at = 1;
- macro_build (NULL, "slt", "d,v,t", AT, sreg, treg);
+ macro_build (NULL, "slt", "d,v,t", AT, op[0], op[1]);
macro_build_branch_rsrt (likely ? M_BEQL : M_BEQ,
&offset_expr, AT, ZERO);
}
case M_BLEZL:
case M_BLTZL:
case M_BLTZALL:
- macro_build_branch_rs (mask, &offset_expr, sreg);
+ macro_build_branch_rs (mask, &offset_expr, op[0]);
break;
case M_BGTL_I:
likely = 1;
case M_BGT_I:
/* Check for > max integer. */
- if (imm_expr.X_op == O_constant && imm_expr.X_add_number >= GPR_SMAX)
+ if (imm_expr.X_add_number >= GPR_SMAX)
{
do_false:
/* Result is always false. */
macro_build_branch_rsrt (M_BNEL, &offset_expr, ZERO, ZERO);
break;
}
- if (imm_expr.X_op != O_constant)
- as_bad (_("Unsupported large constant"));
++imm_expr.X_add_number;
/* FALLTHROUGH */
case M_BGE_I:
case M_BGEL_I:
if (mask == M_BGEL_I)
likely = 1;
- if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
+ if (imm_expr.X_add_number == 0)
{
macro_build_branch_rs (likely ? M_BGEZL : M_BGEZ,
- &offset_expr, sreg);
+ &offset_expr, op[0]);
break;
}
- if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
+ if (imm_expr.X_add_number == 1)
{
macro_build_branch_rs (likely ? M_BGTZL : M_BGTZ,
- &offset_expr, sreg);
+ &offset_expr, op[0]);
break;
}
- if (imm_expr.X_op == O_constant && imm_expr.X_add_number <= GPR_SMIN)
+ if (imm_expr.X_add_number <= GPR_SMIN)
{
do_true:
/* result is always true */
- as_warn (_("Branch %s is always true"), ip->insn_mo->name);
+ as_warn (_("branch %s is always true"), ip->insn_mo->name);
macro_build (&offset_expr, "b", "p");
break;
}
used_at = 1;
- set_at (sreg, 0);
+ set_at (op[0], 0);
macro_build_branch_rsrt (likely ? M_BEQL : M_BEQ,
&offset_expr, AT, ZERO);
break;
case M_BGEUL:
likely = 1;
case M_BGEU:
- if (treg == 0)
+ if (op[1] == 0)
goto do_true;
- else if (sreg == 0)
+ else if (op[0] == 0)
macro_build_branch_rsrt (likely ? M_BEQL : M_BEQ,
- &offset_expr, ZERO, treg);
+ &offset_expr, ZERO, op[1]);
else
{
used_at = 1;
- macro_build (NULL, "sltu", "d,v,t", AT, sreg, treg);
+ macro_build (NULL, "sltu", "d,v,t", AT, op[0], op[1]);
macro_build_branch_rsrt (likely ? M_BEQL : M_BEQ,
&offset_expr, AT, ZERO);
}
case M_BGTUL_I:
likely = 1;
case M_BGTU_I:
- if (sreg == 0
+ if (op[0] == 0
|| (HAVE_32BIT_GPRS
- && imm_expr.X_op == O_constant
&& imm_expr.X_add_number == -1))
goto do_false;
- if (imm_expr.X_op != O_constant)
- as_bad (_("Unsupported large constant"));
++imm_expr.X_add_number;
/* FALLTHROUGH */
case M_BGEU_I:
case M_BGEUL_I:
if (mask == M_BGEUL_I)
likely = 1;
- if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
+ if (imm_expr.X_add_number == 0)
goto do_true;
- else if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
+ else if (imm_expr.X_add_number == 1)
macro_build_branch_rsrt (likely ? M_BNEL : M_BNE,
- &offset_expr, sreg, ZERO);
+ &offset_expr, op[0], ZERO);
else
{
used_at = 1;
- set_at (sreg, 1);
+ set_at (op[0], 1);
macro_build_branch_rsrt (likely ? M_BEQL : M_BEQ,
&offset_expr, AT, ZERO);
}
case M_BGTL:
likely = 1;
case M_BGT:
- if (treg == 0)
- macro_build_branch_rs (likely ? M_BGTZL : M_BGTZ, &offset_expr, sreg);
- else if (sreg == 0)
- macro_build_branch_rs (likely ? M_BLTZL : M_BLTZ, &offset_expr, treg);
+ if (op[1] == 0)
+ macro_build_branch_rs (likely ? M_BGTZL : M_BGTZ, &offset_expr, op[0]);
+ else if (op[0] == 0)
+ macro_build_branch_rs (likely ? M_BLTZL : M_BLTZ, &offset_expr, op[1]);
else
{
used_at = 1;
- macro_build (NULL, "slt", "d,v,t", AT, treg, sreg);
+ macro_build (NULL, "slt", "d,v,t", AT, op[1], op[0]);
macro_build_branch_rsrt (likely ? M_BNEL : M_BNE,
&offset_expr, AT, ZERO);
}
case M_BGTUL:
likely = 1;
case M_BGTU:
- if (treg == 0)
+ if (op[1] == 0)
macro_build_branch_rsrt (likely ? M_BNEL : M_BNE,
- &offset_expr, sreg, ZERO);
- else if (sreg == 0)
+ &offset_expr, op[0], ZERO);
+ else if (op[0] == 0)
goto do_false;
else
{
used_at = 1;
- macro_build (NULL, "sltu", "d,v,t", AT, treg, sreg);
+ macro_build (NULL, "sltu", "d,v,t", AT, op[1], op[0]);
macro_build_branch_rsrt (likely ? M_BNEL : M_BNE,
&offset_expr, AT, ZERO);
}
case M_BLEL:
likely = 1;
case M_BLE:
- if (treg == 0)
- macro_build_branch_rs (likely ? M_BLEZL : M_BLEZ, &offset_expr, sreg);
- else if (sreg == 0)
- macro_build_branch_rs (likely ? M_BGEZL : M_BGEZ, &offset_expr, treg);
+ if (op[1] == 0)
+ macro_build_branch_rs (likely ? M_BLEZL : M_BLEZ, &offset_expr, op[0]);
+ else if (op[0] == 0)
+ macro_build_branch_rs (likely ? M_BGEZL : M_BGEZ, &offset_expr, op[1]);
else
{
used_at = 1;
- macro_build (NULL, "slt", "d,v,t", AT, treg, sreg);
+ macro_build (NULL, "slt", "d,v,t", AT, op[1], op[0]);
macro_build_branch_rsrt (likely ? M_BEQL : M_BEQ,
&offset_expr, AT, ZERO);
}
case M_BLEL_I:
likely = 1;
case M_BLE_I:
- if (imm_expr.X_op == O_constant && imm_expr.X_add_number >= GPR_SMAX)
+ if (imm_expr.X_add_number >= GPR_SMAX)
goto do_true;
- if (imm_expr.X_op != O_constant)
- as_bad (_("Unsupported large constant"));
++imm_expr.X_add_number;
/* FALLTHROUGH */
case M_BLT_I:
case M_BLTL_I:
if (mask == M_BLTL_I)
likely = 1;
- if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
- macro_build_branch_rs (likely ? M_BLTZL : M_BLTZ, &offset_expr, sreg);
- else if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
- macro_build_branch_rs (likely ? M_BLEZL : M_BLEZ, &offset_expr, sreg);
+ if (imm_expr.X_add_number == 0)
+ macro_build_branch_rs (likely ? M_BLTZL : M_BLTZ, &offset_expr, op[0]);
+ else if (imm_expr.X_add_number == 1)
+ macro_build_branch_rs (likely ? M_BLEZL : M_BLEZ, &offset_expr, op[0]);
else
{
used_at = 1;
- set_at (sreg, 0);
+ set_at (op[0], 0);
macro_build_branch_rsrt (likely ? M_BNEL : M_BNE,
&offset_expr, AT, ZERO);
}
case M_BLEUL:
likely = 1;
case M_BLEU:
- if (treg == 0)
+ if (op[1] == 0)
macro_build_branch_rsrt (likely ? M_BEQL : M_BEQ,
- &offset_expr, sreg, ZERO);
- else if (sreg == 0)
+ &offset_expr, op[0], ZERO);
+ else if (op[0] == 0)
goto do_true;
else
{
used_at = 1;
- macro_build (NULL, "sltu", "d,v,t", AT, treg, sreg);
+ macro_build (NULL, "sltu", "d,v,t", AT, op[1], op[0]);
macro_build_branch_rsrt (likely ? M_BEQL : M_BEQ,
&offset_expr, AT, ZERO);
}
case M_BLEUL_I:
likely = 1;
case M_BLEU_I:
- if (sreg == 0
+ if (op[0] == 0
|| (HAVE_32BIT_GPRS
- && imm_expr.X_op == O_constant
&& imm_expr.X_add_number == -1))
goto do_true;
- if (imm_expr.X_op != O_constant)
- as_bad (_("Unsupported large constant"));
++imm_expr.X_add_number;
/* FALLTHROUGH */
case M_BLTU_I:
case M_BLTUL_I:
if (mask == M_BLTUL_I)
likely = 1;
- if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
+ if (imm_expr.X_add_number == 0)
goto do_false;
- else if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
+ else if (imm_expr.X_add_number == 1)
macro_build_branch_rsrt (likely ? M_BEQL : M_BEQ,
- &offset_expr, sreg, ZERO);
+ &offset_expr, op[0], ZERO);
else
{
used_at = 1;
- set_at (sreg, 1);
+ set_at (op[0], 1);
macro_build_branch_rsrt (likely ? M_BNEL : M_BNE,
&offset_expr, AT, ZERO);
}
case M_BLTL:
likely = 1;
case M_BLT:
- if (treg == 0)
- macro_build_branch_rs (likely ? M_BLTZL : M_BLTZ, &offset_expr, sreg);
- else if (sreg == 0)
- macro_build_branch_rs (likely ? M_BGTZL : M_BGTZ, &offset_expr, treg);
+ if (op[1] == 0)
+ macro_build_branch_rs (likely ? M_BLTZL : M_BLTZ, &offset_expr, op[0]);
+ else if (op[0] == 0)
+ macro_build_branch_rs (likely ? M_BGTZL : M_BGTZ, &offset_expr, op[1]);
else
{
used_at = 1;
- macro_build (NULL, "slt", "d,v,t", AT, sreg, treg);
+ macro_build (NULL, "slt", "d,v,t", AT, op[0], op[1]);
macro_build_branch_rsrt (likely ? M_BNEL : M_BNE,
&offset_expr, AT, ZERO);
}
case M_BLTUL:
likely = 1;
case M_BLTU:
- if (treg == 0)
+ if (op[1] == 0)
goto do_false;
- else if (sreg == 0)
+ else if (op[0] == 0)
macro_build_branch_rsrt (likely ? M_BNEL : M_BNE,
- &offset_expr, ZERO, treg);
+ &offset_expr, ZERO, op[1]);
else
{
used_at = 1;
- macro_build (NULL, "sltu", "d,v,t", AT, sreg, treg);
+ macro_build (NULL, "sltu", "d,v,t", AT, op[0], op[1]);
macro_build_branch_rsrt (likely ? M_BNEL : M_BNE,
&offset_expr, AT, ZERO);
}
break;
- case M_DEXT:
- {
- /* Use unsigned arithmetic. */
- addressT pos;
- addressT size;
-
- if (imm_expr.X_op != O_constant || imm2_expr.X_op != O_constant)
- {
- as_bad (_("Unsupported large constant"));
- pos = size = 1;
- }
- else
- {
- pos = imm_expr.X_add_number;
- size = imm2_expr.X_add_number;
- }
-
- if (pos > 63)
- {
- report_bad_range (ip, 3, pos, 0, 63, FALSE);
- pos = 1;
- }
- if (size == 0 || size > 64 || (pos + size - 1) > 63)
- {
- report_bad_field (pos, size);
- size = 1;
- }
-
- if (size <= 32 && pos < 32)
- {
- s = "dext";
- fmt = "t,r,+A,+C";
- }
- else if (size <= 32)
- {
- s = "dextu";
- fmt = "t,r,+E,+H";
- }
- else
- {
- s = "dextm";
- fmt = "t,r,+A,+G";
- }
- macro_build ((expressionS *) NULL, s, fmt, treg, sreg, (int) pos,
- (int) (size - 1));
- }
- break;
-
- case M_DINS:
- {
- /* Use unsigned arithmetic. */
- addressT pos;
- addressT size;
-
- if (imm_expr.X_op != O_constant || imm2_expr.X_op != O_constant)
- {
- as_bad (_("Unsupported large constant"));
- pos = size = 1;
- }
- else
- {
- pos = imm_expr.X_add_number;
- size = imm2_expr.X_add_number;
- }
-
- if (pos > 63)
- {
- report_bad_range (ip, 3, pos, 0, 63, FALSE);
- pos = 1;
- }
- if (size == 0 || size > 64 || (pos + size - 1) > 63)
- {
- report_bad_field (pos, size);
- size = 1;
- }
-
- if (pos < 32 && (pos + size - 1) < 32)
- {
- s = "dins";
- fmt = "t,r,+A,+B";
- }
- else if (pos >= 32)
- {
- s = "dinsu";
- fmt = "t,r,+E,+F";
- }
- else
- {
- s = "dinsm";
- fmt = "t,r,+A,+F";
- }
- macro_build ((expressionS *) NULL, s, fmt, treg, sreg, (int) pos,
- (int) (pos + size - 1));
- }
- break;
-
case M_DDIV_3:
dbl = 1;
case M_DIV_3:
case M_REM_3:
s = "mfhi";
do_div3:
- if (treg == 0)
+ if (op[2] == 0)
{
- as_warn (_("Divide by zero."));
+ as_warn (_("divide by zero"));
if (mips_trap)
macro_build (NULL, "teq", TRAP_FMT, ZERO, ZERO, 7);
else
start_noreorder ();
if (mips_trap)
{
- macro_build (NULL, "teq", TRAP_FMT, treg, ZERO, 7);
- macro_build (NULL, dbl ? "ddiv" : "div", "z,s,t", sreg, treg);
+ macro_build (NULL, "teq", TRAP_FMT, op[2], ZERO, 7);
+ macro_build (NULL, dbl ? "ddiv" : "div", "z,s,t", op[1], op[2]);
}
else
{
micromips_label_expr (&label_expr);
else
label_expr.X_add_number = 8;
- macro_build (&label_expr, "bne", "s,t,p", treg, ZERO);
- macro_build (NULL, dbl ? "ddiv" : "div", "z,s,t", sreg, treg);
+ macro_build (&label_expr, "bne", "s,t,p", op[2], ZERO);
+ macro_build (NULL, dbl ? "ddiv" : "div", "z,s,t", op[1], op[2]);
macro_build (NULL, "break", BRK_FMT, 7);
if (mips_opts.micromips)
micromips_add_label ();
micromips_label_expr (&label_expr);
else
label_expr.X_add_number = mips_trap ? (dbl ? 12 : 8) : (dbl ? 20 : 16);
- macro_build (&label_expr, "bne", "s,t,p", treg, AT);
+ macro_build (&label_expr, "bne", "s,t,p", op[2], AT);
if (dbl)
{
expr1.X_add_number = 1;
}
if (mips_trap)
{
- macro_build (NULL, "teq", TRAP_FMT, sreg, AT, 6);
+ macro_build (NULL, "teq", TRAP_FMT, op[1], AT, 6);
/* We want to close the noreorder block as soon as possible, so
that later insns are available for delay slot filling. */
end_noreorder ();
micromips_label_expr (&label_expr);
else
label_expr.X_add_number = 8;
- macro_build (&label_expr, "bne", "s,t,p", sreg, AT);
+ macro_build (&label_expr, "bne", "s,t,p", op[1], AT);
macro_build (NULL, "nop", "");
/* We want to close the noreorder block as soon as possible, so
}
if (mips_opts.micromips)
micromips_add_label ();
- macro_build (NULL, s, MFHL_FMT, dreg);
+ macro_build (NULL, s, MFHL_FMT, op[0]);
break;
case M_DIV_3I:
s = "ddivu";
s2 = "mfhi";
do_divi:
- if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
+ if (imm_expr.X_add_number == 0)
{
- as_warn (_("Divide by zero."));
+ as_warn (_("divide by zero"));
if (mips_trap)
macro_build (NULL, "teq", TRAP_FMT, ZERO, ZERO, 7);
else
macro_build (NULL, "break", BRK_FMT, 7);
break;
}
- if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
+ if (imm_expr.X_add_number == 1)
{
if (strcmp (s2, "mflo") == 0)
- move_register (dreg, sreg);
+ move_register (op[0], op[1]);
else
- move_register (dreg, ZERO);
+ move_register (op[0], ZERO);
break;
}
- if (imm_expr.X_op == O_constant
- && imm_expr.X_add_number == -1
- && s[strlen (s) - 1] != 'u')
+ if (imm_expr.X_add_number == -1 && s[strlen (s) - 1] != 'u')
{
if (strcmp (s2, "mflo") == 0)
- {
- macro_build (NULL, dbl ? "dneg" : "neg", "d,w", dreg, sreg);
- }
+ macro_build (NULL, dbl ? "dneg" : "neg", "d,w", op[0], op[1]);
else
- move_register (dreg, ZERO);
+ move_register (op[0], ZERO);
break;
}
used_at = 1;
load_register (AT, &imm_expr, dbl);
- macro_build (NULL, s, "z,s,t", sreg, AT);
- macro_build (NULL, s2, MFHL_FMT, dreg);
+ macro_build (NULL, s, "z,s,t", op[1], AT);
+ macro_build (NULL, s2, MFHL_FMT, op[0]);
break;
case M_DIVU_3:
start_noreorder ();
if (mips_trap)
{
- macro_build (NULL, "teq", TRAP_FMT, treg, ZERO, 7);
- macro_build (NULL, s, "z,s,t", sreg, treg);
+ macro_build (NULL, "teq", TRAP_FMT, op[2], ZERO, 7);
+ macro_build (NULL, s, "z,s,t", op[1], op[2]);
/* We want to close the noreorder block as soon as possible, so
that later insns are available for delay slot filling. */
end_noreorder ();
micromips_label_expr (&label_expr);
else
label_expr.X_add_number = 8;
- macro_build (&label_expr, "bne", "s,t,p", treg, ZERO);
- macro_build (NULL, s, "z,s,t", sreg, treg);
+ macro_build (&label_expr, "bne", "s,t,p", op[2], ZERO);
+ macro_build (NULL, s, "z,s,t", op[1], op[2]);
/* We want to close the noreorder block as soon as possible, so
that later insns are available for delay slot filling. */
if (mips_opts.micromips)
micromips_add_label ();
}
- macro_build (NULL, s2, MFHL_FMT, dreg);
+ macro_build (NULL, s2, MFHL_FMT, op[0]);
break;
case M_DLCA_AB:
/* Load the address of a symbol into a register. If breg is not
zero, we then add a base register to it. */
+ breg = op[2];
if (dbl && HAVE_32BIT_GPRS)
as_warn (_("dla used to load 32-bit register"));
if (small_offset_p (0, align, 16))
{
- macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", treg, breg,
+ macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", op[0], breg,
-1, offset_reloc[0], offset_reloc[1], offset_reloc[2]);
break;
}
- if (mips_opts.at && (treg == breg))
+ if (mips_opts.at && (op[0] == breg))
{
tempreg = AT;
used_at = 1;
}
else
- {
- tempreg = treg;
- }
+ tempreg = op[0];
if (offset_expr.X_op != O_symbol
&& offset_expr.X_op != O_constant)
{
- as_bad (_("Expression too complex"));
+ as_bad (_("expression too complex"));
offset_expr.X_op = O_constant;
}
relax_switch ();
}
if (!IS_SEXT_32BIT_NUM (offset_expr.X_add_number))
- as_bad (_("Offset too large"));
+ as_bad (_("offset too large"));
macro_build_lui (&offset_expr, tempreg);
macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
tempreg, tempreg, BFD_RELOC_LO16);
current AT (from the global offset table) and the
register into the register now, and pretend we were
not using a base register. */
- if (breg == treg)
+ if (breg == op[0])
{
load_delay_nop ();
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
- treg, AT, breg);
+ op[0], AT, breg);
breg = 0;
- tempreg = treg;
+ tempreg = op[0];
}
add_got_offset_hilo (tempreg, &offset_expr, AT);
used_at = 1;
}
else if (IS_SEXT_32BIT_NUM (expr1.X_add_number + 0x8000))
{
+ unsigned int dreg;
+
/* If we are going to add in a base register, and the
target register and the base register are the same,
then we are using AT as a temporary register. Since
current AT (from the global offset table) and the
register into the register now, and pretend we were
not using a base register. */
- if (breg != treg)
+ if (breg != op[0])
dreg = tempreg;
else
{
gas_assert (tempreg == AT);
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
- treg, AT, breg);
- dreg = treg;
+ op[0], AT, breg);
+ dreg = op[0];
add_breg_early = 1;
}
if (add_breg_early)
{
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
- treg, tempreg, breg);
+ op[0], tempreg, breg);
breg = 0;
- tempreg = treg;
+ tempreg = op[0];
}
relax_end ();
}
}
else
{
+ unsigned int dreg;
+
/* If we are going to add in a base register, and the
target register and the base register are the same,
then we are using AT as a temporary register. Since
current AT (from the global offset table) and the
register into the register now, and pretend we were
not using a base register. */
- if (breg != treg)
+ if (breg != op[0])
dreg = tempreg;
else
{
gas_assert (tempreg == AT);
load_delay_nop ();
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
- treg, AT, breg);
- dreg = treg;
+ op[0], AT, breg);
+ dreg = op[0];
}
load_register (AT, &expr1, HAVE_64BIT_ADDRESSES);
}
else
{
- if (breg == treg)
+ if (breg == op[0])
{
/* We must add in the base register now, as in the
external symbol case. */
gas_assert (tempreg == AT);
load_delay_nop ();
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
- treg, AT, breg);
- tempreg = treg;
+ op[0], AT, breg);
+ tempreg = op[0];
/* We set breg to 0 because we have arranged to add
it in in both cases. */
breg = 0;
}
else if (IS_SEXT_32BIT_NUM (expr1.X_add_number + 0x8000))
{
+ unsigned int dreg;
+
/* If we are going to add in a base register, and the
target register and the base register are the same,
then we are using AT as a temporary register. Since
current AT (from the global offset table) and the
register into the register now, and pretend we were
not using a base register. */
- if (breg != treg)
+ if (breg != op[0])
dreg = tempreg;
else
{
gas_assert (tempreg == AT);
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
- treg, AT, breg);
- dreg = treg;
+ op[0], AT, breg);
+ dreg = op[0];
add_breg_early = 1;
}
if (add_breg_early)
{
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
- treg, tempreg, breg);
+ op[0], tempreg, breg);
breg = 0;
- tempreg = treg;
+ tempreg = op[0];
}
relax_end ();
}
abort ();
if (breg != 0)
- macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", treg, tempreg, breg);
+ macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", op[0], tempreg, breg);
break;
case M_MSGSND:
gas_assert (!mips_opts.micromips);
- macro_build (NULL, "c2", "C", (treg << 16) | 0x01);
+ macro_build (NULL, "c2", "C", (op[0] << 16) | 0x01);
break;
case M_MSGLD:
case M_MSGLD_T:
gas_assert (!mips_opts.micromips);
- macro_build (NULL, "c2", "C", (treg << 16) | 0x02);
+ macro_build (NULL, "c2", "C", (op[0] << 16) | 0x02);
break;
case M_MSGWAIT:
case M_MSGWAIT_T:
gas_assert (!mips_opts.micromips);
- macro_build (NULL, "c2", "C", (treg << 16) | 0x03);
+ macro_build (NULL, "c2", "C", (op[0] << 16) | 0x03);
break;
case M_J_A:
generating PIC code they expand to multi-instruction
sequences. Normally they are simple instructions. */
case M_JALS_1:
- dreg = RA;
+ op[1] = op[0];
+ op[0] = RA;
/* Fall through. */
case M_JALS_2:
gas_assert (mips_opts.micromips);
if (mips_opts.insn32)
{
- as_bad (_("Opcode not supported in the `insn32' mode `%s'"), str);
+ as_bad (_("opcode not supported in the `insn32' mode `%s'"), str);
break;
}
jals = 1;
goto jal;
case M_JAL_1:
- dreg = RA;
+ op[1] = op[0];
+ op[0] = RA;
/* Fall through. */
case M_JAL_2:
jal:
s = jals ? "jalrs" : "jalr";
if (mips_opts.micromips
&& !mips_opts.insn32
- && dreg == RA
+ && op[0] == RA
&& !(history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT))
- macro_build (NULL, s, "mj", sreg);
+ macro_build (NULL, s, "mj", op[1]);
else
- macro_build (NULL, s, JALR_FMT, dreg, sreg);
+ macro_build (NULL, s, JALR_FMT, op[0], op[1]);
}
else
{
int cprestore = (mips_pic == SVR4_PIC && !HAVE_NEWABI
&& mips_cprestore_offset >= 0);
- if (sreg != PIC_CALL_REG)
+ if (op[1] != PIC_CALL_REG)
as_warn (_("MIPS PIC call to register other than $25"));
s = ((mips_opts.micromips
? "jalrs" : "jalr");
if (mips_opts.micromips
&& !mips_opts.insn32
- && dreg == RA
+ && op[0] == RA
&& !(history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT))
- macro_build (NULL, s, "mj", sreg);
+ macro_build (NULL, s, "mj", op[1]);
else
- macro_build (NULL, s, JALR_FMT, dreg, sreg);
+ macro_build (NULL, s, JALR_FMT, op[0], op[1]);
if (mips_pic == SVR4_PIC && !HAVE_NEWABI)
{
if (mips_cprestore_offset < 0)
- as_warn (_("No .cprestore pseudo-op used in PIC code"));
+ as_warn (_("no .cprestore pseudo-op used in PIC code"));
else
{
if (!mips_frame_reg_valid)
{
- as_warn (_("No .frame pseudo-op used in PIC code"));
+ as_warn (_("no .frame pseudo-op used in PIC code"));
/* Quiet this warning. */
mips_frame_reg_valid = 1;
}
if (!mips_cprestore_valid)
{
- as_warn (_("No .cprestore pseudo-op used in PIC code"));
+ as_warn (_("no .cprestore pseudo-op used in PIC code"));
/* Quiet this warning. */
mips_cprestore_valid = 1;
}
gas_assert (mips_opts.micromips);
if (mips_opts.insn32)
{
- as_bad (_("Opcode not supported in the `insn32' mode `%s'"), str);
+ as_bad (_("opcode not supported in the `insn32' mode `%s'"), str);
break;
}
jals = 1;
macro_build_jalr (&offset_expr, mips_cprestore_offset >= 0);
if (mips_cprestore_offset < 0)
- as_warn (_("No .cprestore pseudo-op used in PIC code"));
+ as_warn (_("no .cprestore pseudo-op used in PIC code"));
else
{
if (!mips_frame_reg_valid)
{
- as_warn (_("No .frame pseudo-op used in PIC code"));
+ as_warn (_("no .frame pseudo-op used in PIC code"));
/* Quiet this warning. */
mips_frame_reg_valid = 1;
}
if (!mips_cprestore_valid)
{
- as_warn (_("No .cprestore pseudo-op used in PIC code"));
+ as_warn (_("no .cprestore pseudo-op used in PIC code"));
/* Quiet this warning. */
mips_cprestore_valid = 1;
}
}
}
else if (mips_pic == VXWORKS_PIC)
- as_bad (_("Non-PIC jump used in PIC library"));
+ as_bad (_("non-PIC jump used in PIC library"));
else
abort ();
goto ld_st;
case M_ACLR_AB:
s = "aclr";
- treg = EXTRACT_OPERAND (mips_opts.micromips, 3BITPOS, *ip);
fmt = "\\,~(b)";
offbits = 12;
goto ld_st;
case M_ASET_AB:
s = "aset";
- treg = EXTRACT_OPERAND (mips_opts.micromips, 3BITPOS, *ip);
fmt = "\\,~(b)";
offbits = 12;
goto ld_st;
goto ld_st;
case M_LQC2_AB:
s = "lqc2";
- fmt = "E,o(b)";
+ fmt = "+7,o(b)";
/* Itbl support may require additional care here. */
coproc = 1;
goto ld_st;
ld:
/* We don't want to use $0 as tempreg. */
- if (breg == treg + lp || treg + lp == ZERO)
+ if (op[2] == op[0] + lp || op[0] + lp == ZERO)
goto ld_st;
else
- tempreg = treg + lp;
+ tempreg = op[0] + lp;
goto ld_noat;
case M_SB_AB:
goto ld_st;
case M_SQC2_AB:
s = "sqc2";
- fmt = "E,o(b)";
+ fmt = "+7,o(b)";
/* Itbl support may require additional care here. */
coproc = 1;
goto ld_st;
ld_st:
tempreg = AT;
ld_noat:
+ breg = op[2];
if (small_offset_p (0, align, 16))
{
/* The first case exists for M_LD_AB and M_SD_AB, which are
macros for o32 but which should act like normal instructions
otherwise. */
if (offbits == 16)
- macro_build (&offset_expr, s, fmt, treg, -1, offset_reloc[0],
+ macro_build (&offset_expr, s, fmt, op[0], -1, offset_reloc[0],
offset_reloc[1], offset_reloc[2], breg);
else if (small_offset_p (0, align, offbits))
{
if (offbits == 0)
- macro_build (NULL, s, fmt, treg, breg);
+ macro_build (NULL, s, fmt, op[0], breg);
else
- macro_build (NULL, s, fmt, treg,
+ macro_build (NULL, s, fmt, op[0],
(int) offset_expr.X_add_number, breg);
}
else
tempreg, breg, -1, offset_reloc[0],
offset_reloc[1], offset_reloc[2]);
if (offbits == 0)
- macro_build (NULL, s, fmt, treg, tempreg);
+ macro_build (NULL, s, fmt, op[0], tempreg);
else
- macro_build (NULL, s, fmt, treg, 0, tempreg);
+ macro_build (NULL, s, fmt, op[0], 0, tempreg);
}
break;
}
if (offset_expr.X_op != O_constant
&& offset_expr.X_op != O_symbol)
{
- as_bad (_("Expression too complex"));
+ as_bad (_("expression too complex"));
offset_expr.X_op = O_constant;
}
char value [32];
sprintf_vma (value, offset_expr.X_add_number);
- as_bad (_("Number (0x%s) larger than 32 bits"), value);
+ as_bad (_("number (0x%s) larger than 32 bits"), value);
}
/* A constant expression in PIC code can be handled just as it
if (offset_expr.X_add_number != 0)
macro_build (&offset_expr, ADDRESS_ADDI_INSN,
"t,r,j", tempreg, tempreg, BFD_RELOC_LO16);
- macro_build (NULL, s, fmt, treg, tempreg);
+ macro_build (NULL, s, fmt, op[0], tempreg);
}
else if (offbits == 16)
- macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16, tempreg);
+ macro_build (&offset_expr, s, fmt, op[0], BFD_RELOC_LO16, tempreg);
else
- macro_build (NULL, s, fmt, treg,
+ macro_build (NULL, s, fmt, op[0],
(int) offset_expr.X_add_number, tempreg);
}
else if (offbits != 16)
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
tempreg, tempreg, breg);
if (offbits == 0)
- macro_build (NULL, s, fmt, treg, tempreg);
+ macro_build (NULL, s, fmt, op[0], tempreg);
else
- macro_build (NULL, s, fmt, treg, 0, tempreg);
+ macro_build (NULL, s, fmt, op[0], 0, tempreg);
}
else if (mips_pic == NO_PIC)
{
/* If this is a reference to a GP relative symbol, and there
is no base register, we want
- <op> $treg,<sym>($gp) (BFD_RELOC_GPREL16)
+ <op> op[0],<sym>($gp) (BFD_RELOC_GPREL16)
Otherwise, if there is no base register, we want
lui $tempreg,<sym> (BFD_RELOC_HI16_S)
- <op> $treg,<sym>($tempreg) (BFD_RELOC_LO16)
+ <op> op[0],<sym>($tempreg) (BFD_RELOC_LO16)
If we have a constant, we need two instructions anyhow,
so we always use the latter form.
If we have a base register, and this is a reference to a
GP relative symbol, we want
addu $tempreg,$breg,$gp
- <op> $treg,<sym>($tempreg) (BFD_RELOC_GPREL16)
+ <op> op[0],<sym>($tempreg) (BFD_RELOC_GPREL16)
Otherwise we want
lui $tempreg,<sym> (BFD_RELOC_HI16_S)
addu $tempreg,$tempreg,$breg
- <op> $treg,<sym>($tempreg) (BFD_RELOC_LO16)
+ <op> op[0],<sym>($tempreg) (BFD_RELOC_LO16)
With a constant we always use the latter case.
With 64bit address space and no base register and $at usable,
daddiu $tempreg,<sym> (BFD_RELOC_MIPS_HIGHER)
dsll32 $tempreg,0
daddu $tempreg,$at
- <op> $treg,<sym>($tempreg) (BFD_RELOC_LO16)
+ <op> op[0],<sym>($tempreg) (BFD_RELOC_LO16)
If we have a base register, we want
lui $tempreg,<sym> (BFD_RELOC_MIPS_HIGHEST)
lui $at,<sym> (BFD_RELOC_HI16_S)
daddu $at,$breg
dsll32 $tempreg,0
daddu $tempreg,$at
- <op> $treg,<sym>($tempreg) (BFD_RELOC_LO16)
+ <op> op[0],<sym>($tempreg) (BFD_RELOC_LO16)
Without $at we can't generate the optimal path for superscalar
processors here since this would require two temporary registers.
dsll $tempreg,16
daddiu $tempreg,<sym> (BFD_RELOC_HI16_S)
dsll $tempreg,16
- <op> $treg,<sym>($tempreg) (BFD_RELOC_LO16)
+ <op> op[0],<sym>($tempreg) (BFD_RELOC_LO16)
If we have a base register, we want
lui $tempreg,<sym> (BFD_RELOC_MIPS_HIGHEST)
daddiu $tempreg,<sym> (BFD_RELOC_MIPS_HIGHER)
daddiu $tempreg,<sym> (BFD_RELOC_HI16_S)
dsll $tempreg,16
daddu $tempreg,$tempreg,$breg
- <op> $treg,<sym>($tempreg) (BFD_RELOC_LO16)
+ <op> op[0],<sym>($tempreg) (BFD_RELOC_LO16)
For GP relative symbols in 64bit address space we can use
the same sequence as in 32bit address space. */
relax_start (offset_expr.X_add_symbol);
if (breg == 0)
{
- macro_build (&offset_expr, s, fmt, treg,
+ macro_build (&offset_expr, s, fmt, op[0],
BFD_RELOC_GPREL16, mips_gp_register);
}
else
{
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
tempreg, breg, mips_gp_register);
- macro_build (&offset_expr, s, fmt, treg,
+ macro_build (&offset_expr, s, fmt, op[0],
BFD_RELOC_GPREL16, tempreg);
}
relax_switch ();
macro_build (NULL, "daddu", "d,v,t", AT, AT, breg);
macro_build (NULL, "dsll32", SHFT_FMT, tempreg, tempreg, 0);
macro_build (NULL, "daddu", "d,v,t", tempreg, tempreg, AT);
- macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16,
+ macro_build (&offset_expr, s, fmt, op[0], BFD_RELOC_LO16,
tempreg);
used_at = 1;
}
if (breg != 0)
macro_build (NULL, "daddu", "d,v,t",
tempreg, tempreg, breg);
- macro_build (&offset_expr, s, fmt, treg,
+ macro_build (&offset_expr, s, fmt, op[0],
BFD_RELOC_LO16, tempreg);
}
&& !nopic_need_relax (offset_expr.X_add_symbol, 1))
{
relax_start (offset_expr.X_add_symbol);
- macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_GPREL16,
+ macro_build (&offset_expr, s, fmt, op[0], BFD_RELOC_GPREL16,
mips_gp_register);
relax_switch ();
}
macro_build_lui (&offset_expr, tempreg);
- macro_build (&offset_expr, s, fmt, treg,
+ macro_build (&offset_expr, s, fmt, op[0],
BFD_RELOC_LO16, tempreg);
if (mips_relax.sequence)
relax_end ();
relax_start (offset_expr.X_add_symbol);
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
tempreg, breg, mips_gp_register);
- macro_build (&offset_expr, s, fmt, treg,
+ macro_build (&offset_expr, s, fmt, op[0],
BFD_RELOC_GPREL16, tempreg);
relax_switch ();
}
macro_build_lui (&offset_expr, tempreg);
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
tempreg, tempreg, breg);
- macro_build (&offset_expr, s, fmt, treg,
+ macro_build (&offset_expr, s, fmt, op[0],
BFD_RELOC_LO16, tempreg);
if (mips_relax.sequence)
relax_end ();
/* If this is a reference to an external symbol, we want
lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT16)
nop
- <op> $treg,0($tempreg)
+ <op> op[0],0($tempreg)
Otherwise we want
lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT16)
nop
addiu $tempreg,$tempreg,<sym> (BFD_RELOC_LO16)
- <op> $treg,0($tempreg)
+ <op> op[0],0($tempreg)
For NewABI, we want
lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT_PAGE)
- <op> $treg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_OFST)
+ <op> op[0],<sym>($tempreg) (BFD_RELOC_MIPS_GOT_OFST)
If there is a base register, we add it to $tempreg before
the <op>. If there is a constant, we stick it in the
if (breg != 0)
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
tempreg, tempreg, breg);
- macro_build (&offset_expr, s, fmt, treg,
+ macro_build (&offset_expr, s, fmt, op[0],
BFD_RELOC_MIPS_GOT_OFST, tempreg);
break;
}
if (breg != 0)
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
tempreg, tempreg, breg);
- macro_build (&expr1, s, fmt, treg, BFD_RELOC_LO16, tempreg);
+ macro_build (&expr1, s, fmt, op[0], BFD_RELOC_LO16, tempreg);
}
else if (mips_big_got && !HAVE_NEWABI)
{
lui $tempreg,<sym> (BFD_RELOC_MIPS_GOT_HI16)
addu $tempreg,$tempreg,$gp
lw $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
- <op> $treg,0($tempreg)
+ <op> op[0],0($tempreg)
Otherwise we want
lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT16)
nop
addiu $tempreg,$tempreg,<sym> (BFD_RELOC_LO16)
- <op> $treg,0($tempreg)
+ <op> op[0],0($tempreg)
If there is a base register, we add it to $tempreg before
the <op>. If there is a constant, we stick it in the
<op> instruction. We don't handle constants larger than
if (breg != 0)
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
tempreg, tempreg, breg);
- macro_build (&expr1, s, fmt, treg, BFD_RELOC_LO16, tempreg);
+ macro_build (&expr1, s, fmt, op[0], BFD_RELOC_LO16, tempreg);
}
else if (mips_big_got && HAVE_NEWABI)
{
lui $tempreg,<sym> (BFD_RELOC_MIPS_GOT_HI16)
add $tempreg,$tempreg,$gp
lw $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
- <op> $treg,<ofst>($tempreg)
+ <op> op[0],<ofst>($tempreg)
Otherwise, for local symbols, we want:
lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT_PAGE)
- <op> $treg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_OFST) */
+ <op> op[0],<sym>($tempreg) (BFD_RELOC_MIPS_GOT_OFST) */
gas_assert (offset_expr.X_op == O_symbol);
expr1.X_add_number = offset_expr.X_add_number;
offset_expr.X_add_number = 0;
if (breg != 0)
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
tempreg, tempreg, breg);
- macro_build (&expr1, s, fmt, treg, BFD_RELOC_LO16, tempreg);
+ macro_build (&expr1, s, fmt, op[0], BFD_RELOC_LO16, tempreg);
relax_switch ();
offset_expr.X_add_number = expr1.X_add_number;
if (breg != 0)
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
tempreg, tempreg, breg);
- macro_build (&offset_expr, s, fmt, treg,
+ macro_build (&offset_expr, s, fmt, op[0],
BFD_RELOC_MIPS_GOT_OFST, tempreg);
relax_end ();
}
gas_assert (mips_opts.insn32);
start_noreorder ();
macro_build (NULL, "jr", "s", RA);
- expr1.X_add_number = EXTRACT_OPERAND (1, IMMP, *ip) << 2;
+ expr1.X_add_number = op[0] << 2;
macro_build (&expr1, "addiu", "t,r,j", SP, SP, BFD_RELOC_LO16);
end_noreorder ();
break;
case M_JRC:
gas_assert (mips_opts.micromips);
gas_assert (mips_opts.insn32);
- macro_build (NULL, "jr", "s", sreg);
+ macro_build (NULL, "jr", "s", op[0]);
if (mips_opts.noreorder)
macro_build (NULL, "nop", "");
break;
case M_LI:
case M_LI_S:
- load_register (treg, &imm_expr, 0);
+ load_register (op[0], &imm_expr, 0);
break;
case M_DLI:
- load_register (treg, &imm_expr, 1);
+ load_register (op[0], &imm_expr, 1);
break;
case M_LI_SS:
{
used_at = 1;
load_register (AT, &imm_expr, 0);
- macro_build (NULL, "mtc1", "t,G", AT, treg);
+ macro_build (NULL, "mtc1", "t,G", AT, op[0]);
break;
}
else
{
- gas_assert (offset_expr.X_op == O_symbol
+ gas_assert (imm_expr.X_op == O_absent
+ && offset_expr.X_op == O_symbol
&& strcmp (segment_name (S_GET_SEGMENT
(offset_expr.X_add_symbol)),
".lit4") == 0
&& offset_expr.X_add_number == 0);
- macro_build (&offset_expr, "lwc1", "T,o(b)", treg,
+ macro_build (&offset_expr, "lwc1", "T,o(b)", op[0],
BFD_RELOC_MIPS_LITERAL, mips_gp_register);
break;
}
wide, IMM_EXPR is the entire value. Otherwise IMM_EXPR is the high
order 32 bits of the value and the low order 32 bits are either
zero or in OFFSET_EXPR. */
- if (imm_expr.X_op == O_constant || imm_expr.X_op == O_big)
+ if (imm_expr.X_op == O_constant)
{
if (HAVE_64BIT_GPRS)
- load_register (treg, &imm_expr, 1);
+ load_register (op[0], &imm_expr, 1);
else
{
int hreg, lreg;
if (target_big_endian)
{
- hreg = treg;
- lreg = treg + 1;
+ hreg = op[0];
+ lreg = op[0] + 1;
}
else
{
- hreg = treg + 1;
- lreg = treg;
+ hreg = op[0] + 1;
+ lreg = op[0];
}
if (hreg <= 31)
}
break;
}
+ gas_assert (imm_expr.X_op == O_absent);
/* We know that sym is in the .rdata section. First we get the
upper 16 bits of the address. */
if (HAVE_64BIT_GPRS)
{
used_at = 1;
- macro_build (&offset_expr, "ld", "t,o(b)", treg, BFD_RELOC_LO16, AT);
+ macro_build (&offset_expr, "ld", "t,o(b)", op[0],
+ BFD_RELOC_LO16, AT);
}
else
{
used_at = 1;
- macro_build (&offset_expr, "lw", "t,o(b)", treg, BFD_RELOC_LO16, AT);
- if (treg != RA)
+ macro_build (&offset_expr, "lw", "t,o(b)", op[0],
+ BFD_RELOC_LO16, AT);
+ if (op[0] != RA)
{
/* FIXME: How in the world do we deal with the possible
overflow here? */
offset_expr.X_add_number += 4;
macro_build (&offset_expr, "lw", "t,o(b)",
- treg + 1, BFD_RELOC_LO16, AT);
+ op[0] + 1, BFD_RELOC_LO16, AT);
}
}
break;
bits wide as well. Otherwise IMM_EXPR is the high order 32 bits of
the value and the low order 32 bits are either zero or in
OFFSET_EXPR. */
- if (imm_expr.X_op == O_constant || imm_expr.X_op == O_big)
+ if (imm_expr.X_op == O_constant)
{
used_at = 1;
load_register (AT, &imm_expr, HAVE_64BIT_FPRS);
if (HAVE_64BIT_FPRS)
{
gas_assert (HAVE_64BIT_GPRS);
- macro_build (NULL, "dmtc1", "t,S", AT, treg);
+ macro_build (NULL, "dmtc1", "t,S", AT, op[0]);
}
else
{
- macro_build (NULL, "mtc1", "t,G", AT, treg + 1);
+ macro_build (NULL, "mtc1", "t,G", AT, op[0] + 1);
if (offset_expr.X_op == O_absent)
- macro_build (NULL, "mtc1", "t,G", 0, treg);
+ macro_build (NULL, "mtc1", "t,G", 0, op[0]);
else
{
gas_assert (offset_expr.X_op == O_constant);
load_register (AT, &offset_expr, 0);
- macro_build (NULL, "mtc1", "t,G", AT, treg);
+ macro_build (NULL, "mtc1", "t,G", AT, op[0]);
}
}
break;
}
- gas_assert (offset_expr.X_op == O_symbol
+ gas_assert (imm_expr.X_op == O_absent
+ && offset_expr.X_op == O_symbol
&& offset_expr.X_add_number == 0);
s = segment_name (S_GET_SEGMENT (offset_expr.X_add_symbol));
if (strcmp (s, ".lit8") == 0)
{
- breg = mips_gp_register;
+ op[2] = mips_gp_register;
offset_reloc[0] = BFD_RELOC_MIPS_LITERAL;
offset_reloc[1] = BFD_RELOC_UNUSED;
offset_reloc[2] = BFD_RELOC_UNUSED;
macro_build_lui (&offset_expr, AT);
}
- breg = AT;
+ op[2] = AT;
offset_reloc[0] = BFD_RELOC_LO16;
offset_reloc[1] = BFD_RELOC_UNUSED;
offset_reloc[2] = BFD_RELOC_UNUSED;
if (!target_big_endian)
coproc = 0;
+ breg = op[2];
if (small_offset_p (0, align, 16))
{
ep = &offset_expr;
offset_reloc[1] = BFD_RELOC_UNUSED;
offset_reloc[2] = BFD_RELOC_UNUSED;
}
- if (strcmp (s, "lw") == 0 && treg == breg)
+ if (strcmp (s, "lw") == 0 && op[0] == breg)
{
ep->X_add_number += 4;
- macro_build (ep, s, fmt, treg + 1, -1, offset_reloc[0],
+ macro_build (ep, s, fmt, op[0] + 1, -1, offset_reloc[0],
offset_reloc[1], offset_reloc[2], breg);
ep->X_add_number -= 4;
- macro_build (ep, s, fmt, treg, -1, offset_reloc[0],
+ macro_build (ep, s, fmt, op[0], -1, offset_reloc[0],
offset_reloc[1], offset_reloc[2], breg);
}
else
{
- macro_build (ep, s, fmt, coproc ? treg + 1 : treg, -1,
+ macro_build (ep, s, fmt, coproc ? op[0] + 1 : op[0], -1,
offset_reloc[0], offset_reloc[1], offset_reloc[2],
breg);
ep->X_add_number += 4;
- macro_build (ep, s, fmt, coproc ? treg : treg + 1, -1,
+ macro_build (ep, s, fmt, coproc ? op[0] : op[0] + 1, -1,
offset_reloc[0], offset_reloc[1], offset_reloc[2],
breg);
}
if (offset_expr.X_op != O_symbol
&& offset_expr.X_op != O_constant)
{
- as_bad (_("Expression too complex"));
+ as_bad (_("expression too complex"));
offset_expr.X_op = O_constant;
}
char value [32];
sprintf_vma (value, offset_expr.X_add_number);
- as_bad (_("Number (0x%s) larger than 32 bits"), value);
+ as_bad (_("number (0x%s) larger than 32 bits"), value);
}
if (mips_pic == NO_PIC || offset_expr.X_op == O_constant)
{
/* If this is a reference to a GP relative symbol, we want
- <op> $treg,<sym>($gp) (BFD_RELOC_GPREL16)
- <op> $treg+1,<sym>+4($gp) (BFD_RELOC_GPREL16)
+ <op> op[0],<sym>($gp) (BFD_RELOC_GPREL16)
+ <op> op[0]+1,<sym>+4($gp) (BFD_RELOC_GPREL16)
If we have a base register, we use this
addu $at,$breg,$gp
- <op> $treg,<sym>($at) (BFD_RELOC_GPREL16)
- <op> $treg+1,<sym>+4($at) (BFD_RELOC_GPREL16)
+ <op> op[0],<sym>($at) (BFD_RELOC_GPREL16)
+ <op> op[0]+1,<sym>+4($at) (BFD_RELOC_GPREL16)
If this is not a GP relative symbol, we want
lui $at,<sym> (BFD_RELOC_HI16_S)
- <op> $treg,<sym>($at) (BFD_RELOC_LO16)
- <op> $treg+1,<sym>+4($at) (BFD_RELOC_LO16)
+ <op> op[0],<sym>($at) (BFD_RELOC_LO16)
+ <op> op[0]+1,<sym>+4($at) (BFD_RELOC_LO16)
If there is a base register, we add it to $at after the
lui instruction. If there is a constant, we always use
the last case. */
}
/* Itbl support may require additional care here. */
- macro_build (&offset_expr, s, fmt, coproc ? treg + 1 : treg,
+ macro_build (&offset_expr, s, fmt, coproc ? op[0] + 1 : op[0],
BFD_RELOC_GPREL16, tempreg);
offset_expr.X_add_number += 4;
hold_mips_optimize = mips_optimize;
mips_optimize = 2;
/* Itbl support may require additional care here. */
- macro_build (&offset_expr, s, fmt, coproc ? treg : treg + 1,
+ macro_build (&offset_expr, s, fmt, coproc ? op[0] : op[0] + 1,
BFD_RELOC_GPREL16, tempreg);
mips_optimize = hold_mips_optimize;
if (breg != 0)
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, breg, AT);
/* Itbl support may require additional care here. */
- macro_build (&offset_expr, s, fmt, coproc ? treg + 1 : treg,
+ macro_build (&offset_expr, s, fmt, coproc ? op[0] + 1 : op[0],
BFD_RELOC_LO16, AT);
/* FIXME: How do we handle overflow here? */
offset_expr.X_add_number += 4;
/* Itbl support may require additional care here. */
- macro_build (&offset_expr, s, fmt, coproc ? treg : treg + 1,
+ macro_build (&offset_expr, s, fmt, coproc ? op[0] : op[0] + 1,
BFD_RELOC_LO16, AT);
if (mips_relax.sequence)
relax_end ();
/* If this is a reference to an external symbol, we want
lw $at,<sym>($gp) (BFD_RELOC_MIPS_GOT16)
nop
- <op> $treg,0($at)
- <op> $treg+1,4($at)
+ <op> op[0],0($at)
+ <op> op[0]+1,4($at)
Otherwise we want
lw $at,<sym>($gp) (BFD_RELOC_MIPS_GOT16)
nop
- <op> $treg,<sym>($at) (BFD_RELOC_LO16)
- <op> $treg+1,<sym>+4($at) (BFD_RELOC_LO16)
+ <op> op[0],<sym>($at) (BFD_RELOC_LO16)
+ <op> op[0]+1,<sym>+4($at) (BFD_RELOC_LO16)
If there is a base register we add it to $at before the
lwc1 instructions. If there is a constant we include it
in the lwc1 instructions. */
/* Itbl support may require additional care here. */
relax_start (offset_expr.X_add_symbol);
- macro_build (&expr1, s, fmt, coproc ? treg + 1 : treg,
+ macro_build (&expr1, s, fmt, coproc ? op[0] + 1 : op[0],
BFD_RELOC_LO16, AT);
expr1.X_add_number += 4;
- macro_build (&expr1, s, fmt, coproc ? treg : treg + 1,
+ macro_build (&expr1, s, fmt, coproc ? op[0] : op[0] + 1,
BFD_RELOC_LO16, AT);
relax_switch ();
- macro_build (&offset_expr, s, fmt, coproc ? treg + 1 : treg,
+ macro_build (&offset_expr, s, fmt, coproc ? op[0] + 1 : op[0],
BFD_RELOC_LO16, AT);
offset_expr.X_add_number += 4;
- macro_build (&offset_expr, s, fmt, coproc ? treg : treg + 1,
+ macro_build (&offset_expr, s, fmt, coproc ? op[0] : op[0] + 1,
BFD_RELOC_LO16, AT);
relax_end ();
addu $at,$at,$gp
lw $at,<sym>($at) (BFD_RELOC_MIPS_GOT_LO16)
nop
- <op> $treg,0($at)
- <op> $treg+1,4($at)
+ <op> op[0],0($at)
+ <op> op[0]+1,4($at)
Otherwise we want
lw $at,<sym>($gp) (BFD_RELOC_MIPS_GOT16)
nop
- <op> $treg,<sym>($at) (BFD_RELOC_LO16)
- <op> $treg+1,<sym>+4($at) (BFD_RELOC_LO16)
+ <op> op[0],<sym>($at) (BFD_RELOC_LO16)
+ <op> op[0]+1,<sym>+4($at) (BFD_RELOC_LO16)
If there is a base register we add it to $at before the
lwc1 instructions. If there is a constant we include it
in the lwc1 instructions. */
if (breg != 0)
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, breg, AT);
/* Itbl support may require additional care here. */
- macro_build (&expr1, s, fmt, coproc ? treg + 1 : treg,
+ macro_build (&expr1, s, fmt, coproc ? op[0] + 1 : op[0],
BFD_RELOC_LO16, AT);
expr1.X_add_number += 4;
hold_mips_optimize = mips_optimize;
mips_optimize = 2;
/* Itbl support may require additional care here. */
- macro_build (&expr1, s, fmt, coproc ? treg : treg + 1,
+ macro_build (&expr1, s, fmt, coproc ? op[0] : op[0] + 1,
BFD_RELOC_LO16, AT);
mips_optimize = hold_mips_optimize;
expr1.X_add_number -= 4;
if (breg != 0)
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, breg, AT);
/* Itbl support may require additional care here. */
- macro_build (&offset_expr, s, fmt, coproc ? treg + 1 : treg,
+ macro_build (&offset_expr, s, fmt, coproc ? op[0] + 1 : op[0],
BFD_RELOC_LO16, AT);
offset_expr.X_add_number += 4;
hold_mips_optimize = mips_optimize;
mips_optimize = 2;
/* Itbl support may require additional care here. */
- macro_build (&offset_expr, s, fmt, coproc ? treg : treg + 1,
+ macro_build (&offset_expr, s, fmt, coproc ? op[0] : op[0] + 1,
BFD_RELOC_LO16, AT);
mips_optimize = hold_mips_optimize;
relax_end ();
break;
case M_MOVE:
- move_register (dreg, sreg);
+ move_register (op[0], op[1]);
break;
case M_MOVEP:
gas_assert (mips_opts.micromips);
gas_assert (mips_opts.insn32);
- dreg = micromips_to_32_reg_h_map1[EXTRACT_OPERAND (1, MH, *ip)];
- breg = micromips_to_32_reg_h_map2[EXTRACT_OPERAND (1, MH, *ip)];
- sreg = micromips_to_32_reg_m_map[EXTRACT_OPERAND (1, MM, *ip)];
- treg = micromips_to_32_reg_n_map[EXTRACT_OPERAND (1, MN, *ip)];
- move_register (dreg, sreg);
- move_register (breg, treg);
+ move_register (micromips_to_32_reg_h_map1[op[0]],
+ micromips_to_32_reg_m_map[op[1]]);
+ move_register (micromips_to_32_reg_h_map2[op[0]],
+ micromips_to_32_reg_n_map[op[2]]);
break;
case M_DMUL:
dbl = 1;
case M_MUL:
if (mips_opts.arch == CPU_R5900)
- {
- macro_build (NULL, dbl ? "dmultu" : "multu", "d,s,t", dreg, sreg, treg);
- }
+ macro_build (NULL, dbl ? "dmultu" : "multu", "d,s,t", op[0], op[1],
+ op[2]);
else
{
- macro_build (NULL, dbl ? "dmultu" : "multu", "s,t", sreg, treg);
- macro_build (NULL, "mflo", MFHL_FMT, dreg);
+ macro_build (NULL, dbl ? "dmultu" : "multu", "s,t", op[1], op[2]);
+ macro_build (NULL, "mflo", MFHL_FMT, op[0]);
}
break;
anyway. */
used_at = 1;
load_register (AT, &imm_expr, dbl);
- macro_build (NULL, dbl ? "dmult" : "mult", "s,t", sreg, AT);
- macro_build (NULL, "mflo", MFHL_FMT, dreg);
+ macro_build (NULL, dbl ? "dmult" : "mult", "s,t", op[1], AT);
+ macro_build (NULL, "mflo", MFHL_FMT, op[0]);
break;
case M_DMULO_I:
used_at = 1;
if (imm)
load_register (AT, &imm_expr, dbl);
- macro_build (NULL, dbl ? "dmult" : "mult", "s,t", sreg, imm ? AT : treg);
- macro_build (NULL, "mflo", MFHL_FMT, dreg);
- macro_build (NULL, dbl ? "dsra32" : "sra", SHFT_FMT, dreg, dreg, RA);
+ macro_build (NULL, dbl ? "dmult" : "mult", "s,t",
+ op[1], imm ? AT : op[2]);
+ macro_build (NULL, "mflo", MFHL_FMT, op[0]);
+ macro_build (NULL, dbl ? "dsra32" : "sra", SHFT_FMT, op[0], op[0], 31);
macro_build (NULL, "mfhi", MFHL_FMT, AT);
if (mips_trap)
- macro_build (NULL, "tne", TRAP_FMT, dreg, AT, 6);
+ macro_build (NULL, "tne", TRAP_FMT, op[0], AT, 6);
else
{
if (mips_opts.micromips)
micromips_label_expr (&label_expr);
else
label_expr.X_add_number = 8;
- macro_build (&label_expr, "beq", "s,t,p", dreg, AT);
+ macro_build (&label_expr, "beq", "s,t,p", op[0], AT);
macro_build (NULL, "nop", "");
macro_build (NULL, "break", BRK_FMT, 6);
if (mips_opts.micromips)
micromips_add_label ();
}
end_noreorder ();
- macro_build (NULL, "mflo", MFHL_FMT, dreg);
+ macro_build (NULL, "mflo", MFHL_FMT, op[0]);
break;
case M_DMULOU_I:
if (imm)
load_register (AT, &imm_expr, dbl);
macro_build (NULL, dbl ? "dmultu" : "multu", "s,t",
- sreg, imm ? AT : treg);
+ op[1], imm ? AT : op[2]);
macro_build (NULL, "mfhi", MFHL_FMT, AT);
- macro_build (NULL, "mflo", MFHL_FMT, dreg);
+ macro_build (NULL, "mflo", MFHL_FMT, op[0]);
if (mips_trap)
macro_build (NULL, "tne", TRAP_FMT, AT, ZERO, 6);
else
case M_DROL:
if (ISA_HAS_DROR (mips_opts.isa) || CPU_HAS_DROR (mips_opts.arch))
{
- if (dreg == sreg)
+ if (op[0] == op[1])
{
tempreg = AT;
used_at = 1;
}
- else
- {
- tempreg = dreg;
- }
- macro_build (NULL, "dnegu", "d,w", tempreg, treg);
- macro_build (NULL, "drorv", "d,t,s", dreg, sreg, tempreg);
+ else
+ tempreg = op[0];
+ macro_build (NULL, "dnegu", "d,w", tempreg, op[2]);
+ macro_build (NULL, "drorv", "d,t,s", op[0], op[1], tempreg);
break;
}
used_at = 1;
- macro_build (NULL, "dsubu", "d,v,t", AT, ZERO, treg);
- macro_build (NULL, "dsrlv", "d,t,s", AT, sreg, AT);
- macro_build (NULL, "dsllv", "d,t,s", dreg, sreg, treg);
- macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
+ macro_build (NULL, "dsubu", "d,v,t", AT, ZERO, op[2]);
+ macro_build (NULL, "dsrlv", "d,t,s", AT, op[1], AT);
+ macro_build (NULL, "dsllv", "d,t,s", op[0], op[1], op[2]);
+ macro_build (NULL, "or", "d,v,t", op[0], op[0], AT);
break;
case M_ROL:
if (ISA_HAS_ROR (mips_opts.isa) || CPU_HAS_ROR (mips_opts.arch))
{
- if (dreg == sreg)
+ if (op[0] == op[1])
{
tempreg = AT;
used_at = 1;
}
else
- {
- tempreg = dreg;
- }
- macro_build (NULL, "negu", "d,w", tempreg, treg);
- macro_build (NULL, "rorv", "d,t,s", dreg, sreg, tempreg);
+ tempreg = op[0];
+ macro_build (NULL, "negu", "d,w", tempreg, op[2]);
+ macro_build (NULL, "rorv", "d,t,s", op[0], op[1], tempreg);
break;
}
used_at = 1;
- macro_build (NULL, "subu", "d,v,t", AT, ZERO, treg);
- macro_build (NULL, "srlv", "d,t,s", AT, sreg, AT);
- macro_build (NULL, "sllv", "d,t,s", dreg, sreg, treg);
- macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
+ macro_build (NULL, "subu", "d,v,t", AT, ZERO, op[2]);
+ macro_build (NULL, "srlv", "d,t,s", AT, op[1], AT);
+ macro_build (NULL, "sllv", "d,t,s", op[0], op[1], op[2]);
+ macro_build (NULL, "or", "d,v,t", op[0], op[0], AT);
break;
case M_DROL_I:
char *l;
char *rr;
- if (imm_expr.X_op != O_constant)
- as_bad (_("Improper rotate count"));
rot = imm_expr.X_add_number & 0x3f;
if (ISA_HAS_DROR (mips_opts.isa) || CPU_HAS_DROR (mips_opts.arch))
{
rot = (64 - rot) & 0x3f;
if (rot >= 32)
- macro_build (NULL, "dror32", SHFT_FMT, dreg, sreg, rot - 32);
+ macro_build (NULL, "dror32", SHFT_FMT, op[0], op[1], rot - 32);
else
- macro_build (NULL, "dror", SHFT_FMT, dreg, sreg, rot);
+ macro_build (NULL, "dror", SHFT_FMT, op[0], op[1], rot);
break;
}
if (rot == 0)
{
- macro_build (NULL, "dsrl", SHFT_FMT, dreg, sreg, 0);
+ macro_build (NULL, "dsrl", SHFT_FMT, op[0], op[1], 0);
break;
}
l = (rot < 0x20) ? "dsll" : "dsll32";
rr = ((0x40 - rot) < 0x20) ? "dsrl" : "dsrl32";
rot &= 0x1f;
used_at = 1;
- macro_build (NULL, l, SHFT_FMT, AT, sreg, rot);
- macro_build (NULL, rr, SHFT_FMT, dreg, sreg, (0x20 - rot) & 0x1f);
- macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
+ macro_build (NULL, l, SHFT_FMT, AT, op[1], rot);
+ macro_build (NULL, rr, SHFT_FMT, op[0], op[1], (0x20 - rot) & 0x1f);
+ macro_build (NULL, "or", "d,v,t", op[0], op[0], AT);
}
break;
{
unsigned int rot;
- if (imm_expr.X_op != O_constant)
- as_bad (_("Improper rotate count"));
rot = imm_expr.X_add_number & 0x1f;
if (ISA_HAS_ROR (mips_opts.isa) || CPU_HAS_ROR (mips_opts.arch))
{
- macro_build (NULL, "ror", SHFT_FMT, dreg, sreg, (32 - rot) & 0x1f);
+ macro_build (NULL, "ror", SHFT_FMT, op[0], op[1],
+ (32 - rot) & 0x1f);
break;
}
if (rot == 0)
{
- macro_build (NULL, "srl", SHFT_FMT, dreg, sreg, 0);
+ macro_build (NULL, "srl", SHFT_FMT, op[0], op[1], 0);
break;
}
used_at = 1;
- macro_build (NULL, "sll", SHFT_FMT, AT, sreg, rot);
- macro_build (NULL, "srl", SHFT_FMT, dreg, sreg, (0x20 - rot) & 0x1f);
- macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
+ macro_build (NULL, "sll", SHFT_FMT, AT, op[1], rot);
+ macro_build (NULL, "srl", SHFT_FMT, op[0], op[1], (0x20 - rot) & 0x1f);
+ macro_build (NULL, "or", "d,v,t", op[0], op[0], AT);
}
break;
case M_DROR:
if (ISA_HAS_DROR (mips_opts.isa) || CPU_HAS_DROR (mips_opts.arch))
{
- macro_build (NULL, "drorv", "d,t,s", dreg, sreg, treg);
+ macro_build (NULL, "drorv", "d,t,s", op[0], op[1], op[2]);
break;
}
used_at = 1;
- macro_build (NULL, "dsubu", "d,v,t", AT, ZERO, treg);
- macro_build (NULL, "dsllv", "d,t,s", AT, sreg, AT);
- macro_build (NULL, "dsrlv", "d,t,s", dreg, sreg, treg);
- macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
+ macro_build (NULL, "dsubu", "d,v,t", AT, ZERO, op[2]);
+ macro_build (NULL, "dsllv", "d,t,s", AT, op[1], AT);
+ macro_build (NULL, "dsrlv", "d,t,s", op[0], op[1], op[2]);
+ macro_build (NULL, "or", "d,v,t", op[0], op[0], AT);
break;
case M_ROR:
if (ISA_HAS_ROR (mips_opts.isa) || CPU_HAS_ROR (mips_opts.arch))
{
- macro_build (NULL, "rorv", "d,t,s", dreg, sreg, treg);
+ macro_build (NULL, "rorv", "d,t,s", op[0], op[1], op[2]);
break;
}
used_at = 1;
- macro_build (NULL, "subu", "d,v,t", AT, ZERO, treg);
- macro_build (NULL, "sllv", "d,t,s", AT, sreg, AT);
- macro_build (NULL, "srlv", "d,t,s", dreg, sreg, treg);
- macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
+ macro_build (NULL, "subu", "d,v,t", AT, ZERO, op[2]);
+ macro_build (NULL, "sllv", "d,t,s", AT, op[1], AT);
+ macro_build (NULL, "srlv", "d,t,s", op[0], op[1], op[2]);
+ macro_build (NULL, "or", "d,v,t", op[0], op[0], AT);
break;
case M_DROR_I:
char *l;
char *rr;
- if (imm_expr.X_op != O_constant)
- as_bad (_("Improper rotate count"));
rot = imm_expr.X_add_number & 0x3f;
if (ISA_HAS_DROR (mips_opts.isa) || CPU_HAS_DROR (mips_opts.arch))
{
if (rot >= 32)
- macro_build (NULL, "dror32", SHFT_FMT, dreg, sreg, rot - 32);
+ macro_build (NULL, "dror32", SHFT_FMT, op[0], op[1], rot - 32);
else
- macro_build (NULL, "dror", SHFT_FMT, dreg, sreg, rot);
+ macro_build (NULL, "dror", SHFT_FMT, op[0], op[1], rot);
break;
}
if (rot == 0)
{
- macro_build (NULL, "dsrl", SHFT_FMT, dreg, sreg, 0);
+ macro_build (NULL, "dsrl", SHFT_FMT, op[0], op[1], 0);
break;
}
rr = (rot < 0x20) ? "dsrl" : "dsrl32";
l = ((0x40 - rot) < 0x20) ? "dsll" : "dsll32";
rot &= 0x1f;
used_at = 1;
- macro_build (NULL, rr, SHFT_FMT, AT, sreg, rot);
- macro_build (NULL, l, SHFT_FMT, dreg, sreg, (0x20 - rot) & 0x1f);
- macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
+ macro_build (NULL, rr, SHFT_FMT, AT, op[1], rot);
+ macro_build (NULL, l, SHFT_FMT, op[0], op[1], (0x20 - rot) & 0x1f);
+ macro_build (NULL, "or", "d,v,t", op[0], op[0], AT);
}
break;
{
unsigned int rot;
- if (imm_expr.X_op != O_constant)
- as_bad (_("Improper rotate count"));
rot = imm_expr.X_add_number & 0x1f;
if (ISA_HAS_ROR (mips_opts.isa) || CPU_HAS_ROR (mips_opts.arch))
{
- macro_build (NULL, "ror", SHFT_FMT, dreg, sreg, rot);
+ macro_build (NULL, "ror", SHFT_FMT, op[0], op[1], rot);
break;
}
if (rot == 0)
{
- macro_build (NULL, "srl", SHFT_FMT, dreg, sreg, 0);
+ macro_build (NULL, "srl", SHFT_FMT, op[0], op[1], 0);
break;
}
used_at = 1;
- macro_build (NULL, "srl", SHFT_FMT, AT, sreg, rot);
- macro_build (NULL, "sll", SHFT_FMT, dreg, sreg, (0x20 - rot) & 0x1f);
- macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
+ macro_build (NULL, "srl", SHFT_FMT, AT, op[1], rot);
+ macro_build (NULL, "sll", SHFT_FMT, op[0], op[1], (0x20 - rot) & 0x1f);
+ macro_build (NULL, "or", "d,v,t", op[0], op[0], AT);
}
break;
case M_SEQ:
- if (sreg == 0)
- macro_build (&expr1, "sltiu", "t,r,j", dreg, treg, BFD_RELOC_LO16);
- else if (treg == 0)
- macro_build (&expr1, "sltiu", "t,r,j", dreg, sreg, BFD_RELOC_LO16);
+ if (op[1] == 0)
+ macro_build (&expr1, "sltiu", "t,r,j", op[0], op[2], BFD_RELOC_LO16);
+ else if (op[2] == 0)
+ macro_build (&expr1, "sltiu", "t,r,j", op[0], op[1], BFD_RELOC_LO16);
else
{
- macro_build (NULL, "xor", "d,v,t", dreg, sreg, treg);
- macro_build (&expr1, "sltiu", "t,r,j", dreg, dreg, BFD_RELOC_LO16);
+ macro_build (NULL, "xor", "d,v,t", op[0], op[1], op[2]);
+ macro_build (&expr1, "sltiu", "t,r,j", op[0], op[0], BFD_RELOC_LO16);
}
break;
case M_SEQ_I:
- if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
+ if (imm_expr.X_add_number == 0)
{
- macro_build (&expr1, "sltiu", "t,r,j", dreg, sreg, BFD_RELOC_LO16);
+ macro_build (&expr1, "sltiu", "t,r,j", op[0], op[1], BFD_RELOC_LO16);
break;
}
- if (sreg == 0)
+ if (op[1] == 0)
{
- as_warn (_("Instruction %s: result is always false"),
+ as_warn (_("instruction %s: result is always false"),
ip->insn_mo->name);
- move_register (dreg, 0);
+ move_register (op[0], 0);
break;
}
if (CPU_HAS_SEQ (mips_opts.arch)
&& -512 <= imm_expr.X_add_number
&& imm_expr.X_add_number < 512)
{
- macro_build (NULL, "seqi", "t,r,+Q", dreg, sreg,
+ macro_build (NULL, "seqi", "t,r,+Q", op[0], op[1],
(int) imm_expr.X_add_number);
break;
}
- if (imm_expr.X_op == O_constant
- && imm_expr.X_add_number >= 0
+ if (imm_expr.X_add_number >= 0
&& imm_expr.X_add_number < 0x10000)
- {
- macro_build (&imm_expr, "xori", "t,r,i", dreg, sreg, BFD_RELOC_LO16);
- }
- else if (imm_expr.X_op == O_constant
- && imm_expr.X_add_number > -0x8000
+ macro_build (&imm_expr, "xori", "t,r,i", op[0], op[1], BFD_RELOC_LO16);
+ else if (imm_expr.X_add_number > -0x8000
&& imm_expr.X_add_number < 0)
{
imm_expr.X_add_number = -imm_expr.X_add_number;
macro_build (&imm_expr, HAVE_32BIT_GPRS ? "addiu" : "daddiu",
- "t,r,j", dreg, sreg, BFD_RELOC_LO16);
+ "t,r,j", op[0], op[1], BFD_RELOC_LO16);
}
else if (CPU_HAS_SEQ (mips_opts.arch))
{
used_at = 1;
load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
- macro_build (NULL, "seq", "d,v,t", dreg, sreg, AT);
+ macro_build (NULL, "seq", "d,v,t", op[0], op[1], AT);
break;
}
else
{
load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
- macro_build (NULL, "xor", "d,v,t", dreg, sreg, AT);
+ macro_build (NULL, "xor", "d,v,t", op[0], op[1], AT);
used_at = 1;
}
- macro_build (&expr1, "sltiu", "t,r,j", dreg, dreg, BFD_RELOC_LO16);
+ macro_build (&expr1, "sltiu", "t,r,j", op[0], op[0], BFD_RELOC_LO16);
break;
- case M_SGE: /* sreg >= treg <==> not (sreg < treg) */
+ case M_SGE: /* X >= Y <==> not (X < Y) */
s = "slt";
goto sge;
case M_SGEU:
s = "sltu";
sge:
- macro_build (NULL, s, "d,v,t", dreg, sreg, treg);
- macro_build (&expr1, "xori", "t,r,i", dreg, dreg, BFD_RELOC_LO16);
+ macro_build (NULL, s, "d,v,t", op[0], op[1], op[2]);
+ macro_build (&expr1, "xori", "t,r,i", op[0], op[0], BFD_RELOC_LO16);
break;
- case M_SGE_I: /* sreg >= I <==> not (sreg < I) */
+ case M_SGE_I: /* X >= I <==> not (X < I) */
case M_SGEU_I:
- if (imm_expr.X_op == O_constant
- && imm_expr.X_add_number >= -0x8000
+ if (imm_expr.X_add_number >= -0x8000
&& imm_expr.X_add_number < 0x8000)
- {
- macro_build (&imm_expr, mask == M_SGE_I ? "slti" : "sltiu", "t,r,j",
- dreg, sreg, BFD_RELOC_LO16);
- }
+ macro_build (&imm_expr, mask == M_SGE_I ? "slti" : "sltiu", "t,r,j",
+ op[0], op[1], BFD_RELOC_LO16);
else
{
load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
macro_build (NULL, mask == M_SGE_I ? "slt" : "sltu", "d,v,t",
- dreg, sreg, AT);
+ op[0], op[1], AT);
used_at = 1;
}
- macro_build (&expr1, "xori", "t,r,i", dreg, dreg, BFD_RELOC_LO16);
+ macro_build (&expr1, "xori", "t,r,i", op[0], op[0], BFD_RELOC_LO16);
break;
- case M_SGT: /* sreg > treg <==> treg < sreg */
+ case M_SGT: /* X > Y <==> Y < X */
s = "slt";
goto sgt;
case M_SGTU:
s = "sltu";
sgt:
- macro_build (NULL, s, "d,v,t", dreg, treg, sreg);
+ macro_build (NULL, s, "d,v,t", op[0], op[2], op[1]);
break;
- case M_SGT_I: /* sreg > I <==> I < sreg */
+ case M_SGT_I: /* X > I <==> I < X */
s = "slt";
goto sgti;
case M_SGTU_I:
sgti:
used_at = 1;
load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
- macro_build (NULL, s, "d,v,t", dreg, AT, sreg);
+ macro_build (NULL, s, "d,v,t", op[0], AT, op[1]);
break;
- case M_SLE: /* sreg <= treg <==> treg >= sreg <==> not (treg < sreg) */
+ case M_SLE: /* X <= Y <==> Y >= X <==> not (Y < X) */
s = "slt";
goto sle;
case M_SLEU:
s = "sltu";
sle:
- macro_build (NULL, s, "d,v,t", dreg, treg, sreg);
- macro_build (&expr1, "xori", "t,r,i", dreg, dreg, BFD_RELOC_LO16);
+ macro_build (NULL, s, "d,v,t", op[0], op[2], op[1]);
+ macro_build (&expr1, "xori", "t,r,i", op[0], op[0], BFD_RELOC_LO16);
break;
- case M_SLE_I: /* sreg <= I <==> I >= sreg <==> not (I < sreg) */
+ case M_SLE_I: /* X <= I <==> I >= X <==> not (I < X) */
s = "slt";
goto slei;
case M_SLEU_I:
slei:
used_at = 1;
load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
- macro_build (NULL, s, "d,v,t", dreg, AT, sreg);
- macro_build (&expr1, "xori", "t,r,i", dreg, dreg, BFD_RELOC_LO16);
+ macro_build (NULL, s, "d,v,t", op[0], AT, op[1]);
+ macro_build (&expr1, "xori", "t,r,i", op[0], op[0], BFD_RELOC_LO16);
break;
case M_SLT_I:
- if (imm_expr.X_op == O_constant
- && imm_expr.X_add_number >= -0x8000
+ if (imm_expr.X_add_number >= -0x8000
&& imm_expr.X_add_number < 0x8000)
{
- macro_build (&imm_expr, "slti", "t,r,j", dreg, sreg, BFD_RELOC_LO16);
+ macro_build (&imm_expr, "slti", "t,r,j", op[0], op[1],
+ BFD_RELOC_LO16);
break;
}
used_at = 1;
load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
- macro_build (NULL, "slt", "d,v,t", dreg, sreg, AT);
+ macro_build (NULL, "slt", "d,v,t", op[0], op[1], AT);
break;
case M_SLTU_I:
- if (imm_expr.X_op == O_constant
- && imm_expr.X_add_number >= -0x8000
+ if (imm_expr.X_add_number >= -0x8000
&& imm_expr.X_add_number < 0x8000)
{
- macro_build (&imm_expr, "sltiu", "t,r,j", dreg, sreg,
+ macro_build (&imm_expr, "sltiu", "t,r,j", op[0], op[1],
BFD_RELOC_LO16);
break;
}
used_at = 1;
load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
- macro_build (NULL, "sltu", "d,v,t", dreg, sreg, AT);
+ macro_build (NULL, "sltu", "d,v,t", op[0], op[1], AT);
break;
case M_SNE:
- if (sreg == 0)
- macro_build (NULL, "sltu", "d,v,t", dreg, 0, treg);
- else if (treg == 0)
- macro_build (NULL, "sltu", "d,v,t", dreg, 0, sreg);
+ if (op[1] == 0)
+ macro_build (NULL, "sltu", "d,v,t", op[0], 0, op[2]);
+ else if (op[2] == 0)
+ macro_build (NULL, "sltu", "d,v,t", op[0], 0, op[1]);
else
{
- macro_build (NULL, "xor", "d,v,t", dreg, sreg, treg);
- macro_build (NULL, "sltu", "d,v,t", dreg, 0, dreg);
+ macro_build (NULL, "xor", "d,v,t", op[0], op[1], op[2]);
+ macro_build (NULL, "sltu", "d,v,t", op[0], 0, op[0]);
}
break;
case M_SNE_I:
- if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
+ if (imm_expr.X_add_number == 0)
{
- macro_build (NULL, "sltu", "d,v,t", dreg, 0, sreg);
+ macro_build (NULL, "sltu", "d,v,t", op[0], 0, op[1]);
break;
}
- if (sreg == 0)
+ if (op[1] == 0)
{
- as_warn (_("Instruction %s: result is always true"),
+ as_warn (_("instruction %s: result is always true"),
ip->insn_mo->name);
macro_build (&expr1, HAVE_32BIT_GPRS ? "addiu" : "daddiu", "t,r,j",
- dreg, 0, BFD_RELOC_LO16);
+ op[0], 0, BFD_RELOC_LO16);
break;
}
if (CPU_HAS_SEQ (mips_opts.arch)
&& -512 <= imm_expr.X_add_number
&& imm_expr.X_add_number < 512)
{
- macro_build (NULL, "snei", "t,r,+Q", dreg, sreg,
+ macro_build (NULL, "snei", "t,r,+Q", op[0], op[1],
(int) imm_expr.X_add_number);
break;
}
- if (imm_expr.X_op == O_constant
- && imm_expr.X_add_number >= 0
+ if (imm_expr.X_add_number >= 0
&& imm_expr.X_add_number < 0x10000)
{
- macro_build (&imm_expr, "xori", "t,r,i", dreg, sreg, BFD_RELOC_LO16);
+ macro_build (&imm_expr, "xori", "t,r,i", op[0], op[1],
+ BFD_RELOC_LO16);
}
- else if (imm_expr.X_op == O_constant
- && imm_expr.X_add_number > -0x8000
+ else if (imm_expr.X_add_number > -0x8000
&& imm_expr.X_add_number < 0)
{
imm_expr.X_add_number = -imm_expr.X_add_number;
macro_build (&imm_expr, HAVE_32BIT_GPRS ? "addiu" : "daddiu",
- "t,r,j", dreg, sreg, BFD_RELOC_LO16);
+ "t,r,j", op[0], op[1], BFD_RELOC_LO16);
}
else if (CPU_HAS_SEQ (mips_opts.arch))
{
used_at = 1;
load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
- macro_build (NULL, "sne", "d,v,t", dreg, sreg, AT);
+ macro_build (NULL, "sne", "d,v,t", op[0], op[1], AT);
break;
}
else
{
load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
- macro_build (NULL, "xor", "d,v,t", dreg, sreg, AT);
+ macro_build (NULL, "xor", "d,v,t", op[0], op[1], AT);
used_at = 1;
}
- macro_build (NULL, "sltu", "d,v,t", dreg, 0, dreg);
+ macro_build (NULL, "sltu", "d,v,t", op[0], 0, op[0]);
break;
case M_SUB_I:
s2 = "dsub";
if (!mips_opts.micromips)
goto do_subi;
- if (imm_expr.X_op == O_constant
- && imm_expr.X_add_number > -0x200
+ if (imm_expr.X_add_number > -0x200
&& imm_expr.X_add_number <= 0x200)
{
- macro_build (NULL, s, "t,r,.", dreg, sreg, -imm_expr.X_add_number);
+ macro_build (NULL, s, "t,r,.", op[0], op[1],
+ (int) -imm_expr.X_add_number);
break;
}
goto do_subi_i;
s = "daddiu";
s2 = "dsubu";
do_subi:
- if (imm_expr.X_op == O_constant
- && imm_expr.X_add_number > -0x8000
+ if (imm_expr.X_add_number > -0x8000
&& imm_expr.X_add_number <= 0x8000)
{
imm_expr.X_add_number = -imm_expr.X_add_number;
- macro_build (&imm_expr, s, "t,r,j", dreg, sreg, BFD_RELOC_LO16);
+ macro_build (&imm_expr, s, "t,r,j", op[0], op[1], BFD_RELOC_LO16);
break;
}
do_subi_i:
used_at = 1;
load_register (AT, &imm_expr, dbl);
- macro_build (NULL, s2, "d,v,t", dreg, sreg, AT);
+ macro_build (NULL, s2, "d,v,t", op[0], op[1], AT);
break;
case M_TEQ_I:
trap:
used_at = 1;
load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
- macro_build (NULL, s, "s,t", sreg, AT);
+ macro_build (NULL, s, "s,t", op[0], AT);
break;
case M_TRUNCWS:
gas_assert (!mips_opts.micromips);
gas_assert (mips_opts.isa == ISA_MIPS1);
used_at = 1;
- sreg = (ip->insn_opcode >> 11) & 0x1f; /* floating reg */
- dreg = (ip->insn_opcode >> 06) & 0x1f; /* floating reg */
/*
* Is the double cfc1 instruction a bug in the mips assembler;
* or is there a reason for it?
*/
start_noreorder ();
- macro_build (NULL, "cfc1", "t,G", treg, RA);
- macro_build (NULL, "cfc1", "t,G", treg, RA);
+ macro_build (NULL, "cfc1", "t,G", op[2], RA);
+ macro_build (NULL, "cfc1", "t,G", op[2], RA);
macro_build (NULL, "nop", "");
expr1.X_add_number = 3;
- macro_build (&expr1, "ori", "t,r,i", AT, treg, BFD_RELOC_LO16);
+ macro_build (&expr1, "ori", "t,r,i", AT, op[2], BFD_RELOC_LO16);
expr1.X_add_number = 2;
macro_build (&expr1, "xori", "t,r,i", AT, AT, BFD_RELOC_LO16);
macro_build (NULL, "ctc1", "t,G", AT, RA);
macro_build (NULL, "nop", "");
macro_build (NULL, mask == M_TRUNCWD ? "cvt.w.d" : "cvt.w.s", "D,S",
- dreg, sreg);
- macro_build (NULL, "ctc1", "t,G", treg, RA);
+ op[0], op[1]);
+ macro_build (NULL, "ctc1", "t,G", op[2], RA);
macro_build (NULL, "nop", "");
end_noreorder ();
break;
ust = 1;
uld_st:
+ breg = op[2];
large_offset = !small_offset_p (off, align, offbits);
ep = &offset_expr;
expr1.X_add_number = 0;
offset_reloc[1] = BFD_RELOC_UNUSED;
offset_reloc[2] = BFD_RELOC_UNUSED;
breg = tempreg;
- tempreg = treg;
+ tempreg = op[0];
ep = &expr1;
}
- else if (!ust && treg == breg)
+ else if (!ust && op[0] == breg)
{
used_at = 1;
tempreg = AT;
}
else
- tempreg = treg;
+ tempreg = op[0];
if (off == 1)
goto ulh_sh;
offset_reloc[0], offset_reloc[1], offset_reloc[2], breg);
/* If necessary, move the result in tempreg to the final destination. */
- if (!ust && treg != tempreg)
+ if (!ust && op[0] != tempreg)
{
/* Protect second load's delay slot. */
load_delay_nop ();
- move_register (treg, tempreg);
+ move_register (op[0], tempreg);
}
break;
used_at = 1;
if (target_big_endian == ust)
ep->X_add_number += off;
- tempreg = ust || large_offset ? treg : AT;
+ tempreg = ust || large_offset ? op[0] : AT;
macro_build (ep, s, "t,o(b)", tempreg, -1,
offset_reloc[0], offset_reloc[1], offset_reloc[2], breg);
bytes. Unfortunately for M_USH_A we have none available before
the next store as AT holds the base address. We deal with this
case by clobbering TREG and then restoring it as with ULH. */
- tempreg = ust == large_offset ? treg : AT;
+ tempreg = ust == large_offset ? op[0] : AT;
if (ust)
- macro_build (NULL, "srl", SHFT_FMT, tempreg, treg, 8);
+ macro_build (NULL, "srl", SHFT_FMT, tempreg, op[0], 8);
if (target_big_endian == ust)
ep->X_add_number -= off;
/* For ULH and M_USH_A OR the LSB in. */
if (!ust || large_offset)
{
- tempreg = !large_offset ? AT : treg;
+ tempreg = !large_offset ? AT : op[0];
macro_build (NULL, "sll", SHFT_FMT, tempreg, tempreg, 8);
- macro_build (NULL, "or", "d,v,t", treg, treg, AT);
+ macro_build (NULL, "or", "d,v,t", op[0], op[0], AT);
}
break;
default:
/* FIXME: Check if this is one of the itbl macros, since they
are added dynamically. */
- as_bad (_("Macro %s not implemented yet"), ip->insn_mo->name);
+ as_bad (_("macro %s not implemented yet"), ip->insn_mo->name);
break;
}
if (!mips_opts.at && used_at)
- as_bad (_("Macro used $at after \".set noat\""));
+ as_bad (_("macro used $at after \".set noat\""));
}
/* Implement macros in mips16 mode. */
static void
mips16_macro (struct mips_cl_insn *ip)
{
+ const struct mips_operand_array *operands;
int mask;
- int xreg, yreg, zreg, tmp;
+ int tmp;
expressionS expr1;
int dbl;
const char *s, *s2, *s3;
+ unsigned int op[MAX_OPERANDS];
+ unsigned int i;
mask = ip->insn_mo->mask;
- xreg = MIPS16_EXTRACT_OPERAND (RX, *ip);
- yreg = MIPS16_EXTRACT_OPERAND (RY, *ip);
- zreg = MIPS16_EXTRACT_OPERAND (RZ, *ip);
+ operands = insn_operands (ip);
+ for (i = 0; i < MAX_OPERANDS; i++)
+ if (operands->operand[i])
+ op[i] = insn_extract_operand (ip, operands->operand[i]);
+ else
+ op[i] = -1;
expr1.X_op = O_constant;
expr1.X_op_symbol = NULL;
s = "mfhi";
do_div3:
start_noreorder ();
- macro_build (NULL, dbl ? "ddiv" : "div", "0,x,y", xreg, yreg);
+ macro_build (NULL, dbl ? "ddiv" : "div", "0,x,y", op[1], op[2]);
expr1.X_add_number = 2;
- macro_build (&expr1, "bnez", "x,p", yreg);
+ macro_build (&expr1, "bnez", "x,p", op[2]);
macro_build (NULL, "break", "6", 7);
/* FIXME: The normal code checks for of -1 / -0x80000000 here,
but I don't see how to do the comparisons without a temporary
register. */
end_noreorder ();
- macro_build (NULL, s, "x", zreg);
+ macro_build (NULL, s, "x", op[0]);
break;
case M_DIVU_3:
s2 = "mfhi";
do_divu3:
start_noreorder ();
- macro_build (NULL, s, "0,x,y", xreg, yreg);
+ macro_build (NULL, s, "0,x,y", op[1], op[2]);
expr1.X_add_number = 2;
- macro_build (&expr1, "bnez", "x,p", yreg);
+ macro_build (&expr1, "bnez", "x,p", op[2]);
macro_build (NULL, "break", "6", 7);
end_noreorder ();
- macro_build (NULL, s2, "x", zreg);
+ macro_build (NULL, s2, "x", op[0]);
break;
case M_DMUL:
dbl = 1;
case M_MUL:
- macro_build (NULL, dbl ? "dmultu" : "multu", "x,y", xreg, yreg);
- macro_build (NULL, "mflo", "x", zreg);
+ macro_build (NULL, dbl ? "dmultu" : "multu", "x,y", op[1], op[2]);
+ macro_build (NULL, "mflo", "x", op[0]);
break;
case M_DSUBU_I:
goto do_subu;
case M_SUBU_I:
do_subu:
- if (imm_expr.X_op != O_constant)
- as_bad (_("Unsupported large constant"));
imm_expr.X_add_number = -imm_expr.X_add_number;
- macro_build (&imm_expr, dbl ? "daddiu" : "addiu", "y,x,4", yreg, xreg);
+ macro_build (&imm_expr, dbl ? "daddiu" : "addiu", "y,x,4", op[0], op[1]);
break;
case M_SUBU_I_2:
- if (imm_expr.X_op != O_constant)
- as_bad (_("Unsupported large constant"));
imm_expr.X_add_number = -imm_expr.X_add_number;
- macro_build (&imm_expr, "addiu", "x,k", xreg);
+ macro_build (&imm_expr, "addiu", "x,k", op[0]);
break;
case M_DSUBU_I_2:
- if (imm_expr.X_op != O_constant)
- as_bad (_("Unsupported large constant"));
imm_expr.X_add_number = -imm_expr.X_add_number;
- macro_build (&imm_expr, "daddiu", "y,j", yreg);
+ macro_build (&imm_expr, "daddiu", "y,j", op[0]);
break;
case M_BEQ:
s2 = "btnez";
do_reverse_branch:
- tmp = xreg;
- xreg = yreg;
- yreg = tmp;
+ tmp = op[1];
+ op[1] = op[0];
+ op[0] = tmp;
do_branch:
- macro_build (NULL, s, "x,y", xreg, yreg);
+ macro_build (NULL, s, "x,y", op[0], op[1]);
macro_build (&offset_expr, s2, "p");
break;
s3 = "x,8";
do_addone_branch_i:
- if (imm_expr.X_op != O_constant)
- as_bad (_("Unsupported large constant"));
++imm_expr.X_add_number;
do_branch_i:
- macro_build (&imm_expr, s, s3, xreg);
+ macro_build (&imm_expr, s, s3, op[0]);
macro_build (&offset_expr, s2, "p");
break;
case M_ABS:
expr1.X_add_number = 0;
- macro_build (&expr1, "slti", "x,8", yreg);
- if (xreg != yreg)
- macro_build (NULL, "move", "y,X", xreg, mips16_to_32_reg_map[yreg]);
+ macro_build (&expr1, "slti", "x,8", op[1]);
+ if (op[0] != op[1])
+ macro_build (NULL, "move", "y,X", op[0], mips16_to_32_reg_map[op[1]]);
expr1.X_add_number = 2;
macro_build (&expr1, "bteqz", "p");
- macro_build (NULL, "neg", "x,w", xreg, xreg);
+ macro_build (NULL, "neg", "x,w", op[0], op[0]);
break;
}
}
+/* Look up instruction [START, START + LENGTH) in HASH. Record any extra
+ opcode bits in *OPCODE_EXTRA. */
+
+static struct mips_opcode *
+mips_lookup_insn (struct hash_control *hash, const char *start,
+ ssize_t length, unsigned int *opcode_extra)
+{
+ char *name, *dot, *p;
+ unsigned int mask, suffix;
+ ssize_t opend;
+ struct mips_opcode *insn;
+
+ /* Make a copy of the instruction so that we can fiddle with it. */
+ name = alloca (length + 1);
+ memcpy (name, start, length);
+ name[length] = '\0';
+
+ /* Look up the instruction as-is. */
+ insn = (struct mips_opcode *) hash_find (hash, name);
+ if (insn)
+ return insn;
+
+ dot = strchr (name, '.');
+ if (dot && dot[1])
+ {
+ /* Try to interpret the text after the dot as a VU0 channel suffix. */
+ p = mips_parse_vu0_channels (dot + 1, &mask);
+ if (*p == 0 && mask != 0)
+ {
+ *dot = 0;
+ insn = (struct mips_opcode *) hash_find (hash, name);
+ *dot = '.';
+ if (insn && (insn->pinfo2 & INSN2_VU0_CHANNEL_SUFFIX) != 0)
+ {
+ *opcode_extra |= mask << mips_vu0_channel_mask.lsb;
+ return insn;
+ }
+ }
+ }
+
+ if (mips_opts.micromips)
+ {
+ /* See if there's an instruction size override suffix,
+ either `16' or `32', at the end of the mnemonic proper,
+ that defines the operation, i.e. before the first `.'
+ character if any. Strip it and retry. */
+ opend = dot != NULL ? dot - name : length;
+ if (opend >= 3 && name[opend - 2] == '1' && name[opend - 1] == '6')
+ suffix = 2;
+ else if (name[opend - 2] == '3' && name[opend - 1] == '2')
+ suffix = 4;
+ else
+ suffix = 0;
+ if (suffix)
+ {
+ memcpy (name + opend - 2, name + opend, length - opend + 1);
+ insn = (struct mips_opcode *) hash_find (hash, name);
+ if (insn)
+ {
+ forced_insn_length = suffix;
+ return insn;
+ }
+ }
+ }
+
+ return NULL;
+}
+
/* Assemble an instruction into its binary format. If the instruction
- is a macro, set imm_expr, imm2_expr and offset_expr to the values
- associated with "I", "+I" and "A" operands respectively. Otherwise
- store the value of the relocatable field (if any) in offset_expr.
- In both cases set offset_reloc to the relocation operators applied
- to offset_expr. */
+ is a macro, set imm_expr and offset_expr to the values associated
+ with "I" and "A" operands respectively. Otherwise store the value
+ of the relocatable field (if any) in offset_expr. In both cases
+ set offset_reloc to the relocation operators applied to offset_expr. */
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;
- bfd_boolean need_delay_slot_ok = TRUE;
- struct mips_opcode *firstinsn = NULL;
- const struct mips_opcode *past;
+ const struct mips_opcode *first, *past;
struct hash_control *hash;
- const char *args;
- char c = 0;
- struct mips_opcode *insn;
- long opend;
- char *name;
- char *dot;
char format;
- long end;
- const struct mips_operand *operand;
- struct mips_arg_info arg;
+ size_t end;
struct mips_operand_token *tokens;
- bfd_boolean optional_reg;
-
- insn_error = NULL;
+ unsigned int opcode_extra;
if (mips_opts.micromips)
{
past = &mips_opcodes[NUMOPCODES];
}
forced_insn_length = 0;
- insn = NULL;
+ opcode_extra = 0;
/* 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++)
continue;
- /* Make a copy of the instruction so that we can fiddle with it. */
- name = alloca (end + 1);
- memcpy (name, str, end);
- name[end] = '\0';
-
- for (;;)
+ first = mips_lookup_insn (hash, str, end, &opcode_extra);
+ if (first == NULL)
{
- insn = (struct mips_opcode *) hash_find (hash, name);
-
- if (insn != NULL || !mips_opts.micromips)
- break;
- if (forced_insn_length)
- break;
-
- /* See if there's an instruction size override suffix,
- either `16' or `32', at the end of the mnemonic proper,
- that defines the operation, i.e. before the first `.'
- character if any. Strip it and retry. */
- dot = strchr (name, '.');
- opend = dot != NULL ? dot - name : end;
- if (opend < 3)
- break;
- if (name[opend - 2] == '1' && name[opend - 1] == '6')
- forced_insn_length = 2;
- else if (name[opend - 2] == '3' && name[opend - 1] == '2')
- forced_insn_length = 4;
- else
- break;
- memcpy (name + opend - 2, name + opend, end - opend + 1);
- }
- if (insn == NULL)
- {
- insn_error = _("Unrecognized opcode");
+ set_insn_error (0, _("unrecognized opcode"));
return;
}
- if (strcmp (name, "li.s") == 0)
+ if (strcmp (first->name, "li.s") == 0)
format = 'f';
- else if (strcmp (name, "li.d") == 0)
+ else if (strcmp (first->name, "li.d") == 0)
format = 'd';
else
format = 0;
if (!tokens)
return;
- /* For microMIPS instructions placed in a fixed-length branch delay slot
- we make up to two passes over the relevant fragment of the opcode
- table. First we try instructions that meet the delay slot's length
- 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, 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)
- {
- static char buf[256];
-
- 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;
- }
-
- obstack_free (&mips_operand_tokens, tokens);
- if (insn_error)
- return;
-
- if (!ok)
- sprintf (buf, _("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)
- sprintf (buf, _("Opcode not supported in the `insn32' mode"));
- else
- sprintf (buf, _("Unrecognized %u-bit version of microMIPS opcode"),
- 8 * forced_insn_length);
- insn_error = buf;
-
- return;
- }
-
- imm_expr.X_op = O_absent;
- imm2_expr.X_op = O_absent;
- offset_expr.X_op = O_absent;
- offset_reloc[0] = BFD_RELOC_UNUSED;
- offset_reloc[1] = BFD_RELOC_UNUSED;
- offset_reloc[2] = BFD_RELOC_UNUSED;
-
- create_insn (ip, insn);
- insn_error = NULL;
- memset (&arg, 0, sizeof (arg));
- arg.insn = ip;
- arg.token = tokens;
- arg.argnum = 1;
- arg.last_regno = ILLEGAL_REG;
- arg.dest_regno = ILLEGAL_REG;
- arg.soft_match = (more_alts
- || (wrong_delay_slot_insns && need_delay_slot_ok));
- for (args = insn->args;; ++args)
- {
- if (arg.token->type == OT_END)
- {
- /* Handle unary instructions in which only one operand is given.
- The source is then the same as the destination. */
- if (arg.opnum == 1 && *args == ',')
- switch (args[1])
- {
- case 'r':
- case 'v':
- case 'w':
- case 'W':
- case 'V':
- arg.token = tokens;
- arg.argnum = 1;
- continue;
- }
-
- /* Treat elided base registers as $0. */
- if (strcmp (args, "(b)") == 0)
- args += 3;
-
- /* Fail the match if there were too few operands. */
- if (*args)
- break;
-
- /* Successful match. */
- if (arg.dest_regno == arg.last_regno
- && strncmp (ip->insn_mo->name, "jalr", 4) == 0)
- {
- if (arg.opnum == 2)
- as_bad (_("Source and destination must be different"));
- else if (arg.last_regno == 31)
- as_bad (_("A destination register must be supplied"));
- }
- check_completed_insn (&arg);
- obstack_free (&mips_operand_tokens, tokens);
- return;
- }
-
- /* Fail the match if the line has too many operands. */
- if (*args == 0)
- break;
-
- /* Handle characters that need to match exactly. */
- if (*args == '(' || *args == ')' || *args == ',')
- {
- if (match_char (&arg, *args))
- continue;
- break;
- }
-
- /* Handle special macro operands. Work out the properties of
- other operands. */
- arg.opnum += 1;
- arg.lax_max = FALSE;
- optional_reg = FALSE;
- switch (*args)
- {
- case '+':
- switch (args[1])
- {
- case '1':
- case '2':
- case '3':
- case '4':
- case 'B':
- case 'C':
- case 'F':
- case 'G':
- case 'H':
- case 'J':
- case 'Q':
- case 'S':
- case 's':
- /* If these integer forms come last, there is no other
- form of the instruction that could match. Prefer to
- give detailed error messages where possible. */
- if (args[2] == 0)
- arg.soft_match = FALSE;
- break;
-
- case 'I':
- /* "+I" is like "I", except that imm2_expr is used. */
- if (match_const_int (&arg, &imm2_expr.X_add_number, 0))
- imm2_expr.X_op = O_constant;
- else
- insn_error = _("absolute expression required");
- if (HAVE_32BIT_GPRS)
- normalize_constant_expr (&imm2_expr);
- ++args;
- continue;
-
- case 'i':
- *offset_reloc = BFD_RELOC_MIPS_JMP;
- break;
- }
- break;
-
- case '\'':
- case ':':
- case '@':
- case '^':
- case '$':
- case '\\':
- case '%':
- case '|':
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '8':
- case 'B':
- case 'C':
- case 'J':
- case 'O':
- case 'P':
- case 'Q':
- case 'c':
- case 'h':
- case 'q':
- /* If these integer forms come last, there is no other
- form of the instruction that could match. Prefer to
- give detailed error messages where possible. */
- if (args[1] == 0)
- arg.soft_match = FALSE;
- break;
-
- case 'r':
- case 'v':
- case 'w':
- case 'W':
- case 'V':
- /* We have already matched a comma by this point, so the register
- is only optional if there is another operand to come. */
- gas_assert (arg.opnum == 2);
- optional_reg = (args[1] == ',');
- break;
-
- case 'I':
- if (match_const_int (&arg, &imm_expr.X_add_number, 0))
- imm_expr.X_op = O_constant;
- else
- insn_error = _("absolute expression required");
- if (HAVE_32BIT_GPRS)
- normalize_constant_expr (&imm_expr);
- continue;
-
- case 'A':
- if (arg.token->type == OT_CHAR && arg.token->u.ch == '(')
- {
- /* Assume that the offset has been elided and that what
- we saw was a base register. The match will fail later
- if that assumption turns out to be wrong. */
- offset_expr.X_op = O_constant;
- offset_expr.X_add_number = 0;
- }
- else if (match_expression (&arg, &offset_expr, offset_reloc))
- normalize_address_expr (&offset_expr);
- else
- insn_error = _("absolute expression required");
- continue;
-
- case 'F':
- if (!match_float_constant (&arg, &imm_expr, &offset_expr,
- 8, TRUE))
- insn_error = _("floating-point expression required");
- continue;
-
- case 'L':
- if (!match_float_constant (&arg, &imm_expr, &offset_expr,
- 8, FALSE))
- insn_error = _("floating-point expression required");
- continue;
-
- case 'f':
- if (!match_float_constant (&arg, &imm_expr, &offset_expr,
- 4, TRUE))
- insn_error = _("floating-point expression required");
- continue;
-
- case 'l':
- if (!match_float_constant (&arg, &imm_expr, &offset_expr,
- 4, FALSE))
- insn_error = _("floating-point expression required");
- 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':
- *offset_reloc = BFD_RELOC_16_PCREL_S2;
- break;
-
- case 'a':
- *offset_reloc = BFD_RELOC_MIPS_JMP;
- break;
-
- case 'm':
- gas_assert (mips_opts.micromips);
- c = args[1];
- switch (c)
- {
- case 't':
- case 'c':
- case 'e':
- /* We have already matched a comma by this point,
- so the register is only optional if there is another
- operand to come. */
- gas_assert (arg.opnum == 2);
- optional_reg = (args[2] == ',');
- break;
-
- case 'D':
- case 'E':
- if (!forced_insn_length)
- *offset_reloc = (int) BFD_RELOC_UNUSED + c;
- else if (c == 'D')
- *offset_reloc = BFD_RELOC_MICROMIPS_10_PCREL_S1;
- else
- *offset_reloc = BFD_RELOC_MICROMIPS_7_PCREL_S1;
- break;
- }
- break;
- }
-
- operand = (mips_opts.micromips
- ? decode_micromips_operand (args)
- : decode_mips_operand (args));
- if (!operand)
- abort ();
-
- if (optional_reg
- && (arg.token[0].type != OT_REG
- || arg.token[1].type == OT_END))
- {
- /* Assume that the register has been elided and is the
- same as the first operand. */
- arg.token = tokens;
- arg.argnum = 1;
- }
-
- if (!match_operand (&arg, operand))
- break;
-
- /* Skip prefixes. */
- if (*args == '+' || *args == 'm')
- args++;
+ if (!match_insns (insn, first, past, tokens, opcode_extra, FALSE)
+ && !match_insns (insn, first, past, tokens, opcode_extra, TRUE))
+ set_insn_error (0, _("invalid operands"));
- continue;
- }
- /* Args don't match. */
- insn_error = _("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;
- }
- obstack_free (&mips_operand_tokens, tokens);
- return;
- }
+ obstack_free (&mips_operand_tokens, tokens);
}
/* As for mips_ip, but used when assembling MIPS16 code.
bytes if the user explicitly requested a small or extended instruction. */
static void
-mips16_ip (char *str, struct mips_cl_insn *ip)
+mips16_ip (char *str, struct mips_cl_insn *insn)
{
- char *s;
- const char *args;
- struct mips_opcode *insn;
- const struct mips_operand *operand;
- const struct mips_operand *ext_operand;
- struct mips_arg_info arg;
+ char *end, *s, c;
+ struct mips_opcode *first;
struct mips_operand_token *tokens;
- bfd_boolean optional_reg;
-
- insn_error = NULL;
forced_insn_length = 0;
for (s = str; ISLOWER (*s); ++s)
;
- switch (*s)
+ end = s;
+ c = *end;
+ switch (c)
{
case '\0':
break;
case ' ':
- *s++ = '\0';
+ s++;
break;
case '.':
if (s[1] == 't' && s[2] == ' ')
{
- *s = '\0';
forced_insn_length = 2;
s += 3;
break;
}
else if (s[1] == 'e' && s[2] == ' ')
{
- *s = '\0';
forced_insn_length = 4;
s += 3;
break;
}
/* Fall through. */
default:
- insn_error = _("unknown opcode");
+ set_insn_error (0, _("unrecognized opcode"));
return;
}
if (mips_opts.noautoextend && !forced_insn_length)
forced_insn_length = 2;
- if ((insn = (struct mips_opcode *) hash_find (mips16_op_hash, str)) == NULL)
+ *end = 0;
+ first = (struct mips_opcode *) hash_find (mips16_op_hash, str);
+ *end = c;
+
+ if (!first)
{
- insn_error = _("unrecognized opcode");
+ set_insn_error (0, _("unrecognized opcode"));
return;
}
if (!tokens)
return;
- for (;;)
- {
- bfd_boolean ok;
- bfd_boolean more_alts;
- char relax_char;
-
- gas_assert (strcmp (insn->name, str) == 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
- {
- if (!insn_error)
- {
- static char buf[100];
- sprintf (buf,
- _("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);
- insn_error = buf;
- }
- obstack_free (&mips_operand_tokens, tokens);
- return;
- }
- }
-
- create_insn (ip, insn);
- imm_expr.X_op = O_absent;
- imm2_expr.X_op = O_absent;
- offset_expr.X_op = O_absent;
- offset_reloc[0] = BFD_RELOC_UNUSED;
- offset_reloc[1] = BFD_RELOC_UNUSED;
- offset_reloc[2] = BFD_RELOC_UNUSED;
- relax_char = 0;
-
- memset (&arg, 0, sizeof (arg));
- arg.insn = ip;
- arg.token = tokens;
- arg.argnum = 1;
- arg.last_regno = ILLEGAL_REG;
- arg.dest_regno = ILLEGAL_REG;
- arg.soft_match = more_alts;
- relax_char = 0;
- for (args = insn->args; 1; ++args)
- {
- int c;
-
- if (arg.token->type == OT_END)
- {
- offsetT value;
-
- /* Handle unary instructions in which only one operand is given.
- The source is then the same as the destination. */
- if (arg.opnum == 1 && *args == ',')
- switch (args[1])
- {
- case 'v':
- case 'w':
- arg.token = tokens;
- arg.argnum = 1;
- continue;
- }
-
- /* Fail the match if there were too few operands. */
- if (*args)
- break;
-
- /* Successful match. Stuff the immediate value in now, if
- we can. */
- if (insn->pinfo == INSN_MACRO)
- {
- gas_assert (relax_char == 0 || relax_char == 'p');
- gas_assert (*offset_reloc == BFD_RELOC_UNUSED);
- }
- else if (relax_char
- && offset_expr.X_op == O_constant
- && calculate_reloc (*offset_reloc,
- offset_expr.X_add_number,
- &value))
- {
- mips16_immed (NULL, 0, relax_char, *offset_reloc, value,
- forced_insn_length, &ip->insn_opcode);
- offset_expr.X_op = O_absent;
- *offset_reloc = BFD_RELOC_UNUSED;
- }
- else if (relax_char && *offset_reloc != BFD_RELOC_UNUSED)
- {
- if (forced_insn_length == 2)
- as_bad (_("invalid unextended operand value"));
- forced_insn_length = 4;
- ip->insn_opcode |= MIPS16_EXTEND;
- }
- else if (relax_char)
- *offset_reloc = (int) BFD_RELOC_UNUSED + relax_char;
-
- check_completed_insn (&arg);
- obstack_free (&mips_operand_tokens, tokens);
- return;
- }
-
- /* Fail the match if the line has too many operands. */
- if (*args == 0)
- break;
-
- /* Handle characters that need to match exactly. */
- if (*args == '(' || *args == ')' || *args == ',')
- {
- if (match_char (&arg, *args))
- continue;
- break;
- }
-
- arg.opnum += 1;
- optional_reg = FALSE;
- c = *args;
- switch (c)
- {
- case 'v':
- case 'w':
- optional_reg = (args[1] == ',');
- break;
-
- case 'p':
- case 'q':
- case 'A':
- case 'B':
- case 'E':
- relax_char = c;
- break;
-
- case 'I':
- if (match_const_int (&arg, &imm_expr.X_add_number, 0))
- imm_expr.X_op = O_constant;
- else
- insn_error = _("absolute expression required");
- if (HAVE_32BIT_GPRS)
- normalize_constant_expr (&imm_expr);
- continue;
-
- case 'a':
- case 'i':
- *offset_reloc = BFD_RELOC_MIPS16_JMP;
- ip->insn_opcode <<= 16;
- break;
- }
+ if (!match_mips16_insns (insn, first, tokens))
+ set_insn_error (0, _("invalid operands"));
- operand = decode_mips16_operand (c, FALSE);
- if (!operand)
- abort ();
-
- /* '6' is a special case. It is used for BREAK and SDBBP,
- whose operands are only meaningful to the software that decodes
- them. This means that there is no architectural reason why
- they cannot be prefixed by EXTEND, but in practice,
- exception handlers will only look at the instruction
- itself. We therefore allow '6' to be extended when
- disassembling but not when assembling. */
- if (operand->type != OP_PCREL && c != '6')
- {
- ext_operand = decode_mips16_operand (c, TRUE);
- if (operand != ext_operand)
- {
- if (arg.token->type == OT_CHAR && arg.token->u.ch == '(')
- {
- offset_expr.X_op = O_constant;
- offset_expr.X_add_number = 0;
- relax_char = c;
- continue;
- }
-
- /* We need the OT_INTEGER check because some MIPS16
- immediate variants are listed before the register ones. */
- if (arg.token->type != OT_INTEGER
- || !match_expression (&arg, &offset_expr, offset_reloc))
- break;
-
- /* '8' is used for SLTI(U) and has traditionally not
- been allowed to take relocation operators. */
- if (offset_reloc[0] != BFD_RELOC_UNUSED
- && (ext_operand->size != 16 || c == '8'))
- break;
-
- relax_char = c;
- continue;
- }
- }
-
- if (optional_reg
- && (arg.token[0].type != OT_REG
- || arg.token[1].type == OT_END))
- {
- /* Assume that the register has been elided and is the
- same as the first operand. */
- arg.token = tokens;
- arg.argnum = 1;
- }
-
- if (!match_operand (&arg, operand))
- break;
- continue;
- }
-
- /* Args don't match. */
- if (more_alts)
- {
- ++insn;
- continue;
- }
-
- insn_error = _("illegal operands");
-
- obstack_free (&mips_operand_tokens, tokens);
- return;
- }
+ obstack_free (&mips_operand_tokens, tokens);
}
/* Marshal immediate value VAL for an extended MIPS16 instruction.
mips_set_option_string (const char **string_ptr, const char *new_value)
{
if (*string_ptr != 0 && strcasecmp (*string_ptr, new_value) != 0)
- as_warn (_("A different %s was already specified, is now %s"),
+ as_warn (_("a different %s was already specified, is now %s"),
string_ptr == &mips_arch_string ? "-march" : "-mtune",
new_value);
case OPTION_64:
mips_abi = N64_ABI;
if (!support_64bit_objects())
- as_fatal (_("No compiled in support for 64 bit object file format"));
+ as_fatal (_("no compiled in support for 64 bit object file format"));
break;
case OPTION_GP32:
{
mips_abi = N64_ABI;
if (! support_64bit_objects())
- as_fatal (_("No compiled in support for 64 bit object file "
+ as_fatal (_("no compiled in support for 64 bit object file "
"format"));
}
else if (strcmp (arg, "eabi") == 0)
mips_flag_nan2008 = FALSE;
else
{
- as_fatal (_("Invalid NaN setting -mnan=%s"), arg);
+ as_fatal (_("invalid NaN setting -mnan=%s"), arg);
return 0;
}
break;
if (strncmp (TARGET_OS, "pe", 2) == 0)
{
if (g_switch_seen && g_switch_value != 0)
- as_bad (_("-G not supported in this configuration."));
+ as_bad (_("-G not supported in this configuration"));
g_switch_value = 0;
}
There's no harm in specifying both as long as the ISA levels
are the same. */
if (file_mips_isa != arch_info->isa)
- as_bad (_("-%s conflicts with the other architecture options, which imply -%s"),
+ as_bad (_("-%s conflicts with the other architecture options,"
+ " which imply -%s"),
mips_cpu_info_from_isa (file_mips_isa)->name,
mips_cpu_info_from_isa (arch_info->isa)->name);
}
/* We have no relocation type for PC relative MIPS16 instructions. */
if (fixP->fx_addsy && S_GET_SEGMENT (fixP->fx_addsy) != now_seg)
as_bad_where (fixP->fx_file, fixP->fx_line,
- _("PC relative MIPS16 instruction references a different section"));
+ _("PC relative MIPS16 instruction references"
+ " a different section"));
return addr;
}
}
}
else
as_bad_where (fixP->fx_file, fixP->fx_line,
- _("Unsupported constant in relocation"));
+ _("unsupported constant in relocation"));
}
break;
case BFD_RELOC_16_PCREL_S2:
if ((*valP & 0x3) != 0)
as_bad_where (fixP->fx_file, fixP->fx_line,
- _("Branch to misaligned address (%lx)"), (long) *valP);
+ _("branch to misaligned address (%lx)"), (long) *valP);
/* We need to save the bits in the instruction since fixup_segment()
might be deleting the relocation entry (i.e., a branch within
and there's nothing we can do to fix this instruction
without turning it into a longer sequence. */
as_bad_where (fixP->fx_file, fixP->fx_line,
- _("Branch out of range"));
+ _("branch out of range"));
}
break;
temp = get_absolute_expression ();
if (temp > max_alignment)
- as_bad (_("Alignment too large: %d. assumed."), temp = max_alignment);
+ as_bad (_("alignment too large, %d assumed"), temp = max_alignment);
else if (temp < 0)
{
- as_warn (_("Alignment negative: 0 assumed."));
+ as_warn (_("alignment negative, 0 assumed"));
temp = 0;
}
if (*input_line_pointer == ',')
}
}
else
- as_warn (_("Unrecognized option \"%s\""), opt);
+ as_warn (_("unrecognized option \"%s\""), opt);
*input_line_pointer = c;
demand_empty_rest_of_line ();
char *s = name + 3;
if (!reg_lookup (&s, RTYPE_NUM | RTYPE_GP, &mips_opts.at))
- as_bad (_("Unrecognized register name `%s'"), s);
+ as_bad (_("unrecognized register name `%s'"), s);
}
else if (strcmp (name, "at") == 0)
{
}
else
{
- as_warn (_("Tried to set unrecognized symbol: %s\n"), name);
+ as_warn (_("tried to set unrecognized symbol: %s\n"), name);
}
mips_check_isa_supports_ases ();
*input_line_pointer = ch;
if (ex.X_op != O_symbol)
{
- as_bad (_("Unsupported use of %s"), dirstr);
+ as_bad (_("unsupported use of %s"), dirstr);
ignore_rest_of_line ();
}
if (ex.X_op != O_symbol || ex.X_add_number != 0)
{
- as_bad (_("Unsupported use of .gpword"));
+ as_bad (_("unsupported use of .gpword"));
ignore_rest_of_line ();
}
if (ex.X_op != O_symbol || ex.X_add_number != 0)
{
- as_bad (_("Unsupported use of .gpdword"));
+ as_bad (_("unsupported use of .gpdword"));
ignore_rest_of_line ();
}
if (ex.X_op != O_symbol || ex.X_add_number != 0)
{
- as_bad (_("Unsupported use of .ehword"));
+ as_bad (_("unsupported use of .ehword"));
ignore_rest_of_line ();
}
&& memcmp (input_line_pointer, str_legacy, i) == 0)
mips_flag_nan2008 = FALSE;
else
- as_bad (_("Bad .nan directive"));
+ as_bad (_("bad .nan directive"));
input_line_pointer += i;
demand_empty_rest_of_line ();
if (reloc->howto == NULL)
{
as_bad_where (fixp->fx_file, fixp->fx_line,
- _("Can not represent %s relocation in this object file format"),
+ _("cannot represent %s relocation in this object file"
+ " format"),
bfd_get_reloc_code_name (code));
retval[0] = NULL;
}
int i;
as_warn_where (fragp->fr_file, fragp->fr_line,
- _("Relaxed out-of-range branch into a jump"));
+ _("relaxed out-of-range branch into a jump"));
if (RELAX_BRANCH_UNCOND (fragp->fr_subtype))
goto uncond;
/* Relax 32-bit branches to a sequence of instructions. */
as_warn_where (fragp->fr_file, fragp->fr_line,
- _("Relaxed out-of-range branch into a jump"));
+ _("relaxed out-of-range branch into a jump"));
/* Set the short-delay-slot bit. */
short_ds = al && (insn & 0x02000000) != 0;
if (!cur_proc_ptr)
{
- as_warn (_(".end directive without a preceding .ent directive."));
+ as_warn (_(".end directive without a preceding .ent directive"));
demand_empty_rest_of_line ();
return;
}
{
gas_assert (S_GET_NAME (p));
if (strcmp (S_GET_NAME (p), S_GET_NAME (cur_proc_ptr->func_sym)))
- as_warn (_(".end symbol does not match .ent symbol."));
+ as_warn (_(".end symbol does not match .ent symbol"));
if (debug_type == DEBUG_STABS)
stabs_generate_asm_endfunc (S_GET_NAME (p),
get_number ();
if ((bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) == 0)
- as_warn (_(".ent or .aent not in text section."));
+ as_warn (_(".ent or .aent not in text section"));
if (!aent && cur_proc_ptr)
as_warn (_("missing .end"));
if (*input_line_pointer++ != ','
|| get_absolute_expression_and_terminator (&val) != ',')
{
- as_warn (_("Bad .frame directive"));
+ as_warn (_("bad .frame directive"));
--input_line_pointer;
demand_empty_rest_of_line ();
return;
if (get_absolute_expression_and_terminator (&mask) != ',')
{
- as_warn (_("Bad .mask/.fmask directive"));
+ as_warn (_("bad .mask/.fmask directive"));
--input_line_pointer;
demand_empty_rest_of_line ();
return;
if (mips_matching_cpu_name_p (p->name, cpu_string))
return p;
- as_bad (_("Bad value (%s) for %s"), cpu_string, option);
+ as_bad (_("bad value (%s) for %s"), cpu_string, option);
return 0;
}