/* tc-mips.c -- assemble code for a MIPS chip.
- Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
- Free Software Foundation, Inc.
+ Copyright (C) 1993-2014 Free Software Foundation, Inc.
Contributed by the OSF and Ralph Campbell.
Written by Keith Knowles and Ralph Campbell, working independently.
Modified for ECOFF and R4000 support by Ian Lance Taylor of Cygnus
#define DBG(x)
#endif
+#define streq(a, b) (strcmp (a, b) == 0)
+
#define SKIP_SPACE_TABS(S) \
do { while (*(S) == ' ' || *(S) == '\t') ++(S); } while (0)
/* Restrict general purpose registers and floating point registers
to 32 bit. This is initially determined when -mgp32 or -mfp32
is passed but can changed if the assembler code uses .set mipsN. */
- int gp32;
- int fp32;
+ int gp;
+ int fp;
/* MIPS architecture (CPU) type. Changed by .set arch=FOO, the -march
command line option, and the default CPU. */
int arch;
bfd_boolean single_float;
};
-/* This is the struct we use to hold the current set of options. Note
- that we must set the isa field to ISA_UNKNOWN and the ASE fields to
- -1 to indicate that they have not been initialized. */
-
-/* True if -mgp32 was passed. */
-static int file_mips_gp32 = -1;
-
-/* True if -mfp32 was passed. */
-static int file_mips_fp32 = -1;
+/* True if -mnan=2008, false if -mnan=legacy. */
+static bfd_boolean mips_flag_nan2008 = FALSE;
-/* 1 if -msoft-float, 0 if -mhard-float. The default is 0. */
-static int file_mips_soft_float = 0;
+/* This is the struct we use to hold the module level set of options.
+ Note that we must set the isa field to ISA_UNKNOWN and the ASE, gp and
+ fp fields to -1 to indicate that they have not been initialized. */
-/* 1 if -msingle-float, 0 if -mdouble-float. The default is 0. */
-static int file_mips_single_float = 0;
+static struct mips_set_options file_mips_opts =
+{
+ /* isa */ ISA_UNKNOWN, /* ase */ 0, /* mips16 */ -1, /* micromips */ -1,
+ /* noreorder */ 0, /* at */ ATREG, /* warn_about_macros */ 0,
+ /* nomove */ 0, /* nobopt */ 0, /* noautoextend */ 0, /* insn32 */ FALSE,
+ /* gp */ -1, /* fp */ -1, /* arch */ CPU_UNKNOWN, /* sym32 */ FALSE,
+ /* soft_float */ FALSE, /* single_float */ FALSE
+};
-/* True if -mnan=2008, false if -mnan=legacy. */
-static bfd_boolean mips_flag_nan2008 = FALSE;
+/* This is similar to file_mips_opts, but for the current set of options. */
static struct mips_set_options mips_opts =
{
/* isa */ ISA_UNKNOWN, /* ase */ 0, /* mips16 */ -1, /* micromips */ -1,
/* noreorder */ 0, /* at */ ATREG, /* warn_about_macros */ 0,
/* nomove */ 0, /* nobopt */ 0, /* noautoextend */ 0, /* insn32 */ FALSE,
- /* gp32 */ 0, /* fp32 */ 0, /* arch */ CPU_UNKNOWN, /* sym32 */ FALSE,
+ /* gp */ -1, /* fp */ -1, /* arch */ CPU_UNKNOWN, /* sym32 */ FALSE,
/* soft_float */ FALSE, /* single_float */ FALSE
};
unsigned long mips_gprmask;
unsigned long mips_cprmask[4];
-/* MIPS ISA we are using for this output file. */
-static int file_mips_isa = ISA_UNKNOWN;
-
/* True if any MIPS16 code was produced. */
static int file_ase_mips16;
#define ISA_SUPPORTS_MIPS16E (mips_opts.isa == ISA_MIPS32 \
|| mips_opts.isa == ISA_MIPS32R2 \
+ || mips_opts.isa == ISA_MIPS32R3 \
+ || mips_opts.isa == ISA_MIPS32R5 \
|| mips_opts.isa == ISA_MIPS64 \
- || mips_opts.isa == ISA_MIPS64R2)
+ || mips_opts.isa == ISA_MIPS64R2 \
+ || mips_opts.isa == ISA_MIPS64R3 \
+ || mips_opts.isa == ISA_MIPS64R5)
/* True if any microMIPS code was produced. */
static int file_ase_micromips;
#endif
/* The argument of the -march= flag. The architecture we are assembling. */
-static int file_mips_arch = CPU_UNKNOWN;
static const char *mips_arch_string;
/* The argument of the -mtune= flag. The architecture for which we
|| (ISA) == ISA_MIPS4 \
|| (ISA) == ISA_MIPS5 \
|| (ISA) == ISA_MIPS64 \
- || (ISA) == ISA_MIPS64R2)
+ || (ISA) == ISA_MIPS64R2 \
+ || (ISA) == ISA_MIPS64R3 \
+ || (ISA) == ISA_MIPS64R5)
/* Return true if ISA supports 64 bit wide float registers. */
#define ISA_HAS_64BIT_FPRS(ISA) \
|| (ISA) == ISA_MIPS4 \
|| (ISA) == ISA_MIPS5 \
|| (ISA) == ISA_MIPS32R2 \
+ || (ISA) == ISA_MIPS32R3 \
+ || (ISA) == ISA_MIPS32R5 \
|| (ISA) == ISA_MIPS64 \
- || (ISA) == ISA_MIPS64R2)
+ || (ISA) == ISA_MIPS64R2 \
+ || (ISA) == ISA_MIPS64R3 \
+ || (ISA) == ISA_MIPS64R5 )
/* Return true if ISA supports 64-bit right rotate (dror et al.)
instructions. */
#define ISA_HAS_DROR(ISA) \
((ISA) == ISA_MIPS64R2 \
+ || (ISA) == ISA_MIPS64R3 \
+ || (ISA) == ISA_MIPS64R5 \
|| (mips_opts.micromips \
&& ISA_HAS_64BIT_REGS (ISA)) \
)
instructions. */
#define ISA_HAS_ROR(ISA) \
((ISA) == ISA_MIPS32R2 \
+ || (ISA) == ISA_MIPS32R3 \
+ || (ISA) == ISA_MIPS32R5 \
|| (ISA) == ISA_MIPS64R2 \
+ || (ISA) == ISA_MIPS64R3 \
+ || (ISA) == ISA_MIPS64R5 \
|| (mips_opts.ase & ASE_SMARTMIPS) \
|| mips_opts.micromips \
)
#define ISA_HAS_ODD_SINGLE_FPR(ISA) \
((ISA) == ISA_MIPS32 \
|| (ISA) == ISA_MIPS32R2 \
+ || (ISA) == ISA_MIPS32R3 \
+ || (ISA) == ISA_MIPS32R5 \
|| (ISA) == ISA_MIPS64 \
- || (ISA) == ISA_MIPS64R2)
+ || (ISA) == ISA_MIPS64R2 \
+ || (ISA) == ISA_MIPS64R3 \
+ || (ISA) == ISA_MIPS64R5)
/* Return true if ISA supports move to/from high part of a 64-bit
floating-point register. */
#define ISA_HAS_MXHC1(ISA) \
((ISA) == ISA_MIPS32R2 \
- || (ISA) == ISA_MIPS64R2)
-
-#define HAVE_32BIT_GPRS \
- (mips_opts.gp32 || !ISA_HAS_64BIT_REGS (mips_opts.isa))
+ || (ISA) == ISA_MIPS32R3 \
+ || (ISA) == ISA_MIPS32R5 \
+ || (ISA) == ISA_MIPS64R2 \
+ || (ISA) == ISA_MIPS64R3 \
+ || (ISA) == ISA_MIPS64R5)
-#define HAVE_32BIT_FPRS \
- (mips_opts.fp32 || !ISA_HAS_64BIT_FPRS (mips_opts.isa))
+#define GPR_SIZE \
+ (mips_opts.gp == 64 && !ISA_HAS_64BIT_REGS (mips_opts.isa) \
+ ? 32 \
+ : mips_opts.gp)
-#define HAVE_64BIT_GPRS (!HAVE_32BIT_GPRS)
-#define HAVE_64BIT_FPRS (!HAVE_32BIT_FPRS)
+#define FPR_SIZE \
+ (mips_opts.fp == 64 && !ISA_HAS_64BIT_FPRS (mips_opts.isa) \
+ ? 32 \
+ : mips_opts.fp)
#define HAVE_NEWABI (mips_abi == N32_ABI || mips_abi == N64_ABI)
/* The ABI-derived address size. */
#define HAVE_64BIT_ADDRESSES \
- (HAVE_64BIT_GPRS && (mips_abi == EABI_ABI || mips_abi == N64_ABI))
+ (GPR_SIZE == 64 && (mips_abi == EABI_ABI || mips_abi == N64_ABI))
#define HAVE_32BIT_ADDRESSES (!HAVE_64BIT_ADDRESSES)
/* The size of symbolic constants (i.e., expressions of the form
#define hilo_interlocks \
(mips_opts.isa == ISA_MIPS32 \
|| mips_opts.isa == ISA_MIPS32R2 \
+ || mips_opts.isa == ISA_MIPS32R3 \
+ || mips_opts.isa == ISA_MIPS32R5 \
|| mips_opts.isa == ISA_MIPS64 \
|| mips_opts.isa == ISA_MIPS64R2 \
+ || mips_opts.isa == ISA_MIPS64R3 \
+ || mips_opts.isa == ISA_MIPS64R5 \
|| mips_opts.arch == CPU_R4010 \
|| mips_opts.arch == CPU_R5900 \
|| mips_opts.arch == CPU_R10000 \
/* Whether the processor uses hardware interlocks to protect reads
from the GPRs after they are loaded from memory, and thus does not
require nops to be inserted. This applies to instructions marked
- INSN_LOAD_MEMORY_DELAY. These nops are only required at MIPS ISA
+ INSN_LOAD_MEMORY. These nops are only required at MIPS ISA
level I and microMIPS mode instructions are always interlocked. */
#define gpr_interlocks \
(mips_opts.isa != ISA_MIPS1 \
((mips_opts.mips16 | mips_opts.micromips) != 0)
/* The minimum and maximum signed values that can be stored in a GPR. */
-#define GPR_SMAX ((offsetT) (((valueT) 1 << (HAVE_64BIT_GPRS ? 63 : 31)) - 1))
+#define GPR_SMAX ((offsetT) (((valueT) 1 << (GPR_SIZE - 1)) - 1))
#define GPR_SMIN (-GPR_SMAX - 1)
/* MIPS PIC level. */
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;
/* ...likewise -mfix-24k. */
static int mips_fix_24k;
+/* ...likewise -mfix-rm7000 */
+static int mips_fix_rm7000;
+
/* ...likewise -mfix-cn63xxp1 */
static bfd_boolean mips_fix_cn63xxp1;
OPTION_MIPS32,
OPTION_MIPS64,
OPTION_MIPS32R2,
+ OPTION_MIPS32R3,
+ OPTION_MIPS32R5,
OPTION_MIPS64R2,
+ OPTION_MIPS64R3,
+ OPTION_MIPS64R5,
OPTION_MIPS16,
OPTION_NO_MIPS16,
OPTION_MIPS3D,
OPTION_NO_MT,
OPTION_VIRT,
OPTION_NO_VIRT,
+ OPTION_MSA,
+ OPTION_NO_MSA,
OPTION_SMARTMIPS,
OPTION_NO_SMARTMIPS,
OPTION_DSPR2,
OPTION_NO_DSPR2,
OPTION_EVA,
OPTION_NO_EVA,
+ OPTION_XPA,
+ OPTION_NO_XPA,
OPTION_MICROMIPS,
OPTION_NO_MICROMIPS,
OPTION_MCU,
OPTION_MNO_7000_HILO_FIX,
OPTION_FIX_24K,
OPTION_NO_FIX_24K,
+ OPTION_FIX_RM7000,
+ OPTION_NO_FIX_RM7000,
OPTION_FIX_LOONGSON2F_JUMP,
OPTION_NO_FIX_LOONGSON2F_JUMP,
OPTION_FIX_LOONGSON2F_NOP,
{"mips32", no_argument, NULL, OPTION_MIPS32},
{"mips64", no_argument, NULL, OPTION_MIPS64},
{"mips32r2", no_argument, NULL, OPTION_MIPS32R2},
+ {"mips32r3", no_argument, NULL, OPTION_MIPS32R3},
+ {"mips32r5", no_argument, NULL, OPTION_MIPS32R5},
{"mips64r2", no_argument, NULL, OPTION_MIPS64R2},
+ {"mips64r3", no_argument, NULL, OPTION_MIPS64R3},
+ {"mips64r5", no_argument, NULL, OPTION_MIPS64R5},
/* Options which specify Application Specific Extensions (ASEs). */
{"mips16", no_argument, NULL, OPTION_MIPS16},
{"mno-mcu", no_argument, NULL, OPTION_NO_MCU},
{"mvirt", no_argument, NULL, OPTION_VIRT},
{"mno-virt", no_argument, NULL, OPTION_NO_VIRT},
+ {"mmsa", no_argument, NULL, OPTION_MSA},
+ {"mno-msa", no_argument, NULL, OPTION_NO_MSA},
+ {"mxpa", no_argument, NULL, OPTION_XPA},
+ {"mno-xpa", no_argument, NULL, OPTION_NO_XPA},
/* Old-style architecture options. Don't add more of these. */
{"m4650", no_argument, NULL, OPTION_M4650},
{"mno-fix-vr4130", no_argument, NULL, OPTION_NO_FIX_VR4130},
{"mfix-24k", no_argument, NULL, OPTION_FIX_24K},
{"mno-fix-24k", no_argument, NULL, OPTION_NO_FIX_24K},
+ {"mfix-rm7000", no_argument, NULL, OPTION_FIX_RM7000},
+ {"mno-fix-rm7000", no_argument, NULL, OPTION_NO_FIX_RM7000},
{"mfix-cn63xxp1", no_argument, NULL, OPTION_FIX_CN63XXP1},
{"mno-fix-cn63xxp1", no_argument, NULL, OPTION_NO_FIX_CN63XXP1},
{ "virt", ASE_VIRT, ASE_VIRT64,
OPTION_VIRT, OPTION_NO_VIRT,
- 2, 2, 2, 2 }
+ 2, 2, 2, 2 },
+
+ { "msa", ASE_MSA, ASE_MSA64,
+ OPTION_MSA, OPTION_NO_MSA,
+ 2, 2, 2, 2 },
+
+ { "xpa", ASE_XPA, 0,
+ OPTION_XPA, OPTION_NO_XPA,
+ 2, 2, -1, -1 }
};
/* The set of ASEs that require -mfp64. */
\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
if (mips_opts.isa == ISA_MIPS32R2 || mips_opts.isa == ISA_MIPS64R2)
return 2;
+ if (mips_opts.isa == ISA_MIPS32R3 || mips_opts.isa == ISA_MIPS64R3)
+ return 3;
+
+ if (mips_opts.isa == ISA_MIPS32R5 || mips_opts.isa == ISA_MIPS64R5)
+ return 5;
+
/* microMIPS implies revision 2 or above. */
if (mips_opts.micromips)
return 2;
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)
- && mips_opts.fp32
+ && mips_opts.fp != 64
&& (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. */
};
#define RNUM_MASK 0x00000ff
-#define RTYPE_MASK 0x0efff00
+#define RTYPE_MASK 0x0ffff00
#define RTYPE_NUM 0x0000100
#define RTYPE_FPU 0x0000200
#define RTYPE_FCC 0x0000400
#define RTYPE_R5900_Q 0x0100000
#define RTYPE_R5900_R 0x0200000
#define RTYPE_R5900_ACC 0x0400000
+#define RTYPE_MSA 0x0800000
#define RWARN 0x8000000
#define GENERIC_REGISTER_NUMBERS \
else
{
if (types & RWARN)
- as_warn (_("Unrecognized register name `%s'"), *s);
+ as_warn (_("unrecognized register name `%s'"), *s);
regno = ~0;
}
if (regnop)
/* A 4-bit XYZW channel mask. */
OT_CHANNELS,
- /* An element of a vector, e.g. $v0[1]. */
- OT_REG_ELEMENT,
+ /* A constant vector index, e.g. [1]. */
+ OT_INTEGER_INDEX,
+
+ /* A register vector index, e.g. [$2]. */
+ OT_REG_INDEX,
/* A continuous range of registers, e.g. $s0-$s4. */
OT_REG_RANGE,
enum mips_operand_token_type type;
union
{
- /* The register symbol value for an OT_REG. */
+ /* The register symbol value for an OT_REG or OT_REG_INDEX. */
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;
- addressT index;
- } reg_element;
+ /* The integer value of an OT_INTEGER_INDEX. */
+ addressT index;
/* The two register symbol values involved in an OT_REG_RANGE. */
struct {
SKIP_SPACE_TABS (s);
if (!mips_parse_register (&s, ®no2, NULL))
{
- insn_error = _("Invalid register range");
+ set_insn_error (0, _("invalid register range"));
return 0;
}
mips_add_token (&token, OT_REG_RANGE);
return s;
}
- else if (*s == '[')
- {
- /* A vector element. */
- expressionS element;
+ /* Add the register itself. */
+ token.u.regno = regno1;
+ mips_add_token (&token, OT_REG);
+
+ /* Check for a vector index. */
+ if (*s == '[')
+ {
++s;
SKIP_SPACE_TABS (s);
- my_getExpression (&element, s);
- if (element.X_op != O_constant)
+ if (mips_parse_register (&s, &token.u.regno, NULL))
+ mips_add_token (&token, OT_REG_INDEX);
+ else
{
- insn_error = _("Vector element must be constant");
- return 0;
+ expressionS element;
+
+ my_getExpression (&element, s);
+ if (element.X_op != O_constant)
+ {
+ set_insn_error (0, _("vector element must be constant"));
+ return 0;
+ }
+ s = expr_end;
+ token.u.index = element.X_add_number;
+ mips_add_token (&token, OT_INTEGER_INDEX);
}
- s = expr_end;
SKIP_SPACE_TABS (s);
if (*s != ']')
{
- insn_error = _("Missing `]'");
+ set_insn_error (0, _("missing `]'"));
return 0;
}
++s;
-
- token.u.reg_element.regno = regno1;
- token.u.reg_element.index = element.X_add_number;
- mips_add_token (&token, OT_REG_ELEMENT);
- return s;
}
-
- /* Looks like just a plain register. */
- token.u.regno = regno1;
- mips_add_token (&token, OT_REG);
return s;
}
input_line_pointer = save_in;
if (err && *err)
{
- insn_error = err;
+ set_insn_error (0, err);
return 0;
}
if (s != end)
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;
}
g_switch_value = 0;
}
- if (! bfd_set_arch_mach (stdoutput, bfd_arch_mips, file_mips_arch))
- as_warn (_("Could not set architecture and machine"));
+ if (! bfd_set_arch_mach (stdoutput, bfd_arch_mips, file_mips_opts.arch))
+ 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. */
symbol_table_insert (symbol_new (regname, reg_section,
RTYPE_VI | i, &zero_address_frag));
+ /* MSA register. */
+ snprintf (regname, sizeof (regname) - 1, "$w%d", i);
+ symbol_table_insert (symbol_new (regname, reg_section,
+ RTYPE_MSA | i, &zero_address_frag));
}
obstack_init (&mips_operand_tokens);
= {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_PC:
case OP_VU0_SUFFIX:
case OP_VU0_MATCH_SUFFIX:
+ case OP_IMM_INDEX:
abort ();
case OP_REG:
if ((vsel & 0x18) == 0x18)
return 0;
return 1 << (uval & 31);
+
+ case OP_REG_INDEX:
+ if (!(type_mask & (1 << OP_REG_GP)))
+ return 0;
+ return 1 << insn_extract_operand (insn, operand);
}
abort ();
}
unsigned long pinfo;
unsigned int mask;
- mask = insn_reg_mask (ip, (1 << OP_REG_FP) | (1 << OP_REG_VEC),
+ mask = insn_reg_mask (ip, ((1 << OP_REG_FP) | (1 << OP_REG_VEC)
+ | (1 << OP_REG_MSA)),
insn_read_mask (ip->insn_mo));
pinfo = ip->insn_mo->pinfo;
/* Conservatively treat all operands to an FP_D instruction are doubles.
(This is overly pessimistic for things like cvt.d.s.) */
- if (HAVE_32BIT_FPRS && (pinfo & FP_D))
+ if (FPR_SIZE != 64 && (pinfo & FP_D))
mask |= mask << 1;
return mask;
}
unsigned long pinfo;
unsigned int mask;
- mask = insn_reg_mask (ip, (1 << OP_REG_FP) | (1 << OP_REG_VEC),
+ mask = insn_reg_mask (ip, ((1 << OP_REG_FP) | (1 << OP_REG_VEC)
+ | (1 << OP_REG_MSA)),
insn_write_mask (ip->insn_mo));
pinfo = ip->insn_mo->pinfo;
/* Conservatively treat all operands to an FP_D instruction are doubles.
(This is overly pessimistic for things like cvt.s.d.) */
- if (HAVE_32BIT_FPRS && (pinfo & FP_D))
+ if (FPR_SIZE != 64 && (pinfo & FP_D))
mask |= mask << 1;
return mask;
}
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;
}
&& (opcode->pinfo & (INSN_COPROC_MOVE_DELAY
| INSN_COPROC_MEMORY_DELAY
| INSN_LOAD_COPROC_DELAY
- | INSN_LOAD_MEMORY_DELAY
+ | INSN_LOAD_MEMORY
| INSN_STORE_MEMORY)))
return RTYPE_FPU | RTYPE_VEC;
return RTYPE_FPU;
case OP_REG_R5900_ACC:
return RTYPE_R5900_ACC;
+
+ case OP_REG_MSA:
+ return RTYPE_MSA;
+
+ case OP_REG_MSA_CTRL:
+ return RTYPE_NUM;
}
abort ();
}
if (type == OP_REG_FP
&& (regno & 1) != 0
- && HAVE_32BIT_FPRS
+ && FPR_SIZE != 64
&& !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 (sval < min_val || sval > max_val || sval % factor)
{
- 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 (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;
uval = mips_extract_operand (operand, opcode->match);
is_qh = (uval != 0);
- if (arg->token->type == OT_REG || arg->token->type == OT_REG_ELEMENT)
+ if (arg->token->type == OT_REG)
{
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;
}
+ if (!match_regno (arg, OP_REG_VEC, arg->token->u.regno, ®no))
+ return FALSE;
+ ++arg->token;
+
/* Check whether this is a vector register or a broadcast of
a single element. */
- if (arg->token->type == OT_REG_ELEMENT)
+ if (arg->token->type == OT_INTEGER_INDEX)
{
- if (!match_regno (arg, OP_REG_VEC, arg->token->u.reg_element.regno,
- ®no))
- return FALSE;
- if (arg->token->u.reg_element.index > (is_qh ? 3 : 7))
+ if (arg->token->u.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;
+ uval |= arg->token->u.index << (is_qh ? 2 : 1) << 5;
+ ++arg->token;
}
else
{
&& (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))
- return FALSE;
if (is_qh)
uval |= MDMX_FMTSEL_VEC_QH << 5;
else
uval |= MDMX_FMTSEL_VEC_OB << 5;
}
uval |= regno;
- ++arg->token;
}
else
{
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)
return TRUE;
}
+/* OP_IMM_INDEX matcher. */
+
+static bfd_boolean
+match_imm_index_operand (struct mips_arg_info *arg,
+ const struct mips_operand *operand)
+{
+ unsigned int max_val;
+
+ if (arg->token->type != OT_INTEGER_INDEX)
+ return FALSE;
+
+ max_val = (1 << operand->size) - 1;
+ if (arg->token->u.index > max_val)
+ {
+ match_out_of_range (arg);
+ return FALSE;
+ }
+ insn_insert_operand (arg->insn, operand, arg->token->u.index);
+ ++arg->token;
+ return TRUE;
+}
+
+/* OP_REG_INDEX matcher. */
+
+static bfd_boolean
+match_reg_index_operand (struct mips_arg_info *arg,
+ const struct mips_operand *operand)
+{
+ unsigned int regno;
+
+ if (arg->token->type != OT_REG_INDEX)
+ return FALSE;
+
+ if (!match_regno (arg, OP_REG_GP, arg->token->u.regno, ®no))
+ return FALSE;
+
+ insn_insert_operand (arg->insn, operand, regno);
+ ++arg->token;
+ return TRUE;
+}
+
/* OP_PC matcher. */
static bfd_boolean
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;
but the GPRs are only 32 bits wide. */
/* ??? No longer true with the addition of MTHC1, but this
is legacy code... */
- && (using_gprs || !(HAVE_64BIT_FPRS && HAVE_32BIT_GPRS))
+ && (using_gprs || !(FPR_SIZE == 64 && GPR_SIZE == 32))
&& ((data[0] == 0 && data[1] == 0)
|| (data[2] == 0 && data[3] == 0))
&& ((data[4] == 0 && data[5] == 0)
If using 32-bit registers, set IMM to the high order 32 bits and
OFFSET to the low order 32 bits. Otherwise, set IMM to the entire
64 bit constant. */
- if (using_gprs ? HAVE_32BIT_GPRS : HAVE_32BIT_FPRS)
+ if (using_gprs ? GPR_SIZE == 32 : FPR_SIZE != 64)
{
imm->X_op = O_constant;
offset->X_op = O_constant;
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;
case OP_VU0_MATCH_SUFFIX:
return match_vu0_suffix_operand (arg, operand, TRUE);
+
+ case OP_IMM_INDEX:
+ return match_imm_index_operand (arg, operand);
+
+ case OP_REG_INDEX:
+ return match_reg_index_operand (arg, operand);
}
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);
}
}
prev_pinfo = history[0].insn_mo->pinfo;
if (!mips_opts.noreorder
- && (((prev_pinfo & INSN_LOAD_MEMORY_DELAY) && !gpr_interlocks)
+ && (((prev_pinfo & INSN_LOAD_MEMORY) && !gpr_interlocks)
|| ((prev_pinfo & INSN_LOAD_COPROC_DELAY) && !cop_interlocks))
&& (gpr_write_mask (&history[0]) & (1 << reg)))
return TRUE;
return NUM_FIX_VR4120_CLASSES;
}
-#define INSN_ERET 0x42000018
-#define INSN_DERET 0x4200001f
+#define INSN_ERET 0x42000018
+#define INSN_DERET 0x4200001f
+#define INSN_DMULT 0x1c
+#define INSN_DMULTU 0x1d
/* Return the number of instructions that must separate INSN1 and INSN2,
where INSN1 is the earlier instruction. Return the worst-case value
}
}
+ /* If we're working around PMC RM7000 errata, there must be three
+ nops between a dmult and a load instruction. */
+ if (mips_fix_rm7000 && !mips_opts.micromips)
+ {
+ if ((insn1->insn_opcode & insn1->insn_mo->mask) == INSN_DMULT
+ || (insn1->insn_opcode & insn1->insn_mo->mask) == INSN_DMULTU)
+ {
+ if (pinfo2 & INSN_LOAD_MEMORY)
+ return 3;
+ }
+ }
+
/* If working around VR4120 errata, check for combinations that need
a single intervening instruction. */
if (mips_fix_vr4120 && !mips_opts.micromips)
/* Check for GPR or coprocessor load delays. All such delays
are on the RT register. */
/* Itbl support may require additional care here. */
- if ((!gpr_interlocks && (pinfo1 & INSN_LOAD_MEMORY_DELAY))
+ if ((!gpr_interlocks && (pinfo1 & INSN_LOAD_MEMORY))
|| (!cop_interlocks && (pinfo1 & INSN_LOAD_COPROC_DELAY)))
{
if (insn2 == NULL || (gpr_read_mask (insn2) & gpr_write_mask (insn1)))
{
unsigned long pinfo, pinfo2, prev_pinfo, prev_pinfo2;
unsigned int gpr_read, gpr_write, prev_gpr_read, prev_gpr_write;
+ unsigned int fpr_read, prev_fpr_write;
/* -O2 and above is required for this optimization. */
if (mips_optimize < 2)
if (gpr_read & prev_gpr_write)
return FALSE;
+ fpr_read = fpr_read_mask (ip);
+ prev_fpr_write = fpr_write_mask (&history[0]);
+ if (fpr_read & prev_fpr_write)
+ return FALSE;
+
/* If the branch writes a register that the previous
instruction sets, we can not swap. */
gpr_write = gpr_write_mask (ip);
&& 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)
/* These relocations can have an addend that won't fit in
4 octets for 64bit assembly. */
- if (HAVE_64BIT_GPRS
+ if (GPR_SIZE == 64
&& ! howto->partial_inplace
&& (reloc_type[0] == BFD_RELOC_16
|| reloc_type[0] == BFD_RELOC_32
}
}
-/* 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)
{
- memset (&mips_macro_warning.sizes, 0, sizeof (mips_macro_warning.sizes));
- memset (&mips_macro_warning.first_insn_sizes, 0,
- sizeof (mips_macro_warning.first_insn_sizes));
- memset (&mips_macro_warning.insns, 0, sizeof (mips_macro_warning.insns));
- mips_macro_warning.delay_slot_p = (mips_opts.noreorder
- && delayed_branch_p (&history[0]));
- switch (history[0].insn_mo->pinfo2
- & (INSN2_BRANCH_DELAY_32BIT | INSN2_BRANCH_DELAY_16BIT))
- {
- case INSN2_BRANCH_DELAY_32BIT:
+ 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 (GPR_SIZE == 32)
+ 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 (GPR_SIZE == 32)
+ 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,
+ sizeof (mips_macro_warning.first_insn_sizes));
+ memset (&mips_macro_warning.insns, 0, sizeof (mips_macro_warning.insns));
+ mips_macro_warning.delay_slot_p = (mips_opts.noreorder
+ && delayed_branch_p (&history[0]));
+ switch (history[0].insn_mo->pinfo2
+ & (INSN2_BRANCH_DELAY_32BIT | INSN2_BRANCH_DELAY_16BIT))
+ {
+ case INSN2_BRANCH_DELAY_32BIT:
mips_macro_warning.delay_slot_length = 4;
break;
case INSN2_BRANCH_DELAY_16BIT:
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;
}
/*
- * 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);
else
{
- load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+ load_register (AT, &imm_expr, GPR_SIZE == 64);
macro_build (NULL, unsignedp ? "sltu" : "slt", "d,v,t", AT, reg, AT);
}
}
/* The value is larger than 32 bits. */
- if (!dbl || HAVE_32BIT_GPRS)
+ if (!dbl || GPR_SIZE == 32)
{
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. */
&& !(history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT))
macro_build (NULL, "move", "mp,mj", dest, source);
else
- macro_build (NULL, HAVE_32BIT_GPRS ? "addu" : "daddu", "d,v,t",
+ macro_build (NULL, GPR_SIZE == 32 ? "addu" : "daddu", "d,v,t",
dest, source, 0);
}
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,.", op[0], op[1], 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", op[0], op[1], BFD_RELOC_LO16);
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)
}
used_at = 1;
- load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+ load_register (AT, &imm_expr, GPR_SIZE == 64);
macro_build (NULL, s2, "d,v,t", op[0], op[1], AT);
break;
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)
+ if (imm_expr.X_add_number == 0)
op[1] = 0;
else
{
op[1] = AT;
used_at = 1;
- load_register (op[1], &imm_expr, HAVE_64BIT_GPRS);
+ load_register (op[1], &imm_expr, GPR_SIZE == 64);
}
/* Fall through. */
case M_BEQL:
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, 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, 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;
}
likely = 1;
case M_BGTU_I:
if (op[0] == 0
- || (HAVE_32BIT_GPRS
- && imm_expr.X_op == O_constant
+ || (GPR_SIZE == 32
&& 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, op[0], ZERO);
else
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)
+ 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_op == O_constant && imm_expr.X_add_number == 1)
+ else if (imm_expr.X_add_number == 1)
macro_build_branch_rs (likely ? M_BLEZL : M_BLEZ, &offset_expr, op[0]);
else
{
likely = 1;
case M_BLEU_I:
if (op[0] == 0
- || (HAVE_32BIT_GPRS
- && imm_expr.X_op == O_constant
+ || (GPR_SIZE == 32
&& 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, op[0], ZERO);
else
}
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, op[0], op[1], (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, op[0], op[1], (int) pos,
- (int) (pos + size - 1));
- }
- break;
-
case M_DDIV_3:
dbl = 1;
case M_DIV_3:
do_div3:
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
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 (op[0], op[1]);
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", op[0], op[1]);
zero, we then add a base register to it. */
breg = op[2];
- if (dbl && HAVE_32BIT_GPRS)
+ if (dbl && GPR_SIZE == 32)
as_warn (_("dla used to load 32-bit register"));
if (!dbl && HAVE_64BIT_OBJECTS)
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);
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;
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 ();
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
}
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
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)
+ if (GPR_SIZE == 64)
load_register (op[0], &imm_expr, 1);
else
{
}
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. */
}
/* Now we load the register(s). */
- if (HAVE_64BIT_GPRS)
+ if (GPR_SIZE == 64)
{
used_at = 1;
macro_build (&offset_expr, "ld", "t,o(b)", op[0],
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)
+ load_register (AT, &imm_expr, FPR_SIZE == 64);
+ if (FPR_SIZE == 64)
{
- gas_assert (HAVE_64BIT_GPRS);
+ gas_assert (GPR_SIZE == 64);
macro_build (NULL, "dmtc1", "t,S", AT, op[0]);
}
else
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)
case M_LD_AB:
fmt = "t,o(b)";
- if (HAVE_64BIT_GPRS)
+ if (GPR_SIZE == 64)
{
s = "ld";
goto ld;
case M_SD_AB:
fmt = "t,o(b)";
- if (HAVE_64BIT_GPRS)
+ if (GPR_SIZE == 64)
{
s = "sd";
goto ld_st;
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)
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))
{
{
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))
{
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))
{
{
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))
{
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", op[0], op[1], BFD_RELOC_LO16);
break;
}
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 (op[0], 0);
break;
(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", 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",
+ macro_build (&imm_expr, GPR_SIZE == 32 ? "addiu" : "daddiu",
"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);
+ load_register (AT, &imm_expr, GPR_SIZE == 64);
macro_build (NULL, "seq", "d,v,t", op[0], op[1], AT);
break;
}
else
{
- load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+ load_register (AT, &imm_expr, GPR_SIZE == 64);
macro_build (NULL, "xor", "d,v,t", op[0], op[1], AT);
used_at = 1;
}
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",
op[0], op[1], BFD_RELOC_LO16);
else
{
- load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+ load_register (AT, &imm_expr, GPR_SIZE == 64);
macro_build (NULL, mask == M_SGE_I ? "slt" : "sltu", "d,v,t",
op[0], op[1], AT);
used_at = 1;
s = "sltu";
sgti:
used_at = 1;
- load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+ load_register (AT, &imm_expr, GPR_SIZE == 64);
macro_build (NULL, s, "d,v,t", op[0], AT, op[1]);
break;
s = "sltu";
slei:
used_at = 1;
- load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+ load_register (AT, &imm_expr, GPR_SIZE == 64);
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", op[0], op[1],
break;
}
used_at = 1;
- load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+ load_register (AT, &imm_expr, GPR_SIZE == 64);
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", op[0], op[1],
break;
}
used_at = 1;
- load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+ load_register (AT, &imm_expr, GPR_SIZE == 64);
macro_build (NULL, "sltu", "d,v,t", op[0], op[1], AT);
break;
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", op[0], 0, op[1]);
break;
}
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",
+ macro_build (&expr1, GPR_SIZE == 32 ? "addiu" : "daddiu", "t,r,j",
op[0], 0, BFD_RELOC_LO16);
break;
}
(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", 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",
+ macro_build (&imm_expr, GPR_SIZE == 32 ? "addiu" : "daddiu",
"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);
+ load_register (AT, &imm_expr, GPR_SIZE == 64);
macro_build (NULL, "sne", "d,v,t", op[0], op[1], AT);
break;
}
else
{
- load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+ load_register (AT, &imm_expr, GPR_SIZE == 64);
macro_build (NULL, "xor", "d,v,t", op[0], op[1], AT);
used_at = 1;
}
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,.", op[0], op[1], -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;
s = "tne";
trap:
used_at = 1;
- load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+ load_register (AT, &imm_expr, GPR_SIZE == 64);
macro_build (NULL, s, "s,t", 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. */
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", 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", 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", op[0]);
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:
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. */
-
-static void
-mips_ip (char *str, struct mips_cl_insn *ip)
-{
- bfd_boolean wrong_delay_slot_insns = FALSE;
- bfd_boolean need_delay_slot_ok = TRUE;
- struct mips_opcode *firstinsn = NULL;
- const struct mips_opcode *past;
- struct hash_control *hash;
- const char *args;
- char c = 0;
- struct mips_opcode *first, *insn;
- char format;
- size_t end;
- const struct mips_operand *operand;
- struct mips_arg_info arg;
- struct mips_operand_token *tokens;
- unsigned int opcode_extra;
-
- insn_error = NULL;
-
- if (mips_opts.micromips)
- {
- hash = micromips_op_hash;
- past = µmips_opcodes[bfd_micromips_num_opcodes];
- }
- else
- {
- hash = op_hash;
- 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;
-
- first = insn = mips_lookup_insn (hash, str, end, &opcode_extra);
- if (insn == NULL)
- {
- insn_error = _("Unrecognized opcode");
- return;
- }
- /* When no opcode suffix is specified, assume ".xyzw". */
- if ((insn->pinfo2 & INSN2_VU0_CHANNEL_SUFFIX) != 0 && opcode_extra == 0)
- opcode_extra = 0xf << mips_vu0_channel_mask.lsb;
-
- if (strcmp (insn->name, "li.s") == 0)
- format = 'f';
- else if (strcmp (insn->name, "li.d") == 0)
- format = 'd';
- else
- format = 0;
- tokens = mips_parse_arguments (str + end, format);
- 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, first->name) == 0);
-
- ok = is_opcode_valid (insn);
- size_ok = is_size_valid (insn);
- delay_slot_ok = is_delay_slot_valid (insn);
- if (!delay_slot_ok && !wrong_delay_slot_insns)
- {
- firstinsn = insn;
- wrong_delay_slot_insns = TRUE;
- }
- more_alts = (insn + 1 < past
- && strcmp (insn[0].name, insn[1].name) == 0);
- if (!ok || !size_ok || delay_slot_ok != need_delay_slot_ok)
- {
- 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);
- ip->insn_opcode |= opcode_extra;
- 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 == ',')
- {
- 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)
- 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;
- }
- if (*args == '#')
- {
- ++args;
- if (arg.token->type == OT_DOUBLE_CHAR
- && arg.token->u.ch == *args)
- {
- ++arg.token;
- continue;
- }
- break;
- }
-
- /* Handle special macro operands. Work out the properties of
- other operands. */
- arg.opnum += 1;
- arg.lax_max = 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 '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;
+ name = alloca (length + 1);
+ memcpy (name, start, length);
+ name[length] = '\0';
- case 'p':
- *offset_reloc = BFD_RELOC_16_PCREL_S2;
- break;
+ /* Look up the instruction as-is. */
+ insn = (struct mips_opcode *) hash_find (hash, name);
+ if (insn)
+ return insn;
- case 'a':
- *offset_reloc = BFD_RELOC_MIPS_JMP;
- break;
+ 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;
+ }
+ }
+ }
- 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;
+ 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;
}
+ }
+ }
- operand = (mips_opts.micromips
- ? decode_micromips_operand (args)
- : decode_mips_operand (args));
- if (!operand)
- abort ();
+ return NULL;
+}
- /* Skip prefixes. */
- if (*args == '+' || *args == 'm')
- args++;
+/* Assemble an instruction into its binary format. If the instruction
+ 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. */
- 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;
- }
+static void
+mips_ip (char *str, struct mips_cl_insn *insn)
+{
+ const struct mips_opcode *first, *past;
+ struct hash_control *hash;
+ char format;
+ size_t end;
+ struct mips_operand_token *tokens;
+ unsigned int opcode_extra;
- if (!match_operand (&arg, operand))
- break;
+ if (mips_opts.micromips)
+ {
+ hash = micromips_op_hash;
+ past = µmips_opcodes[bfd_micromips_num_opcodes];
+ }
+ else
+ {
+ hash = op_hash;
+ past = &mips_opcodes[NUMOPCODES];
+ }
+ forced_insn_length = 0;
+ opcode_extra = 0;
- 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);
+ /* 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;
+
+ first = mips_lookup_insn (hash, str, end, &opcode_extra);
+ if (first == NULL)
+ {
+ set_insn_error (0, _("unrecognized opcode"));
return;
}
+
+ if (strcmp (first->name, "li.s") == 0)
+ format = 'f';
+ else if (strcmp (first->name, "li.d") == 0)
+ format = 'd';
+ else
+ format = 0;
+ tokens = mips_parse_arguments (str + end, format);
+ if (!tokens)
+ return;
+
+ 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"));
+
+ 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;
- 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 == ',')
- {
- 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)
- 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;
- 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, 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;
- }
-
- 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 (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))
- break;
- continue;
- }
-
- /* Args don't match. */
- if (more_alts)
- {
- ++insn;
- continue;
- }
-
- insn_error = _("illegal operands");
+ if (!match_mips16_insns (insn, first, tokens))
+ set_insn_error (0, _("invalid 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);
break;
case OPTION_MIPS1:
- file_mips_isa = ISA_MIPS1;
+ file_mips_opts.isa = ISA_MIPS1;
break;
case OPTION_MIPS2:
- file_mips_isa = ISA_MIPS2;
+ file_mips_opts.isa = ISA_MIPS2;
break;
case OPTION_MIPS3:
- file_mips_isa = ISA_MIPS3;
+ file_mips_opts.isa = ISA_MIPS3;
break;
case OPTION_MIPS4:
- file_mips_isa = ISA_MIPS4;
+ file_mips_opts.isa = ISA_MIPS4;
break;
case OPTION_MIPS5:
- file_mips_isa = ISA_MIPS5;
+ file_mips_opts.isa = ISA_MIPS5;
break;
case OPTION_MIPS32:
- file_mips_isa = ISA_MIPS32;
+ file_mips_opts.isa = ISA_MIPS32;
break;
case OPTION_MIPS32R2:
- file_mips_isa = ISA_MIPS32R2;
+ file_mips_opts.isa = ISA_MIPS32R2;
+ break;
+
+ case OPTION_MIPS32R3:
+ file_mips_opts.isa = ISA_MIPS32R3;
+ break;
+
+ case OPTION_MIPS32R5:
+ file_mips_opts.isa = ISA_MIPS32R5;
break;
case OPTION_MIPS64R2:
- file_mips_isa = ISA_MIPS64R2;
+ file_mips_opts.isa = ISA_MIPS64R2;
+ break;
+
+ case OPTION_MIPS64R3:
+ file_mips_opts.isa = ISA_MIPS64R3;
+ break;
+
+ case OPTION_MIPS64R5:
+ file_mips_opts.isa = ISA_MIPS64R5;
break;
case OPTION_MIPS64:
- file_mips_isa = ISA_MIPS64;
+ file_mips_opts.isa = ISA_MIPS64;
break;
case OPTION_MTUNE:
mips_fix_24k = 0;
break;
+ case OPTION_FIX_RM7000:
+ mips_fix_rm7000 = 1;
+ break;
+
+ case OPTION_NO_FIX_RM7000:
+ mips_fix_rm7000 = 0;
+ break;
+
case OPTION_FIX_LOONGSON2F_JUMP:
mips_fix_loongson2f_jump = TRUE;
break;
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:
- file_mips_gp32 = 1;
+ file_mips_opts.gp = 32;
break;
case OPTION_GP64:
- file_mips_gp32 = 0;
+ file_mips_opts.gp = 64;
break;
case OPTION_FP32:
- file_mips_fp32 = 1;
+ file_mips_opts.fp = 32;
break;
case OPTION_FP64:
- file_mips_fp32 = 0;
+ file_mips_opts.fp = 64;
break;
case OPTION_SINGLE_FLOAT:
- file_mips_single_float = 1;
+ file_mips_opts.single_float = 1;
break;
case OPTION_DOUBLE_FLOAT:
- file_mips_single_float = 0;
+ file_mips_opts.single_float = 0;
break;
case OPTION_SOFT_FLOAT:
- file_mips_soft_float = 1;
+ file_mips_opts.soft_float = 1;
break;
case OPTION_HARD_FLOAT:
- file_mips_soft_float = 0;
+ file_mips_opts.soft_float = 0;
break;
case OPTION_MABI:
{
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 (info != 0)
{
- file_mips_arch = info->cpu;
+ file_mips_opts.arch = info->cpu;
mips_opts.arch = info->cpu;
mips_opts.isa = info->isa;
}
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;
}
if (mips_arch_string != 0)
arch_info = mips_parse_cpu ("-march", mips_arch_string);
- if (file_mips_isa != ISA_UNKNOWN)
+ if (file_mips_opts.isa != ISA_UNKNOWN)
{
- /* Handle -mipsN. At this point, file_mips_isa contains the
+ /* Handle -mipsN. At this point, file_mips_opts.isa contains the
ISA level specified by -mipsN, while arch_info->isa contains
the -march selection (if any). */
if (arch_info != 0)
/* -march takes precedence over -mipsN, since it is more descriptive.
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"),
- mips_cpu_info_from_isa (file_mips_isa)->name,
+ if (file_mips_opts.isa != arch_info->isa)
+ as_bad (_("-%s conflicts with the other architecture options,"
+ " which imply -%s"),
+ mips_cpu_info_from_isa (file_mips_opts.isa)->name,
mips_cpu_info_from_isa (arch_info->isa)->name);
}
else
- arch_info = mips_cpu_info_from_isa (file_mips_isa);
+ arch_info = mips_cpu_info_from_isa (file_mips_opts.isa);
}
if (arch_info == 0)
mips_set_architecture (arch_info);
- /* Optimize for file_mips_arch, unless -mtune selects a different processor. */
+ /* Optimize for file_mips_opts.arch, unless -mtune selects a different
+ processor. */
if (mips_tune_string != 0)
tune_info = mips_parse_cpu ("-mtune", mips_tune_string);
else
mips_set_tune (tune_info);
- if (file_mips_gp32 >= 0)
+ if (file_mips_opts.gp >= 0)
{
/* The user specified the size of the integer registers. Make sure
it agrees with the ABI and ISA. */
- if (file_mips_gp32 == 0 && !ISA_HAS_64BIT_REGS (mips_opts.isa))
+ if (file_mips_opts.gp == 64 && !ISA_HAS_64BIT_REGS (mips_opts.isa))
as_bad (_("-mgp64 used with a 32-bit processor"));
- else if (file_mips_gp32 == 1 && ABI_NEEDS_64BIT_REGS (mips_abi))
+ else if (file_mips_opts.gp == 32 && ABI_NEEDS_64BIT_REGS (mips_abi))
as_bad (_("-mgp32 used with a 64-bit ABI"));
- else if (file_mips_gp32 == 0 && ABI_NEEDS_32BIT_REGS (mips_abi))
+ else if (file_mips_opts.gp == 64 && ABI_NEEDS_32BIT_REGS (mips_abi))
as_bad (_("-mgp64 used with a 32-bit ABI"));
}
else
/* Infer the integer register size from the ABI and processor.
Restrict ourselves to 32-bit registers if that's all the
processor has, or if the ABI cannot handle 64-bit registers. */
- file_mips_gp32 = (ABI_NEEDS_32BIT_REGS (mips_abi)
- || !ISA_HAS_64BIT_REGS (mips_opts.isa));
+ file_mips_opts.gp = (ABI_NEEDS_32BIT_REGS (mips_abi)
+ || !ISA_HAS_64BIT_REGS (mips_opts.isa))
+ ? 32 : 64;
}
- switch (file_mips_fp32)
+ switch (file_mips_opts.fp)
{
default:
case -1:
registers would lead to spurious "register must be even" messages.
So here we assume float registers are never smaller than the
integer ones. */
- if (file_mips_gp32 == 0)
+ if (file_mips_opts.gp == 64)
/* 64-bit integer registers implies 64-bit float registers. */
- file_mips_fp32 = 0;
+ file_mips_opts.fp = 64;
else if ((mips_opts.ase & FP64_ASES)
&& ISA_HAS_64BIT_FPRS (mips_opts.isa))
/* -mips3d and -mdmx imply 64-bit float registers, if possible. */
- file_mips_fp32 = 0;
+ file_mips_opts.fp = 64;
else
/* 32-bit float registers. */
- file_mips_fp32 = 1;
+ file_mips_opts.fp = 32;
break;
/* The user specified the size of the float registers. Check if it
agrees with the ABI and ISA. */
- case 0:
+ case 64:
if (!ISA_HAS_64BIT_FPRS (mips_opts.isa))
as_bad (_("-mfp64 used with a 32-bit fpu"));
else if (ABI_NEEDS_32BIT_REGS (mips_abi)
&& !ISA_HAS_MXHC1 (mips_opts.isa))
as_warn (_("-mfp64 used with a 32-bit ABI"));
break;
- case 1:
+ case 32:
if (ABI_NEEDS_64BIT_REGS (mips_abi))
as_warn (_("-mfp32 used with a 64-bit ABI"));
break;
/* This flag is set when we have a 64-bit capable CPU but use only
32-bit wide registers. Note that EABI does not use it. */
if (ISA_HAS_64BIT_REGS (mips_opts.isa)
- && ((mips_abi == NO_ABI && file_mips_gp32 == 1)
+ && ((mips_abi == NO_ABI && file_mips_opts.gp == 32)
|| mips_abi == O32_ABI))
mips_32bitmode = 1;
/* If the selected architecture includes support for ASEs, enable
generation of code for them. */
if (mips_opts.mips16 == -1)
- mips_opts.mips16 = (CPU_HAS_MIPS16 (file_mips_arch)) ? 1 : 0;
+ mips_opts.mips16 = (CPU_HAS_MIPS16 (file_mips_opts.arch)) ? 1 : 0;
if (mips_opts.micromips == -1)
- mips_opts.micromips = (CPU_HAS_MICROMIPS (file_mips_arch)) ? 1 : 0;
+ mips_opts.micromips = (CPU_HAS_MICROMIPS (file_mips_opts.arch))
+ ? 1 : 0;
/* MIPS3D and MDMX require 64-bit FPRs, so -mfp32 should stop those
ASEs from being selected implicitly. */
- if (file_mips_fp32 == 1)
+ if (file_mips_opts.fp != 64)
file_ase_explicit |= ASE_MIPS3D | ASE_MDMX;
/* If the user didn't explicitly select or deselect a particular ASE,
use the default setting for the CPU. */
mips_opts.ase |= (arch_info->ase & ~file_ase_explicit);
- file_mips_isa = mips_opts.isa;
- file_ase = mips_opts.ase;
- mips_opts.gp32 = file_mips_gp32;
- mips_opts.fp32 = file_mips_fp32;
- mips_opts.soft_float = file_mips_soft_float;
- mips_opts.single_float = file_mips_single_float;
+ file_mips_opts.isa = mips_opts.isa;
+ file_mips_opts.ase = mips_opts.ase;
+ mips_opts.gp = file_mips_opts.gp;
+ mips_opts.fp = file_mips_opts.fp;
+ mips_opts.soft_float = file_mips_opts.soft_float;
+ mips_opts.single_float = file_mips_opts.single_float;
mips_check_isa_supports_ases ();
/* Return the address of the delay slot. */
return addr + 4;
- case BFD_RELOC_32_PCREL:
- return addr;
-
default:
- /* 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"));
return addr;
}
}
unsigned long insn;
reloc_howto_type *howto;
- /* We ignore generic BFD relocations we don't know about. */
- howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
- if (! howto)
- return;
+ if (fixP->fx_pcrel)
+ switch (fixP->fx_r_type)
+ {
+ case BFD_RELOC_16_PCREL_S2:
+ case BFD_RELOC_MICROMIPS_7_PCREL_S1:
+ case BFD_RELOC_MICROMIPS_10_PCREL_S1:
+ case BFD_RELOC_MICROMIPS_16_PCREL_S1:
+ case BFD_RELOC_32_PCREL:
+ break;
+
+ case BFD_RELOC_32:
+ fixP->fx_r_type = BFD_RELOC_32_PCREL;
+ break;
+
+ default:
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("PC-relative reference to a different section"));
+ break;
+ }
+
+ /* Handle BFD_RELOC_8, since it's easy. Punt on other bfd relocations
+ that have no MIPS ELF equivalent. */
+ if (fixP->fx_r_type != BFD_RELOC_8)
+ {
+ howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
+ if (!howto)
+ return;
+ }
gas_assert (fixP->fx_size == 2
|| fixP->fx_size == 4
+ || fixP->fx_r_type == BFD_RELOC_8
|| fixP->fx_r_type == BFD_RELOC_16
|| fixP->fx_r_type == BFD_RELOC_64
|| fixP->fx_r_type == BFD_RELOC_CTOR
buf = fixP->fx_frag->fr_literal + fixP->fx_where;
- gas_assert (!fixP->fx_pcrel || fixP->fx_r_type == BFD_RELOC_16_PCREL_S2
- || fixP->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
- || fixP->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1
- || fixP->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1
- || fixP->fx_r_type == BFD_RELOC_32_PCREL);
-
/* Don't treat parts of a composite relocation as done. There are two
reasons for this:
}
else
as_bad_where (fixP->fx_file, fixP->fx_line,
- _("Unsupported constant in relocation"));
+ _("unsupported constant in relocation"));
}
break;
case BFD_RELOC_32:
case BFD_RELOC_32_PCREL:
case BFD_RELOC_16:
+ case BFD_RELOC_8:
/* If we are deleting this reloc entry, we must fill in the
value now. This can happen if we have a .word which is not
resolved when it appears but is later defined. */
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)
{
mips_opts.nobopt = 1;
}
else if (strcmp (name, "gp=default") == 0)
- mips_opts.gp32 = file_mips_gp32;
+ mips_opts.gp = file_mips_opts.gp;
else if (strcmp (name, "gp=32") == 0)
- mips_opts.gp32 = 1;
+ mips_opts.gp = 32;
else if (strcmp (name, "gp=64") == 0)
{
if (!ISA_HAS_64BIT_REGS (mips_opts.isa))
as_warn (_("%s isa does not support 64-bit registers"),
mips_cpu_info_from_isa (mips_opts.isa)->name);
- mips_opts.gp32 = 0;
+ mips_opts.gp = 64;
}
else if (strcmp (name, "fp=default") == 0)
- mips_opts.fp32 = file_mips_fp32;
+ mips_opts.fp = file_mips_opts.fp;
else if (strcmp (name, "fp=32") == 0)
- mips_opts.fp32 = 1;
+ mips_opts.fp = 32;
else if (strcmp (name, "fp=64") == 0)
{
if (!ISA_HAS_64BIT_FPRS (mips_opts.isa))
as_warn (_("%s isa does not support 64-bit floating point registers"),
mips_cpu_info_from_isa (mips_opts.isa)->name);
- mips_opts.fp32 = 0;
+ mips_opts.fp = 64;
}
else if (strcmp (name, "softfloat") == 0)
mips_opts.soft_float = 1;
if (strcmp (name, "mips0") == 0 || strcmp (name, "arch=default") == 0)
{
reset = 1;
- mips_opts.isa = file_mips_isa;
- mips_opts.arch = file_mips_arch;
+ mips_opts.isa = file_mips_opts.isa;
+ mips_opts.arch = file_mips_opts.arch;
}
else if (strncmp (name, "arch=", 5) == 0)
{
case ISA_MIPS2:
case ISA_MIPS32:
case ISA_MIPS32R2:
- mips_opts.gp32 = 1;
- mips_opts.fp32 = 1;
+ case ISA_MIPS32R3:
+ case ISA_MIPS32R5:
+ mips_opts.gp = 32;
+ mips_opts.fp = 32;
break;
case ISA_MIPS3:
case ISA_MIPS4:
case ISA_MIPS5:
case ISA_MIPS64:
case ISA_MIPS64R2:
- mips_opts.gp32 = 0;
+ case ISA_MIPS64R3:
+ case ISA_MIPS64R5:
+ mips_opts.gp = 64;
if (mips_opts.arch == CPU_R5900)
{
- mips_opts.fp32 = 1;
+ mips_opts.fp = 32;
}
else
{
- mips_opts.fp32 = 0;
+ mips_opts.fp = 64;
}
break;
default:
}
if (reset)
{
- mips_opts.gp32 = file_mips_gp32;
- mips_opts.fp32 = file_mips_fp32;
+ mips_opts.gp = file_mips_opts.gp;
+ mips_opts.fp = file_mips_opts.fp;
}
}
else if (strcmp (name, "autoextend") == 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;
switch ((insn >> 28) & 0xf)
{
case 4:
- /* bc[0-3][tf]l? instructions can have the condition
- reversed by tweaking a single TF bit, and their
- opcodes all have 0x4???????. */
- gas_assert ((insn & 0xf3e00000) == 0x41000000);
- insn ^= 0x00010000;
+ if ((insn & 0xff000000) == 0x47000000
+ || (insn & 0xff600000) == 0x45600000)
+ {
+ /* BZ.df/BNZ.df, BZ.V/BNZ.V can have the condition
+ reversed by tweaking bit 23. */
+ insn ^= 0x00800000;
+ }
+ else
+ {
+ /* bc[0-3][tf]l? instructions can have the condition
+ reversed by tweaking a single TF bit, and their
+ opcodes all have 0x4???????. */
+ gas_assert ((insn & 0xf3e00000) == 0x41000000);
+ insn ^= 0x00010000;
+ }
break;
case 0:
/* 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;
|| (insn & 0xffe30000) == 0x42800000 /* bc2f */
|| (insn & 0xffe30000) == 0x42a00000) /* bc2t */
insn ^= 0x00200000;
+ else if ((insn & 0xff000000) == 0x83000000 /* BZ.df
+ BNZ.df */
+ || (insn & 0xff600000) == 0x81600000) /* BZ.V
+ BNZ.V */
+ insn ^= 0x00800000;
else
abort ();
elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_O64;
else if (mips_abi == EABI_ABI)
{
- if (!file_mips_gp32)
+ if (file_mips_opts.gp == 64)
elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_EABI64;
else
elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_EABI32;
if (mips_flag_nan2008)
elf_elfheader (stdoutput)->e_flags |= EF_MIPS_NAN2008;
-#if 0 /* XXX FIXME */
/* 32 bit code with 64 bit FP registers. */
- if (!file_mips_fp32 && ABI_NEEDS_32BIT_REGS (mips_abi))
- elf_elfheader (stdoutput)->e_flags |= ???;
-#endif
+ if (file_mips_opts.fp == 64 && ABI_NEEDS_32BIT_REGS (mips_abi))
+ elf_elfheader (stdoutput)->e_flags |= EF_MIPS_FP64;
}
\f
typedef struct proc {
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;
{ "mips5", MIPS_CPU_IS_ISA, 0, ISA_MIPS5, CPU_MIPS5 },
{ "mips32", MIPS_CPU_IS_ISA, 0, ISA_MIPS32, CPU_MIPS32 },
{ "mips32r2", MIPS_CPU_IS_ISA, 0, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "mips32r3", MIPS_CPU_IS_ISA, 0, ISA_MIPS32R3, CPU_MIPS32R3 },
+ { "mips32r5", MIPS_CPU_IS_ISA, 0, ISA_MIPS32R5, CPU_MIPS32R5 },
{ "mips64", MIPS_CPU_IS_ISA, 0, ISA_MIPS64, CPU_MIPS64 },
{ "mips64r2", MIPS_CPU_IS_ISA, 0, ISA_MIPS64R2, CPU_MIPS64R2 },
+ { "mips64r3", MIPS_CPU_IS_ISA, 0, ISA_MIPS64R3, CPU_MIPS64R3 },
+ { "mips64r5", MIPS_CPU_IS_ISA, 0, ISA_MIPS64R5, CPU_MIPS64R5 },
/* MIPS I */
{ "r3000", 0, 0, ISA_MIPS1, CPU_R3000 },
{ "1004kf2_1", 0, ASE_DSP | ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
{ "1004kf", 0, ASE_DSP | ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
{ "1004kf1_1", 0, ASE_DSP | ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
+ /* P5600 with EVA and Virtualization ASEs, other ASEs are optional. */
+ { "p5600", 0, ASE_VIRT | ASE_EVA | ASE_XPA, ISA_MIPS32R5, CPU_MIPS32R5 },
/* MIPS 64 */
{ "5kc", 0, 0, ISA_MIPS64, CPU_MIPS64 },
/* Broadcom SB-1A CPU core */
{ "sb1a", 0, ASE_MIPS3D | ASE_MDMX, ISA_MIPS64, CPU_SB1 },
- { "loongson3a", 0, 0, ISA_MIPS64, CPU_LOONGSON_3A },
+ { "loongson3a", 0, 0, ISA_MIPS64R2, CPU_LOONGSON_3A },
/* MIPS 64 Release 2 */
if (ABI_NEEDS_64BIT_REGS (mips_abi))
return mips_cpu_info_from_isa (ISA_MIPS3);
- if (file_mips_gp32 >= 0)
- return mips_cpu_info_from_isa (file_mips_gp32 ? ISA_MIPS1 : ISA_MIPS3);
+ if (file_mips_opts.gp >= 0)
+ return mips_cpu_info_from_isa (file_mips_opts.gp == 32
+ ? ISA_MIPS1 : ISA_MIPS3);
return mips_cpu_info_from_isa (MIPS_DEFAULT_64BIT
? ISA_MIPS3
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;
}
-mips5 generate MIPS ISA V instructions\n\
-mips32 generate MIPS32 ISA instructions\n\
-mips32r2 generate MIPS32 release 2 ISA instructions\n\
+-mips32r3 generate MIPS32 release 3 ISA instructions\n\
+-mips32r5 generate MIPS32 release 5 ISA instructions\n\
-mips64 generate MIPS64 ISA instructions\n\
-mips64r2 generate MIPS64 release 2 ISA instructions\n\
+-mips64r3 generate MIPS64 release 3 ISA instructions\n\
+-mips64r5 generate MIPS64 release 5 ISA instructions\n\
-march=CPU/-mtune=CPU generate code/schedule for CPU, where CPU is one of:\n"));
first = 1;
-mmcu generate MCU instructions\n\
-mno-mcu do not generate MCU instructions\n"));
fprintf (stream, _("\
+-mmsa generate MSA instructions\n\
+-mno-msa do not generate MSA instructions\n"));
+ fprintf (stream, _("\
+-mxpa generate eXtended Physical Address (XPA) instructions\n\
+-mno-xpa do not generate eXtended Physical Address (XPA) instructions\n"));
+ fprintf (stream, _("\
-mvirt generate Virtualization instructions\n\
-mno-virt do not generate Virtualization instructions\n"));
fprintf (stream, _("\
return regnum;
}
+
+/* Implement CONVERT_SYMBOLIC_ATTRIBUTE.
+ Given a symbolic attribute NAME, return the proper integer value.
+ Returns -1 if the attribute is not known. */
+
+int
+mips_convert_symbolic_attribute (const char *name)
+{
+ static const struct
+ {
+ const char * name;
+ const int tag;
+ }
+ attribute_table[] =
+ {
+#define T(tag) {#tag, tag}
+ T (Tag_GNU_MIPS_ABI_FP),
+ T (Tag_GNU_MIPS_ABI_MSA),
+#undef T
+ };
+ unsigned int i;
+
+ if (name == NULL)
+ return -1;
+
+ for (i = 0; i < ARRAY_SIZE (attribute_table); i++)
+ if (streq (name, attribute_table[i].name))
+ return attribute_table[i].tag;
+
+ return -1;
+}